CAMP 1.0.0
Chemistry Across Multiple Phases
aero_rep_modal_binned_mass.c
Go to the documentation of this file.
1/* Copyright (C) 2021 Barcelona Supercomputing Center and University of
2 * Illinois at Urbana-Champaign
3 * SPDX-License-Identifier: MIT
4 *
5 * Modal mass aerosol representation functions
6 *
7 */
8/** \file
9 * \brief Modal mass aerosol representation functions
10 */
11#include <math.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include "../aero_phase_solver.h"
15#include "../aero_reps.h"
16#include "../camp_solver.h"
17
18// TODO Lookup environmental indicies during initialization
19#define TEMPERATURE_K_ env_data[0]
20#define PRESSURE_PA_ env_data[1]
21
22#define UPDATE_GMD 0
23#define UPDATE_GSD 1
24
25#define BINNED 1
26#define MODAL 2
27
28#define NUM_SECTION_ (int_data[0])
29#define INT_DATA_SIZE_ (int_data[1])
30#define FLOAT_DATA_SIZE_ (int_data[2])
31#define AERO_REP_ID_ (int_data[3])
32#define NUM_INT_PROP_ 4
33#define NUM_FLOAT_PROP_ 0
34#define NUM_ENV_PARAM_ 0
35#define MODE_INT_PROP_LOC_(x) (int_data[NUM_INT_PROP_ + x] - 1)
36#define MODE_FLOAT_PROP_LOC_(x) (int_data[NUM_INT_PROP_ + NUM_SECTION_ + x] - 1)
37#define SECTION_TYPE_(x) (int_data[MODE_INT_PROP_LOC_(x)])
38
39// For modes, NUM_BINS_ = 1
40#define NUM_BINS_(x) (int_data[MODE_INT_PROP_LOC_(x) + 1])
41
42// Number of aerosol phases in this mode/bin set
43#define NUM_PHASE_(x) (int_data[MODE_INT_PROP_LOC_(x) + 2])
44
45// Phase state and model data ids
46#define PHASE_STATE_ID_(x, y, b) \
47 (int_data[MODE_INT_PROP_LOC_(x) + 3 + b * NUM_PHASE_(x) + y] - 1)
48#define PHASE_MODEL_DATA_ID_(x, y, b) \
49 (int_data[MODE_INT_PROP_LOC_(x) + 3 + NUM_BINS_(x) * NUM_PHASE_(x) + \
50 b * NUM_PHASE_(x) + y] - \
51 1)
52
53// Number of Jacobian elements in a phase
54#define PHASE_NUM_JAC_ELEM_(x, y, b) \
55 int_data[MODE_INT_PROP_LOC_(x) + 3 + 2 * NUM_BINS_(x) * NUM_PHASE_(x) + \
56 b * NUM_PHASE_(x) + y]
57
58// Bin diameter (for bins)
59#define BIN_DP_(x, b) (float_data[MODE_FLOAT_PROP_LOC_(x) + b * 3])
60
61// GMD and GSD - only used for modes
62#define GMD_(x) (aero_rep_env_data[x])
63#define GSD_(x) (aero_rep_env_data[NUM_SECTION_ + x])
64
65// Real-time number concentration - used for modes and bins - for modes, b=0
66#define NUMBER_CONC_(x, b) (float_data[MODE_FLOAT_PROP_LOC_(x) + b * 3 + 1])
67
68// Real-time effective radius - for modes, b=0
69#define EFFECTIVE_RADIUS_(x, b) \
70 (float_data[MODE_FLOAT_PROP_LOC_(x) + b * 3 + 2])
71
72// Real-time phase mass (kg/m^3) - used for modes and bins - for modes, b=0
73#define PHASE_MASS_(x, y, b) \
74 (float_data[MODE_FLOAT_PROP_LOC_(x) + 3 * NUM_BINS_(x) + b * NUM_PHASE_(x) + \
75 y])
76
77// Real-time phase average MW (kg/mol) - used for modes and bins - for modes,
78// b=0
79#define PHASE_AVG_MW_(x, y, b) \
80 (float_data[MODE_FLOAT_PROP_LOC_(x) + (3 + NUM_PHASE_(x)) * NUM_BINS_(x) + \
81 b * NUM_PHASE_(x) + y])
82
83/** \brief Flag Jacobian elements used in calcualtions of mass and volume
84 *
85 * \param model_data Pointer to the model data
86 * \param aero_rep_int_data Pointer to the aerosol representation integer data
87 * \param aero_rep_float_data Pointer to the aerosol representation
88 * floating-point data
89 * \param aero_phase_idx Index of the aerosol phase to find elements for
90 * \param jac_struct 1D array of flags indicating potentially non-zero
91 * Jacobian elements. (The dependent variable should have
92 * been chosen by the calling function.)
93 * \return Number of Jacobian elements flagged
94 */
96 int aero_phase_idx,
97 int *aero_rep_int_data,
98 double *aero_rep_float_data,
99 bool *jac_struct) {
100 int *int_data = aero_rep_int_data;
101 double *float_data = aero_rep_float_data;
102
103 int num_flagged_elem = 0;
104
105 // Loop through the modes/bins flagging Jacobian elements used by each
106 // aerosol phase
107 for (int i_section = 0; i_section < NUM_SECTION_ && aero_phase_idx >= 0;
108 i_section++) {
109 for (int i_bin = 0; i_bin < NUM_BINS_(i_section) && aero_phase_idx >= 0;
110 i_bin++) {
111 for (int i_phase = 0;
112 i_phase < NUM_PHASE_(i_section) && aero_phase_idx >= 0; i_phase++) {
113 if (aero_phase_idx == 0) {
114 for (int j_phase = 0; j_phase < NUM_PHASE_(i_section); j_phase++) {
115 PHASE_NUM_JAC_ELEM_(i_section, j_phase, i_bin) =
117 model_data, PHASE_MODEL_DATA_ID_(i_section, j_phase, i_bin),
118 PHASE_STATE_ID_(i_section, j_phase, i_bin), jac_struct);
119 num_flagged_elem += PHASE_NUM_JAC_ELEM_(i_section, j_phase, i_bin);
120 }
121 }
122 aero_phase_idx -= 1;
123 }
124 }
125 }
126
127 return num_flagged_elem;
128}
129
130/** \brief Flag elements on the state array used by this aerosol representation
131 *
132 * The modal mass aerosol representation functions do not use state array values
133 *
134 * \param aero_rep_int_data Pointer to the aerosol representation integer data
135 * \param aero_rep_float_data Pointer to the aerosol representation
136 * floating-point data
137 * \param state_flags Array of flags indicating state array elements used
138 */
140 double *aero_rep_float_data,
141 bool *state_flags) {
142 int *int_data = aero_rep_int_data;
143 double *float_data = aero_rep_float_data;
144
145 return;
146}
147
148/** \brief Update aerosol representation data for new environmental conditions
149 *
150 * The modal mass aerosol representation is not updated for new environmental
151 * conditions
152 *
153 * \param model_data Pointer to the model data
154 * \param aero_rep_int_data Pointer to the aerosol representation integer data
155 * \param aero_rep_float_data Pointer to the aerosol representation
156 * floating-point data
157 * \param aero_rep_env_data Pointer to the aerosol representation
158 * environment-dependent parameters
159 */
161 int *aero_rep_int_data,
162 double *aero_rep_float_data,
163 double *aero_rep_env_data) {
164 int *int_data = aero_rep_int_data;
165 double *float_data = aero_rep_float_data;
166 double *env_data = model_data->grid_cell_env;
167
168 return;
169}
170
171/** \brief Update aerosol representation data for a new state
172 *
173 * The modal mass aerosol representation recalculates effective radius and
174 * number concentration for each new state.
175 *
176 * \param model_data Pointer to the model data, including the state array
177 * \param aero_rep_int_data Pointer to the aerosol representation integer data
178 * \param aero_rep_float_data Pointer to the aerosol representation
179 * floating-point data
180 * \param aero_rep_env_data Pointer to the aerosol representation
181 * environment-dependent parameters
182 */
184 int *aero_rep_int_data,
185 double *aero_rep_float_data,
186 double *aero_rep_env_data) {
187 int *int_data = aero_rep_int_data;
188 double *float_data = aero_rep_float_data;
189
190 // Loop through the modes and calculate effective radius and number
191 // concentration
192 for (int i_section = 0; i_section < NUM_SECTION_; i_section++) {
193 double volume, mass;
194 switch (SECTION_TYPE_(i_section)) {
195 // Mode
196 case (MODAL):
197
198 // Sum the volumes of each species in the mode [m3 m-3]
199 volume = 0.0;
200 for (int i_phase = 0; i_phase < NUM_PHASE_(i_section); i_phase++) {
201 // Get a pointer to the phase on the state array
202 double *state = (double *)(model_data->grid_cell_state);
203 state += PHASE_STATE_ID_(i_section, i_phase, 0);
204
205 // Set the aerosol-phase mass [kg m-3] and average MW [kg mol-1]
207 model_data, PHASE_MODEL_DATA_ID_(i_section, i_phase, 0), state,
208 &(PHASE_MASS_(i_section, i_phase, 0)),
209 &(PHASE_AVG_MW_(i_section, i_phase, 0)), NULL, NULL);
210
211 // Get the phase volume [m3 m-3]
212 double phase_volume = 0.0;
214 model_data, PHASE_MODEL_DATA_ID_(i_section, i_phase, 0), state,
215 &phase_volume, NULL);
216 volume += phase_volume;
217 }
218
219 // Calculate the number concentration [# m-3] based on the total mode
220 // volume (see aero_rep_modal_binned_mass_get_number_conc for details)
221 NUMBER_CONC_(i_section, 0) =
222 volume * 6.0 /
223 (M_PI * pow(GMD_(i_section), 3) *
224 exp(9.0 / 2.0 * pow(log(GSD_(i_section)), 2)));
225
226 break;
227
228 // Bins
229 case (BINNED):
230
231 // Loop through the bins
232 for (int i_bin = 0; i_bin < NUM_BINS_(i_section); i_bin++) {
233 // Sum the volumes of each species in the bin [m3 m-3]
234 volume = 0.0;
235 for (int i_phase = 0; i_phase < NUM_PHASE_(i_section); i_phase++) {
236 // Get a pointer to the phase on the state array
237 double *state = (double *)(model_data->grid_cell_state);
238 state += PHASE_STATE_ID_(i_section, i_phase, i_bin);
239
240 // Set the aerosol-phase mass [kg m-3] and average MW [kg mol-1]
242 model_data, PHASE_MODEL_DATA_ID_(i_section, i_phase, i_bin),
243 state, &(PHASE_MASS_(i_section, i_phase, i_bin)),
244 &(PHASE_AVG_MW_(i_section, i_phase, i_bin)), NULL, NULL);
245
246 // Get the phase volume [m3 m-3]
247 double phase_volume = 0.0;
249 model_data, PHASE_MODEL_DATA_ID_(i_section, i_phase, i_bin),
250 state, &phase_volume, NULL);
251 volume += phase_volume;
252 }
253
254 // Calculate the number concentration [# m-3] based on the total bin
255 // volume (see aero_rep_modal_binned_mass_get_number_conc for details)
256 NUMBER_CONC_(i_section, i_bin) =
257 volume * 3.0 / (4.0 * M_PI) /
258 pow(BIN_DP_(i_section, i_bin) / 2.0, 3);
259 }
260
261 break;
262 }
263 }
264
265 return;
266}
267
268/** \brief Get the effective particle radius \f$r_{eff}\f$ (m)
269 *
270 * The modal mass effective radius is calculated for a log-normal distribution
271 * where the geometric mean diameter (\f$\tilde{D}_n\f$) and geometric standard
272 * deviation (\f$\sigma_g\f$) are set by the aerosol model prior to
273 * solving the chemistry. Thus, all \f$\frac{\partial r_{eff}}{\partial y}\f$
274 * are zero. The effective radius is calculated according to the equation given
275 * in Table 1 of Zender \cite Zender2002 :
276 *
277 * \f[
278 * \tilde{\sigma_g} \equiv ln( \sigma_g )
279 * \f]
280 * \f[
281 * D_s = D_{eff} = \tilde{D_n} e^{5 \tilde{\sigma}_g^2 / 2}
282 * \f]
283 * \f[
284 * r_{eff} = \frac{D_{eff}}{2}
285 * \f]
286 *
287 * For bins, \f$r_{eff}\f$ is assumed to be the bin radius.
288 *
289 * \param model_data Pointer to the model data, including the state array
290 * \param aero_phase_idx Index of the aerosol phase within the representation
291 * \param radius Effective particle radius (m)
292 * \param partial_deriv \f$\frac{\partial r_{eff}}{\partial y}\f$ where \f$y\f$
293 * are species on the state array
294 * \param aero_rep_int_data Pointer to the aerosol representation integer data
295 * \param aero_rep_float_data Pointer to the aerosol representation
296 * floating-point data
297 * \param aero_rep_env_data Pointer to the aerosol representation
298 * environment-dependent parameters
299 */
301 ModelData *model_data, int aero_phase_idx, double *radius,
302 double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data,
303 double *aero_rep_env_data) {
304 int *int_data = aero_rep_int_data;
305 double *float_data = aero_rep_float_data;
306
307 for (int i_section = 0; i_section < NUM_SECTION_; i_section++) {
308 for (int i_bin = 0; i_bin < NUM_BINS_(i_section); i_bin++) {
309 aero_phase_idx -= NUM_PHASE_(i_section);
310 if (aero_phase_idx < 0) {
311 *radius = EFFECTIVE_RADIUS_(i_section, i_bin);
312 // Effective radii are constant for bins and modes
313 if (partial_deriv) {
314 for (int i_phase = 0; i_phase < NUM_PHASE_(i_section); ++i_phase) {
315 for (int i_elem = 0;
316 i_elem < PHASE_NUM_JAC_ELEM_(i_section, i_phase, i_bin);
317 ++i_elem) {
318 *(partial_deriv++) = ZERO;
319 }
320 }
321 }
322 i_section = NUM_SECTION_;
323 break;
324 }
325 }
326 }
327
328 return;
329}
330
331/** \brief Get the particle number concentration \f$n\f$
332 * (\f$\mbox{\si{\#\per\cubic\metre}}\f$)
333 *
334 * The modal mass number concentration is calculated for a log-normal
335 * distribution where the geometric mean diameter (\f$\tilde{D}_n\f$) and
336 * geometric standard deviation (\f$\tilde{\sigma}_g\f$) are set by the aerosol
337 * model prior to solving the chemistry. The number concentration is
338 * calculated according to the equation given in Table 1 of Zender
339 * \cite Zender2002 :
340 * \f[
341 * n = N_0 = \frac{6V_0}{\pi}\tilde{D}_n^{-3}e^{-9
342 * ln(\tilde{\sigma}_g)^2/2} \f] \f[ V_0 = \sum_i{\frac{m_i}{\rho_i}} \f] where
343 * \f$\rho_i\f$ and \f$m_i\f$ are the density and total mass of species \f$i\f$
344 * in the specified mode.
345 *
346 * The binned number concentration is calculated according to:
347 * \f[
348 * n = V_0 / V_p
349 * \f]
350 * \f[
351 * V_p = \frac{4}{3}\pi r^{3}
352 * \f]
353 * where \f$r\f$ is the radius of the size bin and \f$V_0\f$ is defined as
354 * above.
355 *
356 * \param model_data Pointer to the model data, including the state array
357 * \param aero_phase_idx Index of the aerosol phase within the representation
358 * \param number_conc Particle number concentration, \f$n\f$
359 * (\f$\mbox{\si{\#\per\cubic\centi\metre}}\f$)
360 * \param partial_deriv \f$\frac{\partial n}{\partial y}\f$ where \f$y\f$ are
361 * the species on the state array
362 * \param aero_rep_int_data Pointer to the aerosol representation integer data
363 * \param aero_rep_float_data Pointer to the aerosol representation
364 * floating-point data
365 * \param aero_rep_env_data Pointer to the aerosol representation
366 * environment-dependent parameters
367 */
369 ModelData *model_data, int aero_phase_idx, double *number_conc,
370 double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data,
371 double *aero_rep_env_data) {
372 int *int_data = aero_rep_int_data;
373 double *float_data = aero_rep_float_data;
374
375 for (int i_section = 0; i_section < NUM_SECTION_ && aero_phase_idx >= 0;
376 i_section++) {
377 for (int i_bin = 0; i_bin < NUM_BINS_(i_section) && aero_phase_idx >= 0;
378 i_bin++) {
379 aero_phase_idx -= NUM_PHASE_(i_section);
380 if (aero_phase_idx < 0) {
381 *number_conc = NUMBER_CONC_(i_section, i_bin);
382 if (partial_deriv) {
383 for (int i_phase = 0; i_phase < NUM_PHASE_(i_section); ++i_phase) {
384 // Get a pointer to the phase on the state array
385 double *state = (double *)(model_data->grid_cell_state);
386 state += PHASE_STATE_ID_(i_section, i_phase, i_bin);
387
388 // Get the aerosol phase volume [m3 m-3]
389 double phase_volume = 0.0;
391 model_data, PHASE_MODEL_DATA_ID_(i_section, i_phase, i_bin),
392 state, &phase_volume, partial_deriv);
393
394 // Convert d_vol/d_conc to d_number/d_conc
395 for (int i_elem = 0;
396 i_elem < PHASE_NUM_JAC_ELEM_(i_section, i_phase, i_bin);
397 ++i_elem) {
398 switch (SECTION_TYPE_(i_section)) {
399 case (MODAL):
400 *(partial_deriv++) *=
401 6.0 / (M_PI * pow(GMD_(i_section), 3) *
402 exp(9.0 / 2.0 * pow(log(GSD_(i_section)), 2)));
403 break;
404 case (BINNED):
405 *(partial_deriv++) *= 3.0 / (4.0 * M_PI) /
406 pow(BIN_DP_(i_section, i_bin) / 2.0, 3);
407 break;
408 }
409 }
410 }
411 }
412 i_section = NUM_SECTION_;
413 break;
414 }
415 }
416 }
417
418 return;
419}
420
421/** \brief Get the type of aerosol concentration used.
422 *
423 * Modal mass concentrations are per-mode or per-bin.
424 *
425 * \param aero_phase_idx Index of the aerosol phase within the representation
426 * \param aero_conc_type Pointer to int that will hold the concentration type
427 * code
428 * \param aero_rep_int_data Pointer to the aerosol representation integer data
429 * \param aero_rep_float_data Pointer to the aerosol representation
430 * floating-point data
431 * \param aero_rep_env_data Pointer to the aerosol representation
432 * environment-dependent parameters
433 */
435 int *aero_conc_type,
436 int *aero_rep_int_data,
437 double *aero_rep_float_data,
438 double *aero_rep_env_data) {
439 int *int_data = aero_rep_int_data;
440 double *float_data = aero_rep_float_data;
441
442 *aero_conc_type = 1;
443
444 return;
445}
446
447/** \brief Get the total mass in an aerosol phase \f$m\f$
448 * (\f$\mbox{\si{\kilogram\per\cubic\metre}}\f$)
449 *
450 * \param model_data Pointer to the model data, including the state array
451 * \param aero_phase_idx Index of the aerosol phase within the representation
452 * \param aero_phase_mass Total mass in the aerosol phase, \f$m\f$
453 * (\f$\mbox{\si{\kilogram\per\cubic\metre}}\f$)
454 * \param partial_deriv \f$\frac{\partial m}{\partial y}\f$ where \f$y\f$ are
455 * the species on the state array
456 * \param aero_rep_int_data Pointer to the aerosol representation integer data
457 * \param aero_rep_float_data Pointer to the aerosol representation
458 * floating-point data
459 * \param aero_rep_env_data Pointer to the aerosol representation
460 * environment-dependent parameters
461 */
463 ModelData *model_data, int aero_phase_idx, double *aero_phase_mass,
464 double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data,
465 double *aero_rep_env_data) {
466 int *int_data = aero_rep_int_data;
467 double *float_data = aero_rep_float_data;
468
469 for (int i_section = 0; i_section < NUM_SECTION_ && aero_phase_idx >= 0;
470 ++i_section) {
471 for (int i_bin = 0; i_bin < NUM_BINS_(i_section) && aero_phase_idx >= 0;
472 ++i_bin) {
473 if (aero_phase_idx < 0 || aero_phase_idx >= NUM_PHASE_(i_section)) {
474 aero_phase_idx -= NUM_PHASE_(i_section);
475 continue;
476 }
477 for (int i_phase = 0; i_phase < NUM_PHASE_(i_section); ++i_phase) {
478 if (aero_phase_idx == 0) {
479 *aero_phase_mass = PHASE_MASS_(i_section, i_phase, i_bin);
480 if (partial_deriv) {
481 // Get a pointer to the phase on the state array
482 double *state = (double *)(model_data->grid_cell_state);
483 state += PHASE_STATE_ID_(i_section, i_phase, i_bin);
484
485 // Get d_mass / d_conc
486 double mass, mw;
488 model_data, PHASE_MODEL_DATA_ID_(i_section, i_phase, i_bin),
489 state, &mass, &mw, partial_deriv, NULL);
490 partial_deriv += PHASE_NUM_JAC_ELEM_(i_section, i_phase, i_bin);
491 }
492
493 // Other phases present in the bin or mode do not contribute to
494 // the aerosol phase mass
495 } else if (partial_deriv) {
496 for (int i_elem = 0;
497 i_elem < PHASE_NUM_JAC_ELEM_(i_section, i_phase, i_bin);
498 ++i_elem) {
499 *(partial_deriv++) = ZERO;
500 }
501 }
502 aero_phase_idx -= 1;
503 }
504 }
505 }
506
507 return;
508}
509
510/** \brief Get the average molecular weight in an aerosol phase
511 ** \f$m\f$ (\f$\mbox{\si{\kilogram\per\mole}}\f$)
512 *
513 * \param model_data Pointer to the model data, including the state array
514 * \param aero_phase_idx Index of the aerosol phase within the representation
515 * \param aero_phase_avg_MW Average molecular weight in the aerosol phase
516 * (\f$\mbox{\si{\kilogram\per\mole}}\f$)
517 * \param partial_deriv \f$\frac{\partial m}{\partial y}\f$ where \f$y\f$ are
518 * the species on the state array
519 * \param aero_rep_int_data Pointer to the aerosol representation integer data
520 * \param aero_rep_float_data Pointer to the aerosol representation
521 * floating-point data
522 * \param aero_rep_env_data Pointer to the aerosol representation
523 * environment-dependent parameters
524 */
526 ModelData *model_data, int aero_phase_idx, double *aero_phase_avg_MW,
527 double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data,
528 double *aero_rep_env_data) {
529 int *int_data = aero_rep_int_data;
530 double *float_data = aero_rep_float_data;
531
532 for (int i_section = 0; i_section < NUM_SECTION_ && aero_phase_idx >= 0;
533 ++i_section) {
534 for (int i_bin = 0; i_bin < NUM_BINS_(i_section) && aero_phase_idx >= 0;
535 ++i_bin) {
536 if (aero_phase_idx < 0 || aero_phase_idx >= NUM_PHASE_(i_section)) {
537 aero_phase_idx -= NUM_PHASE_(i_section);
538 continue;
539 }
540 for (int i_phase = 0; i_phase < NUM_PHASE_(i_section); ++i_phase) {
541 if (aero_phase_idx == 0) {
542 *aero_phase_avg_MW = PHASE_AVG_MW_(i_section, i_phase, i_bin);
543 if (partial_deriv) {
544 // Get a pointer to the phase on the state array
545 double *state = (double *)(model_data->grid_cell_state);
546 state += PHASE_STATE_ID_(i_section, i_phase, i_bin);
547
548 // Get d_MW / d_conc
549 double mass, mw;
551 model_data, PHASE_MODEL_DATA_ID_(i_section, i_phase, i_bin),
552 state, &mass, &mw, NULL, partial_deriv);
553 partial_deriv += PHASE_NUM_JAC_ELEM_(i_section, i_phase, i_bin);
554 }
555
556 // Other phases present in the bin/mode do not contribute to the
557 // average MW of the aerosol phase
558 } else if (partial_deriv) {
559 for (int i_elem = 0;
560 i_elem < PHASE_NUM_JAC_ELEM_(i_section, i_phase, i_bin);
561 ++i_elem) {
562 *(partial_deriv++) = ZERO;
563 }
564 }
565 aero_phase_idx -= 1;
566 }
567 }
568 }
569
570 return;
571}
572
573/** \brief Update the aerosol representation data
574 *
575 * The model mass aerosol representation update data is structured as follows:
576 *
577 * - \b int aero_rep_id (Id of one or more aerosol representations set by the
578 * host model using the
579 * camp_aero_rep_modal_binned_mass::aero_rep_modal_binned_mass_t::set_id
580 * function prior to initializing the solver.)
581 * - \b int update_type (Type of update to perform. Can be UPDATE_GMD or
582 * UPDATE_GSD.)
583 * - \b int section_id (Index of the mode to update.)
584 * - \b double new_value (Either the new GMD (m) or the new GSD (unitless).)
585 *
586 * \param update_data Pointer to the updated aerosol representation data
587 * \param aero_rep_int_data Pointer to the aerosol representation integer data
588 * \param aero_rep_float_data Pointer to the aerosol representation
589 * floating-point data
590 * \param aero_rep_env_data Pointer to the aerosol representation
591 * environment-dependent parameters
592 * \return Flag indicating whether this is the aerosol representation to update
593 */
595 int *aero_rep_int_data,
596 double *aero_rep_float_data,
597 double *aero_rep_env_data) {
598 int *int_data = aero_rep_int_data;
599 double *float_data = aero_rep_float_data;
600
601 int *aero_rep_id = (int *)update_data;
602 int *update_type = (int *)&(aero_rep_id[1]);
603 int *section_id = (int *)&(update_type[1]);
604 double *new_value = (double *)&(section_id[1]);
605 bool ret_val = false;
606
607 // Set the new GMD or GSD for matching aerosol representations
608 if (*aero_rep_id == AERO_REP_ID_ && AERO_REP_ID_ != 0) {
609 if (*update_type == UPDATE_GMD) {
610 if (SECTION_TYPE_(*section_id) != MODAL) {
611 printf(
612 "\n\nERROR Trying to set geometric mean diameter for non-modal"
613 " aerosol section.");
614 exit(1);
615 }
616 GMD_(*section_id) = (double)*new_value; // [m]
617 ret_val = true;
618 } else if (*update_type == UPDATE_GSD) {
619 if (SECTION_TYPE_(*section_id) != MODAL) {
620 printf(
621 "\n\nERROR Trying to set geometric standard deviation for non-modal"
622 " aerosol section.");
623 exit(1);
624 }
625 GSD_(*section_id) = (double)*new_value;
626 ret_val = true;
627 }
628 }
629
630 if (ret_val == true) {
631 /// Recalculate the effective radius [m]
632 ///
633 /// Equation based on \cite Zender2002
634 /// Table 1 effective diameter \f$(D_s, D_{eff}\f$) equations:
635 /// \f[
636 /// \tilde{\sigma_g} \equiv ln( \sigma_g )
637 /// \f]
638 /// \f[
639 /// D_s = D_{eff} = \tilde{D_n} e^{5 \tilde{\sigma}_g^2 / 2}
640 /// \f]
641 /// \f[
642 /// r_{eff} = \frac{D_{eff}}{2}
643 /// \f]
644 /// where \f$\tilde{D_n}\f$ is the geometric mean diameter [m],
645 /// \f$\sigma_g\f$
646 /// is the geometric standard deviation [unitless], and \f$r_{eff}\f$
647 /// is the effective radius [m].
648 ///
649 double ln_gsd = log(GSD_(*section_id));
650 EFFECTIVE_RADIUS_(*section_id, 0) =
651 GMD_(*section_id) / 2.0 * exp(5.0 * ln_gsd * ln_gsd / 2.0);
652 }
653
654 return ret_val;
655}
656
657/** \brief Print the mass-only modal/binned reaction parameters
658 *
659 * \param aero_rep_int_data Pointer to the aerosol representation integer data
660 * \param aero_rep_float_data Pointer to the aerosol representation
661 * floating-point data
662 */
663void aero_rep_modal_binned_mass_print(int *aero_rep_int_data,
664 double *aero_rep_float_data) {
665 int *int_data = aero_rep_int_data;
666 double *float_data = aero_rep_float_data;
667
668 printf("\n\nModal/binned mass-only aerosol representation\n");
669
670 return;
671}
672
673/** \brief Create update data for new GMD
674 *
675 * \return Pointer to a new GMD update data object
676 */
678 int *update_data = (int *)malloc(3 * sizeof(int) + sizeof(double));
679 if (update_data == NULL) {
680 printf("\n\nERROR allocating space for GMD update data.\n\n");
681 exit(1);
682 }
683 return (void *)update_data;
684}
685
686/** \brief Set GMD update data
687 *
688 * \param update_data Pointer to an allocated GMD update data object
689 * \param aero_rep_id Id of the aerosol representation(s) to update
690 * \param section_id Id of the mode to update
691 * \param gmd New mode GMD (m)
692 */
694 int aero_rep_id,
695 int section_id,
696 double gmd) {
697 int *new_aero_rep_id = (int *)update_data;
698 int *update_type = (int *)&(new_aero_rep_id[1]);
699 int *new_section_id = (int *)&(update_type[1]);
700 double *new_GMD = (double *)&(new_section_id[1]);
701 *new_aero_rep_id = aero_rep_id;
702 *update_type = UPDATE_GMD;
703 *new_section_id = section_id;
704 *new_GMD = gmd;
705}
706
707/** \brief Create update data for new GSD
708 *
709 * \return Pointer to a new GSD update data object
710 */
712 int *update_data = (int *)malloc(3 * sizeof(int) + sizeof(double));
713 if (update_data == NULL) {
714 printf("\n\nERROR allocating space for GSD update data.\n\n");
715 exit(1);
716 }
717 return (void *)update_data;
718}
719
720/** \brief Set GSD update data
721 *
722 * \param update_data Pointer to an allocated GSD update data object
723 * \param aero_rep_id Id of the aerosol representation(s) to update
724 * \param section_id Id of the mode to update
725 * \param gsd New mode GSD (unitless)
726 */
728 int aero_rep_id,
729 int section_id,
730 double gsd) {
731 int *new_aero_rep_id = (int *)update_data;
732 int *update_type = (int *)&(new_aero_rep_id[1]);
733 int *new_section_id = (int *)&(update_type[1]);
734 double *new_GSD = (double *)&(new_section_id[1]);
735 *new_aero_rep_id = aero_rep_id;
736 *update_type = UPDATE_GSD;
737 *new_section_id = section_id;
738 *new_GSD = gsd;
739}
void aero_phase_get_volume__m3_m3(ModelData *model_data, int aero_phase_idx, double *state_var, double *volume, double *jac_elem)
Get the volume of an aerosol phase.
int aero_phase_get_used_jac_elem(ModelData *model_data, int aero_phase_idx, int state_var_id, bool *jac_struct)
Flag Jacobian elements used in calculations of mass and volume.
void aero_phase_get_mass__kg_m3(ModelData *model_data, int aero_phase_idx, double *state_var, double *mass, double *MW, double *jac_elem_mass, double *jac_elem_MW)
Get the mass and average MW in an aerosol phase.
void aero_rep_modal_binned_mass_set_gsd_update_data(void *update_data, int aero_rep_id, int section_id, double gsd)
Set GSD update data.
bool aero_rep_modal_binned_mass_update_data(void *update_data, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Update the aerosol representation data.
#define BINNED
#define PHASE_STATE_ID_(x, y, b)
#define NUM_SECTION_
void aero_rep_modal_binned_mass_get_aero_phase_avg_MW__kg_mol(ModelData *model_data, int aero_phase_idx, double *aero_phase_avg_MW, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the average molecular weight in an aerosol phase ( )
void aero_rep_modal_binned_mass_get_number_conc__n_m3(ModelData *model_data, int aero_phase_idx, double *number_conc, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the particle number concentration ( )
void aero_rep_modal_binned_mass_set_gmd_update_data(void *update_data, int aero_rep_id, int section_id, double gmd)
Set GMD update data.
#define PHASE_MODEL_DATA_ID_(x, y, b)
void aero_rep_modal_binned_mass_update_state(ModelData *model_data, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Update aerosol representation data for a new state.
void aero_rep_modal_binned_mass_get_aero_conc_type(int aero_phase_idx, int *aero_conc_type, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the type of aerosol concentration used.
#define SECTION_TYPE_(x)
void aero_rep_modal_binned_mass_update_env_state(ModelData *model_data, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Update aerosol representation data for new environmental conditions.
void aero_rep_modal_binned_mass_print(int *aero_rep_int_data, double *aero_rep_float_data)
Print the mass-only modal/binned reaction parameters.
#define AERO_REP_ID_
#define UPDATE_GMD
void aero_rep_modal_binned_mass_get_effective_radius__m(ModelData *model_data, int aero_phase_idx, double *radius, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the effective particle radius (m)
void aero_rep_modal_binned_mass_get_dependencies(int *aero_rep_int_data, double *aero_rep_float_data, bool *state_flags)
Flag elements on the state array used by this aerosol representation.
#define NUM_PHASE_(x)
#define NUMBER_CONC_(x, b)
#define GMD_(x)
void aero_rep_modal_binned_mass_get_aero_phase_mass__kg_m3(ModelData *model_data, int aero_phase_idx, double *aero_phase_mass, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the total mass in an aerosol phase ( )
void * aero_rep_modal_binned_mass_create_gmd_update_data()
Create update data for new GMD.
int aero_rep_modal_binned_mass_get_used_jac_elem(ModelData *model_data, int aero_phase_idx, int *aero_rep_int_data, double *aero_rep_float_data, bool *jac_struct)
Flag Jacobian elements used in calcualtions of mass and volume.
#define MODAL
#define BIN_DP_(x, b)
#define PHASE_AVG_MW_(x, y, b)
#define UPDATE_GSD
#define NUM_BINS_(x)
#define PHASE_NUM_JAC_ELEM_(x, y, b)
#define PHASE_MASS_(x, y, b)
void * aero_rep_modal_binned_mass_create_gsd_update_data()
Create update data for new GSD.
#define EFFECTIVE_RADIUS_(x, b)
#define GSD_(x)
#define ZERO
Definition camp_common.h:42
#define M_PI
Definition camp_common.h:48
double * grid_cell_env
double * grid_cell_state