CAMP 1.0.0
Chemistry Across Multiple Phases
sub_model_ZSR_aerosol_water.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 * ZSR Aerosol Water sub model solver functions
6 *
7 */
8/** \file
9 * \brief ZSR Aerosol Water sub model solver functions
10 */
11#include <math.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include "../Jacobian.h"
15#include "../sub_models.h"
16
17// TODO Lookup environmental indices during initialization
18#define TEMPERATURE_K_ env_data[0]
19#define PRESSURE_PA_ env_data[1]
20
21// Minimum aerosol water mass [kg m-3]
22#define MINIMUM_WATER_MASS_ 1.0e-30L
23
24// Smoothing factor for max function
25#define ALPHA_ (-100.0)
26
27#define ACT_TYPE_JACOBSON 1
28#define ACT_TYPE_EQSAM 2
29
30#define NUM_PHASE_ (int_data[0])
31#define GAS_WATER_ID_ (int_data[1] - 1)
32#define NUM_ION_PAIR_ (int_data[2])
33#define INT_DATA_SIZE_ (int_data[3])
34#define FLOAT_DATA_SIZE_ (int_data[4])
35#define PPM_TO_RH_ (sub_model_env_data[0])
36#define NUM_INT_PROP_ 5
37#define NUM_REAL_PROP_ 0
38#define NUM_ENV_PARAM_ 1
39#define PHASE_ID_(p) (int_data[NUM_INT_PROP_ + p] - 1)
40#define PAIR_INT_PARAM_LOC_(x) (int_data[NUM_INT_PROP_ + NUM_PHASE_ + x] - 1)
41#define PAIR_FLOAT_PARAM_LOC_(x) \
42 (int_data[NUM_INT_PROP_ + NUM_PHASE_ + NUM_ION_PAIR_ + x] - 1)
43#define TYPE_(x) (int_data[PAIR_INT_PARAM_LOC_(x)])
44#define JACOB_NUM_CATION_(x) (int_data[PAIR_INT_PARAM_LOC_(x) + 1])
45#define JACOB_NUM_ANION_(x) (int_data[PAIR_INT_PARAM_LOC_(x) + 2])
46#define JACOB_CATION_ID_(x) (int_data[PAIR_INT_PARAM_LOC_(x) + 3])
47#define JACOB_ANION_ID_(x) (int_data[PAIR_INT_PARAM_LOC_(x) + 4])
48#define JACOB_NUM_Y_(x) (int_data[PAIR_INT_PARAM_LOC_(x) + 5])
49#define JACOB_GAS_WATER_JAC_ID_(p, x) int_data[PAIR_INT_PARAM_LOC_(x) + 6 + p]
50#define JACOB_CATION_JAC_ID_(p, x) \
51 int_data[PAIR_INT_PARAM_LOC_(x) + 6 + NUM_PHASE_ + p]
52#define JACOB_ANION_JAC_ID_(p, x) \
53 int_data[PAIR_INT_PARAM_LOC_(x) + 6 + 2 * NUM_PHASE_ + p]
54#define EQSAM_NUM_ION_(x) (int_data[PAIR_INT_PARAM_LOC_(x) + 1])
55#define EQSAM_GAS_WATER_JAC_ID_(p, x) (int_data[PAIR_INT_PARAM_LOC_(x) + 2 + p])
56#define EQSAM_ION_ID_(x, y) \
57 (int_data[PAIR_INT_PARAM_LOC_(x) + 2 + NUM_PHASE_ + y])
58#define EQSAM_ION_JAC_ID_(p, x, y) \
59 int_data[PAIR_INT_PARAM_LOC_(x) + 2 + NUM_PHASE_ + EQSAM_NUM_ION_(x) + \
60 y * NUM_PHASE_ + p]
61#define JACOB_low_RH_(x) (float_data[PAIR_FLOAT_PARAM_LOC_(x)])
62#define JACOB_CATION_MW_(x) (float_data[PAIR_FLOAT_PARAM_LOC_(x) + 1])
63#define JACOB_ANION_MW_(x) (float_data[PAIR_FLOAT_PARAM_LOC_(x) + 2])
64#define JACOB_Y_(x, y) (float_data[PAIR_FLOAT_PARAM_LOC_(x) + 3 + y])
65#define EQSAM_NW_(x) (float_data[PAIR_FLOAT_PARAM_LOC_(x)])
66#define EQSAM_ZW_(x) (float_data[PAIR_FLOAT_PARAM_LOC_(x) + 1])
67#define EQSAM_ION_PAIR_MW_(x) (float_data[PAIR_FLOAT_PARAM_LOC_(x) + 2])
68#define EQSAM_ION_MW_(x, y) (float_data[PAIR_FLOAT_PARAM_LOC_(x) + 3 + y])
69
70// Update types (These must match values in sub_model_UNIFAC.F90)
71// (none right now)
72
73/** \brief Flag Jacobian elements used by this sub model
74 *
75 * ZSR aerosol water sub models are assumed to be at equilibrium
76 *
77 * \param sub_model_int_data Pointer to the sub model integer data
78 * \param sub_model_float_data Pointer to the sub model floating-point data
79 * \param jac Jacobian
80 */
82 double *sub_model_float_data,
83 Jacobian *jac) {
84 int *int_data = sub_model_int_data;
85 double *float_data = sub_model_float_data;
86
87 // Loop through the dependent species - aerosol water and set all Jacobian
88 // elements for each
89 for (int i_phase = 0; i_phase < NUM_PHASE_; ++i_phase) {
90 // Flag the gas-phase water species
92
93 // Flag elements for each ion pair
94 for (int i_ion_pair = 0; i_ion_pair < NUM_ION_PAIR_; ++i_ion_pair) {
95 // Flag aerosol elements by calculation type
96 switch (TYPE_(i_ion_pair)) {
97 // Jacobson et al. (1996)
99
100 // Flag the anion and cation Jacobian elements
102 jac, PHASE_ID_(i_phase),
103 PHASE_ID_(i_phase) + JACOB_CATION_ID_(i_ion_pair));
105 jac, PHASE_ID_(i_phase),
106 PHASE_ID_(i_phase) + JACOB_ANION_ID_(i_ion_pair));
107 break;
108
109 // EQSAM (Metger et al., 2002)
110 case ACT_TYPE_EQSAM:
111
112 // Flag the ion Jacobian elements
113 for (int i_ion = 0; i_ion < EQSAM_NUM_ION_(i_ion_pair); i_ion++) {
115 jac, PHASE_ID_(i_phase),
116 PHASE_ID_(i_phase) + EQSAM_ION_ID_(i_ion_pair, i_ion));
117 }
118 break;
119 }
120 }
121 }
122}
123
124/** \brief Update the time derivative and Jacbobian array indices
125 *
126 * ZSR aerosol water sub models are assumed to be at equilibrium
127 *
128 * \param sub_model_int_data Pointer to the sub model integer data
129 * \param sub_model_float_data Pointer to the sub model floating-point data
130 * \param deriv_ids Indices for state array variables on the solver state array
131 * \param jac Jacobian
132 */
133void sub_model_ZSR_aerosol_water_update_ids(int *sub_model_int_data,
134 double *sub_model_float_data,
135 int *deriv_ids, Jacobian jac) {
136 int *int_data = sub_model_int_data;
137 double *float_data = sub_model_float_data;
138
139 // Loop through the dependent species - aerosol water and set all Jacobian
140 // elements for each
141 for (int i_phase = 0; i_phase < NUM_PHASE_; ++i_phase) {
142 // Flag elements for each ion pair
143 for (int i_ion_pair = 0; i_ion_pair < NUM_ION_PAIR_; ++i_ion_pair) {
144 // Flag aerosol elements by calculation type
145 switch (TYPE_(i_ion_pair)) {
146 // Jacobson et al. (1996)
148
149 // Save the gas-phase water species
150 JACOB_GAS_WATER_JAC_ID_(i_phase, i_ion_pair) =
152
153 // Save the cation and anion Jacobian elements
154 JACOB_CATION_JAC_ID_(i_phase, i_ion_pair) = jacobian_get_element_id(
155 jac, PHASE_ID_(i_phase),
156 PHASE_ID_(i_phase) + JACOB_CATION_ID_(i_ion_pair));
157 JACOB_ANION_JAC_ID_(i_phase, i_ion_pair) = jacobian_get_element_id(
158 jac, PHASE_ID_(i_phase),
159 PHASE_ID_(i_phase) + JACOB_ANION_ID_(i_ion_pair));
160 break;
161
162 // EQSAM (Metger et al., 2002)
163 case ACT_TYPE_EQSAM:
164
165 // Save the gas-phase water species
166 EQSAM_GAS_WATER_JAC_ID_(i_phase, i_ion_pair) =
168
169 // Save the ion Jacobian elements
170 for (int i_ion = 0; i_ion < EQSAM_NUM_ION_(i_ion_pair); i_ion++) {
171 EQSAM_ION_JAC_ID_(i_phase, i_ion_pair, i_ion) =
173 jac, PHASE_ID_(i_phase),
174 PHASE_ID_(i_phase) + EQSAM_ION_ID_(i_ion_pair, i_ion));
175 }
176 break;
177 }
178 }
179 }
180}
181
182/** \brief Update sub model data for new environmental conditions
183 *
184 * \param sub_model_int_data Pointer to the sub model integer data
185 * \param sub_model_float_data Pointer to the sub model floating-point data
186 * \param sub_model_env_data Pointer to the sub model environment-dependent data
187 * \param model_data Pointer to the model data
188 */
190 double *sub_model_float_data,
191 double *sub_model_env_data,
192 ModelData *model_data) {
193 int *int_data = sub_model_int_data;
194 double *float_data = sub_model_float_data;
195 double *env_data = model_data->grid_cell_env;
196
197 // Calculate PPM_TO_RH_
198 // From MOSAIC code - reference to Seinfeld & Pandis page 181
199 // TODO Figure out how to have consistent RH<->ppm conversions
200 double t_steam = 373.15; // steam temperature (K)
201 double a = 1.0 - t_steam / TEMPERATURE_K_;
202
203 a = (((-0.1299 * a - 0.6445) * a - 1.976) * a + 13.3185) * a;
204 double water_vp = 101325.0 * exp(a); // (Pa)
205
206 PPM_TO_RH_ = PRESSURE_PA_ / water_vp / 1.0e6; // (1/ppm)
207}
208
209/** \brief Do pre-derivative calculations
210 *
211 * \param sub_model_int_data Pointer to the sub model integer data
212 * \param sub_model_float_data Pointer to the sub model floating-point data
213 * \param sub_model_env_data Pointer to the sub model environment-dependent data
214 * \param model_data Pointer to the model data, including the state array
215 */
216void sub_model_ZSR_aerosol_water_calculate(int *sub_model_int_data,
217 double *sub_model_float_data,
218 double *sub_model_env_data,
219 ModelData *model_data) {
220 double *state = model_data->grid_cell_state;
221 int *int_data = sub_model_int_data;
222 double *float_data = sub_model_float_data;
223
224 // Calculate the water activity---i.e., relative humidity (0-1)
225 long double a_w = PPM_TO_RH_ * state[GAS_WATER_ID_];
226
227 // Calculate the total aerosol water for each instance of the aerosol phase
228 for (int i_phase = 0; i_phase < NUM_PHASE_; i_phase++) {
229 double *water = &(state[PHASE_ID_(i_phase)]);
230 *water = MINIMUM_WATER_MASS_;
231
232 // Get the contribution from each ion pair
233 for (int i_ion_pair = 0; i_ion_pair < NUM_ION_PAIR_; i_ion_pair++) {
234 long double molality, conc;
235
236 // Determine which type of activity calculation should be used
237 switch (TYPE_(i_ion_pair)) {
238 // Jacobson et al. (1996)
239 case ACT_TYPE_JACOBSON:;
240
241 // Determine whether to use the minimum RH in the calculation
242 long double j_aw =
243 a_w > JACOB_low_RH_(i_ion_pair) ? a_w : JACOB_low_RH_(i_ion_pair);
244
245 // Calculate the molality of the pure binary ion pair solution
246 molality = 0.0;
247 for (int i_order = 0; i_order < JACOB_NUM_Y_(i_ion_pair); i_order++)
248 molality += JACOB_Y_(i_ion_pair, i_order) * pow(j_aw, i_order);
249 molality *= molality; // (mol/kg)
250
251 // Calculate the water associated with this ion pair
252 long double cation =
253 state[PHASE_ID_(i_phase) + JACOB_CATION_ID_(i_ion_pair)] /
254 JACOB_NUM_CATION_(i_ion_pair) / JACOB_CATION_MW_(i_ion_pair) /
255 1000.0; // (umol/m3)
256 long double anion =
257 state[PHASE_ID_(i_phase) + JACOB_ANION_ID_(i_ion_pair)] /
258 JACOB_NUM_ANION_(i_ion_pair) / JACOB_ANION_MW_(i_ion_pair) /
259 1000.0; // (umol/m3)
260
261 // Ensure a smooth transition from cation<->anion saturation
262 // using the 'smooth maximum' function:
263 // conc = (cation * e^(alpha*cation) + anion * e^(alpha*anion))
264 // -----------------------------------------------------
265 // (e^(alpha*cation) + e^(alpha*anion))
266 // where alpha is a constant smoothing factor
267 // orig eq: conc = (cation > anion ? anion : cation);
268 long double e_ac = exp(ALPHA_ * cation);
269 long double e_aa = exp(ALPHA_ * anion);
270 conc = (cation * e_ac + anion * e_aa) / (e_ac + e_aa);
271
272 *water += conc / molality * 1000.0; // (ug/m3)
273
274 break;
275
276 // EQSAM (Metger et al., 2002)
277 case ACT_TYPE_EQSAM:;
278
279 // Keep the water activity within the range specified in EQSAM
280 long double e_aw = a_w > 0.99 ? 0.99 : a_w;
281 e_aw = e_aw < 0.001 ? 0.001 : e_aw;
282
283 // Calculate the molality of the ion pair
284 molality =
285 (EQSAM_NW_(i_ion_pair) * 55.51 * 18.01 /
286 EQSAM_ION_PAIR_MW_(i_ion_pair) / 1000.0 * (1.0 / e_aw - 1.0));
287 molality = pow(molality, EQSAM_ZW_(i_ion_pair)); // (mol/kg)
288
289 // Calculate the water associated with this ion pair
290 for (int i_ion = 0; i_ion < EQSAM_NUM_ION_(i_ion_pair); i_ion++) {
291 conc = state[PHASE_ID_(i_phase) + EQSAM_ION_ID_(i_ion_pair, i_ion)];
292 conc = (conc > 0.0 ? conc : 0.0);
293 *water +=
294 conc / EQSAM_ION_MW_(i_ion_pair, i_ion) / molality; // (ug/m3);
295 }
296
297 break;
298 }
299 }
300 }
301}
302
303/** \brief Add contributions to the Jacobian from derivates calculated using the
304 * output of this sub model
305 *
306 * \param sub_model_int_data Pointer to the sub model integer data
307 * \param sub_model_float_data Pointer to the sub model floating-point data
308 * \param sub_model_env_data Pointer to the sub model environment-dependent data
309 * \param model_data Pointer to the model data
310 * \param J Jacobian to be calculated
311 * \param time_step Current time step [s]
312 */
313#ifdef CAMP_USE_SUNDIALS
315 double *sub_model_float_data,
316 double *sub_model_env_data,
317 ModelData *model_data,
318 realtype *J,
319 double time_step) {
320 int *int_data = sub_model_int_data;
321 double *float_data = sub_model_float_data;
322 double *state = model_data->grid_cell_state;
323 double *env_data = model_data->grid_cell_env;
324
325 // Calculate the water activity---i.e., relative humidity (0-1)
326 long double a_w = PPM_TO_RH_ * state[GAS_WATER_ID_];
327 long double d_aw_d_wg = PPM_TO_RH_;
328
329 // Calculate the total aerosol water for each instance of the aerosol phase
330 for (int i_phase = 0; i_phase < NUM_PHASE_; i_phase++) {
331 // Get the contribution from each ion pair
332 for (int i_ion_pair = 0; i_ion_pair < NUM_ION_PAIR_; i_ion_pair++) {
333 long double molality, d_molal_d_wg;
334 long double conc;
335
336 // Determine which type of activity calculation should be used
337 switch (TYPE_(i_ion_pair)) {
338 // Jacobson et al. (1996)
339 case ACT_TYPE_JACOBSON:;
340
341 // Determine whether to use the minimum RH in the calculation
342 long double j_aw =
343 a_w > JACOB_low_RH_(i_ion_pair) ? a_w : JACOB_low_RH_(i_ion_pair);
344 long double d_jaw_d_wg =
345 a_w > JACOB_low_RH_(i_ion_pair) ? d_aw_d_wg : 0.0;
346
347 // Calculate the molality of the pure binary ion pair solution
348 molality = JACOB_Y_(i_ion_pair, 0);
349 d_molal_d_wg = 0.0;
350 for (int i_order = 1; i_order < JACOB_NUM_Y_(i_ion_pair); i_order++) {
351 molality += JACOB_Y_(i_ion_pair, i_order) * pow(j_aw, i_order);
352 d_molal_d_wg += JACOB_Y_(i_ion_pair, i_order) * i_order *
353 pow(j_aw, (i_order - 1));
354 }
355 d_molal_d_wg *= d_jaw_d_wg;
356
357 // Calculate the water associated with this ion pair
358 long double cation =
359 state[PHASE_ID_(i_phase) + JACOB_CATION_ID_(i_ion_pair)] /
360 JACOB_NUM_CATION_(i_ion_pair) / JACOB_CATION_MW_(i_ion_pair) /
361 1000.0; // (umol/m3)
362 long double d_cation_d_C = 1.0 / JACOB_NUM_CATION_(i_ion_pair) /
363 JACOB_CATION_MW_(i_ion_pair) / 1000.0;
364 long double anion =
365 state[PHASE_ID_(i_phase) + JACOB_ANION_ID_(i_ion_pair)] /
366 JACOB_NUM_ANION_(i_ion_pair) / JACOB_ANION_MW_(i_ion_pair) /
367 1000.0; // (umol/m3)
368 long double d_anion_d_A = 1.0 / JACOB_NUM_ANION_(i_ion_pair) /
369 JACOB_ANION_MW_(i_ion_pair) / 1000.0;
370
371 // Calculate the smooth-maximum ion pair concentration
372 // (see calculate() function for details)
373 long double e_ac = exp(ALPHA_ * cation);
374 long double e_aa = exp(ALPHA_ * anion);
375 conc = (cation * e_ac + anion * e_aa) / (e_ac + e_aa);
376 long double denom = (e_ac + e_aa) * (e_ac + e_aa);
377 long double d_conc_d_cation =
378 (e_ac * e_ac +
379 e_ac * e_aa * (1.0 - ALPHA_ * anion + ALPHA_ * cation)) /
380 denom;
381 long double d_conc_d_anion =
382 (e_aa * e_aa +
383 e_ac * e_aa * (1.0 - ALPHA_ * cation + ALPHA_ * anion)) /
384 denom;
385
386 // Add the Jacobian contributions
387 J[JACOB_GAS_WATER_JAC_ID_(i_phase, i_ion_pair)] +=
388 -2.0 * conc / pow(molality, 3) * 1000.0 * d_molal_d_wg;
389 J[JACOB_ANION_JAC_ID_(i_phase, i_ion_pair)] +=
390 1.0 / pow(molality, 2) * 1000.0 * d_conc_d_anion * d_anion_d_A;
391 J[JACOB_CATION_JAC_ID_(i_phase, i_ion_pair)] +=
392 1.0 / pow(molality, 2) * 1000.0 * d_conc_d_cation * d_cation_d_C;
393
394 break;
395
396 // EQSAM (Metger et al., 2002)
397 case ACT_TYPE_EQSAM:;
398
399 // Keep the water activity within the range specified in EQSAM
400 long double e_aw = a_w > 0.99 ? 0.99 : a_w;
401 e_aw = e_aw < 0.001 ? 0.001 : e_aw;
402 long double d_eaw_d_wg = a_w > 0.99 ? 0.0 : d_aw_d_wg;
403 d_eaw_d_wg = a_w < 0.001 ? 0.0 : d_eaw_d_wg;
404
405 // Calculate the molality of the ion pair
406 molality =
407 (EQSAM_NW_(i_ion_pair) * 55.51 * 18.01 /
408 EQSAM_ION_PAIR_MW_(i_ion_pair) / 1000.0 * (1.0 / e_aw - 1.0));
409 d_molal_d_wg = -EQSAM_NW_(i_ion_pair) * 55.51 * 18.01 /
410 EQSAM_ION_PAIR_MW_(i_ion_pair) / 1000.0 /
411 pow(e_aw, 2) * d_eaw_d_wg;
412 d_molal_d_wg = EQSAM_ZW_(i_ion_pair) *
413 pow(molality, EQSAM_ZW_(i_ion_pair) - 1.0) *
414 d_molal_d_wg;
415 molality = pow(molality, EQSAM_ZW_(i_ion_pair)); // (mol/kg)
416
417 // Calculate the Jacobian contributions
418 for (int i_ion = 0; i_ion < EQSAM_NUM_ION_(i_ion_pair); i_ion++) {
419 conc = state[PHASE_ID_(i_phase) + EQSAM_ION_ID_(i_ion_pair, i_ion)];
420 conc = (conc > 0.0 ? conc : 0.0);
421 long double d_conc_d_ion = (conc > 0.0 ? 1.0 : 0.0);
422
423 // Gas-phase water contribution
424 J[EQSAM_GAS_WATER_JAC_ID_(i_phase, i_ion_pair)] +=
425 -1.0 * conc / EQSAM_ION_MW_(i_ion_pair, i_ion) /
426 pow(molality, 2) * d_molal_d_wg;
427
428 // Ion contribution
429 J[EQSAM_ION_JAC_ID_(i_phase, i_ion_pair, i_ion)] +=
430 d_conc_d_ion / EQSAM_ION_MW_(i_ion_pair, i_ion) / molality;
431 }
432
433 break;
434 }
435 }
436 }
437}
438#endif
439
440/** \brief Print the ZSR Aerosol Water sub model parameters
441 *
442 * \param sub_model_int_data Pointer to the sub model integer data
443 * \param sub_model_float_data Pointer to the sub model floating-point data
444 */
445void sub_model_ZSR_aerosol_water_print(int *sub_model_int_data,
446 double *sub_model_float_data) {
447 int *int_data = sub_model_int_data;
448 double *float_data = sub_model_float_data;
449
450 printf("\n\nZSR aerosol water sub model\n");
451 for (int i = 0; i < INT_DATA_SIZE_; i++)
452 printf(" int param %d = %d\n", i, int_data[i]);
453 for (int i = 0; i < FLOAT_DATA_SIZE_; i++)
454 printf(" float param %d = %le\n", i, float_data[i]);
455 printf("\nNumber of phases: %d", NUM_PHASE_);
456 printf("\nGas-phase water state id: %d", GAS_WATER_ID_);
457 printf("\nNumber of ion pairs: %d", NUM_ION_PAIR_);
458 printf("\n*** Phase state ids (index of water in each phase) ***");
459 for (int i_phase = 0; i_phase < NUM_PHASE_; ++i_phase) {
460 printf("\n phase %d: %d", i_phase, PHASE_ID_(i_phase));
461 }
462 printf("\n*** Ion-Pair info ***");
463 for (int i_ion_pair = 0; i_ion_pair < NUM_ION_PAIR_; ++i_ion_pair) {
464 printf("\n ION PAIR %d", i_ion_pair);
465 switch (TYPE_(i_ion_pair)) {
466 case (ACT_TYPE_JACOBSON):
467 printf("\n *** JACOBSON ***");
468 printf("\n low RH: %le", JACOB_low_RH_(i_ion_pair));
469 printf("\n number of cations: %d number of anions: %d",
470 JACOB_NUM_CATION_(i_ion_pair), JACOB_NUM_ANION_(i_ion_pair));
471 printf("\n cation id: %d anion id: %d", JACOB_CATION_ID_(i_ion_pair),
472 JACOB_ANION_ID_(i_ion_pair));
473 printf("\n cation MW: %le anion MW: %le",
474 JACOB_CATION_MW_(i_ion_pair), JACOB_ANION_MW_(i_ion_pair));
475 printf("\n number of Y parameters: %d:", JACOB_NUM_Y_(i_ion_pair));
476 for (int i_Y = 0; i_Y < JACOB_NUM_Y_(i_ion_pair); ++i_Y)
477 printf(" Y(%d)=%le", i_Y, JACOB_Y_(i_ion_pair, i_Y));
478 for (int i_phase = 0; i_phase < NUM_PHASE_; ++i_phase) {
479 printf("\n PHASE %d:", i_phase);
480 printf(" gas-phase water Jac id: %d",
481 JACOB_GAS_WATER_JAC_ID_(i_phase, i_ion_pair));
482 printf(" cation Jac id: %d",
483 JACOB_CATION_JAC_ID_(i_phase, i_ion_pair));
484 printf(" anion Jac id: %d", JACOB_ANION_JAC_ID_(i_phase, i_ion_pair));
485 }
486 break;
487 case (ACT_TYPE_EQSAM):
488 printf("\n *** EQSAM ***");
489 printf("\n NW: %le ZW: %le ion pair MW: %le", EQSAM_NW_(i_ion_pair),
490 EQSAM_ZW_(i_ion_pair), EQSAM_ION_PAIR_MW_(i_ion_pair));
491 printf("\n number of ions: %d", EQSAM_NUM_ION_(i_ion_pair));
492 printf("\n IONS");
493 for (int i_ion = 0; i_ion < EQSAM_NUM_ION_(i_ion_pair); ++i_ion) {
494 printf("\n ion id: %d", EQSAM_ION_ID_(i_ion_pair, i_ion));
495 for (int i_phase = 0; i_phase < NUM_PHASE_; ++i_phase) {
496 printf(
497 "\n phase: %d gas-phase water Jac id: %d "
498 "ion Jac id: %d",
499 i_phase, EQSAM_GAS_WATER_JAC_ID_(i_phase, i_ion_pair),
500 EQSAM_ION_JAC_ID_(i_phase, i_ion_pair, i_ion));
501 }
502 }
503 break;
504 default:
505 printf("\n !!! INVALID TYPE SPECIFIED: %d", TYPE_(i_ion_pair));
506 break;
507 }
508 }
509}
unsigned int jacobian_get_element_id(Jacobian jac, unsigned int dep_id, unsigned int ind_id)
Get an element id in the Jacobian data arrays.
Definition Jacobian.c:200
void jacobian_register_element(Jacobian *jac, unsigned int dep_id, unsigned int ind_id)
Adds an element to the sparse matrix.
Definition Jacobian.c:105
double * grid_cell_env
double * grid_cell_state
#define EQSAM_NUM_ION_(x)
#define EQSAM_ION_PAIR_MW_(x)
#define EQSAM_NW_(x)
#define EQSAM_ION_ID_(x, y)
void sub_model_ZSR_aerosol_water_get_used_jac_elem(int *sub_model_int_data, double *sub_model_float_data, Jacobian *jac)
Flag Jacobian elements used by this sub model.
#define MINIMUM_WATER_MASS_
#define NUM_ION_PAIR_
#define EQSAM_ION_JAC_ID_(p, x, y)
#define PRESSURE_PA_
#define EQSAM_ZW_(x)
#define EQSAM_GAS_WATER_JAC_ID_(p, x)
#define JACOB_CATION_MW_(x)
#define JACOB_CATION_ID_(x)
#define FLOAT_DATA_SIZE_
void sub_model_ZSR_aerosol_water_calculate(int *sub_model_int_data, double *sub_model_float_data, double *sub_model_env_data, ModelData *model_data)
Do pre-derivative calculations.
void sub_model_ZSR_aerosol_water_print(int *sub_model_int_data, double *sub_model_float_data)
Print the ZSR Aerosol Water sub model parameters.
#define GAS_WATER_ID_
#define ACT_TYPE_EQSAM
#define JACOB_NUM_Y_(x)
#define PPM_TO_RH_
#define JACOB_ANION_JAC_ID_(p, x)
void sub_model_ZSR_aerosol_water_update_env_state(int *sub_model_int_data, double *sub_model_float_data, double *sub_model_env_data, ModelData *model_data)
Update sub model data for new environmental conditions.
#define JACOB_ANION_MW_(x)
#define INT_DATA_SIZE_
#define ACT_TYPE_JACOBSON
void sub_model_ZSR_aerosol_water_get_jac_contrib(int *sub_model_int_data, double *sub_model_float_data, double *sub_model_env_data, ModelData *model_data, realtype *J, double time_step)
Add contributions to the Jacobian from derivates calculated using the output of this sub model.
#define TEMPERATURE_K_
#define PHASE_ID_(p)
#define EQSAM_ION_MW_(x, y)
#define JACOB_Y_(x, y)
#define JACOB_low_RH_(x)
#define JACOB_NUM_ANION_(x)
#define TYPE_(x)
#define JACOB_ANION_ID_(x)
#define JACOB_GAS_WATER_JAC_ID_(p, x)
#define JACOB_NUM_CATION_(x)
void sub_model_ZSR_aerosol_water_update_ids(int *sub_model_int_data, double *sub_model_float_data, int *deriv_ids, Jacobian jac)
Update the time derivative and Jacbobian array indices.
#define JACOB_CATION_JAC_ID_(p, x)
#define NUM_PHASE_