MPTRAC
mptrac.c
Go to the documentation of this file.
1/*
2 This file is part of MPTRAC.
3
4 MPTRAC is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 MPTRAC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with MPTRAC. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright (C) 2013-2025 Forschungszentrum Juelich GmbH
18*/
19
25#include "mptrac.h"
26
27#ifdef KPP
28#include "kpp_chem.h"
29#endif
30
32static gsl_rng *rng[NTHREADS];
33
35static uint64_t rng_ctr;
36
38#ifdef CURAND
39static curandGenerator_t rng_curand;
40#endif
41
42/*****************************************************************************/
43
44#ifdef MPI
46 void *data,
47 size_t N) {
48
49#define CHUNK_SIZE 2147483647
50
51 /* Broadcast the size of the data first... */
52 MPI_Bcast(&N, 1, MPI_UINT64_T, 0, MPI_COMM_WORLD);
53
54 /* Calculate the number of chunks... */
55 const size_t num_chunks = (N + CHUNK_SIZE - 1) / CHUNK_SIZE;
56
57 /* Loop over chunks... */
58 for (size_t i = 0; i < num_chunks; i++) {
59
60 /* Determine the start and end indices for the current chunk... */
61 const size_t start = i * CHUNK_SIZE;
62 const size_t end = (start + CHUNK_SIZE > N) ? N : start + CHUNK_SIZE;
63 const size_t chunk_size = end - start;
64
65 /* Broadcast the current chunk... */
66 MPI_Bcast((char *) data + start, (int) chunk_size, MPI_BYTE, 0,
67 MPI_COMM_WORLD);
68 }
69}
70#endif
71
72/*****************************************************************************/
73
75 const double *x,
76 double *z,
77 double *lon,
78 double *lat) {
79
80 const double radius = NORM(x);
81
82 *lat = RAD2DEG(asin(x[2] / radius));
83 *lon = RAD2DEG(atan2(x[1], x[0]));
84 *z = radius - RE;
85}
86
87/*****************************************************************************/
88
89double clim_oh(
90 const ctl_t *ctl,
91 const clim_t *clim,
92 const double t,
93 const double lon,
94 const double lat,
95 const double p) {
96
97 /* Set SZA threshold... */
98 const double sza_thresh = DEG2RAD(85.), cos_sza_thresh = cos(sza_thresh);
99
100 /* Get OH data from climatology... */
101 const double oh = clim_zm(&clim->oh, t, lat, p);
102
103 /* Apply diurnal correction... */
104 if (ctl->oh_chem_beta > 0) {
105 double sza = sza_calc(t, lon, lat);
106 if (sza <= sza_thresh)
107 return oh * exp(-ctl->oh_chem_beta / cos(sza));
108 else
109 return oh * exp(-ctl->oh_chem_beta / cos_sza_thresh);
110 } else
111 return oh;
112}
113
114/*****************************************************************************/
115
117 const ctl_t *ctl,
118 clim_t *clim) {
119
120 /* Set SZA threshold... */
121 const double sza_thresh = DEG2RAD(85.), cos_sza_thresh = cos(sza_thresh);
122
123 /* Loop over climatology data points... */
124 for (int it = 0; it < clim->oh.ntime; it++)
125 for (int iz = 0; iz < clim->oh.np; iz++)
126 for (int iy = 0; iy < clim->oh.nlat; iy++) {
127
128 /* Init... */
129 int n = 0;
130 double sum = 0;
131
132 /* Integrate day/night correction factor over longitude... */
133 for (double lon = -180; lon < 180; lon += 1.0) {
134 double sza = sza_calc(clim->oh.time[it], lon, clim->oh.lat[iy]);
135 if (sza <= sza_thresh)
136 sum += exp(-ctl->oh_chem_beta / cos(sza));
137 else
138 sum += exp(-ctl->oh_chem_beta / cos_sza_thresh);
139 n++;
140 }
141
142 /* Apply scaling factor to OH data... */
143 clim->oh.vmr[it][iz][iy] /= (sum / (double) n);
144 }
145}
146
147/*****************************************************************************/
148
150 const double rate[CP][CSZA][CO3],
151 const clim_photo_t *photo,
152 const double p,
153 const double sza,
154 const double o3c) {
155
156 /* Check pressure range... */
157 double p_help = p;
158 if (p < photo->p[photo->np - 1])
159 p_help = photo->p[photo->np - 1];
160 else if (p > photo->p[0])
161 p_help = photo->p[0];
162
163 /* Check sza range... */
164 double sza_help = sza;
165 if (sza < photo->sza[0])
166 sza_help = photo->sza[0];
167 else if (sza > photo->sza[photo->nsza - 1])
168 sza_help = photo->sza[photo->nsza - 1];
169
170 /* Check ozone column range... */
171 double o3c_help = o3c;
172 if (o3c < photo->o3c[0])
173 o3c_help = photo->o3c[0];
174 else if (o3c > photo->o3c[photo->no3c - 1])
175 o3c_help = photo->o3c[photo->no3c - 1];
176
177 /* Get indices... */
178 const int ip = locate_irr(photo->p, photo->np, p_help);
179 const int isza = locate_reg(photo->sza, photo->nsza, sza_help);
180 const int io3c = locate_reg(photo->o3c, photo->no3c, o3c_help);
181
182 /* Interpolate photolysis rate... */
183 double aux00 = LIN(photo->p[ip], rate[ip][isza][io3c],
184 photo->p[ip + 1], rate[ip + 1][isza][io3c], p_help);
185 double aux01 = LIN(photo->p[ip], rate[ip][isza][io3c + 1],
186 photo->p[ip + 1], rate[ip + 1][isza][io3c + 1], p_help);
187 double aux10 = LIN(photo->p[ip], rate[ip][isza + 1][io3c],
188 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c], p_help);
189 double aux11 = LIN(photo->p[ip], rate[ip][isza + 1][io3c + 1],
190 photo->p[ip + 1], rate[ip + 1][isza + 1][io3c + 1],
191 p_help);
192 aux00 = LIN(photo->o3c[io3c], aux00, photo->o3c[io3c + 1], aux01, o3c_help);
193 aux11 = LIN(photo->o3c[io3c], aux10, photo->o3c[io3c + 1], aux11, o3c_help);
194 aux00 = LIN(photo->sza[isza], aux00, photo->sza[isza + 1], aux11, sza_help);
195 return MAX(aux00, 0.0);
196}
197
198/*****************************************************************************/
199
201 const clim_t *clim,
202 const double t,
203 const double lat) {
204
205 /* Get seconds since begin of year... */
206 double sec = FMOD(t, 365.25 * 86400.);
207 while (sec < 0)
208 sec += 365.25 * 86400.;
209
210 /* Get indices... */
211 const int isec = locate_irr(clim->tropo_time, clim->tropo_ntime, sec);
212 const int ilat = locate_reg(clim->tropo_lat, clim->tropo_nlat, lat);
213
214 /* Interpolate tropopause pressure... */
215 const double p0 = LIN(clim->tropo_lat[ilat],
216 clim->tropo[isec][ilat],
217 clim->tropo_lat[ilat + 1],
218 clim->tropo[isec][ilat + 1], lat);
219 const double p1 = LIN(clim->tropo_lat[ilat],
220 clim->tropo[isec + 1][ilat],
221 clim->tropo_lat[ilat + 1],
222 clim->tropo[isec + 1][ilat + 1], lat);
223 return LIN(clim->tropo_time[isec], p0, clim->tropo_time[isec + 1], p1, sec);
224}
225
226/*****************************************************************************/
227
229 clim_t *clim) {
230
231 /* Write info... */
232 LOG(1, "Initialize tropopause data...");
233
234 /* Set time [s]... */
235 clim->tropo_ntime = 12;
236 double tropo_time[12] = {
237 1209600.00, 3888000.00, 6393600.00,
238 9072000.00, 11664000.00, 14342400.00,
239 16934400.00, 19612800.00, 22291200.00,
240 24883200.00, 27561600.00, 30153600.00
241 };
242 memcpy(clim->tropo_time, tropo_time, sizeof(clim->tropo_time));
243
244 /* Set latitudes [deg]... */
245 clim->tropo_nlat = 73;
246 double tropo_lat[73] = {
247 -90, -87.5, -85, -82.5, -80, -77.5, -75, -72.5, -70, -67.5,
248 -65, -62.5, -60, -57.5, -55, -52.5, -50, -47.5, -45, -42.5,
249 -40, -37.5, -35, -32.5, -30, -27.5, -25, -22.5, -20, -17.5,
250 -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5,
251 15, 17.5, 20, 22.5, 25, 27.5, 30, 32.5, 35, 37.5, 40, 42.5,
252 45, 47.5, 50, 52.5, 55, 57.5, 60, 62.5, 65, 67.5, 70, 72.5,
253 75, 77.5, 80, 82.5, 85, 87.5, 90
254 };
255 memcpy(clim->tropo_lat, tropo_lat, sizeof(clim->tropo_lat));
256
257 /* Set tropopause pressure [hPa] (NCEP/NCAR Reanalysis 1)... */
258 double tropo[12][73] = {
259 {324.1, 325.6, 325, 324.3, 322.5, 319.7, 314, 307.2, 301.8, 299.6,
260 297.1, 292.2, 285.6, 276.1, 264, 248.9, 231.9, 213.5, 194.4,
261 175.3, 157, 140.4, 126.7, 116.3, 109.5, 105.4, 103, 101.4, 100.4,
262 99.69, 99.19, 98.84, 98.56, 98.39, 98.39, 98.42, 98.44, 98.54,
263 98.68, 98.81, 98.89, 98.96, 99.12, 99.65, 101.4, 105.4, 113.5, 128,
264 152.1, 184.7, 214, 234.1, 247.3, 255.8, 262.6, 267.7, 271.7, 275,
265 277.2, 279, 280.1, 280.4, 280.6, 280.1, 279.3, 278.3, 276.8, 275.8,
266 275.3, 275.6, 275.4, 274.1, 273.5},
267 {337.3, 338.7, 337.8, 336.4, 333, 328.8, 321.1, 312.6, 306.6, 303.7,
268 300.2, 293.8, 285.4, 273.8, 259.6, 242.7, 224.4, 205.2, 186, 167.5,
269 150.3, 135, 122.8, 113.9, 108.2, 104.7, 102.5, 101.1, 100.2, 99.42,
270 98.88, 98.52, 98.25, 98.09, 98.07, 98.1, 98.12, 98.2, 98.25, 98.27,
271 98.26, 98.27, 98.36, 98.79, 100.2, 104.2, 113.7, 131.2, 159.5, 193,
272 220.4, 238.1, 250.2, 258.1, 264.7, 269.7, 273.7, 277.3, 280.2, 282.8,
273 284.9, 286.5, 288.1, 288.8, 289, 288.5, 287.2, 286.3, 286.1, 287.2,
274 287.5, 286.2, 285.8},
275 {335, 336, 335.7, 335.1, 332.3, 328.1, 320.6, 311.8, 305.1, 301.9,
276 297.6, 290, 280.4, 268.3, 254.6, 239.6, 223.9, 207.9, 192.2, 176.9,
277 161.7, 146.4, 132.2, 120.6, 112.3, 107.2, 104.3, 102.4, 101.3,
278 100.4, 99.86, 99.47, 99.16, 98.97, 98.94, 98.97, 99, 99.09, 99.2,
279 99.31, 99.35, 99.41, 99.51, 99.86, 101.1, 104.9, 114.3, 131, 156.8,
280 186.3, 209.3, 224.6, 236.8, 246.3, 254.9, 262.3, 268.8, 274.8,
281 279.9, 284.6, 288.6, 291.6, 294.9, 297.5, 299.8, 301.8, 303.1,
282 304.3, 304.9, 306, 306.6, 306.2, 306},
283 {306.2, 306.7, 305.7, 307.1, 307.3, 306.4, 301.8, 296.2, 292.4,
284 290.3, 287.1, 280.9, 273.4, 264.3, 254.1, 242.8, 231, 219, 207.2,
285 195.5, 183.3, 169.7, 154.7, 138.7, 124.1, 113.6, 107.8, 104.7,
286 102.8, 101.7, 100.9, 100.4, 100, 99.79, 99.7, 99.66, 99.68, 99.79,
287 99.94, 100.2, 100.5, 100.9, 101.4, 102.1, 103.4, 107, 115.2, 129.1,
288 148.7, 171, 190.8, 205.6, 218.4, 229.4, 239.6, 248.6, 256.5,
289 263.7, 270.3, 276.6, 282.6, 288.1, 294.5, 300.4, 306.3, 311.4,
290 315.1, 318.3, 320.3, 322.2, 322.8, 321.5, 321.1},
291 {266.5, 264.9, 260.8, 261, 262, 263, 261.3, 259.7, 259.2, 259.8,
292 260.1, 258.6, 256.7, 253.6, 249.5, 243.9, 237.4, 230, 222.1, 213.9,
293 205, 194.4, 180.4, 161.8, 140.7, 122.9, 112.1, 106.7, 104.1, 102.7,
294 101.8, 101.4, 101.1, 101, 101, 101, 101.1, 101.2, 101.5, 101.9,
295 102.4, 103, 103.8, 104.9, 106.8, 110.1, 115.6, 124, 135.2, 148.9,
296 165.2, 181.3, 198, 211.8, 223.5, 233.8, 242.9, 251.5, 259, 266.2,
297 273.1, 279.2, 286.2, 292.8, 299.6, 306, 311.1, 315.5, 318.8, 322.6,
298 325.3, 325.8, 325.8},
299 {220.1, 218.1, 210.8, 207.2, 207.6, 210.5, 211.4, 213.5, 217.3,
300 222.4, 227.9, 232.8, 237.4, 240.8, 242.8, 243, 241.5, 238.6, 234.2,
301 228.5, 221, 210.7, 195.1, 172.9, 147.8, 127.6, 115.6, 109.9, 107.1,
302 105.7, 105, 104.8, 104.8, 104.9, 105, 105.1, 105.3, 105.5, 105.8,
303 106.4, 107, 107.6, 108.1, 108.8, 110, 111.8, 114.2, 117.4, 121.6,
304 127.9, 137.3, 151.2, 169.5, 189, 205.8, 218.9, 229.1, 237.8, 245,
305 251.5, 257.1, 262.3, 268.2, 274, 280.4, 286.7, 292.4, 297.9, 302.9,
306 308.5, 312.2, 313.1, 313.3},
307 {187.4, 184.5, 173.3, 166.1, 165.4, 167.8, 169.6, 173.6, 179.6,
308 187.9, 198.9, 210, 220.5, 229.2, 235.7, 239.9, 241.8, 241.6, 239.6,
309 235.8, 229.4, 218.6, 200.9, 175.9, 149.4, 129.4, 118.3, 113.1,
310 110.8, 109.7, 109.3, 109.4, 109.7, 110, 110.2, 110.4, 110.5, 110.7,
311 111, 111.4, 111.8, 112.1, 112.3, 112.7, 113.2, 113.9, 115, 116.4,
312 117.9, 120.4, 124.1, 130.9, 142.2, 159.6, 179.6, 198.5, 212.9,
313 224.2, 232.7, 239.1, 243.8, 247.7, 252.4, 257.3, 263.2, 269.5,
314 275.4, 281.1, 286.3, 292, 296.3, 298.2, 298.8},
315 {166, 166.4, 155.7, 148.3, 147.1, 149, 152.1, 157, 163.6, 172.4,
316 185.3, 199.2, 212.6, 224, 233.2, 239.6, 243.3, 244.6, 243.6, 240.3,
317 233.9, 222.6, 203.7, 177, 149.5, 129.7, 119, 114, 111.7, 110.7,
318 110.3, 110.3, 110.6, 110.9, 111.1, 111.3, 111.5, 111.6, 111.9,
319 112.2, 112.5, 112.6, 112.8, 113, 113.4, 114, 115.1, 116.5, 118.3,
320 120.9, 124.4, 130.2, 139.4, 154.6, 173.8, 193.1, 208.1, 220.4,
321 230.1, 238.2, 244.7, 249.5, 254.5, 259.3, 264.5, 269.4, 273.7,
322 278.2, 282.6, 287.4, 290.9, 292.5, 293},
323 {171.9, 172.8, 166.2, 162.3, 161.4, 162.5, 165.2, 169.6, 175.3,
324 183.1, 193.8, 205.9, 218.3, 229.6, 238.5, 244.3, 246.9, 246.7,
325 243.8, 238.4, 230.2, 217.9, 199.6, 174.9, 148.9, 129.8, 119.5,
326 114.8, 112.3, 110.9, 110.3, 110.1, 110.2, 110.3, 110.4, 110.5,
327 110.6, 110.8, 111, 111.4, 111.8, 112, 112.2, 112.4, 112.9, 113.6,
328 114.7, 116.3, 118.4, 121.9, 127.1, 136.1, 149.8, 168.4, 186.9,
329 203.3, 217, 229.1, 238.7, 247, 254, 259.3, 264.3, 268.3, 272.5,
330 276.6, 280.4, 284.4, 288.4, 293.3, 297.2, 298.7, 299.1},
331 {191.6, 192.2, 189, 188.1, 190.2, 193.7, 197.8, 202.9, 208.5,
332 215.6, 224.2, 233.1, 241.2, 247.3, 250.8, 251.3, 248.9, 244.2,
333 237.3, 228.4, 217.2, 202.9, 184.5, 162.5, 140.7, 124.8, 116.2,
334 111.8, 109.4, 107.9, 107, 106.7, 106.6, 106.6, 106.7, 106.7,
335 106.8, 107, 107.4, 108, 108.7, 109.3, 109.8, 110.4, 111.2,
336 112.4, 114.2, 116.9, 121.1, 127.9, 139.3, 155.2, 173.6, 190.7,
337 206.1, 220.1, 232.3, 243, 251.8, 259.2, 265.7, 270.6, 275.3,
338 279.3, 283.3, 286.9, 289.7, 292.8, 296.1, 300.5, 303.9, 304.8,
339 305.1},
340 {241.5, 239.6, 236.8, 237.4, 239.4, 242.3, 244.2, 246.4, 249.2,
341 253.6, 258.6, 262.7, 264.8, 264.2, 260.6, 254.1, 245.5, 235.3,
342 223.9, 211.7, 198.3, 183.1, 165.6, 147.1, 130.5, 118.7, 111.9,
343 108.1, 105.8, 104.3, 103.4, 102.8, 102.5, 102.4, 102.5, 102.5,
344 102.5, 102.7, 103.1, 103.8, 104.6, 105.4, 106.1, 107, 108.2,
345 109.9, 112.8, 117.5, 126, 140.4, 161, 181.9, 201.2, 216.8, 230.4,
346 241.8, 251.4, 259.9, 266.9, 272.8, 277.4, 280.4, 282.9, 284.6,
347 286.1, 287.4, 288.3, 289.5, 290.9, 294.2, 296.9, 297.5, 297.6},
348 {301.2, 300.3, 296.6, 295.4, 295, 294.3, 291.2, 287.4, 284.9, 284.7,
349 284.1, 281.5, 277.1, 270.4, 261.7, 250.6, 237.6, 223.1, 207.9, 192,
350 175.8, 158.8, 142.1, 127.6, 116.8, 109.9, 106, 103.6, 102.1, 101.1,
351 100.4, 99.96, 99.6, 99.37, 99.32, 99.32, 99.31, 99.46, 99.77, 100.2,
352 100.7, 101.3, 101.8, 102.7, 104.1, 106.8, 111.9, 121, 136.7, 160,
353 186.9, 209.9, 228.1, 241.2, 251.5, 259.5, 265.7, 270.9, 274.8, 278,
354 280.3, 281.8, 283, 283.3, 283.7, 283.8, 283, 282.2, 281.2, 281.4,
355 281.7, 281.1, 281.2}
356 };
357 memcpy(clim->tropo, tropo, sizeof(clim->tropo));
358
359 /* Get range... */
360 double tropomin = 1e99, tropomax = -1e99;
361 for (int it = 0; it < clim->tropo_ntime; it++)
362 for (int iy = 0; iy < clim->tropo_nlat; iy++) {
363 tropomin = MIN(tropomin, clim->tropo[it][iy]);
364 tropomax = MAX(tropomax, clim->tropo[it][iy]);
365 }
366
367 /* Write info... */
368 LOG(2, "Number of time steps: %d", clim->tropo_ntime);
369 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
370 clim->tropo_time[0], clim->tropo_time[1],
371 clim->tropo_time[clim->tropo_ntime - 1]);
372 LOG(2, "Number of latitudes: %d", clim->tropo_nlat);
373 LOG(2, "Latitudes: %g, %g ... %g deg",
374 clim->tropo_lat[0], clim->tropo_lat[1],
375 clim->tropo_lat[clim->tropo_nlat - 1]);
376 LOG(2, "Tropopause altitude range: %g ... %g hPa", Z(tropomax),
377 Z(tropomin));
378 LOG(2, "Tropopause pressure range: %g ... %g hPa", tropomin, tropomax);
379}
380
381/*****************************************************************************/
382
383double clim_ts(
384 const clim_ts_t *ts,
385 const double t) {
386
387 /* Interpolate... */
388 if (t <= ts->time[0])
389 return ts->vmr[0];
390 else if (t >= ts->time[ts->ntime - 1])
391 return ts->vmr[ts->ntime - 1];
392 else {
393 int idx = locate_irr(ts->time, ts->ntime, t);
394 return LIN(ts->time[idx], ts->vmr[idx],
395 ts->time[idx + 1], ts->vmr[idx + 1], t);
396 }
397}
398
399/*****************************************************************************/
400
401double clim_zm(
402 const clim_zm_t *zm,
403 const double t,
404 const double lat,
405 const double p) {
406
407 /* Get seconds since begin of year... */
408 double sec = FMOD(t, 365.25 * 86400.);
409 while (sec < 0)
410 sec += 365.25 * 86400.;
411
412 /* Check pressure range... */
413 double p_help = p;
414 if (p < zm->p[zm->np - 1])
415 p_help = zm->p[zm->np - 1];
416 else if (p > zm->p[0])
417 p_help = zm->p[0];
418
419 /* Check latitude range... */
420 double lat_help = lat;
421 if (lat < zm->lat[0])
422 lat_help = zm->lat[0];
423 else if (lat > zm->lat[zm->nlat - 1])
424 lat_help = zm->lat[zm->nlat - 1];
425
426 /* Get indices... */
427 const int isec = locate_irr(zm->time, zm->ntime, sec);
428 const int ilat = locate_reg(zm->lat, zm->nlat, lat_help);
429 const int ip = locate_irr(zm->p, zm->np, p_help);
430
431 /* Interpolate climatology data... */
432 double aux00 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat],
433 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat], p_help);
434 double aux01 = LIN(zm->p[ip], zm->vmr[isec][ip][ilat + 1],
435 zm->p[ip + 1], zm->vmr[isec][ip + 1][ilat + 1], p_help);
436 double aux10 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat],
437 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat], p_help);
438 double aux11 = LIN(zm->p[ip], zm->vmr[isec + 1][ip][ilat + 1],
439 zm->p[ip + 1], zm->vmr[isec + 1][ip + 1][ilat + 1],
440 p_help);
441 aux00 = LIN(zm->lat[ilat], aux00, zm->lat[ilat + 1], aux01, lat_help);
442 aux11 = LIN(zm->lat[ilat], aux10, zm->lat[ilat + 1], aux11, lat_help);
443 aux00 = LIN(zm->time[isec], aux00, zm->time[isec + 1], aux11, sec);
444
445 return MAX(aux00, 0.0);
446}
447
448/*****************************************************************************/
449
450#ifdef CMS
451void compress_cms(
452 const ctl_t *ctl,
453 const char *varname,
454 float *array,
455 const size_t nx,
456 const size_t ny,
457 const size_t np,
458 const int decompress,
459 FILE *inout) {
460
461 /* Set lon-lat grid... */
462 const size_t nxy = nx * ny;
463 double lon[EX], lat[EY];
464 for (size_t ix = 0; ix < nx; ix++)
465 lon[ix] = 360. * (double) ix / ((double) nx - 1.);
466 for (size_t iy = 0; iy < ny; iy++)
467 lat[iy] = -(180. * (double) iy / ((double) ny - 1.) - 90.);
468
469 /* Set multiscale parameters... */
470 const char domain[] = "[0.0, 360.0]x[-90.0, 90.0]";
471 const int Nd0_x = 6;
472 const int Nd0_y = 3;
473 const int max_level_grid = 7;
474 cms_param_t *cms_param
475 = cms_set_parameters(nx, ny, max_level_grid, Nd0_x, Nd0_y, domain);
476
477 /* Init... */
478 double cr = 0, t_coars = 0, t_eval = 0;
479
480 /* Read compressed stream and decompress array... */
481 if (decompress) {
482
483 /* Loop over levels... */
484 for (size_t ip = 0; ip < np; ip++) {
485
486 /* Initialize multiscale module... */
487 cms_module_t *cms_ptr = cms_init(cms_param);
488
489 /* Read binary data... */
490 cms_sol_t *cms_sol;
491 if (ctl->met_cms_zstd == 1)
492 cms_sol = cms_read_zstd_sol(cms_ptr, inout);
493 else
494 cms_sol = cms_read_sol(cms_ptr, inout);
495
496 /* Evaluate... */
497#pragma omp parallel for default(shared)
498 for (size_t ix = 0; ix < nx; ix++)
499 for (size_t iy = 0; iy < ny; iy++) {
500 double val;
501 const double x[] = { lon[ix], lat[iy] };
502 cms_eval(cms_ptr, cms_sol, x, &val);
503 array[ARRAY_3D(ix, iy, ny, ip, np)] = (float) val;
504 }
505
506 /* Calculate mean compression ratio... */
507 cr += cms_compression_rate(cms_ptr, cms_sol) / (double) np;
508
509 /* Free... */
510 cms_delete_sol(cms_sol);
511 cms_delete_module(cms_ptr);
512 }
513
514 /* Write info... */
515 LOG(2, "Read 3-D variable: %s (cms, RATIO= %g)", varname, cr);
516 }
517
518 /* Compress array and output compressed stream... */
519 else {
520
521 /* Init... */
522 cms_module_t *cms_ptr[EP];
523 cms_sol_t *cms_sol[EP];
524
525 /* Loop over batches... */
526 const size_t dip = (ctl->met_cms_batch <= 0
527 ? (size_t) omp_get_max_threads()
528 : (size_t) ctl->met_cms_batch);
529 for (size_t ip0 = 0; ip0 < np; ip0 += dip) {
530
531 /* Measure time... */
532 double t0 = omp_get_wtime();
533
534 /* Loop over levels... */
535#pragma omp parallel for default(shared)
536 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
537
538 /* Allocate... */
539 float *tmp_arr;
540 ALLOC(tmp_arr, float,
541 nxy);
542
543 /* Copy level data... */
544 for (size_t ix = 0; ix < nx; ++ix)
545 for (size_t iy = 0; iy < ny; ++iy)
546 tmp_arr[ARRAY_2D(ix, iy, ny)] =
547 array[ARRAY_3D(ix, iy, ny, ip, np)];
548
549 /* Initialize multiscale module... */
550 cms_ptr[ip] = cms_init(cms_param);
551
552 /* Create solution pointer... */
553 cms_sol[ip] = cms_read_arr(cms_ptr[ip], tmp_arr, lon, lat, nx, ny);
554
555 /* Set eps threshold value... */
556 if (strcasecmp(varname, "Z") == 0)
557 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_z);
558 else if (strcasecmp(varname, "T") == 0)
559 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_t);
560 else if (strcasecmp(varname, "U") == 0)
561 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_u);
562 else if (strcasecmp(varname, "V") == 0)
563 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_v);
564 else if (strcasecmp(varname, "W") == 0)
565 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_w);
566 else if (strcasecmp(varname, "PV") == 0)
567 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_pv);
568 else if (strcasecmp(varname, "H2O") == 0)
569 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_h2o);
570 else if (strcasecmp(varname, "O3") == 0)
571 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_o3);
572 else if (strcasecmp(varname, "LWC") == 0)
573 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_lwc);
574 else if (strcasecmp(varname, "RWC") == 0)
575 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_rwc);
576 else if (strcasecmp(varname, "IWC") == 0)
577 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_iwc);
578 else if (strcasecmp(varname, "SWC") == 0)
579 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_swc);
580 else if (strcasecmp(varname, "CC") == 0)
581 cms_set_eps(cms_ptr[ip], ctl->met_cms_eps_cc);
582 else
583 ERRMSG("Variable name unknown!");
584
585 /* Coarsening... */
586 cms_coarsening(cms_ptr[ip], cms_sol[ip],
587 (unsigned int) ctl->met_cms_heur);
588
589 /* Free... */
590 free(tmp_arr);
591 }
592
593 /* Measure time... */
594 t_coars += (omp_get_wtime() - t0);
595
596 /* Loop over levels... */
597 for (size_t ip = ip0; ip < MIN(ip0 + dip, np); ip++) {
598
599 /* Allocate... */
600 double *tmp_cms, *tmp_org, *tmp_diff;
601 ALLOC(tmp_cms, double,
602 nxy);
603 ALLOC(tmp_org, double,
604 nxy);
605 ALLOC(tmp_diff, double,
606 nxy);
607
608 /* Measure time... */
609 t0 = omp_get_wtime();
610
611 /* Evaluate... */
612#pragma omp parallel for default(shared)
613 for (size_t ix = 0; ix < nx; ix++)
614 for (size_t iy = 0; iy < ny; iy++) {
615 const size_t idx = ARRAY_2D(ix, iy, ny);
616 const double x[] = { lon[ix], lat[iy] };
617 cms_eval(cms_ptr[ip], cms_sol[ip], x, &tmp_cms[idx]);
618 tmp_org[idx] = array[ARRAY_3D(ix, iy, ny, ip, np)];
619 tmp_diff[idx] = tmp_cms[idx] - tmp_org[idx];
620 }
621
622 /* Measure time... */
623 t_eval += (omp_get_wtime() - t0);
624
625 /* Write info... */
626 LOG(2,
627 "cmultiscale: var= %s / lev= %lu / ratio= %g / rho= %g"
628 " / mean= %g / sd= %g / min= %g / max= %g", varname, ip,
629 cms_compression_rate(cms_ptr[ip], cms_sol[ip]),
630 gsl_stats_correlation(tmp_cms, 1, tmp_org, 1, nxy),
631 gsl_stats_mean(tmp_diff, 1, nxy), gsl_stats_sd(tmp_diff, 1, nxy),
632 gsl_stats_min(tmp_diff, 1, nxy), gsl_stats_max(tmp_diff, 1, nxy));
633
634 /* Calculate mean compression ratio... */
635 cr += cms_compression_rate(cms_ptr[ip], cms_sol[ip]) / (double) np;
636
637 /* Save binary data... */
638 if (ctl->met_cms_zstd == 1)
639 cms_save_zstd_sol(cms_sol[ip], inout, 3);
640 else
641 cms_save_sol(cms_sol[ip], inout);
642
643 /* Free... */
644 cms_delete_sol(cms_sol[ip]);
645 cms_delete_module(cms_ptr[ip]);
646 free(tmp_cms);
647 free(tmp_org);
648 free(tmp_diff);
649 }
650 }
651
652 /* Write info... */
653 LOG(2, "Write 3-D variable: %s"
654 " (cms, RATIO= %g, T_COARS= %g s, T_EVAL= %g s)",
655 varname, cr, t_coars, t_eval);
656 }
657
658 /* Free... */
659 cms_delete_param(cms_param);
660}
661#endif
662
663/*****************************************************************************/
664
666 const char *varname,
667 float *array,
668 const size_t nxy,
669 const size_t nz,
670 const int decompress,
671 FILE *inout) {
672
673 double min[EP], max[EP], off[EP], scl[EP];
674
675 unsigned short *sarray;
676
677 /* Allocate... */
678 ALLOC(sarray, unsigned short,
679 nxy * nz);
680
681 /* Read compressed stream and decompress array... */
682 if (decompress) {
683
684 /* Write info... */
685 LOG(2, "Read 3-D variable: %s (pck, RATIO= %g)",
686 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
687
688 /* Read data... */
689 FREAD(&scl, double,
690 nz,
691 inout);
692 FREAD(&off, double,
693 nz,
694 inout);
695 FREAD(sarray, unsigned short,
696 nxy * nz,
697 inout);
698
699 /* Convert to float... */
700#pragma omp parallel for default(shared)
701 for (size_t ixy = 0; ixy < nxy; ixy++)
702 for (size_t iz = 0; iz < nz; iz++)
703 array[ixy * nz + iz]
704 = (float) (sarray[ixy * nz + iz] * scl[iz] + off[iz]);
705 }
706
707 /* Compress array and output compressed stream... */
708 else {
709
710 /* Write info... */
711 LOG(2, "Write 3-D variable: %s (pck, RATIO= %g)",
712 varname, (double) sizeof(float) / (double) sizeof(unsigned short));
713
714 /* Get range... */
715 for (size_t iz = 0; iz < nz; iz++) {
716 min[iz] = array[iz];
717 max[iz] = array[iz];
718 }
719 for (size_t ixy = 1; ixy < nxy; ixy++)
720 for (size_t iz = 0; iz < nz; iz++) {
721 if (array[ixy * nz + iz] < min[iz])
722 min[iz] = array[ixy * nz + iz];
723 if (array[ixy * nz + iz] > max[iz])
724 max[iz] = array[ixy * nz + iz];
725 }
726
727 /* Get offset and scaling factor... */
728 for (size_t iz = 0; iz < nz; iz++) {
729 scl[iz] = (max[iz] - min[iz]) / 65533.;
730 off[iz] = min[iz];
731 }
732
733 /* Convert to short... */
734#pragma omp parallel for default(shared)
735 for (size_t ixy = 0; ixy < nxy; ixy++)
736 for (size_t iz = 0; iz < nz; iz++)
737 if (scl[iz] != 0)
738 sarray[ixy * nz + iz] = (unsigned short)
739 ((array[ixy * nz + iz] - off[iz]) / scl[iz] + .5);
740 else
741 sarray[ixy * nz + iz] = 0;
742
743 /* Write data... */
744 FWRITE(&scl, double,
745 nz,
746 inout);
747 FWRITE(&off, double,
748 nz,
749 inout);
750 FWRITE(sarray, unsigned short,
751 nxy * nz,
752 inout);
753 }
754
755 /* Free... */
756 free(sarray);
757}
758
759/*****************************************************************************/
760
761#ifdef ZFP
762void compress_zfp(
763 const char *varname,
764 float *array,
765 const int nx,
766 const int ny,
767 const int nz,
768 const int precision,
769 const double tolerance,
770 const int decompress,
771 FILE *inout) {
772
773 /* Allocate meta data for the 3D array a[nz][ny][nx]... */
774 const zfp_type type = zfp_type_float;
775 zfp_field *field =
776 zfp_field_3d(array, type, (uint) nx, (uint) ny, (uint) nz);
777
778 /* Allocate meta data for a compressed stream... */
779 zfp_stream *zfp = zfp_stream_open(NULL);
780
781 /* Set compression mode... */
782 int actual_prec = 0;
783 double actual_tol = 0;
784 if (precision > 0)
785 actual_prec = (int) zfp_stream_set_precision(zfp, (uint) precision);
786 else if (tolerance > 0)
787 actual_tol = zfp_stream_set_accuracy(zfp, tolerance);
788 else
789 ERRMSG("Set precision or tolerance!");
790
791 /* Allocate buffer for compressed data... */
792 const size_t bufsize = zfp_stream_maximum_size(zfp, field);
793 void *buffer = malloc(bufsize);
794
795 /* Associate bit stream with allocated buffer... */
796 bitstream *stream = stream_open(buffer, bufsize);
797 zfp_stream_set_bit_stream(zfp, stream);
798 zfp_stream_rewind(zfp);
799
800 /* Read compressed stream and decompress array... */
801 size_t zfpsize;
802 if (decompress) {
803 FREAD(&zfpsize, size_t,
804 1,
805 inout);
806 if (fread(buffer, 1, zfpsize, inout) != zfpsize)
807 ERRMSG("Error while reading zfp data!");
808 if (!zfp_decompress(zfp, field)) {
809 ERRMSG("Decompression failed!");
810 }
811 LOG(2, "Read 3-D variable: %s "
812 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
813 varname, actual_prec, actual_tol,
814 ((double) (nx * ny * nz)) / (double) zfpsize);
815 }
816
817 /* Compress array and output compressed stream... */
818 else {
819 zfpsize = zfp_compress(zfp, field);
820 if (!zfpsize) {
821 ERRMSG("Compression failed!");
822 } else {
823 FWRITE(&zfpsize, size_t,
824 1,
825 inout);
826 if (fwrite(buffer, 1, zfpsize, inout) != zfpsize)
827 ERRMSG("Error while writing zfp data!");
828 }
829 LOG(2, "Write 3-D variable: %s "
830 "(zfp, PREC= %d, TOL= %g, RATIO= %g)",
831 varname, actual_prec, actual_tol,
832 ((double) (nx * ny * nz)) / (double) zfpsize);
833 }
834
835 /* Free... */
836 zfp_field_free(field);
837 zfp_stream_close(zfp);
838 stream_close(stream);
839 free(buffer);
840}
841#endif
842
843/*****************************************************************************/
844
845#ifdef ZSTD
846void compress_zstd(
847 const char *varname,
848 float *array,
849 const size_t n,
850 const int decompress,
851 const int level,
852 FILE *inout) {
853
854 /* Get buffer sizes... */
855 const size_t uncomprLen = n * sizeof(float);
856 size_t comprLen = ZSTD_compressBound(uncomprLen);
857 size_t compsize;
858
859 /* Allocate... */
860 char *compr = (char *) calloc((uint) comprLen, 1);
861 char *uncompr = (char *) array;
862
863 /* Read compressed stream and decompress array... */
864 if (decompress) {
865 FREAD(&comprLen, size_t,
866 1,
867 inout);
868 if (fread(compr, 1, comprLen, inout) != comprLen)
869 ERRMSG("Error while reading zstd data!");
870 compsize = ZSTD_decompress(uncompr, uncomprLen, compr, comprLen);
871 if (ZSTD_isError(compsize)) {
872 ERRMSG("Decompression failed!");
873 }
874 LOG(2, "Read 3-D variable: %s (zstd, RATIO= %g)",
875 varname, ((double) uncomprLen) / (double) comprLen)
876 }
877
878 /* Compress array and output compressed stream... */
879 else {
880 compsize = ZSTD_compress(compr, comprLen, uncompr, uncomprLen, level);
881 if (ZSTD_isError(compsize)) {
882 ERRMSG("Compression failed!");
883 } else {
884 FWRITE(&compsize, size_t,
885 1,
886 inout);
887 if (fwrite(compr, 1, compsize, inout) != compsize)
888 ERRMSG("Error while writing zstd data!");
889 }
890 LOG(2, "Write 3-D variable: %s (zstd, RATIO= %g)",
891 varname, ((double) uncomprLen) / (double) compsize);
892 }
893
894 /* Free... */
895 free(compr);
896}
897#endif
898
899/*****************************************************************************/
900
902 const int year,
903 const int mon,
904 const int day,
905 int *doy) {
906
907 const int
908 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
909 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
910
911 /* Get day of year... */
912 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
913 *doy = d0l[mon - 1] + day - 1;
914 else
915 *doy = d0[mon - 1] + day - 1;
916}
917
918/*****************************************************************************/
919
921 const int year,
922 const int doy,
923 int *mon,
924 int *day) {
925
926 const int
927 d0[12] = { 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 },
928 d0l[12] = { 1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336 };
929
930 int i;
931
932 /* Get month and day... */
933 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {
934 for (i = 11; i > 0; i--)
935 if (d0l[i] <= doy)
936 break;
937 *mon = i + 1;
938 *day = doy - d0l[i] + 1;
939 } else {
940 for (i = 11; i > 0; i--)
941 if (d0[i] <= doy)
942 break;
943 *mon = i + 1;
944 *day = doy - d0[i] + 1;
945 }
946}
947
948/*****************************************************************************/
949
951 double *fcReal,
952 double *fcImag,
953 const int n) {
954
955 double data[2 * EX];
956
957 /* Check size... */
958 if (n > EX)
959 ERRMSG("Too many data points!");
960
961 /* Allocate... */
962 gsl_fft_complex_wavetable *wavetable =
963 gsl_fft_complex_wavetable_alloc((size_t) n);
964 gsl_fft_complex_workspace *workspace =
965 gsl_fft_complex_workspace_alloc((size_t) n);
966
967 /* Set data (real, complex)... */
968 for (int i = 0; i < n; i++) {
969 data[2 * i] = fcReal[i];
970 data[2 * i + 1] = fcImag[i];
971 }
972
973 /* Calculate FFT... */
974 gsl_fft_complex_forward(data, 1, (size_t) n, wavetable, workspace);
975
976 /* Copy data... */
977 for (int i = 0; i < n; i++) {
978 fcReal[i] = data[2 * i];
979 fcImag[i] = data[2 * i + 1];
980 }
981
982 /* Free... */
983 gsl_fft_complex_wavetable_free(wavetable);
984 gsl_fft_complex_workspace_free(workspace);
985}
986
987/*****************************************************************************/
988
990 const double z,
991 const double lon,
992 const double lat,
993 double *x) {
994
995 const double radius = z + RE;
996 const double latrad = DEG2RAD(lat);
997 const double lonrad = DEG2RAD(lon);
998 const double coslat = cos(latrad);
999
1000 x[0] = radius * coslat * cos(lonrad);
1001 x[1] = radius * coslat * sin(lonrad);
1002 x[2] = radius * sin(latrad);
1003}
1004
1005/*****************************************************************************/
1006
1008 const ctl_t *ctl,
1009 const double t,
1010 const int direct,
1011 const char *metbase,
1012 const double dt_met,
1013 char *filename) {
1014
1015 char repl[LEN];
1016
1017 double t6, r;
1018
1019 int year, mon, day, hour, min, sec;
1020
1021 /* Round time to fixed intervals... */
1022 if (direct == -1)
1023 t6 = floor(t / dt_met) * dt_met;
1024 else
1025 t6 = ceil(t / dt_met) * dt_met;
1026
1027 /* Decode time... */
1028 jsec2time(t6, &year, &mon, &day, &hour, &min, &sec, &r);
1029
1030 /* Set filename of MPTRAC meteo files... */
1031 if (ctl->met_clams == 0) {
1032 if (ctl->met_type == 0)
1033 sprintf(filename, "%s_YYYY_MM_DD_HH.nc", metbase);
1034 else if (ctl->met_type == 1)
1035 sprintf(filename, "%s_YYYY_MM_DD_HH.bin", metbase);
1036 else if (ctl->met_type == 2)
1037 sprintf(filename, "%s_YYYY_MM_DD_HH.pck", metbase);
1038 else if (ctl->met_type == 3)
1039 sprintf(filename, "%s_YYYY_MM_DD_HH.zfp", metbase);
1040 else if (ctl->met_type == 4)
1041 sprintf(filename, "%s_YYYY_MM_DD_HH.zstd", metbase);
1042 else if (ctl->met_type == 5)
1043 sprintf(filename, "%s_YYYY_MM_DD_HH.cms", metbase);
1044 sprintf(repl, "%d", year);
1045 get_met_replace(filename, "YYYY", repl);
1046 sprintf(repl, "%02d", mon);
1047 get_met_replace(filename, "MM", repl);
1048 sprintf(repl, "%02d", day);
1049 get_met_replace(filename, "DD", repl);
1050 sprintf(repl, "%02d", hour);
1051 get_met_replace(filename, "HH", repl);
1052 }
1053
1054 /* Set filename of CLaMS meteo files... */
1055 else {
1056 sprintf(filename, "%s_YYMMDDHH.nc", metbase);
1057 sprintf(repl, "%d", year);
1058 get_met_replace(filename, "YYYY", repl);
1059 sprintf(repl, "%02d", year % 100);
1060 get_met_replace(filename, "YY", repl);
1061 sprintf(repl, "%02d", mon);
1062 get_met_replace(filename, "MM", repl);
1063 sprintf(repl, "%02d", day);
1064 get_met_replace(filename, "DD", repl);
1065 sprintf(repl, "%02d", hour);
1066 get_met_replace(filename, "HH", repl);
1067 }
1068}
1069
1070/*****************************************************************************/
1071
1073 char *orig,
1074 char *search,
1075 char *repl) {
1076
1077 char buffer[LEN];
1078
1079 /* Iterate... */
1080 for (int i = 0; i < 3; i++) {
1081
1082 /* Replace sub-string... */
1083 char *ch;
1084 if (!(ch = strstr(orig, search)))
1085 return;
1086 strncpy(buffer, orig, (size_t) (ch - orig));
1087 buffer[ch - orig] = 0;
1088 sprintf(buffer + (ch - orig), "%s%s", repl, ch + strlen(search));
1089 orig[0] = 0;
1090 strcpy(orig, buffer);
1091 }
1092}
1093
1094/*****************************************************************************/
1095
1097 const int met_tropo,
1098 ctl_t *ctl,
1099 clim_t *clim,
1100 met_t *met,
1101 const double *lons,
1102 const int nx,
1103 const double *lats,
1104 const int ny,
1105 double *pt,
1106 double *zt,
1107 double *tt,
1108 double *qt,
1109 double *o3t,
1110 double *ps,
1111 double *zs) {
1112
1114
1115 ctl->met_tropo = met_tropo;
1116 read_met_tropo(ctl, clim, met);
1117#pragma omp parallel for default(shared) private(ci,cw)
1118 for (int ix = 0; ix < nx; ix++)
1119 for (int iy = 0; iy < ny; iy++) {
1120 intpol_met_space_2d(met, met->pt, lons[ix], lats[iy],
1121 &pt[iy * nx + ix], ci, cw, 1);
1122 intpol_met_space_2d(met, met->ps, lons[ix], lats[iy],
1123 &ps[iy * nx + ix], ci, cw, 0);
1124 intpol_met_space_2d(met, met->zs, lons[ix], lats[iy],
1125 &zs[iy * nx + ix], ci, cw, 0);
1126 intpol_met_space_3d(met, met->z, pt[iy * nx + ix], lons[ix],
1127 lats[iy], &zt[iy * nx + ix], ci, cw, 1);
1128 intpol_met_space_3d(met, met->t, pt[iy * nx + ix], lons[ix],
1129 lats[iy], &tt[iy * nx + ix], ci, cw, 0);
1130 intpol_met_space_3d(met, met->h2o, pt[iy * nx + ix], lons[ix],
1131 lats[iy], &qt[iy * nx + ix], ci, cw, 0);
1132 intpol_met_space_3d(met, met->o3, pt[iy * nx + ix], lons[ix],
1133 lats[iy], &o3t[iy * nx + ix], ci, cw, 0);
1134 }
1135}
1136
1137/*****************************************************************************/
1138
1140 const double *lons,
1141 const int nlon,
1142 const double *lats,
1143 const int nlat,
1144 const double lon,
1145 const double lat,
1146 double *lon2,
1147 double *lat2) {
1148
1149 /* Check longitude... */
1150 *lon2 = FMOD(lon, 360.);
1151 if (*lon2 < lons[0])
1152 *lon2 += 360;
1153 else if (*lon2 > lons[nlon - 1])
1154 *lon2 -= 360;
1155
1156 /* Check latitude... */
1157 *lat2 = lat;
1158 if (lats[0] < lats[nlat - 1])
1159 *lat2 = MIN(MAX(*lat2, lats[0]), lats[nlat - 1]);
1160 else
1161 *lat2 = MIN(MAX(*lat2, lats[nlat - 1]), lats[0]);
1162}
1163
1164/*****************************************************************************/
1165
1167 const met_t *met0,
1168 float heights0[EX][EY][EP],
1169 float array0[EX][EY][EP],
1170 const met_t *met1,
1171 float heights1[EX][EY][EP],
1172 float array1[EX][EY][EP],
1173 const double ts,
1174 const double height,
1175 const double lon,
1176 const double lat,
1177 double *var,
1178 int *ci,
1179 double *cw,
1180 const int init) {
1181
1182 if (init) {
1183
1184 /* Check longitude and latitude... */
1185 double lon2, lat2;
1186 intpol_check_lon_lat(met0->lon, met0->nx, met0->lat, met0->ny, lon, lat,
1187 &lon2, &lat2);
1188
1189 /* Get horizontal indizes... */
1190 ci[0] = locate_irr(met0->lon, met0->nx, lon2);
1191 ci[1] = locate_irr(met0->lat, met0->ny, lat2);
1192
1193 /* Locate the vertical indizes for each edge of the column... */
1194 int ind[2][4];
1195 locate_vert(heights0, met0->npl, ci[0], ci[1], height, ind[0]);
1196 locate_vert(heights1, met1->npl, ci[0], ci[1], height, ind[1]);
1197
1198 /* Find minimum and maximum indizes... */
1199 ci[2] = ind[0][0];
1200 int k_max = ind[0][0];
1201 for (int i = 0; i < 2; i++)
1202 for (int j = 0; j < 4; j++) {
1203 if (ci[2] > ind[i][j])
1204 ci[2] = ind[i][j];
1205 if (k_max < ind[i][j])
1206 k_max = ind[i][j];
1207 }
1208
1209 /* Get weighting factors for time, longitude and latitude... */
1210 cw[3] = (ts - met0->time) / (met1->time - met0->time);
1211 cw[0] = (lon2 - met0->lon[ci[0]]) /
1212 (met0->lon[ci[0] + 1] - met0->lon[ci[0]]);
1213 cw[1] = (lat2 - met0->lat[ci[1]]) /
1214 (met0->lat[ci[1] + 1] - met0->lat[ci[1]]);
1215
1216 /* Interpolate in time at the lowest level... */
1217 double height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2]]
1218 - heights0[ci[0]][ci[1]][ci[2]])
1219 + heights0[ci[0]][ci[1]][ci[2]];
1220 double height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2]]
1221 - heights0[ci[0]][ci[1] + 1][ci[2]])
1222 + heights0[ci[0]][ci[1] + 1][ci[2]];
1223 double height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2]]
1224 - heights0[ci[0] + 1][ci[1]][ci[2]])
1225 + heights0[ci[0] + 1][ci[1]][ci[2]];
1226 double height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2]]
1227 - heights0[ci[0] + 1][ci[1] + 1][ci[2]])
1228 + heights0[ci[0] + 1][ci[1] + 1][ci[2]];
1229
1230 /* Interpolate in latitude direction... */
1231 double height0 = cw[1] * (height01 - height00) + height00;
1232 double height1 = cw[1] * (height11 - height10) + height10;
1233
1234 /* Interpolate in longitude direction... */
1235 double height_bot = cw[0] * (height1 - height0) + height0;
1236
1237 /* Interpolate in time at the upper level... */
1238 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1239 - heights0[ci[0]][ci[1]][ci[2] + 1])
1240 + heights0[ci[0]][ci[1]][ci[2] + 1];
1241 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1242 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1243 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1244 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1245 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1246 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1247 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1248 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1249 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1250
1251 /* Interpolate in latitude direction... */
1252 height0 = cw[1] * (height01 - height00) + height00;
1253 height1 = cw[1] * (height11 - height10) + height10;
1254
1255 /* Interpolate in longitude direction... */
1256 double height_top = cw[0] * (height1 - height0) + height0;
1257
1258 /* Search at higher levels if height is not in box... */
1259 while (((heights0[0][0][0] > heights0[0][0][1]) &&
1260 ((height_bot <= height) || (height_top > height))
1261 && (height_bot >= height) && (ci[2] < k_max))
1262 ||
1263 ((heights0[0][0][0] < heights0[0][0][1]) &&
1264 ((height_bot >= height) || (height_top < height))
1265 && (height_bot <= height) && (ci[2] < k_max))
1266 ) {
1267
1268 ci[2]++;
1269 height_bot = height_top;
1270
1271 /* Interpolate in time at the next level... */
1272 height00 = cw[3] * (heights1[ci[0]][ci[1]][ci[2] + 1]
1273 - heights0[ci[0]][ci[1]][ci[2] + 1])
1274 + heights0[ci[0]][ci[1]][ci[2] + 1];
1275 height01 = cw[3] * (heights1[ci[0]][ci[1] + 1][ci[2] + 1]
1276 - heights0[ci[0]][ci[1] + 1][ci[2] + 1])
1277 + heights0[ci[0]][ci[1] + 1][ci[2] + 1];
1278 height10 = cw[3] * (heights1[ci[0] + 1][ci[1]][ci[2] + 1]
1279 - heights0[ci[0] + 1][ci[1]][ci[2] + 1])
1280 + heights0[ci[0] + 1][ci[1]][ci[2] + 1];
1281 height11 = cw[3] * (heights1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1282 - heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1283 + heights0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1284
1285 /* Interpolate in latitude direction... */
1286 height0 = cw[1] * (height01 - height00) + height00;
1287 height1 = cw[1] * (height11 - height10) + height10;
1288
1289 /* Interpolate in longitude direction... */
1290 height_top = cw[0] * (height1 - height0) + height0;
1291 }
1292
1293 /* Get vertical weighting factors... */
1294 cw[2] = (height - height_bot)
1295 / (height_top - height_bot);
1296 }
1297
1298 /* Calculate the needed array values... */
1299 double array000 = cw[3] * (array1[ci[0]][ci[1]][ci[2]]
1300 - array0[ci[0]][ci[1]][ci[2]])
1301 + array0[ci[0]][ci[1]][ci[2]];
1302 double array100 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2]]
1303 - array0[ci[0] + 1][ci[1]][ci[2]])
1304 + array0[ci[0] + 1][ci[1]][ci[2]];
1305 double array010 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2]]
1306 - array0[ci[0]][ci[1] + 1][ci[2]])
1307 + array0[ci[0]][ci[1] + 1][ci[2]];
1308 double array110 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2]]
1309 - array0[ci[0] + 1][ci[1] + 1][ci[2]])
1310 + array0[ci[0] + 1][ci[1] + 1][ci[2]];
1311 double array001 = cw[3] * (array1[ci[0]][ci[1]][ci[2] + 1]
1312 - array0[ci[0]][ci[1]][ci[2] + 1])
1313 + array0[ci[0]][ci[1]][ci[2] + 1];
1314 double array101 = cw[3] * (array1[ci[0] + 1][ci[1]][ci[2] + 1]
1315 - array0[ci[0] + 1][ci[1]][ci[2] + 1])
1316 + array0[ci[0] + 1][ci[1]][ci[2] + 1];
1317 double array011 = cw[3] * (array1[ci[0]][ci[1] + 1][ci[2] + 1]
1318 - array0[ci[0]][ci[1] + 1][ci[2] + 1])
1319 + array0[ci[0]][ci[1] + 1][ci[2] + 1];
1320 double array111 = cw[3] * (array1[ci[0] + 1][ci[1] + 1][ci[2] + 1]
1321 - array0[ci[0] + 1][ci[1] + 1][ci[2] + 1])
1322 + array0[ci[0] + 1][ci[1] + 1][ci[2] + 1];
1323
1324 double array00 = cw[0] * (array100 - array000) + array000;
1325 double array10 = cw[0] * (array110 - array010) + array010;
1326 double array01 = cw[0] * (array101 - array001) + array001;
1327 double array11 = cw[0] * (array111 - array011) + array011;
1328
1329 double aux0 = cw[1] * (array10 - array00) + array00;
1330 double aux1 = cw[1] * (array11 - array01) + array01;
1331
1332 /* Interpolate vertically... */
1333 *var = cw[2] * (aux1 - aux0) + aux0;
1334}
1335
1336/*****************************************************************************/
1337
1339 const met_t *met,
1340 float array[EX][EY][EP],
1341 const double p,
1342 const double lon,
1343 const double lat,
1344 double *var,
1345 int *ci,
1346 double *cw,
1347 const int init) {
1348
1349 /* Initialize interpolation... */
1350 if (init) {
1351
1352 /* Check longitude and latitude... */
1353 double lon2, lat2;
1354 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1355 &lon2, &lat2);
1356
1357 /* Get interpolation indices... */
1358 ci[0] = locate_irr(met->p, met->np, p);
1359 ci[1] = locate_reg(met->lon, met->nx, lon2);
1360 ci[2] = locate_irr(met->lat, met->ny, lat2);
1361
1362 /* Get interpolation weights... */
1363 cw[0] = (met->p[ci[0] + 1] - p)
1364 / (met->p[ci[0] + 1] - met->p[ci[0]]);
1365 cw[1] = (met->lon[ci[1] + 1] - lon2)
1366 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1367 cw[2] = (met->lat[ci[2] + 1] - lat2)
1368 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1369 }
1370
1371 /* Interpolate vertically... */
1372 double aux00 =
1373 cw[0] * (array[ci[1]][ci[2]][ci[0]] - array[ci[1]][ci[2]][ci[0] + 1])
1374 + array[ci[1]][ci[2]][ci[0] + 1];
1375 double aux01 =
1376 cw[0] * (array[ci[1]][ci[2] + 1][ci[0]] -
1377 array[ci[1]][ci[2] + 1][ci[0] + 1])
1378 + array[ci[1]][ci[2] + 1][ci[0] + 1];
1379 double aux10 =
1380 cw[0] * (array[ci[1] + 1][ci[2]][ci[0]] -
1381 array[ci[1] + 1][ci[2]][ci[0] + 1])
1382 + array[ci[1] + 1][ci[2]][ci[0] + 1];
1383 double aux11 =
1384 cw[0] * (array[ci[1] + 1][ci[2] + 1][ci[0]] -
1385 array[ci[1] + 1][ci[2] + 1][ci[0] + 1])
1386 + array[ci[1] + 1][ci[2] + 1][ci[0] + 1];
1387
1388 /* Interpolate horizontally... */
1389 aux00 = cw[2] * (aux00 - aux01) + aux01;
1390 aux11 = cw[2] * (aux10 - aux11) + aux11;
1391 *var = cw[1] * (aux00 - aux11) + aux11;
1392}
1393
1394/*****************************************************************************/
1395
1397 const met_t *met,
1398 float zs[EX][EY][EP],
1399 float array[EX][EY][EP],
1400 const double z,
1401 const double lon,
1402 const double lat,
1403 double *var) {
1404
1405 /* Check longitude and latitude... */
1406 double lon2, lat2;
1407 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat, &lon2,
1408 &lat2);
1409
1410 /* Get horizontal indices... */
1411 const int ix = locate_reg(met->lon, met->nx, lon2);
1412 const int iy = locate_irr(met->lat, met->ny, lat2);
1413
1414 /* Interpolate vertically... */
1415 int iz = locate_irr_float(zs[ix][iy], met->npl, z, 0);
1416 double aux00;
1417 if (z >= zs[ix][iy][iz + 1])
1418 aux00 = array[ix][iy][iz + 1];
1419 else if (z <= zs[ix][iy][iz])
1420 aux00 = array[ix][iy][iz];
1421 else
1422 aux00 = LIN(zs[ix][iy][iz], array[ix][iy][iz],
1423 zs[ix][iy][iz + 1], array[ix][iy][iz + 1], z);
1424
1425 iz = locate_irr_float(zs[ix][iy + 1], met->npl, z, iz);
1426 double aux01;
1427 if (z >= zs[ix][iy + 1][iz + 1])
1428 aux01 = array[ix][iy + 1][iz + 1];
1429 else if (z <= zs[ix][iy + 1][iz])
1430 aux01 = array[ix][iy + 1][iz];
1431 else
1432 aux01 = LIN(zs[ix][iy + 1][iz], array[ix][iy + 1][iz],
1433 zs[ix][iy + 1][iz + 1], array[ix][iy + 1][iz + 1], z);
1434
1435 iz = locate_irr_float(zs[ix + 1][iy], met->npl, z, iz);
1436 double aux10;
1437 if (z >= zs[ix + 1][iy][iz + 1])
1438 aux10 = array[ix + 1][iy][iz + 1];
1439 else if (z <= zs[ix + 1][iy][iz])
1440 aux10 = array[ix + 1][iy][iz];
1441 else
1442 aux10 = LIN(zs[ix + 1][iy][iz], array[ix + 1][iy][iz],
1443 zs[ix + 1][iy][iz + 1], array[ix + 1][iy][iz + 1], z);
1444
1445 iz = locate_irr_float(zs[ix + 1][iy + 1], met->npl, z, iz);
1446 double aux11;
1447 if (z >= zs[ix + 1][iy + 1][iz + 1])
1448 aux11 = array[ix + 1][iy + 1][iz + 1];
1449 else if (z <= zs[ix + 1][iy + 1][iz])
1450 aux11 = array[ix + 1][iy + 1][iz];
1451 else
1452 aux11 = LIN(zs[ix + 1][iy + 1][iz], array[ix + 1][iy + 1][iz],
1453 zs[ix + 1][iy + 1][iz + 1], array[ix + 1][iy + 1][iz + 1], z);
1454
1455 /* Interpolate horizontally... */
1456 double aux0 = LIN(met->lat[iy], aux00, met->lat[iy + 1], aux01, lat2);
1457 double aux1 = LIN(met->lat[iy], aux10, met->lat[iy + 1], aux11, lat2);
1458 *var = LIN(met->lon[ix], aux0, met->lon[ix + 1], aux1, lon2);
1459}
1460
1461/*****************************************************************************/
1462
1464 const met_t *met,
1465 float array[EX][EY],
1466 const double lon,
1467 const double lat,
1468 double *var,
1469 int *ci,
1470 double *cw,
1471 const int init) {
1472
1473 /* Initialize interpolation... */
1474 if (init) {
1475
1476 /* Check longitude and latitude... */
1477 double lon2, lat2;
1478 intpol_check_lon_lat(met->lon, met->nx, met->lat, met->ny, lon, lat,
1479 &lon2, &lat2);
1480
1481 /* Get interpolation indices... */
1482 ci[1] = locate_reg(met->lon, met->nx, lon2);
1483 ci[2] = locate_irr(met->lat, met->ny, lat2);
1484
1485 /* Get interpolation weights... */
1486 cw[1] = (met->lon[ci[1] + 1] - lon2)
1487 / (met->lon[ci[1] + 1] - met->lon[ci[1]]);
1488 cw[2] = (met->lat[ci[2] + 1] - lat2)
1489 / (met->lat[ci[2] + 1] - met->lat[ci[2]]);
1490 }
1491
1492 /* Set variables... */
1493 double aux00 = array[ci[1]][ci[2]];
1494 double aux01 = array[ci[1]][ci[2] + 1];
1495 double aux10 = array[ci[1] + 1][ci[2]];
1496 double aux11 = array[ci[1] + 1][ci[2] + 1];
1497
1498 /* Interpolate horizontally... */
1499 if (isfinite(aux00) && isfinite(aux01)
1500 && isfinite(aux10) && isfinite(aux11)) {
1501 aux00 = cw[2] * (aux00 - aux01) + aux01;
1502 aux11 = cw[2] * (aux10 - aux11) + aux11;
1503 *var = cw[1] * (aux00 - aux11) + aux11;
1504 } else {
1505 if (cw[2] < 0.5) {
1506 if (cw[1] < 0.5)
1507 *var = aux11;
1508 else
1509 *var = aux01;
1510 } else {
1511 if (cw[1] < 0.5)
1512 *var = aux10;
1513 else
1514 *var = aux00;
1515 }
1516 }
1517}
1518
1519/*****************************************************************************/
1520
1522 const met_t *met0,
1523 float array0[EX][EY][EP],
1524 const met_t *met1,
1525 float array1[EX][EY][EP],
1526 const double ts,
1527 const double p,
1528 const double lon,
1529 const double lat,
1530 double *var,
1531 int *ci,
1532 double *cw,
1533 const int init) {
1534
1535 double var0, var1;
1536
1537 /* Spatial interpolation... */
1538 intpol_met_space_3d(met0, array0, p, lon, lat, &var0, ci, cw, init);
1539 intpol_met_space_3d(met1, array1, p, lon, lat, &var1, ci, cw, 0);
1540
1541 /* Get weighting factor... */
1542 const double wt = (met1->time - ts) / (met1->time - met0->time);
1543
1544 /* Interpolate... */
1545 *var = wt * (var0 - var1) + var1;
1546}
1547
1548/*****************************************************************************/
1549
1551 const met_t *met0,
1552 float zs0[EX][EY][EP],
1553 float array0[EX][EY][EP],
1554 const met_t *met1,
1555 float zs1[EX][EY][EP],
1556 float array1[EX][EY][EP],
1557 const double ts,
1558 const double p,
1559 const double lon,
1560 const double lat,
1561 double *var) {
1562
1563 double var0, var1;
1564
1565 /* Spatial interpolation... */
1566 intpol_met_space_3d_ml(met0, zs0, array0, p, lon, lat, &var0);
1567 intpol_met_space_3d_ml(met1, zs1, array1, p, lon, lat, &var1);
1568
1569 /* Interpolate... */
1570 *var = LIN(met0->time, var0, met1->time, var1, ts);
1571}
1572
1573/*****************************************************************************/
1574
1576 const met_t *met0,
1577 float array0[EX][EY],
1578 const met_t *met1,
1579 float array1[EX][EY],
1580 const double ts,
1581 const double lon,
1582 const double lat,
1583 double *var,
1584 int *ci,
1585 double *cw,
1586 const int init) {
1587
1588 double var0, var1;
1589
1590 /* Spatial interpolation... */
1591 intpol_met_space_2d(met0, array0, lon, lat, &var0, ci, cw, init);
1592 intpol_met_space_2d(met1, array1, lon, lat, &var1, ci, cw, 0);
1593
1594 /* Get weighting factor... */
1595 const double wt = (met1->time - ts) / (met1->time - met0->time);
1596
1597 /* Interpolate... */
1598 if (isfinite(var0) && isfinite(var1))
1599 *var = wt * (var0 - var1) + var1;
1600 else if (wt < 0.5)
1601 *var = var1;
1602 else
1603 *var = var0;
1604}
1605
1606/*****************************************************************************/
1607
1609 const double time0,
1610 float array0[EX][EY],
1611 const double time1,
1612 float array1[EX][EY],
1613 const double lons[EX],
1614 const double lats[EY],
1615 const int nlon,
1616 const int nlat,
1617 const double time,
1618 const double lon,
1619 const double lat,
1620 const int method,
1621 double *var,
1622 double *sigma) {
1623
1624 double aux0, aux1, aux00, aux01, aux10, aux11, mean = 0;
1625
1626 int n = 0;
1627
1628 /* Check longitude and latitude... */
1629 double lon2, lat2;
1630 intpol_check_lon_lat(lons, nlon, lats, nlat, lon, lat, &lon2, &lat2);
1631
1632 /* Get indices... */
1633 const int ix = locate_reg(lons, (int) nlon, lon2);
1634 const int iy = locate_irr(lats, (int) nlat, lat2);
1635
1636 /* Calculate standard deviation... */
1637 *sigma = 0;
1638 for (int dx = 0; dx < 2; dx++)
1639 for (int dy = 0; dy < 2; dy++) {
1640 if (isfinite(array0[ix + dx][iy + dy])) {
1641 mean += array0[ix + dx][iy + dy];
1642 *sigma += SQR(array0[ix + dx][iy + dy]);
1643 n++;
1644 }
1645 if (isfinite(array1[ix + dx][iy + dy])) {
1646 mean += array1[ix + dx][iy + dy];
1647 *sigma += SQR(array1[ix + dx][iy + dy]);
1648 n++;
1649 }
1650 }
1651 if (n > 0)
1652 *sigma = sqrt(MAX(*sigma / n - SQR(mean / n), 0.0));
1653
1654 /* Linear interpolation... */
1655 if (method == 1 && isfinite(array0[ix][iy])
1656 && isfinite(array0[ix][iy + 1])
1657 && isfinite(array0[ix + 1][iy])
1658 && isfinite(array0[ix + 1][iy + 1])
1659 && isfinite(array1[ix][iy])
1660 && isfinite(array1[ix][iy + 1])
1661 && isfinite(array1[ix + 1][iy])
1662 && isfinite(array1[ix + 1][iy + 1])) {
1663
1664 aux00 = LIN(lons[ix], array0[ix][iy],
1665 lons[ix + 1], array0[ix + 1][iy], lon2);
1666 aux01 = LIN(lons[ix], array0[ix][iy + 1],
1667 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1668 aux0 = LIN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1669
1670 aux10 = LIN(lons[ix], array1[ix][iy],
1671 lons[ix + 1], array1[ix + 1][iy], lon2);
1672 aux11 = LIN(lons[ix], array1[ix][iy + 1],
1673 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1674 aux1 = LIN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1675
1676 *var = LIN(time0, aux0, time1, aux1, time);
1677 }
1678
1679 /* Nearest neighbor interpolation... */
1680 else {
1681 aux00 = NN(lons[ix], array0[ix][iy],
1682 lons[ix + 1], array0[ix + 1][iy], lon2);
1683 aux01 = NN(lons[ix], array0[ix][iy + 1],
1684 lons[ix + 1], array0[ix + 1][iy + 1], lon2);
1685 aux0 = NN(lats[iy], aux00, lats[iy + 1], aux01, lat2);
1686
1687 aux10 = NN(lons[ix], array1[ix][iy],
1688 lons[ix + 1], array1[ix + 1][iy], lon2);
1689 aux11 = NN(lons[ix], array1[ix][iy + 1],
1690 lons[ix + 1], array1[ix + 1][iy + 1], lon2);
1691 aux1 = NN(lats[iy], aux10, lats[iy + 1], aux11, lat2);
1692
1693 *var = NN(time0, aux0, time1, aux1, time);
1694 }
1695}
1696
1697/*****************************************************************************/
1698
1700 const double jsec,
1701 int *year,
1702 int *mon,
1703 int *day,
1704 int *hour,
1705 int *min,
1706 int *sec,
1707 double *remain) {
1708
1709 struct tm t0, *t1;
1710
1711 t0.tm_year = 100;
1712 t0.tm_mon = 0;
1713 t0.tm_mday = 1;
1714 t0.tm_hour = 0;
1715 t0.tm_min = 0;
1716 t0.tm_sec = 0;
1717
1718 const time_t jsec0 = (time_t) jsec + timegm(&t0);
1719 t1 = gmtime(&jsec0);
1720
1721 *year = t1->tm_year + 1900;
1722 *mon = t1->tm_mon + 1;
1723 *day = t1->tm_mday;
1724 *hour = t1->tm_hour;
1725 *min = t1->tm_min;
1726 *sec = t1->tm_sec;
1727 *remain = jsec - floor(jsec);
1728}
1729
1730/*****************************************************************************/
1731
1733 const double kz[EP],
1734 const double kw[EP],
1735 const int nk,
1736 const double p) {
1737
1738 /* Check number of data points... */
1739 if (nk < 2)
1740 return 1.0;
1741
1742 /* Get altitude... */
1743 const double z = Z(p);
1744
1745 /* Get weighting factor... */
1746 if (z < kz[0])
1747 return kw[0];
1748 else if (z > kz[nk - 1])
1749 return kw[nk - 1];
1750 else {
1751 int idx = locate_irr(kz, nk, z);
1752 return LIN(kz[idx], kw[idx], kz[idx + 1], kw[idx + 1], z);
1753 }
1754}
1755
1756/*****************************************************************************/
1757
1759 const double t,
1760 const double h2o) {
1761
1762 /*
1763 Calculate moist adiabatic lapse rate [K/km] from temperature [K]
1764 and water vapor volume mixing ratio [1].
1765
1766 Reference: https://en.wikipedia.org/wiki/Lapse_rate
1767 */
1768
1769 const double a = RA * SQR(t), r = SH(h2o) / (1. - SH(h2o));
1770
1771 return 1e3 * G0 * (a + LV * r * t) / (CPD * a + SQR(LV) * r * EPS);
1772}
1773
1774/*****************************************************************************/
1775
1777 ctl_t *ctl) {
1778
1779 if (0 == ctl->met_press_level_def) {
1780
1781 ctl->met_np = 138;
1782
1783 const double press[138] = {
1784 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1785 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1786 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1787 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1788 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1789 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1790 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1791 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1792 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1793 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1794 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1795 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1796 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1797 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1798 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1799 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1800 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1801 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1802 1010.8487, 1013.2500, 1044.45
1803 };
1804
1805 for (int ip = 0; ip < ctl->met_np; ip++)
1806 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1807
1808 } else if (1 == ctl->met_press_level_def) {
1809
1810 ctl->met_np = 92;
1811
1812 const double press[92] = {
1813 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1814 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1815 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1816 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1817 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1818 113.6382,
1819 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1820 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1821 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1822 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1823 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1824 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1825 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1826 1007.4431, 1010.8487, 1013.2500, 1044.45
1827 };
1828
1829 for (int ip = 0; ip < ctl->met_np; ip++)
1830 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1831
1832 } else if (2 == ctl->met_press_level_def) {
1833
1834 ctl->met_np = 60;
1835
1836 const double press[60] = {
1837 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1838 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1839 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1840 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1841 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1842 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1843 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1844 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1044.45
1845 };
1846
1847 for (int ip = 0; ip < ctl->met_np; ip++)
1848 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1849
1850 } else if (3 == ctl->met_press_level_def) {
1851
1852 ctl->met_np = 147;
1853
1854 const double press[147] = {
1855 0.0200, 0.0310, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861, 0.2499,
1856 0.3299, 0.4288, 0.5496, 0.6952, 0.8690, 1.0742, 1.3143, 1.5928, 1.9134,
1857 2.2797, 2.6954, 3.1642, 3.6898, 4.2759, 4.9262, 5.6441, 6.4334, 7.2974,
1858 8.2397, 9.2634, 10.3720, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945,
1859 18.9752, 20.7610, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1860 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.1990, 54.5299, 57.9834,
1861 61.5607, 65.2695, 69.1187, 73.1187, 77.2810, 81.6182, 86.1450, 90.8774,
1862 95.8280, 101.0047, 106.4153, 112.0681, 117.9714, 124.1337, 130.5637,
1863 137.2703, 144.2624, 151.5493, 159.1403, 167.0450, 175.2731, 183.8344,
1864 192.7389, 201.9969, 211.6186, 221.6146, 231.9954, 242.7719, 253.9549,
1865 265.5556, 277.5852, 290.0548, 302.9762, 316.3607, 330.2202, 344.5663,
1866 359.4111, 374.7666, 390.6450, 407.0583, 424.0190, 441.5395, 459.6321,
1867 478.3096, 497.5845, 517.4198, 537.7195, 558.3430, 579.1926, 600.1668,
1868 621.1624, 642.0764, 662.8084, 683.2620, 703.3467, 722.9795, 742.0855,
1869 760.5996, 778.4661, 795.6396, 812.0847, 827.7756, 842.6959, 856.8376,
1870 870.2004, 882.7910, 894.6222, 905.7116, 916.0815, 925.7571, 934.7666,
1871 943.1399, 950.9082, 958.1037, 964.7584, 970.9046, 976.5737, 981.7968,
1872 986.6036, 991.0230, 995.0824, 998.8081, 1002.2250, 1005.3562, 1008.2239,
1873 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73, 1028.85,
1874 1031.97,
1875 1035.09, 1038.21, 1041.33, 1044.45
1876 };
1877
1878 for (int ip = 0; ip < ctl->met_np; ip++)
1879 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1880
1881 } else if (4 == ctl->met_press_level_def) {
1882
1883 ctl->met_np = 101;
1884
1885 const double press[101] = {
1886 0.0200, 0.0398, 0.0739, 0.1291, 0.2141, 0.3395, 0.5175, 0.7617,
1887 1.0872, 1.5099, 2.0464, 2.7136, 3.5282, 4.5069, 5.6652, 7.0181,
1888 8.5795, 10.3617, 12.3759, 14.6316, 17.1371, 19.8987, 22.9216, 26.2090,
1889 29.7630, 33.5843, 37.6720, 42.0242, 46.6378, 51.5086, 56.6316, 61.9984,
1890 67.5973, 73.4150, 79.4434, 85.7016, 92.2162, 99.0182, 106.1445,
1891 113.6382,
1892 121.5502, 129.9403, 138.8558, 148.3260, 158.3816, 169.0545, 180.3786,
1893 192.3889, 205.1222, 218.6172, 232.9140, 248.0547, 264.0833, 281.0456,
1894 298.9895, 317.9651, 338.0245, 359.2221, 381.6144, 405.2606, 430.2069,
1895 456.4813, 483.8505, 512.0662, 540.8577, 569.9401, 599.0310, 627.9668,
1896 656.6129, 684.8491, 712.5573, 739.5739, 765.7697, 791.0376, 815.2774,
1897 838.3507, 860.1516, 880.6080, 899.6602, 917.2205, 933.2247, 947.6584,
1898 960.5245, 971.8169, 981.5301, 989.7322, 996.8732, 1002.8013,
1899 1007.4431, 1010.8487, 1013.25, 1016.37, 1019.49, 1022.61, 1025.73,
1900 1028.85, 1031.97,
1901 1035.09, 1038.21, 1041.33, 1044.45
1902 };
1903
1904 for (int ip = 0; ip < ctl->met_np; ip++)
1905 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1906
1907 } else if (5 == ctl->met_press_level_def) {
1908
1909 ctl->met_np = 62;
1910
1911 const double press[62] = {
1912 0.01, 0.1361, 0.2499, 0.4288, 0.6952, 1.0742,
1913 2.2797, 3.1642, 4.2759, 7.2974, 9.2634, 11.5685, 14.2377, 20.761,
1914 24.6577, 33.8174, 39.1149, 51.199, 57.9834, 73.1187, 81.6182,
1915 90.8774, 101.005, 112.068, 124.134, 137.27, 151.549, 167.045, 183.834,
1916 201.997, 221.615, 242.772, 265.556, 290.055, 316.361, 344.566, 374.767,
1917 407.058, 441.539, 478.31, 517.42, 558.343, 600.167, 683.262, 722.979,
1918 760.6, 795.64, 827.776, 856.838, 882.791, 905.712, 925.757, 943.14,
1919 958.104, 972.495, 986.886, 1001.28, 1015.67, 1030.06, 1034.86, 1039.65,
1920 1044.45
1921 };
1922
1923 for (int ip = 0; ip < ctl->met_np; ip++)
1924 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1925
1926 } else if (6 == ctl->met_press_level_def) {
1927
1928 ctl->met_np = 137;
1929
1930 const double press[137] = {
1931 0.01, 0.02, 0.031, 0.0467, 0.0683, 0.0975, 0.1361, 0.1861,
1932 0.2499, 0.3299, 0.4288, 0.5496, 0.6952, 0.869, 1.0742,
1933 1.3143, 1.5928, 1.9134, 2.2797, 2.6954, 3.1642, 3.6898,
1934 4.2759, 4.9262, 5.6441, 6.4334, 7.2974, 8.2397, 9.2634,
1935 10.372, 11.5685, 12.8561, 14.2377, 15.7162, 17.2945, 18.9752,
1936 20.761, 22.6543, 24.6577, 26.7735, 29.0039, 31.3512, 33.8174,
1937 36.4047, 39.1149, 41.9493, 44.9082, 47.9915, 51.199, 54.5299,
1938 57.9834, 61.5607, 65.2695, 69.1187, 73.1187, 77.281, 81.6182,
1939 86.145, 90.8774, 95.828, 101.005, 106.415, 112.068, 117.971,
1940 124.134, 130.564, 137.27, 144.262, 151.549, 159.14, 167.045,
1941 175.273, 183.834, 192.739, 201.997, 211.619, 221.615, 231.995,
1942 242.772, 253.955, 265.556, 277.585, 290.055, 302.976, 316.361,
1943 330.22, 344.566, 359.411, 374.767, 390.645, 407.058, 424.019,
1944 441.539, 459.632, 478.31, 497.584, 517.42, 537.72, 558.343,
1945 579.193, 600.167, 621.162, 642.076, 662.808, 683.262, 703.347,
1946 722.979, 742.086, 760.6, 778.466, 795.64, 812.085, 827.776,
1947 842.696, 856.838, 870.2, 882.791, 894.622, 905.712, 916.081,
1948 925.757, 934.767, 943.14, 950.908, 958.104, 965.299, 972.495,
1949 979.69, 986.886, 994.081, 1001.28, 1008.47, 1015.67, 1022.86,
1950 1030.06, 1037.25, 1044.45
1951 };
1952
1953 for (int ip = 0; ip < ctl->met_np; ip++)
1954 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1955
1956 } else if (7 == ctl->met_press_level_def) {
1957
1958 ctl->met_np = 59;
1959
1960 const double press[59] = {
1961 0.1, 0.2, 0.3843, 0.6365, 0.9564, 1.3448, 1.8058, 2.3478,
1962 2.985, 3.7397, 4.6462, 5.7565, 7.1322, 8.8366, 10.9483,
1963 13.5647, 16.8064, 20.8227, 25.7989, 31.9642, 39.6029, 49.0671,
1964 60.1802, 73.0663, 87.7274, 104.229, 122.614, 142.902, 165.089,
1965 189.147, 215.025, 242.652, 272.059, 303.217, 336.044, 370.407,
1966 406.133, 443.009, 480.791, 519.209, 557.973, 596.777, 635.306,
1967 673.24, 710.263, 746.063, 780.346, 812.83, 843.263, 871.42,
1968 897.112, 920.189, 940.551, 958.148, 975.744, 993.341, 1010.94,
1969 1028.53, 1046.13
1970 };
1971
1972 for (int ip = 0; ip < ctl->met_np; ip++)
1973 ctl->met_p[ctl->met_np - ip - 1] = press[ip];
1974
1975 } else {
1976 ERRMSG("Use 0 for l137, 1 for l91, 2 for l60 or values between 3 and 7.")
1977 }
1978}
1979
1980/*****************************************************************************/
1981
1983 const double *xx,
1984 const int n,
1985 const double x) {
1986
1987 int ilo = 0;
1988 int ihi = n - 1;
1989 int i = (ihi + ilo) >> 1;
1990
1991 if (xx[i] < xx[i + 1])
1992 while (ihi > ilo + 1) {
1993 i = (ihi + ilo) >> 1;
1994 if (xx[i] > x)
1995 ihi = i;
1996 else
1997 ilo = i;
1998 } else
1999 while (ihi > ilo + 1) {
2000 i = (ihi + ilo) >> 1;
2001 if (xx[i] <= x)
2002 ihi = i;
2003 else
2004 ilo = i;
2005 }
2006
2007 return ilo;
2008}
2009
2010/*****************************************************************************/
2011
2013 const float *xx,
2014 const int n,
2015 const double x,
2016 const int ig) {
2017
2018 int ilo = 0;
2019 int ihi = n - 1;
2020 int i = (ihi + ilo) >> 1;
2021
2022 if (x >= xx[ig] && x < xx[ig + 1])
2023 return ig;
2024
2025 if (xx[i] < xx[i + 1])
2026 while (ihi > ilo + 1) {
2027 i = (ihi + ilo) >> 1;
2028 if (xx[i] > x)
2029 ihi = i;
2030 else
2031 ilo = i;
2032 } else
2033 while (ihi > ilo + 1) {
2034 i = (ihi + ilo) >> 1;
2035 if (xx[i] <= x)
2036 ihi = i;
2037 else
2038 ilo = i;
2039 }
2040
2041 return ilo;
2042}
2043
2044/*****************************************************************************/
2045
2047 const double *xx,
2048 const int n,
2049 const double x) {
2050
2051 /* Calculate index... */
2052 const int i = (int) ((x - xx[0]) / (xx[1] - xx[0]));
2053
2054 /* Check range... */
2055 if (i < 0)
2056 return 0;
2057 else if (i > n - 2)
2058 return n - 2;
2059 else
2060 return i;
2061}
2062
2063/*****************************************************************************/
2064
2066 float profiles[EX][EY][EP],
2067 const int np,
2068 const int lon_ap_ind,
2069 const int lat_ap_ind,
2070 const double height_ap,
2071 int *ind) {
2072
2073 ind[0] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind],
2074 np, height_ap, 0);
2075 ind[1] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind],
2076 np, height_ap, ind[0]);
2077 ind[2] = locate_irr_float(profiles[lon_ap_ind][lat_ap_ind + 1],
2078 np, height_ap, ind[1]);
2079 ind[3] = locate_irr_float(profiles[lon_ap_ind + 1][lat_ap_ind + 1],
2080 np, height_ap, ind[2]);
2081}
2082
2083/*****************************************************************************/
2084
2086 const ctl_t *ctl,
2087 const cache_t *cache,
2088 met_t *met0,
2089 met_t *met1,
2090 atm_t *atm) {
2091
2092 /* Set timer... */
2093 SELECT_TIMER("MODULE_ADVECT", "PHYSICS", NVTX_GPU);
2094
2095 /* Use omega vertical velocity... */
2096 if (ctl->advect_vert_coord == 0 || ctl->advect_vert_coord == 2) {
2097
2098 /* Loop over particles... */
2099 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2100
2101 /* Init... */
2103 double dts, u[4], um = 0, v[4], vm = 0, w[4], wm = 0,
2104 x[3] = { 0, 0, 0 };
2105
2106 /* Loop over integration nodes... */
2107 for (int i = 0; i < ctl->advect; i++) {
2108
2109 /* Set position... */
2110 if (i == 0) {
2111 dts = 0.0;
2112 x[0] = atm->lon[ip];
2113 x[1] = atm->lat[ip];
2114 x[2] = atm->p[ip];
2115 } else {
2116 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2117 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2118 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2119 x[2] = atm->p[ip] + dts * w[i - 1];
2120 }
2121 const double tm = atm->time[ip] + dts;
2122
2123 /* Interpolate meteo data on pressure levels... */
2124 if (ctl->advect_vert_coord == 0) {
2125 intpol_met_time_3d(met0, met0->u, met1, met1->u,
2126 tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2127 intpol_met_time_3d(met0, met0->v, met1, met1->v,
2128 tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2129 intpol_met_time_3d(met0, met0->w, met1, met1->w,
2130 tm, x[2], x[0], x[1], &w[i], ci, cw, 0);
2131 }
2132
2133 /* Interpolate meteo data on model levels... */
2134 else {
2135 intpol_met_time_3d_ml(met0, met0->pl, met0->ul,
2136 met1, met1->pl, met1->ul,
2137 tm, x[2], x[0], x[1], &u[i]);
2138 intpol_met_time_3d_ml(met0, met0->pl, met0->vl,
2139 met1, met1->pl, met1->vl,
2140 tm, x[2], x[0], x[1], &v[i]);
2141 intpol_met_time_3d_ml(met0, met0->pl, met0->wl,
2142 met1, met1->pl, met1->wl,
2143 tm, x[2], x[0], x[1], &w[i]);
2144 }
2145
2146 /* Get mean wind... */
2147 double k = 1.0;
2148 if (ctl->advect == 2)
2149 k = (i == 0 ? 0.0 : 1.0);
2150 else if (ctl->advect == 4)
2151 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2152 um += k * u[i];
2153 vm += k * v[i];
2154 wm += k * w[i];
2155 }
2156
2157 /* Set new position... */
2158 atm->time[ip] += cache->dt[ip];
2159 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2160 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2161 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2162 atm->p[ip] += cache->dt[ip] * wm;
2163 }
2164 }
2165
2166 /* Use zetadot vertical velocity... */
2167 else if (ctl->advect_vert_coord == 1) {
2168
2169 /* Loop over particles... */
2170 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2171
2172 /* Convert pressure to zeta... */
2174 intpol_met_4d_coord(met0, met0->pl, met0->zetal, met1,
2175 met1->pl, met1->zetal, atm->time[ip], atm->p[ip],
2176 atm->lon[ip], atm->lat[ip],
2177 &atm->q[ctl->qnt_zeta][ip], ci, cw, 1);
2178
2179 /* Init... */
2180 double dts, u[4], um = 0, v[4], vm = 0, zeta_dot[4],
2181 zeta_dotm = 0, x[3] = { 0, 0, 0 };
2182
2183 /* Loop over integration nodes... */
2184 for (int i = 0; i < ctl->advect; i++) {
2185
2186 /* Set position... */
2187 if (i == 0) {
2188 dts = 0.0;
2189 x[0] = atm->lon[ip];
2190 x[1] = atm->lat[ip];
2191 x[2] = atm->q[ctl->qnt_zeta][ip];
2192 } else {
2193 dts = (i == 3 ? 1.0 : 0.5) * cache->dt[ip];
2194 x[0] = atm->lon[ip] + DX2DEG(dts * u[i - 1] / 1000., atm->lat[ip]);
2195 x[1] = atm->lat[ip] + DY2DEG(dts * v[i - 1] / 1000.);
2196 x[2] = atm->q[ctl->qnt_zeta][ip] + dts * zeta_dot[i - 1];
2197 }
2198 const double tm = atm->time[ip] + dts;
2199
2200 /* Interpolate meteo data... */
2201 intpol_met_4d_coord(met0, met0->zetal, met0->ul, met1, met1->zetal,
2202 met1->ul, tm, x[2], x[0], x[1], &u[i], ci, cw, 1);
2203 intpol_met_4d_coord(met0, met0->zetal, met0->vl, met1, met1->zetal,
2204 met1->vl, tm, x[2], x[0], x[1], &v[i], ci, cw, 0);
2205 intpol_met_4d_coord(met0, met0->zetal, met0->zeta_dotl, met1,
2206 met1->zetal, met1->zeta_dotl, tm, x[2], x[0],
2207 x[1], &zeta_dot[i], ci, cw, 0);
2208
2209 /* Get mean wind... */
2210 double k = 1.0;
2211 if (ctl->advect == 2)
2212 k = (i == 0 ? 0.0 : 1.0);
2213 else if (ctl->advect == 4)
2214 k = (i == 0 || i == 3 ? 1.0 / 6.0 : 2.0 / 6.0);
2215 um += k * u[i];
2216 vm += k * v[i];
2217 zeta_dotm += k * zeta_dot[i];
2218 }
2219
2220 /* Set new position... */
2221 atm->time[ip] += cache->dt[ip];
2222 atm->lon[ip] += DX2DEG(cache->dt[ip] * um / 1000.,
2223 (ctl->advect == 2 ? x[1] : atm->lat[ip]));
2224 atm->lat[ip] += DY2DEG(cache->dt[ip] * vm / 1000.);
2225 atm->q[ctl->qnt_zeta][ip] += cache->dt[ip] * zeta_dotm;
2226
2227 /* Convert zeta to pressure... */
2228 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2229 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2230 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2231 }
2232 }
2233}
2234
2235/*****************************************************************************/
2236
2238 const ctl_t *ctl,
2239 const cache_t *cache,
2240 met_t *met0,
2241 met_t *met1,
2242 atm_t *atm) {
2243
2244 /* Check parameters... */
2245 if (ctl->advect_vert_coord != 1)
2246 return;
2247
2248 /* Set timer... */
2249 SELECT_TIMER("MODULE_ADVECT_INIT", "PHYSICS", NVTX_GPU);
2250
2251 /* Loop over particles... */
2252 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,met0,met1,atm)") {
2253
2254 /* Initialize pressure consistent with zeta... */
2256 intpol_met_4d_coord(met0, met0->zetal, met0->pl, met1, met1->zetal,
2257 met1->pl, atm->time[ip], atm->q[ctl->qnt_zeta][ip],
2258 atm->lon[ip], atm->lat[ip], &atm->p[ip], ci, cw, 1);
2259 }
2260}
2261
2262/*****************************************************************************/
2263
2265 const ctl_t *ctl,
2266 const cache_t *cache,
2267 const clim_t *clim,
2268 met_t *met0,
2269 met_t *met1,
2270 atm_t *atm) {
2271
2272 /* Set timer... */
2273 SELECT_TIMER("MODULE_BOUND_COND", "PHYSICS", NVTX_GPU);
2274
2275 /* Check quantity flags... */
2276 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0 && ctl->qnt_Cccl4
2277 && ctl->qnt_Cccl3f < 0 && ctl->qnt_Cccl2f2 < 0
2278 && ctl->qnt_Cn2o < 0 && ctl->qnt_Csf6 < 0 && ctl->qnt_aoa < 0)
2279 return;
2280
2281 /* Loop over particles... */
2282 PARTICLE_LOOP(0, atm->np, 1,
2283 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2284
2285 /* Check latitude and pressure range... */
2286 if (atm->lat[ip] < ctl->bound_lat0 || atm->lat[ip] > ctl->bound_lat1
2287 || atm->p[ip] > ctl->bound_p0 || atm->p[ip] < ctl->bound_p1)
2288 continue;
2289
2290 /* Check surface layer... */
2291 if (ctl->bound_dps > 0 || ctl->bound_dzs > 0
2292 || ctl->bound_zetas > 0 || ctl->bound_pbl) {
2293
2294 /* Get surface pressure... */
2295 double ps;
2297 INTPOL_2D(ps, 1);
2298
2299 /* Check pressure... */
2300 if (ctl->bound_dps > 0 && atm->p[ip] < ps - ctl->bound_dps)
2301 continue;
2302
2303 /* Check height... */
2304 if (ctl->bound_dzs > 0 && Z(atm->p[ip]) > Z(ps) + ctl->bound_dzs)
2305 continue;
2306
2307 /* Check zeta range... */
2308 if (ctl->bound_zetas > 0) {
2309 double t;
2310 INTPOL_3D(t, 1);
2311 if (ZETA(ps, atm->p[ip], t) > ctl->bound_zetas)
2312 continue;
2313 }
2314
2315 /* Check planetary boundary layer... */
2316 if (ctl->bound_pbl) {
2317 double pbl;
2318 INTPOL_2D(pbl, 0);
2319 if (atm->p[ip] < pbl)
2320 continue;
2321 }
2322 }
2323
2324 /* Set mass and volume mixing ratio... */
2325 if (ctl->qnt_m >= 0 && ctl->bound_mass >= 0)
2326 atm->q[ctl->qnt_m][ip] =
2327 ctl->bound_mass + ctl->bound_mass_trend * atm->time[ip];
2328 if (ctl->qnt_vmr >= 0 && ctl->bound_vmr >= 0)
2329 atm->q[ctl->qnt_vmr][ip] =
2330 ctl->bound_vmr + ctl->bound_vmr_trend * atm->time[ip];
2331
2332 /* Set CFC-10 volume mixing ratio... */
2333 if (ctl->qnt_Cccl4 >= 0 && ctl->clim_ccl4_timeseries[0] != '-')
2334 atm->q[ctl->qnt_Cccl4][ip] = clim_ts(&clim->ccl4, atm->time[ip]);
2335
2336 /* Set CFC-11 volume mixing ratio... */
2337 if (ctl->qnt_Cccl3f >= 0 && ctl->clim_ccl3f_timeseries[0] != '-')
2338 atm->q[ctl->qnt_Cccl3f][ip] = clim_ts(&clim->ccl3f, atm->time[ip]);
2339
2340 /* Set CFC-12 volume mixing ratio... */
2341 if (ctl->qnt_Cccl2f2 >= 0 && ctl->clim_ccl2f2_timeseries[0] != '-')
2342 atm->q[ctl->qnt_Cccl2f2][ip] = clim_ts(&clim->ccl2f2, atm->time[ip]);
2343
2344 /* Set N2O volume mixing ratio... */
2345 if (ctl->qnt_Cn2o >= 0 && ctl->clim_n2o_timeseries[0] != '-')
2346 atm->q[ctl->qnt_Cn2o][ip] = clim_ts(&clim->n2o, atm->time[ip]);
2347
2348 /* Set SF6 volume mixing ratio... */
2349 if (ctl->qnt_Csf6 >= 0 && ctl->clim_sf6_timeseries[0] != '-')
2350 atm->q[ctl->qnt_Csf6][ip] = clim_ts(&clim->sf6, atm->time[ip]);
2351
2352 /* Set age of air... */
2353 if (ctl->qnt_aoa >= 0)
2354 atm->q[ctl->qnt_aoa][ip] = atm->time[ip];
2355 }
2356}
2357
2358/*****************************************************************************/
2359
2361 const ctl_t *ctl,
2362 met_t *met0,
2363 met_t *met1,
2364 atm_t *atm,
2365 const double tt) {
2366
2367 /* Check quantities... */
2368 if (ctl->qnt_m < 0 || ctl->qnt_Cx < 0)
2369 return;
2370 if (ctl->molmass <= 0)
2371 ERRMSG("Molar mass is not defined!");
2372
2373 /* Set timer... */
2374 SELECT_TIMER("MODULE_CHEM_GRID", "PHYSICS", NVTX_GPU);
2375
2376 /* Allocate... */
2377 const int np = atm->np;
2378 const int nz = ctl->chemgrid_nz;
2379 const int nx = ctl->chemgrid_nx;
2380 const int ny = ctl->chemgrid_ny;
2381 const int ngrid = nx * ny * nz;
2382
2383 double *restrict const z = (double *) malloc((size_t) nz * sizeof(double));
2384 double *restrict const press =
2385 (double *) malloc((size_t) nz * sizeof(double));
2386 double *restrict const mass =
2387 (double *) calloc((size_t) ngrid, sizeof(double));
2388 double *restrict const area =
2389 (double *) malloc((size_t) ny * sizeof(double));
2390 double *restrict const lon =
2391 (double *) malloc((size_t) nx * sizeof(double));
2392 double *restrict const lat =
2393 (double *) malloc((size_t) ny * sizeof(double));
2394
2395 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
2396 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
2397 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
2398
2399 /* Set grid box size... */
2400 const double dz = (ctl->chemgrid_z1 - ctl->chemgrid_z0) / nz;
2401 const double dlon = (ctl->chemgrid_lon1 - ctl->chemgrid_lon0) / nx;
2402 const double dlat = (ctl->chemgrid_lat1 - ctl->chemgrid_lat0) / ny;
2403
2404 /* Set vertical coordinates... */
2405#ifdef _OPENACC
2406#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])
2407#pragma acc data present(ctl,met0,met1,atm,ixs,iys,izs,z,press,mass,area,lon,lat)
2408#pragma acc parallel loop independent gang vector
2409#else
2410#pragma omp parallel for default(shared)
2411#endif
2412 for (int iz = 0; iz < nz; iz++) {
2413 z[iz] = ctl->chemgrid_z0 + dz * (iz + 0.5);
2414 press[iz] = P(z[iz]);
2415 }
2416
2417 /* Set time interval for output... */
2418 const double t0 = tt - 0.5 * ctl->dt_mod;
2419 const double t1 = tt + 0.5 * ctl->dt_mod;
2420
2421 /* Get indices... */
2422#ifdef _OPENACC
2423#pragma acc parallel loop independent gang vector
2424#else
2425#pragma omp parallel for default(shared)
2426#endif
2427 for (int ip = 0; ip < np; ip++) {
2428 ixs[ip] = (int) ((atm->lon[ip] - ctl->chemgrid_lon0) / dlon);
2429 iys[ip] = (int) ((atm->lat[ip] - ctl->chemgrid_lat0) / dlat);
2430 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->chemgrid_z0) / dz);
2431 if (atm->time[ip] < t0 || atm->time[ip] > t1
2432 || ixs[ip] < 0 || ixs[ip] >= nx
2433 || iys[ip] < 0 || iys[ip] >= ny || izs[ip] < 0 || izs[ip] >= nz)
2434 izs[ip] = -1;
2435 }
2436
2437 /* Set horizontal coordinates... */
2438#ifdef _OPENACC
2439#pragma acc parallel loop independent gang vector
2440#else
2441#pragma omp parallel for default(shared)
2442#endif
2443 for (int ix = 0; ix < nx; ix++)
2444 lon[ix] = ctl->chemgrid_lon0 + dlon * (ix + 0.5);
2445#ifdef _OPENACC
2446#pragma acc parallel loop independent gang vector
2447#else
2448#pragma omp parallel for default(shared)
2449#endif
2450 for (int iy = 0; iy < ny; iy++) {
2451 lat[iy] = ctl->chemgrid_lat0 + dlat * (iy + 0.5);
2452 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
2453 }
2454
2455 /* Get mass per grid box... */
2456#ifdef _OPENACC
2457#pragma acc parallel loop independent gang vector
2458#endif
2459 for (int ip = 0; ip < np; ip++)
2460 if (izs[ip] >= 0)
2461#ifdef _OPENACC
2462#pragma acc atomic update
2463#endif
2464 mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)]
2465 += atm->q[ctl->qnt_m][ip];
2466
2467 /* Assign grid data to air parcels ... */
2468#ifdef _OPENACC
2469#pragma acc parallel loop independent gang vector
2470#else
2471#pragma omp parallel for default(shared)
2472#endif
2473 for (int ip = 0; ip < np; ip++)
2474 if (izs[ip] >= 0) {
2475
2476 /* Interpolate temperature... */
2477 double temp;
2479 intpol_met_time_3d(met0, met0->t, met1, met1->t, tt, press[izs[ip]],
2480 lon[ixs[ip]], lat[iys[ip]], &temp, ci, cw, 1);
2481
2482 /* Set mass... */
2483 const double m = mass[ARRAY_3D(ixs[ip], iys[ip], ny, izs[ip], nz)];
2484
2485 /* Calculate volume mixing ratio... */
2486 atm->q[ctl->qnt_Cx][ip] = MA / ctl->molmass * m
2487 / (RHO(press[izs[ip]], temp) * area[iys[ip]] * dz * 1e9);
2488 }
2489#ifdef _OPENACC
2490#pragma acc exit data delete(ixs,iys,izs,z,press,mass,area,lon,lat)
2491#endif
2492
2493 /* Free... */
2494 free(mass);
2495 free(lon);
2496 free(lat);
2497 free(area);
2498 free(z);
2499 free(press);
2500 free(ixs);
2501 free(iys);
2502 free(izs);
2503}
2504
2505/*****************************************************************************/
2506
2508 const ctl_t *ctl,
2509 const cache_t *cache,
2510 const clim_t *clim,
2511 met_t *met0,
2512 met_t *met1,
2513 atm_t *atm) {
2514
2515 /* Set timer... */
2516 SELECT_TIMER("MODULE_CHEM_INIT", "PHYSICS", NVTX_GPU);
2517
2518 /* Loop over particles... */
2519 PARTICLE_LOOP(0, atm->np, 0,
2520 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2521
2522 /* Set H2O and O3 using meteo data... */
2524 if (ctl->qnt_Ch2o >= 0) {
2525 double h2o;
2526 INTPOL_3D(h2o, 1);
2527 SET_ATM(qnt_Ch2o, h2o);
2528 }
2529 if (ctl->qnt_Co3 >= 0) {
2530 double o3;
2531 INTPOL_3D(o3, 1);
2532 SET_ATM(qnt_Co3, o3);
2533 }
2534
2535 /* Set radical species... */
2536 SET_ATM(qnt_Coh, clim_oh(ctl, clim, atm->time[ip],
2537 atm->lon[ip], atm->lat[ip], atm->p[ip]));
2538 SET_ATM(qnt_Cho2, clim_zm(&clim->ho2, atm->time[ip],
2539 atm->lat[ip], atm->p[ip]));
2540 SET_ATM(qnt_Ch2o2, clim_zm(&clim->h2o2, atm->time[ip],
2541 atm->lat[ip], atm->p[ip]));
2542 SET_ATM(qnt_Co1d, clim_zm(&clim->o1d, atm->time[ip],
2543 atm->lat[ip], atm->p[ip]));
2544 }
2545}
2546
2547/*****************************************************************************/
2548
2550 const ctl_t *ctl,
2551 cache_t *cache,
2552 met_t *met0,
2553 met_t *met1,
2554 atm_t *atm) {
2555
2556 /* Set timer... */
2557 SELECT_TIMER("MODULE_CONVECTION", "PHYSICS", NVTX_GPU);
2558
2559 /* Create random numbers... */
2560 module_rng(ctl, cache->rs, (size_t) atm->np, 0);
2561
2562 /* Loop over particles... */
2563 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2564
2565 /* Interpolate CAPE... */
2566 double ps;
2568 INTPOL_2D(ps, 1);
2569
2570 /* Initialize pressure range for vertical mixing... */
2571 double pbot = ps, ptop = ps;
2572
2573 /* Mixing in the PBL... */
2574 if (ctl->conv_mix_pbl) {
2575
2576 /* Interpolate PBL... */
2577 double pbl;
2578 INTPOL_2D(pbl, 0);
2579
2580 /* Set pressure range... */
2581 ptop = pbl - ctl->conv_pbl_trans * (ps - pbl);
2582 }
2583
2584 /* Convective mixing... */
2585 if (ctl->conv_cape >= 0) {
2586
2587 /* Interpolate CAPE, CIN, and equilibrium level... */
2588 double cape, cin, pel;
2589 INTPOL_2D(cape, 0);
2590 INTPOL_2D(cin, 0);
2591 INTPOL_2D(pel, 0);
2592
2593 /* Set pressure range... */
2594 if (isfinite(cape) && cape >= ctl->conv_cape
2595 && (ctl->conv_cin <= 0 || (isfinite(cin) && cin >= ctl->conv_cin)))
2596 ptop = GSL_MIN(ptop, pel);
2597 }
2598
2599 /* Apply vertical mixing... */
2600 if (ptop != pbot && atm->p[ip] >= ptop) {
2601
2602 /* Get density range... */
2603 double tbot, ttop;
2604 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2605 pbot, atm->lon[ip], atm->lat[ip], &tbot, ci, cw, 1);
2606 intpol_met_time_3d(met0, met0->t, met1, met1->t, atm->time[ip],
2607 ptop, atm->lon[ip], atm->lat[ip], &ttop, ci, cw, 1);
2608 const double rhobot = pbot / tbot;
2609 const double rhotop = ptop / ttop;
2610
2611 /* Get new density... */
2612 const double rho = rhobot + (rhotop - rhobot) * cache->rs[ip];
2613
2614 /* Get pressure... */
2615 atm->p[ip] = LIN(rhobot, pbot, rhotop, ptop, rho);
2616 }
2617 }
2618}
2619
2620/*****************************************************************************/
2621
2623 const ctl_t *ctl,
2624 const cache_t *cache,
2625 const clim_t *clim,
2626 atm_t *atm) {
2627
2628 /* Set timer... */
2629 SELECT_TIMER("MODULE_DECAY", "PHYSICS", NVTX_GPU);
2630
2631 /* Check quantity flags... */
2632 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2633 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2634
2635 /* Loop over particles... */
2636 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,clim,atm)") {
2637
2638 /* Get weighting factor... */
2639 const double w = tropo_weight(clim, atm, ip);
2640
2641 /* Set lifetime... */
2642 const double tdec = w * ctl->tdec_trop + (1 - w) * ctl->tdec_strat;
2643
2644 /* Calculate exponential decay... */
2645 const double aux = exp(-cache->dt[ip] / tdec);
2646 if (ctl->qnt_m >= 0) {
2647 if (ctl->qnt_mloss_decay >= 0)
2648 atm->q[ctl->qnt_mloss_decay][ip]
2649 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2650 atm->q[ctl->qnt_m][ip] *= aux;
2651 if (ctl->qnt_loss_rate >= 0)
2652 atm->q[ctl->qnt_loss_rate][ip] += 1. / tdec;
2653 }
2654 if (ctl->qnt_vmr >= 0)
2655 atm->q[ctl->qnt_vmr][ip] *= aux;
2656 }
2657}
2658
2659/*****************************************************************************/
2660
2662 const ctl_t *ctl,
2663 cache_t *cache,
2664 met_t *met0,
2665 met_t *met1,
2666 atm_t *atm) {
2667
2668 /* Set timer... */
2669 SELECT_TIMER("MODULE_DIFF_MESO", "PHYSICS", NVTX_GPU);
2670
2671 /* Create random numbers... */
2672 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2673
2674 /* Loop over particles... */
2675 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2676
2677 /* Get indices... */
2678 const int ix = locate_reg(met0->lon, met0->nx, atm->lon[ip]);
2679 const int iy = locate_irr(met0->lat, met0->ny, atm->lat[ip]);
2680 const int iz = locate_irr(met0->p, met0->np, atm->p[ip]);
2681
2682 /* Get standard deviations of local wind data... */
2683 float umean = 0, usig = 0, vmean = 0, vsig = 0, wmean = 0, wsig = 0;
2684 for (int i = 0; i < 2; i++)
2685 for (int j = 0; j < 2; j++)
2686 for (int k = 0; k < 2; k++) {
2687 umean += met0->u[ix + i][iy + j][iz + k];
2688 usig += SQR(met0->u[ix + i][iy + j][iz + k]);
2689 vmean += met0->v[ix + i][iy + j][iz + k];
2690 vsig += SQR(met0->v[ix + i][iy + j][iz + k]);
2691 wmean += met0->w[ix + i][iy + j][iz + k];
2692 wsig += SQR(met0->w[ix + i][iy + j][iz + k]);
2693
2694 umean += met1->u[ix + i][iy + j][iz + k];
2695 usig += SQR(met1->u[ix + i][iy + j][iz + k]);
2696 vmean += met1->v[ix + i][iy + j][iz + k];
2697 vsig += SQR(met1->v[ix + i][iy + j][iz + k]);
2698 wmean += met1->w[ix + i][iy + j][iz + k];
2699 wsig += SQR(met1->w[ix + i][iy + j][iz + k]);
2700 }
2701 usig = usig / 16.f - SQR(umean / 16.f);
2702 usig = (usig > 0 ? sqrtf(usig) : 0);
2703 vsig = vsig / 16.f - SQR(vmean / 16.f);
2704 vsig = (vsig > 0 ? sqrtf(vsig) : 0);
2705 wsig = wsig / 16.f - SQR(wmean / 16.f);
2706 wsig = (wsig > 0 ? sqrtf(wsig) : 0);
2707
2708 /* Set temporal correlations for mesoscale fluctuations... */
2709 const double r = 1 - 2 * fabs(cache->dt[ip]) / ctl->dt_met;
2710 const double r2 = sqrt(1 - r * r);
2711
2712 /* Calculate horizontal mesoscale wind fluctuations... */
2713 if (ctl->turb_mesox > 0) {
2714 cache->uvwp[ip][0] =
2715 (float) (r * cache->uvwp[ip][0] +
2716 r2 * cache->rs[3 * ip] * ctl->turb_mesox * usig);
2717 atm->lon[ip] +=
2718 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2719
2720 cache->uvwp[ip][1] =
2721 (float) (r * cache->uvwp[ip][1] +
2722 r2 * cache->rs[3 * ip + 1] * ctl->turb_mesox * vsig);
2723 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2724 }
2725
2726 /* Calculate vertical mesoscale wind fluctuations... */
2727 if (ctl->turb_mesoz > 0) {
2728 cache->uvwp[ip][2] =
2729 (float) (r * cache->uvwp[ip][2] +
2730 r2 * cache->rs[3 * ip + 2] * ctl->turb_mesoz * wsig);
2731 atm->p[ip] += cache->uvwp[ip][2] * cache->dt[ip];
2732 }
2733 }
2734}
2735
2736/*****************************************************************************/
2737
2739 const ctl_t *ctl,
2740 cache_t *cache,
2741 met_t *met0,
2742 met_t *met1,
2743 atm_t *atm) {
2744
2745 /* Set timer... */
2746 SELECT_TIMER("MODULE_DIFF_PBL", "PHYSICS", NVTX_GPU);
2747
2748 /* Create random numbers... */
2749 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2750
2751 /* Loop over particles... */
2752 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2753
2754 double dsigw_dz = 0.0, sig_u = 0.25, sig_w = 0.1,
2755 tau_u = 300., tau_w = 100.;
2756
2757 /* Get surface and PBL pressure... */
2758 double pbl, ps;
2760 INTPOL_2D(ps, 1);
2761 INTPOL_2D(pbl, 0);
2762
2763 /* Boundary layer... */
2764 if (atm->p[ip] >= pbl) {
2765
2766 /* Calculate heights... */
2767 const double p = MIN(atm->p[ip], ps);
2768 const double zs = Z(ps);
2769 const double z = 1e3 * (Z(p) - zs);
2770 const double zi = 1e3 * (Z(pbl) - zs);
2771 const double zratio = z / zi;
2772
2773 /* Calculate friction velocity... */
2774 double ess, nss, h2o, t;
2775 INTPOL_2D(ess, 0);
2776 INTPOL_2D(nss, 0);
2777 INTPOL_3D(t, 1);
2778 INTPOL_3D(h2o, 0);
2779 const double rho = RHO(p, TVIRT(t, h2o));
2780 const double tau = sqrt(SQR(ess) + SQR(nss));
2781 const double ustar = sqrt(tau / rho);
2782
2783 /* Get surface sensible heat flux... */
2784 double shf;
2785 INTPOL_2D(shf, 1);
2786
2787 /* Stable or neutral conditions... */
2788 if (shf <= 0) {
2789
2790 /* Calcalute turbulent velocity variances... */
2791 sig_u = 1e-2 + 2.0 * ustar * (1.0 - zratio);
2792 sig_w = 1e-2 + 1.3 * ustar * (1.0 - zratio);
2793
2794 /* Calculate derivative dsig_w/dz... */
2795 dsigw_dz = -1.3 * ustar / zi;
2796
2797 /* Calcalute Lagrangian timescales... */
2798 tau_u = 0.07 * zi / sig_u * sqrt(zratio);
2799 tau_w = 0.1 * zi / sig_w * pow(zratio, 0.8);
2800 }
2801
2802 /* Unstable conditions... */
2803 else {
2804
2805 /* Convective velocity... */
2806 const double wstar =
2807 pow(G0 / THETAVIRT(p, t, h2o) * shf / (rho * CPD) * zi, 1. / 3.);
2808
2809 /* Calcalute turbulent velocity variances... */
2810 sig_u = 1e-2
2811 + sqrt(0.4 * SQR(wstar) + (5.0 - 4.0 * zratio) * SQR(ustar));
2812 sig_w = 1e-2 + sqrt(1.2 * SQR(wstar) * (1.0 - 0.9 * zratio)
2813 * pow(zratio, 2.0 / 3.0)
2814 + (1.8 - 1.4 * zratio) * SQR(ustar));
2815
2816 /* Calculate derivative dsig_w/dz... */
2817 dsigw_dz = 0.5 / sig_w / zi * (-1.4 * SQR(ustar) + SQR(wstar)
2818 * (0.8 *
2819 pow(MAX(zratio, 1e-3), -1.0 / 3.0)
2820 - 1.8 * pow(zratio, 2.0 / 3.0)));
2821
2822 /* Calcalute Lagrangian timescales... */
2823 const double C0 = 3.0; // TODO: typically 3...6, NAME model uses 3?
2824 const double eps =
2825 (1.5 - 1.2 * pow(zratio, 1.0 / 3.0)) * SQR(wstar) * wstar / zi
2826 + SQR(ustar) * ustar * (1.0 - 0.8 * zratio) / (KARMAN * z);
2827 tau_u = 2 * SQR(sig_u) / (C0 * eps);
2828 tau_w = 2 * SQR(sig_w) / (C0 * eps);
2829 }
2830 }
2831
2832 /* Set minimum values... */
2833 sig_u = MAX(sig_u, 0.25);
2834 sig_w = MAX(sig_w, 0.1);
2835 tau_u = MAX(tau_u, 300.);
2836 tau_w = MAX(tau_w, 100.);
2837
2838 /* Update perturbations... */
2839 const double ru = exp(-fabs(cache->dt[ip]) / tau_u);
2840 const double ru2 = sqrt(1.0 - SQR(ru));
2841 cache->uvwp[ip][0]
2842 = (float) (cache->uvwp[ip][0] * ru + ru2 * cache->rs[3 * ip]);
2843 cache->uvwp[ip][1]
2844 = (float) (cache->uvwp[ip][1] * ru + ru2 * cache->rs[3 * ip + 1]);
2845
2846 const double rw = exp(-fabs(cache->dt[ip]) / tau_w);
2847 const double rw2 = sqrt(1.0 - SQR(rw));
2848 cache->uvwp[ip][2]
2849 = (float) (cache->uvwp[ip][2] * rw + rw2 * cache->rs[3 * ip + 2]
2850 + sig_w * dsigw_dz * cache->dt[ip]); // TODO: check approx for density correction?
2851
2852 /* Calculate new air parcel position... */
2853 atm->lon[ip] +=
2854 DX2DEG(cache->uvwp[ip][0] * cache->dt[ip] / 1000., atm->lat[ip]);
2855 atm->lat[ip] += DY2DEG(cache->uvwp[ip][1] * cache->dt[ip] / 1000.);
2856 atm->p[ip] +=
2857 DZ2DP(cache->uvwp[ip][2] * cache->dt[ip] / 1000., atm->p[ip]);
2858 }
2859}
2860
2861/*****************************************************************************/
2862
2864 const ctl_t *ctl,
2865 cache_t *cache,
2866 const clim_t *clim,
2867 met_t *met0,
2868 met_t *met1,
2869 atm_t *atm) {
2870
2871 /* Set timer... */
2872 SELECT_TIMER("MODULE_DIFF_TURB", "PHYSICS", NVTX_GPU);
2873
2874 /* Create random numbers... */
2875 module_rng(ctl, cache->rs, 3 * (size_t) atm->np, 1);
2876
2877 /* Loop over particles... */
2878 PARTICLE_LOOP(0, atm->np, 1,
2879 "acc data present(ctl,cache,clim,met0,met1,atm)") {
2880
2881 /* Get PBL and surface pressure... */
2882 double pbl, ps;
2884 INTPOL_2D(pbl, 1);
2885 INTPOL_2D(ps, 0);
2886
2887 /* Get weighting factors... */
2888 const double wpbl = pbl_weight(ctl, atm, ip, pbl, ps);
2889 const double wtrop = tropo_weight(clim, atm, ip) * (1.0 - wpbl);
2890 const double wstrat = 1.0 - wpbl - wtrop;
2891
2892 /* Set diffusivity... */
2893 const double dx = wpbl * ctl->turb_dx_pbl + wtrop * ctl->turb_dx_trop
2894 + wstrat * ctl->turb_dx_strat;
2895 const double dz = wpbl * ctl->turb_dz_pbl + wtrop * ctl->turb_dz_trop
2896 + wstrat * ctl->turb_dz_strat;
2897
2898 /* Horizontal turbulent diffusion... */
2899 if (dx > 0) {
2900 const double sigma = sqrt(2.0 * dx * fabs(cache->dt[ip])) / 1000.;
2901 atm->lon[ip] += DX2DEG(cache->rs[3 * ip] * sigma, atm->lat[ip]);
2902 atm->lat[ip] += DY2DEG(cache->rs[3 * ip + 1] * sigma);
2903 }
2904
2905 /* Vertical turbulent diffusion... */
2906 if (dz > 0) {
2907 const double sigma = sqrt(2.0 * dz * fabs(cache->dt[ip])) / 1000.;
2908 atm->p[ip] += DZ2DP(cache->rs[3 * ip + 2] * sigma, atm->p[ip]);
2909 }
2910 }
2911}
2912
2913/*****************************************************************************/
2914
2916 const ctl_t *ctl,
2917 const cache_t *cache,
2918 met_t *met0,
2919 met_t *met1,
2920 atm_t *atm) {
2921
2922 /* Set timer... */
2923 SELECT_TIMER("MODULE_DRY_DEPO", "PHYSICS", NVTX_GPU);
2924
2925 /* Check quantity flags... */
2926 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2927 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2928
2929 /* Loop over particles... */
2930 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
2931
2932 /* Get surface pressure... */
2933 double ps;
2935 INTPOL_2D(ps, 1);
2936
2937 /* Check whether particle is above the surface layer... */
2938 if (atm->p[ip] < ps - ctl->dry_depo_dp)
2939 continue;
2940
2941 /* Set depth of surface layer... */
2942 const double dz = 1000. * (Z(ps - ctl->dry_depo_dp) - Z(ps));
2943
2944 /* Calculate sedimentation velocity for particles... */
2945 double v_dep;
2946 if (ctl->qnt_rp > 0 && ctl->qnt_rhop > 0) {
2947
2948 /* Get temperature... */
2949 double t;
2950 INTPOL_3D(t, 1);
2951
2952 /* Set deposition velocity... */
2953 v_dep = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
2954 atm->q[ctl->qnt_rhop][ip]);
2955 }
2956
2957 /* Use explicit sedimentation velocity for gases... */
2958 else
2959 v_dep = ctl->dry_depo_vdep;
2960
2961 /* Calculate loss of mass based on deposition velocity... */
2962 const double aux = exp(-cache->dt[ip] * v_dep / dz);
2963 if (ctl->qnt_m >= 0) {
2964 if (ctl->qnt_mloss_dry >= 0)
2965 atm->q[ctl->qnt_mloss_dry][ip]
2966 += atm->q[ctl->qnt_m][ip] * (1 - aux);
2967 atm->q[ctl->qnt_m][ip] *= aux;
2968 if (ctl->qnt_loss_rate >= 0)
2969 atm->q[ctl->qnt_loss_rate][ip] += v_dep / dz;
2970 }
2971 if (ctl->qnt_vmr >= 0)
2972 atm->q[ctl->qnt_vmr][ip] *= aux;
2973 }
2974}
2975
2976/*****************************************************************************/
2977
2979 const ctl_t *ctl,
2980 const cache_t *cache,
2981 const clim_t *clim,
2982 met_t *met0,
2983 met_t *met1,
2984 atm_t *atm) {
2985
2986 /* Set timer... */
2987 SELECT_TIMER("MODULE_H2O2_CHEM", "PHYSICS", NVTX_GPU);
2988
2989 /* Check quantity flags... */
2990 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
2991 ERRMSG("Module needs quantity mass or volume mixing ratio!");
2992
2993 /* Parameter of SO2 correction... */
2994 const double a = 3.12541941e-06;
2995 const double b = -5.72532259e-01;
2996 const double low = pow(1. / a, 1. / b);
2997
2998 /* Loop over particles... */
2999 PARTICLE_LOOP(0, atm->np, 1,
3000 "acc data present(ctl,cache,ctl,met0,met1,atm)") {
3001
3002 /* Check whether particle is inside cloud... */
3003 double lwc, rwc;
3005 INTPOL_3D(lwc, 1);
3006 INTPOL_3D(rwc, 0);
3007 if (!(lwc > 0 || rwc > 0))
3008 continue;
3009
3010 /* Get temperature... */
3011 double t;
3012 INTPOL_3D(t, 0);
3013
3014 /* Get molecular density... */
3015 const double M = MOLEC_DENS(atm->p[ip], t);
3016
3017 /* Reaction rate (Berglen et al., 2004)... */
3018 const double k = 9.1e7 * exp(-29700. / RI * (1. / t - 1. / 298.15)); /* (Maass, 1999), unit: M^(-2) */
3019
3020 /* Henry constant of SO2... */
3021 const double H_SO2 =
3022 1.3e-2 * exp(2900. * (1. / t - 1. / 298.15)) * RI * t;
3023 const double K_1S = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15)); /* unit: mol/L */
3024
3025 /* Henry constant of H2O2... */
3026 const double H_h2o2 =
3027 8.3e2 * exp(7600. * (1. / t - 1. / 298.15)) * RI * t;
3028
3029 /* Correction factor for high SO2 concentration
3030 (if qnt_Cx is defined, the correction is switched on)... */
3031 double cor = 1.0;
3032 if (ctl->qnt_Cx >= 0)
3033 cor = atm->q[ctl->qnt_Cx][ip] >
3034 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3035
3036 const double h2o2 = H_h2o2
3037 * clim_zm(&clim->h2o2, atm->time[ip], atm->lat[ip], atm->p[ip])
3038 * M * cor * 1000. / AVO; /* unit: mol/L */
3039
3040 /* Volume water content in cloud [m^3 m^(-3)]... */
3041 const double rho_air = atm->p[ip] / (RI * t) * MA / 10.;
3042 const double CWC = (lwc + rwc) * rho_air / 1e3;
3043
3044 /* Calculate exponential decay (Rolph et al., 1992)... */
3045 const double rate_coef = k * K_1S * h2o2 * H_SO2 * CWC;
3046 const double aux = exp(-cache->dt[ip] * rate_coef);
3047 if (ctl->qnt_m >= 0) {
3048 if (ctl->qnt_mloss_h2o2 >= 0)
3049 atm->q[ctl->qnt_mloss_h2o2][ip] += atm->q[ctl->qnt_m][ip] * (1 - aux);
3050 atm->q[ctl->qnt_m][ip] *= aux;
3051 if (ctl->qnt_loss_rate >= 0)
3052 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3053 }
3054 if (ctl->qnt_vmr >= 0)
3055 atm->q[ctl->qnt_vmr][ip] *= aux;
3056 }
3057}
3058
3059/*****************************************************************************/
3060
3062 const ctl_t *ctl,
3063 cache_t *cache,
3064 met_t *met0,
3065 met_t *met1,
3066 atm_t *atm) {
3067
3068 double t;
3069
3070 /* Set timer... */
3071 SELECT_TIMER("MODULE_ISOSURF_INIT", "PHYSICS", NVTX_GPU);
3072
3073 /* Save pressure... */
3074 if (ctl->isosurf == 1) {
3075 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,atm)") {
3076 cache->iso_var[ip] = atm->p[ip];
3077 }
3078 }
3079
3080 /* Save density... */
3081 else if (ctl->isosurf == 2) {
3082 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3084 INTPOL_3D(t, 1);
3085 cache->iso_var[ip] = atm->p[ip] / t;
3086 }
3087 }
3088
3089 /* Save potential temperature... */
3090 else if (ctl->isosurf == 3) {
3091 PARTICLE_LOOP(0, atm->np, 0, "acc data present(cache,met0,met1,atm)") {
3093 INTPOL_3D(t, 1);
3094 cache->iso_var[ip] = THETA(atm->p[ip], t);
3095 }
3096 }
3097
3098 /* Read balloon pressure data... */
3099 else if (ctl->isosurf == 4) {
3100
3101 /* Write info... */
3102 LOG(1, "Read balloon pressure data: %s", ctl->balloon);
3103
3104 /* Open file... */
3105 FILE *in;
3106 if (!(in = fopen(ctl->balloon, "r")))
3107 ERRMSG("Cannot open file!");
3108
3109 /* Read pressure time series... */
3110 char line[LEN];
3111 while (fgets(line, LEN, in))
3112 if (sscanf(line, "%lg %lg", &(cache->iso_ts[cache->iso_n]),
3113 &(cache->iso_ps[cache->iso_n])) == 2)
3114 if ((++cache->iso_n) > NP)
3115 ERRMSG("Too many data points!");
3116
3117 /* Check number of points... */
3118 if (cache->iso_n < 1)
3119 ERRMSG("Could not read any data!");
3120
3121 /* Close file... */
3122 fclose(in);
3123
3124 /* Update of cache data on device... */
3125 mptrac_update_device(NULL, cache, NULL, NULL, NULL, NULL);
3126 }
3127}
3128
3129/*****************************************************************************/
3130
3132 const ctl_t *ctl,
3133 const cache_t *cache,
3134 met_t *met0,
3135 met_t *met1,
3136 atm_t *atm) {
3137
3138 /* Set timer... */
3139 SELECT_TIMER("MODULE_ISOSURF", "PHYSICS", NVTX_GPU);
3140
3141 /* Loop over particles... */
3142 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,met1,atm)") {
3143
3144 /* Init... */
3145 double t;
3147
3148 /* Restore pressure... */
3149 if (ctl->isosurf == 1)
3150 atm->p[ip] = cache->iso_var[ip];
3151
3152 /* Restore density... */
3153 else if (ctl->isosurf == 2) {
3154 INTPOL_3D(t, 1);
3155 atm->p[ip] = cache->iso_var[ip] * t;
3156 }
3157
3158 /* Restore potential temperature... */
3159 else if (ctl->isosurf == 3) {
3160 INTPOL_3D(t, 1);
3161 atm->p[ip] = 1000. * pow(cache->iso_var[ip] / t, -1. / 0.286);
3162 }
3163
3164 /* Interpolate pressure... */
3165 else if (ctl->isosurf == 4) {
3166 if (atm->time[ip] <= cache->iso_ts[0])
3167 atm->p[ip] = cache->iso_ps[0];
3168 else if (atm->time[ip] >= cache->iso_ts[cache->iso_n - 1])
3169 atm->p[ip] = cache->iso_ps[cache->iso_n - 1];
3170 else {
3171 int idx = locate_irr(cache->iso_ts, cache->iso_n, atm->time[ip]);
3172 atm->p[ip] = LIN(cache->iso_ts[idx], cache->iso_ps[idx],
3173 cache->iso_ts[idx + 1], cache->iso_ps[idx + 1],
3174 atm->time[ip]);
3175 }
3176 }
3177 }
3178}
3179
3180/*****************************************************************************/
3181
3182#ifdef KPP
3183void module_kpp_chem(
3184 ctl_t *ctl,
3185 cache_t *cache,
3186 clim_t *clim,
3187 met_t *met0,
3188 met_t *met1,
3189 atm_t *atm) {
3190
3191 /* Set timer... */
3192 SELECT_TIMER("MODULE_KPP_CHEM", "PHYSICS", NVTX_GPU);
3193
3194 const int nvar = NVAR, nfix = NFIX, nreact = NREACT;
3195 double rtol[1] = { 1.0e-3 };
3196 double atol[1] = { 1.0 };
3197
3198 /* Loop over particles... */
3199#ifdef _OPENACC
3200#pragma acc data copy(rtol,atol,nvar,nfix,nreact)
3201#endif
3202 PARTICLE_LOOP(0, atm->np, 1,
3203 "acc data present(ctl,cache,clim,met0,met1,atm) ") {
3204
3205 /* Initialize... */
3206 double var[nvar], fix[nfix], rconst[nreact];
3207 for (int i = 0; i < nvar; i++)
3208 var[i] = 0.0;
3209 for (int i = 0; i < nfix; i++)
3210 fix[i] = 0.0;
3211 for (int i = 0; i < nreact; i++)
3212 rconst[i] = 0.0;
3213 kpp_chem_initialize(ctl, clim, met0, met1, atm, var, fix, rconst, ip);
3214
3215 /* Integrate... */
3216 double rpar[20];
3217 int ipar[20];
3218 for (int i = 0; i < 20; i++) {
3219 ipar[i] = 0;
3220 rpar[i] = 0.0;
3221 }
3222 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) */
3223 ipar[1] = 1; /* 0: NVAR-dimentional vector of tolerances; 1:scalar tolerances */
3224 ipar[3] = 4; /* choice of the method:Rodas3 */
3225 Rosenbrock(var, fix, rconst, 0, ctl->dt_kpp,
3226 atol, rtol, &FunTemplate, &JacTemplate, rpar, ipar);
3227
3228 /* Save results.. */
3229 kpp_chem_output2atm(atm, ctl, met0, met1, var, ip);
3230 }
3231}
3232#endif
3233
3234/*****************************************************************************/
3235
3237 const ctl_t *ctl,
3238 const cache_t *cache,
3239 const clim_t *clim,
3240 met_t *met0,
3241 met_t *met1,
3242 atm_t *atm) {
3243
3244 /* Set timer... */
3245 SELECT_TIMER("MODULE_METEO", "PHYSICS", NVTX_GPU);
3246
3247 /* Check quantity flags... */
3248 if (ctl->qnt_tsts >= 0)
3249 if (ctl->qnt_tice < 0 || ctl->qnt_tnat < 0)
3250 ERRMSG("Need T_ice and T_NAT to calculate T_STS!");
3251
3252 /* Loop over particles... */
3253 PARTICLE_LOOP(0, atm->np, 0,
3254 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3255
3256 double ps, ts, zs, us, vs, ess, nss, shf, lsm, sst, pbl, pt, pct, pcb, cl,
3257 plcl, plfc, pel, cape, cin, o3c, pv, t, tt, u, v, w, h2o, h2ot, o3, lwc,
3258 rwc, iwc, swc, cc, z, zt;
3259
3260 /* Interpolate meteo data... */
3262 INTPOL_TIME_ALL(atm->time[ip], atm->p[ip], atm->lon[ip], atm->lat[ip]);
3263
3264 /* Set quantities... */
3265 SET_ATM(qnt_ps, ps);
3266 SET_ATM(qnt_ts, ts);
3267 SET_ATM(qnt_zs, zs);
3268 SET_ATM(qnt_us, us);
3269 SET_ATM(qnt_vs, vs);
3270 SET_ATM(qnt_ess, ess);
3271 SET_ATM(qnt_nss, nss);
3272 SET_ATM(qnt_shf, shf);
3273 SET_ATM(qnt_lsm, lsm);
3274 SET_ATM(qnt_sst, sst);
3275 SET_ATM(qnt_pbl, pbl);
3276 SET_ATM(qnt_pt, pt);
3277 SET_ATM(qnt_tt, tt);
3278 SET_ATM(qnt_zt, zt);
3279 SET_ATM(qnt_h2ot, h2ot);
3280 SET_ATM(qnt_zg, z);
3281 SET_ATM(qnt_p, atm->p[ip]);
3282 SET_ATM(qnt_t, t);
3283 SET_ATM(qnt_rho, RHO(atm->p[ip], t));
3284 SET_ATM(qnt_u, u);
3285 SET_ATM(qnt_v, v);
3286 SET_ATM(qnt_w, w);
3287 SET_ATM(qnt_h2o, h2o);
3288 SET_ATM(qnt_o3, o3);
3289 SET_ATM(qnt_lwc, lwc);
3290 SET_ATM(qnt_rwc, rwc);
3291 SET_ATM(qnt_iwc, iwc);
3292 SET_ATM(qnt_swc, swc);
3293 SET_ATM(qnt_cc, cc);
3294 SET_ATM(qnt_pct, pct);
3295 SET_ATM(qnt_pcb, pcb);
3296 SET_ATM(qnt_cl, cl);
3297 SET_ATM(qnt_plcl, plcl);
3298 SET_ATM(qnt_plfc, plfc);
3299 SET_ATM(qnt_pel, pel);
3300 SET_ATM(qnt_cape, cape);
3301 SET_ATM(qnt_cin, cin);
3302 SET_ATM(qnt_o3c, o3c);
3303 SET_ATM(qnt_hno3,
3304 clim_zm(&clim->hno3, atm->time[ip], atm->lat[ip], atm->p[ip]));
3305 SET_ATM(qnt_oh, clim_oh(ctl, clim, atm->time[ip],
3306 atm->lon[ip], atm->lat[ip], atm->p[ip]));
3307 SET_ATM(qnt_h2o2, clim_zm(&clim->h2o2, atm->time[ip],
3308 atm->lat[ip], atm->p[ip]));
3309 SET_ATM(qnt_ho2, clim_zm(&clim->ho2, atm->time[ip],
3310 atm->lat[ip], atm->p[ip]));
3311 SET_ATM(qnt_o1d, clim_zm(&clim->o1d, atm->time[ip],
3312 atm->lat[ip], atm->p[ip]));
3313 SET_ATM(qnt_vh, sqrt(u * u + v * v));
3314 SET_ATM(qnt_vz, -1e3 * H0 / atm->p[ip] * w);
3315 SET_ATM(qnt_psat, PSAT(t));
3316 SET_ATM(qnt_psice, PSICE(t));
3317 SET_ATM(qnt_pw, PW(atm->p[ip], h2o));
3318 SET_ATM(qnt_sh, SH(h2o));
3319 SET_ATM(qnt_rh, RH(atm->p[ip], t, h2o));
3320 SET_ATM(qnt_rhice, RHICE(atm->p[ip], t, h2o));
3321 SET_ATM(qnt_theta, THETA(atm->p[ip], t));
3322 SET_ATM(qnt_zeta, atm->q[ctl->qnt_zeta][ip]);
3323 SET_ATM(qnt_zeta_d, ZETA(ps, atm->p[ip], t));
3324 SET_ATM(qnt_tvirt, TVIRT(t, h2o));
3325 SET_ATM(qnt_lapse, lapse_rate(t, h2o));
3326 SET_ATM(qnt_pv, pv);
3327 SET_ATM(qnt_tdew, TDEW(atm->p[ip], h2o));
3328 SET_ATM(qnt_tice, TICE(atm->p[ip], h2o));
3329 SET_ATM(qnt_tnat,
3330 nat_temperature(atm->p[ip], h2o,
3331 clim_zm(&clim->hno3, atm->time[ip],
3332 atm->lat[ip], atm->p[ip])));
3333 SET_ATM(qnt_tsts,
3334 0.5 * (atm->q[ctl->qnt_tice][ip] + atm->q[ctl->qnt_tnat][ip]));
3335 }
3336}
3337
3338/*****************************************************************************/
3339
3341 const ctl_t *ctl,
3342 const clim_t *clim,
3343 atm_t *atm,
3344 const double t) {
3345
3346 /* Set timer... */
3347 SELECT_TIMER("MODULE_MIXING", "PHYSICS", NVTX_GPU);
3348
3349 /* Allocate... */
3350 const int np = atm->np;
3351 int *restrict const ixs = (int *) malloc((size_t) np * sizeof(int));
3352 int *restrict const iys = (int *) malloc((size_t) np * sizeof(int));
3353 int *restrict const izs = (int *) malloc((size_t) np * sizeof(int));
3354
3355 /* Set grid box size... */
3356 const double dz = (ctl->mixing_z1 - ctl->mixing_z0) / ctl->mixing_nz;
3357 const double dlon = (ctl->mixing_lon1 - ctl->mixing_lon0) / ctl->mixing_nx;
3358 const double dlat = (ctl->mixing_lat1 - ctl->mixing_lat0) / ctl->mixing_ny;
3359
3360 /* Set time interval... */
3361 const double t0 = t - 0.5 * ctl->dt_mod;
3362 const double t1 = t + 0.5 * ctl->dt_mod;
3363
3364 /* Get indices... */
3365#ifdef _OPENACC
3366#pragma acc enter data create(ixs[0:np],iys[0:np],izs[0:np])
3367#pragma acc data present(ctl,clim,atm,ixs,iys,izs)
3368#pragma acc parallel loop independent gang vector
3369#else
3370#pragma omp parallel for default(shared)
3371#endif
3372 for (int ip = 0; ip < np; ip++) {
3373 ixs[ip] = (int) ((atm->lon[ip] - ctl->mixing_lon0) / dlon);
3374 iys[ip] = (int) ((atm->lat[ip] - ctl->mixing_lat0) / dlat);
3375 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->mixing_z0) / dz);
3376 if (atm->time[ip] < t0 || atm->time[ip] > t1
3377 || ixs[ip] < 0 || ixs[ip] >= ctl->mixing_nx
3378 || iys[ip] < 0 || iys[ip] >= ctl->mixing_ny
3379 || izs[ip] < 0 || izs[ip] >= ctl->mixing_nz)
3380 izs[ip] = -1;
3381 }
3382
3383 /* Calculate interparcel mixing... */
3384 if (ctl->qnt_m >= 0)
3385 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_m);
3386 if (ctl->qnt_vmr >= 0)
3387 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_vmr);
3388 if (ctl->qnt_Ch2o >= 0)
3389 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o);
3390 if (ctl->qnt_Co3 >= 0)
3391 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3);
3392 if (ctl->qnt_Cco >= 0)
3393 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cco);
3394 if (ctl->qnt_Coh >= 0)
3395 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Coh);
3396 if (ctl->qnt_Ch >= 0)
3397 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch);
3398 if (ctl->qnt_Cho2 >= 0)
3399 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cho2);
3400 if (ctl->qnt_Ch2o2 >= 0)
3401 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Ch2o2);
3402 if (ctl->qnt_Co1d >= 0)
3403 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co1d);
3404 if (ctl->qnt_Co3p >= 0)
3405 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Co3p);
3406 if (ctl->qnt_Cccl4 >= 0)
3407 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl4);
3408 if (ctl->qnt_Cccl3f >= 0)
3409 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl3f);
3410 if (ctl->qnt_Cccl2f2 >= 0)
3411 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cccl2f2);
3412 if (ctl->qnt_Cn2o >= 0)
3413 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Cn2o);
3414 if (ctl->qnt_Csf6 >= 0)
3415 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_Csf6);
3416 if (ctl->qnt_aoa >= 0)
3417 module_mixing_help(ctl, clim, atm, ixs, iys, izs, ctl->qnt_aoa);
3418
3419 /* Free... */
3420#ifdef _OPENACC
3421#pragma acc exit data delete(ixs,iys,izs)
3422#endif
3423 free(ixs);
3424 free(iys);
3425 free(izs);
3426}
3427
3428/*****************************************************************************/
3429
3431 const ctl_t *ctl,
3432 const clim_t *clim,
3433 atm_t *atm,
3434 const int *ixs,
3435 const int *iys,
3436 const int *izs,
3437 const int qnt_idx) {
3438
3439 /* Allocate... */
3440 const int np = atm->np;
3441 const int ngrid = ctl->mixing_nx * ctl->mixing_ny * ctl->mixing_nz;
3442 double *restrict const cmean =
3443 (double *) malloc((size_t) ngrid * sizeof(double));
3444 int *restrict const count = (int *) malloc((size_t) ngrid * sizeof(int));
3445
3446 /* Init... */
3447#ifdef _OPENACC
3448#pragma acc enter data create(cmean[0:ngrid],count[0:ngrid])
3449#pragma acc data present(ctl,clim,atm,ixs,iys,izs,cmean,count)
3450#pragma acc parallel loop independent gang vector
3451#else
3452#ifdef __NVCOMPILER
3453#pragma novector
3454#endif
3455#pragma omp parallel for
3456#endif
3457 for (int i = 0; i < ngrid; i++) {
3458 count[i] = 0;
3459 cmean[i] = 0;
3460 }
3461
3462 /* Loop over particles... */
3463#ifdef _OPENACC
3464#pragma acc parallel loop independent gang vector
3465#endif
3466 for (int ip = 0; ip < np; ip++)
3467 if (izs[ip] >= 0) {
3468 int idx = ARRAY_3D
3469 (ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz);
3470#ifdef _OPENACC
3471#pragma acc atomic update
3472#endif
3473 cmean[idx] += atm->q[qnt_idx][ip];
3474#ifdef _OPENACC
3475#pragma acc atomic update
3476#endif
3477 count[idx]++;
3478 }
3479#ifdef _OPENACC
3480#pragma acc parallel loop independent gang vector
3481#else
3482#ifdef __NVCOMPILER
3483#pragma novector
3484#endif
3485#pragma omp parallel for
3486#endif
3487 for (int i = 0; i < ngrid; i++)
3488 if (count[i] > 0)
3489 cmean[i] /= count[i];
3490
3491 /* Calculate interparcel mixing... */
3492#ifdef _OPENACC
3493#pragma acc parallel loop independent gang vector
3494#else
3495#pragma omp parallel for
3496#endif
3497 for (int ip = 0; ip < np; ip++)
3498 if (izs[ip] >= 0) {
3499
3500 /* Set mixing parameter... */
3501 double mixparam = 1.0;
3502 if (ctl->mixing_trop < 1 || ctl->mixing_strat < 1) {
3503 double w = tropo_weight(clim, atm, ip);
3504 mixparam = w * ctl->mixing_trop + (1 - w) * ctl->mixing_strat;
3505 }
3506
3507 /* Adjust quantity... */
3508 atm->q[qnt_idx][ip] +=
3509 (cmean
3510 [ARRAY_3D(ixs[ip], iys[ip], ctl->mixing_ny, izs[ip], ctl->mixing_nz)]
3511 - atm->q[qnt_idx][ip]) * mixparam;
3512 }
3513
3514 /* Free... */
3515#ifdef _OPENACC
3516#pragma acc exit data delete(cmean,count)
3517#endif
3518 free(cmean);
3519 free(count);
3520}
3521
3522/*****************************************************************************/
3523
3525 const ctl_t *ctl,
3526 const cache_t *cache,
3527 const clim_t *clim,
3528 met_t *met0,
3529 met_t *met1,
3530 atm_t *atm) {
3531
3532 /* Set timer... */
3533 SELECT_TIMER("MODULE_OH_CHEM", "PHYSICS", NVTX_GPU);
3534
3535 /* Check quantity flags... */
3536 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
3537 ERRMSG("Module needs quantity mass or volume mixing ratio!");
3538
3539 /* Parameter of SO2 correction... */
3540 const double a = 4.71572206e-08;
3541 const double b = -8.28782867e-01;
3542 const double low = pow(1. / a, 1. / b);
3543
3544 /* Loop over particles... */
3545 PARTICLE_LOOP(0, atm->np, 1,
3546 "acc data present(ctl,cache,clim,met0,met1,atm)") {
3547
3548 /* Get temperature... */
3549 double t;
3551 INTPOL_3D(t, 1);
3552
3553 /* Calculate molecular density... */
3554 const double M = MOLEC_DENS(atm->p[ip], t);
3555
3556 /* Use constant reaction rate... */
3557 double k = NAN;
3558 if (ctl->oh_chem_reaction == 1)
3559 k = ctl->oh_chem[0];
3560
3561 /* Calculate bimolecular reaction rate... */
3562 else if (ctl->oh_chem_reaction == 2)
3563 k = ctl->oh_chem[0] * exp(-ctl->oh_chem[1] / t);
3564
3565 /* Calculate termolecular reaction rate... */
3566 if (ctl->oh_chem_reaction == 3) {
3567
3568 /* Calculate rate coefficient for X + OH + M -> XOH + M
3569 (JPL Publication 19-05) ... */
3570 const double k0 =
3571 ctl->oh_chem[0] * (ctl->oh_chem[1] !=
3572 0 ? pow(298. / t, ctl->oh_chem[1]) : 1.);
3573 const double ki =
3574 ctl->oh_chem[2] * (ctl->oh_chem[3] !=
3575 0 ? pow(298. / t, ctl->oh_chem[3]) : 1.);
3576 const double c = log10(k0 * M / ki);
3577 k = k0 * M / (1. + k0 * M / ki) * pow(0.6, 1. / (1. + c * c));
3578 }
3579
3580 /* Correction factor for high SO2 concentration
3581 (if qnt_Cx is defined, the correction is switched on)... */
3582 double cor = 1;
3583 if (ctl->qnt_Cx >= 0)
3584 cor =
3585 atm->q[ctl->qnt_Cx][ip] >
3586 low ? a * pow(atm->q[ctl->qnt_Cx][ip], b) : 1;
3587
3588 /* Calculate exponential decay... */
3589 const double rate_coef =
3590 k * clim_oh(ctl, clim, atm->time[ip], atm->lon[ip],
3591 atm->lat[ip], atm->p[ip]) * M * cor;
3592 const double aux = exp(-cache->dt[ip] * rate_coef);
3593 if (ctl->qnt_m >= 0) {
3594 if (ctl->qnt_mloss_oh >= 0)
3595 atm->q[ctl->qnt_mloss_oh][ip]
3596 += atm->q[ctl->qnt_m][ip] * (1 - aux);
3597 atm->q[ctl->qnt_m][ip] *= aux;
3598 if (ctl->qnt_loss_rate >= 0)
3599 atm->q[ctl->qnt_loss_rate][ip] += rate_coef;
3600 }
3601 if (ctl->qnt_vmr >= 0)
3602 atm->q[ctl->qnt_vmr][ip] *= aux;
3603 }
3604}
3605
3606/*****************************************************************************/
3607
3609 const cache_t *cache,
3610 met_t *met0,
3611 met_t *met1,
3612 atm_t *atm) {
3613
3614 /* Set timer... */
3615 SELECT_TIMER("MODULE_POSITION", "PHYSICS", NVTX_GPU);
3616
3617 /* Loop over particles... */
3618 PARTICLE_LOOP(0, atm->np, 1, "acc data present(cache,met0,met1,atm)") {
3619
3620 /* Init... */
3621 double ps;
3623
3624 /* Calculate modulo... */
3625 atm->lon[ip] = FMOD(atm->lon[ip], 360.);
3626 atm->lat[ip] = FMOD(atm->lat[ip], 360.);
3627
3628 /* Check latitude... */
3629 while (atm->lat[ip] < -90 || atm->lat[ip] > 90) {
3630 if (atm->lat[ip] > 90) {
3631 atm->lat[ip] = 180 - atm->lat[ip];
3632 atm->lon[ip] += 180;
3633 }
3634 if (atm->lat[ip] < -90) {
3635 atm->lat[ip] = -180 - atm->lat[ip];
3636 atm->lon[ip] += 180;
3637 }
3638 }
3639
3640 /* Check longitude... */
3641 while (atm->lon[ip] < -180)
3642 atm->lon[ip] += 360;
3643 while (atm->lon[ip] >= 180)
3644 atm->lon[ip] -= 360;
3645
3646 /* Check pressure... */
3647 if (atm->p[ip] < met0->p[met0->np - 1]) {
3648 atm->p[ip] = met0->p[met0->np - 1];
3649 } else if (atm->p[ip] > 300.) {
3650 INTPOL_2D(ps, 1);
3651 if (atm->p[ip] > ps)
3652 atm->p[ip] = ps;
3653 }
3654 }
3655}
3656
3657/*****************************************************************************/
3658
3660 const int ntask) {
3661
3662 /* Initialize GSL random number generators... */
3663 gsl_rng_env_setup();
3664 if (omp_get_max_threads() > NTHREADS)
3665 ERRMSG("Too many threads!");
3666 for (int i = 0; i < NTHREADS; i++) {
3667 rng[i] = gsl_rng_alloc(gsl_rng_default);
3668 gsl_rng_set(rng[i], gsl_rng_default_seed
3669 + (long unsigned) (ntask * NTHREADS + i));
3670 }
3671
3672 /* Initialize cuRAND random number generators... */
3673#ifdef CURAND
3674 if (curandCreateGenerator(&rng_curand, CURAND_RNG_PSEUDO_DEFAULT) !=
3675 CURAND_STATUS_SUCCESS)
3676 ERRMSG("Cannot create random number generator!");
3677 if (curandSetPseudoRandomGeneratorSeed(rng_curand, ntask) !=
3678 CURAND_STATUS_SUCCESS)
3679 ERRMSG("Cannot set seed for random number generator!");
3680 if (curandSetStream
3681 (rng_curand,
3682 (cudaStream_t) acc_get_cuda_stream(acc_async_sync)) !=
3683 CURAND_STATUS_SUCCESS)
3684 ERRMSG("Cannot set stream for random number generator!");
3685#endif
3686}
3687
3688/*****************************************************************************/
3689
3691 const ctl_t *ctl,
3692 double *rs,
3693 const size_t n,
3694 const int method) {
3695
3696 /* Use GSL random number generators... */
3697 if (ctl->rng_type == 0) {
3698
3699 /* Uniform distribution... */
3700 if (method == 0) {
3701#pragma omp parallel for default(shared)
3702 for (size_t i = 0; i < n; ++i)
3703 rs[i] = gsl_rng_uniform(rng[omp_get_thread_num()]);
3704 }
3705
3706 /* Normal distribution... */
3707 else if (method == 1) {
3708#pragma omp parallel for default(shared)
3709 for (size_t i = 0; i < n; ++i)
3710 rs[i] = gsl_ran_gaussian_ziggurat(rng[omp_get_thread_num()], 1.0);
3711 }
3712
3713 /* Update of random numbers on device... */
3714#ifdef _OPENACC
3715 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
3716#pragma acc update device(rs[:n])
3717#endif
3718 }
3719
3720 /* Use Squares random number generator (Widynski, 2022)... */
3721 else if (ctl->rng_type == 1) {
3722
3723 /* Set key (don't change this!)... */
3724 const uint64_t key = 0xc8e4fd154ce32f6d;
3725
3726 /* Uniform distribution... */
3727#ifdef _OPENACC
3728#pragma acc data present(rs)
3729#pragma acc parallel loop independent gang vector
3730#else
3731#pragma omp parallel for default(shared)
3732#endif
3733 for (size_t i = 0; i < n + 1; ++i) {
3734 uint64_t r, t, x, y, z;
3735 y = x = (rng_ctr + i) * key;
3736 z = y + key;
3737 x = x * x + y;
3738 x = (x >> 32) | (x << 32);
3739 x = x * x + z;
3740 x = (x >> 32) | (x << 32);
3741 x = x * x + y;
3742 x = (x >> 32) | (x << 32);
3743 t = x = x * x + z;
3744 x = (x >> 32) | (x << 32);
3745 r = t ^ ((x * x + y) >> 32);
3746 rs[i] = (double) r / (double) UINT64_MAX;
3747 }
3748 rng_ctr += n + 1;
3749
3750 /* Normal distribution... */
3751 if (method == 1) {
3752#ifdef _OPENACC
3753#pragma acc parallel loop independent gang vector
3754#else
3755#pragma omp parallel for default(shared)
3756#endif
3757 for (size_t i = 0; i < n; i += 2) {
3758 const double r = sqrt(-2.0 * log(rs[i]));
3759 const double phi = 2.0 * M_PI * rs[i + 1];
3760 rs[i] = r * cosf((float) phi);
3761 rs[i + 1] = r * sinf((float) phi);
3762 }
3763 }
3764 }
3765
3766 /* Use cuRAND random number generators... */
3767 else if (ctl->rng_type == 2) {
3768#ifdef CURAND
3769#pragma acc host_data use_device(rs)
3770 {
3771
3772 /* Uniform distribution... */
3773 if (method == 0) {
3774 if (curandGenerateUniformDouble(rng_curand, rs, (n < 4 ? 4 : n)) !=
3775 CURAND_STATUS_SUCCESS)
3776 ERRMSG("Cannot create random numbers!");
3777 }
3778
3779 /* Normal distribution... */
3780 else if (method == 1) {
3781 if (curandGenerateNormalDouble
3782 (rng_curand, rs, (n < 4 ? 4 : n), 0.0,
3783 1.0) != CURAND_STATUS_SUCCESS)
3784 ERRMSG("Cannot create random numbers!");
3785 }
3786 }
3787#else
3788 ERRMSG("MPTRAC was compiled without cuRAND!");
3789#endif
3790 }
3791}
3792
3793/*****************************************************************************/
3794
3796 const ctl_t *ctl,
3797 const cache_t *cache,
3798 met_t *met0,
3799 met_t *met1,
3800 atm_t *atm) {
3801
3802 /* Set timer... */
3803 SELECT_TIMER("MODULE_SEDI", "PHYSICS", NVTX_GPU);
3804
3805 /* Loop over particles... */
3806 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
3807
3808 /* Get temperature... */
3809 double t;
3811 INTPOL_3D(t, 1);
3812
3813 /* Sedimentation velocity... */
3814 const double v_s = sedi(atm->p[ip], t, atm->q[ctl->qnt_rp][ip],
3815 atm->q[ctl->qnt_rhop][ip]);
3816
3817 /* Calculate pressure change... */
3818 atm->p[ip] += DZ2DP(v_s * cache->dt[ip] / 1000., atm->p[ip]);
3819 }
3820}
3821
3822/*****************************************************************************/
3823
3825 const ctl_t *ctl,
3826 met_t *met0,
3827 atm_t *atm) {
3828
3829 /* Set timer... */
3830 SELECT_TIMER("MODULE_SORT", "PHYSICS", NVTX_GPU);
3831
3832 /* Allocate... */
3833 const int np = atm->np;
3834 double *restrict const a = (double *) malloc((size_t) np * sizeof(double));
3835 int *restrict const p = (int *) malloc((size_t) np * sizeof(int));
3836
3837#ifdef _OPENACC
3838#pragma acc enter data create(a[0:np],p[0:np])
3839#pragma acc data present(ctl,met0,atm,a,p)
3840#endif
3841
3842 /* Get box index... */
3843#ifdef _OPENACC
3844#pragma acc parallel loop independent gang vector
3845#else
3846#pragma omp parallel for default(shared)
3847#endif
3848 for (int ip = 0; ip < np; ip++) {
3849 a[ip] =
3850 (double) ((locate_reg(met0->lon, met0->nx, atm->lon[ip]) * met0->ny +
3851 locate_irr(met0->lat, met0->ny, atm->lat[ip]))
3852 * met0->np + locate_irr(met0->p, met0->np, atm->p[ip]));
3853 p[ip] = ip;
3854 }
3855
3856 /* Sorting... */
3857#ifdef _OPENACC
3858#pragma acc host_data use_device(a,p)
3859#endif
3860#ifdef THRUST
3861 thrustSortWrapper(a, np, p);
3862#else
3863 ERRMSG("MPTRAC was compiled without Thrust library!");
3864#endif
3865
3866 /* Sort data... */
3867 module_sort_help(atm->time, p, np);
3868 module_sort_help(atm->p, p, np);
3869 module_sort_help(atm->lon, p, np);
3870 module_sort_help(atm->lat, p, np);
3871 for (int iq = 0; iq < ctl->nq; iq++)
3872 module_sort_help(atm->q[iq], p, np);
3873
3874 /* Free... */
3875#ifdef _OPENACC
3876#pragma acc exit data delete(a,p)
3877#endif
3878 free(a);
3879 free(p);
3880}
3881
3882/*****************************************************************************/
3883
3885 double *a,
3886 const int *p,
3887 const int np) {
3888
3889 /* Allocate... */
3890 double *restrict const help =
3891 (double *) malloc((size_t) np * sizeof(double));
3892
3893 /* Reordering of array... */
3894#ifdef _OPENACC
3895#pragma acc enter data create(help[0:np])
3896#pragma acc data present(a,p,help)
3897#pragma acc parallel loop independent gang vector
3898#else
3899#pragma omp parallel for default(shared)
3900#endif
3901 for (int ip = 0; ip < np; ip++)
3902 help[ip] = a[p[ip]];
3903#ifdef _OPENACC
3904#pragma acc parallel loop independent gang vector
3905#else
3906#pragma omp parallel for default(shared)
3907#endif
3908 for (int ip = 0; ip < np; ip++)
3909 a[ip] = help[ip];
3910
3911 /* Free... */
3912#ifdef _OPENACC
3913#pragma acc exit data delete(help)
3914#endif
3915 free(help);
3916}
3917
3918/*****************************************************************************/
3919
3921 const ctl_t *ctl,
3922 cache_t *cache,
3923 met_t *met0,
3924 atm_t *atm,
3925 const double t) {
3926
3927 /* Set timer... */
3928 SELECT_TIMER("MODULE_TIMESTEPS", "PHYSICS", NVTX_GPU);
3929
3930 const double latmin = gsl_stats_min(met0->lat, 1, (size_t) met0->ny),
3931 latmax = gsl_stats_max(met0->lat, 1, (size_t) met0->ny);
3932
3933 const int local =
3934 (fabs(met0->lon[met0->nx - 1] - met0->lon[0] - 360.0) >= 0.01);
3935
3936 /* Loop over particles... */
3937 PARTICLE_LOOP(0, atm->np, 0, "acc data present(ctl,cache,met0,atm)") {
3938
3939 /* Set time step for each air parcel... */
3940 if ((ctl->direction * (atm->time[ip] - ctl->t_start) >= 0
3941 && ctl->direction * (atm->time[ip] - ctl->t_stop) <= 0
3942 && ctl->direction * (atm->time[ip] - t) < 0))
3943 cache->dt[ip] = t - atm->time[ip];
3944 else
3945 cache->dt[ip] = 0.0;
3946
3947 /* Check horizontal boundaries of local meteo data... */
3948 if (local && (atm->lon[ip] <= met0->lon[0]
3949 || atm->lon[ip] >= met0->lon[met0->nx - 1]
3950 || atm->lat[ip] <= latmin || atm->lat[ip] >= latmax))
3951 cache->dt[ip] = 0.0;
3952 }
3953}
3954
3955/*****************************************************************************/
3956
3958 ctl_t *ctl,
3959 const atm_t *atm) {
3960
3961 /* Set timer... */
3962 SELECT_TIMER("MODULE_TIMESTEPS_INIT", "PHYSICS", NVTX_GPU);
3963
3964 /* Set start time... */
3965 if (ctl->direction == 1) {
3966 ctl->t_start = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3967 if (ctl->t_stop > 1e99)
3968 ctl->t_stop = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3969 } else {
3970 ctl->t_start = gsl_stats_max(atm->time, 1, (size_t) atm->np);
3971 if (ctl->t_stop > 1e99)
3972 ctl->t_stop = gsl_stats_min(atm->time, 1, (size_t) atm->np);
3973 }
3974
3975 /* Check time interval... */
3976 if (ctl->direction * (ctl->t_stop - ctl->t_start) <= 0)
3977 ERRMSG("Nothing to do! Check T_STOP and DIRECTION!");
3978
3979 /* Round start time... */
3980 if (ctl->direction == 1)
3981 ctl->t_start = floor(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3982 else
3983 ctl->t_start = ceil(ctl->t_start / ctl->dt_mod) * ctl->dt_mod;
3984}
3985
3986/*****************************************************************************/
3987
3989 const ctl_t *ctl,
3990 const cache_t *cache,
3991 const clim_t *clim,
3992 met_t *met0,
3993 met_t *met1,
3994 atm_t *atm) {
3995
3996 /* Set timer... */
3997 SELECT_TIMER("MODULE_TRACER_CHEM", "PHYSICS", NVTX_GPU);
3998
3999 /* Loop over particles... */
4000 PARTICLE_LOOP(0, atm->np, 1,
4001 "acc data present(ctl,cache,clim,met0,met1,atm)") {
4002
4003 /* Get temperature... */
4004 double t;
4006 INTPOL_3D(t, 1);
4007
4008 /* Get molecular density... */
4009 const double M = MOLEC_DENS(atm->p[ip], t);
4010
4011 /* Get total column ozone... */
4012 double o3c;
4013 INTPOL_2D(o3c, 1);
4014
4015 /* Get solar zenith angle... */
4016 const double sza = sza_calc(atm->time[ip], atm->lon[ip], atm->lat[ip]);
4017
4018 /* Get O(1D) volume mixing ratio... */
4019 const double o1d =
4020 clim_zm(&clim->o1d, atm->time[ip], atm->lat[ip], atm->p[ip]);
4021
4022 /* Reactions for CFC-10... */
4023 if (ctl->qnt_Cccl4 >= 0) {
4024 const double K_o1d = ARRHENIUS(3.30e-10, 0, t) * o1d * M;
4025 const double K_hv = clim_photo(clim->photo.ccl4, &(clim->photo),
4026 atm->p[ip], sza, o3c);
4027 atm->q[ctl->qnt_Cccl4][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4028 }
4029
4030 /* Reactions for CFC-11... */
4031 if (ctl->qnt_Cccl3f >= 0) {
4032 const double K_o1d = ARRHENIUS(2.30e-10, 0, t) * o1d * M;
4033 const double K_hv = clim_photo(clim->photo.ccl3f, &(clim->photo),
4034 atm->p[ip], sza, o3c);
4035 atm->q[ctl->qnt_Cccl3f][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4036 }
4037
4038 /* Reactions for CFC-12... */
4039 if (ctl->qnt_Cccl2f2 >= 0) {
4040 const double K_o1d = ARRHENIUS(1.40e-10, -25, t) * o1d * M;
4041 const double K_hv = clim_photo(clim->photo.ccl2f2, &(clim->photo),
4042 atm->p[ip], sza, o3c);
4043 atm->q[ctl->qnt_Cccl2f2][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4044 }
4045
4046 /* Reactions for N2O... */
4047 if (ctl->qnt_Cn2o >= 0) {
4048 const double K_o1d = ARRHENIUS(1.19e-10, -20, t) * o1d * M;
4049 const double K_hv = clim_photo(clim->photo.n2o, &(clim->photo),
4050 atm->p[ip], sza, o3c);
4051 atm->q[ctl->qnt_Cn2o][ip] *= exp(-cache->dt[ip] * (K_hv + K_o1d));
4052 }
4053 }
4054}
4055
4056/*****************************************************************************/
4057
4059 const ctl_t *ctl,
4060 const cache_t *cache,
4061 met_t *met0,
4062 met_t *met1,
4063 atm_t *atm) {
4064
4065 /* Set timer... */
4066 SELECT_TIMER("MODULE_WET_DEPO", "PHYSICS", NVTX_GPU);
4067
4068 /* Check quantity flags... */
4069 if (ctl->qnt_m < 0 && ctl->qnt_vmr < 0)
4070 ERRMSG("Module needs quantity mass or volume mixing ratio!");
4071
4072 /* Loop over particles... */
4073 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,cache,met0,met1,atm)") {
4074
4075 /* Check whether particle is below cloud top... */
4076 double pct;
4078 INTPOL_2D(pct, 1);
4079 if (!isfinite(pct) || atm->p[ip] <= pct)
4080 continue;
4081
4082 /* Get cloud bottom pressure... */
4083 double pcb;
4084 INTPOL_2D(pcb, 0);
4085
4086 /* Estimate precipitation rate (Pisso et al., 2019)... */
4087 double cl;
4088 INTPOL_2D(cl, 0);
4089 const double Is =
4090 pow(1. / ctl->wet_depo_pre[0] * cl, 1. / ctl->wet_depo_pre[1]);
4091 if (Is < 0.01)
4092 continue;
4093
4094 /* Check whether particle is inside or below cloud... */
4095 double lwc, rwc, iwc, swc;
4096 INTPOL_3D(lwc, 1);
4097 INTPOL_3D(rwc, 0);
4098 INTPOL_3D(iwc, 0);
4099 INTPOL_3D(swc, 0);
4100 const int inside = (lwc > 0 || rwc > 0 || iwc > 0 || swc > 0);
4101
4102 /* Get temperature... */
4103 double t;
4104 INTPOL_3D(t, 0);
4105
4106 /* Calculate in-cloud scavenging coefficient... */
4107 double lambda = 0;
4108 if (inside) {
4109
4110 /* Calculate retention factor... */
4111 double eta;
4112 if (t > 273.15)
4113 eta = 1;
4114 else if (t <= 238.15)
4115 eta = ctl->wet_depo_ic_ret_ratio;
4116 else
4117 eta = LIN(273.15, 1, 238.15, ctl->wet_depo_ic_ret_ratio, t);
4118
4119 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4120 if (ctl->wet_depo_ic_a > 0)
4121 lambda = ctl->wet_depo_ic_a * pow(Is, ctl->wet_depo_ic_b) * eta;
4122
4123 /* Use Henry's law for gases... */
4124 else if (ctl->wet_depo_ic_h[0] > 0) {
4125
4126 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4127 double h = ctl->wet_depo_ic_h[0]
4128 * exp(ctl->wet_depo_ic_h[1] * (1. / t - 1. / 298.15));
4129
4130 /* Use effective Henry's constant for SO2
4131 (Berglen, 2004; Simpson, 2012)... */
4132 if (ctl->wet_depo_so2_ph > 0) {
4133 const double H_ion = pow(10., -ctl->wet_depo_so2_ph);
4134 const double K_1 = 1.23e-2 * exp(2.01e3 * (1. / t - 1. / 298.15));
4135 const double K_2 = 6e-8 * exp(1.12e3 * (1. / t - 1. / 298.15));
4136 h *= (1. + K_1 / H_ion + K_1 * K_2 / SQR(H_ion));
4137 }
4138
4139 /* Estimate depth of cloud layer... */
4140 const double dz = 1e3 * (Z(pct) - Z(pcb));
4141
4142 /* Calculate scavenging coefficient... */
4143 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4144 }
4145 }
4146
4147 /* Calculate below-cloud scavenging coefficient... */
4148 else {
4149
4150 /* Calculate retention factor... */
4151 double eta;
4152 if (t > 270)
4153 eta = 1;
4154 else
4155 eta = ctl->wet_depo_bc_ret_ratio;
4156
4157 /* Use exponential dependency for particles (Bakels et al., 2024)... */
4158 if (ctl->wet_depo_bc_a > 0)
4159 lambda = ctl->wet_depo_bc_a * pow(Is, ctl->wet_depo_bc_b) * eta;
4160
4161 /* Use Henry's law for gases... */
4162 else if (ctl->wet_depo_bc_h[0] > 0) {
4163
4164 /* Get Henry's constant (Burkholder et al., 2019; Sander, 2023)... */
4165 const double h = ctl->wet_depo_bc_h[0]
4166 * exp(ctl->wet_depo_bc_h[1] * (1. / t - 1. / 298.15));
4167
4168 /* Estimate depth of cloud layer... */
4169 const double dz = 1e3 * (Z(pct) - Z(pcb));
4170
4171 /* Calculate scavenging coefficient... */
4172 lambda = h * RI * t * Is / 3.6e6 / dz * eta;
4173 }
4174 }
4175
4176 /* Calculate exponential decay of mass... */
4177 const double aux = exp(-cache->dt[ip] * lambda);
4178 if (ctl->qnt_m >= 0) {
4179 if (ctl->qnt_mloss_wet >= 0)
4180 atm->q[ctl->qnt_mloss_wet][ip]
4181 += atm->q[ctl->qnt_m][ip] * (1 - aux);
4182 atm->q[ctl->qnt_m][ip] *= aux;
4183 if (ctl->qnt_loss_rate >= 0)
4184 atm->q[ctl->qnt_loss_rate][ip] += lambda;
4185 }
4186 if (ctl->qnt_vmr >= 0)
4187 atm->q[ctl->qnt_vmr][ip] *= aux;
4188 }
4189}
4190
4191/*****************************************************************************/
4192
4194 ctl_t **ctl,
4195 cache_t **cache,
4196 clim_t **clim,
4197 met_t **met0,
4198 met_t **met1,
4199 atm_t **atm) {
4200
4201 /* Initialize GPU... */
4202#ifdef _OPENACC
4203 SELECT_TIMER("ACC_INIT", "INIT", NVTX_GPU);
4204 int rank = 0;
4205#ifdef MPI
4206 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
4207#endif
4208 if (acc_get_num_devices(acc_device_nvidia) <= 0)
4209 ERRMSG("Not running on a GPU device!");
4210 acc_set_device_num(rank % acc_get_num_devices(acc_device_nvidia),
4211 acc_device_nvidia);
4212 acc_device_t device_type = acc_get_device_type();
4213 acc_init(device_type);
4214#endif
4215
4216 /* Allocate... */
4217 SELECT_TIMER("ALLOC", "MEMORY", NVTX_CPU);
4218 ALLOC(*ctl, ctl_t, 1);
4219 ALLOC(*cache, cache_t, 1);
4220 ALLOC(*clim, clim_t, 1);
4221 ALLOC(*met0, met_t, 1);
4222 ALLOC(*met1, met_t, 1);
4223 ALLOC(*atm, atm_t, 1);
4224
4225 /* Create data region on GPU... */
4226#ifdef _OPENACC
4227 SELECT_TIMER("CREATE_DATA_REGION", "MEMORY", NVTX_GPU);
4228 ctl_t *ctlup = *ctl;
4229 cache_t *cacheup = *cache;
4230 clim_t *climup = *clim;
4231 met_t *met0up = *met0;
4232 met_t *met1up = *met1;
4233 atm_t *atmup = *atm;
4234#pragma acc enter data create(ctlup[:1],cacheup[:1],climup[:1],met0up[:1],met1up[:1],atmup[:1])
4235#endif
4236}
4237
4238/*****************************************************************************/
4239
4241 ctl_t *ctl,
4242 cache_t *cache,
4243 clim_t *clim,
4244 met_t *met0,
4245 met_t *met1,
4246 atm_t *atm) {
4247
4248 /* Delete data region on GPU... */
4249#ifdef _OPENACC
4250 SELECT_TIMER("DELETE_DATA_REGION", "MEMORY", NVTX_GPU);
4251#pragma acc exit data delete (ctl,cache,clim,met0,met1,atm)
4252#endif
4253
4254 /* Free... */
4255 SELECT_TIMER("FREE", "MEMORY", NVTX_CPU);
4256 free(atm);
4257 free(ctl);
4258 free(cache);
4259 free(clim);
4260 free(met0);
4261 free(met1);
4262}
4263
4264/*****************************************************************************/
4265
4267 ctl_t *ctl,
4268 clim_t *clim,
4269 const double t,
4270 met_t **met0,
4271 met_t **met1) {
4272
4273 static int init;
4274
4275 met_t *mets;
4276
4277 char cachefile[LEN], cmd[2 * LEN], filename[LEN];
4278
4279 /* Set timer... */
4280 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4281
4282 /* Init... */
4283 if (t == ctl->t_start || !init) {
4284 init = 1;
4285
4286 /* Read meteo data... */
4287 get_met_help(ctl, t + (ctl->direction == -1 ? -1 : 0), -1,
4288 ctl->metbase, ctl->dt_met, filename);
4289 if (!mptrac_read_met(filename, ctl, clim, *met0))
4290 ERRMSG("Cannot open file!");
4291
4292 get_met_help(ctl, t + (ctl->direction == 1 ? 1 : 0), 1,
4293 ctl->metbase, ctl->dt_met, filename);
4294 if (!mptrac_read_met(filename, ctl, clim, *met1))
4295 ERRMSG("Cannot open file!");
4296
4297 /* Update GPU... */
4298 mptrac_update_device(NULL, NULL, NULL, met0, met1, NULL);
4299 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4300
4301 /* Caching... */
4302 if (ctl->met_cache && t != ctl->t_stop) {
4303 get_met_help(ctl, t + 1.1 * ctl->dt_met * ctl->direction,
4304 ctl->direction, ctl->metbase, ctl->dt_met, cachefile);
4305 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4306 LOG(1, "Caching: %s", cachefile);
4307 if (system(cmd) != 0)
4308 WARN("Caching command failed!");
4309 }
4310 }
4311
4312 /* Read new data for forward trajectories... */
4313 if (t > (*met1)->time) {
4314
4315 /* Pointer swap... */
4316 mets = *met1;
4317 *met1 = *met0;
4318 *met0 = mets;
4319
4320 /* Read new meteo data... */
4321 get_met_help(ctl, t, 1, ctl->metbase, ctl->dt_met, filename);
4322 if (!mptrac_read_met(filename, ctl, clim, *met1))
4323 ERRMSG("Cannot open file!");
4324
4325 /* Update GPU... */
4326 mptrac_update_device(NULL, NULL, NULL, NULL, met1, NULL);
4327 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4328
4329 /* Caching... */
4330 if (ctl->met_cache && t != ctl->t_stop) {
4331 get_met_help(ctl, t + ctl->dt_met, 1, ctl->metbase, ctl->dt_met,
4332 cachefile);
4333 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4334 LOG(1, "Caching: %s", cachefile);
4335 if (system(cmd) != 0)
4336 WARN("Caching command failed!");
4337 }
4338 }
4339
4340 /* Read new data for backward trajectories... */
4341 if (t < (*met0)->time) {
4342
4343 /* Pointer swap... */
4344 mets = *met1;
4345 *met1 = *met0;
4346 *met0 = mets;
4347
4348 /* Read new meteo data... */
4349 get_met_help(ctl, t, -1, ctl->metbase, ctl->dt_met, filename);
4350 if (!mptrac_read_met(filename, ctl, clim, *met0))
4351 ERRMSG("Cannot open file!");
4352
4353 /* Update GPU... */
4354 mptrac_update_device(NULL, NULL, NULL, met0, NULL, NULL);
4355 SELECT_TIMER("GET_MET", "INPUT", NVTX_READ);
4356
4357 /* Caching... */
4358 if (ctl->met_cache && t != ctl->t_stop) {
4359 get_met_help(ctl, t - ctl->dt_met, -1, ctl->metbase, ctl->dt_met,
4360 cachefile);
4361 sprintf(cmd, "cat %s > /dev/null &", cachefile);
4362 LOG(1, "Caching: %s", cachefile);
4363 if (system(cmd) != 0)
4364 WARN("Caching command failed!");
4365 }
4366 }
4367
4368 /* Check that grids are consistent... */
4369 if ((*met0)->nx != 0 && (*met1)->nx != 0) {
4370 if ((*met0)->nx != (*met1)->nx
4371 || (*met0)->ny != (*met1)->ny || (*met0)->np != (*met1)->np)
4372 ERRMSG("Meteo grid dimensions do not match!");
4373 for (int ix = 0; ix < (*met0)->nx; ix++)
4374 if (fabs((*met0)->lon[ix] - (*met1)->lon[ix]) > 0.001)
4375 ERRMSG("Meteo grid longitudes do not match!");
4376 for (int iy = 0; iy < (*met0)->ny; iy++)
4377 if (fabs((*met0)->lat[iy] - (*met1)->lat[iy]) > 0.001)
4378 ERRMSG("Meteo grid latitudes do not match!");
4379 for (int ip = 0; ip < (*met0)->np; ip++)
4380 if (fabs((*met0)->p[ip] - (*met1)->p[ip]) > 0.001)
4381 ERRMSG("Meteo grid pressure levels do not match!");
4382 }
4383}
4384
4385/*****************************************************************************/
4386
4388 ctl_t *ctl,
4389 cache_t *cache,
4390 clim_t *clim,
4391 atm_t *atm,
4392 const int ntask) {
4393
4394 /* Initialize timesteps... */
4395 module_timesteps_init(ctl, atm);
4396
4397 /* Initialize random number generator... */
4398 module_rng_init(ntask);
4399
4400 /* Update GPU memory... */
4401 mptrac_update_device(ctl, cache, clim, NULL, NULL, atm);
4402}
4403
4404/*****************************************************************************/
4405
4407 const char *filename,
4408 const ctl_t *ctl,
4409 atm_t *atm) {
4410
4411 int result;
4412
4413 /* Set timer... */
4414 SELECT_TIMER("READ_ATM", "INPUT", NVTX_READ);
4415
4416 /* Init... */
4417 atm->np = 0;
4418
4419 /* Write info... */
4420 LOG(1, "Read atmospheric data: %s", filename);
4421
4422 /* Read ASCII data... */
4423 if (ctl->atm_type == 0)
4424 result = read_atm_asc(filename, ctl, atm);
4425
4426 /* Read binary data... */
4427 else if (ctl->atm_type == 1)
4428 result = read_atm_bin(filename, ctl, atm);
4429
4430 /* Read netCDF data... */
4431 else if (ctl->atm_type == 2)
4432 result = read_atm_nc(filename, ctl, atm);
4433
4434 /* Read CLaMS data... */
4435 else if (ctl->atm_type == 3 || ctl->atm_type == 4)
4436 result = read_atm_clams(filename, ctl, atm);
4437
4438 /* Error... */
4439 else
4440 ERRMSG("Atmospheric data type not supported!");
4441
4442 /* Check result... */
4443 if (result != 1)
4444 return 0;
4445
4446 /* Check number of air parcels... */
4447 if (atm->np < 1)
4448 ERRMSG("Can not read any data!");
4449
4450 /* Write info... */
4451 double mini, maxi;
4452 LOG(2, "Number of particles: %d", atm->np);
4453 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
4454 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
4455 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
4456 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
4457 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
4458 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
4459 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
4460 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
4461 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
4462 for (int iq = 0; iq < ctl->nq; iq++) {
4463 char msg[5 * LEN];
4464 sprintf(msg, "Quantity %s range: %s ... %s %s",
4465 ctl->qnt_name[iq], ctl->qnt_format[iq],
4466 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
4467 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
4468 LOG(2, msg, mini, maxi);
4469 }
4470
4471 /* Return success... */
4472 return 1;
4473}
4474
4475/*****************************************************************************/
4476
4478 const ctl_t *ctl,
4479 clim_t *clim) {
4480
4481 /* Set timer... */
4482 SELECT_TIMER("READ_CLIM", "INPUT", NVTX_READ);
4483
4484 /* Init tropopause climatology... */
4485 clim_tropo_init(clim);
4486
4487 /* Read photolysis rates... */
4488 if (ctl->clim_photo[0] != '-')
4489 read_clim_photo(ctl->clim_photo, &clim->photo);
4490
4491 /* Read HNO3 climatology... */
4492 if (ctl->clim_hno3_filename[0] != '-')
4493 read_clim_zm(ctl->clim_hno3_filename, "HNO3", &clim->hno3);
4494
4495 /* Read OH climatology... */
4496 if (ctl->clim_oh_filename[0] != '-') {
4497 read_clim_zm(ctl->clim_oh_filename, "OH", &clim->oh);
4498 if (ctl->oh_chem_beta > 0)
4499 clim_oh_diurnal_correction(ctl, clim);
4500 }
4501
4502 /* Read H2O2 climatology... */
4503 if (ctl->clim_h2o2_filename[0] != '-')
4504 read_clim_zm(ctl->clim_h2o2_filename, "H2O2", &clim->h2o2);
4505
4506 /* Read HO2 climatology... */
4507 if (ctl->clim_ho2_filename[0] != '-')
4508 read_clim_zm(ctl->clim_ho2_filename, "HO2", &clim->ho2);
4509
4510 /* Read O(1D) climatology... */
4511 if (ctl->clim_o1d_filename[0] != '-')
4512 read_clim_zm(ctl->clim_o1d_filename, "O1D", &clim->o1d);
4513
4514 /* Read CFC-10 time series... */
4515 if (ctl->clim_ccl4_timeseries[0] != '-')
4517
4518 /* Read CFC-11 time series... */
4519 if (ctl->clim_ccl3f_timeseries[0] != '-')
4521
4522 /* Read CFC-12 time series... */
4523 if (ctl->clim_ccl2f2_timeseries[0] != '-')
4525
4526 /* Read N2O time series... */
4527 if (ctl->clim_n2o_timeseries[0] != '-')
4528 read_clim_ts(ctl->clim_n2o_timeseries, &clim->n2o);
4529
4530 /* Read SF6 time series... */
4531 if (ctl->clim_sf6_timeseries[0] != '-')
4532 read_clim_ts(ctl->clim_sf6_timeseries, &clim->sf6);
4533}
4534
4535/*****************************************************************************/
4536
4538 const char *filename,
4539 int argc,
4540 char *argv[],
4541 ctl_t *ctl) {
4542
4543 /* Set timer... */
4544 SELECT_TIMER("READ_CTL", "INPUT", NVTX_READ);
4545
4546 /* Write info... */
4547 LOG(1, "\nMassive-Parallel Trajectory Calculations (MPTRAC)\n"
4548 "(executable: %s | version: %s | compiled: %s, %s)\n",
4549 argv[0], VERSION, __DATE__, __TIME__);
4550
4551 /* Initialize quantity indices... */
4552 ctl->qnt_idx = -1;
4553 ctl->qnt_ens = -1;
4554 ctl->qnt_stat = -1;
4555 ctl->qnt_m = -1;
4556 ctl->qnt_vmr = -1;
4557 ctl->qnt_rp = -1;
4558 ctl->qnt_rhop = -1;
4559 ctl->qnt_ps = -1;
4560 ctl->qnt_ts = -1;
4561 ctl->qnt_zs = -1;
4562 ctl->qnt_us = -1;
4563 ctl->qnt_vs = -1;
4564 ctl->qnt_ess = -1;
4565 ctl->qnt_nss = -1;
4566 ctl->qnt_shf = -1;
4567 ctl->qnt_lsm = -1;
4568 ctl->qnt_sst = -1;
4569 ctl->qnt_pbl = -1;
4570 ctl->qnt_pt = -1;
4571 ctl->qnt_tt = -1;
4572 ctl->qnt_zt = -1;
4573 ctl->qnt_h2ot = -1;
4574 ctl->qnt_zg = -1;
4575 ctl->qnt_p = -1;
4576 ctl->qnt_t = -1;
4577 ctl->qnt_rho = -1;
4578 ctl->qnt_u = -1;
4579 ctl->qnt_v = -1;
4580 ctl->qnt_w = -1;
4581 ctl->qnt_h2o = -1;
4582 ctl->qnt_o3 = -1;
4583 ctl->qnt_lwc = -1;
4584 ctl->qnt_rwc = -1;
4585 ctl->qnt_iwc = -1;
4586 ctl->qnt_swc = -1;
4587 ctl->qnt_cc = -1;
4588 ctl->qnt_pct = -1;
4589 ctl->qnt_pcb = -1;
4590 ctl->qnt_cl = -1;
4591 ctl->qnt_plcl = -1;
4592 ctl->qnt_plfc = -1;
4593 ctl->qnt_pel = -1;
4594 ctl->qnt_cape = -1;
4595 ctl->qnt_cin = -1;
4596 ctl->qnt_o3c = -1;
4597 ctl->qnt_hno3 = -1;
4598 ctl->qnt_oh = -1;
4599 ctl->qnt_h2o2 = -1;
4600 ctl->qnt_ho2 = -1;
4601 ctl->qnt_o1d = -1;
4602 ctl->qnt_mloss_oh = -1;
4603 ctl->qnt_mloss_h2o2 = -1;
4604 ctl->qnt_mloss_kpp = -1;
4605 ctl->qnt_mloss_wet = -1;
4606 ctl->qnt_mloss_dry = -1;
4607 ctl->qnt_mloss_decay = -1;
4608 ctl->qnt_loss_rate = -1;
4609 ctl->qnt_psat = -1;
4610 ctl->qnt_psice = -1;
4611 ctl->qnt_pw = -1;
4612 ctl->qnt_sh = -1;
4613 ctl->qnt_rh = -1;
4614 ctl->qnt_rhice = -1;
4615 ctl->qnt_theta = -1;
4616 ctl->qnt_zeta = -1;
4617 ctl->qnt_zeta_d = -1;
4618 ctl->qnt_tvirt = -1;
4619 ctl->qnt_lapse = -1;
4620 ctl->qnt_vh = -1;
4621 ctl->qnt_vz = -1;
4622 ctl->qnt_pv = -1;
4623 ctl->qnt_tdew = -1;
4624 ctl->qnt_tice = -1;
4625 ctl->qnt_tsts = -1;
4626 ctl->qnt_tnat = -1;
4627 ctl->qnt_Cx = -1;
4628 ctl->qnt_Ch2o = -1;
4629 ctl->qnt_Co3 = -1;
4630 ctl->qnt_Cco = -1;
4631 ctl->qnt_Coh = -1;
4632 ctl->qnt_Ch = -1;
4633 ctl->qnt_Cho2 = -1;
4634 ctl->qnt_Ch2o2 = -1;
4635 ctl->qnt_Co1d = -1;
4636 ctl->qnt_Co3p = -1;
4637 ctl->qnt_Cccl4 = -1;
4638 ctl->qnt_Cccl3f = -1;
4639 ctl->qnt_Cccl2f2 = -1;
4640 ctl->qnt_Cn2o = -1;
4641 ctl->qnt_Csf6 = -1;
4642 ctl->qnt_aoa = -1;
4643
4644 /* Read quantities... */
4645 ctl->nq = (int) scan_ctl(filename, argc, argv, "NQ", -1, "0", NULL);
4646 if (ctl->nq > NQ)
4647 ERRMSG("Too many quantities!");
4648 for (int iq = 0; iq < ctl->nq; iq++) {
4649
4650 /* Read quantity name and format... */
4651 scan_ctl(filename, argc, argv, "QNT_NAME", iq, "", ctl->qnt_name[iq]);
4652 scan_ctl(filename, argc, argv, "QNT_LONGNAME", iq, ctl->qnt_name[iq],
4653 ctl->qnt_longname[iq]);
4654 scan_ctl(filename, argc, argv, "QNT_FORMAT", iq, "%g",
4655 ctl->qnt_format[iq]);
4656 if (strcasecmp(ctl->qnt_name[iq], "aoa") == 0)
4657 sprintf(ctl->qnt_format[iq], "%%.2f");
4658
4659 /* Try to identify quantity... */
4660 SET_QNT(qnt_idx, "idx", "particle index", "-")
4661 SET_QNT(qnt_ens, "ens", "ensemble index", "-")
4662 SET_QNT(qnt_stat, "stat", "station flag", "-")
4663 SET_QNT(qnt_m, "m", "mass", "kg")
4664 SET_QNT(qnt_vmr, "vmr", "volume mixing ratio", "ppv")
4665 SET_QNT(qnt_rp, "rp", "particle radius", "microns")
4666 SET_QNT(qnt_rhop, "rhop", "particle density", "kg/m^3")
4667 SET_QNT(qnt_ps, "ps", "surface pressure", "hPa")
4668 SET_QNT(qnt_ts, "ts", "surface temperature", "K")
4669 SET_QNT(qnt_zs, "zs", "surface height", "km")
4670 SET_QNT(qnt_us, "us", "surface zonal wind", "m/s")
4671 SET_QNT(qnt_vs, "vs", "surface meridional wind", "m/s")
4672 SET_QNT(qnt_ess, "ess", "eastward turbulent surface stress", "N/m^2")
4673 SET_QNT(qnt_nss, "nss", "northward turbulent surface stress", "N/m^2")
4674 SET_QNT(qnt_shf, "shf", "surface sensible heat flux", "W/m^2")
4675 SET_QNT(qnt_lsm, "lsm", "land-sea mask", "1")
4676 SET_QNT(qnt_sst, "sst", "sea surface temperature", "K")
4677 SET_QNT(qnt_pbl, "pbl", "planetary boundary layer", "hPa")
4678 SET_QNT(qnt_pt, "pt", "tropopause pressure", "hPa")
4679 SET_QNT(qnt_tt, "tt", "tropopause temperature", "K")
4680 SET_QNT(qnt_zt, "zt", "tropopause geopotential height", "km")
4681 SET_QNT(qnt_h2ot, "h2ot", "tropopause water vapor", "ppv")
4682 SET_QNT(qnt_zg, "zg", "geopotential height", "km")
4683 SET_QNT(qnt_p, "p", "pressure", "hPa")
4684 SET_QNT(qnt_t, "t", "temperature", "K")
4685 SET_QNT(qnt_rho, "rho", "air density", "kg/m^3")
4686 SET_QNT(qnt_u, "u", "zonal wind", "m/s")
4687 SET_QNT(qnt_v, "v", "meridional wind", "m/s")
4688 SET_QNT(qnt_w, "w", "vertical velocity", "hPa/s")
4689 SET_QNT(qnt_h2o, "h2o", "water vapor", "ppv")
4690 SET_QNT(qnt_o3, "o3", "ozone", "ppv")
4691 SET_QNT(qnt_lwc, "lwc", "cloud liquid water content", "kg/kg")
4692 SET_QNT(qnt_rwc, "rwc", "cloud rain water content", "kg/kg")
4693 SET_QNT(qnt_iwc, "iwc", "cloud ice water content", "kg/kg")
4694 SET_QNT(qnt_swc, "swc", "cloud snow water content", "kg/kg")
4695 SET_QNT(qnt_cc, "cc", "cloud cover", "1")
4696 SET_QNT(qnt_pct, "pct", "cloud top pressure", "hPa")
4697 SET_QNT(qnt_pcb, "pcb", "cloud bottom pressure", "hPa")
4698 SET_QNT(qnt_cl, "cl", "total column cloud water", "kg/m^2")
4699 SET_QNT(qnt_plcl, "plcl", "lifted condensation level", "hPa")
4700 SET_QNT(qnt_plfc, "plfc", "level of free convection", "hPa")
4701 SET_QNT(qnt_pel, "pel", "equilibrium level", "hPa")
4702 SET_QNT(qnt_cape, "cape", "convective available potential energy",
4703 "J/kg")
4704 SET_QNT(qnt_cin, "cin", "convective inhibition", "J/kg")
4705 SET_QNT(qnt_o3c, "o3c", "total column ozone", "DU")
4706 SET_QNT(qnt_hno3, "hno3", "nitric acid", "ppv")
4707 SET_QNT(qnt_oh, "oh", "hydroxyl radical", "ppv")
4708 SET_QNT(qnt_h2o2, "h2o2", "hydrogen peroxide", "ppv")
4709 SET_QNT(qnt_ho2, "ho2", "hydroperoxyl radical", "ppv")
4710 SET_QNT(qnt_o1d, "o1d", "atomic oxygen", "ppv")
4711 SET_QNT(qnt_mloss_oh, "mloss_oh", "mass loss due to OH chemistry", "kg")
4712 SET_QNT(qnt_mloss_h2o2, "mloss_h2o2", "mass loss due to H2O2 chemistry",
4713 "kg")
4714 SET_QNT(qnt_mloss_kpp, "mloss_kpp", "mass loss due to kpp chemistry",
4715 "kg")
4716 SET_QNT(qnt_mloss_wet, "mloss_wet", "mass loss due to wet deposition",
4717 "kg")
4718 SET_QNT(qnt_mloss_dry, "mloss_dry", "mass loss due to dry deposition",
4719 "kg")
4720 SET_QNT(qnt_mloss_decay, "mloss_decay",
4721 "mass loss due to exponential decay", "kg")
4722 SET_QNT(qnt_loss_rate, "loss_rate", "total loss rate", "s^-1")
4723 SET_QNT(qnt_psat, "psat", "saturation pressure over water", "hPa")
4724 SET_QNT(qnt_psice, "psice", "saturation pressure over ice", "hPa")
4725 SET_QNT(qnt_pw, "pw", "partial water vapor pressure", "hPa")
4726 SET_QNT(qnt_sh, "sh", "specific humidity", "kg/kg")
4727 SET_QNT(qnt_rh, "rh", "relative humidity", "%%")
4728 SET_QNT(qnt_rhice, "rhice", "relative humidity over ice", "%%")
4729 SET_QNT(qnt_theta, "theta", "potential temperature", "K")
4730 SET_QNT(qnt_zeta, "zeta", "zeta coordinate", "K")
4731 SET_QNT(qnt_zeta_d, "zeta_d", "diagnosed zeta coordinate", "K")
4732 SET_QNT(qnt_tvirt, "tvirt", "virtual temperature", "K")
4733 SET_QNT(qnt_lapse, "lapse", "temperature lapse rate", "K/km")
4734 SET_QNT(qnt_vh, "vh", "horizontal velocity", "m/s")
4735 SET_QNT(qnt_vz, "vz", "vertical velocity", "m/s")
4736 SET_QNT(qnt_pv, "pv", "potential vorticity", "PVU")
4737 SET_QNT(qnt_tdew, "tdew", "dew point temperature", "K")
4738 SET_QNT(qnt_tice, "tice", "frost point temperature", "K")
4739 SET_QNT(qnt_tsts, "tsts", "STS existence temperature", "K")
4740 SET_QNT(qnt_tnat, "tnat", "NAT existence temperature", "K")
4741 SET_QNT(qnt_Cx, "Cx", "Trace species x volume mixing ratio", "ppv")
4742 SET_QNT(qnt_Ch2o, "Ch2o", "H2O volume mixing ratio", "ppv")
4743 SET_QNT(qnt_Co3, "Co3", "O3 volume mixing ratio", "ppv")
4744 SET_QNT(qnt_Cco, "Cco", "CO volume mixing ratio", "ppv")
4745 SET_QNT(qnt_Coh, "Coh", "HO volume mixing ratio", "ppv")
4746 SET_QNT(qnt_Ch, "Ch", "H radical volume mixing ratio", "ppv")
4747 SET_QNT(qnt_Cho2, "Cho2", "HO2 volume mixing ratio", "ppv")
4748 SET_QNT(qnt_Ch2o2, "Ch2o2", "H2O2 volume mixing ratio", "ppv")
4749 SET_QNT(qnt_Co1d, "Co1d", "O(1D) volume mixing ratio", "ppv")
4750 SET_QNT(qnt_Co3p, "Co3p", "O(3P) radical volume mixing ratio", "ppv")
4751 SET_QNT(qnt_Cccl4, "Cccl4", "CCl4 (CFC-10) volume mixing ratio", "ppv")
4752 SET_QNT(qnt_Cccl3f, "Cccl3f", "CCl3F (CFC-11) volume mixing ratio",
4753 "ppv")
4754 SET_QNT(qnt_Cccl2f2, "Cccl2f2", "CCl2F2 (CFC-12) volume mixing ratio",
4755 "ppv")
4756 SET_QNT(qnt_Cn2o, "Cn2o", "N2O volume mixing ratio", "ppv")
4757 SET_QNT(qnt_Csf6, "Csf6", "SF6 volume mixing ratio", "ppv")
4758 SET_QNT(qnt_aoa, "aoa", "age of air", "s")
4759 scan_ctl(filename, argc, argv, "QNT_UNIT", iq, "", ctl->qnt_unit[iq]);
4760 }
4761
4762 /* Vertical coordinates and velocities... */
4763 ctl->advect_vert_coord =
4764 (int) scan_ctl(filename, argc, argv, "ADVECT_VERT_COORD", -1, "0", NULL);
4765 if (ctl->advect_vert_coord < 0 || ctl->advect_vert_coord > 2)
4766 ERRMSG("Set ADVECT_VERT_COORD to 0, 1, or 2!");
4767 ctl->met_vert_coord =
4768 (int) scan_ctl(filename, argc, argv, "MET_VERT_COORD", -1, "0", NULL);
4769 if (ctl->met_vert_coord < 0 || ctl->met_vert_coord > 4)
4770 ERRMSG("Set MET_VERT_COORD to 0, 1, 2, 3, or 4!");
4771 if (ctl->advect_vert_coord == 1 && ctl->qnt_zeta < 0)
4772 ERRMSG("Please add zeta to your quantities for diabatic calculations!");
4773 if (ctl->advect_vert_coord == 2 && ctl->met_vert_coord == 0)
4774 ERRMSG
4775 ("Using ADVECT_VERT_COORD = 2 requires meteo data on model levels!");
4776
4777 /* Time steps of simulation... */
4778 ctl->direction =
4779 (int) scan_ctl(filename, argc, argv, "DIRECTION", -1, "1", NULL);
4780 if (ctl->direction != -1 && ctl->direction != 1)
4781 ERRMSG("Set DIRECTION to -1 or 1!");
4782 ctl->t_stop = scan_ctl(filename, argc, argv, "T_STOP", -1, "1e100", NULL);
4783 ctl->dt_mod = scan_ctl(filename, argc, argv, "DT_MOD", -1, "180", NULL);
4784
4785 /* Meteo data... */
4786 scan_ctl(filename, argc, argv, "METBASE", -1, "-", ctl->metbase);
4787 ctl->dt_met = scan_ctl(filename, argc, argv, "DT_MET", -1, "3600", NULL);
4788 ctl->met_convention =
4789 (int) scan_ctl(filename, argc, argv, "MET_CONVENTION", -1, "0", NULL);
4790 ctl->met_type =
4791 (int) scan_ctl(filename, argc, argv, "MET_TYPE", -1, "0", NULL);
4792 if (ctl->advect_vert_coord == 1 && ctl->met_type != 0)
4793 ERRMSG
4794 ("Please use meteo files in netcdf format for diabatic calculations.");
4795 ctl->met_clams =
4796 (int) scan_ctl(filename, argc, argv, "MET_CLAMS", -1, "0", NULL);
4797 ctl->met_nc_scale =
4798 (int) scan_ctl(filename, argc, argv, "MET_NC_SCALE", -1, "1", NULL);
4799 ctl->met_nc_level =
4800 (int) scan_ctl(filename, argc, argv, "MET_NC_LEVEL", -1, "0", NULL);
4801 ctl->met_nc_quant =
4802 (int) scan_ctl(filename, argc, argv, "MET_NC_QUANT", -1, "0", NULL);
4803 ctl->met_zstd_level =
4804 (int) scan_ctl(filename, argc, argv, "MET_ZSTD_LEVEL", -1, "0", NULL);
4805 ctl->met_zfp_prec =
4806 (int) scan_ctl(filename, argc, argv, "MET_ZFP_PREC", -1, "8", NULL);
4807 ctl->met_zfp_tol_t =
4808 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_T", -1, "5.0", NULL);
4809 ctl->met_zfp_tol_z =
4810 scan_ctl(filename, argc, argv, "MET_ZFP_TOL_Z", -1, "0.5", NULL);
4811 ctl->met_cms_batch =
4812 (int) scan_ctl(filename, argc, argv, "MET_CMS_BATCH", -1, "-1", NULL);
4813 ctl->met_cms_zstd =
4814 (int) scan_ctl(filename, argc, argv, "MET_CMS_ZSTD", -1, "1", NULL);
4815 ctl->met_cms_heur =
4816 (int) scan_ctl(filename, argc, argv, "MET_CMS_HEUR", -1, "1", NULL);
4817 ctl->met_cms_eps_z =
4818 scan_ctl(filename, argc, argv, "MET_CMS_EPS_Z", -1, "1.0", NULL);
4819 ctl->met_cms_eps_t =
4820 scan_ctl(filename, argc, argv, "MET_CMS_EPS_T", -1, "0.05", NULL);
4821 ctl->met_cms_eps_u =
4822 scan_ctl(filename, argc, argv, "MET_CMS_EPS_U", -1, "0.05", NULL);
4823 ctl->met_cms_eps_v =
4824 scan_ctl(filename, argc, argv, "MET_CMS_EPS_V", -1, "0.05", NULL);
4825 ctl->met_cms_eps_w =
4826 scan_ctl(filename, argc, argv, "MET_CMS_EPS_W", -1, "1.0", NULL);
4827 ctl->met_cms_eps_pv =
4828 scan_ctl(filename, argc, argv, "MET_CMS_EPS_PV", -1, "1.0", NULL);
4829 ctl->met_cms_eps_h2o =
4830 scan_ctl(filename, argc, argv, "MET_CMS_EPS_H2O", -1, "1.0", NULL);
4831 ctl->met_cms_eps_o3 =
4832 scan_ctl(filename, argc, argv, "MET_CMS_EPS_O3", -1, "1.0", NULL);
4833 ctl->met_cms_eps_lwc =
4834 scan_ctl(filename, argc, argv, "MET_CMS_EPS_LWC", -1, "1.0", NULL);
4835 ctl->met_cms_eps_rwc =
4836 scan_ctl(filename, argc, argv, "MET_CMS_EPS_RWC", -1, "1.0", NULL);
4837 ctl->met_cms_eps_iwc =
4838 scan_ctl(filename, argc, argv, "MET_CMS_EPS_IWC", -1, "1.0", NULL);
4839 ctl->met_cms_eps_swc =
4840 scan_ctl(filename, argc, argv, "MET_CMS_EPS_SWC", -1, "1.0", NULL);
4841 ctl->met_cms_eps_cc =
4842 scan_ctl(filename, argc, argv, "MET_CMS_EPS_CC", -1, "1.0", NULL);
4843 ctl->met_dx = (int) scan_ctl(filename, argc, argv, "MET_DX", -1, "1", NULL);
4844 ctl->met_dy = (int) scan_ctl(filename, argc, argv, "MET_DY", -1, "1", NULL);
4845 ctl->met_dp = (int) scan_ctl(filename, argc, argv, "MET_DP", -1, "1", NULL);
4846 if (ctl->met_dx < 1 || ctl->met_dy < 1 || ctl->met_dp < 1)
4847 ERRMSG("MET_DX, MET_DY, and MET_DP need to be greater than zero!");
4848 ctl->met_sx = (int) scan_ctl(filename, argc, argv, "MET_SX", -1, "1", NULL);
4849 ctl->met_sy = (int) scan_ctl(filename, argc, argv, "MET_SY", -1, "1", NULL);
4850 ctl->met_sp = (int) scan_ctl(filename, argc, argv, "MET_SP", -1, "1", NULL);
4851 if (ctl->met_sx < 1 || ctl->met_sy < 1 || ctl->met_sp < 1)
4852 ERRMSG("MET_SX, MET_SY, and MET_SP need to be greater than zero!");
4853 ctl->met_detrend =
4854 scan_ctl(filename, argc, argv, "MET_DETREND", -1, "-999", NULL);
4855 ctl->met_np = (int) scan_ctl(filename, argc, argv, "MET_NP", -1, "0", NULL);
4856 if (ctl->met_np > EP)
4857 ERRMSG("Too many pressure levels!");
4858 ctl->met_press_level_def =
4859 (int) scan_ctl(filename, argc, argv, "MET_PRESS_LEVEL_DEF", -1, "-1",
4860 NULL);
4861 if (ctl->met_press_level_def >= 0) {
4862 level_definitions(ctl);
4863 } else {
4864 if (ctl->met_np > 0) {
4865 for (int ip = 0; ip < ctl->met_np; ip++)
4866 ctl->met_p[ip] =
4867 scan_ctl(filename, argc, argv, "MET_P", ip, "", NULL);
4868 }
4869 }
4870 ctl->met_nlev =
4871 (int) scan_ctl(filename, argc, argv, "MET_NLEV", -1, "0", NULL);
4872 if (ctl->met_nlev > EP)
4873 ERRMSG("Too many model levels!");
4874 for (int ip = 0; ip < ctl->met_nlev; ip++) {
4875 ctl->met_lev_hyam[ip] =
4876 scan_ctl(filename, argc, argv, "MET_LEV_HYAM", ip, "", NULL);
4877 ctl->met_lev_hybm[ip] =
4878 scan_ctl(filename, argc, argv, "MET_LEV_HYBM", ip, "", NULL);
4879 }
4880 ctl->met_geopot_sx =
4881 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SX", -1, "-1", NULL);
4882 ctl->met_geopot_sy =
4883 (int) scan_ctl(filename, argc, argv, "MET_GEOPOT_SY", -1, "-1", NULL);
4884 ctl->met_relhum =
4885 (int) scan_ctl(filename, argc, argv, "MET_RELHUM", -1, "0", NULL);
4886 ctl->met_cape =
4887 (int) scan_ctl(filename, argc, argv, "MET_CAPE", -1, "1", NULL);
4888 if (ctl->met_cape < 0 || ctl->met_cape > 1)
4889 ERRMSG("Set MET_CAPE to 0 or 1!");
4890 ctl->met_pbl =
4891 (int) scan_ctl(filename, argc, argv, "MET_PBL", -1, "3", NULL);
4892 if (ctl->met_pbl < 0 || ctl->met_pbl > 3)
4893 ERRMSG("Set MET_PBL to 0 ... 3!");
4894 ctl->met_pbl_min =
4895 scan_ctl(filename, argc, argv, "MET_PBL_MIN", -1, "0.1", NULL);
4896 ctl->met_pbl_max =
4897 scan_ctl(filename, argc, argv, "MET_PBL_MAX", -1, "5.0", NULL);
4898 ctl->met_tropo =
4899 (int) scan_ctl(filename, argc, argv, "MET_TROPO", -1, "3", NULL);
4900 if (ctl->met_tropo < 0 || ctl->met_tropo > 5)
4901 ERRMSG("Set MET_TROPO to 0 ... 5!");
4902 ctl->met_tropo_pv =
4903 scan_ctl(filename, argc, argv, "MET_TROPO_PV", -1, "3.5", NULL);
4904 ctl->met_tropo_theta =
4905 scan_ctl(filename, argc, argv, "MET_TROPO_THETA", -1, "380", NULL);
4906 ctl->met_tropo_spline =
4907 (int) scan_ctl(filename, argc, argv, "MET_TROPO_SPLINE", -1, "1", NULL);
4908 ctl->met_dt_out =
4909 scan_ctl(filename, argc, argv, "MET_DT_OUT", -1, "0.1", NULL);
4910 ctl->met_cache =
4911 (int) scan_ctl(filename, argc, argv, "MET_CACHE", -1, "0", NULL);
4912 ctl->met_mpi_share =
4913 (int) scan_ctl(filename, argc, argv, "MET_MPI_SHARE", -1, "0", NULL);
4914
4915 /* Sorting... */
4916 ctl->sort_dt = scan_ctl(filename, argc, argv, "SORT_DT", -1, "-999", NULL);
4917
4918 /* Isosurface parameters... */
4919 ctl->isosurf =
4920 (int) scan_ctl(filename, argc, argv, "ISOSURF", -1, "0", NULL);
4921 scan_ctl(filename, argc, argv, "BALLOON", -1, "-", ctl->balloon);
4922
4923 /* Random number generator... */
4924 ctl->rng_type =
4925 (int) scan_ctl(filename, argc, argv, "RNG_TYPE", -1, "1", NULL);
4926 if (ctl->rng_type < 0 || ctl->rng_type > 2)
4927 ERRMSG("Set RNG_TYPE to 0, 1, or 2!");
4928
4929 /* Advection parameters... */
4930 ctl->advect = (int) scan_ctl(filename, argc, argv, "ADVECT", -1, "2", NULL);
4931 if (!(ctl->advect == 0 || ctl->advect == 1
4932 || ctl->advect == 2 || ctl->advect == 4))
4933 ERRMSG("Set ADVECT to 0, 1, 2, or 4!");
4934
4935 /* Diffusion parameters... */
4936 ctl->diffusion
4937 = (int) scan_ctl(filename, argc, argv, "DIFFUSION", -1, "0", NULL);
4938 if (ctl->diffusion < 0 || ctl->diffusion > 2)
4939 ERRMSG("Set DIFFUSION to 0, 1 or 2!");
4940 ctl->turb_dx_pbl =
4941 scan_ctl(filename, argc, argv, "TURB_DX_PBL", -1, "50", NULL);
4942 ctl->turb_dx_trop =
4943 scan_ctl(filename, argc, argv, "TURB_DX_TROP", -1, "50", NULL);
4944 ctl->turb_dx_strat =
4945 scan_ctl(filename, argc, argv, "TURB_DX_STRAT", -1, "0", NULL);
4946 ctl->turb_dz_pbl =
4947 scan_ctl(filename, argc, argv, "TURB_DZ_PBL", -1, "0", NULL);
4948 ctl->turb_dz_trop =
4949 scan_ctl(filename, argc, argv, "TURB_DZ_TROP", -1, "0", NULL);
4950 ctl->turb_dz_strat =
4951 scan_ctl(filename, argc, argv, "TURB_DZ_STRAT", -1, "0.1", NULL);
4952 ctl->turb_mesox =
4953 scan_ctl(filename, argc, argv, "TURB_MESOX", -1, "0.16", NULL);
4954 ctl->turb_mesoz =
4955 scan_ctl(filename, argc, argv, "TURB_MESOZ", -1, "0.16", NULL);
4956
4957 /* Convection... */
4958 ctl->conv_mix_pbl
4959 = (int) scan_ctl(filename, argc, argv, "CONV_MIX_PBL", -1, "0", NULL);
4960 ctl->conv_pbl_trans
4961 = scan_ctl(filename, argc, argv, "CONV_PBL_TRANS", -1, "0", NULL);
4962 ctl->conv_cape
4963 = scan_ctl(filename, argc, argv, "CONV_CAPE", -1, "-999", NULL);
4964 ctl->conv_cin
4965 = scan_ctl(filename, argc, argv, "CONV_CIN", -1, "-999", NULL);
4966 ctl->conv_dt = scan_ctl(filename, argc, argv, "CONV_DT", -1, "-999", NULL);
4967
4968 /* Boundary conditions... */
4969 ctl->bound_mass =
4970 scan_ctl(filename, argc, argv, "BOUND_MASS", -1, "-999", NULL);
4971 ctl->bound_mass_trend =
4972 scan_ctl(filename, argc, argv, "BOUND_MASS_TREND", -1, "0", NULL);
4973 ctl->bound_vmr =
4974 scan_ctl(filename, argc, argv, "BOUND_VMR", -1, "-999", NULL);
4975 ctl->bound_vmr_trend =
4976 scan_ctl(filename, argc, argv, "BOUND_VMR_TREND", -1, "0", NULL);
4977 ctl->bound_lat0 =
4978 scan_ctl(filename, argc, argv, "BOUND_LAT0", -1, "-999", NULL);
4979 ctl->bound_lat1 =
4980 scan_ctl(filename, argc, argv, "BOUND_LAT1", -1, "-999", NULL);
4981 ctl->bound_p0 =
4982 scan_ctl(filename, argc, argv, "BOUND_P0", -1, "-999", NULL);
4983 ctl->bound_p1 =
4984 scan_ctl(filename, argc, argv, "BOUND_P1", -1, "-999", NULL);
4985 ctl->bound_dps =
4986 scan_ctl(filename, argc, argv, "BOUND_DPS", -1, "-999", NULL);
4987 ctl->bound_dzs =
4988 scan_ctl(filename, argc, argv, "BOUND_DZS", -1, "-999", NULL);
4989 ctl->bound_zetas =
4990 scan_ctl(filename, argc, argv, "BOUND_ZETAS", -1, "-999", NULL);
4991 ctl->bound_pbl =
4992 (int) scan_ctl(filename, argc, argv, "BOUND_PBL", -1, "0", NULL);
4993
4994 /* Species parameters... */
4995 scan_ctl(filename, argc, argv, "SPECIES", -1, "-", ctl->species);
4996 if (strcasecmp(ctl->species, "CF2Cl2") == 0) {
4997 ctl->molmass = 120.907;
4998 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3e-5;
4999 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3500.0;
5000 } else if (strcasecmp(ctl->species, "CFCl3") == 0) {
5001 ctl->molmass = 137.359;
5002 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.1e-4;
5003 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3300.0;
5004 } else if (strcasecmp(ctl->species, "CH4") == 0) {
5005 ctl->molmass = 16.043;
5006 ctl->oh_chem_reaction = 2;
5007 ctl->oh_chem[0] = 2.45e-12;
5008 ctl->oh_chem[1] = 1775;
5009 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.4e-5;
5010 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5011 } else if (strcasecmp(ctl->species, "CO") == 0) {
5012 ctl->molmass = 28.01;
5013 ctl->oh_chem_reaction = 3;
5014 ctl->oh_chem[0] = 6.9e-33;
5015 ctl->oh_chem[1] = 2.1;
5016 ctl->oh_chem[2] = 1.1e-12;
5017 ctl->oh_chem[3] = -1.3;
5018 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 9.7e-6;
5019 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1300.0;
5020 } else if (strcasecmp(ctl->species, "CO2") == 0) {
5021 ctl->molmass = 44.009;
5022 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 3.3e-4;
5023 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5024 } else if (strcasecmp(ctl->species, "H2O") == 0) {
5025 ctl->molmass = 18.01528;
5026 } else if (strcasecmp(ctl->species, "N2O") == 0) {
5027 ctl->molmass = 44.013;
5028 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-4;
5029 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2600.;
5030 } else if (strcasecmp(ctl->species, "NH3") == 0) {
5031 ctl->molmass = 17.031;
5032 ctl->oh_chem_reaction = 2;
5033 ctl->oh_chem[0] = 1.7e-12;
5034 ctl->oh_chem[1] = 710;
5035 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 5.9e-1;
5036 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 4200.0;
5037 } else if (strcasecmp(ctl->species, "HNO3") == 0) {
5038 ctl->molmass = 63.012;
5039 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.1e3;
5040 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 8700.0;
5041 } else if (strcasecmp(ctl->species, "NO") == 0) {
5042 ctl->molmass = 30.006;
5043 ctl->oh_chem_reaction = 3;
5044 ctl->oh_chem[0] = 7.1e-31;
5045 ctl->oh_chem[1] = 2.6;
5046 ctl->oh_chem[2] = 3.6e-11;
5047 ctl->oh_chem[3] = 0.1;
5048 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.9e-5;
5049 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 1600.0;
5050 } else if (strcasecmp(ctl->species, "NO2") == 0) {
5051 ctl->molmass = 46.005;
5052 ctl->oh_chem_reaction = 3;
5053 ctl->oh_chem[0] = 1.8e-30;
5054 ctl->oh_chem[1] = 3.0;
5055 ctl->oh_chem[2] = 2.8e-11;
5056 ctl->oh_chem[3] = 0.0;
5057 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.2e-4;
5058 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2400.0;
5059 } else if (strcasecmp(ctl->species, "O3") == 0) {
5060 ctl->molmass = 47.997;
5061 ctl->oh_chem_reaction = 2;
5062 ctl->oh_chem[0] = 1.7e-12;
5063 ctl->oh_chem[1] = 940;
5064 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1e-4;
5065 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2800.0;
5066 } else if (strcasecmp(ctl->species, "SF6") == 0) {
5067 ctl->molmass = 146.048;
5068 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 2.4e-6;
5069 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 3100.0;
5070 } else if (strcasecmp(ctl->species, "SO2") == 0) {
5071 ctl->molmass = 64.066;
5072 ctl->oh_chem_reaction = 3;
5073 ctl->oh_chem[0] = 2.9e-31;
5074 ctl->oh_chem[1] = 4.1;
5075 ctl->oh_chem[2] = 1.7e-12;
5076 ctl->oh_chem[3] = -0.2;
5077 ctl->wet_depo_ic_h[0] = ctl->wet_depo_bc_h[0] = 1.3e-2;
5078 ctl->wet_depo_ic_h[1] = ctl->wet_depo_bc_h[1] = 2900.0;
5079 }
5080
5081 /* Molar mass... */
5082 char defstr[LEN];
5083 sprintf(defstr, "%g", ctl->molmass);
5084 ctl->molmass = scan_ctl(filename, argc, argv, "MOLMASS", -1, defstr, NULL);
5085
5086 /* OH chemistry... */
5087 sprintf(defstr, "%d", ctl->oh_chem_reaction);
5088 ctl->oh_chem_reaction =
5089 (int) scan_ctl(filename, argc, argv, "OH_CHEM_REACTION", -1, defstr,
5090 NULL);
5091 for (int ip = 0; ip < 4; ip++) {
5092 sprintf(defstr, "%g", ctl->oh_chem[ip]);
5093 ctl->oh_chem[ip] =
5094 scan_ctl(filename, argc, argv, "OH_CHEM", ip, defstr, NULL);
5095 }
5096 ctl->oh_chem_beta =
5097 scan_ctl(filename, argc, argv, "OH_CHEM_BETA", -1, "0", NULL);
5098
5099 /* H2O2 chemistry... */
5100 ctl->h2o2_chem_reaction =
5101 (int) scan_ctl(filename, argc, argv, "H2O2_CHEM_REACTION", -1, "0", NULL);
5102
5103 /* KPP chemistry... */
5104 ctl->kpp_chem =
5105 (int) scan_ctl(filename, argc, argv, "KPP_CHEM", -1, "0", NULL);
5106 ctl->dt_kpp = scan_ctl(filename, argc, argv, "DT_KPP", -1, "1800", NULL);
5107
5108 /* First order tracer chemistry... */
5109 ctl->tracer_chem =
5110 (int) scan_ctl(filename, argc, argv, "TRACER_CHEM", -1, "0", NULL);
5111
5112 /* Wet deposition... */
5113 for (int ip = 0; ip < 2; ip++) {
5114 sprintf(defstr, "%g", ctl->wet_depo_ic_h[ip]);
5115 ctl->wet_depo_ic_h[ip] =
5116 scan_ctl(filename, argc, argv, "WET_DEPO_IC_H", ip, defstr, NULL);
5117 }
5118 for (int ip = 0; ip < 1; ip++) {
5119 sprintf(defstr, "%g", ctl->wet_depo_bc_h[ip]);
5120 ctl->wet_depo_bc_h[ip] =
5121 scan_ctl(filename, argc, argv, "WET_DEPO_BC_H", ip, defstr, NULL);
5122 }
5123 ctl->wet_depo_so2_ph =
5124 scan_ctl(filename, argc, argv, "WET_DEPO_SO2_PH", -1, "0", NULL);
5125 ctl->wet_depo_ic_a =
5126 scan_ctl(filename, argc, argv, "WET_DEPO_IC_A", -1, "0", NULL);
5127 ctl->wet_depo_ic_b =
5128 scan_ctl(filename, argc, argv, "WET_DEPO_IC_B", -1, "0", NULL);
5129 ctl->wet_depo_bc_a =
5130 scan_ctl(filename, argc, argv, "WET_DEPO_BC_A", -1, "0", NULL);
5131 ctl->wet_depo_bc_b =
5132 scan_ctl(filename, argc, argv, "WET_DEPO_BC_B", -1, "0", NULL);
5133 ctl->wet_depo_pre[0] =
5134 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 0, "0.5", NULL);
5135 ctl->wet_depo_pre[1] =
5136 scan_ctl(filename, argc, argv, "WET_DEPO_PRE", 1, "0.36", NULL);
5138 scan_ctl(filename, argc, argv, "WET_DEPO_IC_RET_RATIO", -1, "1", NULL);
5140 scan_ctl(filename, argc, argv, "WET_DEPO_BC_RET_RATIO", -1, "1", NULL);
5141
5142 /* Dry deposition... */
5143 ctl->dry_depo_vdep =
5144 scan_ctl(filename, argc, argv, "DRY_DEPO_VDEP", -1, "0", NULL);
5145 ctl->dry_depo_dp =
5146 scan_ctl(filename, argc, argv, "DRY_DEPO_DP", -1, "30", NULL);
5147
5148 /* Climatological data... */
5149 scan_ctl(filename, argc, argv, "CLIM_PHOTO", -1,
5150 "../../data/clams_photolysis_rates.nc", ctl->clim_photo);
5151 scan_ctl(filename, argc, argv, "CLIM_HNO3_FILENAME", -1,
5152 "../../data/gozcards_HNO3.nc", ctl->clim_hno3_filename);
5153 scan_ctl(filename, argc, argv, "CLIM_OH_FILENAME", -1,
5154 "../../data/clams_radical_species_vmr.nc", ctl->clim_oh_filename);
5155 scan_ctl(filename, argc, argv, "CLIM_H2O2_FILENAME", -1,
5156 "../../data/cams_H2O2.nc", ctl->clim_h2o2_filename);
5157 scan_ctl(filename, argc, argv, "CLIM_HO2_FILENAME", -1,
5158 "../../data/clams_radical_species_vmr.nc", ctl->clim_ho2_filename);
5159 scan_ctl(filename, argc, argv, "CLIM_O1D_FILENAME", -1,
5160 "../../data/clams_radical_species_vmr.nc", ctl->clim_o1d_filename);
5161 scan_ctl(filename, argc, argv, "CLIM_CCL4_TIMESERIES", -1,
5162 "../../data/noaa_gml_ccl4.tab", ctl->clim_ccl4_timeseries);
5163 scan_ctl(filename, argc, argv, "CLIM_CCL3F_TIMESERIES", -1,
5164 "../../data/noaa_gml_cfc11.tab", ctl->clim_ccl3f_timeseries);
5165 scan_ctl(filename, argc, argv, "CLIM_CCL2F2_TIMESERIES", -1,
5166 "../../data/noaa_gml_cfc12.tab", ctl->clim_ccl2f2_timeseries);
5167 scan_ctl(filename, argc, argv, "CLIM_N2O_TIMESERIES", -1,
5168 "../../data/noaa_gml_n2o.tab", ctl->clim_n2o_timeseries);
5169 scan_ctl(filename, argc, argv, "CLIM_SF6_TIMESERIES", -1,
5170 "../../data/noaa_gml_sf6.tab", ctl->clim_sf6_timeseries);
5171
5172 /* Mixing... */
5173 ctl->mixing_dt =
5174 scan_ctl(filename, argc, argv, "MIXING_DT", -1, "3600.", NULL);
5175 ctl->mixing_trop =
5176 scan_ctl(filename, argc, argv, "MIXING_TROP", -1, "-999", NULL);
5177 ctl->mixing_strat =
5178 scan_ctl(filename, argc, argv, "MIXING_STRAT", -1, "-999", NULL);
5179 ctl->mixing_z0 =
5180 scan_ctl(filename, argc, argv, "MIXING_Z0", -1, "-5", NULL);
5181 ctl->mixing_z1 =
5182 scan_ctl(filename, argc, argv, "MIXING_Z1", -1, "85", NULL);
5183 ctl->mixing_nz =
5184 (int) scan_ctl(filename, argc, argv, "MIXING_NZ", -1, "90", NULL);
5185 ctl->mixing_lon0 =
5186 scan_ctl(filename, argc, argv, "MIXING_LON0", -1, "-180", NULL);
5187 ctl->mixing_lon1 =
5188 scan_ctl(filename, argc, argv, "MIXING_LON1", -1, "180", NULL);
5189 ctl->mixing_nx =
5190 (int) scan_ctl(filename, argc, argv, "MIXING_NX", -1, "360", NULL);
5191 ctl->mixing_lat0 =
5192 scan_ctl(filename, argc, argv, "MIXING_LAT0", -1, "-90", NULL);
5193 ctl->mixing_lat1 =
5194 scan_ctl(filename, argc, argv, "MIXING_LAT1", -1, "90", NULL);
5195 ctl->mixing_ny =
5196 (int) scan_ctl(filename, argc, argv, "MIXING_NY", -1, "180", NULL);
5197
5198 /* Chemistry grid... */
5199 ctl->chemgrid_z0 =
5200 scan_ctl(filename, argc, argv, "CHEMGRID_Z0", -1, "-5", NULL);
5201 ctl->chemgrid_z1 =
5202 scan_ctl(filename, argc, argv, "CHEMGRID_Z1", -1, "85", NULL);
5203 ctl->chemgrid_nz =
5204 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NZ", -1, "90", NULL);
5205 ctl->chemgrid_lon0 =
5206 scan_ctl(filename, argc, argv, "CHEMGRID_LON0", -1, "-180", NULL);
5207 ctl->chemgrid_lon1 =
5208 scan_ctl(filename, argc, argv, "CHEMGRID_LON1", -1, "180", NULL);
5209 ctl->chemgrid_nx =
5210 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NX", -1, "360", NULL);
5211 ctl->chemgrid_lat0 =
5212 scan_ctl(filename, argc, argv, "CHEMGRID_LAT0", -1, "-90", NULL);
5213 ctl->chemgrid_lat1 =
5214 scan_ctl(filename, argc, argv, "CHEMGRID_LAT1", -1, "90", NULL);
5215 ctl->chemgrid_ny =
5216 (int) scan_ctl(filename, argc, argv, "CHEMGRID_NY", -1, "180", NULL);
5217
5218 /* Exponential decay... */
5219 ctl->tdec_trop = scan_ctl(filename, argc, argv, "TDEC_TROP", -1, "0", NULL);
5220 ctl->tdec_strat
5221 = scan_ctl(filename, argc, argv, "TDEC_STRAT", -1, "0", NULL);
5222
5223 /* PSC analysis... */
5224 ctl->psc_h2o = scan_ctl(filename, argc, argv, "PSC_H2O", -1, "4e-6", NULL);
5225 ctl->psc_hno3 =
5226 scan_ctl(filename, argc, argv, "PSC_HNO3", -1, "9e-9", NULL);
5227
5228 /* Output of atmospheric data... */
5229 scan_ctl(filename, argc, argv, "ATM_BASENAME", -1, "-", ctl->atm_basename);
5230 scan_ctl(filename, argc, argv, "ATM_GPFILE", -1, "-", ctl->atm_gpfile);
5231 ctl->atm_dt_out =
5232 scan_ctl(filename, argc, argv, "ATM_DT_OUT", -1, "86400", NULL);
5233 ctl->atm_filter =
5234 (int) scan_ctl(filename, argc, argv, "ATM_FILTER", -1, "0", NULL);
5235 ctl->atm_stride =
5236 (int) scan_ctl(filename, argc, argv, "ATM_STRIDE", -1, "1", NULL);
5237 ctl->atm_type =
5238 (int) scan_ctl(filename, argc, argv, "ATM_TYPE", -1, "0", NULL);
5239 ctl->atm_type_out =
5240 (int) scan_ctl(filename, argc, argv, "ATM_TYPE_OUT", -1, "-1", NULL);
5241 if (ctl->atm_type_out == -1)
5242 ctl->atm_type_out = ctl->atm_type;
5243 ctl->atm_nc_level =
5244 (int) scan_ctl(filename, argc, argv, "ATM_NC_LEVEL", -1, "0", NULL);
5245 for (int iq = 0; iq < ctl->nq; iq++)
5246 ctl->atm_nc_quant[iq] =
5247 (int) scan_ctl(filename, argc, argv, "ATM_NC_QUANT", iq, "0", NULL);
5248 ctl->obs_type =
5249 (int) scan_ctl(filename, argc, argv, "OBS_TYPE", -1, "0", NULL);
5250
5251 /* Output of CSI data... */
5252 scan_ctl(filename, argc, argv, "CSI_BASENAME", -1, "-", ctl->csi_basename);
5253 scan_ctl(filename, argc, argv, "CSI_KERNEL", -1, "-", ctl->csi_kernel);
5254 ctl->csi_dt_out =
5255 scan_ctl(filename, argc, argv, "CSI_DT_OUT", -1, "86400", NULL);
5256 scan_ctl(filename, argc, argv, "CSI_OBSFILE", -1, "-", ctl->csi_obsfile);
5257 ctl->csi_obsmin =
5258 scan_ctl(filename, argc, argv, "CSI_OBSMIN", -1, "0", NULL);
5259 ctl->csi_modmin =
5260 scan_ctl(filename, argc, argv, "CSI_MODMIN", -1, "0", NULL);
5261 ctl->csi_z0 = scan_ctl(filename, argc, argv, "CSI_Z0", -1, "-5", NULL);
5262 ctl->csi_z1 = scan_ctl(filename, argc, argv, "CSI_Z1", -1, "85", NULL);
5263 ctl->csi_nz = (int) scan_ctl(filename, argc, argv, "CSI_NZ", -1, "1", NULL);
5264 ctl->csi_lon0 =
5265 scan_ctl(filename, argc, argv, "CSI_LON0", -1, "-180", NULL);
5266 ctl->csi_lon1 = scan_ctl(filename, argc, argv, "CSI_LON1", -1, "180", NULL);
5267 ctl->csi_nx =
5268 (int) scan_ctl(filename, argc, argv, "CSI_NX", -1, "360", NULL);
5269 ctl->csi_lat0 = scan_ctl(filename, argc, argv, "CSI_LAT0", -1, "-90", NULL);
5270 ctl->csi_lat1 = scan_ctl(filename, argc, argv, "CSI_LAT1", -1, "90", NULL);
5271 ctl->csi_ny =
5272 (int) scan_ctl(filename, argc, argv, "CSI_NY", -1, "180", NULL);
5273
5274 /* Output of ensemble data... */
5275 scan_ctl(filename, argc, argv, "ENS_BASENAME", -1, "-", ctl->ens_basename);
5276 ctl->ens_dt_out =
5277 scan_ctl(filename, argc, argv, "ENS_DT_OUT", -1, "86400", NULL);
5278
5279 /* Output of grid data... */
5280 scan_ctl(filename, argc, argv, "GRID_BASENAME", -1, "-",
5281 ctl->grid_basename);
5282 scan_ctl(filename, argc, argv, "GRID_KERNEL", -1, "-", ctl->grid_kernel);
5283 scan_ctl(filename, argc, argv, "GRID_GPFILE", -1, "-", ctl->grid_gpfile);
5284 ctl->grid_dt_out =
5285 scan_ctl(filename, argc, argv, "GRID_DT_OUT", -1, "86400", NULL);
5286 ctl->grid_sparse =
5287 (int) scan_ctl(filename, argc, argv, "GRID_SPARSE", -1, "0", NULL);
5288 ctl->grid_nc_level =
5289 (int) scan_ctl(filename, argc, argv, "GRID_NC_LEVEL", -1, "0", NULL);
5290 for (int iq = 0; iq < ctl->nq; iq++)
5291 ctl->grid_nc_quant[iq] =
5292 (int) scan_ctl(filename, argc, argv, "GRID_NC_QUANT", iq, "0", NULL);
5293 ctl->grid_stddev =
5294 (int) scan_ctl(filename, argc, argv, "GRID_STDDEV", -1, "0", NULL);
5295 ctl->grid_z0 = scan_ctl(filename, argc, argv, "GRID_Z0", -1, "-5", NULL);
5296 ctl->grid_z1 = scan_ctl(filename, argc, argv, "GRID_Z1", -1, "85", NULL);
5297 ctl->grid_nz =
5298 (int) scan_ctl(filename, argc, argv, "GRID_NZ", -1, "1", NULL);
5299 ctl->grid_lon0 =
5300 scan_ctl(filename, argc, argv, "GRID_LON0", -1, "-180", NULL);
5301 ctl->grid_lon1 =
5302 scan_ctl(filename, argc, argv, "GRID_LON1", -1, "180", NULL);
5303 ctl->grid_nx =
5304 (int) scan_ctl(filename, argc, argv, "GRID_NX", -1, "360", NULL);
5305 ctl->grid_lat0 =
5306 scan_ctl(filename, argc, argv, "GRID_LAT0", -1, "-90", NULL);
5307 ctl->grid_lat1 =
5308 scan_ctl(filename, argc, argv, "GRID_LAT1", -1, "90", NULL);
5309 ctl->grid_ny =
5310 (int) scan_ctl(filename, argc, argv, "GRID_NY", -1, "180", NULL);
5311 ctl->grid_type =
5312 (int) scan_ctl(filename, argc, argv, "GRID_TYPE", -1, "0", NULL);
5313
5314 /* Output of profile data... */
5315 scan_ctl(filename, argc, argv, "PROF_BASENAME", -1, "-",
5316 ctl->prof_basename);
5317 scan_ctl(filename, argc, argv, "PROF_OBSFILE", -1, "-", ctl->prof_obsfile);
5318 ctl->prof_z0 = scan_ctl(filename, argc, argv, "PROF_Z0", -1, "0", NULL);
5319 ctl->prof_z1 = scan_ctl(filename, argc, argv, "PROF_Z1", -1, "60", NULL);
5320 ctl->prof_nz =
5321 (int) scan_ctl(filename, argc, argv, "PROF_NZ", -1, "60", NULL);
5322 ctl->prof_lon0 =
5323 scan_ctl(filename, argc, argv, "PROF_LON0", -1, "-180", NULL);
5324 ctl->prof_lon1 =
5325 scan_ctl(filename, argc, argv, "PROF_LON1", -1, "180", NULL);
5326 ctl->prof_nx =
5327 (int) scan_ctl(filename, argc, argv, "PROF_NX", -1, "360", NULL);
5328 ctl->prof_lat0 =
5329 scan_ctl(filename, argc, argv, "PROF_LAT0", -1, "-90", NULL);
5330 ctl->prof_lat1 =
5331 scan_ctl(filename, argc, argv, "PROF_LAT1", -1, "90", NULL);
5332 ctl->prof_ny =
5333 (int) scan_ctl(filename, argc, argv, "PROF_NY", -1, "180", NULL);
5334
5335 /* Output of sample data... */
5336 scan_ctl(filename, argc, argv, "SAMPLE_BASENAME", -1, "-",
5337 ctl->sample_basename);
5338 scan_ctl(filename, argc, argv, "SAMPLE_KERNEL", -1, "-",
5339 ctl->sample_kernel);
5340 scan_ctl(filename, argc, argv, "SAMPLE_OBSFILE", -1, "-",
5341 ctl->sample_obsfile);
5342 ctl->sample_dx =
5343 scan_ctl(filename, argc, argv, "SAMPLE_DX", -1, "50", NULL);
5344 ctl->sample_dz =
5345 scan_ctl(filename, argc, argv, "SAMPLE_DZ", -1, "-999", NULL);
5346
5347 /* Output of station data... */
5348 scan_ctl(filename, argc, argv, "STAT_BASENAME", -1, "-",
5349 ctl->stat_basename);
5350 ctl->stat_lon = scan_ctl(filename, argc, argv, "STAT_LON", -1, "0", NULL);
5351 ctl->stat_lat = scan_ctl(filename, argc, argv, "STAT_LAT", -1, "0", NULL);
5352 ctl->stat_r = scan_ctl(filename, argc, argv, "STAT_R", -1, "50", NULL);
5353 ctl->stat_t0 =
5354 scan_ctl(filename, argc, argv, "STAT_T0", -1, "-1e100", NULL);
5355 ctl->stat_t1 = scan_ctl(filename, argc, argv, "STAT_T1", -1, "1e100", NULL);
5356
5357 /* Output of VTK data... */
5358 scan_ctl(filename, argc, argv, "VTK_BASENAME", -1, "-", ctl->vtk_basename);
5359 ctl->vtk_dt_out =
5360 scan_ctl(filename, argc, argv, "VTK_DT_OUT", -1, "86400", NULL);
5361 ctl->vtk_stride =
5362 (int) scan_ctl(filename, argc, argv, "VTK_STRIDE", -1, "1", NULL);
5363 ctl->vtk_scale =
5364 scan_ctl(filename, argc, argv, "VTK_SCALE", -1, "1.0", NULL);
5365 ctl->vtk_offset =
5366 scan_ctl(filename, argc, argv, "VTK_OFFSET", -1, "0.0", NULL);
5367 ctl->vtk_sphere =
5368 (int) scan_ctl(filename, argc, argv, "VTK_SPHERE", -1, "0", NULL);
5369}
5370
5371/*****************************************************************************/
5372
5374 const char *filename,
5375 const ctl_t *ctl,
5376 const clim_t *clim,
5377 met_t *met) {
5378
5379 /* Write info... */
5380 LOG(1, "Read meteo data: %s", filename);
5381
5382 /* Set rank... */
5383 int rank = 0;
5384#ifdef MPI
5385 if (ctl->met_mpi_share)
5386 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
5387#endif
5388
5389 /* Check rank... */
5390 if (!ctl->met_mpi_share || rank == 0) {
5391
5392 /* Read netCDF data... */
5393 if (ctl->met_type == 0) {
5394 if (read_met_nc(filename, ctl, clim, met) != 1)
5395 return 0;
5396 }
5397
5398 /* Read binary data... */
5399 else if (ctl->met_type >= 1 && ctl->met_type <= 5) {
5400 if (read_met_bin(filename, ctl, met) != 1)
5401 return 0;
5402 }
5403
5404 /* Not implemented... */
5405 else
5406 ERRMSG("MET_TYPE not implemented!");
5407 }
5408
5409 /* Broadcast data via MPI... */
5410#ifdef MPI
5411 if (ctl->met_mpi_share) {
5412
5413 /* Set timer... */
5414 SELECT_TIMER("READ_MET_MPI_BCAST", "COMM", NVTX_SEND);
5415 LOG(2, "Broadcast data on rank %d...", rank);
5416
5417 /* Broadcast... */
5418 broadcast_large_data(met, sizeof(met_t));
5419 }
5420#endif
5421
5422 /* Return success... */
5423 return 1;
5424}
5425
5426/*****************************************************************************/
5427
5429 ctl_t *ctl,
5430 cache_t *cache,
5431 clim_t *clim,
5432 met_t **met0,
5433 met_t **met1,
5434 atm_t *atm,
5435 double t) {
5436
5437 /* Initialize modules... */
5438 if (t == ctl->t_start) {
5439
5440 /* Initialize isosurface data... */
5441 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5442 module_isosurf_init(ctl, cache, *met0, *met1, atm);
5443
5444 /* Initialize advection... */
5445 module_advect_init(ctl, cache, *met0, *met1, atm);
5446
5447 /* Initialize chemistry... */
5448 module_chem_init(ctl, cache, clim, *met0, *met1, atm);
5449 }
5450
5451 /* Set time steps of air parcels... */
5452 module_timesteps(ctl, cache, *met0, atm, t);
5453
5454 /* Sort particles... */
5455 if (ctl->sort_dt > 0 && fmod(t, ctl->sort_dt) == 0)
5456 module_sort(ctl, *met0, atm);
5457
5458 /* Check positions (initial)... */
5459 module_position(cache, *met0, *met1, atm);
5460
5461 /* Advection... */
5462 if (ctl->advect > 0)
5463 module_advect(ctl, cache, *met0, *met1, atm);
5464
5465 /* Turbulent diffusion... */
5466 if (ctl->diffusion == 1
5467 && (ctl->turb_dx_pbl > 0 || ctl->turb_dz_pbl > 0
5468 || ctl->turb_dx_trop > 0 || ctl->turb_dz_trop > 0
5469 || ctl->turb_dx_strat > 0 || ctl->turb_dz_strat > 0))
5470 module_diff_turb(ctl, cache, clim, *met0, *met1, atm);
5471
5472 /* Mesoscale diffusion... */
5473 if (ctl->diffusion == 1 && (ctl->turb_mesox > 0 || ctl->turb_mesoz > 0))
5474 module_diff_meso(ctl, cache, *met0, *met1, atm);
5475
5476 /* Diffusion... */
5477 if (ctl->diffusion == 2)
5478 module_diff_pbl(ctl, cache, *met0, *met1, atm);
5479
5480 /* Convection... */
5481 if ((ctl->conv_mix_pbl || ctl->conv_cape >= 0)
5482 && (ctl->conv_dt <= 0 || fmod(t, ctl->conv_dt) == 0))
5483 module_convection(ctl, cache, *met0, *met1, atm);
5484
5485 /* Sedimentation... */
5486 if (ctl->qnt_rp >= 0 && ctl->qnt_rhop >= 0)
5487 module_sedi(ctl, cache, *met0, *met1, atm);
5488
5489 /* Isosurface... */
5490 if (ctl->isosurf >= 1 && ctl->isosurf <= 4)
5491 module_isosurf(ctl, cache, *met0, *met1, atm);
5492
5493 /* Check positions (final)... */
5494 module_position(cache, *met0, *met1, atm);
5495
5496 /* Interpolate meteo data... */
5497 if (ctl->met_dt_out > 0
5498 && (ctl->met_dt_out < ctl->dt_mod || fmod(t, ctl->met_dt_out) == 0))
5499 module_meteo(ctl, cache, clim, *met0, *met1, atm);
5500
5501 /* Check boundary conditions (initial)... */
5502 if ((ctl->bound_lat0 < ctl->bound_lat1)
5503 && (ctl->bound_p0 > ctl->bound_p1))
5504 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5505
5506 /* Initialize quantity of total loss rate... */
5507 if (ctl->qnt_loss_rate >= 0) {
5508 PARTICLE_LOOP(0, atm->np, 1, "acc data present(ctl,atm)") {
5509 atm->q[ctl->qnt_loss_rate][ip] = 0;
5510 }
5511 }
5512
5513 /* Decay of particle mass... */
5514 if (ctl->tdec_trop > 0 && ctl->tdec_strat > 0)
5515 module_decay(ctl, cache, clim, atm);
5516
5517 /* Interparcel mixing... */
5518 if (ctl->mixing_trop >= 0 && ctl->mixing_strat >= 0
5519 && (ctl->mixing_dt <= 0 || fmod(t, ctl->mixing_dt) == 0))
5520 module_mixing(ctl, clim, atm, t);
5521
5522 /* Calculate the tracer vmr in the chemistry grid... */
5523 if (ctl->oh_chem_reaction != 0 || ctl->h2o2_chem_reaction != 0
5524 || (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0))
5525 module_chem_grid(ctl, *met0, *met1, atm, t);
5526
5527 /* OH chemistry... */
5528 if (ctl->oh_chem_reaction != 0)
5529 module_oh_chem(ctl, cache, clim, *met0, *met1, atm);
5530
5531 /* H2O2 chemistry (for SO2 aqueous phase oxidation)... */
5532 if (ctl->h2o2_chem_reaction != 0)
5533 module_h2o2_chem(ctl, cache, clim, *met0, *met1, atm);
5534
5535 /* First-order tracer chemistry... */
5536 if (ctl->tracer_chem)
5537 module_tracer_chem(ctl, cache, clim, *met0, *met1, atm);
5538
5539 /* KPP chemistry... */
5540 if (ctl->kpp_chem && fmod(t, ctl->dt_kpp) == 0) {
5541#ifdef KPP
5542 module_kpp_chem(ctl, cache, clim, *met0, *met1, atm);
5543#else
5544 ERRMSG("Code was compiled without KPP!");
5545#endif
5546 }
5547
5548 /* Wet deposition... */
5549 if ((ctl->wet_depo_ic_a > 0 || ctl->wet_depo_ic_h[0] > 0)
5550 && (ctl->wet_depo_bc_a > 0 || ctl->wet_depo_bc_h[0] > 0))
5551 module_wet_depo(ctl, cache, *met0, *met1, atm);
5552
5553 /* Dry deposition... */
5554 if (ctl->dry_depo_vdep > 0)
5555 module_dry_depo(ctl, cache, *met0, *met1, atm);
5556
5557 /* Check boundary conditions (final)... */
5558 if ((ctl->bound_lat0 < ctl->bound_lat1)
5559 && (ctl->bound_p0 > ctl->bound_p1))
5560 module_bound_cond(ctl, cache, clim, *met0, *met1, atm);
5561}
5562
5563/*****************************************************************************/
5564
5566 const ctl_t *ctl,
5567 const cache_t *cache,
5568 const clim_t *clim,
5569 met_t **met0,
5570 met_t **met1,
5571 const atm_t *atm) {
5572
5573 /* Update GPU... */
5574 if (ctl != NULL) {
5575#ifdef _OPENACC
5576 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5577#pragma acc update device(ctl[:1])
5578#endif
5579 }
5580
5581 if (cache != NULL) {
5582#ifdef _OPENACC
5583 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5584#pragma acc update device(cache[:1])
5585#endif
5586 }
5587
5588 if (clim != NULL) {
5589#ifdef _OPENACC
5590 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5591#pragma acc update device(clim[:1])
5592#endif
5593 }
5594
5595 if (met0 != NULL) {
5596#ifdef _OPENACC
5597 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5598 met_t *met0up = *met0;
5599#pragma acc update device(met0up[:1])
5600#endif
5601 }
5602
5603 if (met1 != NULL) {
5604#ifdef _OPENACC
5605 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5606 met_t *met1up = *met1;
5607#pragma acc update device(met1up[:1])
5608#endif
5609 }
5610
5611 if (atm != NULL) {
5612#ifdef _OPENACC
5613 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5614#pragma acc update device(atm[:1])
5615#endif
5616 }
5617}
5618
5619/*****************************************************************************/
5620
5622 const ctl_t *ctl,
5623 const cache_t *cache,
5624 const clim_t *clim,
5625 met_t **met0,
5626 met_t **met1,
5627 const atm_t *atm) {
5628
5629 /* Update GPU... */
5630 if (ctl != NULL) {
5631#ifdef _OPENACC
5632 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5633#pragma acc update host(ctl[:1])
5634#endif
5635 }
5636
5637 if (cache != NULL) {
5638#ifdef _OPENACC
5639 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5640#pragma acc update host(cache[:1])
5641#endif
5642 }
5643
5644 if (clim != NULL) {
5645#ifdef _OPENACC
5646 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5647#pragma acc update host(clim[:1])
5648#endif
5649 }
5650
5651 if (met0 != NULL) {
5652#ifdef _OPENACC
5653 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5654 met_t *met0up = *met0;
5655#pragma acc update host(met0up[:1])
5656#endif
5657 }
5658
5659 if (met1 != NULL) {
5660#ifdef _OPENACC
5661 SELECT_TIMER("UPDATE_DEVICE", "MEMORY", NVTX_H2D);
5662 met_t *met1up = *met1;
5663#pragma acc update host(met1up[:1])
5664#endif
5665 }
5666
5667 if (atm != NULL) {
5668#ifdef _OPENACC
5669 SELECT_TIMER("UPDATE_HOST", "MEMORY", NVTX_H2D);
5670#pragma acc update host(atm[:1])
5671#endif
5672 }
5673}
5674
5675/*****************************************************************************/
5676
5678 const char *filename,
5679 const ctl_t *ctl,
5680 const atm_t *atm,
5681 const double t) {
5682
5683 /* Set timer... */
5684 SELECT_TIMER("WRITE_ATM", "OUTPUT", NVTX_WRITE);
5685
5686 /* Write info... */
5687 LOG(1, "Write atmospheric data: %s", filename);
5688
5689 /* Write ASCII data... */
5690 if (ctl->atm_type_out == 0)
5691 write_atm_asc(filename, ctl, atm, t);
5692
5693 /* Write binary data... */
5694 else if (ctl->atm_type_out == 1)
5695 write_atm_bin(filename, ctl, atm);
5696
5697 /* Write netCDF data... */
5698 else if (ctl->atm_type_out == 2)
5699 write_atm_nc(filename, ctl, atm);
5700
5701 /* Write CLaMS trajectory data... */
5702 else if (ctl->atm_type_out == 3)
5703 write_atm_clams_traj(filename, ctl, atm, t);
5704
5705 /* Write CLaMS pos data... */
5706 else if (ctl->atm_type_out == 4)
5707 write_atm_clams(filename, ctl, atm);
5708
5709 /* Error... */
5710 else
5711 ERRMSG("Atmospheric data type not supported!");
5712
5713 /* Write info... */
5714 double mini, maxi;
5715 LOG(2, "Number of particles: %d", atm->np);
5716 gsl_stats_minmax(&mini, &maxi, atm->time, 1, (size_t) atm->np);
5717 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
5718 gsl_stats_minmax(&mini, &maxi, atm->p, 1, (size_t) atm->np);
5719 LOG(2, "Altitude range: %g ... %g km", Z(maxi), Z(mini));
5720 LOG(2, "Pressure range: %g ... %g hPa", maxi, mini);
5721 gsl_stats_minmax(&mini, &maxi, atm->lon, 1, (size_t) atm->np);
5722 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
5723 gsl_stats_minmax(&mini, &maxi, atm->lat, 1, (size_t) atm->np);
5724 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
5725 for (int iq = 0; iq < ctl->nq; iq++) {
5726 char msg[5 * LEN];
5727 sprintf(msg, "Quantity %s range: %s ... %s %s",
5728 ctl->qnt_name[iq], ctl->qnt_format[iq],
5729 ctl->qnt_format[iq], ctl->qnt_unit[iq]);
5730 gsl_stats_minmax(&mini, &maxi, atm->q[iq], 1, (size_t) atm->np);
5731 LOG(2, msg, mini, maxi);
5732 }
5733}
5734
5735/*****************************************************************************/
5736
5738 const char *filename,
5739 const ctl_t *ctl,
5740 met_t *met) {
5741
5742 /* Set timer... */
5743 SELECT_TIMER("WRITE_MET", "OUTPUT", NVTX_WRITE);
5744
5745 /* Write info... */
5746 LOG(1, "Write meteo data: %s", filename);
5747
5748 /* Check compression flags... */
5749#ifndef ZFP
5750 if (ctl->met_type == 3)
5751 ERRMSG("MPTRAC was compiled without zfp compression!");
5752#endif
5753#ifndef ZSTD
5754 if (ctl->met_type == 4)
5755 ERRMSG("MPTRAC was compiled without zstd compression!");
5756#endif
5757#ifndef CMS
5758 if (ctl->met_type == 5)
5759 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
5760#endif
5761
5762 /* Write netCDF data... */
5763 if (ctl->met_type == 0)
5764 write_met_nc(filename, ctl, met);
5765
5766 /* Write binary data... */
5767 else if (ctl->met_type >= 1 && ctl->met_type <= 5)
5768 write_met_bin(filename, ctl, met);
5769
5770 /* Not implemented... */
5771 else
5772 ERRMSG("MET_TYPE not implemented!");
5773}
5774
5775/*****************************************************************************/
5776
5778 const char *dirname,
5779 const ctl_t *ctl,
5780 met_t *met0,
5781 met_t *met1,
5782 atm_t *atm,
5783 const double t) {
5784
5785 char ext[10], filename[2 * LEN];
5786
5787 double r;
5788
5789 int year, mon, day, hour, min, sec;
5790
5791 /* Get time... */
5792 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
5793
5794 /* Update host... */
5795 if ((ctl->atm_basename[0] != '-' && fmod(t, ctl->atm_dt_out) == 0)
5796 || (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0)
5797 || (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0)
5798 || ctl->csi_basename[0] != '-' || ctl->prof_basename[0] != '-'
5799 || ctl->sample_basename[0] != '-' || ctl->stat_basename[0] != '-'
5800 || (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0))
5801 mptrac_update_host(NULL, NULL, NULL, NULL, NULL, atm);
5802
5803 /* Write atmospheric data... */
5804 if (ctl->atm_basename[0] != '-' &&
5805 (fmod(t, ctl->atm_dt_out) == 0 || t == ctl->t_stop)) {
5806 if (ctl->atm_type_out == 0)
5807 sprintf(ext, "tab");
5808 else if (ctl->atm_type_out == 1)
5809 sprintf(ext, "bin");
5810 else if (ctl->atm_type_out == 2)
5811 sprintf(ext, "nc");
5812 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5813 dirname, ctl->atm_basename, year, mon, day, hour, min, ext);
5814 mptrac_write_atm(filename, ctl, atm, t);
5815 }
5816
5817 /* Write gridded data... */
5818 if (ctl->grid_basename[0] != '-' && fmod(t, ctl->grid_dt_out) == 0) {
5819 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.%s",
5820 dirname, ctl->grid_basename, year, mon, day, hour, min,
5821 ctl->grid_type == 0 ? "tab" : "nc");
5822 write_grid(filename, ctl, met0, met1, atm, t);
5823 }
5824
5825 /* Write CSI data... */
5826 if (ctl->csi_basename[0] != '-') {
5827 sprintf(filename, "%s/%s.tab", dirname, ctl->csi_basename);
5828 write_csi(filename, ctl, atm, t);
5829 }
5830
5831 /* Write ensemble data... */
5832 if (ctl->ens_basename[0] != '-' && fmod(t, ctl->ens_dt_out) == 0) {
5833 sprintf(filename, "%s/%s_%04d_%02d_%02d_%02d_%02d.tab",
5834 dirname, ctl->ens_basename, year, mon, day, hour, min);
5835 write_ens(filename, ctl, atm, t);
5836 }
5837
5838 /* Write profile data... */
5839 if (ctl->prof_basename[0] != '-') {
5840 sprintf(filename, "%s/%s.tab", dirname, ctl->prof_basename);
5841 write_prof(filename, ctl, met0, met1, atm, t);
5842 }
5843
5844 /* Write sample data... */
5845 if (ctl->sample_basename[0] != '-') {
5846 sprintf(filename, "%s/%s.tab", dirname, ctl->sample_basename);
5847 write_sample(filename, ctl, met0, met1, atm, t);
5848 }
5849
5850 /* Write station data... */
5851 if (ctl->stat_basename[0] != '-') {
5852 sprintf(filename, "%s/%s.tab", dirname, ctl->stat_basename);
5853 write_station(filename, ctl, atm, t);
5854 }
5855
5856 /* Write VTK data... */
5857 if (ctl->vtk_basename[0] != '-' && fmod(t, ctl->vtk_dt_out) == 0) {
5858 static int nvtk;
5859 if (t == ctl->t_start)
5860 nvtk = 0;
5861 sprintf(filename, "%s/%s_%05d.vtk", dirname, ctl->vtk_basename, ++nvtk);
5862 write_vtk(filename, ctl, atm, t);
5863 }
5864}
5865
5866/*****************************************************************************/
5867
5869 const double p,
5870 const double h2o,
5871 const double hno3) {
5872
5873 /* Check water vapor volume mixing ratio... */
5874 const double h2o_help = MAX(h2o, 0.1e-6);
5875
5876 /* Calculate T_NAT... */
5877 const double p_hno3 = hno3 * p / 1.333224;
5878 const double p_h2o = h2o_help * p / 1.333224;
5879 const double a = 0.009179 - 0.00088 * log10(p_h2o);
5880 const double b = (38.9855 - log10(p_hno3) - 2.7836 * log10(p_h2o)) / a;
5881 const double c = -11397.0 / a;
5882 double tnat = (-b + sqrt(b * b - 4. * c)) / 2.;
5883 double x2 = (-b - sqrt(b * b - 4. * c)) / 2.;
5884 if (x2 > 0)
5885 tnat = x2;
5886
5887 return tnat;
5888}
5889
5890/*****************************************************************************/
5891
5893 const ctl_t *ctl,
5894 const atm_t *atm,
5895 const int ip,
5896 const double pbl,
5897 const double ps) {
5898
5899 /* Get pressure range... */
5900 const double p1 = pbl - ctl->conv_pbl_trans * (ps - pbl);
5901 const double p0 = pbl;
5902
5903 /* Get weighting factor... */
5904 if (atm->p[ip] > p0)
5905 return 1;
5906 else if (atm->p[ip] < p1)
5907 return 0;
5908 else
5909 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
5910}
5911
5912/*****************************************************************************/
5913
5915 const char *filename,
5916 const ctl_t *ctl,
5917 atm_t *atm) {
5918
5919 /* Open file... */
5920 FILE *in;
5921 if (!(in = fopen(filename, "r"))) {
5922 WARN("Cannot open file!");
5923 return 0;
5924 }
5925
5926 /* Read line... */
5927 char line[LEN];
5928 while (fgets(line, LEN, in)) {
5929
5930 /* Read data... */
5931 char *tok;
5932 TOK(line, tok, "%lg", atm->time[atm->np]);
5933 TOK(NULL, tok, "%lg", atm->p[atm->np]);
5934 TOK(NULL, tok, "%lg", atm->lon[atm->np]);
5935 TOK(NULL, tok, "%lg", atm->lat[atm->np]);
5936 for (int iq = 0; iq < ctl->nq; iq++)
5937 TOK(NULL, tok, "%lg", atm->q[iq][atm->np]);
5938
5939 /* Convert altitude to pressure... */
5940 atm->p[atm->np] = P(atm->p[atm->np]);
5941
5942 /* Increment data point counter... */
5943 if ((++atm->np) > NP)
5944 ERRMSG("Too many data points!");
5945 }
5946
5947 /* Close file... */
5948 fclose(in);
5949
5950 /* Return success... */
5951 return 1;
5952}
5953
5954/*****************************************************************************/
5955
5957 const char *filename,
5958 const ctl_t *ctl,
5959 atm_t *atm) {
5960
5961 /* Open file... */
5962 FILE *in;
5963 if (!(in = fopen(filename, "r")))
5964 return 0;
5965
5966 /* Check version of binary data... */
5967 int version;
5968 FREAD(&version, int,
5969 1,
5970 in);
5971 if (version != 100)
5972 ERRMSG("Wrong version of binary data!");
5973
5974 /* Read data... */
5975 FREAD(&atm->np, int,
5976 1,
5977 in);
5978 FREAD(atm->time, double,
5979 (size_t) atm->np,
5980 in);
5981 FREAD(atm->p, double,
5982 (size_t) atm->np,
5983 in);
5984 FREAD(atm->lon, double,
5985 (size_t) atm->np,
5986 in);
5987 FREAD(atm->lat, double,
5988 (size_t) atm->np,
5989 in);
5990 for (int iq = 0; iq < ctl->nq; iq++)
5991 FREAD(atm->q[iq], double,
5992 (size_t) atm->np,
5993 in);
5994
5995 /* Read final flag... */
5996 int final;
5997 FREAD(&final, int,
5998 1,
5999 in);
6000 if (final != 999)
6001 ERRMSG("Error while reading binary data!");
6002
6003 /* Close file... */
6004 fclose(in);
6005
6006 /* Return success... */
6007 return 1;
6008}
6009
6010/*****************************************************************************/
6011
6013 const char *filename,
6014 const ctl_t *ctl,
6015 atm_t *atm) {
6016
6017 int ncid, varid;
6018
6019 /* Open file... */
6020 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6021 return 0;
6022
6023 /* Get dimensions... */
6024 NC_INQ_DIM("NPARTS", &atm->np, 1, NP);
6025
6026 /* Get time... */
6027 if (nc_inq_varid(ncid, "TIME_INIT", &varid) == NC_NOERR) {
6028 NC(nc_get_var_double(ncid, varid, atm->time));
6029 } else {
6030 WARN("TIME_INIT not found use time instead!");
6031 double time_init;
6032 NC_GET_DOUBLE("time", &time_init, 1);
6033 for (int ip = 0; ip < atm->np; ip++) {
6034 atm->time[ip] = time_init;
6035 }
6036 }
6037
6038 /* Read zeta coordinate, pressure is optional... */
6039 if (ctl->advect_vert_coord == 1) {
6040 NC_GET_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
6041 NC_GET_DOUBLE("PRESS", atm->p, 0);
6042 }
6043
6044 /* Read pressure, zeta coordinate is optional... */
6045 else {
6046 if (nc_inq_varid(ncid, "PRESS_INIT", &varid) == NC_NOERR) {
6047 NC(nc_get_var_double(ncid, varid, atm->p));
6048 } else {
6049 WARN("PRESS_INIT not found use PRESS instead!");
6050 nc_inq_varid(ncid, "PRESS", &varid);
6051 NC(nc_get_var_double(ncid, varid, atm->p));
6052 }
6053 }
6054
6055 /* Read longitude and latitude... */
6056 NC_GET_DOUBLE("LON", atm->lon, 1);
6057 NC_GET_DOUBLE("LAT", atm->lat, 1);
6058
6059 /* Close file... */
6060 NC(nc_close(ncid));
6061
6062 /* Return success... */
6063 return 1;
6064}
6065
6066/*****************************************************************************/
6067
6069 const char *filename,
6070 const ctl_t *ctl,
6071 atm_t *atm) {
6072
6073 int ncid, varid;
6074
6075 /* Open file... */
6076 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
6077 return 0;
6078
6079 /* Get dimensions... */
6080 NC_INQ_DIM("obs", &atm->np, 1, NP);
6081
6082 /* Read geolocations... */
6083 NC_GET_DOUBLE("time", atm->time, 1);
6084 NC_GET_DOUBLE("press", atm->p, 1);
6085 NC_GET_DOUBLE("lon", atm->lon, 1);
6086 NC_GET_DOUBLE("lat", atm->lat, 1);
6087
6088 /* Read variables... */
6089 for (int iq = 0; iq < ctl->nq; iq++)
6090 NC_GET_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
6091
6092 /* Close file... */
6093 NC(nc_close(ncid));
6094
6095 /* Return success... */
6096 return 1;
6097}
6098
6099/*****************************************************************************/
6100
6102 const char *filename,
6103 clim_photo_t *photo) {
6104
6105 int ncid, varid;
6106
6107 /* Write info... */
6108 LOG(1, "Read photolysis rates: %s", filename);
6109
6110 /* Open netCDF file... */
6111 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6112 WARN("Photolysis rate data are missing!");
6113 return;
6114 }
6115
6116 /* Read pressure data... */
6117 NC_INQ_DIM("press", &photo->np, 2, CP);
6118 NC_GET_DOUBLE("press", photo->p, 1);
6119 if (photo->p[0] < photo->p[1])
6120 ERRMSG("Pressure data are not descending!");
6121
6122 /* Read total column ozone data... */
6123 NC_INQ_DIM("total_o3col", &photo->no3c, 2, CO3);
6124 NC_GET_DOUBLE("total_o3col", photo->o3c, 1);
6125 if (photo->o3c[0] > photo->o3c[1])
6126 ERRMSG("Total column ozone data are not ascending!");
6127
6128 /* Read solar zenith angle data... */
6129 NC_INQ_DIM("sza", &photo->nsza, 2, CSZA);
6130 NC_GET_DOUBLE("sza", photo->sza, 1);
6131 if (photo->sza[0] > photo->sza[1])
6132 ERRMSG("Solar zenith angle data are not ascending!");
6133
6134 /* Read data... */
6135 read_clim_photo_help(ncid, "J_N2O", photo, photo->n2o);
6136 read_clim_photo_help(ncid, "J_CCl4", photo, photo->ccl4);
6137 read_clim_photo_help(ncid, "J_CFC-11", photo, photo->ccl3f);
6138 read_clim_photo_help(ncid, "J_CFC-12", photo, photo->ccl2f2);
6139 read_clim_photo_help(ncid, "J_O2", photo, photo->o2);
6140 read_clim_photo_help(ncid, "J_O3b", photo, photo->o3_1);
6141 read_clim_photo_help(ncid, "J_O3a", photo, photo->o3_2);
6142 read_clim_photo_help(ncid, "J_H2O2", photo, photo->h2o2);
6143 read_clim_photo_help(ncid, "J_H2O", photo, photo->h2o);
6144
6145 /* Close netCDF file... */
6146 NC(nc_close(ncid));
6147
6148 /* Write info... */
6149 LOG(2, "Number of pressure levels: %d", photo->np);
6150 LOG(2, "Altitude levels: %g, %g ... %g km",
6151 Z(photo->p[0]), Z(photo->p[1]), Z(photo->p[photo->np - 1]));
6152 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6153 photo->p[0], photo->p[1], photo->p[photo->np - 1]);
6154 LOG(2, "Number of solar zenith angles: %d", photo->nsza);
6155 LOG(2, "Solar zenith angles: %g, %g ... %g deg",
6156 RAD2DEG(photo->sza[0]), RAD2DEG(photo->sza[1]),
6157 RAD2DEG(photo->sza[photo->nsza - 1]));
6158 LOG(2, "Number of total column ozone values: %d", photo->no3c);
6159 LOG(2, "Total column ozone: %g, %g ... %g DU",
6160 photo->o3c[0], photo->o3c[1], photo->o3c[photo->no3c - 1]);
6161 LOG(2, "N2O photolysis rate: %g, %g ... %g s**-1",
6162 photo->n2o[0][0][0], photo->n2o[1][0][0],
6163 photo->n2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6164 LOG(2, "CCl4 photolysis rate: %g, %g ... %g s**-1",
6165 photo->ccl4[0][0][0], photo->ccl4[1][0][0],
6166 photo->ccl4[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6167 LOG(2, "CFC-11 photolysis rate: %g, %g ... %g s**-1",
6168 photo->ccl3f[0][0][0], photo->ccl3f[1][0][0],
6169 photo->ccl3f[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6170 LOG(2, "CFC-12 photolysis rate: %g, %g ... %g s**-1",
6171 photo->ccl2f2[0][0][0], photo->ccl2f2[1][0][0],
6172 photo->ccl2f2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6173 LOG(2, "O2 photolysis rate: %g, %g ... %g s**-1",
6174 photo->o2[0][0][0], photo->o2[1][0][0],
6175 photo->o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6176 LOG(2, "O3 -> O(1D) photolysis rate: %g, %g ... %g s**-1",
6177 photo->o3_1[0][0][0], photo->o3_1[1][0][0],
6178 photo->o3_1[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6179 LOG(2, "O3 -> O(3P) photolysis rate: %g, %g ... %g s**-1",
6180 photo->o3_2[0][0][0], photo->o3_2[1][0][0],
6181 photo->o3_2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6182 LOG(2, "H2O2 photolysis rate: %g, %g ... %g s**-1",
6183 photo->h2o2[0][0][0], photo->h2o2[1][0][0],
6184 photo->h2o2[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6185 LOG(2, "H2O photolysis rate: %g, %g ... %g s**-1",
6186 photo->h2o[0][0][0], photo->h2o[1][0][0],
6187 photo->h2o[photo->np - 1][photo->nsza - 1][photo->no3c - 1]);
6188}
6189
6190/*****************************************************************************/
6191
6193 const int ncid,
6194 const char *varname,
6195 const clim_photo_t *photo,
6196 double var[CP][CSZA][CO3]) {
6197
6198 /* Allocate... */
6199 double *help;
6200 ALLOC(help, double,
6201 photo->np * photo->nsza * photo->no3c);
6202
6203 /* Read varible... */
6204 int varid;
6205 NC_GET_DOUBLE(varname, help, 1);
6206
6207 /* Copy data... */
6208 for (int ip = 0; ip < photo->np; ip++)
6209 for (int is = 0; is < photo->nsza; is++)
6210 for (int io = 0; io < photo->no3c; io++)
6211 var[ip][is][io] =
6212 help[ARRAY_3D(ip, is, photo->nsza, io, photo->no3c)];
6213
6214 /* Free... */
6215 free(help);
6216}
6217
6218/*****************************************************************************/
6219
6221 const char *filename,
6222 clim_ts_t *ts) {
6223
6224 /* Write info... */
6225 LOG(1, "Read climatological time series: %s", filename);
6226
6227 /* Open file... */
6228 FILE *in;
6229 if (!(in = fopen(filename, "r"))) {
6230 WARN("Cannot open file!");
6231 return 0;
6232 }
6233
6234 /* Read data... */
6235 char line[LEN];
6236 int nh = 0;
6237 while (fgets(line, LEN, in))
6238 if (sscanf(line, "%lg %lg", &ts->time[nh], &ts->vmr[nh]) == 2) {
6239
6240 /* Convert years to seconds... */
6241 ts->time[nh] = (ts->time[nh] - 2000.0) * 365.25 * 86400.;
6242
6243 /* Check data... */
6244 if (nh > 0 && ts->time[nh] <= ts->time[nh - 1])
6245 ERRMSG("Time series must be ascending!");
6246
6247 /* Count time steps... */
6248 if ((++nh) >= CTS)
6249 ERRMSG("Too many data points!");
6250 }
6251
6252 /* Close file... */
6253 fclose(in);
6254
6255 /* Check number of data points... */
6256 ts->ntime = nh;
6257 if (nh < 2)
6258 ERRMSG("Not enough data points!");
6259
6260 /* Write info... */
6261 LOG(2, "Number of time steps: %d", ts->ntime);
6262 LOG(2, "Time steps: %.2f, %.2f ... %.2f s", ts->time[0], ts->time[1],
6263 ts->time[nh - 1]);
6264 LOG(2, "Volume mixing ratio range: %g ... %g ppv",
6265 gsl_stats_min(ts->vmr, 1, (size_t) nh), gsl_stats_max(ts->vmr, 1,
6266 (size_t) nh));
6267
6268 /* Exit success... */
6269 return 1;
6270}
6271
6272/*****************************************************************************/
6273
6275 const char *filename,
6276 const char *varname,
6277 clim_zm_t *zm) {
6278
6279 int ncid, varid, it, iy, iz, iz2, nt;
6280
6281 double *help, varmin = 1e99, varmax = -1e99;
6282
6283 /* Write info... */
6284 LOG(1, "Read %s data: %s", varname, filename);
6285
6286 /* Open netCDF file... */
6287 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
6288 WARN("%s climatology data are missing!", varname);
6289 return;
6290 }
6291
6292 /* Read pressure data... */
6293 NC_INQ_DIM("press", &zm->np, 2, CP);
6294 NC_GET_DOUBLE("press", zm->p, 1);
6295 if (zm->p[0] < zm->p[1])
6296 ERRMSG("Pressure data are not descending!");
6297
6298 /* Read latitudes... */
6299 NC_INQ_DIM("lat", &zm->nlat, 2, CY);
6300 NC_GET_DOUBLE("lat", zm->lat, 1);
6301 if (zm->lat[0] > zm->lat[1])
6302 ERRMSG("Latitude data are not ascending!");
6303
6304 /* Set time data (for monthly means)... */
6305 zm->ntime = 12;
6306 zm->time[0] = 1209600.00;
6307 zm->time[1] = 3888000.00;
6308 zm->time[2] = 6393600.00;
6309 zm->time[3] = 9072000.00;
6310 zm->time[4] = 11664000.00;
6311 zm->time[5] = 14342400.00;
6312 zm->time[6] = 16934400.00;
6313 zm->time[7] = 19612800.00;
6314 zm->time[8] = 22291200.00;
6315 zm->time[9] = 24883200.00;
6316 zm->time[10] = 27561600.00;
6317 zm->time[11] = 30153600.00;
6318
6319 /* Check number of timesteps... */
6320 NC_INQ_DIM("time", &nt, 12, 12);
6321
6322 /* Read data... */
6323 ALLOC(help, double,
6324 zm->nlat * zm->np * zm->ntime);
6325 NC_GET_DOUBLE(varname, help, 1);
6326 for (it = 0; it < zm->ntime; it++)
6327 for (iz = 0; iz < zm->np; iz++)
6328 for (iy = 0; iy < zm->nlat; iy++)
6329 zm->vmr[it][iz][iy] = help[ARRAY_3D(it, iz, zm->np, iy, zm->nlat)];
6330 free(help);
6331
6332 /* Fix data gaps... */
6333 for (it = 0; it < zm->ntime; it++)
6334 for (iy = 0; iy < zm->nlat; iy++)
6335 for (iz = 0; iz < zm->np; iz++) {
6336 if (zm->vmr[it][iz][iy] < 0) {
6337 for (iz2 = 0; iz2 < zm->np; iz2++)
6338 if (zm->vmr[it][iz2][iy] >= 0) {
6339 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6340 break;
6341 }
6342 for (iz2 = zm->np - 1; iz2 >= 0; iz2--)
6343 if (zm->vmr[it][iz2][iy] >= 0) {
6344 zm->vmr[it][iz][iy] = zm->vmr[it][iz2][iy];
6345 break;
6346 }
6347 }
6348 varmin = MIN(varmin, zm->vmr[it][iz][iy]);
6349 varmax = MAX(varmax, zm->vmr[it][iz][iy]);
6350 }
6351
6352 /* Close netCDF file... */
6353 NC(nc_close(ncid));
6354
6355 /* Write info... */
6356 LOG(2, "Number of time steps: %d", zm->ntime);
6357 LOG(2, "Time steps: %.2f, %.2f ... %.2f s",
6358 zm->time[0], zm->time[1], zm->time[zm->ntime - 1]);
6359 LOG(2, "Number of pressure levels: %d", zm->np);
6360 LOG(2, "Altitude levels: %g, %g ... %g km",
6361 Z(zm->p[0]), Z(zm->p[1]), Z(zm->p[zm->np - 1]));
6362 LOG(2, "Pressure levels: %g, %g ... %g hPa", zm->p[0],
6363 zm->p[1], zm->p[zm->np - 1]);
6364 LOG(2, "Number of latitudes: %d", zm->nlat);
6365 LOG(2, "Latitudes: %g, %g ... %g deg",
6366 zm->lat[0], zm->lat[1], zm->lat[zm->nlat - 1]);
6367 LOG(2, "%s volume mixing ratio range: %g ... %g ppv", varname, varmin,
6368 varmax);
6369}
6370
6371/*****************************************************************************/
6372
6374 const char *filename,
6375 double kz[EP],
6376 double kw[EP],
6377 int *nk) {
6378
6379 /* Write info... */
6380 LOG(1, "Read kernel function: %s", filename);
6381
6382 /* Open file... */
6383 FILE *in;
6384 if (!(in = fopen(filename, "r")))
6385 ERRMSG("Cannot open file!");
6386
6387 /* Read data... */
6388 char line[LEN];
6389 int n = 0;
6390 while (fgets(line, LEN, in))
6391 if (sscanf(line, "%lg %lg", &kz[n], &kw[n]) == 2) {
6392 if (n > 0 && kz[n] < kz[n - 1])
6393 ERRMSG("Height levels must be ascending!");
6394 if ((++n) >= EP)
6395 ERRMSG("Too many height levels!");
6396 }
6397
6398 /* Close file... */
6399 fclose(in);
6400
6401 /* Check number of data points... */
6402 *nk = n;
6403 if (n < 2)
6404 ERRMSG("Not enough height levels!");
6405
6406 /* Normalize kernel function... */
6407 const double kmax = gsl_stats_max(kw, 1, (size_t) n);
6408 for (int iz = 0; iz < n; iz++)
6409 kw[iz] /= kmax;
6410}
6411
6412/*****************************************************************************/
6413
6415 const char *filename,
6416 const ctl_t *ctl,
6417 met_t *met) {
6418
6419 FILE *in;
6420
6421 double r;
6422
6423 int year, mon, day, hour, min, sec;
6424
6425 /* Set timer... */
6426 SELECT_TIMER("READ_MET_BIN", "INPUT", NVTX_READ);
6427
6428 /* Open file... */
6429 if (!(in = fopen(filename, "r"))) {
6430 WARN("Cannot open file!");
6431 return 0;
6432 }
6433
6434 /* Check type of binary data... */
6435 int met_type;
6436 FREAD(&met_type, int,
6437 1,
6438 in);
6439 if (met_type != ctl->met_type)
6440 ERRMSG("Wrong MET_TYPE of binary data!");
6441
6442 /* Check version of binary data... */
6443 int version;
6444 FREAD(&version, int,
6445 1,
6446 in);
6447 if (version != 103)
6448 ERRMSG("Wrong version of binary data!");
6449
6450 /* Read time... */
6451 FREAD(&met->time, double,
6452 1,
6453 in);
6454 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
6455 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
6456 met->time, year, mon, day, hour, min);
6457 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
6458 || day < 1 || day > 31 || hour < 0 || hour > 23)
6459 ERRMSG("Error while reading time!");
6460
6461 /* Read dimensions... */
6462 FREAD(&met->nx, int,
6463 1,
6464 in);
6465 LOG(2, "Number of longitudes: %d", met->nx);
6466 if (met->nx < 2 || met->nx > EX)
6467 ERRMSG("Number of longitudes out of range!");
6468
6469 FREAD(&met->ny, int,
6470 1,
6471 in);
6472 LOG(2, "Number of latitudes: %d", met->ny);
6473 if (met->ny < 2 || met->ny > EY)
6474 ERRMSG("Number of latitudes out of range!");
6475
6476 FREAD(&met->np, int,
6477 1,
6478 in);
6479 LOG(2, "Number of levels: %d", met->np);
6480 if (met->np < 2 || met->np > EP)
6481 ERRMSG("Number of levels out of range!");
6482
6483 /* Read grid... */
6484 FREAD(met->lon, double,
6485 (size_t) met->nx,
6486 in);
6487 LOG(2, "Longitudes: %g, %g ... %g deg",
6488 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
6489
6490 FREAD(met->lat, double,
6491 (size_t) met->ny,
6492 in);
6493 LOG(2, "Latitudes: %g, %g ... %g deg",
6494 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
6495
6496 FREAD(met->p, double,
6497 (size_t) met->np,
6498 in);
6499 LOG(2, "Altitude levels: %g, %g ... %g km",
6500 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
6501 LOG(2, "Pressure levels: %g, %g ... %g hPa",
6502 met->p[0], met->p[1], met->p[met->np - 1]);
6503
6504 /* Read surface data... */
6505 read_met_bin_2d(in, met, met->ps, "PS");
6506 read_met_bin_2d(in, met, met->ts, "TS");
6507 read_met_bin_2d(in, met, met->zs, "ZS");
6508 read_met_bin_2d(in, met, met->us, "US");
6509 read_met_bin_2d(in, met, met->vs, "VS");
6510 read_met_bin_2d(in, met, met->ess, "ESS");
6511 read_met_bin_2d(in, met, met->nss, "NSS");
6512 read_met_bin_2d(in, met, met->shf, "SHF");
6513 read_met_bin_2d(in, met, met->lsm, "LSM");
6514 read_met_bin_2d(in, met, met->sst, "SST");
6515 read_met_bin_2d(in, met, met->pbl, "PBL");
6516 read_met_bin_2d(in, met, met->pt, "PT");
6517 read_met_bin_2d(in, met, met->tt, "TT");
6518 read_met_bin_2d(in, met, met->zt, "ZT");
6519 read_met_bin_2d(in, met, met->h2ot, "H2OT");
6520 read_met_bin_2d(in, met, met->pct, "PCT");
6521 read_met_bin_2d(in, met, met->pcb, "PCB");
6522 read_met_bin_2d(in, met, met->cl, "CL");
6523 read_met_bin_2d(in, met, met->plcl, "PLCL");
6524 read_met_bin_2d(in, met, met->plfc, "PLFC");
6525 read_met_bin_2d(in, met, met->pel, "PEL");
6526 read_met_bin_2d(in, met, met->cape, "CAPE");
6527 read_met_bin_2d(in, met, met->cin, "CIN");
6528 read_met_bin_2d(in, met, met->o3c, "O3C");
6529
6530 /* Read level data... */
6531 read_met_bin_3d(in, ctl, met, met->z, "Z", -1e34f, 1e34f);
6532 read_met_bin_3d(in, ctl, met, met->t, "T", 0, 1e34f);
6533 read_met_bin_3d(in, ctl, met, met->u, "U", -1e34f, 1e34f);
6534 read_met_bin_3d(in, ctl, met, met->v, "V", -1e34f, 1e34f);
6535 read_met_bin_3d(in, ctl, met, met->w, "W", -1e34f, 1e34f);
6536 read_met_bin_3d(in, ctl, met, met->pv, "PV", -1e34f, 1e34f);
6537 read_met_bin_3d(in, ctl, met, met->h2o, "H2O", 0, 1e34f);
6538 read_met_bin_3d(in, ctl, met, met->o3, "O3", 0, 1e34f);
6539 read_met_bin_3d(in, ctl, met, met->lwc, "LWC", 0, 1e34f);
6540 read_met_bin_3d(in, ctl, met, met->rwc, "RWC", 0, 1e34f);
6541 read_met_bin_3d(in, ctl, met, met->iwc, "IWC", 0, 1e34f);
6542 read_met_bin_3d(in, ctl, met, met->swc, "SWC", 0, 1e34f);
6543 read_met_bin_3d(in, ctl, met, met->cc, "CC", 0, 1);
6544
6545 /* Read final flag... */
6546 int final;
6547 FREAD(&final, int,
6548 1,
6549 in);
6550 if (final != 999)
6551 ERRMSG("Error while reading binary data!");
6552
6553 /* Close file... */
6554 fclose(in);
6555
6556 /* Return success... */
6557 return 1;
6558}
6559
6560/*****************************************************************************/
6561
6563 FILE *in,
6564 const met_t *met,
6565 float var[EX][EY],
6566 const char *varname) {
6567
6568 float *help;
6569
6570 /* Allocate... */
6571 ALLOC(help, float,
6572 EX * EY);
6573
6574 /* Read uncompressed... */
6575 LOG(2, "Read 2-D variable: %s (uncompressed)", varname);
6576 FREAD(help, float,
6577 (size_t) (met->nx * met->ny),
6578 in);
6579
6580 /* Copy data... */
6581 for (int ix = 0; ix < met->nx; ix++)
6582 for (int iy = 0; iy < met->ny; iy++)
6583 var[ix][iy] = help[ARRAY_2D(ix, iy, met->ny)];
6584
6585 /* Free... */
6586 free(help);
6587}
6588
6589/*****************************************************************************/
6590
6592 FILE *in,
6593 const ctl_t *ctl,
6594 const met_t *met,
6595 float var[EX][EY][EP],
6596 const char *varname,
6597 const float bound_min,
6598 const float bound_max) {
6599
6600 float *help;
6601
6602 /* Allocate... */
6603 ALLOC(help, float,
6604 EX * EY * EP);
6605
6606 /* Read uncompressed data... */
6607 if (ctl->met_type == 1) {
6608 LOG(2, "Read 3-D variable: %s (uncompressed)", varname);
6609 FREAD(help, float,
6610 (size_t) (met->nx * met->ny * met->np),
6611 in);
6612 }
6613
6614 /* Read packed data... */
6615 else if (ctl->met_type == 2)
6616 compress_pck(varname, help, (size_t) (met->ny * met->nx),
6617 (size_t) met->np, 1, in);
6618
6619 /* Read zfp data... */
6620 else if (ctl->met_type == 3) {
6621#ifdef ZFP
6622 int precision;
6623 FREAD(&precision, int,
6624 1,
6625 in);
6626
6627 double tolerance;
6628 FREAD(&tolerance, double,
6629 1,
6630 in);
6631
6632 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
6633 tolerance, 1, in);
6634#else
6635 ERRMSG("MPTRAC was compiled without zfp compression!");
6636#endif
6637 }
6638
6639 /* Read zstd data... */
6640 else if (ctl->met_type == 4) {
6641#ifdef ZSTD
6642 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 1,
6643 ctl->met_zstd_level, in);
6644#else
6645 ERRMSG("MPTRAC was compiled without zstd compression!");
6646#endif
6647 }
6648
6649 /* Read cmultiscale data... */
6650 else if (ctl->met_type == 5) {
6651#ifdef CMS
6652 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
6653 (size_t) met->np, 1, in);
6654#else
6655 ERRMSG("MPTRAC was compiled without cmultiscale compression!");
6656#endif
6657 }
6658
6659 /* Copy data... */
6660#pragma omp parallel for default(shared) collapse(2)
6661 for (int ix = 0; ix < met->nx; ix++)
6662 for (int iy = 0; iy < met->ny; iy++)
6663 for (int ip = 0; ip < met->np; ip++) {
6664 var[ix][iy][ip] = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
6665 if (var[ix][iy][ip] < bound_min)
6666 var[ix][iy][ip] = bound_min;
6667 else if (var[ix][iy][ip] > bound_max)
6668 var[ix][iy][ip] = bound_max;
6669 }
6670
6671 /* Free... */
6672 free(help);
6673}
6674
6675/*****************************************************************************/
6676
6678 const ctl_t *ctl,
6679 const clim_t *clim,
6680 met_t *met) {
6681
6682 /* Check parameters... */
6683 if (ctl->met_cape != 1)
6684 return;
6685
6686 /* Set timer... */
6687 SELECT_TIMER("READ_MET_CAPE", "METPROC", NVTX_READ);
6688 LOG(2, "Calculate CAPE...");
6689
6690 /* Vertical spacing (about 100 m)... */
6691 const double pfac = 1.01439, dz0 = RI / MA / G0 * log(pfac);
6692
6693 /* Loop over columns... */
6694#pragma omp parallel for default(shared) collapse(2)
6695 for (int ix = 0; ix < met->nx; ix++)
6696 for (int iy = 0; iy < met->ny; iy++) {
6697
6698 /* Get potential temperature and water vapor at lowest 50 hPa... */
6699 int n = 0;
6700 double h2o = 0, t, theta = 0;
6701 double pbot = MIN(met->ps[ix][iy], met->p[0]);
6702 double ptop = pbot - 50.;
6703 for (int ip = 0; ip < met->np; ip++) {
6704 if (met->p[ip] <= pbot) {
6705 theta += THETA(met->p[ip], met->t[ix][iy][ip]);
6706 h2o += met->h2o[ix][iy][ip];
6707 n++;
6708 }
6709 if (met->p[ip] < ptop && n > 0)
6710 break;
6711 }
6712 theta /= n;
6713 h2o /= n;
6714
6715 /* Cannot compute anything if water vapor is missing... */
6716 met->plcl[ix][iy] = NAN;
6717 met->plfc[ix][iy] = NAN;
6718 met->pel[ix][iy] = NAN;
6719 met->cape[ix][iy] = NAN;
6720 met->cin[ix][iy] = NAN;
6721 if (h2o <= 0)
6722 continue;
6723
6724 /* Find lifted condensation level (LCL)... */
6725 ptop = P(20.);
6726 pbot = met->ps[ix][iy];
6727 do {
6728 met->plcl[ix][iy] = (float) (0.5 * (pbot + ptop));
6729 t = theta / pow(1000. / met->plcl[ix][iy], 0.286);
6730 if (RH(met->plcl[ix][iy], t, h2o) > 100.)
6731 ptop = met->plcl[ix][iy];
6732 else
6733 pbot = met->plcl[ix][iy];
6734 } while (pbot - ptop > 0.1);
6735
6736 /* Calculate CIN up to LCL... */
6738 double dcape, dz, h2o_env, t_env;
6739 double p = met->ps[ix][iy];
6740 met->cape[ix][iy] = met->cin[ix][iy] = 0;
6741 do {
6742 dz = dz0 * TVIRT(t, h2o);
6743 p /= pfac;
6744 t = theta / pow(1000. / p, 0.286);
6745 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6746 &t_env, ci, cw, 1);
6747 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6748 &h2o_env, ci, cw, 0);
6749 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6750 TVIRT(t_env, h2o_env) * dz;
6751 if (dcape < 0)
6752 met->cin[ix][iy] += fabsf((float) dcape);
6753 } while (p > met->plcl[ix][iy]);
6754
6755 /* Calculate level of free convection (LFC), equilibrium level (EL),
6756 and convective available potential energy (CAPE)... */
6757 dcape = 0;
6758 p = met->plcl[ix][iy];
6759 t = theta / pow(1000. / p, 0.286);
6760 ptop = 0.75 * clim_tropo(clim, met->time, met->lat[iy]);
6761 do {
6762 dz = dz0 * TVIRT(t, h2o);
6763 p /= pfac;
6764 t -= lapse_rate(t, h2o) * dz;
6765 double psat = PSAT(t);
6766 h2o = psat / (p - (1. - EPS) * psat);
6767 intpol_met_space_3d(met, met->t, p, met->lon[ix], met->lat[iy],
6768 &t_env, ci, cw, 1);
6769 intpol_met_space_3d(met, met->h2o, p, met->lon[ix], met->lat[iy],
6770 &h2o_env, ci, cw, 0);
6771 double dcape_old = dcape;
6772 dcape = 1e3 * G0 * (TVIRT(t, h2o) - TVIRT(t_env, h2o_env)) /
6773 TVIRT(t_env, h2o_env) * dz;
6774 if (dcape > 0) {
6775 met->cape[ix][iy] += (float) dcape;
6776 if (!isfinite(met->plfc[ix][iy]))
6777 met->plfc[ix][iy] = (float) p;
6778 } else if (dcape_old > 0)
6779 met->pel[ix][iy] = (float) p;
6780 if (dcape < 0 && !isfinite(met->plfc[ix][iy]))
6781 met->cin[ix][iy] += fabsf((float) dcape);
6782 } while (p > ptop);
6783
6784 /* Check results... */
6785 if (!isfinite(met->plfc[ix][iy]))
6786 met->cin[ix][iy] = NAN;
6787 }
6788}
6789
6790/*****************************************************************************/
6791
6793 met_t *met) {
6794
6795 /* Set timer... */
6796 SELECT_TIMER("READ_MET_CLOUD", "METPROC", NVTX_READ);
6797 LOG(2, "Calculate cloud data...");
6798
6799 /* Thresholds for cloud detection... */
6800 const double ccmin = 0.01, cwmin = 1e-6;
6801
6802 /* Loop over columns... */
6803#pragma omp parallel for default(shared) collapse(2)
6804 for (int ix = 0; ix < met->nx; ix++)
6805 for (int iy = 0; iy < met->ny; iy++) {
6806
6807 /* Init... */
6808 met->pct[ix][iy] = NAN;
6809 met->pcb[ix][iy] = NAN;
6810 met->cl[ix][iy] = 0;
6811
6812 /* Loop over pressure levels... */
6813 for (int ip = 0; ip < met->np - 1; ip++) {
6814
6815 /* Check pressure... */
6816 if (met->p[ip] > met->ps[ix][iy] || met->p[ip] < P(20.))
6817 continue;
6818
6819 /* Check ice water and liquid water content... */
6820 if (met->cc[ix][iy][ip] > ccmin
6821 && (met->lwc[ix][iy][ip] > cwmin
6822 || met->rwc[ix][iy][ip] > cwmin
6823 || met->iwc[ix][iy][ip] > cwmin
6824 || met->swc[ix][iy][ip] > cwmin)) {
6825
6826 /* Get cloud top pressure ... */
6827 met->pct[ix][iy]
6828 = (float) (0.5 * (met->p[ip] + (float) met->p[ip + 1]));
6829
6830 /* Get cloud bottom pressure ... */
6831 if (!isfinite(met->pcb[ix][iy]))
6832 met->pcb[ix][iy]
6833 = (float) (0.5 * (met->p[ip] + met->p[MAX(ip - 1, 0)]));
6834 }
6835
6836 /* Get cloud water... */
6837 met->cl[ix][iy] += (float)
6838 (0.5 * (met->lwc[ix][iy][ip] + met->lwc[ix][iy][ip + 1]
6839 + met->rwc[ix][iy][ip] + met->rwc[ix][iy][ip + 1]
6840 + met->iwc[ix][iy][ip] + met->iwc[ix][iy][ip + 1]
6841 + met->swc[ix][iy][ip] + met->swc[ix][iy][ip + 1])
6842 * 100. * (met->p[ip] - met->p[ip + 1]) / G0);
6843 }
6844 }
6845}
6846
6847/*****************************************************************************/
6848
6850 const ctl_t *ctl,
6851 met_t *met) {
6852
6853 met_t *help;
6854
6855 /* Check parameters... */
6856 if (ctl->met_detrend <= 0)
6857 return;
6858
6859 /* Set timer... */
6860 SELECT_TIMER("READ_MET_DETREND", "METPROC", NVTX_READ);
6861 LOG(2, "Detrend meteo data...");
6862
6863 /* Allocate... */
6864 ALLOC(help, met_t, 1);
6865
6866 /* Calculate standard deviation... */
6867 const double sigma = ctl->met_detrend / 2.355;
6868 const double tssq = 2. * SQR(sigma);
6869
6870 /* Calculate box size in latitude... */
6871 int sy = (int) (3. * DY2DEG(sigma) / fabs(met->lat[1] - met->lat[0]));
6872 sy = MIN(MAX(1, sy), met->ny / 2);
6873
6874 /* Calculate background... */
6875#pragma omp parallel for default(shared) collapse(2)
6876 for (int ix = 0; ix < met->nx; ix++) {
6877 for (int iy = 0; iy < met->ny; iy++) {
6878
6879 /* Calculate Cartesian coordinates... */
6880 double x0[3];
6881 geo2cart(0.0, met->lon[ix], met->lat[iy], x0);
6882
6883 /* Calculate box size in longitude... */
6884 int sx =
6885 (int) (3. * DX2DEG(sigma, met->lat[iy]) /
6886 fabs(met->lon[1] - met->lon[0]));
6887 sx = MIN(MAX(1, sx), met->nx / 2);
6888
6889 /* Init... */
6890 float wsum = 0;
6891 for (int ip = 0; ip < met->np; ip++) {
6892 help->t[ix][iy][ip] = 0;
6893 help->u[ix][iy][ip] = 0;
6894 help->v[ix][iy][ip] = 0;
6895 help->w[ix][iy][ip] = 0;
6896 }
6897
6898 /* Loop over neighboring grid points... */
6899 for (int ix2 = ix - sx; ix2 <= ix + sx; ix2++) {
6900 int ix3 = ix2;
6901 if (ix3 < 0)
6902 ix3 += met->nx;
6903 else if (ix3 >= met->nx)
6904 ix3 -= met->nx;
6905 for (int iy2 = MAX(iy - sy, 0);
6906 iy2 <= MIN(iy + sy, met->ny - 1); iy2++) {
6907
6908 /* Calculate Cartesian coordinates... */
6909 double x1[3];
6910 geo2cart(0.0, met->lon[ix3], met->lat[iy2], x1);
6911
6912 /* Calculate weighting factor... */
6913 const float w = (float) exp(-DIST2(x0, x1) / tssq);
6914
6915 /* Add data... */
6916 wsum += w;
6917 for (int ip = 0; ip < met->np; ip++) {
6918 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip];
6919 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip];
6920 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip];
6921 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip];
6922 }
6923 }
6924 }
6925
6926 /* Normalize... */
6927 for (int ip = 0; ip < met->np; ip++) {
6928 help->t[ix][iy][ip] /= wsum;
6929 help->u[ix][iy][ip] /= wsum;
6930 help->v[ix][iy][ip] /= wsum;
6931 help->w[ix][iy][ip] /= wsum;
6932 }
6933 }
6934 }
6935
6936 /* Subtract background... */
6937#pragma omp parallel for default(shared) collapse(3)
6938 for (int ix = 0; ix < met->nx; ix++)
6939 for (int iy = 0; iy < met->ny; iy++)
6940 for (int ip = 0; ip < met->np; ip++) {
6941 met->t[ix][iy][ip] -= help->t[ix][iy][ip];
6942 met->u[ix][iy][ip] -= help->u[ix][iy][ip];
6943 met->v[ix][iy][ip] -= help->v[ix][iy][ip];
6944 met->w[ix][iy][ip] -= help->w[ix][iy][ip];
6945 }
6946
6947 /* Free... */
6948 free(help);
6949}
6950
6951/*****************************************************************************/
6952
6954 met_t *met) {
6955
6956 /* Set timer... */
6957 SELECT_TIMER("READ_MET_EXTRAPOLATE", "METPROC", NVTX_READ);
6958 LOG(2, "Extrapolate meteo data...");
6959
6960 /* Loop over columns... */
6961#pragma omp parallel for default(shared) collapse(2)
6962 for (int ix = 0; ix < met->nx; ix++)
6963 for (int iy = 0; iy < met->ny; iy++) {
6964
6965 /* Find lowest valid data point... */
6966 int ip0;
6967 for (ip0 = met->np - 1; ip0 >= 0; ip0--)
6968 if (!isfinite(met->t[ix][iy][ip0])
6969 || !isfinite(met->u[ix][iy][ip0])
6970 || !isfinite(met->v[ix][iy][ip0])
6971 || !isfinite(met->w[ix][iy][ip0]))
6972 break;
6973
6974 /* Extrapolate... */
6975 for (int ip = ip0; ip >= 0; ip--) {
6976 met->t[ix][iy][ip] = met->t[ix][iy][ip + 1];
6977 met->u[ix][iy][ip] = met->u[ix][iy][ip + 1];
6978 met->v[ix][iy][ip] = met->v[ix][iy][ip + 1];
6979 met->w[ix][iy][ip] = met->w[ix][iy][ip + 1];
6980 met->h2o[ix][iy][ip] = met->h2o[ix][iy][ip + 1];
6981 met->o3[ix][iy][ip] = met->o3[ix][iy][ip + 1];
6982 met->lwc[ix][iy][ip] = met->lwc[ix][iy][ip + 1];
6983 met->rwc[ix][iy][ip] = met->rwc[ix][iy][ip + 1];
6984 met->iwc[ix][iy][ip] = met->iwc[ix][iy][ip + 1];
6985 met->swc[ix][iy][ip] = met->swc[ix][iy][ip + 1];
6986 met->cc[ix][iy][ip] = met->cc[ix][iy][ip + 1];
6987 }
6988 }
6989}
6990
6991/*****************************************************************************/
6992
6994 const ctl_t *ctl,
6995 met_t *met) {
6996
6997 float *help;
6998
6999 double logp[EP];
7000
7001 int dx = ctl->met_geopot_sx, dy = ctl->met_geopot_sy;
7002
7003 /* Set timer... */
7004 SELECT_TIMER("READ_MET_GEOPOT", "METPROC", NVTX_READ);
7005 LOG(2, "Calculate geopotential heights...");
7006
7007 /* Allocate... */
7008 ALLOC(help, float,
7009 EX * EY * EP);
7010
7011 /* Calculate log pressure... */
7012#pragma omp parallel for default(shared)
7013 for (int ip = 0; ip < met->np; ip++)
7014 logp[ip] = log(met->p[ip]);
7015
7016 /* Apply hydrostatic equation to calculate geopotential heights... */
7017#pragma omp parallel for default(shared) collapse(2)
7018 for (int ix = 0; ix < met->nx; ix++)
7019 for (int iy = 0; iy < met->ny; iy++) {
7020
7021 /* Get surface height and pressure... */
7022 const double zs = met->zs[ix][iy];
7023 const double lnps = log(met->ps[ix][iy]);
7024
7025 /* Get temperature and water vapor at the surface... */
7026 const int ip0 = locate_irr(met->p, met->np, met->ps[ix][iy]);
7027 const double ts = LIN(met->p[ip0], met->t[ix][iy][ip0], met->p[ip0 + 1],
7028 met->t[ix][iy][ip0 + 1], met->ps[ix][iy]);
7029 const double h2os =
7030 LIN(met->p[ip0], met->h2o[ix][iy][ip0], met->p[ip0 + 1],
7031 met->h2o[ix][iy][ip0 + 1], met->ps[ix][iy]);
7032
7033 /* Upper part of profile... */
7034 met->z[ix][iy][ip0 + 1]
7035 = (float) (zs +
7036 ZDIFF(lnps, ts, h2os, logp[ip0 + 1],
7037 met->t[ix][iy][ip0 + 1], met->h2o[ix][iy][ip0 + 1]));
7038 for (int ip = ip0 + 2; ip < met->np; ip++)
7039 met->z[ix][iy][ip]
7040 = (float) (met->z[ix][iy][ip - 1] +
7041 ZDIFF(logp[ip - 1], met->t[ix][iy][ip - 1],
7042 met->h2o[ix][iy][ip - 1], logp[ip],
7043 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7044
7045 /* Lower part of profile... */
7046 met->z[ix][iy][ip0]
7047 = (float) (zs +
7048 ZDIFF(lnps, ts, h2os, logp[ip0],
7049 met->t[ix][iy][ip0], met->h2o[ix][iy][ip0]));
7050 for (int ip = ip0 - 1; ip >= 0; ip--)
7051 met->z[ix][iy][ip]
7052 = (float) (met->z[ix][iy][ip + 1] +
7053 ZDIFF(logp[ip + 1], met->t[ix][iy][ip + 1],
7054 met->h2o[ix][iy][ip + 1], logp[ip],
7055 met->t[ix][iy][ip], met->h2o[ix][iy][ip]));
7056 }
7057
7058 /* Check control parameters... */
7059 if (dx == 0 || dy == 0)
7060 return;
7061
7062 /* Default smoothing parameters... */
7063 if (dx < 0 || dy < 0) {
7064 if (fabs(met->lon[1] - met->lon[0]) < 0.5) {
7065 dx = 3;
7066 dy = 2;
7067 } else {
7068 dx = 6;
7069 dy = 4;
7070 }
7071 }
7072
7073 /* Calculate weights for smoothing... */
7074 float ws[dx + 1][dy + 1];
7075#pragma omp parallel for default(shared) collapse(2)
7076 for (int ix = 0; ix <= dx; ix++)
7077 for (int iy = 0; iy < dy; iy++)
7078 ws[ix][iy] = (1.0f - (float) ix / (float) dx)
7079 * (1.0f - (float) iy / (float) dy);
7080
7081 /* Copy data... */
7082#pragma omp parallel for default(shared) collapse(3)
7083 for (int ix = 0; ix < met->nx; ix++)
7084 for (int iy = 0; iy < met->ny; iy++)
7085 for (int ip = 0; ip < met->np; ip++)
7086 help[ARRAY_3D(ip, ix, met->nx, iy, met->ny)] = met->z[ix][iy][ip];
7087
7088 /* Horizontal smoothing... */
7089#pragma omp parallel for default(shared) collapse(3)
7090 for (int ip = 0; ip < met->np; ip++)
7091 for (int ix = 0; ix < met->nx; ix++)
7092 for (int iy = 0; iy < met->ny; iy++) {
7093 float res = 0, wsum = 0;
7094 int iy0 = MAX(iy - dy + 1, 0);
7095 int iy1 = MIN(iy + dy - 1, met->ny - 1);
7096 for (int ix2 = ix - dx + 1; ix2 <= ix + dx - 1; ++ix2) {
7097 int ix3 = ix2;
7098 if (ix3 < 0)
7099 ix3 += met->nx;
7100 else if (ix3 >= met->nx)
7101 ix3 -= met->nx;
7102 for (int iy2 = iy0; iy2 <= iy1; ++iy2)
7103 if (isfinite(help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)])) {
7104 float w = ws[abs(ix - ix2)][abs(iy - iy2)];
7105 res += w * help[ARRAY_3D(ip, ix3, met->nx, iy2, met->ny)];
7106 wsum += w;
7107 }
7108 }
7109 if (wsum > 0)
7110 met->z[ix][iy][ip] = res / wsum;
7111 else
7112 met->z[ix][iy][ip] = NAN;
7113 }
7114
7115 /* Free... */
7116 free(help);
7117}
7118
7119/*****************************************************************************/
7120
7122 const char *filename,
7123 const int ncid,
7124 const ctl_t *ctl,
7125 met_t *met) {
7126
7127 char levname[LEN], tstr[10];
7128
7129 double rtime = 0, r, r2;
7130
7131 int varid, year2, mon2, day2, hour2, min2, sec2,
7132 year, mon, day, hour, min, sec;
7133
7134 size_t np;
7135
7136 /* Set timer... */
7137 SELECT_TIMER("READ_MET_GRID", "INPUT", NVTX_READ);
7138 LOG(2, "Read meteo grid information...");
7139
7140 /* MPTRAC meteo files... */
7141 if (ctl->met_clams == 0) {
7142
7143 /* Get time from filename... */
7144 met->time = time_from_filename(filename, 16);
7145
7146 /* Check time information from data file... */
7147 jsec2time(met->time, &year, &mon, &day, &hour, &min, &sec, &r);
7148 if (nc_inq_varid(ncid, "time", &varid) == NC_NOERR) {
7149 NC(nc_get_var_double(ncid, varid, &rtime));
7150 if (fabs(year * 10000. + mon * 100. + day + hour / 24. - rtime) > 1.0)
7151 WARN("Time information in meteo file does not match filename!");
7152 } else
7153 WARN("Time information in meteo file is missing!");
7154 }
7155
7156 /* CLaMS meteo files... */
7157 else {
7158
7159 /* Read time from file... */
7160 NC_GET_DOUBLE("time", &rtime, 0);
7161
7162 /* Get time from filename (considering the century)... */
7163 if (rtime < 0)
7164 sprintf(tstr, "19%.2s", &filename[strlen(filename) - 11]);
7165 else
7166 sprintf(tstr, "20%.2s", &filename[strlen(filename) - 11]);
7167 year = atoi(tstr);
7168 sprintf(tstr, "%.2s", &filename[strlen(filename) - 9]);
7169 mon = atoi(tstr);
7170 sprintf(tstr, "%.2s", &filename[strlen(filename) - 7]);
7171 day = atoi(tstr);
7172 sprintf(tstr, "%.2s", &filename[strlen(filename) - 5]);
7173 hour = atoi(tstr);
7174 time2jsec(year, mon, day, hour, 0, 0, 0, &met->time);
7175 }
7176
7177 /* Check time... */
7178 if (year < 1900 || year > 2100 || mon < 1 || mon > 12
7179 || day < 1 || day > 31 || hour < 0 || hour > 23)
7180 ERRMSG("Cannot read time from filename!");
7181 jsec2time(met->time, &year2, &mon2, &day2, &hour2, &min2, &sec2, &r2);
7182 LOG(2, "Time: %.2f (%d-%02d-%02d, %02d:%02d UTC)",
7183 met->time, year2, mon2, day2, hour2, min2);
7184
7185 /* Get grid dimensions... */
7186 NC_INQ_DIM("lon", &met->nx, 2, EX);
7187 LOG(2, "Number of longitudes: %d", met->nx);
7188
7189 NC_INQ_DIM("lat", &met->ny, 2, EY);
7190 LOG(2, "Number of latitudes: %d", met->ny);
7191
7192 int dimid2;
7193 sprintf(levname, "lev");
7194 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7195 sprintf(levname, "plev");
7196 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7197 sprintf(levname, "hybrid");
7198 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR)
7199 sprintf(levname, "hybrid_level");
7200
7201 NC_INQ_DIM(levname, &met->np, 1, EP);
7202 if (met->np == 1) {
7203 sprintf(levname, "lev_2");
7204 if (nc_inq_dimid(ncid, levname, &dimid2) != NC_NOERR) {
7205 sprintf(levname, "plev");
7206 NC(nc_inq_dimid(ncid, levname, &dimid2));
7207 }
7208 NC(nc_inq_dimlen(ncid, dimid2, &np));
7209 met->np = (int) np;
7210 }
7211 LOG(2, "Number of levels: %d", met->np);
7212 if (met->np < 2 || met->np > EP)
7213 ERRMSG("Number of levels out of range!");
7214
7215 /* Read longitudes and latitudes... */
7216 NC_GET_DOUBLE("lon", met->lon, 1);
7217 LOG(2, "Longitudes: %g, %g ... %g deg",
7218 met->lon[0], met->lon[1], met->lon[met->nx - 1]);
7219 NC_GET_DOUBLE("lat", met->lat, 1);
7220 LOG(2, "Latitudes: %g, %g ... %g deg",
7221 met->lat[0], met->lat[1], met->lat[met->ny - 1]);
7222
7223 /* Check grid spacing... */
7224 for (int ix = 2; ix < met->nx; ix++)
7225 if (fabs
7226 (fabs(met->lon[ix] - met->lon[ix - 1]) -
7227 fabs(met->lon[1] - met->lon[0])) > 0.001)
7228 ERRMSG("No regular grid spacing in longitudes!");
7229 for (int iy = 2; iy < met->ny; iy++)
7230 if (fabs
7231 (fabs(met->lat[iy] - met->lat[iy - 1]) -
7232 fabs(met->lat[1] - met->lat[0])) > 0.001) {
7233 WARN("No regular grid spacing in latitudes!");
7234 break;
7235 }
7236
7237 /* Read pressure levels... */
7238 if (ctl->met_np <= 0) {
7239 NC_GET_DOUBLE(levname, met->p, 1);
7240 for (int ip = 0; ip < met->np; ip++)
7241 met->p[ip] /= 100.;
7242 LOG(2, "Altitude levels: %g, %g ... %g km",
7243 Z(met->p[0]), Z(met->p[1]), Z(met->p[met->np - 1]));
7244 LOG(2, "Pressure levels: %g, %g ... %g hPa",
7245 met->p[0], met->p[1], met->p[met->np - 1]);
7246 }
7247
7248 /* Read hybrid levels... */
7249 if (strcasecmp(levname, "hybrid") == 0)
7250 NC_GET_DOUBLE("hybrid", met->hybrid, 1);
7251}
7252
7253/*****************************************************************************/
7254
7256 const int ncid,
7257 const ctl_t *ctl,
7258 met_t *met) {
7259
7260 /* Set timer... */
7261 SELECT_TIMER("READ_MET_LEVELS", "INPUT", NVTX_READ);
7262 LOG(2, "Read level data...");
7263
7264 /* Read temperature... */
7265 if (!read_met_nc_3d(ncid, "t", "T", "temp", "TEMP", ctl, met, met->t, 1.0))
7266 ERRMSG("Cannot read temperature!");
7267
7268 /* Read horizontal wind and vertical velocity... */
7269 if (!read_met_nc_3d(ncid, "u", "U", NULL, NULL, ctl, met, met->u, 1.0))
7270 ERRMSG("Cannot read zonal wind!");
7271 if (!read_met_nc_3d(ncid, "v", "V", NULL, NULL, ctl, met, met->v, 1.0))
7272 ERRMSG("Cannot read meridional wind!");
7273 if (!read_met_nc_3d
7274 (ncid, "w", "W", "omega", "OMEGA", ctl, met, met->w, 0.01f))
7275 WARN("Cannot read vertical velocity!");
7276
7277 /* Read water vapor... */
7278 if (!ctl->met_relhum) {
7279 if (!read_met_nc_3d
7280 (ncid, "q", "Q", "sh", "SH", ctl, met, met->h2o, (float) (MA / MH2O)))
7281 WARN("Cannot read specific humidity!");
7282 } else {
7283 if (!read_met_nc_3d
7284 (ncid, "rh", "RH", NULL, NULL, ctl, met, met->h2o, 0.01f))
7285 WARN("Cannot read relative humidity!");
7286#pragma omp parallel for default(shared) collapse(2)
7287 for (int ix = 0; ix < met->nx; ix++)
7288 for (int iy = 0; iy < met->ny; iy++)
7289 for (int ip = 0; ip < met->np; ip++) {
7290 double pw = met->h2o[ix][iy][ip] * PSAT(met->t[ix][iy][ip]);
7291 met->h2o[ix][iy][ip] =
7292 (float) (pw / (met->p[ip] - (1.0 - EPS) * pw));
7293 }
7294 }
7295
7296 /* Read ozone... */
7297 if (!read_met_nc_3d
7298 (ncid, "o3", "O3", NULL, NULL, ctl, met, met->o3, (float) (MA / MO3)))
7299 WARN("Cannot read ozone data!");
7300
7301 /* Read cloud data... */
7302 if (!read_met_nc_3d
7303 (ncid, "clwc", "CLWC", NULL, NULL, ctl, met, met->lwc, 1.0))
7304 WARN("Cannot read cloud liquid water content!");
7305 if (!read_met_nc_3d
7306 (ncid, "crwc", "CRWC", NULL, NULL, ctl, met, met->rwc, 1.0))
7307 WARN("Cannot read cloud rain water content!");
7308 if (!read_met_nc_3d
7309 (ncid, "ciwc", "CIWC", NULL, NULL, ctl, met, met->iwc, 1.0))
7310 WARN("Cannot read cloud ice water content!");
7311 if (!read_met_nc_3d
7312 (ncid, "cswc", "CSWC", NULL, NULL, ctl, met, met->swc, 1.0))
7313 WARN("Cannot read cloud snow water content!");
7314 if (!read_met_nc_3d(ncid, "cc", "CC", NULL, NULL, ctl, met, met->cc, 1.0))
7315 WARN("Cannot read cloud cover!");
7316
7317 /* Read zeta and zeta_dot... */
7318 if (!read_met_nc_3d
7319 (ncid, "ZETA", "zeta", NULL, NULL, ctl, met, met->zetal, 1.0))
7320 WARN("Cannot read ZETA!");
7321 if (!read_met_nc_3d
7322 (ncid, "ZETA_DOT_TOT", "ZETA_DOT_clr", "zeta_dot_clr",
7323 NULL, ctl, met, met->zeta_dotl, 0.00001157407f))
7324 WARN("Cannot read ZETA_DOT!");
7325
7326 /* Store velocities on model levels... */
7327 if (ctl->met_vert_coord != 0) {
7328 for (int ix = 0; ix < met->nx; ix++)
7329 for (int iy = 0; iy < met->ny; iy++)
7330 for (int ip = 0; ip < met->np; ip++) {
7331 met->ul[ix][iy][ip] = met->u[ix][iy][ip];
7332 met->vl[ix][iy][ip] = met->v[ix][iy][ip];
7333 met->wl[ix][iy][ip] = met->w[ix][iy][ip];
7334 }
7335
7336 /* Save number of model levels... */
7337 met->npl = met->np;
7338 }
7339
7340 /* Get pressure on model levels... */
7341 if (ctl->met_np > 0 || ctl->met_vert_coord != 0) {
7342
7343 /* Read 3-D pressure field... */
7344 if (ctl->met_vert_coord == 1) {
7345 if (!read_met_nc_3d
7346 (ncid, "pl", "PL", "pressure", "PRESSURE", ctl, met, met->pl,
7347 0.01f))
7348 if (!read_met_nc_3d
7349 (ncid, "press", "PRESS", NULL, NULL, ctl, met, met->pl, 1.0))
7350 ERRMSG("Cannot read pressure on model levels!");
7351 }
7352
7353 /* Use a and b coefficients for full levels... */
7354 else if (ctl->met_vert_coord == 2 || ctl->met_vert_coord == 3) {
7355
7356 /* Grid level coefficients... */
7357 double hyam[EP], hybm[EP];
7358
7359 /* Read coefficients from file... */
7360 if (ctl->met_vert_coord == 2) {
7361 int varid;
7362 if (nc_inq_varid(ncid, "hyam", &varid) == NC_NOERR
7363 && nc_inq_varid(ncid, "hybm", &varid) == NC_NOERR) {
7364 NC_GET_DOUBLE("hyam", hyam, 1);
7365 NC_GET_DOUBLE("hybm", hybm, 1);
7366 } else if (nc_inq_varid(ncid, "a_hybrid_level", &varid) == NC_NOERR
7367 && nc_inq_varid(ncid, "b_hybrid_level",
7368 &varid) == NC_NOERR) {
7369 NC_GET_DOUBLE("a_hybrid_level", hyam, 1);
7370 NC_GET_DOUBLE("b_hybrid_level", hybm, 1);
7371 } else
7372 ERRMSG("Cannot read a and b level coefficients from netCDF file!");
7373 }
7374
7375 /* Use control parameters... */
7376 else if (ctl->met_vert_coord == 3) {
7377
7378 /* Check number of levels... */
7379 if (met->np != ctl->met_nlev)
7380 ERRMSG("Mismatch in number of model levels!");
7381
7382 /* Copy parameters... */
7383 for (int ip = 0; ip < met->np; ip++) {
7384 hyam[ip] = ctl->met_lev_hyam[ip];
7385 hybm[ip] = ctl->met_lev_hybm[ip];
7386 }
7387 }
7388
7389 /* Calculate pressure... */
7390 for (int ix = 0; ix < met->nx; ix++)
7391 for (int iy = 0; iy < met->ny; iy++)
7392 for (int ip = 0; ip < met->np; ip++)
7393 met->pl[ix][iy][ip] =
7394 (float) (hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy]);
7395 }
7396
7397 /* Use a and b coefficients for half levels... */
7398 else if (ctl->met_vert_coord == 4) {
7399
7400 /* Grid level coefficients... */
7401 double hyam[EP], hybm[EP];
7402
7403 /* Use control parameters... */
7404 for (int ip = 0; ip < met->np + 1; ip++) {
7405 hyam[ip] = ctl->met_lev_hyam[ip];
7406 hybm[ip] = ctl->met_lev_hybm[ip];
7407 }
7408
7409 /* Check number of levels... */
7410 if (met->np + 1 != ctl->met_nlev)
7411 ERRMSG("Mismatch in number of model levels!");
7412
7413 /* Calculate pressure... */
7414#pragma omp parallel for default(shared) collapse(2)
7415 for (int ix = 0; ix < met->nx; ix++)
7416 for (int iy = 0; iy < met->ny; iy++)
7417 for (int ip = 0; ip < met->np; ip++) {
7418 double p0 = hyam[ip] / 100. + hybm[ip] * met->ps[ix][iy];
7419 double p1 = hyam[ip + 1] / 100. + hybm[ip + 1] * met->ps[ix][iy];
7420 met->pl[ix][iy][ip] = (float) ((p1 - p0) / log(p1 / p0));
7421 }
7422 }
7423
7424 /* Check ordering of pressure levels... */
7425 for (int ix = 0; ix < met->nx; ix++)
7426 for (int iy = 0; iy < met->ny; iy++)
7427 for (int ip = 1; ip < met->np; ip++)
7428 if ((met->pl[ix][iy][0] > met->pl[ix][iy][1]
7429 && met->pl[ix][iy][ip - 1] <= met->pl[ix][iy][ip])
7430 || (met->pl[ix][iy][0] < met->pl[ix][iy][1]
7431 && met->pl[ix][iy][ip - 1] >= met->pl[ix][iy][ip]))
7432 ERRMSG("Pressure profiles are not monotonic!");
7433 }
7434
7435 /* Interpolate from model levels to pressure levels... */
7436 if (ctl->met_np > 0) {
7437
7438 /* Check pressure on model levels... */
7439 if (met->pl[0][0][0] <= 0)
7440 ERRMSG("Pressure on model levels is missing, check MET_VERT_COORD!");
7441
7442 /* Interpolate variables... */
7443 read_met_ml2pl(ctl, met, met->t, "T");
7444 read_met_ml2pl(ctl, met, met->u, "U");
7445 read_met_ml2pl(ctl, met, met->v, "V");
7446 read_met_ml2pl(ctl, met, met->w, "W");
7447 read_met_ml2pl(ctl, met, met->h2o, "H2O");
7448 read_met_ml2pl(ctl, met, met->o3, "O3");
7449 read_met_ml2pl(ctl, met, met->lwc, "LWC");
7450 read_met_ml2pl(ctl, met, met->rwc, "RWC");
7451 read_met_ml2pl(ctl, met, met->iwc, "IWC");
7452 read_met_ml2pl(ctl, met, met->swc, "SWC");
7453 read_met_ml2pl(ctl, met, met->cc, "CC");
7454
7455 /* Set new pressure levels... */
7456 met->np = ctl->met_np;
7457 for (int ip = 0; ip < met->np; ip++)
7458 met->p[ip] = ctl->met_p[ip];
7459 }
7460
7461 /* Check ordering of pressure levels... */
7462 for (int ip = 1; ip < met->np; ip++)
7463 if (met->p[ip - 1] < met->p[ip])
7464 ERRMSG("Pressure levels must be descending!");
7465}
7466
7467/*****************************************************************************/
7468
7470 const ctl_t *ctl,
7471 const met_t *met,
7472 float var[EX][EY][EP],
7473 const char *varname) {
7474
7475 double aux[EP], p[EP];
7476
7477 /* Set timer... */
7478 SELECT_TIMER("READ_MET_ML2PL", "METPROC", NVTX_READ);
7479 LOG(2, "Interpolate meteo data to pressure levels: %s", varname);
7480
7481 /* Loop over columns... */
7482#pragma omp parallel for default(shared) private(aux,p) collapse(2)
7483 for (int ix = 0; ix < met->nx; ix++)
7484 for (int iy = 0; iy < met->ny; iy++) {
7485
7486 /* Copy pressure profile... */
7487 for (int ip = 0; ip < met->np; ip++)
7488 p[ip] = met->pl[ix][iy][ip];
7489
7490 /* Interpolate... */
7491 for (int ip = 0; ip < ctl->met_np; ip++) {
7492 double pt = ctl->met_p[ip];
7493 if ((pt > p[0] && p[0] > p[1]) || (pt < p[0] && p[0] < p[1]))
7494 pt = p[0];
7495 else if ((pt > p[met->np - 1] && p[1] > p[0])
7496 || (pt < p[met->np - 1] && p[1] < p[0]))
7497 pt = p[met->np - 1];
7498 int ip2 = locate_irr(p, met->np, pt);
7499 aux[ip] = LIN(p[ip2], var[ix][iy][ip2],
7500 p[ip2 + 1], var[ix][iy][ip2 + 1], pt);
7501 }
7502
7503 /* Copy data... */
7504 for (int ip = 0; ip < ctl->met_np; ip++)
7505 var[ix][iy][ip] = (float) aux[ip];
7506 }
7507}
7508
7509/*****************************************************************************/
7510
7512 const ctl_t *ctl,
7513 met_t *met) {
7514
7515 /* Check parameters... */
7516 if (ctl->advect_vert_coord != 1)
7517 return;
7518
7519 /* Set timer... */
7520 SELECT_TIMER("READ_MET_MONOTONIZE", "METPROC", NVTX_READ);
7521 LOG(2, "Make zeta profiles monotone...");
7522
7523 /* Create monotone zeta profiles... */
7524#pragma omp parallel for default(shared) collapse(2)
7525 for (int i = 0; i < met->nx; i++)
7526 for (int j = 0; j < met->ny; j++) {
7527 int k = 1;
7528
7529 while (k < met->npl) { /* Check if there is an inversion at level k... */
7530 if ((met->zetal[i][j][k - 1] >= met->zetal[i][j][k])) {
7531 /* Find the upper level k+l over the inversion... */
7532 int l = 0;
7533 do {
7534 l++;
7535 }
7536 while ((met->zetal[i][j][k - 1] >=
7537 met->zetal[i][j][k + l]) & (k + l < met->npl));
7538
7539 /* Interpolate linear between the top and bottom
7540 of the inversion... */
7541 float s =
7542 (float) (met->zetal[i][j][k + l] - met->zetal[i][j][k - 1])
7543 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7544
7545 for (int m = k; m < k + l; m++) {
7546 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7547 met->zetal[i][j][m] = s * d + met->zetal[i][j][k - 1];
7548 }
7549
7550 /* Search for more inversions above the last inversion ... */
7551 k = k + l;
7552 } else {
7553 k++;
7554 }
7555 }
7556 }
7557
7558 /* Create monotone pressure profiles... */
7559#pragma omp parallel for default(shared) collapse(2)
7560 for (int i = 0; i < met->nx; i++)
7561 for (int j = 0; j < met->ny; j++) {
7562 int k = 1;
7563
7564 while (k < met->npl) { /* Check if there is an inversion at level k... */
7565 if ((met->pl[i][j][k - 1] <= met->pl[i][j][k])) {
7566
7567 /* Find the upper level k+l over the inversion... */
7568 int l = 0;
7569 do {
7570 l++;
7571 }
7572 while ((met->pl[i][j][k - 1] <= met->pl[i][j][k + l]) & (k + l <
7573 met->npl));
7574
7575 /* Interpolate linear between the top and bottom
7576 of the inversion... */
7577 float s = (float) (met->pl[i][j][k + l] - met->pl[i][j][k - 1])
7578 / (float) (met->hybrid[k + l] - met->hybrid[k - 1]);
7579
7580 for (int m = k; m < k + l; m++) {
7581 float d = (float) (met->hybrid[m] - met->hybrid[k - 1]);
7582 met->pl[i][j][m] = s * d + met->pl[i][j][k - 1];
7583 }
7584
7585 /* Search for more inversions above the last inversion ... */
7586 k += l;
7587 } else {
7588 k++;
7589 }
7590 }
7591 }
7592}
7593
7594/*****************************************************************************/
7595
7597 const char *filename,
7598 const ctl_t *ctl,
7599 const clim_t *clim,
7600 met_t *met) {
7601
7602 int ncid;
7603
7604 /* Open netCDF file... */
7605 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR) {
7606 WARN("Cannot open file!");
7607 return 0;
7608 }
7609
7610 /* Read coordinates of meteo data... */
7611 read_met_grid(filename, ncid, ctl, met);
7612
7613 /* Read surface data... */
7614 read_met_surface(ncid, ctl, met);
7615
7616 /* Read meteo data on vertical levels... */
7617 read_met_levels(ncid, ctl, met);
7618
7619 /* Extrapolate data for lower boundary... */
7621
7622 /* Fix polar winds... */
7624
7625 /* Create periodic boundary conditions... */
7626 read_met_periodic(met);
7627
7628 /* Downsampling... */
7629 read_met_sample(ctl, met);
7630
7631 /* Calculate geopotential heights... */
7632 read_met_geopot(ctl, met);
7633
7634 /* Calculate potential vorticity... */
7635 read_met_pv(met);
7636
7637 /* Calculate boundary layer data... */
7638 read_met_pbl(ctl, met);
7639
7640 /* Calculate tropopause data... */
7641 read_met_tropo(ctl, clim, met);
7642
7643 /* Calculate cloud properties... */
7644 read_met_cloud(met);
7645
7646 /* Calculate convective available potential energy... */
7647 read_met_cape(ctl, clim, met);
7648
7649 /* Calculate total column ozone... */
7650 read_met_ozone(met);
7651
7652 /* Detrending... */
7653 read_met_detrend(ctl, met);
7654
7655 /* Check meteo data and smooth zeta profiles ... */
7656 read_met_monotonize(ctl, met);
7657
7658 /* Close file... */
7659 NC(nc_close(ncid));
7660
7661 /* Return success... */
7662 return 1;
7663}
7664
7665/*****************************************************************************/
7666
7668 const int ncid,
7669 const char *varname,
7670 const char *varname2,
7671 const char *varname3,
7672 const char *varname4,
7673 const char *varname5,
7674 const char *varname6,
7675 const ctl_t *ctl,
7676 const met_t *met,
7677 float dest[EX][EY],
7678 const float scl,
7679 const int init) {
7680
7681 char varsel[LEN];
7682
7683 float offset, scalfac;
7684
7685 int varid;
7686
7687 /* Check if variable exists... */
7688 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7689 sprintf(varsel, "%s", varname);
7690 else if (varname2 != NULL
7691 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7692 sprintf(varsel, "%s", varname2);
7693 else if (varname3 != NULL
7694 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7695 sprintf(varsel, "%s", varname3);
7696 else if (varname4 != NULL
7697 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7698 sprintf(varsel, "%s", varname4);
7699 else if (varname5 != NULL
7700 && nc_inq_varid(ncid, varname5, &varid) == NC_NOERR)
7701 sprintf(varsel, "%s", varname5);
7702 else if (varname6 != NULL
7703 && nc_inq_varid(ncid, varname6, &varid) == NC_NOERR)
7704 sprintf(varsel, "%s", varname6);
7705 else
7706 return 0;
7707
7708 /* Read packed data... */
7709 if (ctl->met_nc_scale
7710 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7711 && nc_get_att_float(ncid, varid, "scale_factor",
7712 &scalfac) == NC_NOERR) {
7713
7714 /* Allocate... */
7715 short *help;
7716 ALLOC(help, short,
7717 EX * EY * EP);
7718
7719 /* Read fill value and missing value... */
7720 short fillval, missval;
7721 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7722 fillval = 0;
7723 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7724 missval = 0;
7725
7726 /* Write info... */
7727 LOG(2, "Read 2-D variable: %s"
7728 " (FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7729 varsel, fillval, missval, scalfac, offset);
7730
7731 /* Read data... */
7732 NC(nc_get_var_short(ncid, varid, help));
7733
7734 /* Check meteo data layout... */
7735 if (ctl->met_convention != 0)
7736 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7737
7738 /* Copy and check data... */
7739#pragma omp parallel for default(shared) num_threads(12)
7740 for (int ix = 0; ix < met->nx; ix++)
7741 for (int iy = 0; iy < met->ny; iy++) {
7742 if (init)
7743 dest[ix][iy] = 0;
7744 const short aux = help[ARRAY_2D(iy, ix, met->nx)];
7745 if ((fillval == 0 || aux != fillval)
7746 && (missval == 0 || aux != missval)
7747 && fabsf(aux * scalfac + offset) < 1e14f)
7748 dest[ix][iy] += scl * (aux * scalfac + offset);
7749 else
7750 dest[ix][iy] = NAN;
7751 }
7752
7753 /* Free... */
7754 free(help);
7755 }
7756
7757 /* Unpacked data... */
7758 else {
7759
7760 /* Allocate... */
7761 float *help;
7762 ALLOC(help, float,
7763 EX * EY);
7764
7765 /* Read fill value and missing value... */
7766 float fillval, missval;
7767 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7768 fillval = 0;
7769 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7770 missval = 0;
7771
7772 /* Write info... */
7773 LOG(2, "Read 2-D variable: %s (FILL = %g, MISS = %g)",
7774 varsel, fillval, missval);
7775
7776 /* Read data... */
7777 NC(nc_get_var_float(ncid, varid, help));
7778
7779 /* Check meteo data layout... */
7780 if (ctl->met_convention == 0) {
7781
7782 /* Copy and check data (ordering: lat, lon)... */
7783#pragma omp parallel for default(shared) num_threads(12)
7784 for (int ix = 0; ix < met->nx; ix++)
7785 for (int iy = 0; iy < met->ny; iy++) {
7786 if (init)
7787 dest[ix][iy] = 0;
7788 const float aux = help[ARRAY_2D(iy, ix, met->nx)];
7789 if ((fillval == 0 || aux != fillval)
7790 && (missval == 0 || aux != missval)
7791 && fabsf(aux) < 1e14f)
7792 dest[ix][iy] += scl * aux;
7793 else
7794 dest[ix][iy] = NAN;
7795 }
7796
7797 } else {
7798
7799 /* Copy and check data (ordering: lon, lat)... */
7800#pragma omp parallel for default(shared) num_threads(12)
7801 for (int iy = 0; iy < met->ny; iy++)
7802 for (int ix = 0; ix < met->nx; ix++) {
7803 if (init)
7804 dest[ix][iy] = 0;
7805 const float aux = help[ARRAY_2D(ix, iy, met->ny)];
7806 if ((fillval == 0 || aux != fillval)
7807 && (missval == 0 || aux != missval)
7808 && fabsf(aux) < 1e14f)
7809 dest[ix][iy] += scl * aux;
7810 else
7811 dest[ix][iy] = NAN;
7812 }
7813 }
7814
7815 /* Free... */
7816 free(help);
7817 }
7818
7819 /* Return... */
7820 return 1;
7821}
7822
7823/*****************************************************************************/
7824
7826 const int ncid,
7827 const char *varname,
7828 const char *varname2,
7829 const char *varname3,
7830 const char *varname4,
7831 const ctl_t *ctl,
7832 const met_t *met,
7833 float dest[EX][EY][EP],
7834 const float scl) {
7835
7836 char varsel[LEN];
7837
7838 float offset, scalfac;
7839
7840 int varid;
7841
7842 /* Check if variable exists... */
7843 if (nc_inq_varid(ncid, varname, &varid) == NC_NOERR)
7844 sprintf(varsel, "%s", varname);
7845 else if (varname2 != NULL
7846 && nc_inq_varid(ncid, varname2, &varid) == NC_NOERR)
7847 sprintf(varsel, "%s", varname2);
7848 else if (varname3 != NULL
7849 && nc_inq_varid(ncid, varname3, &varid) == NC_NOERR)
7850 sprintf(varsel, "%s", varname3);
7851 else if (varname4 != NULL
7852 && nc_inq_varid(ncid, varname4, &varid) == NC_NOERR)
7853 sprintf(varsel, "%s", varname4);
7854 else
7855 return 0;
7856
7857 /* Read packed data... */
7858 if (ctl->met_nc_scale
7859 && nc_get_att_float(ncid, varid, "add_offset", &offset) == NC_NOERR
7860 && nc_get_att_float(ncid, varid, "scale_factor",
7861 &scalfac) == NC_NOERR) {
7862
7863 /* Allocate... */
7864 short *help;
7865 ALLOC(help, short,
7866 EX * EY * EP);
7867
7868 /* Read fill value and missing value... */
7869 short fillval, missval;
7870 if (nc_get_att_short(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7871 fillval = 0;
7872 if (nc_get_att_short(ncid, varid, "missing_value", &missval) != NC_NOERR)
7873 missval = 0;
7874
7875 /* Write info... */
7876 LOG(2, "Read 3-D variable: %s "
7877 "(FILL = %d, MISS = %d, SCALE = %g, OFFSET = %g)",
7878 varsel, fillval, missval, scalfac, offset);
7879
7880 /* Read data... */
7881 NC(nc_get_var_short(ncid, varid, help));
7882
7883 /* Check meteo data layout... */
7884 if (ctl->met_convention != 0)
7885 ERRMSG("Meteo data layout not implemented for packed netCDF files!");
7886
7887 /* Copy and check data... */
7888#pragma omp parallel for default(shared) num_threads(12)
7889 for (int ix = 0; ix < met->nx; ix++)
7890 for (int iy = 0; iy < met->ny; iy++)
7891 for (int ip = 0; ip < met->np; ip++) {
7892 const short aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7893 if ((fillval == 0 || aux != fillval)
7894 && (missval == 0 || aux != missval)
7895 && fabsf(aux * scalfac + offset) < 1e14f)
7896 dest[ix][iy][ip] = scl * (aux * scalfac + offset);
7897 else
7898 dest[ix][iy][ip] = NAN;
7899 }
7900
7901 /* Free... */
7902 free(help);
7903 }
7904
7905 /* Unpacked data... */
7906 else {
7907
7908 /* Allocate... */
7909 float *help;
7910 ALLOC(help, float,
7911 EX * EY * EP);
7912
7913 /* Read fill value and missing value... */
7914 float fillval, missval;
7915 if (nc_get_att_float(ncid, varid, "_FillValue", &fillval) != NC_NOERR)
7916 fillval = 0;
7917 if (nc_get_att_float(ncid, varid, "missing_value", &missval) != NC_NOERR)
7918 missval = 0;
7919
7920 /* Write info... */
7921 LOG(2, "Read 3-D variable: %s (FILL = %g, MISS = %g)",
7922 varsel, fillval, missval);
7923
7924 /* Read data... */
7925 NC(nc_get_var_float(ncid, varid, help));
7926
7927 /* Check meteo data layout... */
7928 if (ctl->met_convention == 0) {
7929
7930 /* Copy and check data (ordering: lev, lat, lon)... */
7931#pragma omp parallel for default(shared) num_threads(12)
7932 for (int ix = 0; ix < met->nx; ix++)
7933 for (int iy = 0; iy < met->ny; iy++)
7934 for (int ip = 0; ip < met->np; ip++) {
7935 const float aux = help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)];
7936 if ((fillval == 0 || aux != fillval)
7937 && (missval == 0 || aux != missval)
7938 && fabsf(aux) < 1e14f)
7939 dest[ix][iy][ip] = scl * aux;
7940 else
7941 dest[ix][iy][ip] = NAN;
7942 }
7943
7944 } else {
7945
7946 /* Copy and check data (ordering: lon, lat, lev)... */
7947#pragma omp parallel for default(shared) num_threads(12)
7948 for (int ip = 0; ip < met->np; ip++)
7949 for (int iy = 0; iy < met->ny; iy++)
7950 for (int ix = 0; ix < met->nx; ix++) {
7951 const float aux = help[ARRAY_3D(ix, iy, met->ny, ip, met->np)];
7952 if ((fillval == 0 || aux != fillval)
7953 && (missval == 0 || aux != missval)
7954 && fabsf(aux) < 1e14f)
7955 dest[ix][iy][ip] = scl * aux;
7956 else
7957 dest[ix][iy][ip] = NAN;
7958 }
7959 }
7960
7961 /* Free... */
7962 free(help);
7963 }
7964
7965 /* Return... */
7966 return 1;
7967}
7968
7969/*****************************************************************************/
7970
7972 const ctl_t *ctl,
7973 met_t *met) {
7974
7975 /* Set timer... */
7976 SELECT_TIMER("READ_MET_PBL", "METPROC", NVTX_READ);
7977 LOG(2, "Calculate planetary boundary layer...");
7978
7979 /* Convert PBL height from meteo file to pressure... */
7980 if (ctl->met_pbl == 1) {
7981
7982 /* Loop over grid points... */
7983#pragma omp parallel for default(shared) collapse(2)
7984 for (int ix = 0; ix < met->nx; ix++)
7985 for (int iy = 0; iy < met->ny; iy++) {
7986
7987 /* Get pressure at top of PBL... */
7988 const float z = met->zs[ix][iy] + met->pbl[ix][iy];
7989 const int ip = locate_irr_float(met->z[ix][iy], met->np, z, 0);
7990 met->pbl[ix][iy] =
7991 (float) (LIN(met->z[ix][iy][ip], met->p[ip],
7992 met->z[ix][iy][ip + 1], met->p[ip + 1], z));
7993 }
7994 }
7995
7996 /* Determine PBL based on Richardson number... */
7997 else if (ctl->met_pbl == 2) {
7998
7999 /* Parameters used to estimate the height of the PBL
8000 (e.g., Vogelezang and Holtslag, 1996; Seidel et al., 2012)... */
8001 const double rib_crit = 0.25, dz = 0.05, umin = 5.0;
8002
8003 /* Loop over grid points... */
8004#pragma omp parallel for default(shared) collapse(2)
8005 for (int ix = 0; ix < met->nx; ix++)
8006 for (int iy = 0; iy < met->ny; iy++) {
8007
8008 /* Set bottom level of PBL... */
8009 const double pbl_bot = met->ps[ix][iy] * exp(-dz / H0);
8010
8011 /* Find lowest level near the bottom... */
8012 int ip;
8013 for (ip = 1; ip < met->np; ip++)
8014 if (met->p[ip] < pbl_bot)
8015 break;
8016
8017 /* Get near surface data... */
8018 const double h2os = LIN(met->p[ip - 1], met->h2o[ix][iy][ip - 1],
8019 met->p[ip], met->h2o[ix][iy][ip], pbl_bot);
8020 const double tvs = THETAVIRT(pbl_bot, met->ts[ix][iy], h2os);
8021
8022 /* Init... */
8023 double rib_old = 0;
8024
8025 /* Loop over levels... */
8026 for (; ip < met->np; ip++) {
8027
8028 /* Get squared horizontal wind speed... */
8029 double vh2 = SQR(met->u[ix][iy][ip] - met->us[ix][iy])
8030 + SQR(met->v[ix][iy][ip] - met->vs[ix][iy]);
8031 vh2 = MAX(vh2, SQR(umin));
8032
8033 /* Calculate bulk Richardson number... */
8034 const double rib =
8035 G0 * 1e3 * (met->z[ix][iy][ip] - met->zs[ix][iy]) / tvs
8036 * (THETAVIRT(met->p[ip], met->t[ix][iy][ip],
8037 met->h2o[ix][iy][ip]) - tvs) / vh2;
8038
8039 /* Check for critical value... */
8040 if (rib >= rib_crit) {
8041 met->pbl[ix][iy] = (float) (LIN(rib_old, met->p[ip - 1],
8042 rib, met->p[ip], rib_crit));
8043 if (met->pbl[ix][iy] > pbl_bot)
8044 met->pbl[ix][iy] = (float) pbl_bot;
8045 break;
8046 }
8047
8048 /* Save Richardson number... */
8049 rib_old = rib;
8050 }
8051 }
8052 }
8053
8054 /* Determine PBL based on potential temperature... */
8055 if (ctl->met_pbl == 3) {
8056
8057 /* Parameters used to estimate the height of the PBL
8058 (following HYSPLIT model)... */
8059 const double dtheta = 2.0, zmin = 0.1;
8060
8061 /* Loop over grid points... */
8062#pragma omp parallel for default(shared) collapse(2)
8063 for (int ix = 0; ix < met->nx; ix++)
8064 for (int iy = 0; iy < met->ny; iy++) {
8065
8066 /* Potential temperature at the surface... */
8067 const double theta0 = THETA(met->ps[ix][iy], met->ts[ix][iy]);
8068
8069 /* Find topmost level where theta exceeds surface value by 2 K... */
8070 int ip;
8071 for (ip = met->np - 2; ip > 0; ip--)
8072 if (met->p[ip] >= 300.)
8073 if (met->p[ip] > met->ps[ix][iy]
8074 || THETA(met->p[ip], met->t[ix][iy][ip]) <= theta0 + dtheta)
8075 break;
8076
8077 /* Interpolate... */
8078 met->pbl[ix][iy]
8079 = (float) (LIN(THETA(met->p[ip + 1], met->t[ix][iy][ip + 1]),
8080 met->p[ip + 1],
8081 THETA(met->p[ip], met->t[ix][iy][ip]),
8082 met->p[ip], theta0 + dtheta));
8083
8084 /* Check minimum value... */
8085 double pbl_min = met->ps[ix][iy] * exp(-zmin / H0);
8086 if (met->pbl[ix][iy] > pbl_min || met->p[ip] > met->ps[ix][iy])
8087 met->pbl[ix][iy] = (float) pbl_min;
8088 }
8089 }
8090
8091 /* Loop over grid points... */
8092#pragma omp parallel for default(shared) collapse(2)
8093 for (int ix = 0; ix < met->nx; ix++)
8094 for (int iy = 0; iy < met->ny; iy++) {
8095
8096 /* Check minimum value... */
8097 double pbl_min = met->ps[ix][iy] * exp(-ctl->met_pbl_min / H0);
8098 met->pbl[ix][iy] = MIN(met->pbl[ix][iy], (float) pbl_min);
8099
8100 /* Check maximum value... */
8101 double pbl_max = met->ps[ix][iy] * exp(-ctl->met_pbl_max / H0);
8102 met->pbl[ix][iy] = MAX(met->pbl[ix][iy], (float) pbl_max);
8103 }
8104}
8105
8106/*****************************************************************************/
8107
8109 met_t *met) {
8110
8111 /* Set timer... */
8112 SELECT_TIMER("READ_MET_PERIODIC", "METPROC", NVTX_READ);
8113 LOG(2, "Apply periodic boundary conditions...");
8114
8115 /* Check longitudes... */
8116 if (!(fabs(met->lon[met->nx - 1] - met->lon[0]
8117 + met->lon[1] - met->lon[0] - 360) < 0.01))
8118 return;
8119
8120 /* Increase longitude counter... */
8121 if ((++met->nx) >= EX)
8122 ERRMSG("Cannot create periodic boundary conditions!");
8123
8124 /* Set longitude... */
8125 met->lon[met->nx - 1] = met->lon[met->nx - 2] + met->lon[1] - met->lon[0];
8126
8127 /* Loop over latitudes and pressure levels... */
8128#pragma omp parallel for default(shared)
8129 for (int iy = 0; iy < met->ny; iy++) {
8130 met->ps[met->nx - 1][iy] = met->ps[0][iy];
8131 met->zs[met->nx - 1][iy] = met->zs[0][iy];
8132 met->ts[met->nx - 1][iy] = met->ts[0][iy];
8133 met->us[met->nx - 1][iy] = met->us[0][iy];
8134 met->vs[met->nx - 1][iy] = met->vs[0][iy];
8135 met->ess[met->nx - 1][iy] = met->ess[0][iy];
8136 met->nss[met->nx - 1][iy] = met->nss[0][iy];
8137 met->shf[met->nx - 1][iy] = met->shf[0][iy];
8138 met->lsm[met->nx - 1][iy] = met->lsm[0][iy];
8139 met->sst[met->nx - 1][iy] = met->sst[0][iy];
8140 met->pbl[met->nx - 1][iy] = met->pbl[0][iy];
8141 met->cape[met->nx - 1][iy] = met->cape[0][iy];
8142 met->cin[met->nx - 1][iy] = met->cin[0][iy];
8143 for (int ip = 0; ip < met->np; ip++) {
8144 met->t[met->nx - 1][iy][ip] = met->t[0][iy][ip];
8145 met->u[met->nx - 1][iy][ip] = met->u[0][iy][ip];
8146 met->v[met->nx - 1][iy][ip] = met->v[0][iy][ip];
8147 met->w[met->nx - 1][iy][ip] = met->w[0][iy][ip];
8148 met->h2o[met->nx - 1][iy][ip] = met->h2o[0][iy][ip];
8149 met->o3[met->nx - 1][iy][ip] = met->o3[0][iy][ip];
8150 met->lwc[met->nx - 1][iy][ip] = met->lwc[0][iy][ip];
8151 met->rwc[met->nx - 1][iy][ip] = met->rwc[0][iy][ip];
8152 met->iwc[met->nx - 1][iy][ip] = met->iwc[0][iy][ip];
8153 met->swc[met->nx - 1][iy][ip] = met->swc[0][iy][ip];
8154 met->cc[met->nx - 1][iy][ip] = met->cc[0][iy][ip];
8155 }
8156 for (int ip = 0; ip < met->npl; ip++) {
8157 met->ul[met->nx - 1][iy][ip] = met->ul[0][iy][ip];
8158 met->vl[met->nx - 1][iy][ip] = met->vl[0][iy][ip];
8159 met->wl[met->nx - 1][iy][ip] = met->wl[0][iy][ip];
8160 met->pl[met->nx - 1][iy][ip] = met->pl[0][iy][ip];
8161 met->zetal[met->nx - 1][iy][ip] = met->zetal[0][iy][ip];
8162 met->zeta_dotl[met->nx - 1][iy][ip] = met->zeta_dotl[0][iy][ip];
8163 }
8164 }
8165}
8166
8167/*****************************************************************************/
8168
8170 met_t *met) {
8171
8172 /* Set timer... */
8173 SELECT_TIMER("READ_MET_POLAR_WINDS", "METPROC", NVTX_READ);
8174 LOG(2, "Apply fix for polar winds...");
8175
8176 /* Check latitudes... */
8177 if (fabs(met->lat[0]) < 89.999 || fabs(met->lat[met->ny - 1]) < 89.999)
8178 return;
8179
8180 /* Loop over hemispheres... */
8181 for (int ihem = 0; ihem < 2; ihem++) {
8182
8183 /* Set latitude indices... */
8184 int i89 = 1, i90 = 0, sign = 1;
8185 if (ihem == 1) {
8186 i89 = met->ny - 2;
8187 i90 = met->ny - 1;
8188 }
8189 if (met->lat[i90] < 0)
8190 sign = -1;
8191
8192 /* Look-up table of cosinus and sinus... */
8193 double clon[EX], slon[EX];
8194#pragma omp parallel for default(shared)
8195 for (int ix = 0; ix < met->nx; ix++) {
8196 clon[ix] = cos(sign * DEG2RAD(met->lon[ix]));
8197 slon[ix] = sin(sign * DEG2RAD(met->lon[ix]));
8198 }
8199
8200 /* Loop over levels... */
8201#pragma omp parallel for default(shared)
8202 for (int ip = 0; ip < met->np; ip++) {
8203
8204 /* Transform 89 degree u and v winds into Cartesian coordinates and take the mean... */
8205 double vel89x = 0, vel89y = 0;
8206 for (int ix = 0; ix < met->nx; ix++) {
8207 vel89x +=
8208 (met->u[ix][i89][ip] * clon[ix] -
8209 met->v[ix][i89][ip] * slon[ix]) / met->nx;
8210 vel89y +=
8211 (met->u[ix][i89][ip] * slon[ix] +
8212 met->v[ix][i89][ip] * clon[ix]) / met->nx;
8213 }
8214
8215 /* Replace 90 degree winds by 89 degree mean... */
8216 for (int ix = 0; ix < met->nx; ix++) {
8217 met->u[ix][i90][ip]
8218 = (float) (vel89x * clon[ix] + vel89y * slon[ix]);
8219 met->v[ix][i90][ip]
8220 = (float) (-vel89x * slon[ix] + vel89y * clon[ix]);
8221 }
8222 }
8223 }
8224}
8225
8226/*****************************************************************************/
8227
8229 met_t *met) {
8230
8231 double pows[EP];
8232
8233 /* Set timer... */
8234 SELECT_TIMER("READ_MET_PV", "METPROC", NVTX_READ);
8235 LOG(2, "Calculate potential vorticity...");
8236
8237 /* Set powers... */
8238#pragma omp parallel for default(shared)
8239 for (int ip = 0; ip < met->np; ip++)
8240 pows[ip] = pow(1000. / met->p[ip], 0.286);
8241
8242 /* Loop over grid points... */
8243#pragma omp parallel for default(shared)
8244 for (int ix = 0; ix < met->nx; ix++) {
8245
8246 /* Set indices... */
8247 const int ix0 = MAX(ix - 1, 0);
8248 const int ix1 = MIN(ix + 1, met->nx - 1);
8249
8250 /* Loop over grid points... */
8251 for (int iy = 0; iy < met->ny; iy++) {
8252
8253 /* Set indices... */
8254 const int iy0 = MAX(iy - 1, 0);
8255 const int iy1 = MIN(iy + 1, met->ny - 1);
8256
8257 /* Set auxiliary variables... */
8258 const double latr = 0.5 * (met->lat[iy1] + met->lat[iy0]);
8259 const double dx = 1000. * DEG2DX(met->lon[ix1] - met->lon[ix0], latr);
8260 const double dy = 1000. * DEG2DY(met->lat[iy1] - met->lat[iy0]);
8261 const double c0 = cos(DEG2RAD(met->lat[iy0]));
8262 const double c1 = cos(DEG2RAD(met->lat[iy1]));
8263 const double cr = cos(DEG2RAD(latr));
8264 const double vort = 2 * 7.2921e-5 * sin(DEG2RAD(latr));
8265
8266 /* Loop over grid points... */
8267 for (int ip = 0; ip < met->np; ip++) {
8268
8269 /* Get gradients in longitude... */
8270 const double dtdx
8271 = (met->t[ix1][iy][ip] - met->t[ix0][iy][ip]) * pows[ip] / dx;
8272 const double dvdx = (met->v[ix1][iy][ip] - met->v[ix0][iy][ip]) / dx;
8273
8274 /* Get gradients in latitude... */
8275 const double dtdy
8276 = (met->t[ix][iy1][ip] - met->t[ix][iy0][ip]) * pows[ip] / dy;
8277 const double dudy
8278 = (met->u[ix][iy1][ip] * c1 - met->u[ix][iy0][ip] * c0) / dy;
8279
8280 /* Set indices... */
8281 const int ip0 = MAX(ip - 1, 0);
8282 const int ip1 = MIN(ip + 1, met->np - 1);
8283
8284 /* Get gradients in pressure... */
8285 double dtdp, dudp, dvdp;
8286 const double dp0 = 100. * (met->p[ip] - met->p[ip0]);
8287 const double dp1 = 100. * (met->p[ip1] - met->p[ip]);
8288 if (ip != ip0 && ip != ip1) {
8289 double denom = dp0 * dp1 * (dp0 + dp1);
8290 dtdp = (dp0 * dp0 * met->t[ix][iy][ip1] * pows[ip1]
8291 - dp1 * dp1 * met->t[ix][iy][ip0] * pows[ip0]
8292 + (dp1 * dp1 - dp0 * dp0) * met->t[ix][iy][ip] * pows[ip])
8293 / denom;
8294 dudp = (dp0 * dp0 * met->u[ix][iy][ip1]
8295 - dp1 * dp1 * met->u[ix][iy][ip0]
8296 + (dp1 * dp1 - dp0 * dp0) * met->u[ix][iy][ip])
8297 / denom;
8298 dvdp = (dp0 * dp0 * met->v[ix][iy][ip1]
8299 - dp1 * dp1 * met->v[ix][iy][ip0]
8300 + (dp1 * dp1 - dp0 * dp0) * met->v[ix][iy][ip])
8301 / denom;
8302 } else {
8303 const double denom = dp0 + dp1;
8304 dtdp =
8305 (met->t[ix][iy][ip1] * pows[ip1] -
8306 met->t[ix][iy][ip0] * pows[ip0]) / denom;
8307 dudp = (met->u[ix][iy][ip1] - met->u[ix][iy][ip0]) / denom;
8308 dvdp = (met->v[ix][iy][ip1] - met->v[ix][iy][ip0]) / denom;
8309 }
8310
8311 /* Calculate PV... */
8312 met->pv[ix][iy][ip] = (float)
8313 (1e6 * G0 *
8314 (-dtdp * (dvdx - dudy / cr + vort) + dvdp * dtdx - dudp * dtdy));
8315 }
8316 }
8317 }
8318
8319 /* Fix for polar regions... */
8320#pragma omp parallel for default(shared)
8321 for (int ix = 0; ix < met->nx; ix++)
8322 for (int ip = 0; ip < met->np; ip++) {
8323 met->pv[ix][0][ip]
8324 = met->pv[ix][1][ip]
8325 = met->pv[ix][2][ip];
8326 met->pv[ix][met->ny - 1][ip]
8327 = met->pv[ix][met->ny - 2][ip]
8328 = met->pv[ix][met->ny - 3][ip];
8329 }
8330}
8331
8332/*****************************************************************************/
8333
8335 met_t *met) {
8336
8337 /* Set timer... */
8338 SELECT_TIMER("READ_MET_OZONE", "METPROC", NVTX_READ);
8339 LOG(2, "Calculate total column ozone...");
8340
8341 /* Loop over columns... */
8342#pragma omp parallel for default(shared) collapse(2)
8343 for (int ix = 0; ix < met->nx; ix++)
8344 for (int iy = 0; iy < met->ny; iy++) {
8345
8346 /* Integrate... */
8347 double cd = 0;
8348 for (int ip = 1; ip < met->np; ip++)
8349 if (met->p[ip - 1] <= met->ps[ix][iy]) {
8350 const double vmr =
8351 0.5 * (met->o3[ix][iy][ip - 1] + met->o3[ix][iy][ip]);
8352 const double dp = met->p[ip - 1] - met->p[ip];
8353 cd += vmr * MO3 / MA * dp * 1e2 / G0;
8354 }
8355
8356 /* Convert to Dobson units... */
8357 met->o3c[ix][iy] = (float) (cd / 2.1415e-5);
8358 }
8359}
8360
8361/*****************************************************************************/
8362
8364 const ctl_t *ctl,
8365 met_t *met) {
8366
8367 met_t *help;
8368
8369 /* Check parameters... */
8370 if (ctl->met_dp <= 1 && ctl->met_dx <= 1 && ctl->met_dy <= 1
8371 && ctl->met_sp <= 1 && ctl->met_sx <= 1 && ctl->met_sy <= 1)
8372 return;
8373
8374 /* Set timer... */
8375 SELECT_TIMER("READ_MET_SAMPLE", "METPROC", NVTX_READ);
8376 LOG(2, "Downsampling of meteo data...");
8377
8378 /* Allocate... */
8379 ALLOC(help, met_t, 1);
8380
8381 /* Copy data... */
8382 help->nx = met->nx;
8383 help->ny = met->ny;
8384 help->np = met->np;
8385 memcpy(help->lon, met->lon, sizeof(met->lon));
8386 memcpy(help->lat, met->lat, sizeof(met->lat));
8387 memcpy(help->p, met->p, sizeof(met->p));
8388
8389 /* Smoothing... */
8390 for (int ix = 0; ix < met->nx; ix += ctl->met_dx) {
8391 for (int iy = 0; iy < met->ny; iy += ctl->met_dy) {
8392 for (int ip = 0; ip < met->np; ip += ctl->met_dp) {
8393 help->ps[ix][iy] = 0;
8394 help->zs[ix][iy] = 0;
8395 help->ts[ix][iy] = 0;
8396 help->us[ix][iy] = 0;
8397 help->vs[ix][iy] = 0;
8398 help->ess[ix][iy] = 0;
8399 help->nss[ix][iy] = 0;
8400 help->shf[ix][iy] = 0;
8401 help->lsm[ix][iy] = 0;
8402 help->sst[ix][iy] = 0;
8403 help->pbl[ix][iy] = 0;
8404 help->cape[ix][iy] = 0;
8405 help->cin[ix][iy] = 0;
8406 help->t[ix][iy][ip] = 0;
8407 help->u[ix][iy][ip] = 0;
8408 help->v[ix][iy][ip] = 0;
8409 help->w[ix][iy][ip] = 0;
8410 help->h2o[ix][iy][ip] = 0;
8411 help->o3[ix][iy][ip] = 0;
8412 help->lwc[ix][iy][ip] = 0;
8413 help->rwc[ix][iy][ip] = 0;
8414 help->iwc[ix][iy][ip] = 0;
8415 help->swc[ix][iy][ip] = 0;
8416 help->cc[ix][iy][ip] = 0;
8417 float wsum = 0;
8418 for (int ix2 = ix - ctl->met_sx + 1; ix2 <= ix + ctl->met_sx - 1;
8419 ix2++) {
8420 int ix3 = ix2;
8421 if (ix3 < 0)
8422 ix3 += met->nx;
8423 else if (ix3 >= met->nx)
8424 ix3 -= met->nx;
8425
8426 for (int iy2 = MAX(iy - ctl->met_sy + 1, 0);
8427 iy2 <= MIN(iy + ctl->met_sy - 1, met->ny - 1); iy2++)
8428 for (int ip2 = MAX(ip - ctl->met_sp + 1, 0);
8429 ip2 <= MIN(ip + ctl->met_sp - 1, met->np - 1); ip2++) {
8430 float w = (1.0f - (float) abs(ix - ix2) / (float) ctl->met_sx)
8431 * (1.0f - (float) abs(iy - iy2) / (float) ctl->met_sy)
8432 * (1.0f - (float) abs(ip - ip2) / (float) ctl->met_sp);
8433 help->ps[ix][iy] += w * met->ps[ix3][iy2];
8434 help->zs[ix][iy] += w * met->zs[ix3][iy2];
8435 help->ts[ix][iy] += w * met->ts[ix3][iy2];
8436 help->us[ix][iy] += w * met->us[ix3][iy2];
8437 help->vs[ix][iy] += w * met->vs[ix3][iy2];
8438 help->ess[ix][iy] += w * met->ess[ix3][iy2];
8439 help->nss[ix][iy] += w * met->nss[ix3][iy2];
8440 help->shf[ix][iy] += w * met->shf[ix3][iy2];
8441 help->lsm[ix][iy] += w * met->lsm[ix3][iy2];
8442 help->sst[ix][iy] += w * met->sst[ix3][iy2];
8443 help->pbl[ix][iy] += w * met->pbl[ix3][iy2];
8444 help->cape[ix][iy] += w * met->cape[ix3][iy2];
8445 help->cin[ix][iy] += w * met->cin[ix3][iy2];
8446 help->t[ix][iy][ip] += w * met->t[ix3][iy2][ip2];
8447 help->u[ix][iy][ip] += w * met->u[ix3][iy2][ip2];
8448 help->v[ix][iy][ip] += w * met->v[ix3][iy2][ip2];
8449 help->w[ix][iy][ip] += w * met->w[ix3][iy2][ip2];
8450 help->h2o[ix][iy][ip] += w * met->h2o[ix3][iy2][ip2];
8451 help->o3[ix][iy][ip] += w * met->o3[ix3][iy2][ip2];
8452 help->lwc[ix][iy][ip] += w * met->lwc[ix3][iy2][ip2];
8453 help->rwc[ix][iy][ip] += w * met->rwc[ix3][iy2][ip2];
8454 help->iwc[ix][iy][ip] += w * met->iwc[ix3][iy2][ip2];
8455 help->swc[ix][iy][ip] += w * met->swc[ix3][iy2][ip2];
8456 help->cc[ix][iy][ip] += w * met->cc[ix3][iy2][ip2];
8457 wsum += w;
8458 }
8459 }
8460 help->ps[ix][iy] /= wsum;
8461 help->zs[ix][iy] /= wsum;
8462 help->ts[ix][iy] /= wsum;
8463 help->us[ix][iy] /= wsum;
8464 help->vs[ix][iy] /= wsum;
8465 help->ess[ix][iy] /= wsum;
8466 help->nss[ix][iy] /= wsum;
8467 help->shf[ix][iy] /= wsum;
8468 help->lsm[ix][iy] /= wsum;
8469 help->sst[ix][iy] /= wsum;
8470 help->pbl[ix][iy] /= wsum;
8471 help->cape[ix][iy] /= wsum;
8472 help->cin[ix][iy] /= wsum;
8473 help->t[ix][iy][ip] /= wsum;
8474 help->u[ix][iy][ip] /= wsum;
8475 help->v[ix][iy][ip] /= wsum;
8476 help->w[ix][iy][ip] /= wsum;
8477 help->h2o[ix][iy][ip] /= wsum;
8478 help->o3[ix][iy][ip] /= wsum;
8479 help->lwc[ix][iy][ip] /= wsum;
8480 help->rwc[ix][iy][ip] /= wsum;
8481 help->iwc[ix][iy][ip] /= wsum;
8482 help->swc[ix][iy][ip] /= wsum;
8483 help->cc[ix][iy][ip] /= wsum;
8484 }
8485 }
8486 }
8487
8488 /* Downsampling... */
8489 met->nx = 0;
8490 for (int ix = 0; ix < help->nx; ix += ctl->met_dx) {
8491 met->lon[met->nx] = help->lon[ix];
8492 met->ny = 0;
8493 for (int iy = 0; iy < help->ny; iy += ctl->met_dy) {
8494 met->lat[met->ny] = help->lat[iy];
8495 met->ps[met->nx][met->ny] = help->ps[ix][iy];
8496 met->zs[met->nx][met->ny] = help->zs[ix][iy];
8497 met->ts[met->nx][met->ny] = help->ts[ix][iy];
8498 met->us[met->nx][met->ny] = help->us[ix][iy];
8499 met->vs[met->nx][met->ny] = help->vs[ix][iy];
8500 met->ess[met->nx][met->ny] = help->ess[ix][iy];
8501 met->nss[met->nx][met->ny] = help->nss[ix][iy];
8502 met->shf[met->nx][met->ny] = help->shf[ix][iy];
8503 met->lsm[met->nx][met->ny] = help->lsm[ix][iy];
8504 met->sst[met->nx][met->ny] = help->sst[ix][iy];
8505 met->pbl[met->nx][met->ny] = help->pbl[ix][iy];
8506 met->cape[met->nx][met->ny] = help->cape[ix][iy];
8507 met->cin[met->nx][met->ny] = help->cin[ix][iy];
8508 met->np = 0;
8509 for (int ip = 0; ip < help->np; ip += ctl->met_dp) {
8510 met->p[met->np] = help->p[ip];
8511 met->t[met->nx][met->ny][met->np] = help->t[ix][iy][ip];
8512 met->u[met->nx][met->ny][met->np] = help->u[ix][iy][ip];
8513 met->v[met->nx][met->ny][met->np] = help->v[ix][iy][ip];
8514 met->w[met->nx][met->ny][met->np] = help->w[ix][iy][ip];
8515 met->h2o[met->nx][met->ny][met->np] = help->h2o[ix][iy][ip];
8516 met->o3[met->nx][met->ny][met->np] = help->o3[ix][iy][ip];
8517 met->lwc[met->nx][met->ny][met->np] = help->lwc[ix][iy][ip];
8518 met->rwc[met->nx][met->ny][met->np] = help->rwc[ix][iy][ip];
8519 met->iwc[met->nx][met->ny][met->np] = help->iwc[ix][iy][ip];
8520 met->swc[met->nx][met->ny][met->np] = help->swc[ix][iy][ip];
8521 met->cc[met->nx][met->ny][met->np] = help->cc[ix][iy][ip];
8522 met->np++;
8523 }
8524 met->ny++;
8525 }
8526 met->nx++;
8527 }
8528
8529 /* Free... */
8530 free(help);
8531}
8532
8533/*****************************************************************************/
8534
8536 const int ncid,
8537 const ctl_t *ctl,
8538 met_t *met) {
8539
8540 /* Set timer... */
8541 SELECT_TIMER("READ_MET_SURFACE", "INPUT", NVTX_READ);
8542 LOG(2, "Read surface data...");
8543
8544 /* Read surface pressure... */
8545 if (read_met_nc_2d
8546 (ncid, "lnsp", "LNSP", NULL, NULL, NULL, NULL, ctl, met, met->ps, 1.0f,
8547 1)) {
8548 for (int ix = 0; ix < met->nx; ix++)
8549 for (int iy = 0; iy < met->ny; iy++)
8550 met->ps[ix][iy] = (float) (exp(met->ps[ix][iy]) / 100.);
8551 } else
8552 if (!read_met_nc_2d
8553 (ncid, "ps", "PS", "sp", "SP", NULL, NULL, ctl, met, met->ps, 0.01f,
8554 1)) {
8555 WARN("Cannot not read surface pressure data (use lowest level)!");
8556 for (int ix = 0; ix < met->nx; ix++)
8557 for (int iy = 0; iy < met->ny; iy++)
8558 met->ps[ix][iy]
8559 = (ctl->met_np > 0 ? (float) ctl->met_p[0] : (float) met->p[0]);
8560 }
8561
8562 /* MPTRAC meteo data... */
8563 if (ctl->met_clams == 0) {
8564
8565 /* Read geopotential height at the surface... */
8566 if (!read_met_nc_2d
8567 (ncid, "z", "Z", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8568 (float) (1. / (1000. * G0)), 1))
8569 if (!read_met_nc_2d
8570 (ncid, "zm", "ZM", NULL, NULL, NULL, NULL, ctl, met, met->zs,
8571 (float) (1. / 1000.), 1))
8572 WARN("Cannot read surface geopotential height!");
8573 }
8574
8575 /* CLaMS meteo data... */
8576 else {
8577
8578 /* Read geopotential height at the surface
8579 (use lowermost level of 3-D data field)... */
8580 float *help;
8581 ALLOC(help, float,
8582 EX * EY * EP);
8583 memcpy(help, met->pl, sizeof(met->pl));
8584 if (!read_met_nc_3d
8585 (ncid, "gph", "GPH", NULL, NULL, ctl, met, met->pl,
8586 (float) (1e-3 / G0)))
8587 ERRMSG("Cannot read geopotential height!");
8588 for (int ix = 0; ix < met->nx; ix++)
8589 for (int iy = 0; iy < met->ny; iy++)
8590 met->zs[ix][iy] = met->pl[ix][iy][0];
8591 memcpy(met->pl, help, sizeof(met->pl));
8592 free(help);
8593 }
8594
8595 /* Read temperature at the surface... */
8596 if (!read_met_nc_2d
8597 (ncid, "t2m", "T2M", "2t", "2T", "t2", "T2", ctl, met, met->ts, 1.0, 1))
8598 WARN("Cannot read surface temperature!");
8599
8600 /* Read zonal wind at the surface... */
8601 if (!read_met_nc_2d
8602 (ncid, "u10m", "U10M", "10u", "10U", "u10", "U10", ctl, met, met->us,
8603 1.0, 1))
8604 WARN("Cannot read surface zonal wind!");
8605
8606 /* Read meridional wind at the surface... */
8607 if (!read_met_nc_2d
8608 (ncid, "v10m", "V10M", "10v", "10V", "v10", "V10", ctl, met, met->vs,
8609 1.0, 1))
8610 WARN("Cannot read surface meridional wind!");
8611
8612 /* Read eastward turbulent surface stress... */
8613 if (!read_met_nc_2d
8614 (ncid, "iews", "IEWS", NULL, NULL, NULL, NULL, ctl, met, met->ess, 1.0,
8615 1))
8616 WARN("Cannot read eastward turbulent surface stress!");
8617
8618 /* Read northward turbulent surface stress... */
8619 if (!read_met_nc_2d
8620 (ncid, "inss", "INSS", NULL, NULL, NULL, NULL, ctl, met, met->nss, 1.0,
8621 1))
8622 WARN("Cannot read nothward turbulent surface stress!");
8623
8624 /* Read surface sensible heat flux... */
8625 if (!read_met_nc_2d
8626 (ncid, "ishf", "ISHF", NULL, NULL, NULL, NULL, ctl, met, met->shf, 1.0,
8627 1))
8628 WARN("Cannot read surface sensible heat flux!");
8629
8630 /* Read land-sea mask... */
8631 if (!read_met_nc_2d
8632 (ncid, "lsm", "LSM", NULL, NULL, NULL, NULL, ctl, met, met->lsm, 1.0,
8633 1))
8634 WARN("Cannot read land-sea mask!");
8635
8636 /* Read sea surface temperature... */
8637 if (!read_met_nc_2d
8638 (ncid, "sstk", "SSTK", "sst", "SST", NULL, NULL, ctl, met, met->sst,
8639 1.0, 1))
8640 WARN("Cannot read sea surface temperature!");
8641
8642 /* Read PBL... */
8643 if (ctl->met_pbl == 0)
8644 if (!read_met_nc_2d
8645 (ncid, "blp", "BLP", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8646 0.01f, 1))
8647 WARN("Cannot read planetary boundary layer pressure!");
8648 if (ctl->met_pbl == 1)
8649 if (!read_met_nc_2d
8650 (ncid, "blh", "BLH", NULL, NULL, NULL, NULL, ctl, met, met->pbl,
8651 0.001f, 1))
8652 WARN("Cannot read planetary boundary layer height!");
8653
8654 /* Read CAPE... */
8655 if (ctl->met_cape == 0)
8656 if (!read_met_nc_2d
8657 (ncid, "cape", "CAPE", NULL, NULL, NULL, NULL, ctl, met, met->cape,
8658 1.0, 1))
8659 WARN("Cannot read CAPE!");
8660
8661 /* Read CIN... */
8662 if (ctl->met_cape == 0)
8663 if (!read_met_nc_2d
8664 (ncid, "cin", "CIN", NULL, NULL, NULL, NULL, ctl, met, met->cin,
8665 1.0, 1))
8666 WARN("Cannot read convective inhibition!");
8667}
8668
8669/*****************************************************************************/
8670
8672 const ctl_t *ctl,
8673 const clim_t *clim,
8674 met_t *met) {
8675
8676 double p2[200], pv[EP], pv2[200], t[EP], t2[200], th[EP],
8677 th2[200], z[EP], z2[200];
8678
8679 /* Set timer... */
8680 SELECT_TIMER("READ_MET_TROPO", "METPROC", NVTX_READ);
8681 LOG(2, "Calculate tropopause...");
8682
8683 /* Get altitude and pressure profiles... */
8684#pragma omp parallel for default(shared)
8685 for (int iz = 0; iz < met->np; iz++)
8686 z[iz] = Z(met->p[iz]);
8687#pragma omp parallel for default(shared)
8688 for (int iz = 0; iz <= 190; iz++) {
8689 z2[iz] = 4.5 + 0.1 * iz;
8690 p2[iz] = P(z2[iz]);
8691 }
8692
8693 /* Do not calculate tropopause... */
8694 if (ctl->met_tropo == 0)
8695#pragma omp parallel for default(shared) collapse(2)
8696 for (int ix = 0; ix < met->nx; ix++)
8697 for (int iy = 0; iy < met->ny; iy++)
8698 met->pt[ix][iy] = NAN;
8699
8700 /* Use tropopause climatology... */
8701 else if (ctl->met_tropo == 1) {
8702#pragma omp parallel for default(shared) collapse(2)
8703 for (int ix = 0; ix < met->nx; ix++)
8704 for (int iy = 0; iy < met->ny; iy++)
8705 met->pt[ix][iy] = (float) clim_tropo(clim, met->time, met->lat[iy]);
8706 }
8707
8708 /* Use cold point... */
8709 else if (ctl->met_tropo == 2) {
8710
8711 /* Loop over grid points... */
8712#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8713 for (int ix = 0; ix < met->nx; ix++)
8714 for (int iy = 0; iy < met->ny; iy++) {
8715
8716 /* Interpolate temperature profile... */
8717 for (int iz = 0; iz < met->np; iz++)
8718 t[iz] = met->t[ix][iy][iz];
8719 spline(z, t, met->np, z2, t2, 171, ctl->met_tropo_spline);
8720
8721 /* Find minimum... */
8722 int iz = (int) gsl_stats_min_index(t2, 1, 171);
8723 if (iz > 0 && iz < 170)
8724 met->pt[ix][iy] = (float) p2[iz];
8725 else
8726 met->pt[ix][iy] = NAN;
8727 }
8728 }
8729
8730 /* Use WMO definition... */
8731 else if (ctl->met_tropo == 3 || ctl->met_tropo == 4) {
8732
8733 /* Loop over grid points... */
8734#pragma omp parallel for default(shared) private(t,t2) collapse(2)
8735 for (int ix = 0; ix < met->nx; ix++)
8736 for (int iy = 0; iy < met->ny; iy++) {
8737
8738 /* Interpolate temperature profile... */
8739 int iz;
8740 for (iz = 0; iz < met->np; iz++)
8741 t[iz] = met->t[ix][iy][iz];
8742 spline(z, t, met->np, z2, t2, 191, ctl->met_tropo_spline);
8743
8744 /* Find 1st tropopause... */
8745 met->pt[ix][iy] = NAN;
8746 for (iz = 0; iz <= 170; iz++) {
8747 int found = 1;
8748 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8749 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8750 found = 0;
8751 break;
8752 }
8753 if (found) {
8754 if (iz > 0 && iz < 170)
8755 met->pt[ix][iy] = (float) p2[iz];
8756 break;
8757 }
8758 }
8759
8760 /* Find 2nd tropopause... */
8761 if (ctl->met_tropo == 4) {
8762 met->pt[ix][iy] = NAN;
8763 for (; iz <= 170; iz++) {
8764 int found = 1;
8765 for (int iz2 = iz + 1; iz2 <= iz + 10; iz2++)
8766 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) < 3.0) {
8767 found = 0;
8768 break;
8769 }
8770 if (found)
8771 break;
8772 }
8773 for (; iz <= 170; iz++) {
8774 int found = 1;
8775 for (int iz2 = iz + 1; iz2 <= iz + 20; iz2++)
8776 if (LAPSE(p2[iz], t2[iz], p2[iz2], t2[iz2]) > 2.0) {
8777 found = 0;
8778 break;
8779 }
8780 if (found) {
8781 if (iz > 0 && iz < 170)
8782 met->pt[ix][iy] = (float) p2[iz];
8783 break;
8784 }
8785 }
8786 }
8787 }
8788 }
8789
8790 /* Use dynamical tropopause... */
8791 else if (ctl->met_tropo == 5) {
8792
8793 /* Loop over grid points... */
8794#pragma omp parallel for default(shared) private(pv,pv2,th,th2) collapse(2)
8795 for (int ix = 0; ix < met->nx; ix++)
8796 for (int iy = 0; iy < met->ny; iy++) {
8797
8798 /* Interpolate potential vorticity profile... */
8799 for (int iz = 0; iz < met->np; iz++)
8800 pv[iz] = met->pv[ix][iy][iz];
8801 spline(z, pv, met->np, z2, pv2, 171, ctl->met_tropo_spline);
8802
8803 /* Interpolate potential temperature profile... */
8804 for (int iz = 0; iz < met->np; iz++)
8805 th[iz] = THETA(met->p[iz], met->t[ix][iy][iz]);
8806 spline(z, th, met->np, z2, th2, 171, ctl->met_tropo_spline);
8807
8808 /* Find dynamical tropopause... */
8809 met->pt[ix][iy] = NAN;
8810 for (int iz = 0; iz <= 170; iz++)
8811 if (fabs(pv2[iz]) >= ctl->met_tropo_pv
8812 || th2[iz] >= ctl->met_tropo_theta) {
8813 if (iz > 0 && iz < 170)
8814 met->pt[ix][iy] = (float) p2[iz];
8815 break;
8816 }
8817 }
8818 }
8819
8820 else
8821 ERRMSG("Cannot calculate tropopause!");
8822
8823 /* Interpolate temperature, geopotential height, and water vapor... */
8824#pragma omp parallel for default(shared) collapse(2)
8825 for (int ix = 0; ix < met->nx; ix++)
8826 for (int iy = 0; iy < met->ny; iy++) {
8827 double h2ot, tt, zt;
8829 intpol_met_space_3d(met, met->t, met->pt[ix][iy], met->lon[ix],
8830 met->lat[iy], &tt, ci, cw, 1);
8831 intpol_met_space_3d(met, met->z, met->pt[ix][iy], met->lon[ix],
8832 met->lat[iy], &zt, ci, cw, 0);
8833 intpol_met_space_3d(met, met->h2o, met->pt[ix][iy], met->lon[ix],
8834 met->lat[iy], &h2ot, ci, cw, 0);
8835 met->tt[ix][iy] = (float) tt;
8836 met->zt[ix][iy] = (float) zt;
8837 met->h2ot[ix][iy] = (float) h2ot;
8838 }
8839}
8840
8841/*****************************************************************************/
8842
8844 const char *filename,
8845 const ctl_t *ctl,
8846 double *rt,
8847 double *rz,
8848 double *rlon,
8849 double *rlat,
8850 double *robs,
8851 int *nobs) {
8852
8853 /* Write info... */
8854 LOG(1, "Read observation data: %s", filename);
8855
8856 /* Read data... */
8857 if (ctl->obs_type == 0)
8858 read_obs_asc(filename, rt, rz, rlon, rlat, robs, nobs);
8859 else if (ctl->obs_type == 1)
8860 read_obs_nc(filename, rt, rz, rlon, rlat, robs, nobs);
8861 else
8862 ERRMSG("Set OBS_TYPE to 0 or 1!");
8863
8864 /* Check time... */
8865 for (int i = 1; i < *nobs; i++)
8866 if (rt[i] < rt[i - 1])
8867 ERRMSG("Time must be ascending!");
8868
8869 /* Write info... */
8870 int n = *nobs;
8871 double mini, maxi;
8872 LOG(2, "Number of observations: %d", *nobs);
8873 gsl_stats_minmax(&mini, &maxi, rt, 1, (size_t) n);
8874 LOG(2, "Time range: %.2f ... %.2f s", mini, maxi);
8875 gsl_stats_minmax(&mini, &maxi, rz, 1, (size_t) n);
8876 LOG(2, "Altitude range: %g ... %g km", mini, maxi);
8877 gsl_stats_minmax(&mini, &maxi, rlon, 1, (size_t) n);
8878 LOG(2, "Longitude range: %g ... %g deg", mini, maxi);
8879 gsl_stats_minmax(&mini, &maxi, rlat, 1, (size_t) n);
8880 LOG(2, "Latitude range: %g ... %g deg", mini, maxi);
8881 gsl_stats_minmax(&mini, &maxi, robs, 1, (size_t) n);
8882 LOG(2, "Observation range: %g ... %g", mini, maxi);
8883}
8884
8885/*****************************************************************************/
8886
8888 const char *filename,
8889 double *rt,
8890 double *rz,
8891 double *rlon,
8892 double *rlat,
8893 double *robs,
8894 int *nobs) {
8895
8896 /* Open observation data file... */
8897 FILE *in;
8898 if (!(in = fopen(filename, "r")))
8899 ERRMSG("Cannot open file!");
8900
8901 /* Read observations... */
8902 char line[LEN];
8903 while (fgets(line, LEN, in))
8904 if (sscanf(line, "%lg %lg %lg %lg %lg", &rt[*nobs], &rz[*nobs],
8905 &rlon[*nobs], &rlat[*nobs], &robs[*nobs]) == 5)
8906 if ((++(*nobs)) >= NOBS)
8907 ERRMSG("Too many observations!");
8908
8909 /* Close observation data file... */
8910 fclose(in);
8911}
8912
8913/*****************************************************************************/
8914
8916 const char *filename,
8917 double *rt,
8918 double *rz,
8919 double *rlon,
8920 double *rlat,
8921 double *robs,
8922 int *nobs) {
8923
8924 int ncid, varid;
8925
8926 /* Open netCDF file... */
8927 if (nc_open(filename, NC_NOWRITE, &ncid) != NC_NOERR)
8928 ERRMSG("Cannot open file!");
8929
8930 /* Read the observations from the NetCDF file... */
8931 NC_INQ_DIM("nobs", nobs, 1, NOBS);
8932 NC_GET_DOUBLE("time", rt, 1);
8933 NC_GET_DOUBLE("alt", rz, 1);
8934 NC_GET_DOUBLE("lon", rlon, 1);
8935 NC_GET_DOUBLE("lat", rlat, 1);
8936 NC_GET_DOUBLE("obs", robs, 1);
8937
8938 /* Close file... */
8939 NC(nc_close(ncid));
8940}
8941
8942/*****************************************************************************/
8943
8945 const char *filename,
8946 int argc,
8947 char *argv[],
8948 const char *varname,
8949 const int arridx,
8950 const char *defvalue,
8951 char *value) {
8952
8953 FILE *in = NULL;
8954
8955 char fullname1[LEN], fullname2[LEN], rval[LEN];
8956
8957 int contain = 0, i;
8958
8959 /* Open file... */
8960 if (filename[strlen(filename) - 1] != '-')
8961 if (!(in = fopen(filename, "r")))
8962 ERRMSG("Cannot open file!");
8963
8964 /* Set full variable name... */
8965 if (arridx >= 0) {
8966 sprintf(fullname1, "%s[%d]", varname, arridx);
8967 sprintf(fullname2, "%s[*]", varname);
8968 } else {
8969 sprintf(fullname1, "%s", varname);
8970 sprintf(fullname2, "%s", varname);
8971 }
8972
8973 /* Read data... */
8974 if (in != NULL) {
8975 char dummy[LEN], line[LEN], rvarname[LEN];
8976 while (fgets(line, LEN, in)) {
8977 if (sscanf(line, "%4999s %4999s %4999s", rvarname, dummy, rval) == 3)
8978 if (strcasecmp(rvarname, fullname1) == 0 ||
8979 strcasecmp(rvarname, fullname2) == 0) {
8980 contain = 1;
8981 break;
8982 }
8983 }
8984 }
8985 for (i = 1; i < argc - 1; i++)
8986 if (strcasecmp(argv[i], fullname1) == 0 ||
8987 strcasecmp(argv[i], fullname2) == 0) {
8988 sprintf(rval, "%s", argv[i + 1]);
8989 contain = 1;
8990 break;
8991 }
8992
8993 /* Close file... */
8994 if (in != NULL)
8995 fclose(in);
8996
8997 /* Check for missing variables... */
8998 if (!contain) {
8999 if (strlen(defvalue) > 0)
9000 sprintf(rval, "%s", defvalue);
9001 else
9002 ERRMSG("Missing variable %s!\n", fullname1);
9003 }
9004
9005 /* Write info... */
9006 LOG(1, "%s = %s", fullname1, rval);
9007
9008 /* Return values... */
9009 if (value != NULL)
9010 sprintf(value, "%s", rval);
9011 return atof(rval);
9012}
9013
9014/*****************************************************************************/
9015
9016double sedi(
9017 const double p,
9018 const double T,
9019 const double rp,
9020 const double rhop) {
9021
9022 /* Convert particle radius from microns to m... */
9023 const double rp_help = rp * 1e-6;
9024
9025 /* Density of dry air [kg / m^3]... */
9026 const double rho = RHO(p, T);
9027
9028 /* Dynamic viscosity of air [kg / (m s)]... */
9029 const double eta = 1.8325e-5 * (416.16 / (T + 120.)) * pow(T / 296.16, 1.5);
9030
9031 /* Thermal velocity of an air molecule [m / s]... */
9032 const double v = sqrt(8. * KB * T / (M_PI * 4.8096e-26));
9033
9034 /* Mean free path of an air molecule [m]... */
9035 const double lambda = 2. * eta / (rho * v);
9036
9037 /* Knudsen number for air (dimensionless)... */
9038 const double K = lambda / rp_help;
9039
9040 /* Cunningham slip-flow correction (dimensionless)... */
9041 const double G = 1. + K * (1.249 + 0.42 * exp(-0.87 / K));
9042
9043 /* Sedimentation velocity [m / s]... */
9044 return 2. * SQR(rp_help) * (rhop - rho) * G0 / (9. * eta) * G;
9045}
9046
9047/*****************************************************************************/
9048
9050 const double *x,
9051 const double *y,
9052 const int n,
9053 const double *x2,
9054 double *y2,
9055 const int n2,
9056 const int method) {
9057
9058 /* Cubic spline interpolation... */
9059 if (method == 1) {
9060
9061 /* Allocate... */
9062 gsl_interp_accel *acc = gsl_interp_accel_alloc();
9063 gsl_spline *s = gsl_spline_alloc(gsl_interp_cspline, (size_t) n);
9064
9065 /* Interpolate profile... */
9066 gsl_spline_init(s, x, y, (size_t) n);
9067 for (int i = 0; i < n2; i++)
9068 if (x2[i] <= x[0])
9069 y2[i] = y[0];
9070 else if (x2[i] >= x[n - 1])
9071 y2[i] = y[n - 1];
9072 else
9073 y2[i] = gsl_spline_eval(s, x2[i], acc);
9074
9075 /* Free... */
9076 gsl_spline_free(s);
9077 gsl_interp_accel_free(acc);
9078 }
9079
9080 /* Linear interpolation... */
9081 else {
9082 for (int i = 0; i < n2; i++)
9083 if (x2[i] <= x[0])
9084 y2[i] = y[0];
9085 else if (x2[i] >= x[n - 1])
9086 y2[i] = y[n - 1];
9087 else {
9088 int idx = locate_irr(x, n, x2[i]);
9089 y2[i] = LIN(x[idx], y[idx], x[idx + 1], y[idx + 1], x2[i]);
9090 }
9091 }
9092}
9093
9094/*****************************************************************************/
9095
9097 const float *data,
9098 const int n) {
9099
9100 if (n <= 0)
9101 return 0;
9102
9103 float mean = 0, var = 0;
9104
9105 for (int i = 0; i < n; ++i) {
9106 mean += data[i];
9107 var += SQR(data[i]);
9108 }
9109
9110 var = var / (float) n - SQR(mean / (float) n);
9111
9112 return (var > 0 ? sqrtf(var) : 0);
9113}
9114
9115/*****************************************************************************/
9116
9118 const double sec,
9119 const double lon,
9120 const double lat) {
9121
9122 /* Number of days and fraction with respect to 2000-01-01T12:00Z... */
9123 const double D = sec / 86400 - 0.5;
9124
9125 /* Geocentric apparent ecliptic longitude [rad]... */
9126 const double g = DEG2RAD(357.529 + 0.98560028 * D);
9127 const double q = 280.459 + 0.98564736 * D;
9128 const double L = DEG2RAD(q + 1.915 * sin(g) + 0.020 * sin(2 * g));
9129
9130 /* Mean obliquity of the ecliptic [rad]... */
9131 const double e = DEG2RAD(23.439 - 0.00000036 * D);
9132
9133 /* Declination [rad]... */
9134 const double sindec = sin(e) * sin(L);
9135
9136 /* Right ascension [rad]... */
9137 const double ra = atan2(cos(e) * sin(L), cos(L));
9138
9139 /* Greenwich Mean Sidereal Time [h]... */
9140 const double GMST = 18.697374558 + 24.06570982441908 * D;
9141
9142 /* Local Sidereal Time [h]... */
9143 const double LST = GMST + lon / 15;
9144
9145 /* Hour angle [rad]... */
9146 const double h = LST / 12 * M_PI - ra;
9147
9148 /* Convert latitude... */
9149 const double lat_help = DEG2RAD(lat);
9150
9151 /* Return solar zenith angle [rad]... */
9152 return acos(sin(lat_help) * sindec +
9153 cos(lat_help) * sqrt(1 - SQR(sindec)) * cos(h));
9154}
9155
9156/*****************************************************************************/
9157
9159 const int year,
9160 const int mon,
9161 const int day,
9162 const int hour,
9163 const int min,
9164 const int sec,
9165 const double remain,
9166 double *jsec) {
9167
9168 struct tm t0, t1;
9169
9170 t0.tm_year = 100;
9171 t0.tm_mon = 0;
9172 t0.tm_mday = 1;
9173 t0.tm_hour = 0;
9174 t0.tm_min = 0;
9175 t0.tm_sec = 0;
9176
9177 t1.tm_year = year - 1900;
9178 t1.tm_mon = mon - 1;
9179 t1.tm_mday = day;
9180 t1.tm_hour = hour;
9181 t1.tm_min = min;
9182 t1.tm_sec = sec;
9183
9184 *jsec = (double) timegm(&t1) - (double) timegm(&t0) + remain;
9185}
9186
9187/*****************************************************************************/
9188
9190 const char *name,
9191 const char *group,
9192 const int output) {
9193
9194 static char names[NTIMER][100], groups[NTIMER][100];
9195
9196 static double rt_name[NTIMER], rt_group[NTIMER],
9197 rt_min[NTIMER], rt_max[NTIMER], dt, t0, t1;
9198
9199 static int iname = -1, igroup = -1, nname, ngroup, ct_name[NTIMER];
9200
9201 /* Get time... */
9202 t1 = omp_get_wtime();
9203 dt = t1 - t0;
9204
9205 /* Add elapsed time to current timers... */
9206 if (iname >= 0) {
9207 rt_name[iname] += dt;
9208 rt_min[iname] = (ct_name[iname] <= 0 ? dt : MIN(rt_min[iname], dt));
9209 rt_max[iname] = (ct_name[iname] <= 0 ? dt : MAX(rt_max[iname], dt));
9210 ct_name[iname]++;
9211 }
9212 if (igroup >= 0)
9213 rt_group[igroup] += t1 - t0;
9214
9215 /* Report timers... */
9216 if (output) {
9217 for (int i = 0; i < nname; i++)
9218 LOG(1, "TIMER_%s = %.3f s (min= %g s, mean= %g s,"
9219 " max= %g s, n= %d)", names[i], rt_name[i], rt_min[i],
9220 rt_name[i] / ct_name[i], rt_max[i], ct_name[i]);
9221 for (int i = 0; i < ngroup; i++)
9222 LOG(1, "TIMER_GROUP_%s = %.3f s", groups[i], rt_group[i]);
9223 double total = 0.0;
9224 for (int i = 0; i < nname; i++)
9225 total += rt_name[i];
9226 LOG(1, "TIMER_TOTAL = %.3f s", total);
9227 }
9228
9229 /* Identify IDs of next timer... */
9230 for (iname = 0; iname < nname; iname++)
9231 if (strcasecmp(name, names[iname]) == 0)
9232 break;
9233 for (igroup = 0; igroup < ngroup; igroup++)
9234 if (strcasecmp(group, groups[igroup]) == 0)
9235 break;
9236
9237 /* Check whether this is a new timer... */
9238 if (iname >= nname) {
9239 sprintf(names[iname], "%s", name);
9240 if ((++nname) >= NTIMER)
9241 ERRMSG("Too many timers!");
9242 }
9243
9244 /* Check whether this is a new group... */
9245 if (igroup >= ngroup) {
9246 sprintf(groups[igroup], "%s", group);
9247 if ((++ngroup) >= NTIMER)
9248 ERRMSG("Too many groups!");
9249 }
9250
9251 /* Save starting time... */
9252 t0 = t1;
9253}
9254
9255/*****************************************************************************/
9256
9258 const char *filename,
9259 const int offset) {
9260
9261 char tstr[10];
9262
9263 double t;
9264
9265 /* Get time from filename... */
9266 int len = (int) strlen(filename);
9267 sprintf(tstr, "%.4s", &filename[len - offset]);
9268 int year = atoi(tstr);
9269 sprintf(tstr, "%.2s", &filename[len - offset + 5]);
9270 int mon = atoi(tstr);
9271 sprintf(tstr, "%.2s", &filename[len - offset + 8]);
9272 int day = atoi(tstr);
9273 sprintf(tstr, "%.2s", &filename[len - offset + 11]);
9274 int hour = atoi(tstr);
9275 sprintf(tstr, "%.2s", &filename[len - offset + 14]);
9276 int min = atoi(tstr);
9277
9278 /* Check time... */
9279 if (year < 1900 || year > 2100 || mon < 1 || mon > 12 || day < 1
9280 || day > 31 || hour < 0 || hour > 23 || min < 0 || min > 59)
9281 ERRMSG("Cannot read time from filename!");
9282
9283 /* Convert time to Julian seconds... */
9284 time2jsec(year, mon, day, hour, min, 0, 0.0, &t);
9285
9286 /* Return time... */
9287 return t;
9288}
9289
9290/*****************************************************************************/
9291
9293 const clim_t *clim,
9294 const atm_t *atm,
9295 const int ip) {
9296
9297 /* Get tropopause pressure... */
9298 const double pt = clim_tropo(clim, atm->time[ip], atm->lat[ip]);
9299
9300 /* Get pressure range... */
9301 const double p1 = pt * 0.866877899;
9302 const double p0 = pt / 0.866877899;
9303
9304 /* Get weighting factor... */
9305 if (atm->p[ip] > p0)
9306 return 1;
9307 else if (atm->p[ip] < p1)
9308 return 0;
9309 else
9310 return LIN(p0, 1.0, p1, 0.0, atm->p[ip]);
9311}
9312
9313/*****************************************************************************/
9314
9316 const char *filename,
9317 const ctl_t *ctl,
9318 const atm_t *atm,
9319 const double t) {
9320
9321 FILE *out;
9322
9323 /* Set time interval for output... */
9324 const double t0 = t - 0.5 * ctl->dt_mod;
9325 const double t1 = t + 0.5 * ctl->dt_mod;
9326
9327 /* Check if gnuplot output is requested... */
9328 if (ctl->atm_gpfile[0] != '-') {
9329
9330 /* Create gnuplot pipe... */
9331 if (!(out = popen("gnuplot", "w")))
9332 ERRMSG("Cannot create pipe to gnuplot!");
9333
9334 /* Set plot filename... */
9335 fprintf(out, "set out \"%s.png\"\n", filename);
9336
9337 /* Set time string... */
9338 double r;
9339 int year, mon, day, hour, min, sec;
9340 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9341 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
9342 year, mon, day, hour, min);
9343
9344 /* Dump gnuplot file to pipe... */
9345 FILE *in;
9346 if (!(in = fopen(ctl->atm_gpfile, "r")))
9347 ERRMSG("Cannot open file!");
9348 char line[LEN];
9349 while (fgets(line, LEN, in))
9350 fprintf(out, "%s", line);
9351 fclose(in);
9352 }
9353
9354 else {
9355
9356 /* Create file... */
9357 if (!(out = fopen(filename, "w")))
9358 ERRMSG("Cannot create file!");
9359 }
9360
9361 /* Write header... */
9362 fprintf(out,
9363 "# $1 = time [s]\n"
9364 "# $2 = altitude [km]\n"
9365 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
9366 for (int iq = 0; iq < ctl->nq; iq++)
9367 fprintf(out, "# $%i = %s [%s]\n", iq + 5, ctl->qnt_name[iq],
9368 ctl->qnt_unit[iq]);
9369 fprintf(out, "\n");
9370
9371 /* Write data... */
9372 for (int ip = 0; ip < atm->np; ip += ctl->atm_stride) {
9373
9374 /* Check time... */
9375 if (ctl->atm_filter == 2 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9376 continue;
9377
9378 /* Write output... */
9379 fprintf(out, "%.2f %g %g %g", atm->time[ip], Z(atm->p[ip]),
9380 atm->lon[ip], atm->lat[ip]);
9381 for (int iq = 0; iq < ctl->nq; iq++) {
9382 fprintf(out, " ");
9383 if (ctl->atm_filter == 1 && (atm->time[ip] < t0 || atm->time[ip] > t1))
9384 fprintf(out, ctl->qnt_format[iq], NAN);
9385 else
9386 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
9387 }
9388 fprintf(out, "\n");
9389 }
9390
9391 /* Close file... */
9392 fclose(out);
9393}
9394
9395/*****************************************************************************/
9396
9398 const char *filename,
9399 const ctl_t *ctl,
9400 const atm_t *atm) {
9401
9402 FILE *out;
9403
9404 /* Create file... */
9405 if (!(out = fopen(filename, "w")))
9406 ERRMSG("Cannot create file!");
9407
9408 /* Write version of binary data... */
9409 int version = 100;
9410 FWRITE(&version, int,
9411 1,
9412 out);
9413
9414 /* Write data... */
9415 FWRITE(&atm->np, int,
9416 1,
9417 out);
9418 FWRITE(atm->time, double,
9419 (size_t) atm->np,
9420 out);
9421 FWRITE(atm->p, double,
9422 (size_t) atm->np,
9423 out);
9424 FWRITE(atm->lon, double,
9425 (size_t) atm->np,
9426 out);
9427 FWRITE(atm->lat, double,
9428 (size_t) atm->np,
9429 out);
9430 for (int iq = 0; iq < ctl->nq; iq++)
9431 FWRITE(atm->q[iq], double,
9432 (size_t) atm->np,
9433 out);
9434
9435 /* Write final flag... */
9436 int final = 999;
9437 FWRITE(&final, int,
9438 1,
9439 out);
9440
9441 /* Close file... */
9442 fclose(out);
9443}
9444
9445/*****************************************************************************/
9446
9448 const char *filename,
9449 const ctl_t *ctl,
9450 const atm_t *atm) {
9451
9452 int tid, pid, ncid, varid;
9453 size_t start[2], count[2];
9454
9455 /* Create file... */
9456 nc_create(filename, NC_NETCDF4, &ncid);
9457
9458 /* Define dimensions... */
9459 NC(nc_def_dim(ncid, "time", 1, &tid));
9460 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9461
9462 /* Define variables and their attributes... */
9463 int dim_ids[2] = { tid, pid };
9464 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9465 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9466 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9467 ctl->atm_nc_level, 0);
9468 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9469 ctl->atm_nc_level, 0);
9470 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9471 ctl->atm_nc_level, 0);
9472 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9473 for (int iq = 0; iq < ctl->nq; iq++)
9474 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9475 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9476 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9477
9478 /* Define global attributes... */
9479 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9480 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9481
9482 /* End definitions... */
9483 NC(nc_enddef(ncid));
9484
9485 /* Write data... */
9486 NC_PUT_DOUBLE("time", atm->time, 0);
9487 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9488 NC_PUT_DOUBLE("LON", atm->lon, 0);
9489 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9490 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9491 for (int iq = 0; iq < ctl->nq; iq++)
9492 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9493
9494 /* Close file... */
9495 NC(nc_close(ncid));
9496}
9497
9498/*****************************************************************************/
9499
9501 const char *dirname,
9502 const ctl_t *ctl,
9503 const atm_t *atm,
9504 const double t) {
9505
9506 /* Global Counter... */
9507 static size_t out_cnt = 0;
9508
9509 double r, r_start, r_stop;
9510 int year, mon, day, hour, min, sec;
9511 int year_start, mon_start, day_start, hour_start, min_start, sec_start;
9512 int year_stop, mon_stop, day_stop, hour_stop, min_stop, sec_stop;
9513 char filename_out[2 * LEN] = "traj_fix_3d_YYYYMMDDHH_YYYYMMDDHH.nc";
9514
9515 int ncid, varid, tid, pid, cid;
9516 int dim_ids[2];
9517
9518 /* time, nparc */
9519 size_t start[2];
9520 size_t count[2];
9521
9522 /* Determine start and stop times of calculation... */
9523 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
9524 jsec2time(ctl->t_start, &year_start, &mon_start, &day_start, &hour_start,
9525 &min_start, &sec_start, &r_start);
9526 jsec2time(ctl->t_stop, &year_stop, &mon_stop, &day_stop, &hour_stop,
9527 &min_stop, &sec_stop, &r_stop);
9528
9529 sprintf(filename_out, "%s/traj_fix_3d_%02d%02d%02d%02d_%02d%02d%02d%02d.nc",
9530 dirname,
9531 year_start % 100, mon_start, day_start, hour_start,
9532 year_stop % 100, mon_stop, day_stop, hour_stop);
9533 LOG(1, "Write traj file: %s", filename_out);
9534
9535 /* Define hyperslap for the traj_file... */
9536 start[0] = out_cnt;
9537 start[1] = 0;
9538 count[0] = 1;
9539 count[1] = (size_t) atm->np;
9540
9541 /* Create the file at the first timestep... */
9542 if (out_cnt == 0) {
9543
9544 /* Create file... */
9545 nc_create(filename_out, NC_NETCDF4, &ncid);
9546
9547 /* Define dimensions... */
9548 NC(nc_def_dim(ncid, "time", NC_UNLIMITED, &tid));
9549 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9550 NC(nc_def_dim(ncid, "TMDT", 7, &cid));
9551 dim_ids[0] = tid;
9552 dim_ids[1] = pid;
9553
9554 /* Define variables and their attributes... */
9555 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9556 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9557 NC_DEF_VAR("LAT", NC_DOUBLE, 2, dim_ids, "Latitude", "deg",
9558 ctl->atm_nc_level, 0);
9559 NC_DEF_VAR("LON", NC_DOUBLE, 2, dim_ids, "Longitude", "deg",
9560 ctl->atm_nc_level, 0);
9561 NC_DEF_VAR("PRESS", NC_DOUBLE, 2, dim_ids, "Pressure", "hPa",
9562 ctl->atm_nc_level, 0);
9563 NC_DEF_VAR("ZETA", NC_DOUBLE, 2, dim_ids, "Zeta", "K",
9564 ctl->atm_nc_level, 0);
9565 for (int iq = 0; iq < ctl->nq; iq++)
9566 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9567 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9568 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9569
9570 /* Define global attributes... */
9571 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9572 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9573
9574 /* End definitions... */
9575 NC(nc_enddef(ncid));
9576 NC(nc_close(ncid));
9577 }
9578
9579 /* Increment global counter to change hyperslap... */
9580 out_cnt++;
9581
9582 /* Open file... */
9583 NC(nc_open(filename_out, NC_WRITE, &ncid));
9584
9585 /* Write data... */
9586 NC_PUT_DOUBLE("time", atm->time, 1);
9587 NC_PUT_DOUBLE("LAT", atm->lat, 1);
9588 NC_PUT_DOUBLE("LON", atm->lon, 1);
9589 NC_PUT_DOUBLE("PRESS", atm->p, 1);
9590 if (ctl->advect_vert_coord == 1) {
9591 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta], 1);
9592 } else if (ctl->qnt_zeta >= 0) {
9593 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 1);
9594 }
9595 for (int iq = 0; iq < ctl->nq; iq++)
9596 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 1);
9597
9598 /* Close file... */
9599 NC(nc_close(ncid));
9600
9601 /* At the last time step create the init_fix_YYYYMMDDHH file... */
9602 if ((year == year_stop) && (mon == mon_stop)
9603 && (day == day_stop) && (hour == hour_stop)) {
9604
9605 /* Set filename... */
9606 char filename_init[2 * LEN] = "./init_fix_YYYYMMDDHH.nc";
9607 sprintf(filename_init, "%s/init_fix_%02d%02d%02d%02d.nc",
9608 dirname, year_stop % 100, mon_stop, day_stop, hour_stop);
9609 LOG(1, "Write init file: %s", filename_init);
9610
9611 /* Create file... */
9612 nc_create(filename_init, NC_NETCDF4, &ncid);
9613
9614 /* Define dimensions... */
9615 NC(nc_def_dim(ncid, "time", 1, &tid));
9616 NC(nc_def_dim(ncid, "NPARTS", (size_t) atm->np, &pid));
9617 dim_ids[0] = tid;
9618 dim_ids[1] = pid;
9619
9620 /* Define variables and their attributes... */
9621 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "Time",
9622 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9623 NC_DEF_VAR("LAT", NC_DOUBLE, 1, &pid, "Latitude", "deg",
9624 ctl->atm_nc_level, 0);
9625 NC_DEF_VAR("LON", NC_DOUBLE, 1, &pid, "Longitude", "deg",
9626 ctl->atm_nc_level, 0);
9627 NC_DEF_VAR("PRESS", NC_DOUBLE, 1, &pid, "Pressure", "hPa",
9628 ctl->atm_nc_level, 0);
9629 NC_DEF_VAR("ZETA", NC_DOUBLE, 1, &pid, "Zeta", "K", ctl->atm_nc_level, 0);
9630 for (int iq = 0; iq < ctl->nq; iq++)
9631 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 2, dim_ids,
9632 ctl->qnt_name[iq], ctl->qnt_unit[iq],
9633 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9634
9635 /* Define global attributes... */
9636 NC_PUT_ATT_GLOBAL("exp_VERTCOOR_name", "zeta");
9637 NC_PUT_ATT_GLOBAL("model", "MPTRAC");
9638
9639 /* End definitions... */
9640 NC(nc_enddef(ncid));
9641
9642 /* Write data... */
9643 NC_PUT_DOUBLE("time", atm->time, 0);
9644 NC_PUT_DOUBLE("LAT", atm->lat, 0);
9645 NC_PUT_DOUBLE("LON", atm->lon, 0);
9646 NC_PUT_DOUBLE("PRESS", atm->p, 0);
9647 NC_PUT_DOUBLE("ZETA", atm->q[ctl->qnt_zeta_d], 0);
9648 for (int iq = 0; iq < ctl->nq; iq++)
9649 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9650
9651 /* Close file... */
9652 NC(nc_close(ncid));
9653 }
9654}
9655
9656/*****************************************************************************/
9657
9659 const char *filename,
9660 const ctl_t *ctl,
9661 const atm_t *atm) {
9662
9663 int ncid, obsid, varid;
9664
9665 size_t start[2], count[2];
9666
9667 /* Create file... */
9668 NC(nc_create(filename, NC_NETCDF4, &ncid));
9669
9670 /* Define dimensions... */
9671 NC(nc_def_dim(ncid, "obs", (size_t) atm->np, &obsid));
9672
9673 /* Define variables and their attributes... */
9674 NC_DEF_VAR("time", NC_DOUBLE, 1, &obsid, "time",
9675 "seconds since 2000-01-01 00:00:00 UTC", ctl->atm_nc_level, 0);
9676 NC_DEF_VAR("press", NC_DOUBLE, 1, &obsid, "pressure", "hPa",
9677 ctl->atm_nc_level, 0);
9678 NC_DEF_VAR("lon", NC_DOUBLE, 1, &obsid, "longitude", "degrees_east",
9679 ctl->atm_nc_level, 0);
9680 NC_DEF_VAR("lat", NC_DOUBLE, 1, &obsid, "latitude", "degrees_north",
9681 ctl->atm_nc_level, 0);
9682 for (int iq = 0; iq < ctl->nq; iq++)
9683 NC_DEF_VAR(ctl->qnt_name[iq], NC_DOUBLE, 1, &obsid,
9684 ctl->qnt_longname[iq], ctl->qnt_unit[iq],
9685 ctl->atm_nc_level, ctl->atm_nc_quant[iq]);
9686
9687 /* Define global attributes... */
9688 NC_PUT_ATT_GLOBAL("featureType", "point");
9689
9690 /* End definitions... */
9691 NC(nc_enddef(ncid));
9692
9693 /* Write data... */
9694 NC_PUT_DOUBLE("time", atm->time, 0);
9695 NC_PUT_DOUBLE("press", atm->p, 0);
9696 NC_PUT_DOUBLE("lon", atm->lon, 0);
9697 NC_PUT_DOUBLE("lat", atm->lat, 0);
9698 for (int iq = 0; iq < ctl->nq; iq++)
9699 NC_PUT_DOUBLE(ctl->qnt_name[iq], atm->q[iq], 0);
9700
9701 /* Close file... */
9702 NC(nc_close(ncid));
9703}
9704
9705/*****************************************************************************/
9706
9708 const char *filename,
9709 const ctl_t *ctl,
9710 const atm_t *atm,
9711 const double t) {
9712
9713 static FILE *out;
9714
9715 static double *modmean, *obsmean, *obsstd, *rt, *rz, *rlon, *rlat, *robs,
9716 *area, dlon, dlat, dz, x[NCSI], y[NCSI], obsstdn[NCSI], kz[EP], kw[EP];
9717
9718 static int *obscount, ct, cx, cy, cz, ip, ix, iy, iz, n, nobs, nk;
9719
9720 /* Set timer... */
9721 SELECT_TIMER("WRITE_CSI", "OUTPUT", NVTX_WRITE);
9722
9723 /* Init... */
9724 if (t == ctl->t_start) {
9725
9726 /* Check quantity index for mass... */
9727 if (ctl->qnt_m < 0)
9728 ERRMSG("Need quantity mass!");
9729
9730 /* Allocate... */
9731 ALLOC(area, double,
9732 ctl->csi_ny);
9733 ALLOC(rt, double,
9734 NOBS);
9735 ALLOC(rz, double,
9736 NOBS);
9737 ALLOC(rlon, double,
9738 NOBS);
9739 ALLOC(rlat, double,
9740 NOBS);
9741 ALLOC(robs, double,
9742 NOBS);
9743
9744 /* Read observation data... */
9745 read_obs(ctl->csi_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
9746
9747 /* Read kernel data... */
9748 if (ctl->csi_kernel[0] != '-')
9749 read_kernel(ctl->csi_kernel, kz, kw, &nk);
9750
9751 /* Create new file... */
9752 LOG(1, "Write CSI data: %s", filename);
9753 if (!(out = fopen(filename, "w")))
9754 ERRMSG("Cannot create file!");
9755
9756 /* Write header... */
9757 fprintf(out,
9758 "# $1 = time [s]\n"
9759 "# $2 = number of hits (cx)\n"
9760 "# $3 = number of misses (cy)\n"
9761 "# $4 = number of false alarms (cz)\n"
9762 "# $5 = number of observations (cx + cy)\n"
9763 "# $6 = number of forecasts (cx + cz)\n"
9764 "# $7 = bias (ratio of forecasts and observations) [%%]\n"
9765 "# $8 = probability of detection (POD) [%%]\n"
9766 "# $9 = false alarm rate (FAR) [%%]\n"
9767 "# $10 = critical success index (CSI) [%%]\n");
9768 fprintf(out,
9769 "# $11 = hits associated with random chance\n"
9770 "# $12 = equitable threat score (ETS) [%%]\n"
9771 "# $13 = Pearson linear correlation coefficient\n"
9772 "# $14 = Spearman rank-order correlation coefficient\n"
9773 "# $15 = column density mean error (F - O) [kg/m^2]\n"
9774 "# $16 = column density root mean square error (RMSE) [kg/m^2]\n"
9775 "# $17 = column density mean absolute error [kg/m^2]\n"
9776 "# $18 = log-likelihood function\n"
9777 "# $19 = number of data points\n\n");
9778
9779 /* Set grid box size... */
9780 dz = (ctl->csi_z1 - ctl->csi_z0) / ctl->csi_nz;
9781 dlon = (ctl->csi_lon1 - ctl->csi_lon0) / ctl->csi_nx;
9782 dlat = (ctl->csi_lat1 - ctl->csi_lat0) / ctl->csi_ny;
9783
9784 /* Set horizontal coordinates... */
9785 for (iy = 0; iy < ctl->csi_ny; iy++) {
9786 const double lat = ctl->csi_lat0 + dlat * (iy + 0.5);
9787 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat));
9788 }
9789 }
9790
9791 /* Set time interval... */
9792 const double t0 = t - 0.5 * ctl->dt_mod;
9793 const double t1 = t + 0.5 * ctl->dt_mod;
9794
9795 /* Allocate... */
9796 ALLOC(modmean, double,
9797 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9798 ALLOC(obsmean, double,
9799 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9800 ALLOC(obscount, int,
9801 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9802 ALLOC(obsstd, double,
9803 ctl->csi_nx * ctl->csi_ny * ctl->csi_nz);
9804
9805 /* Loop over observations... */
9806 for (int i = 0; i < nobs; i++) {
9807
9808 /* Check time... */
9809 if (rt[i] < t0)
9810 continue;
9811 else if (rt[i] >= t1)
9812 break;
9813
9814 /* Check observation data... */
9815 if (!isfinite(robs[i]))
9816 continue;
9817
9818 /* Calculate indices... */
9819 ix = (int) ((rlon[i] - ctl->csi_lon0) / dlon);
9820 iy = (int) ((rlat[i] - ctl->csi_lat0) / dlat);
9821 iz = (int) ((rz[i] - ctl->csi_z0) / dz);
9822
9823 /* Check indices... */
9824 if (ix < 0 || ix >= ctl->csi_nx ||
9825 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9826 continue;
9827
9828 /* Get mean observation index... */
9829 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9830 obsmean[idx] += robs[i];
9831 obsstd[idx] += SQR(robs[i]);
9832 obscount[idx]++;
9833 }
9834
9835 /* Analyze model data... */
9836 for (ip = 0; ip < atm->np; ip++) {
9837
9838 /* Check time... */
9839 if (atm->time[ip] < t0 || atm->time[ip] > t1)
9840 continue;
9841
9842 /* Get indices... */
9843 ix = (int) ((atm->lon[ip] - ctl->csi_lon0) / dlon);
9844 iy = (int) ((atm->lat[ip] - ctl->csi_lat0) / dlat);
9845 iz = (int) ((Z(atm->p[ip]) - ctl->csi_z0) / dz);
9846
9847 /* Check indices... */
9848 if (ix < 0 || ix >= ctl->csi_nx ||
9849 iy < 0 || iy >= ctl->csi_ny || iz < 0 || iz >= ctl->csi_nz)
9850 continue;
9851
9852 /* Get total mass in grid cell... */
9853 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9854 modmean[idx] += kernel_weight(kz, kw, nk, atm->p[ip])
9855 * atm->q[ctl->qnt_m][ip];
9856 }
9857
9858 /* Analyze all grid cells... */
9859 for (ix = 0; ix < ctl->csi_nx; ix++)
9860 for (iy = 0; iy < ctl->csi_ny; iy++)
9861 for (iz = 0; iz < ctl->csi_nz; iz++) {
9862
9863 /* Calculate mean observation index... */
9864 int idx = ARRAY_3D(ix, iy, ctl->csi_ny, iz, ctl->csi_nz);
9865 if (obscount[idx] > 0) {
9866 obsmean[idx] /= obscount[idx];
9867 obsstd[idx] -= SQR(obsmean[idx]);
9868 obsstd[idx] = sqrt(obsstd[idx]);
9869 }
9870
9871 /* Calculate column density... */
9872 if (modmean[idx] > 0)
9873 modmean[idx] /= (1e6 * area[iy]);
9874
9875 /* Calculate CSI... */
9876 if (obscount[idx] > 0) {
9877 ct++;
9878 if (obsmean[idx] >= ctl->csi_obsmin &&
9879 modmean[idx] >= ctl->csi_modmin)
9880 cx++;
9881 else if (obsmean[idx] >= ctl->csi_obsmin &&
9882 modmean[idx] < ctl->csi_modmin)
9883 cy++;
9884 else if (obsmean[idx] < ctl->csi_obsmin &&
9885 modmean[idx] >= ctl->csi_modmin)
9886 cz++;
9887 }
9888
9889 /* Save data for other verification statistics... */
9890 if (obscount[idx] > 0
9891 && (obsmean[idx] >= ctl->csi_obsmin
9892 || modmean[idx] >= ctl->csi_modmin)) {
9893 x[n] = modmean[idx];
9894 y[n] = obsmean[idx];
9895 if (modmean[idx] >= ctl->csi_modmin)
9896 obsstdn[n] = obsstd[idx];
9897 if ((++n) >= NCSI)
9898 ERRMSG("Too many data points to calculate statistics!");
9899 }
9900 }
9901
9902 /* Write output... */
9903 if (fmod(t, ctl->csi_dt_out) == 0) {
9904
9905 /* Calculate verification statistics
9906 (https://www.cawcr.gov.au/projects/verification/) ... */
9907 static double work[2 * NCSI], work2[2 * NCSI];;
9908 const int n_obs = cx + cy;
9909 const int n_for = cx + cz;
9910 const double bias = (n_obs > 0) ? 100. * n_for / n_obs : NAN;
9911 const double pod = (n_obs > 0) ? (100. * cx) / n_obs : NAN;
9912 const double far = (n_for > 0) ? (100. * cz) / n_for : NAN;
9913 const double csi =
9914 (cx + cy + cz > 0) ? (100. * cx) / (cx + cy + cz) : NAN;
9915 const double cx_rd = (ct > 0) ? (1. * n_obs * n_for) / ct : NAN;
9916 const double ets = (cx + cy + cz - cx_rd > 0) ?
9917 (100. * (cx - cx_rd)) / (cx + cy + cz - cx_rd) : NAN;
9918 const double rho_p =
9919 (n > 0) ? gsl_stats_correlation(x, 1, y, 1, (size_t) n) : NAN;
9920 const double rho_s =
9921 (n > 0) ? gsl_stats_spearman(x, 1, y, 1, (size_t) n, work) : NAN;
9922 for (int i = 0; i < n; i++) {
9923 work[i] = x[i] - y[i];
9924 work2[i] = (obsstdn[i] != 0) ? (x[i] - y[i]) / obsstdn[i] : 0;
9925 }
9926 const double mean = (n > 0) ? gsl_stats_mean(work, 1, (size_t) n) : NAN;
9927 const double rmse =
9928 (n > 0) ? gsl_stats_sd_with_fixed_mean(work, 1, (size_t) n,
9929 0.0) : NAN;
9930 const double absdev =
9931 (n > 0) ? gsl_stats_absdev_m(work, 1, (size_t) n, 0.0) : NAN;
9932 const double loglikelihood =
9933 (n > 0) ? gsl_stats_tss(work2, 1, (size_t) n) * (-0.5) : GSL_NAN;
9934
9935 /* Write... */
9936 fprintf(out,
9937 "%.2f %d %d %d %d %d %g %g %g %g %g %g %g %g %g %g %g %g %d\n", t,
9938 cx, cy, cz, n_obs, n_for, bias, pod, far, csi, cx_rd, ets, rho_p,
9939 rho_s, mean, rmse, absdev, loglikelihood, n);
9940
9941 /* Set counters to zero... */
9942 n = ct = cx = cy = cz = 0;
9943 }
9944
9945 /* Free... */
9946 free(modmean);
9947 free(obsmean);
9948 free(obscount);
9949 free(obsstd);
9950
9951 /* Finalize... */
9952 if (t == ctl->t_stop) {
9953
9954 /* Close output file... */
9955 fclose(out);
9956
9957 /* Free... */
9958 free(area);
9959 free(rt);
9960 free(rz);
9961 free(rlon);
9962 free(rlat);
9963 free(robs);
9964 }
9965}
9966
9967/*****************************************************************************/
9968
9970 const char *filename,
9971 const ctl_t *ctl,
9972 const atm_t *atm,
9973 const double t) {
9974
9975 static FILE *out;
9976
9977 static double dummy, lat, lon, qm[NQ][NENS], qs[NQ][NENS], xm[NENS][3],
9978 x[3], zm[NENS];
9979
9980 static int n[NENS];
9981
9982 /* Set timer... */
9983 SELECT_TIMER("WRITE_ENS", "OUTPUT", NVTX_WRITE);
9984
9985 /* Check quantities... */
9986 if (ctl->qnt_ens < 0)
9987 ERRMSG("Missing ensemble IDs!");
9988
9989 /* Set time interval... */
9990 const double t0 = t - 0.5 * ctl->dt_mod;
9991 const double t1 = t + 0.5 * ctl->dt_mod;
9992
9993 /* Init... */
9994 for (int i = 0; i < NENS; i++) {
9995 for (int iq = 0; iq < ctl->nq; iq++)
9996 qm[iq][i] = qs[iq][i] = 0;
9997 xm[i][0] = xm[i][1] = xm[i][2] = zm[i] = 0;
9998 n[i] = 0;
9999 }
10000
10001 /* Loop over air parcels... */
10002 for (int ip = 0; ip < atm->np; ip++) {
10003
10004 /* Check time... */
10005 if (atm->time[ip] < t0 || atm->time[ip] > t1)
10006 continue;
10007
10008 /* Check ensemble ID... */
10009 if (atm->q[ctl->qnt_ens][ip] < 0 || atm->q[ctl->qnt_ens][ip] >= NENS)
10010 ERRMSG("Ensemble ID is out of range!");
10011
10012 /* Get means... */
10013 geo2cart(0, atm->lon[ip], atm->lat[ip], x);
10014 for (int iq = 0; iq < ctl->nq; iq++) {
10015 qm[iq][ctl->qnt_ens] += atm->q[iq][ip];
10016 qs[iq][ctl->qnt_ens] += SQR(atm->q[iq][ip]);
10017 }
10018 xm[ctl->qnt_ens][0] += x[0];
10019 xm[ctl->qnt_ens][1] += x[1];
10020 xm[ctl->qnt_ens][2] += x[2];
10021 zm[ctl->qnt_ens] += Z(atm->p[ip]);
10022 n[ctl->qnt_ens]++;
10023 }
10024
10025 /* Create file... */
10026 LOG(1, "Write ensemble data: %s", filename);
10027 if (!(out = fopen(filename, "w")))
10028 ERRMSG("Cannot create file!");
10029
10030 /* Write header... */
10031 fprintf(out,
10032 "# $1 = time [s]\n"
10033 "# $2 = altitude [km]\n"
10034 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
10035 for (int iq = 0; iq < ctl->nq; iq++)
10036 fprintf(out, "# $%d = %s (mean) [%s]\n", 5 + iq,
10037 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10038 for (int iq = 0; iq < ctl->nq; iq++)
10039 fprintf(out, "# $%d = %s (sigma) [%s]\n", 5 + ctl->nq + iq,
10040 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10041 fprintf(out, "# $%d = number of members\n\n", 5 + 2 * ctl->nq);
10042
10043 /* Write data... */
10044 for (int i = 0; i < NENS; i++)
10045 if (n[i] > 0) {
10046 cart2geo(xm[i], &dummy, &lon, &lat);
10047 fprintf(out, "%.2f %g %g %g", t, zm[i] / n[i], lon, lat);
10048 for (int iq = 0; iq < ctl->nq; iq++) {
10049 fprintf(out, " ");
10050 fprintf(out, ctl->qnt_format[iq], qm[iq][i] / n[i]);
10051 }
10052 for (int iq = 0; iq < ctl->nq; iq++) {
10053 fprintf(out, " ");
10054 double var = qs[iq][i] / n[i] - SQR(qm[iq][i] / n[i]);
10055 fprintf(out, ctl->qnt_format[iq], (var > 0 ? sqrt(var) : 0));
10056 }
10057 fprintf(out, " %d\n", n[i]);
10058 }
10059
10060 /* Close file... */
10061 fclose(out);
10062}
10063
10064/*****************************************************************************/
10065
10067 const char *filename,
10068 const ctl_t *ctl,
10069 met_t *met0,
10070 met_t *met1,
10071 const atm_t *atm,
10072 const double t) {
10073
10074 static double kz[EP], kw[EP];
10075
10076 static int nk;
10077
10078 double *cd, *mean[NQ], *sigma[NQ], *vmr_impl, *z, *lon, *lat, *area, *press;
10079
10080 int *ixs, *iys, *izs, *np;
10081
10082 /* Set timer... */
10083 SELECT_TIMER("WRITE_GRID", "OUTPUT", NVTX_WRITE);
10084
10085 /* Write info... */
10086 LOG(1, "Write grid data: %s", filename);
10087
10088 /* Init... */
10089 if (t == ctl->t_start) {
10090
10091 /* Read kernel data... */
10092 if (ctl->grid_kernel[0] != '-')
10093 read_kernel(ctl->grid_kernel, kz, kw, &nk);
10094 }
10095
10096 /* Allocate... */
10097 ALLOC(cd, double,
10098 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10099 for (int iq = 0; iq < ctl->nq; iq++) {
10100 ALLOC(mean[iq], double,
10101 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10102 ALLOC(sigma[iq], double,
10103 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10104 }
10105 ALLOC(vmr_impl, double,
10106 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10107 ALLOC(z, double,
10108 ctl->grid_nz);
10109 ALLOC(lon, double,
10110 ctl->grid_nx);
10111 ALLOC(lat, double,
10112 ctl->grid_ny);
10113 ALLOC(area, double,
10114 ctl->grid_ny);
10115 ALLOC(press, double,
10116 ctl->grid_nz);
10117 ALLOC(np, int,
10118 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10119 ALLOC(ixs, int,
10120 atm->np);
10121 ALLOC(iys, int,
10122 atm->np);
10123 ALLOC(izs, int,
10124 atm->np);
10125
10126 /* Set grid box size... */
10127 const double dz = (ctl->grid_z1 - ctl->grid_z0) / ctl->grid_nz;
10128 const double dlon = (ctl->grid_lon1 - ctl->grid_lon0) / ctl->grid_nx;
10129 const double dlat = (ctl->grid_lat1 - ctl->grid_lat0) / ctl->grid_ny;
10130
10131 /* Set vertical coordinates... */
10132#pragma omp parallel for default(shared)
10133 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10134 z[iz] = ctl->grid_z0 + dz * (iz + 0.5);
10135 press[iz] = P(z[iz]);
10136 }
10137
10138 /* Set horizontal coordinates... */
10139 for (int ix = 0; ix < ctl->grid_nx; ix++)
10140 lon[ix] = ctl->grid_lon0 + dlon * (ix + 0.5);
10141#pragma omp parallel for default(shared)
10142 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10143 lat[iy] = ctl->grid_lat0 + dlat * (iy + 0.5);
10144 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
10145 }
10146
10147 /* Set time interval for output... */
10148 const double t0 = t - 0.5 * ctl->dt_mod;
10149 const double t1 = t + 0.5 * ctl->dt_mod;
10150
10151 /* Get grid box indices... */
10152#pragma omp parallel for default(shared)
10153 for (int ip = 0; ip < atm->np; ip++) {
10154 ixs[ip] = (int) ((atm->lon[ip] - ctl->grid_lon0) / dlon);
10155 iys[ip] = (int) ((atm->lat[ip] - ctl->grid_lat0) / dlat);
10156 izs[ip] = (int) ((Z(atm->p[ip]) - ctl->grid_z0) / dz);
10157 if (atm->time[ip] < t0 || atm->time[ip] > t1
10158 || ixs[ip] < 0 || ixs[ip] >= ctl->grid_nx
10159 || iys[ip] < 0 || iys[ip] >= ctl->grid_ny
10160 || izs[ip] < 0 || izs[ip] >= ctl->grid_nz)
10161 izs[ip] = -1;
10162 }
10163
10164 /* Average data... */
10165 for (int ip = 0; ip < atm->np; ip++)
10166 if (izs[ip] >= 0) {
10167 int idx =
10168 ARRAY_3D(ixs[ip], iys[ip], ctl->grid_ny, izs[ip], ctl->grid_nz);
10169 double kernel = kernel_weight(kz, kw, nk, atm->p[ip]);
10170 np[idx]++;
10171 for (int iq = 0; iq < ctl->nq; iq++) {
10172 mean[iq][idx] += kernel * atm->q[iq][ip];
10173 sigma[iq][idx] += SQR(kernel * atm->q[iq][ip]);
10174 }
10175 }
10176
10177 /* Calculate column density and volume mixing ratio... */
10178#pragma omp parallel for default(shared)
10179 for (int ix = 0; ix < ctl->grid_nx; ix++)
10180 for (int iy = 0; iy < ctl->grid_ny; iy++)
10181 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10182
10183 /* Get grid index... */
10184 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10185
10186 /* Calculate column density... */
10187 cd[idx] = NAN;
10188 if (ctl->qnt_m >= 0)
10189 cd[idx] = mean[ctl->qnt_m][idx] / (1e6 * area[iy]);
10190
10191 /* Calculate volume mixing ratio (implicit)... */
10192 vmr_impl[idx] = NAN;
10193 if (ctl->qnt_m >= 0 && ctl->molmass > 0 && met0 != NULL
10194 && met1 != NULL) {
10195 vmr_impl[idx] = 0;
10196 if (mean[ctl->qnt_m][idx] > 0) {
10197
10198 /* Get temperature... */
10199 double temp;
10201 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
10202 lon[ix], lat[iy], &temp, ci, cw, 1);
10203
10204 /* Calculate volume mixing ratio... */
10205 vmr_impl[idx] =
10206 MA / ctl->molmass * cd[idx] / (RHO(press[iz], temp) * dz * 1e3);
10207 }
10208 }
10209
10210 /* Calculate mean... */
10211 if (np[idx] > 0)
10212 for (int iq = 0; iq < ctl->nq; iq++) {
10213 mean[iq][idx] /= np[idx];
10214 double var = sigma[iq][idx] / np[idx] - SQR(mean[iq][idx]);
10215 sigma[iq][idx] = (var > 0 ? sqrt(var) : 0);
10216 } else
10217 for (int iq = 0; iq < ctl->nq; iq++) {
10218 mean[iq][idx] = NAN;
10219 sigma[iq][idx] = NAN;
10220 }
10221 }
10222
10223 /* Write ASCII data... */
10224 if (ctl->grid_type == 0)
10225 write_grid_asc(filename, ctl, cd, mean, sigma, vmr_impl,
10226 t, z, lon, lat, area, dz, np);
10227
10228 /* Write netCDF data... */
10229 else if (ctl->grid_type == 1)
10230 write_grid_nc(filename, ctl, cd, mean, sigma, vmr_impl,
10231 t, z, lon, lat, area, dz, np);
10232
10233 /* Error message... */
10234 else
10235 ERRMSG("Grid data format GRID_TYPE unknown!");
10236
10237 /* Free... */
10238 free(cd);
10239 for (int iq = 0; iq < ctl->nq; iq++) {
10240 free(mean[iq]);
10241 free(sigma[iq]);
10242 }
10243 free(vmr_impl);
10244 free(z);
10245 free(lon);
10246 free(lat);
10247 free(area);
10248 free(press);
10249 free(np);
10250 free(ixs);
10251 free(iys);
10252 free(izs);
10253}
10254
10255/*****************************************************************************/
10256
10258 const char *filename,
10259 const ctl_t *ctl,
10260 const double *cd,
10261 double *mean[NQ],
10262 double *sigma[NQ],
10263 const double *vmr_impl,
10264 const double t,
10265 const double *z,
10266 const double *lon,
10267 const double *lat,
10268 const double *area,
10269 const double dz,
10270 const int *np) {
10271
10272 FILE *out;
10273
10274 /* Check if gnuplot output is requested... */
10275 if (ctl->grid_gpfile[0] != '-') {
10276
10277 /* Create gnuplot pipe... */
10278 if (!(out = popen("gnuplot", "w")))
10279 ERRMSG("Cannot create pipe to gnuplot!");
10280
10281 /* Set plot filename... */
10282 fprintf(out, "set out \"%s.png\"\n", filename);
10283
10284 /* Set time string... */
10285 double r;
10286 int year, mon, day, hour, min, sec;
10287 jsec2time(t, &year, &mon, &day, &hour, &min, &sec, &r);
10288 fprintf(out, "timestr=\"%d-%02d-%02d, %02d:%02d UTC\"\n",
10289 year, mon, day, hour, min);
10290
10291 /* Dump gnuplot file to pipe... */
10292 FILE *in;
10293 char line[LEN];
10294 if (!(in = fopen(ctl->grid_gpfile, "r")))
10295 ERRMSG("Cannot open file!");
10296 while (fgets(line, LEN, in))
10297 fprintf(out, "%s", line);
10298 fclose(in);
10299 }
10300
10301 else {
10302
10303 /* Create file... */
10304 if (!(out = fopen(filename, "w")))
10305 ERRMSG("Cannot create file!");
10306 }
10307
10308 /* Write header... */
10309 fprintf(out,
10310 "# $1 = time [s]\n"
10311 "# $2 = altitude [km]\n"
10312 "# $3 = longitude [deg]\n"
10313 "# $4 = latitude [deg]\n"
10314 "# $5 = surface area [km^2]\n"
10315 "# $6 = layer depth [km]\n"
10316 "# $7 = column density (implicit) [kg/m^2]\n"
10317 "# $8 = volume mixing ratio (implicit) [ppv]\n"
10318 "# $9 = number of particles [1]\n");
10319 for (int iq = 0; iq < ctl->nq; iq++)
10320 fprintf(out, "# $%i = %s (mean) [%s]\n", 10 + iq, ctl->qnt_name[iq],
10321 ctl->qnt_unit[iq]);
10322 if (ctl->grid_stddev)
10323 for (int iq = 0; iq < ctl->nq; iq++)
10324 fprintf(out, "# $%i = %s (stddev) [%s]\n", 10 + ctl->nq + iq,
10325 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
10326 fprintf(out, "\n");
10327
10328 /* Write data... */
10329 for (int ix = 0; ix < ctl->grid_nx; ix++) {
10330 if (ix > 0 && ctl->grid_ny > 1 && !ctl->grid_sparse)
10331 fprintf(out, "\n");
10332 for (int iy = 0; iy < ctl->grid_ny; iy++) {
10333 if (iy > 0 && ctl->grid_nz > 1 && !ctl->grid_sparse)
10334 fprintf(out, "\n");
10335 for (int iz = 0; iz < ctl->grid_nz; iz++) {
10336 int idx = ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz);
10337 if (!ctl->grid_sparse || vmr_impl[idx] > 0) {
10338 fprintf(out, "%.2f %g %g %g %g %g %g %g %d", t, z[iz], lon[ix],
10339 lat[iy], area[iy], dz, cd[idx], vmr_impl[idx], np[idx]);
10340 for (int iq = 0; iq < ctl->nq; iq++) {
10341 fprintf(out, " ");
10342 fprintf(out, ctl->qnt_format[iq], mean[iq][idx]);
10343 }
10344 if (ctl->grid_stddev)
10345 for (int iq = 0; iq < ctl->nq; iq++) {
10346 fprintf(out, " ");
10347 fprintf(out, ctl->qnt_format[iq], sigma[iq][idx]);
10348 }
10349 fprintf(out, "\n");
10350 }
10351 }
10352 }
10353 }
10354
10355 /* Close file... */
10356 fclose(out);
10357}
10358
10359/*****************************************************************************/
10360
10362 const char *filename,
10363 const ctl_t *ctl,
10364 const double *cd,
10365 double *mean[NQ],
10366 double *sigma[NQ],
10367 const double *vmr_impl,
10368 const double t,
10369 const double *z,
10370 const double *lon,
10371 const double *lat,
10372 const double *area,
10373 const double dz,
10374 const int *np) {
10375
10376 char longname[2 * LEN], varname[2 * LEN];
10377
10378 double *help;
10379
10380 int *help2, ncid, dimid[10], varid;
10381
10382 size_t start[2], count[2];
10383
10384 /* Allocate... */
10385 ALLOC(help, double,
10386 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10387 ALLOC(help2, int,
10388 ctl->grid_nx * ctl->grid_ny * ctl->grid_nz);
10389
10390 /* Create file... */
10391 NC(nc_create(filename, NC_NETCDF4, &ncid));
10392
10393 /* Define dimensions... */
10394 NC(nc_def_dim(ncid, "time", 1, &dimid[0]));
10395 NC(nc_def_dim(ncid, "z", (size_t) ctl->grid_nz, &dimid[1]));
10396 NC(nc_def_dim(ncid, "lat", (size_t) ctl->grid_ny, &dimid[2]));
10397 NC(nc_def_dim(ncid, "lon", (size_t) ctl->grid_nx, &dimid[3]));
10398 NC(nc_def_dim(ncid, "dz", 1, &dimid[4]));
10399
10400 /* Define variables and their attributes... */
10401 NC_DEF_VAR("time", NC_DOUBLE, 1, &dimid[0], "time",
10402 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10403 NC_DEF_VAR("z", NC_DOUBLE, 1, &dimid[1], "altitude", "km", 0, 0);
10404 NC_DEF_VAR("lat", NC_DOUBLE, 1, &dimid[2], "latitude", "degrees_north", 0,
10405 0);
10406 NC_DEF_VAR("lon", NC_DOUBLE, 1, &dimid[3], "longitude", "degrees_east", 0,
10407 0);
10408 NC_DEF_VAR("dz", NC_DOUBLE, 1, &dimid[1], "layer depth", "km", 0, 0);
10409 NC_DEF_VAR("area", NC_DOUBLE, 1, &dimid[2], "surface area", "km**2", 0, 0);
10410
10411 NC_DEF_VAR("cd", NC_FLOAT, 4, dimid, "column density", "kg m**-2",
10412 ctl->grid_nc_level, 0);
10413 NC_DEF_VAR("vmr_impl", NC_FLOAT, 4, dimid, "volume mixing ratio (implicit)",
10414 "ppv", ctl->grid_nc_level, 0);
10415 NC_DEF_VAR("np", NC_INT, 4, dimid, "number of particles", "1", 0, 0);
10416 for (int iq = 0; iq < ctl->nq; iq++) {
10417 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10418 sprintf(longname, "%s (mean)", ctl->qnt_longname[iq]);
10419 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10420 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10421 if (ctl->grid_stddev) {
10422 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10423 sprintf(longname, "%s (stddev)", ctl->qnt_longname[iq]);
10424 NC_DEF_VAR(varname, NC_DOUBLE, 4, dimid, longname, ctl->qnt_unit[iq],
10425 ctl->grid_nc_level, ctl->grid_nc_quant[iq]);
10426 }
10427 }
10428 /* End definitions... */
10429 NC(nc_enddef(ncid));
10430
10431 /* Write data... */
10432 NC_PUT_DOUBLE("time", &t, 0);
10433 NC_PUT_DOUBLE("lon", lon, 0);
10434 NC_PUT_DOUBLE("lat", lat, 0);
10435 NC_PUT_DOUBLE("z", z, 0);
10436 NC_PUT_DOUBLE("area", area, 0);
10437 NC_PUT_DOUBLE("dz", &dz, 0);
10438
10439 for (int ix = 0; ix < ctl->grid_nx; ix++)
10440 for (int iy = 0; iy < ctl->grid_ny; iy++)
10441 for (int iz = 0; iz < ctl->grid_nz; iz++)
10442 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10443 cd[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10444 NC_PUT_DOUBLE("cd", help, 0);
10445
10446 for (int ix = 0; ix < ctl->grid_nx; ix++)
10447 for (int iy = 0; iy < ctl->grid_ny; iy++)
10448 for (int iz = 0; iz < ctl->grid_nz; iz++)
10449 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10450 vmr_impl[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10451 NC_PUT_DOUBLE("vmr_impl", help, 0);
10452
10453 for (int ix = 0; ix < ctl->grid_nx; ix++)
10454 for (int iy = 0; iy < ctl->grid_ny; iy++)
10455 for (int iz = 0; iz < ctl->grid_nz; iz++)
10456 help2[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10457 np[ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10458 NC_PUT_INT("np", help2, 0);
10459
10460 for (int iq = 0; iq < ctl->nq; iq++) {
10461 sprintf(varname, "%s_mean", ctl->qnt_name[iq]);
10462 for (int ix = 0; ix < ctl->grid_nx; ix++)
10463 for (int iy = 0; iy < ctl->grid_ny; iy++)
10464 for (int iz = 0; iz < ctl->grid_nz; iz++)
10465 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10466 mean[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10467 NC_PUT_DOUBLE(varname, help, 0);
10468 }
10469
10470 if (ctl->grid_stddev)
10471 for (int iq = 0; iq < ctl->nq; iq++) {
10472 sprintf(varname, "%s_stddev", ctl->qnt_name[iq]);
10473 for (int ix = 0; ix < ctl->grid_nx; ix++)
10474 for (int iy = 0; iy < ctl->grid_ny; iy++)
10475 for (int iz = 0; iz < ctl->grid_nz; iz++)
10476 help[ARRAY_3D(iz, iy, ctl->grid_ny, ix, ctl->grid_nx)] =
10477 sigma[iq][ARRAY_3D(ix, iy, ctl->grid_ny, iz, ctl->grid_nz)];
10478 NC_PUT_DOUBLE(varname, help, 0);
10479 }
10480
10481 /* Close file... */
10482 NC(nc_close(ncid));
10483
10484 /* Free... */
10485 free(help);
10486 free(help2);
10487}
10488
10489/*****************************************************************************/
10490
10492 const char *filename,
10493 const ctl_t *ctl,
10494 met_t *met) {
10495
10496 /* Create file... */
10497 FILE *out;
10498 if (!(out = fopen(filename, "w")))
10499 ERRMSG("Cannot create file!");
10500
10501 /* Write type of binary data... */
10502 FWRITE(&ctl->met_type, int,
10503 1,
10504 out);
10505
10506 /* Write version of binary data... */
10507 int version = 103;
10508 FWRITE(&version, int,
10509 1,
10510 out);
10511
10512 /* Write grid data... */
10513 FWRITE(&met->time, double,
10514 1,
10515 out);
10516 FWRITE(&met->nx, int,
10517 1,
10518 out);
10519 FWRITE(&met->ny, int,
10520 1,
10521 out);
10522 FWRITE(&met->np, int,
10523 1,
10524 out);
10525 FWRITE(met->lon, double,
10526 (size_t) met->nx,
10527 out);
10528 FWRITE(met->lat, double,
10529 (size_t) met->ny,
10530 out);
10531 FWRITE(met->p, double,
10532 (size_t) met->np,
10533 out);
10534
10535 /* Write surface data... */
10536 write_met_bin_2d(out, met, met->ps, "PS");
10537 write_met_bin_2d(out, met, met->ts, "TS");
10538 write_met_bin_2d(out, met, met->zs, "ZS");
10539 write_met_bin_2d(out, met, met->us, "US");
10540 write_met_bin_2d(out, met, met->vs, "VS");
10541 write_met_bin_2d(out, met, met->ess, "ESS");
10542 write_met_bin_2d(out, met, met->nss, "NSS");
10543 write_met_bin_2d(out, met, met->shf, "SHF");
10544 write_met_bin_2d(out, met, met->lsm, "LSM");
10545 write_met_bin_2d(out, met, met->sst, "SST");
10546 write_met_bin_2d(out, met, met->pbl, "PBL");
10547 write_met_bin_2d(out, met, met->pt, "PT");
10548 write_met_bin_2d(out, met, met->tt, "TT");
10549 write_met_bin_2d(out, met, met->zt, "ZT");
10550 write_met_bin_2d(out, met, met->h2ot, "H2OT");
10551 write_met_bin_2d(out, met, met->pct, "PCT");
10552 write_met_bin_2d(out, met, met->pcb, "PCB");
10553 write_met_bin_2d(out, met, met->cl, "CL");
10554 write_met_bin_2d(out, met, met->plcl, "PLCL");
10555 write_met_bin_2d(out, met, met->plfc, "PLFC");
10556 write_met_bin_2d(out, met, met->pel, "PEL");
10557 write_met_bin_2d(out, met, met->cape, "CAPE");
10558 write_met_bin_2d(out, met, met->cin, "CIN");
10559 write_met_bin_2d(out, met, met->o3c, "O3C");
10560
10561 /* Write level data... */
10562 write_met_bin_3d(out, ctl, met, met->z, "Z",
10563 (ctl->met_zfp_tol_z <= 0 ? ctl->met_zfp_prec : 0),
10564 ctl->met_zfp_tol_z);
10565 write_met_bin_3d(out, ctl, met, met->t, "T",
10566 (ctl->met_zfp_tol_t <= 0 ? ctl->met_zfp_prec : 0),
10567 ctl->met_zfp_tol_t);
10568 write_met_bin_3d(out, ctl, met, met->u, "U", ctl->met_zfp_prec, 0);
10569 write_met_bin_3d(out, ctl, met, met->v, "V", ctl->met_zfp_prec, 0);
10570 write_met_bin_3d(out, ctl, met, met->w, "W", ctl->met_zfp_prec, 0);
10571 write_met_bin_3d(out, ctl, met, met->pv, "PV", ctl->met_zfp_prec, 0);
10572 write_met_bin_3d(out, ctl, met, met->h2o, "H2O", ctl->met_zfp_prec, 0);
10573 write_met_bin_3d(out, ctl, met, met->o3, "O3", ctl->met_zfp_prec, 0);
10574 write_met_bin_3d(out, ctl, met, met->lwc, "LWC", ctl->met_zfp_prec, 0);
10575 write_met_bin_3d(out, ctl, met, met->rwc, "RWC", ctl->met_zfp_prec, 0);
10576 write_met_bin_3d(out, ctl, met, met->iwc, "IWC", ctl->met_zfp_prec, 0);
10577 write_met_bin_3d(out, ctl, met, met->swc, "SWC", ctl->met_zfp_prec, 0);
10578 write_met_bin_3d(out, ctl, met, met->cc, "CC", ctl->met_zfp_prec, 0);
10579
10580 /* Write final flag... */
10581 int final = 999;
10582 FWRITE(&final, int,
10583 1,
10584 out);
10585
10586 /* Close file... */
10587 fclose(out);
10588}
10589
10590/*****************************************************************************/
10591
10593 FILE *out,
10594 met_t *met,
10595 float var[EX][EY],
10596 const char *varname) {
10597
10598 float *help;
10599
10600 /* Allocate... */
10601 ALLOC(help, float,
10602 EX * EY);
10603
10604 /* Copy data... */
10605 for (int ix = 0; ix < met->nx; ix++)
10606 for (int iy = 0; iy < met->ny; iy++)
10607 help[ARRAY_2D(ix, iy, met->ny)] = var[ix][iy];
10608
10609 /* Write uncompressed data... */
10610 LOG(2, "Write 2-D variable: %s (uncompressed)", varname);
10611 FWRITE(help, float,
10612 (size_t) (met->nx * met->ny),
10613 out);
10614
10615 /* Free... */
10616 free(help);
10617}
10618
10619/*****************************************************************************/
10620
10622 FILE *out,
10623 const ctl_t *ctl,
10624 met_t *met,
10625 float var[EX][EY][EP],
10626 const char *varname,
10627 const int precision,
10628 const double tolerance) {
10629
10630 float *help;
10631
10632 /* Allocate... */
10633 ALLOC(help, float,
10634 EX * EY * EP);
10635
10636 /* Copy data... */
10637#pragma omp parallel for default(shared) collapse(2)
10638 for (int ix = 0; ix < met->nx; ix++)
10639 for (int iy = 0; iy < met->ny; iy++)
10640 for (int ip = 0; ip < met->np; ip++)
10641 help[ARRAY_3D(ix, iy, met->ny, ip, met->np)] = var[ix][iy][ip];
10642
10643 /* Write uncompressed data... */
10644 if (ctl->met_type == 1) {
10645 LOG(2, "Write 3-D variable: %s (uncompressed)", varname);
10646 FWRITE(help, float,
10647 (size_t) (met->nx * met->ny * met->np),
10648 out);
10649 }
10650
10651 /* Write packed data... */
10652 else if (ctl->met_type == 2)
10653 compress_pck(varname, help, (size_t) (met->ny * met->nx),
10654 (size_t) met->np, 0, out);
10655
10656 /* Write zfp data... */
10657#ifdef ZFP
10658 else if (ctl->met_type == 3) {
10659 FWRITE(&precision, int,
10660 1,
10661 out);
10662 FWRITE(&tolerance, double,
10663 1,
10664 out);
10665 compress_zfp(varname, help, met->np, met->ny, met->nx, precision,
10666 tolerance, 0, out);
10667 }
10668#endif
10669
10670 /* Write zstd data... */
10671#ifdef ZSTD
10672 else if (ctl->met_type == 4)
10673 compress_zstd(varname, help, (size_t) (met->np * met->ny * met->nx), 0,
10674 ctl->met_zstd_level, out);
10675#endif
10676
10677 /* Write cmultiscale data... */
10678#ifdef CMS
10679 else if (ctl->met_type == 5) {
10680 compress_cms(ctl, varname, help, (size_t) met->nx, (size_t) met->ny,
10681 (size_t) met->np, 0, out);
10682 }
10683#endif
10684
10685 /* Unknown method... */
10686 else {
10687 ERRMSG("MET_TYPE not supported!");
10688 LOG(3, "%d %g", precision, tolerance);
10689 }
10690
10691 /* Free... */
10692 free(help);
10693}
10694
10695/*****************************************************************************/
10696
10698 const char *filename,
10699 const ctl_t *ctl,
10700 met_t *met) {
10701
10702 /* Create file... */
10703 int ncid, varid;
10704 size_t start[4], count[4];
10705 nc_create(filename, NC_NETCDF4, &ncid);
10706
10707 /* Define dimensions... */
10708 int tid, lonid, latid, levid;
10709 NC(nc_def_dim(ncid, "time", 1, &tid));
10710 NC(nc_def_dim(ncid, "lon", (size_t) met->nx, &lonid));
10711 NC(nc_def_dim(ncid, "lat", (size_t) met->ny, &latid));
10712 NC(nc_def_dim(ncid, "lev", (size_t) met->np, &levid));
10713
10714 /* Define grid... */
10715 NC_DEF_VAR("time", NC_DOUBLE, 1, &tid, "time",
10716 "seconds since 2000-01-01 00:00:00 UTC", 0, 0);
10717 NC_DEF_VAR("lon", NC_DOUBLE, 1, &lonid, "longitude", "degrees_east", 0, 0);
10718 NC_DEF_VAR("lat", NC_DOUBLE, 1, &latid, "latitude", "degrees_north", 0, 0);
10719 NC_DEF_VAR("lev", NC_DOUBLE, 1, &levid, "pressure", "Pa", 0, 0);
10720
10721 /* Define surface variables... */
10722 int dimid2[2] = { latid, lonid };
10723 NC_DEF_VAR("sp", NC_FLOAT, 2, dimid2, "Surface pressure", "Pa",
10724 ctl->met_nc_level, 0);
10725 NC_DEF_VAR("z", NC_FLOAT, 2, dimid2, "Geopotential", "m**2 s**-2",
10726 ctl->met_nc_level, 0);
10727 NC_DEF_VAR("t2m", NC_FLOAT, 2, dimid2, "2 metre temperature", "K",
10728 ctl->met_nc_level, 0);
10729 NC_DEF_VAR("u10m", NC_FLOAT, 2, dimid2, "10 metre U wind component",
10730 "m s**-1", ctl->met_nc_level, 0);
10731 NC_DEF_VAR("v10m", NC_FLOAT, 2, dimid2, "10 metre V wind component",
10732 "m s**-1", ctl->met_nc_level, 0);
10733 NC_DEF_VAR("iews", NC_FLOAT, 2, dimid2,
10734 "Instantaneous eastward turbulent surface stress", "N m**-2",
10735 ctl->met_nc_level, 0);
10736 NC_DEF_VAR("inss", NC_FLOAT, 2, dimid2,
10737 "Instantaneous northward turbulent surface stress", "N m**-2",
10738 ctl->met_nc_level, 0);
10739 NC_DEF_VAR("ishf", NC_FLOAT, 2, dimid2,
10740 "Instantaneous surface sensible heat flux", "W m**-1",
10741 ctl->met_nc_level, 0);
10742 NC_DEF_VAR("lsm", NC_FLOAT, 2, dimid2, "Land/sea mask", "-",
10743 ctl->met_nc_level, 0);
10744 NC_DEF_VAR("sstk", NC_FLOAT, 2, dimid2, "Sea surface temperature", "K",
10745 ctl->met_nc_level, 0);
10746 NC_DEF_VAR("blp", NC_FLOAT, 2, dimid2, "Boundary layer pressure", "Pa",
10747 ctl->met_nc_level, 0);
10748 NC_DEF_VAR("pt", NC_FLOAT, 2, dimid2, "Tropopause pressure", "Pa",
10749 ctl->met_nc_level, 0);
10750 NC_DEF_VAR("tt", NC_FLOAT, 2, dimid2, "Tropopause temperature", "K",
10751 ctl->met_nc_level, 0);
10752 NC_DEF_VAR("zt", NC_FLOAT, 2, dimid2, "Tropopause height", "m",
10753 ctl->met_nc_level, 0);
10754 NC_DEF_VAR("h2ot", NC_FLOAT, 2, dimid2, "Tropopause water vapor", "ppv",
10755 ctl->met_nc_level, 0);
10756 NC_DEF_VAR("pct", NC_FLOAT, 2, dimid2, "Cloud top pressure", "Pa",
10757 ctl->met_nc_level, 0);
10758 NC_DEF_VAR("pcb", NC_FLOAT, 2, dimid2, "Cloud bottom pressure", "Pa",
10759 ctl->met_nc_level, 0);
10760 NC_DEF_VAR("cl", NC_FLOAT, 2, dimid2, "Total column cloud water", "kg m**2",
10761 ctl->met_nc_level, 0);
10762 NC_DEF_VAR("plcl", NC_FLOAT, 2, dimid2,
10763 "Pressure at lifted condensation level (LCL)", "Pa",
10764 ctl->met_nc_level, 0);
10765 NC_DEF_VAR("plfc", NC_FLOAT, 2, dimid2,
10766 "Pressure at level of free convection (LFC)", "Pa",
10767 ctl->met_nc_level, 0);
10768 NC_DEF_VAR("pel", NC_FLOAT, 2, dimid2, "Pressure at equilibrium level (EL)",
10769 "Pa", ctl->met_nc_level, 0);
10770 NC_DEF_VAR("cape", NC_FLOAT, 2, dimid2,
10771 "Convective available potential energy", "J kg**-1",
10772 ctl->met_nc_level, 0);
10773 NC_DEF_VAR("cin", NC_FLOAT, 2, dimid2, "Convective inhibition", "J kg**-1",
10774 ctl->met_nc_level, 0);
10775 NC_DEF_VAR("o3c", NC_FLOAT, 2, dimid2, "Total column ozone", "DU",
10776 ctl->met_nc_level, 0);
10777
10778 /* Define level data... */
10779 int dimid3[3] = { levid, latid, lonid };
10780 NC_DEF_VAR("t", NC_FLOAT, 3, dimid3, "Temperature", "K",
10781 ctl->met_nc_level, ctl->met_nc_quant);
10782 NC_DEF_VAR("u", NC_FLOAT, 3, dimid3, "U velocity", "m s**-1",
10783 ctl->met_nc_level, ctl->met_nc_quant);
10784 NC_DEF_VAR("v", NC_FLOAT, 3, dimid3, "V velocity", "m s**-1",
10785 ctl->met_nc_level, ctl->met_nc_quant);
10786 NC_DEF_VAR("w", NC_FLOAT, 3, dimid3, "Vertical velocity", "Pa s**-1",
10787 ctl->met_nc_level, ctl->met_nc_quant);
10788 NC_DEF_VAR("q", NC_FLOAT, 3, dimid3, "Specific humidity", "kg kg**-1",
10789 ctl->met_nc_level, ctl->met_nc_quant);
10790 NC_DEF_VAR("o3", NC_FLOAT, 3, dimid3, "Ozone mass mixing ratio",
10791 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10792 NC_DEF_VAR("clwc", NC_FLOAT, 3, dimid3, "Cloud liquid water content",
10793 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10794 NC_DEF_VAR("crwc", NC_FLOAT, 3, dimid3, "Cloud rain water content",
10795 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10796 NC_DEF_VAR("ciwc", NC_FLOAT, 3, dimid3, "Cloud ice water content",
10797 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10798 NC_DEF_VAR("cswc", NC_FLOAT, 3, dimid3, "Cloud snow water content",
10799 "kg kg**-1", ctl->met_nc_level, ctl->met_nc_quant);
10800 NC_DEF_VAR("cc", NC_FLOAT, 3, dimid3, "Cloud cover", "-",
10801 ctl->met_nc_level, ctl->met_nc_quant);
10802
10803 /* End definitions... */
10804 NC(nc_enddef(ncid));
10805
10806 /* Write grid data... */
10807 NC_PUT_DOUBLE("time", &met->time, 0);
10808 NC_PUT_DOUBLE("lon", met->lon, 0);
10809 NC_PUT_DOUBLE("lat", met->lat, 0);
10810 double phelp[EP];
10811 for (int ip = 0; ip < met->np; ip++)
10812 phelp[ip] = 100. * met->p[ip];
10813 NC_PUT_DOUBLE("lev", phelp, 0);
10814
10815 /* Write surface data... */
10816 write_met_nc_2d(ncid, "sp", met, met->ps, 100.0f);
10817 write_met_nc_2d(ncid, "z", met, met->zs, (float) (1000. * G0));
10818 write_met_nc_2d(ncid, "t2m", met, met->ts, 1.0f);
10819 write_met_nc_2d(ncid, "u10m", met, met->us, 1.0f);
10820 write_met_nc_2d(ncid, "v10m", met, met->vs, 1.0f);
10821 write_met_nc_2d(ncid, "iews", met, met->ess, 1.0f);
10822 write_met_nc_2d(ncid, "inss", met, met->nss, 1.0f);
10823 write_met_nc_2d(ncid, "ishf", met, met->shf, 1.0f);
10824 write_met_nc_2d(ncid, "lsm", met, met->lsm, 1.0f);
10825 write_met_nc_2d(ncid, "sstk", met, met->sst, 1.0f);
10826 write_met_nc_2d(ncid, "blp", met, met->pbl, 100.0f);
10827 write_met_nc_2d(ncid, "pt", met, met->pt, 100.0f);
10828 write_met_nc_2d(ncid, "tt", met, met->tt, 1.0f);
10829 write_met_nc_2d(ncid, "zt", met, met->zt, 1000.0f);
10830 write_met_nc_2d(ncid, "h2ot", met, met->h2ot, 1.0f);
10831 write_met_nc_2d(ncid, "pct", met, met->pct, 100.0f);
10832 write_met_nc_2d(ncid, "pcb", met, met->pcb, 100.0f);
10833 write_met_nc_2d(ncid, "cl", met, met->cl, 1.0f);
10834 write_met_nc_2d(ncid, "plcl", met, met->plcl, 100.0f);
10835 write_met_nc_2d(ncid, "plfc", met, met->plfc, 100.0f);
10836 write_met_nc_2d(ncid, "pel", met, met->pel, 100.0f);
10837 write_met_nc_2d(ncid, "cape", met, met->cape, 1.0f);
10838 write_met_nc_2d(ncid, "cin", met, met->cin, 1.0f);
10839 write_met_nc_2d(ncid, "o3c", met, met->o3c, 1.0f);
10840
10841 /* Write level data... */
10842 write_met_nc_3d(ncid, "t", met, met->t, 1.0f);
10843 write_met_nc_3d(ncid, "u", met, met->u, 1.0f);
10844 write_met_nc_3d(ncid, "v", met, met->v, 1.0f);
10845 write_met_nc_3d(ncid, "w", met, met->w, 100.0f);
10846 write_met_nc_3d(ncid, "q", met, met->h2o, (float) (MH2O / MA));
10847 write_met_nc_3d(ncid, "o3", met, met->o3, (float) (MO3 / MA));
10848 write_met_nc_3d(ncid, "clwc", met, met->lwc, 1.0f);
10849 write_met_nc_3d(ncid, "crwc", met, met->rwc, 1.0f);
10850 write_met_nc_3d(ncid, "ciwc", met, met->iwc, 1.0f);
10851 write_met_nc_3d(ncid, "cswc", met, met->swc, 1.0f);
10852 write_met_nc_3d(ncid, "cc", met, met->cc, 1.0f);
10853
10854 /* Close file... */
10855 NC(nc_close(ncid));
10856}
10857
10858/*****************************************************************************/
10859
10861 const int ncid,
10862 const char *varname,
10863 met_t *met,
10864 float var[EX][EY],
10865 const float scl) {
10866
10867 int varid;
10868 size_t start[4], count[4];
10869
10870 /* Allocate... */
10871 float *help;
10872 ALLOC(help, float,
10873 EX * EY);
10874
10875 /* Copy data... */
10876 for (int ix = 0; ix < met->nx; ix++)
10877 for (int iy = 0; iy < met->ny; iy++)
10878 help[ARRAY_2D(iy, ix, met->nx)] = scl * var[ix][iy];
10879
10880 /* Write data... */
10881 NC_PUT_FLOAT(varname, help, 0);
10882
10883 /* Free... */
10884 free(help);
10885}
10886
10887/*****************************************************************************/
10888
10890 const int ncid,
10891 const char *varname,
10892 met_t *met,
10893 float var[EX][EY][EP],
10894 const float scl) {
10895
10896 int varid;
10897 size_t start[4], count[4];
10898
10899 /* Allocate... */
10900 float *help;
10901 ALLOC(help, float,
10902 EX * EY * EP);
10903
10904 /* Copy data... */
10905 for (int ix = 0; ix < met->nx; ix++)
10906 for (int iy = 0; iy < met->ny; iy++)
10907 for (int ip = 0; ip < met->np; ip++)
10908 help[ARRAY_3D(ip, iy, met->ny, ix, met->nx)] = scl * var[ix][iy][ip];
10909
10910 /* Write data... */
10911 NC_PUT_FLOAT(varname, help, 0);
10912
10913 /* Free... */
10914 free(help);
10915}
10916
10917/*****************************************************************************/
10918
10920 const char *filename,
10921 const ctl_t *ctl,
10922 met_t *met0,
10923 met_t *met1,
10924 const atm_t *atm,
10925 const double t) {
10926
10927 static FILE *out;
10928
10929 static double *mass, *obsmean, *rt, *rz, *rlon, *rlat, *robs, *area,
10930 dz, dlon, dlat, *lon, *lat, *z, *press, temp, vmr, h2o, o3;
10931
10932 static int nobs, *obscount, ip, okay;
10933
10934 /* Set timer... */
10935 SELECT_TIMER("WRITE_PROF", "OUTPUT", NVTX_WRITE);
10936
10937 /* Init... */
10938 if (t == ctl->t_start) {
10939
10940 /* Check quantity index for mass... */
10941 if (ctl->qnt_m < 0)
10942 ERRMSG("Need quantity mass!");
10943
10944 /* Check molar mass... */
10945 if (ctl->molmass <= 0)
10946 ERRMSG("Specify molar mass!");
10947
10948 /* Allocate... */
10949 ALLOC(lon, double,
10950 ctl->prof_nx);
10951 ALLOC(lat, double,
10952 ctl->prof_ny);
10953 ALLOC(area, double,
10954 ctl->prof_ny);
10955 ALLOC(z, double,
10956 ctl->prof_nz);
10957 ALLOC(press, double,
10958 ctl->prof_nz);
10959 ALLOC(rt, double,
10960 NOBS);
10961 ALLOC(rz, double,
10962 NOBS);
10963 ALLOC(rlon, double,
10964 NOBS);
10965 ALLOC(rlat, double,
10966 NOBS);
10967 ALLOC(robs, double,
10968 NOBS);
10969
10970 /* Read observation data... */
10971 read_obs(ctl->prof_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
10972
10973 /* Create new output file... */
10974 LOG(1, "Write profile data: %s", filename);
10975 if (!(out = fopen(filename, "w")))
10976 ERRMSG("Cannot create file!");
10977
10978 /* Write header... */
10979 fprintf(out,
10980 "# $1 = time [s]\n"
10981 "# $2 = altitude [km]\n"
10982 "# $3 = longitude [deg]\n"
10983 "# $4 = latitude [deg]\n"
10984 "# $5 = pressure [hPa]\n"
10985 "# $6 = temperature [K]\n"
10986 "# $7 = volume mixing ratio [ppv]\n"
10987 "# $8 = H2O volume mixing ratio [ppv]\n"
10988 "# $9 = O3 volume mixing ratio [ppv]\n"
10989 "# $10 = observed BT index [K]\n"
10990 "# $11 = number of observations\n");
10991
10992 /* Set grid box size... */
10993 dz = (ctl->prof_z1 - ctl->prof_z0) / ctl->prof_nz;
10994 dlon = (ctl->prof_lon1 - ctl->prof_lon0) / ctl->prof_nx;
10995 dlat = (ctl->prof_lat1 - ctl->prof_lat0) / ctl->prof_ny;
10996
10997 /* Set vertical coordinates... */
10998 for (int iz = 0; iz < ctl->prof_nz; iz++) {
10999 z[iz] = ctl->prof_z0 + dz * (iz + 0.5);
11000 press[iz] = P(z[iz]);
11001 }
11002
11003 /* Set horizontal coordinates... */
11004 for (int ix = 0; ix < ctl->prof_nx; ix++)
11005 lon[ix] = ctl->prof_lon0 + dlon * (ix + 0.5);
11006 for (int iy = 0; iy < ctl->prof_ny; iy++) {
11007 lat[iy] = ctl->prof_lat0 + dlat * (iy + 0.5);
11008 area[iy] = dlat * dlon * SQR(RE * M_PI / 180.) * cos(DEG2RAD(lat[iy]));
11009 }
11010 }
11011
11012 /* Set time interval... */
11013 const double t0 = t - 0.5 * ctl->dt_mod;
11014 const double t1 = t + 0.5 * ctl->dt_mod;
11015
11016 /* Allocate... */
11017 ALLOC(mass, double,
11018 ctl->prof_nx * ctl->prof_ny * ctl->prof_nz);
11019 ALLOC(obsmean, double,
11020 ctl->prof_nx * ctl->prof_ny);
11021 ALLOC(obscount, int,
11022 ctl->prof_nx * ctl->prof_ny);
11023
11024 /* Loop over observations... */
11025 for (int i = 0; i < nobs; i++) {
11026
11027 /* Check time... */
11028 if (rt[i] < t0)
11029 continue;
11030 else if (rt[i] >= t1)
11031 break;
11032
11033 /* Check observation data... */
11034 if (!isfinite(robs[i]))
11035 continue;
11036
11037 /* Calculate indices... */
11038 int ix = (int) ((rlon[i] - ctl->prof_lon0) / dlon);
11039 int iy = (int) ((rlat[i] - ctl->prof_lat0) / dlat);
11040
11041 /* Check indices... */
11042 if (ix < 0 || ix >= ctl->prof_nx || iy < 0 || iy >= ctl->prof_ny)
11043 continue;
11044
11045 /* Get mean observation index... */
11046 int idx = ARRAY_2D(ix, iy, ctl->prof_ny);
11047 obsmean[idx] += robs[i];
11048 obscount[idx]++;
11049 }
11050
11051 /* Analyze model data... */
11052 for (ip = 0; ip < atm->np; ip++) {
11053
11054 /* Check time... */
11055 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11056 continue;
11057
11058 /* Get indices... */
11059 int ix = (int) ((atm->lon[ip] - ctl->prof_lon0) / dlon);
11060 int iy = (int) ((atm->lat[ip] - ctl->prof_lat0) / dlat);
11061 int iz = (int) ((Z(atm->p[ip]) - ctl->prof_z0) / dz);
11062
11063 /* Check indices... */
11064 if (ix < 0 || ix >= ctl->prof_nx ||
11065 iy < 0 || iy >= ctl->prof_ny || iz < 0 || iz >= ctl->prof_nz)
11066 continue;
11067
11068 /* Get total mass in grid cell... */
11069 int idx = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11070 mass[idx] += atm->q[ctl->qnt_m][ip];
11071 }
11072
11073 /* Extract profiles... */
11074 for (int ix = 0; ix < ctl->prof_nx; ix++)
11075 for (int iy = 0; iy < ctl->prof_ny; iy++) {
11076 int idx2 = ARRAY_2D(ix, iy, ctl->prof_ny);
11077 if (obscount[idx2] > 0) {
11078
11079 /* Check profile... */
11080 okay = 0;
11081 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11082 int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11083 if (mass[idx3] > 0) {
11084 okay = 1;
11085 break;
11086 }
11087 }
11088 if (!okay)
11089 continue;
11090
11091 /* Write output... */
11092 fprintf(out, "\n");
11093
11094 /* Loop over altitudes... */
11095 for (int iz = 0; iz < ctl->prof_nz; iz++) {
11096
11097 /* Get temperature, water vapor, and ozone... */
11099 intpol_met_time_3d(met0, met0->t, met1, met1->t, t, press[iz],
11100 lon[ix], lat[iy], &temp, ci, cw, 1);
11101 intpol_met_time_3d(met0, met0->h2o, met1, met1->h2o, t, press[iz],
11102 lon[ix], lat[iy], &h2o, ci, cw, 0);
11103 intpol_met_time_3d(met0, met0->o3, met1, met1->o3, t, press[iz],
11104 lon[ix], lat[iy], &o3, ci, cw, 0);
11105
11106 /* Calculate volume mixing ratio... */
11107 const int idx3 = ARRAY_3D(ix, iy, ctl->prof_ny, iz, ctl->prof_nz);
11108 vmr = MA / ctl->molmass * mass[idx3]
11109 / (RHO(press[iz], temp) * area[iy] * dz * 1e9);
11110
11111 /* Write output... */
11112 fprintf(out, "%.2f %g %g %g %g %g %g %g %g %g %d\n",
11113 t, z[iz], lon[ix], lat[iy], press[iz], temp, vmr, h2o, o3,
11114 obsmean[idx2] / obscount[idx2], obscount[idx2]);
11115 }
11116 }
11117 }
11118
11119 /* Free... */
11120 free(mass);
11121 free(obsmean);
11122 free(obscount);
11123
11124 /* Finalize... */
11125 if (t == ctl->t_stop) {
11126
11127 /* Close output file... */
11128 fclose(out);
11129
11130 /* Free... */
11131 free(lon);
11132 free(lat);
11133 free(area);
11134 free(z);
11135 free(press);
11136 free(rt);
11137 free(rz);
11138 free(rlon);
11139 free(rlat);
11140 free(robs);
11141 }
11142}
11143
11144/*****************************************************************************/
11145
11147 const char *filename,
11148 const ctl_t *ctl,
11149 met_t *met0,
11150 met_t *met1,
11151 const atm_t *atm,
11152 const double t) {
11153
11154 static FILE *out;
11155
11156 static double area, dlat, rmax2, *rt, *rz, *rlon, *rlat, *robs, kz[EP],
11157 kw[EP];
11158
11159 static int nobs, nk;
11160
11161 /* Set timer... */
11162 SELECT_TIMER("WRITE_SAMPLE", "OUTPUT", NVTX_WRITE);
11163
11164 /* Init... */
11165 if (t == ctl->t_start) {
11166
11167 /* Allocate... */
11168 ALLOC(rt, double,
11169 NOBS);
11170 ALLOC(rz, double,
11171 NOBS);
11172 ALLOC(rlon, double,
11173 NOBS);
11174 ALLOC(rlat, double,
11175 NOBS);
11176 ALLOC(robs, double,
11177 NOBS);
11178
11179 /* Read observation data... */
11180 read_obs(ctl->sample_obsfile, ctl, rt, rz, rlon, rlat, robs, &nobs);
11181
11182 /* Read kernel data... */
11183 if (ctl->sample_kernel[0] != '-')
11184 read_kernel(ctl->sample_kernel, kz, kw, &nk);
11185
11186 /* Create output file... */
11187 LOG(1, "Write sample data: %s", filename);
11188 if (!(out = fopen(filename, "w")))
11189 ERRMSG("Cannot create file!");
11190
11191 /* Write header... */
11192 fprintf(out,
11193 "# $1 = time [s]\n"
11194 "# $2 = altitude [km]\n"
11195 "# $3 = longitude [deg]\n"
11196 "# $4 = latitude [deg]\n"
11197 "# $5 = surface area [km^2]\n"
11198 "# $6 = layer depth [km]\n"
11199 "# $7 = number of particles [1]\n"
11200 "# $8 = column density [kg/m^2]\n"
11201 "# $9 = volume mixing ratio [ppv]\n"
11202 "# $10 = observed BT index [K]\n\n");
11203
11204 /* Set latitude range, squared radius, and area... */
11205 dlat = DY2DEG(ctl->sample_dx);
11206 rmax2 = SQR(ctl->sample_dx);
11207 area = M_PI * rmax2;
11208 }
11209
11210 /* Set time interval for output... */
11211 const double t0 = t - 0.5 * ctl->dt_mod;
11212 const double t1 = t + 0.5 * ctl->dt_mod;
11213
11214 /* Loop over observations... */
11215 for (int i = 0; i < nobs; i++) {
11216
11217 /* Check time... */
11218 if (rt[i] < t0)
11219 continue;
11220 else if (rt[i] >= t1)
11221 break;
11222
11223 /* Calculate Cartesian coordinates... */
11224 double x0[3];
11225 geo2cart(0, rlon[i], rlat[i], x0);
11226
11227 /* Set pressure range... */
11228 const double rp = P(rz[i]);
11229 const double ptop = P(rz[i] + ctl->sample_dz);
11230 const double pbot = P(rz[i] - ctl->sample_dz);
11231
11232 /* Init... */
11233 double mass = 0;
11234 int np = 0;
11235
11236 /* Loop over air parcels... */
11237 //#pragma omp parallel for default(shared) reduction(+:mass,np)
11238 for (int ip = 0; ip < atm->np; ip++) {
11239
11240 /* Check time... */
11241 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11242 continue;
11243
11244 /* Check latitude... */
11245 if (fabs(rlat[i] - atm->lat[ip]) > dlat)
11246 continue;
11247
11248 /* Check horizontal distance... */
11249 double x1[3];
11250 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11251 if (DIST2(x0, x1) > rmax2)
11252 continue;
11253
11254 /* Check pressure... */
11255 if (ctl->sample_dz > 0)
11256 if (atm->p[ip] > pbot || atm->p[ip] < ptop)
11257 continue;
11258
11259 /* Add mass... */
11260 if (ctl->qnt_m >= 0)
11261 mass +=
11262 kernel_weight(kz, kw, nk, atm->p[ip]) * atm->q[ctl->qnt_m][ip];
11263 np++;
11264 }
11265
11266 /* Calculate column density... */
11267 const double cd = mass / (1e6 * area);
11268
11269 /* Calculate volume mixing ratio... */
11270 double vmr = 0;
11271 if (ctl->molmass > 0 && ctl->sample_dz > 0) {
11272 if (mass > 0) {
11273
11274 /* Get temperature... */
11275 double temp;
11277 intpol_met_time_3d(met0, met0->t, met1, met1->t, rt[i], rp,
11278 rlon[i], rlat[i], &temp, ci, cw, 1);
11279
11280 /* Calculate volume mixing ratio... */
11281 vmr = MA / ctl->molmass * cd / (RHO(rp, temp) * ctl->sample_dz * 1e3);
11282 }
11283 } else
11284 vmr = NAN;
11285
11286 /* Write output... */
11287 fprintf(out, "%.2f %g %g %g %g %g %d %g %g %g\n", rt[i], rz[i],
11288 rlon[i], rlat[i], area, ctl->sample_dz, np, cd, vmr, robs[i]);
11289 }
11290
11291 /* Finalize...... */
11292 if (t == ctl->t_stop) {
11293
11294 /* Close output file... */
11295 fclose(out);
11296
11297 /* Free... */
11298 free(rt);
11299 free(rz);
11300 free(rlon);
11301 free(rlat);
11302 free(robs);
11303 }
11304}
11305
11306/*****************************************************************************/
11307
11309 const char *filename,
11310 const ctl_t *ctl,
11311 atm_t *atm,
11312 const double t) {
11313
11314 static FILE *out;
11315
11316 static double rmax2, x0[3], x1[3];
11317
11318 /* Set timer... */
11319 SELECT_TIMER("WRITE_STATION", "OUTPUT", NVTX_WRITE);
11320
11321 /* Init... */
11322 if (t == ctl->t_start) {
11323
11324 /* Write info... */
11325 LOG(1, "Write station data: %s", filename);
11326
11327 /* Create new file... */
11328 if (!(out = fopen(filename, "w")))
11329 ERRMSG("Cannot create file!");
11330
11331 /* Write header... */
11332 fprintf(out,
11333 "# $1 = time [s]\n"
11334 "# $2 = altitude [km]\n"
11335 "# $3 = longitude [deg]\n" "# $4 = latitude [deg]\n");
11336 for (int iq = 0; iq < ctl->nq; iq++)
11337 fprintf(out, "# $%i = %s [%s]\n", (iq + 5),
11338 ctl->qnt_name[iq], ctl->qnt_unit[iq]);
11339 fprintf(out, "\n");
11340
11341 /* Set geolocation and search radius... */
11342 geo2cart(0, ctl->stat_lon, ctl->stat_lat, x0);
11343 rmax2 = SQR(ctl->stat_r);
11344 }
11345
11346 /* Set time interval for output... */
11347 const double t0 = t - 0.5 * ctl->dt_mod;
11348 const double t1 = t + 0.5 * ctl->dt_mod;
11349
11350 /* Loop over air parcels... */
11351 for (int ip = 0; ip < atm->np; ip++) {
11352
11353 /* Check time... */
11354 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11355 continue;
11356
11357 /* Check time range for station output... */
11358 if (atm->time[ip] < ctl->stat_t0 || atm->time[ip] > ctl->stat_t1)
11359 continue;
11360
11361 /* Check station flag... */
11362 if (ctl->qnt_stat >= 0)
11363 if ((int) atm->q[ctl->qnt_stat][ip])
11364 continue;
11365
11366 /* Get Cartesian coordinates... */
11367 geo2cart(0, atm->lon[ip], atm->lat[ip], x1);
11368
11369 /* Check horizontal distance... */
11370 if (DIST2(x0, x1) > rmax2)
11371 continue;
11372
11373 /* Set station flag... */
11374 if (ctl->qnt_stat >= 0)
11375 atm->q[ctl->qnt_stat][ip] = 1;
11376
11377 /* Write data... */
11378 fprintf(out, "%.2f %g %g %g",
11379 atm->time[ip], Z(atm->p[ip]), atm->lon[ip], atm->lat[ip]);
11380 for (int iq = 0; iq < ctl->nq; iq++) {
11381 fprintf(out, " ");
11382 fprintf(out, ctl->qnt_format[iq], atm->q[iq][ip]);
11383 }
11384 fprintf(out, "\n");
11385 }
11386
11387 /* Close file... */
11388 if (t == ctl->t_stop)
11389 fclose(out);
11390}
11391
11392/*****************************************************************************/
11393
11395 const char *filename,
11396 const ctl_t *ctl,
11397 const atm_t *atm,
11398 const double t) {
11399
11400 FILE *out;
11401
11402 /* Set timer... */
11403 SELECT_TIMER("WRITE_VTK", "OUTPUT", NVTX_WRITE);
11404
11405 /* Write info... */
11406 LOG(1, "Write VTK data: %s", filename);
11407
11408 /* Set time interval for output... */
11409 const double t0 = t - 0.5 * ctl->dt_mod;
11410 const double t1 = t + 0.5 * ctl->dt_mod;
11411
11412 /* Create file... */
11413 if (!(out = fopen(filename, "w")))
11414 ERRMSG("Cannot create file!");
11415
11416 /* Count data points... */
11417 int np = 0;
11418 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11419 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11420 continue;
11421 np++;
11422 }
11423
11424 /* Write header... */
11425 fprintf(out,
11426 "# vtk DataFile Version 3.0\n"
11427 "vtk output\n" "ASCII\n" "DATASET POLYDATA\n");
11428
11429 /* Write point coordinates... */
11430 fprintf(out, "POINTS %d float\n", np);
11431 if (ctl->vtk_sphere) {
11432 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11433 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11434 continue;
11435 const double radius = (RE + Z(atm->p[ip]) * ctl->vtk_scale
11436 + ctl->vtk_offset) / RE;
11437 const double coslat = cos(DEG2RAD(atm->lat[ip]));
11438 const double x = radius * coslat * cos(DEG2RAD(atm->lon[ip]));
11439 const double y = radius * coslat * sin(DEG2RAD(atm->lon[ip]));
11440 const double z = radius * sin(DEG2RAD(atm->lat[ip]));
11441 fprintf(out, "%g %g %g\n", x, y, z);
11442 }
11443 } else
11444 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11445 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11446 continue;
11447 fprintf(out, "%g %g %g\n", atm->lon[ip], atm->lat[ip],
11448 Z(atm->p[ip]) * ctl->vtk_scale + ctl->vtk_offset);
11449 }
11450
11451 /* Write point data... */
11452 fprintf(out, "POINT_DATA %d\n", np);
11453 for (int iq = 0; iq < ctl->nq; iq++) {
11454 fprintf(out, "SCALARS %s float 1\n" "LOOKUP_TABLE default\n",
11455 ctl->qnt_name[iq]);
11456 for (int ip = 0; ip < atm->np; ip += ctl->vtk_stride) {
11457 if (atm->time[ip] < t0 || atm->time[ip] > t1)
11458 continue;
11459 fprintf(out, "%g\n", atm->q[iq][ip]);
11460 }
11461 }
11462
11463 /* Close file... */
11464 fclose(out);
11465}
void read_met_geopot(const ctl_t *ctl, met_t *met)
Calculates geopotential heights from meteorological data.
Definition: mptrac.c:6993
void mptrac_write_atm(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes air parcel data to a file in various formats.
Definition: mptrac.c:5677
void day2doy(const int year, const int mon, const int day, int *doy)
Get day of year from date.
Definition: mptrac.c:901
void read_met_extrapolate(met_t *met)
Extrapolates meteorological data.
Definition: mptrac.c:6953
void read_met_levels(const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological variables at different vertical levels from a NetCDF file.
Definition: mptrac.c:7255
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:7596
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:9500
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:10860
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:4193
void read_met_sample(const ctl_t *ctl, met_t *met)
Downsamples meteorological data based on specified parameters.
Definition: mptrac.c:8363
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:10621
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:8843
void module_advect(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Advances particle positions using different advection schemes.
Definition: mptrac.c:2085
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:3920
int mptrac_read_met(const char *filename, const ctl_t *ctl, const clim_t *clim, met_t *met)
Reads meteorological data from a file, supporting multiple formats and MPI broadcasting.
Definition: mptrac.c:5373
void module_meteo(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Update atmospheric properties using meteorological data.
Definition: mptrac.c:3236
void read_clim_photo(const char *filename, clim_photo_t *photo)
Reads photolysis rates from a NetCDF file and populates the given photolysis structure.
Definition: mptrac.c:6101
void read_met_cloud(met_t *met)
Calculates cloud-related variables for each grid point.
Definition: mptrac.c:6792
void module_decay(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, atm_t *atm)
Simulate exponential decay processes for atmospheric particles.
Definition: mptrac.c:2622
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:9016
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:1463
int read_atm_nc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a generic netCDF file and populates the given atmospheric structure.
Definition: mptrac.c:6068
void read_met_pbl(const ctl_t *ctl, met_t *met)
Computes the planetary boundary layer (PBL) pressure based on meteorological data.
Definition: mptrac.c:7971
void read_met_detrend(const ctl_t *ctl, met_t *met)
Detrends meteorological data.
Definition: mptrac.c:6849
int read_met_nc_2d(const int ncid, const char *varname, const char *varname2, const char *varname3, const char *varname4, const char *varname5, const char *varname6, const ctl_t *ctl, const met_t *met, float dest[EX][EY], const float scl, const int init)
Reads a 2-dimensional meteorological variable from a NetCDF file.
Definition: mptrac.c:7667
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:8671
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:8887
void module_chem_init(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Initializes the chemistry modules by setting atmospheric composition.
Definition: mptrac.c:2507
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:2046
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:1096
void mptrac_get_met(ctl_t *ctl, clim_t *clim, const double t, met_t **met0, met_t **met1)
Retrieves meteorological data for the specified time.
Definition: mptrac.c:4266
void read_met_monotonize(const ctl_t *ctl, met_t *met)
Makes zeta and pressure profiles monotone.
Definition: mptrac.c:7511
int read_clim_ts(const char *filename, clim_ts_t *ts)
Reads a climatological time series from a file and populates the given time series structure.
Definition: mptrac.c:6220
void read_met_periodic(met_t *met)
Applies periodic boundary conditions to meteorological data along longitudinal axis.
Definition: mptrac.c:8108
void module_timesteps_init(ctl_t *ctl, const atm_t *atm)
Initialize start time and time interval for time-stepping.
Definition: mptrac.c:3957
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:9969
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:3340
double clim_zm(const clim_zm_t *zm, const double t, const double lat, const double p)
Interpolates monthly mean zonal mean climatological variables.
Definition: mptrac.c:401
void read_clim_photo_help(const int ncid, const char *varname, const clim_photo_t *photo, double var[CP][CSZA][CO3])
Reads a 3D climatological photochemistry variable from a NetCDF file.
Definition: mptrac.c:6192
void read_met_ml2pl(const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname)
Interpolates meteorological data to specified pressure levels.
Definition: mptrac.c:7469
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:8915
void read_met_grid(const char *filename, const int ncid, const ctl_t *ctl, met_t *met)
Reads meteorological grid information from a NetCDF file.
Definition: mptrac.c:7121
void read_met_bin_2d(FILE *in, const met_t *met, float var[EX][EY], const char *varname)
Reads a 2-dimensional meteorological variable from a binary file and stores it in the provided array.
Definition: mptrac.c:6562
int locate_irr(const double *xx, const int n, const double x)
Locate the index of the interval containing a given value in a sorted array.
Definition: mptrac.c:1982
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:3061
void level_definitions(ctl_t *ctl)
Defines pressure levels for meteorological data.
Definition: mptrac.c:1776
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:1166
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:10257
void mptrac_update_device(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates device memory for specified data structures.
Definition: mptrac.c:5565
void time2jsec(const int year, const int mon, const int day, const int hour, const int min, const int sec, const double remain, double *jsec)
Converts time components to seconds since January 1, 2000, 12:00:00 UTC.
Definition: mptrac.c:9158
void mptrac_init(ctl_t *ctl, cache_t *cache, clim_t *clim, atm_t *atm, const int ntask)
Initializes the MPTRAC model and its associated components.
Definition: mptrac.c:4387
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:1521
void intpol_met_space_3d_ml(const met_t *met, float zs[EX][EY][EP], float array[EX][EY][EP], const double z, const double lon, const double lat, double *var)
Interpolates meteorological data in 3D space.
Definition: mptrac.c:1396
void fft_help(double *fcReal, double *fcImag, const int n)
Computes the Fast Fourier Transform (FFT) of a complex sequence.
Definition: mptrac.c:950
void module_wet_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Perform wet deposition calculations for air parcels.
Definition: mptrac.c:4058
void compress_pck(const char *varname, float *array, const size_t nxy, const size_t nz, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats.
Definition: mptrac.c:665
double nat_temperature(const double p, const double h2o, const double hno3)
Calculates the nitric acid trihydrate (NAT) temperature.
Definition: mptrac.c:5868
void spline(const double *x, const double *y, const int n, const double *x2, double *y2, const int n2, const int method)
Performs spline interpolation or linear interpolation.
Definition: mptrac.c:9049
void module_chem_grid(const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double tt)
Calculate grid data for chemistry modules.
Definition: mptrac.c:2360
double clim_photo(const double rate[CP][CSZA][CO3], const clim_photo_t *photo, const double p, const double sza, const double o3c)
Calculates the photolysis rate for a given set of atmospheric conditions.
Definition: mptrac.c:149
void read_clim_zm(const char *filename, const char *varname, clim_zm_t *zm)
Reads zonally averaged climatological data from a netCDF file and populates the given structure.
Definition: mptrac.c:6274
void module_sedi(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate sedimentation of particles in the atmosphere.
Definition: mptrac.c:3795
void timer(const char *name, const char *group, const int output)
Measures and reports elapsed time for named and grouped timers.
Definition: mptrac.c:9189
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:9315
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:1338
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:8535
void intpol_met_time_3d_ml(const met_t *met0, float zs0[EX][EY][EP], float array0[EX][EY][EP], const met_t *met1, float zs1[EX][EY][EP], float array1[EX][EY][EP], const double ts, const double p, const double lon, const double lat, double *var)
Interpolates meteorological data in both space and time.
Definition: mptrac.c:1550
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:2549
void read_kernel(const char *filename, double kz[EP], double kw[EP], int *nk)
Reads kernel function data from a file and populates the provided arrays.
Definition: mptrac.c:6373
void module_bound_cond(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Apply boundary conditions to particles based on meteorological and climatological data.
Definition: mptrac.c:2264
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:8944
void module_advect_init(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Initializes the advection module by setting up pressure fields.
Definition: mptrac.c:2237
void module_sort_help(double *a, const int *p, const int np)
Reorder an array based on a given permutation.
Definition: mptrac.c:3884
float stddev(const float *data, const int n)
Calculates the standard deviation of a set of data.
Definition: mptrac.c:9096
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:1608
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:7825
void read_met_bin_3d(FILE *in, const ctl_t *ctl, const met_t *met, float var[EX][EY][EP], const char *varname, const float bound_min, const float bound_max)
Reads 3D meteorological data from a binary file, potentially using different compression methods.
Definition: mptrac.c:6591
int locate_irr_float(const float *xx, const int n, const double x, const int ig)
Locate the index of the interval containing a given value in an irregularly spaced array.
Definition: mptrac.c:2012
double time_from_filename(const char *filename, const int offset)
Extracts and converts a timestamp from a filename to Julian seconds.
Definition: mptrac.c:9257
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:10919
void mptrac_read_clim(const ctl_t *ctl, clim_t *clim)
Reads various climatological data and populates the given climatology structure.
Definition: mptrac.c:4477
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:9292
void write_met_nc(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a NetCDF file.
Definition: mptrac.c:10697
void module_rng_init(const int ntask)
Initialize random number generators for parallel tasks.
Definition: mptrac.c:3659
int mptrac_read_atm(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a specified file into the given atmospheric structure.
Definition: mptrac.c:4406
void mptrac_update_host(const ctl_t *ctl, const cache_t *cache, const clim_t *clim, met_t **met0, met_t **met1, const atm_t *atm)
Updates host memory for specified data structures.
Definition: mptrac.c:5621
void mptrac_write_output(const char *dirname, const ctl_t *ctl, met_t *met0, met_t *met1, atm_t *atm, const double t)
Writes various types of output data to files in a specified directory.
Definition: mptrac.c:5777
double clim_oh(const ctl_t *ctl, const clim_t *clim, const double t, const double lon, const double lat, const double p)
Calculates the hydroxyl radical (OH) concentration from climatology data, with an optional diurnal co...
Definition: mptrac.c:89
void read_met_ozone(met_t *met)
Calculates the total column ozone from meteorological ozone data.
Definition: mptrac.c:8334
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:4240
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:3690
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:1007
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:11308
void cart2geo(const double *x, double *z, double *lon, double *lat)
State variables of cuRAND random number generator.
Definition: mptrac.c:74
double sza_calc(const double sec, const double lon, const double lat)
Calculates the solar zenith angle.
Definition: mptrac.c:9117
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:3430
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:920
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:1575
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:3608
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:2065
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:10592
void read_met_pv(met_t *met)
Calculates potential vorticity (PV) from meteorological data.
Definition: mptrac.c:8228
int read_atm_bin(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from a binary file and populates the given atmospheric structure.
Definition: mptrac.c:5956
void get_met_replace(char *orig, char *search, char *repl)
Replaces occurrences of a substring in a string with another substring.
Definition: mptrac.c:1072
void module_diff_meso(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate mesoscale diffusion for atmospheric particles.
Definition: mptrac.c:2661
void module_sort(const ctl_t *ctl, met_t *met0, atm_t *atm)
Sort particles according to box index.
Definition: mptrac.c:3824
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:1699
int read_met_bin(const char *filename, const ctl_t *ctl, met_t *met)
Reads meteorological data from a binary file.
Definition: mptrac.c:6414
void mptrac_run_timestep(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t **met0, met_t **met1, atm_t *atm, double t)
Executes a single timestep of the MPTRAC model simulation.
Definition: mptrac.c:5428
void write_atm_clams(const char *filename, const ctl_t *ctl, const atm_t *atm)
Writes air parcel data to a NetCDF file in the CLaMS format.
Definition: mptrac.c:9447
void module_diff_turb(const ctl_t *ctl, cache_t *cache, const clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
Applies turbulent diffusion processes to atmospheric particles.
Definition: mptrac.c:2863
int read_atm_clams(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads atmospheric data from a CLAMS NetCDF file.
Definition: mptrac.c:6012
void write_vtk(const char *filename, const ctl_t *ctl, const atm_t *atm, const double t)
Writes VTK (Visualization Toolkit) data to a specified file.
Definition: mptrac.c:11394
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:3988
void mptrac_read_ctl(const char *filename, int argc, char *argv[], ctl_t *ctl)
Reads control parameters from a configuration file and populates the given structure.
Definition: mptrac.c:4537
void read_met_polar_winds(met_t *met)
Applies a fix for polar winds in meteorological data.
Definition: mptrac.c:8169
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:2978
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:10361
double pbl_weight(const ctl_t *ctl, const atm_t *atm, const int ip, const double pbl, const double ps)
Computes a weighting factor based on planetary boundary layer pressure.
Definition: mptrac.c:5892
void module_diff_pbl(const ctl_t *ctl, cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Computes particle diffusion within the planetary boundary layer (PBL).
Definition: mptrac.c:2738
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:10889
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:3131
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:3524
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:989
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:1732
int read_atm_asc(const char *filename, const ctl_t *ctl, atm_t *atm)
Reads air parcel data from an ASCII file and populates the given atmospheric structure.
Definition: mptrac.c:5914
void intpol_check_lon_lat(const double *lons, const int nlon, const double *lats, const int nlat, const double lon, const double lat, double *lon2, double *lat2)
Adjusts longitude and latitude to ensure they fall within valid bounds.
Definition: mptrac.c:1139
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:11146
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:10066
void module_dry_depo(const ctl_t *ctl, const cache_t *cache, met_t *met0, met_t *met1, atm_t *atm)
Simulate dry deposition of atmospheric particles.
Definition: mptrac.c:2915
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:10491
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:9397
void read_met_cape(const ctl_t *ctl, const clim_t *clim, met_t *met)
Calculates Convective Available Potential Energy (CAPE) for each grid point.
Definition: mptrac.c:6677
void mptrac_write_met(const char *filename, const ctl_t *ctl, met_t *met)
Writes meteorological data to a file, supporting multiple formats and compression options.
Definition: mptrac.c:5737
double lapse_rate(const double t, const double h2o)
Calculates the moist adiabatic lapse rate in Kelvin per kilometer.
Definition: mptrac.c:1758
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:9707
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:9658
MPTRAC library declarations.
#define NN(x0, y0, x1, y1, x)
Perform nearest-neighbor interpolation.
Definition: mptrac.h:1243
void compress_zstd(const char *varname, float *array, const size_t n, const int decompress, const int level, FILE *inout)
Compresses or decompresses a float array using Zstandard (ZSTD).
#define LEN
Maximum length of ASCII data lines.
Definition: mptrac.h:252
#define RE
Mean radius of Earth [km].
Definition: mptrac.h:233
#define TVIRT(t, h2o)
Compute virtual temperature.
Definition: mptrac.h:1730
#define ARRAY_3D(ix, iy, ny, iz, nz)
Compute the linear index of a 3D array element.
Definition: mptrac.h:402
#define PARTICLE_LOOP(ip0, ip1, check_dt,...)
Loop over particle indices with OpenACC acceleration.
Definition: mptrac.h:1285
#define MA
Molar mass of dry air [g/mol].
Definition: mptrac.h:208
#define AVO
Avogadro constant [1/mol].
Definition: mptrac.h:168
#define KB
Boltzmann constant [kg m^2/(K s^2)].
Definition: mptrac.h:203
#define MH2O
Molar mass of water vapor [g/mol].
Definition: mptrac.h:213
#define NENS
Maximum number of data points for ensemble analysis.
Definition: mptrac.h:287
#define FWRITE(ptr, type, size, out)
Write data from memory to a file stream.
Definition: mptrac.h:678
#define PW(p, h2o)
Calculate partial water vapor pressure.
Definition: mptrac.h:1390
#define H0
Scale height [km].
Definition: mptrac.h:188
#define NC_PUT_ATT_GLOBAL(attname, text)
Add a global text attribute to a NetCDF file.
Definition: mptrac.h:1223
#define MOLEC_DENS(p, t)
Calculate the density of a gas molecule.
Definition: mptrac.h:1013
#define LAPSE(p1, t1, p2, t2)
Calculate lapse rate.
Definition: mptrac.h:851
#define NC(cmd)
Execute a NetCDF command and check for errors.
Definition: mptrac.h:1027
#define RA
Specific gas constant of dry air [J/(kg K)].
Definition: mptrac.h:228
#define KARMAN
Karman's constant.
Definition: mptrac.h:198
#define INTPOL_INIT
Initialize arrays for interpolation.
Definition: mptrac.h:693
#define MIN(a, b)
Macro to determine the minimum of two values.
Definition: mptrac.h:998
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: mptrac.h:1915
#define NC_PUT_INT(varname, ptr, hyperslab)
Write integer data to a NetCDF variable.
Definition: mptrac.h:1184
void compress_cms(const ctl_t *ctl, const char *varname, float *array, const size_t nx, const size_t ny, const size_t np, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using a custom multiscale compression algorithm.
void compress_zfp(const char *varname, float *array, const int nx, const int ny, const int nz, const int precision, const double tolerance, const int decompress, FILE *inout)
Compresses or decompresses a 3D array of floats using the ZFP library.
#define EY
Maximum number of latitudes for meteo data.
Definition: mptrac.h:282
#define SH(h2o)
Compute specific humidity from water vapor volume mixing ratio.
Definition: mptrac.h:1555
#define INTPOL_3D(var, init)
Perform 3D interpolation for a meteorological variable.
Definition: mptrac.h:724
#define NOBS
Maximum number of observation data points.
Definition: mptrac.h:292
#define NTHREADS
Maximum number of OpenMP threads.
Definition: mptrac.h:297
#define ARRAY_2D(ix, iy, ny)
Macro for computing the linear index of a 2D array element.
Definition: mptrac.h:383
#define Z(p)
Convert pressure to altitude.
Definition: mptrac.h:1752
#define P(z)
Compute pressure at given altitude.
Definition: mptrac.h:1315
#define LV
Latent heat of vaporization of water [J/kg].
Definition: mptrac.h:193
#define G0
Standard gravity [m/s^2].
Definition: mptrac.h:183
#define CP
Maximum number of pressure levels for climatological data.
Definition: mptrac.h:312
#define NQ
Maximum number of quantities per data point.
Definition: mptrac.h:262
#define FREAD(ptr, type, size, in)
Read data from a file stream and store it in memory.
Definition: mptrac.h:658
#define DX2DEG(dx, lat)
Convert a distance in kilometers to degrees longitude at a given latitude.
Definition: mptrac.h:536
#define DEG2DY(dlat)
Convert a latitude difference to a distance in the y-direction (north-south).
Definition: mptrac.h:472
#define EX
Maximum number of longitudes for meteo data.
Definition: mptrac.h:277
#define EPS
Ratio of the specific gas constant of dry air and water vapor [1].
Definition: mptrac.h:178
#define PSICE(t)
Compute saturation pressure over ice (WMO, 2018).
Definition: mptrac.h:1363
#define THETA(p, t)
Compute potential temperature.
Definition: mptrac.h:1655
#define RI
Ideal gas constant [J/(mol K)].
Definition: mptrac.h:238
#define NORM(a)
Compute the norm (magnitude) of a vector.
Definition: mptrac.h:1258
#define SET_QNT(qnt, name, longname, unit)
Set atmospheric quantity index.
Definition: mptrac.h:1534
#define TICE(p, h2o)
Calculate frost point temperature (WMO, 2018).
Definition: mptrac.h:1631
#define TOK(line, tok, format, var)
Get string tokens.
Definition: mptrac.h:1705
#define ZDIFF(lnp0, t0, h2o0, lnp1, t1, h2o1)
Calculate geopotential height difference.
Definition: mptrac.h:1783
#define THETAVIRT(p, t, h2o)
Compute virtual potential temperature.
Definition: mptrac.h:1684
#define DZ2DP(dz, p)
Convert a change in altitude to a change in pressure.
Definition: mptrac.h:573
#define WARN(...)
Print a warning message with contextual information.
Definition: mptrac.h:1882
#define ZETA(ps, p, t)
Computes the value of the zeta vertical coordinate.
Definition: mptrac.h:1802
#define RHICE(p, t, h2o)
Compute relative humidity over ice.
Definition: mptrac.h:1467
#define INTPOL_TIME_ALL(time, p, lon, lat)
Interpolate multiple meteorological variables in time.
Definition: mptrac.h:797
#define ALLOC(ptr, type, n)
Allocate memory for a pointer with error handling.
Definition: mptrac.h:360
#define SET_ATM(qnt, val)
Set atmospheric quantity value.
Definition: mptrac.h:1511
#define CTS
Maximum number of data points of climatological time series.
Definition: mptrac.h:327
#define DEG2RAD(deg)
Converts degrees to radians.
Definition: mptrac.h:489
void broadcast_large_data(void *data, size_t N)
Broadcasts large data across all processes in an MPI communicator.
#define MO3
Molar mass of ozone [g/mol].
Definition: mptrac.h:218
#define SQR(x)
Compute the square of a value.
Definition: mptrac.h:1568
#define RAD2DEG(rad)
Converts radians to degrees.
Definition: mptrac.h:1407
#define NC_INQ_DIM(dimname, ptr, min, max)
Inquire the length of a dimension in a NetCDF file.
Definition: mptrac.h:1114
#define NP
Maximum number of atmospheric data points.
Definition: mptrac.h:257
#define NTIMER
Maximum number of timers.
Definition: mptrac.h:1959
#define SELECT_TIMER(id, group, color)
Select and start a timer with specific attributes.
Definition: mptrac.h:1995
#define INTPOL_2D(var, init)
Perform 2D interpolation for a meteorological variable.
Definition: mptrac.h:707
#define RH(p, t, h2o)
Compute relative humidity over water.
Definition: mptrac.h:1437
#define NC_PUT_FLOAT(varname, ptr, hyperslab)
Write a float array to a NetCDF file.
Definition: mptrac.h:1161
#define CY
Maximum number of latitudes for climatological data.
Definition: mptrac.h:302
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: mptrac.h:1845
void thrustSortWrapper(double *__restrict__ c, int n, int *__restrict__ index)
Wrapper to Thrust sorting function.
#define NC_DEF_VAR(varname, type, ndims, dims, long_name, units, level, quant)
Define a NetCDF variable with attributes.
Definition: mptrac.h:1056
#define TDEW(p, h2o)
Calculate dew point temperature.
Definition: mptrac.h:1606
#define ARRHENIUS(a, b, t)
Calculate the Arrhenius rate constant.
Definition: mptrac.h:427
#define NCSI
Maximum number of data points for CSI calculation.
Definition: mptrac.h:267
#define NC_GET_DOUBLE(varname, ptr, force)
Retrieve a double-precision variable from a NetCDF file.
Definition: mptrac.h:1086
#define EP
Maximum number of pressure levels for meteo data.
Definition: mptrac.h:272
#define PSAT(t)
Compute saturation pressure over water.
Definition: mptrac.h:1339
#define RHO(p, t)
Compute density of air.
Definition: mptrac.h:1492
void module_kpp_chem(ctl_t *ctl, cache_t *cache, clim_t *clim, met_t *met0, met_t *met1, atm_t *atm)
KPP chemistry module.
#define CO3
Maximum number of total column ozone data for climatological data.
Definition: mptrac.h:307
#define NC_PUT_DOUBLE(varname, ptr, hyperslab)
Write double precision data to a NetCDF variable.
Definition: mptrac.h:1137
#define LIN(x0, y0, x1, y1, x)
Linear interpolation.
Definition: mptrac.h:870
#define DIST2(a, b)
Calculate the squared Euclidean distance between two points in Cartesian coordinates.
Definition: mptrac.h:605
#define DEG2DX(dlon, lat)
Convert a longitude difference to a distance in the x-direction (east-west) at a specific latitude.
Definition: mptrac.h:451
#define CPD
Specific heat of dry air at constant pressure [J/(kg K)].
Definition: mptrac.h:173
#define CSZA
Maximum number of solar zenith angles for climatological data.
Definition: mptrac.h:317
#define DY2DEG(dy)
Convert a distance in kilometers to degrees latitude.
Definition: mptrac.h:554
#define MAX(a, b)
Macro to determine the maximum of two values.
Definition: mptrac.h:897
#define FMOD(x, y)
Calculate the floating-point remainder of dividing x by y.
Definition: mptrac.h:640
Air parcel data.
Definition: mptrac.h:3163
double time[NP]
Time [s].
Definition: mptrac.h:3169
double lat[NP]
Latitude [deg].
Definition: mptrac.h:3178
double lon[NP]
Longitude [deg].
Definition: mptrac.h:3175
int np
Number of air parcels.
Definition: mptrac.h:3166
double q[NQ][NP]
Quantity data (for various, user-defined attributes).
Definition: mptrac.h:3181
double p[NP]
Pressure [hPa].
Definition: mptrac.h:3172
Cache data structure.
Definition: mptrac.h:3191
double dt[NP]
Timesteps [s].
Definition: mptrac.h:3212
double iso_ts[NP]
Isosurface balloon time [s].
Definition: mptrac.h:3200
int iso_n
Isosurface balloon number of data points.
Definition: mptrac.h:3203
double iso_ps[NP]
Isosurface balloon pressure [hPa].
Definition: mptrac.h:3197
double rs[3 *NP+1]
Random numbers.
Definition: mptrac.h:3209
float uvwp[NP][3]
Wind perturbations [m/s].
Definition: mptrac.h:3206
double iso_var[NP]
Isosurface variables.
Definition: mptrac.h:3194
Climatological data in the form of photolysis rates.
Definition: mptrac.h:3223
int nsza
Number of solar zenith angles.
Definition: mptrac.h:3229
double sza[CSZA]
Solar zenith angle [rad].
Definition: mptrac.h:3238
double o3_1[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O1d + O2) [1/s].
Definition: mptrac.h:3259
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3235
double ccl2f2[CP][CSZA][CO3]
CCl2F2 photolysis rate [1/s].
Definition: mptrac.h:3253
double o2[CP][CSZA][CO3]
O2 photolysis rate [1/s].
Definition: mptrac.h:3256
double ccl3f[CP][CSZA][CO3]
CCl3F photolysis rate [1/s].
Definition: mptrac.h:3250
double n2o[CP][CSZA][CO3]
N2O photolysis rate [1/s].
Definition: mptrac.h:3244
double h2o2[CP][CSZA][CO3]
H2O2 photolysis rate [1/s].
Definition: mptrac.h:3265
double h2o[CP][CSZA][CO3]
H2O photolysis rate [1/s].
Definition: mptrac.h:3268
double ccl4[CP][CSZA][CO3]
CCl4 photolysis rate [1/s].
Definition: mptrac.h:3247
double o3_2[CP][CSZA][CO3]
O3 photolysis rate (O3 + hv = O3p + O2) [1/s].
Definition: mptrac.h:3262
double o3c[CO3]
Total column ozone [DU].
Definition: mptrac.h:3241
int np
Number of pressure levels.
Definition: mptrac.h:3226
int no3c
Number of total ozone columns.
Definition: mptrac.h:3232
Climatological data.
Definition: mptrac.h:3331
clim_ts_t ccl2f2
CFC-12 time series.
Definition: mptrac.h:3373
clim_photo_t photo
Photolysis rates.
Definition: mptrac.h:3349
clim_zm_t ho2
HO2 zonal means.
Definition: mptrac.h:3361
clim_zm_t hno3
HNO3 zonal means.
Definition: mptrac.h:3352
int tropo_ntime
Number of tropopause timesteps.
Definition: mptrac.h:3334
clim_ts_t sf6
SF6 time series.
Definition: mptrac.h:3379
clim_ts_t ccl4
CFC-10 time series.
Definition: mptrac.h:3367
clim_ts_t ccl3f
CFC-11 time series.
Definition: mptrac.h:3370
clim_zm_t o1d
O(1D) zonal means.
Definition: mptrac.h:3364
double tropo_lat[73]
Tropopause latitudes [deg].
Definition: mptrac.h:3343
clim_zm_t h2o2
H2O2 zonal means.
Definition: mptrac.h:3358
int tropo_nlat
Number of tropopause latitudes.
Definition: mptrac.h:3337
clim_zm_t oh
OH zonal means.
Definition: mptrac.h:3355
double tropo[12][73]
Tropopause pressure values [hPa].
Definition: mptrac.h:3346
double tropo_time[12]
Tropopause time steps [s].
Definition: mptrac.h:3340
clim_ts_t n2o
N2O time series.
Definition: mptrac.h:3376
Climatological data in the form of time series.
Definition: mptrac.h:3279
double vmr[CTS]
Volume mixing ratio [ppv].
Definition: mptrac.h:3288
double time[CTS]
Time [s].
Definition: mptrac.h:3285
int ntime
Number of timesteps.
Definition: mptrac.h:3282
Climatological data in the form of zonal means.
Definition: mptrac.h:3299
double time[CT]
Time [s].
Definition: mptrac.h:3311
int np
Number of pressure levels.
Definition: mptrac.h:3308
double p[CP]
Pressure [hPa].
Definition: mptrac.h:3317
double vmr[CT][CP][CY]
Volume mixing ratio [ppv].
Definition: mptrac.h:3320
int ntime
Number of timesteps.
Definition: mptrac.h:3302
int nlat
Number of latitudes.
Definition: mptrac.h:3305
double lat[CY]
Latitude [deg].
Definition: mptrac.h:3314
Control parameters.
Definition: mptrac.h:2169
double grid_z0
Lower altitude of gridded data [km].
Definition: mptrac.h:3043
int qnt_o3
Quantity array index for ozone volume mixing ratio.
Definition: mptrac.h:2281
double csi_lat1
Upper latitude of gridded CSI data [deg].
Definition: mptrac.h:3007
char csi_obsfile[LEN]
Observation data file for CSI analysis.
Definition: mptrac.h:2974
int qnt_Coh
Quantity array index for OH volume mixing ratio (chemistry code).
Definition: mptrac.h:2428
double wet_depo_ic_a
Coefficient A for wet deposition in cloud (exponential form).
Definition: mptrac.h:2895
int met_nc_scale
Check netCDF scaling factors (0=no, 1=yes).
Definition: mptrac.h:2500
int qnt_pel
Quantity array index for pressure at equilibrium level (EL).
Definition: mptrac.h:2314
int csi_nz
Number of altitudes of gridded CSI data.
Definition: mptrac.h:2983
double molmass
Molar mass [g/mol].
Definition: mptrac.h:2757
int qnt_p
Quantity array index for pressure.
Definition: mptrac.h:2260
int qnt_Cccl2f2
Quantity array index for CFC-12 volume mixing ratio (chemistry code).
Definition: mptrac.h:2452
char atm_gpfile[LEN]
Gnuplot file for atmospheric data.
Definition: mptrac.h:2935
int mixing_nx
Number of longitudes of mixing grid.
Definition: mptrac.h:2820
double chemgrid_z1
Upper altitude of chemistry grid [km].
Definition: mptrac.h:2844
char qnt_format[NQ][LEN]
Quantity output format.
Definition: mptrac.h:2188
int qnt_m
Quantity array index for mass.
Definition: mptrac.h:2200
int qnt_aoa
Quantity array index for age of air.
Definition: mptrac.h:2461
int qnt_rhop
Quantity array index for particle density.
Definition: mptrac.h:2209
int qnt_swc
Quantity array index for cloud snow water content.
Definition: mptrac.h:2293
double csi_obsmin
Minimum observation index to trigger detection.
Definition: mptrac.h:2977
int qnt_pcb
Quantity array index for cloud bottom pressure.
Definition: mptrac.h:2302
char clim_n2o_timeseries[LEN]
Filename of N2O time series.
Definition: mptrac.h:2796
double bound_dzs
Boundary conditions surface layer depth [km].
Definition: mptrac.h:2745
double csi_lon1
Upper longitude of gridded CSI data [deg].
Definition: mptrac.h:2998
int qnt_u
Quantity array index for zonal wind.
Definition: mptrac.h:2269
double stat_lon
Longitude of station [deg].
Definition: mptrac.h:3121
double mixing_trop
Interparcel exchange parameter for mixing in the troposphere.
Definition: mptrac.h:2805
double sort_dt
Time step for sorting of particle data [s].
Definition: mptrac.h:2656
double mixing_z1
Upper altitude of mixing grid [km].
Definition: mptrac.h:2817
double stat_r
Search radius around station [km].
Definition: mptrac.h:3127
double wet_depo_bc_a
Coefficient A for wet deposition below cloud (exponential form).
Definition: mptrac.h:2889
int met_zstd_level
ZSTD compression level (from -5 to 22).
Definition: mptrac.h:2509
int csi_ny
Number of latitudes of gridded CSI data.
Definition: mptrac.h:3001
int vtk_sphere
Spherical projection for VTK data (0=no, 1=yes).
Definition: mptrac.h:3151
double chemgrid_z0
Lower altitude of chemistry grid [km].
Definition: mptrac.h:2841
double met_pbl_min
Minimum depth of planetary boundary layer [km].
Definition: mptrac.h:2624
int qnt_iwc
Quantity array index for cloud ice water content.
Definition: mptrac.h:2290
double chemgrid_lat0
Lower latitude of chemistry grid [deg].
Definition: mptrac.h:2859
double conv_cape
CAPE threshold for convection module [J/kg].
Definition: mptrac.h:2709
int qnt_Co1d
Quantity array index for O(1D) volume mixing ratio (chemistry code).
Definition: mptrac.h:2440
double met_cms_eps_pv
cmultiscale compression epsilon for potential vorticity.
Definition: mptrac.h:2546
int qnt_pw
Quantity array index for partial water vapor pressure.
Definition: mptrac.h:2368
char prof_basename[LEN]
Basename for profile output file.
Definition: mptrac.h:3070
double grid_z1
Upper altitude of gridded data [km].
Definition: mptrac.h:3046
int direction
Direction flag (1=forward calculation, -1=backward calculation).
Definition: mptrac.h:2464
char balloon[LEN]
Balloon position filename.
Definition: mptrac.h:2663
int qnt_Cccl4
Quantity array index for CFC-10 volume mixing ratio (chemistry code).
Definition: mptrac.h:2446
int met_dp
Stride for pressure levels.
Definition: mptrac.h:2576
double met_dt_out
Time step for sampling of meteo data along trajectories [s].
Definition: mptrac.h:2643
int qnt_h2o2
Quantity array index for H2O2 volume mixing ratio (climatology).
Definition: mptrac.h:2332
int qnt_vh
Quantity array index for horizontal wind.
Definition: mptrac.h:2395
char species[LEN]
Species.
Definition: mptrac.h:2754
int csi_nx
Number of longitudes of gridded CSI data.
Definition: mptrac.h:2992
double csi_lat0
Lower latitude of gridded CSI data [deg].
Definition: mptrac.h:3004
double turb_dz_trop
Vertical turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2691
int met_pbl
Planetary boundary layer data (0=file, 1=z2p, 2=Richardson, 3=theta).
Definition: mptrac.h:2621
int qnt_lwc
Quantity array index for cloud liquid water content.
Definition: mptrac.h:2284
double turb_mesoz
Vertical scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2700
int grid_nc_level
zlib compression level of netCDF grid data files (0=off).
Definition: mptrac.h:3031
int grid_nx
Number of longitudes of gridded data.
Definition: mptrac.h:3049
int atm_type
Type of atmospheric data files (0=ASCII, 1=binary, 2=netCDF, 3=CLaMS_traj, 4=CLaMS_pos).
Definition: mptrac.h:2948
double bound_mass
Boundary conditions mass per particle [kg].
Definition: mptrac.h:2718
double grid_lat0
Lower latitude of gridded data [deg].
Definition: mptrac.h:3061
int qnt_ts
Quantity array index for surface temperature.
Definition: mptrac.h:2215
int qnt_loss_rate
Quantity array index for total loss rate.
Definition: mptrac.h:2359
double met_cms_eps_h2o
cmultiscale compression epsilon for water vapor.
Definition: mptrac.h:2549
int qnt_plfc
Quantity array index for pressure at level of free convection (LCF).
Definition: mptrac.h:2311
double grid_lon0
Lower longitude of gridded data [deg].
Definition: mptrac.h:3052
int qnt_o1d
Quantity array index for O(1D) volume mixing ratio (climatology).
Definition: mptrac.h:2338
int met_tropo_spline
Tropopause interpolation method (0=linear, 1=spline).
Definition: mptrac.h:2640
char sample_kernel[LEN]
Kernel data file for sample output.
Definition: mptrac.h:3106
int qnt_tvirt
Quantity array index for virtual temperature.
Definition: mptrac.h:2389
double dt_met
Time step of meteo data [s].
Definition: mptrac.h:2483
char clim_ho2_filename[LEN]
Filename of HO2 climatology.
Definition: mptrac.h:2778
double chemgrid_lat1
Upper latitude of chemistry grid [deg].
Definition: mptrac.h:2862
int met_geopot_sy
Latitudinal smoothing of geopotential heights.
Definition: mptrac.h:2612
char grid_gpfile[LEN]
Gnuplot file for gridded data.
Definition: mptrac.h:3022
double met_cms_eps_u
cmultiscale compression epsilon for zonal wind.
Definition: mptrac.h:2537
double turb_dx_strat
Horizontal turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2685
int qnt_vmr
Quantity array index for volume mixing ratio.
Definition: mptrac.h:2203
int qnt_lsm
Quantity array index for land-sea mask.
Definition: mptrac.h:2236
int qnt_theta
Quantity array index for potential temperature.
Definition: mptrac.h:2380
double bound_lat1
Boundary conditions maximum longitude [deg].
Definition: mptrac.h:2733
double stat_t1
Stop time for station output [s].
Definition: mptrac.h:3133
char csi_kernel[LEN]
Kernel data file for CSI output.
Definition: mptrac.h:2968
double turb_dx_trop
Horizontal turbulent diffusion coefficient (troposphere) [m^2/s].
Definition: mptrac.h:2682
int grid_type
Type of grid data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:3067
double csi_lon0
Lower longitude of gridded CSI data [deg].
Definition: mptrac.h:2995
int qnt_pbl
Quantity array index for boundary layer pressure.
Definition: mptrac.h:2242
double oh_chem[4]
Coefficients for OH reaction rate (A, E/R or k0, n, kinf, m).
Definition: mptrac.h:2868
int grid_stddev
Include standard deviations in grid output (0=no, 1=yes).
Definition: mptrac.h:3037
int qnt_psice
Quantity array index for saturation pressure over ice.
Definition: mptrac.h:2365
double chemgrid_lon0
Lower longitude of chemistry grid [deg].
Definition: mptrac.h:2850
int bound_pbl
Boundary conditions planetary boundary layer (0=no, 1=yes).
Definition: mptrac.h:2751
int qnt_mloss_wet
Quantity array index for total mass loss due to wet deposition.
Definition: mptrac.h:2350
int met_geopot_sx
Longitudinal smoothing of geopotential heights.
Definition: mptrac.h:2609
int met_sy
Smoothing for latitudes.
Definition: mptrac.h:2582
int qnt_ps
Quantity array index for surface pressure.
Definition: mptrac.h:2212
int rng_type
Random number generator (0=GSL, 1=Squares, 2=cuRAND).
Definition: mptrac.h:2673
char prof_obsfile[LEN]
Observation data file for profile output.
Definition: mptrac.h:3073
int isosurf
Isosurface parameter (0=none, 1=pressure, 2=density, 3=theta, 4=balloon).
Definition: mptrac.h:2660
double bound_p1
Boundary conditions top pressure [hPa].
Definition: mptrac.h:2739
int qnt_zs
Quantity array index for surface geopotential height.
Definition: mptrac.h:2218
int prof_nz
Number of altitudes of gridded profile data.
Definition: mptrac.h:3076
double csi_dt_out
Time step for CSI output [s].
Definition: mptrac.h:2971
int met_cape
Convective available potential energy data (0=file, 1=calculate).
Definition: mptrac.h:2618
double csi_modmin
Minimum column density to trigger detection [kg/m^2].
Definition: mptrac.h:2980
int met_sx
Smoothing for longitudes.
Definition: mptrac.h:2579
double chemgrid_lon1
Upper longitude of chemistry grid [deg].
Definition: mptrac.h:2853
double turb_mesox
Horizontal scaling factor for mesoscale wind fluctuations.
Definition: mptrac.h:2697
double met_cms_eps_iwc
cmultiscale compression epsilon for cloud ice water content.
Definition: mptrac.h:2561
double met_cms_eps_swc
cmultiscale compression epsilon for cloud snow water content.
Definition: mptrac.h:2564
char grid_kernel[LEN]
Kernel data file for grid output.
Definition: mptrac.h:3019
int met_zfp_prec
ZFP compression precision for all variables, except z and T.
Definition: mptrac.h:2512
double met_cms_eps_v
cmultiscale compression epsilon for meridional wind.
Definition: mptrac.h:2540
double prof_z0
Lower altitude of gridded profile data [km].
Definition: mptrac.h:3079
int qnt_w
Quantity array index for vertical velocity.
Definition: mptrac.h:2275
double bound_vmr
Boundary conditions volume mixing ratio [ppv].
Definition: mptrac.h:2724
double met_tropo_pv
Dynamical tropopause potential vorticity threshold [PVU].
Definition: mptrac.h:2634
int prof_nx
Number of longitudes of gridded profile data.
Definition: mptrac.h:3085
int qnt_stat
Quantity array index for station flag.
Definition: mptrac.h:2197
int met_tropo
Tropopause definition (0=none, 1=clim, 2=cold point, 3=WMO_1st, 4=WMO_2nd, 5=dynamical).
Definition: mptrac.h:2631
int qnt_rp
Quantity array index for particle radius.
Definition: mptrac.h:2206
int met_mpi_share
Use MPI to share meteo (0=no, 1=yes).
Definition: mptrac.h:2649
double mixing_strat
Interparcel exchange parameter for mixing in the stratosphere.
Definition: mptrac.h:2808
int qnt_vz
Quantity array index for vertical velocity.
Definition: mptrac.h:2398
int qnt_ho2
Quantity array index for HO2 volume mixing ratio (climatology).
Definition: mptrac.h:2335
double csi_z1
Upper altitude of gridded CSI data [km].
Definition: mptrac.h:2989
double stat_t0
Start time for station output [s].
Definition: mptrac.h:3130
double oh_chem_beta
Beta parameter for diurnal variablity of OH.
Definition: mptrac.h:2871
char clim_o1d_filename[LEN]
Filename of O(1D) climatology.
Definition: mptrac.h:2781
char clim_photo[LEN]
Filename of photolysis rates climatology.
Definition: mptrac.h:2766
double wet_depo_so2_ph
pH value used to calculate effective Henry constant of SO2.
Definition: mptrac.h:2907
double mixing_z0
Lower altitude of mixing grid [km].
Definition: mptrac.h:2814
int qnt_mloss_decay
Quantity array index for total mass loss due to exponential decay.
Definition: mptrac.h:2356
int atm_type_out
Type of atmospheric data files for output (-1=same as ATM_TYPE, 0=ASCII, 1=binary,...
Definition: mptrac.h:2953
int met_nlev
Number of meteo data model levels.
Definition: mptrac.h:2600
double dt_kpp
Time step for KPP chemistry [s].
Definition: mptrac.h:2880
char csi_basename[LEN]
Basename of CSI data files.
Definition: mptrac.h:2965
double dry_depo_dp
Dry deposition surface layer [hPa].
Definition: mptrac.h:2916
int qnt_shf
Quantity array index for surface sensible heat flux.
Definition: mptrac.h:2233
int qnt_vs
Quantity array index for surface meridional wind.
Definition: mptrac.h:2224
int qnt_Cco
Quantity array index for CO volume mixing ratio (chemistry code).
Definition: mptrac.h:2425
double vtk_dt_out
Time step for VTK data output [s].
Definition: mptrac.h:3139
double t_stop
Stop time of simulation [s].
Definition: mptrac.h:2470
double conv_dt
Time interval for convection module [s].
Definition: mptrac.h:2715
char sample_obsfile[LEN]
Observation data file for sample output.
Definition: mptrac.h:3109
int qnt_hno3
Quantity array index for HNO3 volume mixing ratio (climatology).
Definition: mptrac.h:2326
char grid_basename[LEN]
Basename of grid data files.
Definition: mptrac.h:3016
int met_clams
Read MPTRAC or CLaMS meteo data (0=MPTRAC, 1=CLaMS).
Definition: mptrac.h:2497
int qnt_h2ot
Quantity array index for tropopause water vapor volume mixing ratio.
Definition: mptrac.h:2254
int qnt_rh
Quantity array index for relative humidity over water.
Definition: mptrac.h:2374
double met_cms_eps_cc
cmultiscale compression epsilon for cloud cover.
Definition: mptrac.h:2567
double bound_lat0
Boundary conditions minimum longitude [deg].
Definition: mptrac.h:2730
double met_pbl_max
Maximum depth of planetary boundary layer [km].
Definition: mptrac.h:2627
int met_dx
Stride for longitudes.
Definition: mptrac.h:2570
int mixing_ny
Number of latitudes of mixing grid.
Definition: mptrac.h:2829
int met_convention
Meteo data layout (0=[lev, lat, lon], 1=[lon, lat, lev]).
Definition: mptrac.h:2486
int qnt_zeta_d
Quantity array index for diagnosed zeta vertical coordinate.
Definition: mptrac.h:2386
char clim_h2o2_filename[LEN]
Filename of H2O2 climatology.
Definition: mptrac.h:2775
int tracer_chem
Switch for first order tracer chemistry module (0=off, 1=on).
Definition: mptrac.h:2883
double dt_mod
Time step of simulation [s].
Definition: mptrac.h:2473
int diffusion
Diffusion scheme (0=off, 1=fixed-K, 2=PBL).
Definition: mptrac.h:2676
int qnt_tnat
Quantity array index for T_NAT.
Definition: mptrac.h:2413
int qnt_tice
Quantity array index for T_ice.
Definition: mptrac.h:2407
int qnt_zg
Quantity array index for geopotential height.
Definition: mptrac.h:2257
double vtk_offset
Vertical offset for VTK data [km].
Definition: mptrac.h:3148
int qnt_v
Quantity array index for meridional wind.
Definition: mptrac.h:2272
int qnt_mloss_dry
Quantity array index for total mass loss due to dry deposition.
Definition: mptrac.h:2353
double bound_vmr_trend
Boundary conditions volume mixing ratio trend [ppv/s].
Definition: mptrac.h:2727
int met_cache
Preload meteo data into disk cache (0=no, 1=yes).
Definition: mptrac.h:2646
int qnt_oh
Quantity array index for OH volume mixing ratio (climatology).
Definition: mptrac.h:2329
char qnt_unit[NQ][LEN]
Quantity units.
Definition: mptrac.h:2185
int qnt_Ch
Quantity array index for H volume mixing ratio (chemistry code).
Definition: mptrac.h:2431
int met_press_level_def
Use predefined pressure levels or not.
Definition: mptrac.h:2597
int oh_chem_reaction
Reaction type for OH chemistry (0=none, 2=bimolecular, 3=termolecular).
Definition: mptrac.h:2865
int qnt_h2o
Quantity array index for water vapor volume mixing ratio.
Definition: mptrac.h:2278
int prof_ny
Number of latitudes of gridded profile data.
Definition: mptrac.h:3094
int qnt_rhice
Quantity array index for relative humidity over ice.
Definition: mptrac.h:2377
int qnt_rho
Quantity array index for density of air.
Definition: mptrac.h:2266
double sample_dz
Layer depth for sample output [km].
Definition: mptrac.h:3115
double tdec_strat
Life time of particles in the stratosphere [s].
Definition: mptrac.h:2763
int obs_type
Type of observation data files (0=ASCII, 1=netCDF).
Definition: mptrac.h:2962
int grid_nc_quant[NQ]
Number of digits for quantization of netCDF grid data files (0=off).
Definition: mptrac.h:3034
double met_cms_eps_lwc
cmultiscale compression epsilon for cloud liquid water content.
Definition: mptrac.h:2555
int qnt_us
Quantity array index for surface zonal wind.
Definition: mptrac.h:2221
double met_cms_eps_z
cmultiscale compression epsilon for geopotential height.
Definition: mptrac.h:2531
double grid_lon1
Upper longitude of gridded data [deg].
Definition: mptrac.h:3055
int qnt_Cn2o
Quantity array index for N2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2455
int qnt_Cccl3f
Quantity array index for CFC-11 volume mixing ratio (chemistry code).
Definition: mptrac.h:2449
char qnt_name[NQ][LEN]
Quantity names.
Definition: mptrac.h:2179
char atm_basename[LEN]
Basename of atmospheric data files.
Definition: mptrac.h:2932
double mixing_lat0
Lower latitude of mixing grid [deg].
Definition: mptrac.h:2832
int qnt_pt
Quantity array index for tropopause pressure.
Definition: mptrac.h:2245
int qnt_cl
Quantity array index for total column cloud water.
Definition: mptrac.h:2305
int advect
Advection scheme (0=off, 1=Euler, 2=midpoint, 4=Runge-Kutta).
Definition: mptrac.h:2666
double prof_z1
Upper altitude of gridded profile data [km].
Definition: mptrac.h:3082
double met_lev_hyam[EP]
Meteo data model level a coefficients.
Definition: mptrac.h:2603
int qnt_t
Quantity array index for temperature.
Definition: mptrac.h:2263
int atm_filter
Time filter for atmospheric data output (0=none, 1=missval, 2=remove).
Definition: mptrac.h:2941
int kpp_chem
Switch for KPP chemistry module (0=off, 1=on).
Definition: mptrac.h:2877
int qnt_zeta
Quantity array index for zeta vertical coordinate.
Definition: mptrac.h:2383
double conv_pbl_trans
Depth of PBL transition layer (fraction of PBL depth).
Definition: mptrac.h:2706
char ens_basename[LEN]
Basename of ensemble data file.
Definition: mptrac.h:3010
double wet_depo_pre[2]
Coefficients for precipitation calculation.
Definition: mptrac.h:2886
int met_vert_coord
Vertical coordinate of input meteo data (0=plev, 1=mlev_p_file, 2=mlev_ab_file, 3=mlev_ab_full,...
Definition: mptrac.h:2490
double csi_z0
Lower altitude of gridded CSI data [km].
Definition: mptrac.h:2986
int qnt_lapse
Quantity array index for lapse rate.
Definition: mptrac.h:2392
double stat_lat
Latitude of station [deg].
Definition: mptrac.h:3124
int qnt_Cho2
Quantity array index for HO2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2434
double wet_depo_bc_h[2]
Coefficients for wet deposition below cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2904
int grid_ny
Number of latitudes of gridded data.
Definition: mptrac.h:3058
int qnt_Csf6
Quantity array index for SF6 volume mixing ratio (chemistry code).
Definition: mptrac.h:2458
int qnt_Ch2o
Quantity array index for H2O volume mixing ratio (chemistry code).
Definition: mptrac.h:2419
double met_detrend
FWHM of horizontal Gaussian used for detrending [km].
Definition: mptrac.h:2588
int conv_mix_pbl
Vertical mixing in the PBL (0=off, 1=on).
Definition: mptrac.h:2703
char metbase[LEN]
Basename for meteo data.
Definition: mptrac.h:2480
double bound_dps
Boundary conditions surface layer depth [hPa].
Definition: mptrac.h:2742
double met_cms_eps_t
cmultiscale compression epsilon for temperature.
Definition: mptrac.h:2534
int chemgrid_nz
Number of altitudes of chemistry grid.
Definition: mptrac.h:2838
int qnt_cape
Quantity array index for convective available potential energy (CAPE).
Definition: mptrac.h:2317
double bound_mass_trend
Boundary conditions mass per particle trend [kg/s].
Definition: mptrac.h:2721
int mixing_nz
Number of altitudes of mixing grid.
Definition: mptrac.h:2811
int qnt_o3c
Quantity array index for total column ozone.
Definition: mptrac.h:2323
double bound_p0
Boundary conditions bottom pressure [hPa].
Definition: mptrac.h:2736
double mixing_lon0
Lower longitude of mixing grid [deg].
Definition: mptrac.h:2823
char clim_ccl4_timeseries[LEN]
Filename of CFC-10 time series.
Definition: mptrac.h:2787
int qnt_Co3
Quantity array index for O3 volume mixing ratio (chemistry code).
Definition: mptrac.h:2422
int qnt_tsts
Quantity array index for T_STS.
Definition: mptrac.h:2410
int grid_nz
Number of altitudes of gridded data.
Definition: mptrac.h:3040
char clim_oh_filename[LEN]
Filename of OH climatology.
Definition: mptrac.h:2772
int qnt_nss
Quantity array index for northward turbulent surface stress.
Definition: mptrac.h:2230
double ens_dt_out
Time step for ensemble output [s].
Definition: mptrac.h:3013
char sample_basename[LEN]
Basename of sample data file.
Definition: mptrac.h:3103
int atm_stride
Particle index stride for atmospheric data files.
Definition: mptrac.h:2944
int met_relhum
Try to read relative humidity (0=no, 1=yes).
Definition: mptrac.h:2615
double mixing_lat1
Upper latitude of mixing grid [deg].
Definition: mptrac.h:2835
double atm_dt_out
Time step for atmospheric data output [s].
Definition: mptrac.h:2938
char clim_sf6_timeseries[LEN]
Filename of SF6 time series.
Definition: mptrac.h:2799
double prof_lat1
Upper latitude of gridded profile data [deg].
Definition: mptrac.h:3100
int met_cms_batch
cmultiscale batch size.
Definition: mptrac.h:2521
double psc_h2o
H2O volume mixing ratio for PSC analysis.
Definition: mptrac.h:2922
int met_sp
Smoothing for pressure levels.
Definition: mptrac.h:2585
double prof_lon0
Lower longitude of gridded profile data [deg].
Definition: mptrac.h:3088
int chemgrid_nx
Number of longitudes of chemistry grid.
Definition: mptrac.h:2847
int qnt_pct
Quantity array index for cloud top pressure.
Definition: mptrac.h:2299
int qnt_mloss_kpp
Quantity array index for total mass loss due to KPP chemistry.
Definition: mptrac.h:2347
int qnt_psat
Quantity array index for saturation pressure over water.
Definition: mptrac.h:2362
double met_lev_hybm[EP]
Meteo data model level b coefficients.
Definition: mptrac.h:2606
double prof_lat0
Lower latitude of gridded profile data [deg].
Definition: mptrac.h:3097
int qnt_cin
Quantity array index for convective inhibition (CIN).
Definition: mptrac.h:2320
double psc_hno3
HNO3 volume mixing ratio for PSC analysis.
Definition: mptrac.h:2925
double prof_lon1
Upper longitude of gridded profile data [deg].
Definition: mptrac.h:3091
double met_cms_eps_rwc
cmultiscale compression epsilon for cloud rain water content.
Definition: mptrac.h:2558
int met_nc_quant
Number of digits for quantization of netCDF meteo files (0=off).
Definition: mptrac.h:2506
int h2o2_chem_reaction
Reaction type for H2O2 chemistry (0=none, 1=SO2).
Definition: mptrac.h:2874
int qnt_Co3p
Quantity array index for O(3P) volume mixing ratio (chemistry code).
Definition: mptrac.h:2443
int atm_nc_quant[NQ]
Number of digits for quantization of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2959
double wet_depo_bc_ret_ratio
Coefficients for wet deposition below cloud: retention ratio.
Definition: mptrac.h:2913
int chemgrid_ny
Number of latitudes of chemistry grid.
Definition: mptrac.h:2856
char clim_ccl3f_timeseries[LEN]
Filename of CFC-11 time series.
Definition: mptrac.h:2790
double met_cms_eps_o3
cmultiscale compression epsilon for ozone.
Definition: mptrac.h:2552
int met_cms_zstd
cmultiscale zstd compression (0=off, 1=on).
Definition: mptrac.h:2524
int grid_sparse
Sparse output in grid data files (0=no, 1=yes).
Definition: mptrac.h:3028
char vtk_basename[LEN]
Basename of VTK data files.
Definition: mptrac.h:3136
double dry_depo_vdep
Dry deposition velocity [m/s].
Definition: mptrac.h:2919
int qnt_tt
Quantity array index for tropopause temperature.
Definition: mptrac.h:2248
int met_np
Number of target pressure levels.
Definition: mptrac.h:2591
int qnt_ens
Quantity array index for ensemble IDs.
Definition: mptrac.h:2194
int met_nc_level
zlib compression level of netCDF meteo files (0=off).
Definition: mptrac.h:2503
double met_zfp_tol_t
ZFP compression tolerance for temperature.
Definition: mptrac.h:2515
double mixing_dt
Time interval for mixing [s].
Definition: mptrac.h:2802
int qnt_mloss_h2o2
Quantity array index for total mass loss due to H2O2 chemistry.
Definition: mptrac.h:2344
double met_zfp_tol_z
ZFP compression tolerance for geopotential height.
Definition: mptrac.h:2518
double vtk_scale
Vertical scaling factor for VTK data.
Definition: mptrac.h:3145
char clim_ccl2f2_timeseries[LEN]
Filename of CFC-12 time series.
Definition: mptrac.h:2793
double met_cms_eps_w
cmultiscale compression epsilon for vertical velocity.
Definition: mptrac.h:2543
double wet_depo_ic_h[2]
Coefficients for wet deposition in cloud (Henry's law: Hb, Cb).
Definition: mptrac.h:2901
double turb_dx_pbl
Horizontal turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2679
double conv_cin
CIN threshold for convection module [J/kg].
Definition: mptrac.h:2712
int qnt_pv
Quantity array index for potential vorticity.
Definition: mptrac.h:2401
int advect_vert_coord
Vertical velocity of air parcels (0=omega_on_plev, 1=zetadot_on_mlev, 2=omega_on_mlev).
Definition: mptrac.h:2670
int qnt_mloss_oh
Quantity array index for total mass loss due to OH chemistry.
Definition: mptrac.h:2341
int qnt_Ch2o2
Quantity array index for H2O2 volume mixing ratio (chemistry code).
Definition: mptrac.h:2437
int qnt_sst
Quantity array index for sea surface temperature.
Definition: mptrac.h:2239
double mixing_lon1
Upper longitude of mixing grid [deg].
Definition: mptrac.h:2826
int atm_nc_level
zlib compression level of netCDF atmospheric data files (0=off).
Definition: mptrac.h:2956
char clim_hno3_filename[LEN]
Filename of HNO3 climatology.
Definition: mptrac.h:2769
int met_cms_heur
cmultiscale coarsening heuristics (0=default, 1=mean diff, 2=median diff, 3=max diff).
Definition: mptrac.h:2528
double wet_depo_ic_ret_ratio
Coefficients for wet deposition in cloud: retention ratio.
Definition: mptrac.h:2910
int qnt_sh
Quantity array index for specific humidity.
Definition: mptrac.h:2371
int qnt_ess
Quantity array index for eastward turbulent surface stress.
Definition: mptrac.h:2227
double wet_depo_ic_b
Coefficient B for wet deposition in cloud (exponential form).
Definition: mptrac.h:2898
double wet_depo_bc_b
Coefficient B for wet deposition below cloud (exponential form).
Definition: mptrac.h:2892
int met_dy
Stride for latitudes.
Definition: mptrac.h:2573
int qnt_Cx
Quantity array index for trace species x volume mixing ratio (chemistry code).
Definition: mptrac.h:2416
double turb_dz_strat
Vertical turbulent diffusion coefficient (stratosphere) [m^2/s].
Definition: mptrac.h:2694
double bound_zetas
Boundary conditions surface layer zeta [K].
Definition: mptrac.h:2748
int qnt_idx
Quantity array index for air parcel IDs.
Definition: mptrac.h:2191
double met_tropo_theta
Dynamical tropopause potential temperature threshold [K].
Definition: mptrac.h:2637
int qnt_rwc
Quantity array index for cloud rain water content.
Definition: mptrac.h:2287
double t_start
Start time of simulation [s].
Definition: mptrac.h:2467
char qnt_longname[NQ][LEN]
Quantity long names.
Definition: mptrac.h:2182
double met_p[EP]
Target pressure levels [hPa].
Definition: mptrac.h:2594
int nq
Number of quantities.
Definition: mptrac.h:2176
double tdec_trop
Life time of particles in the troposphere [s].
Definition: mptrac.h:2760
double sample_dx
Horizontal radius for sample output [km].
Definition: mptrac.h:3112
int vtk_stride
Particle index stride for VTK data.
Definition: mptrac.h:3142
char stat_basename[LEN]
Basename of station data file.
Definition: mptrac.h:3118
double turb_dz_pbl
Vertical turbulent diffusion coefficient (PBL) [m^2/s].
Definition: mptrac.h:2688
double grid_lat1
Upper latitude of gridded data [deg].
Definition: mptrac.h:3064
int qnt_zt
Quantity array index for tropopause geopotential height.
Definition: mptrac.h:2251
int met_type
Type of meteo data files (0=netCDF, 1=binary, 2=pck, 3=zfp, 4=zstd, 5=cms).
Definition: mptrac.h:2494
int qnt_cc
Quantity array index for cloud cover.
Definition: mptrac.h:2296
int qnt_plcl
Quantity array index for pressure at lifted condensation level (LCL).
Definition: mptrac.h:2308
double grid_dt_out
Time step for gridded data output [s].
Definition: mptrac.h:3025
int qnt_tdew
Quantity array index for dew point temperature.
Definition: mptrac.h:2404
Meteo data structure.
Definition: mptrac.h:3390
float zt[EX][EY]
Tropopause geopotential height [km].
Definition: mptrac.h:3459
float sst[EX][EY]
Sea surface temperature [K].
Definition: mptrac.h:3447
float rwc[EX][EY][EP]
Cloud rain water content [kg/kg].
Definition: mptrac.h:3519
float o3c[EX][EY]
Total column ozone [DU].
Definition: mptrac.h:3489
float zeta_dotl[EX][EY][EP]
Vertical velocity on model levels [K/s].
Definition: mptrac.h:3546
float h2o[EX][EY][EP]
Water vapor volume mixing ratio [1].
Definition: mptrac.h:3510
float cape[EX][EY]
Convective available potential energy [J/kg].
Definition: mptrac.h:3483
float w[EX][EY][EP]
Vertical velocity [hPa/s].
Definition: mptrac.h:3504
float pct[EX][EY]
Cloud top pressure [hPa].
Definition: mptrac.h:3465
double hybrid[EP]
Model hybrid levels.
Definition: mptrac.h:3417
int nx
Number of longitudes.
Definition: mptrac.h:3396
int ny
Number of latitudes.
Definition: mptrac.h:3399
float shf[EX][EY]
Surface sensible heat flux [W/m^2].
Definition: mptrac.h:3441
float ps[EX][EY]
Surface pressure [hPa].
Definition: mptrac.h:3420
float lwc[EX][EY][EP]
Cloud liquid water content [kg/kg].
Definition: mptrac.h:3516
float us[EX][EY]
Surface zonal wind [m/s].
Definition: mptrac.h:3429
float wl[EX][EY][EP]
Vertical velocity on model levels [hPa/s].
Definition: mptrac.h:3540
float vl[EX][EY][EP]
Meridional wind on model levels [m/s].
Definition: mptrac.h:3537
float zs[EX][EY]
Surface geopotential height [km].
Definition: mptrac.h:3426
float o3[EX][EY][EP]
Ozone volume mixing ratio [1].
Definition: mptrac.h:3513
float cc[EX][EY][EP]
Cloud cover [1].
Definition: mptrac.h:3528
int np
Number of pressure levels.
Definition: mptrac.h:3402
float t[EX][EY][EP]
Temperature [K].
Definition: mptrac.h:3495
float ts[EX][EY]
Surface temperature [K].
Definition: mptrac.h:3423
float u[EX][EY][EP]
Zonal wind [m/s].
Definition: mptrac.h:3498
float ess[EX][EY]
Eastward turbulent surface stress [N/m^2].
Definition: mptrac.h:3435
float ul[EX][EY][EP]
Zonal wind on model levels [m/s].
Definition: mptrac.h:3534
float pcb[EX][EY]
Cloud bottom pressure [hPa].
Definition: mptrac.h:3468
float pel[EX][EY]
Pressure at equilibrium level (EL) [hPa].
Definition: mptrac.h:3480
float cin[EX][EY]
Convective inhibition [J/kg].
Definition: mptrac.h:3486
float plcl[EX][EY]
Pressure at lifted condensation level (LCL) [hPa].
Definition: mptrac.h:3474
double lon[EX]
Longitude [deg].
Definition: mptrac.h:3408
float pt[EX][EY]
Tropopause pressure [hPa].
Definition: mptrac.h:3453
float tt[EX][EY]
Tropopause temperature [K].
Definition: mptrac.h:3456
float pbl[EX][EY]
Boundary layer pressure [hPa].
Definition: mptrac.h:3450
float vs[EX][EY]
Surface meridional wind [m/s].
Definition: mptrac.h:3432
float z[EX][EY][EP]
Geopotential height [km].
Definition: mptrac.h:3492
float v[EX][EY][EP]
Meridional wind [m/s].
Definition: mptrac.h:3501
int npl
Number of model levels.
Definition: mptrac.h:3405
float lsm[EX][EY]
Land-sea mask [1].
Definition: mptrac.h:3444
float iwc[EX][EY][EP]
Cloud ice water content [kg/kg].
Definition: mptrac.h:3522
float h2ot[EX][EY]
Tropopause water vapor volume mixing ratio [ppv].
Definition: mptrac.h:3462
float pv[EX][EY][EP]
Potential vorticity [PVU].
Definition: mptrac.h:3507
double time
Time [s].
Definition: mptrac.h:3393
float cl[EX][EY]
Total column cloud water [kg/m^2].
Definition: mptrac.h:3471
float nss[EX][EY]
Northward turbulent surface stress [N/m^2].
Definition: mptrac.h:3438
float pl[EX][EY][EP]
Pressure on model levels [hPa].
Definition: mptrac.h:3531
float plfc[EX][EY]
Pressure at level of free convection (LFC) [hPa].
Definition: mptrac.h:3477
double lat[EY]
Latitude [deg].
Definition: mptrac.h:3411
float swc[EX][EY][EP]
Cloud snow water content [kg/kg].
Definition: mptrac.h:3525
float zetal[EX][EY][EP]
Zeta on model levels [K].
Definition: mptrac.h:3543
double p[EP]
Pressure levels [hPa].
Definition: mptrac.h:3414