CAMP 1.0.0
Chemistry Across Multiple Phases
rxn_aqueous_equilibrium.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 * Aqueous Equilibrium reaction solver functions
6 *
7 */
8/** \file
9 * \brief Aqueous Equilibrium reaction solver functions
10 */
11#include <math.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include "../rxns.h"
15
16// TODO Lookup environmental indices during initialization
17#define TEMPERATURE_K_ env_data[0]
18#define PRESSURE_PA_ env_data[1]
19
20// Small number
21#define SMALL_NUMBER_ 1.0e-30
22
23// Factor used to calculate minimum water concentration for aqueous
24// phase equilibrium reactions
25#define MIN_WATER_ 1.0e-4
26
27#define NUM_REACT_ (int_data[0])
28#define NUM_PROD_ (int_data[1])
29#define NUM_AERO_PHASE_ (int_data[2])
30#define A_ (float_data[0])
31#define C_ (float_data[1])
32#define RATE_CONST_REVERSE_ (float_data[2])
33#define WATER_CONC_ (float_data[3])
34#define ACTIVITY_COEFF_VALUE_ (float_data[4])
35#define RATE_CONST_FORWARD_ (rxn_env_data[0])
36#define NUM_INT_PROP_ 3
37#define NUM_FLOAT_PROP_ 5
38#define NUM_ENV_PARAM_ 1
39#define REACT_(x) (int_data[NUM_INT_PROP_ + x] - 1)
40#define PROD_(x) \
41 (int_data[NUM_INT_PROP_ + NUM_REACT_ * NUM_AERO_PHASE_ + x] - 1)
42#define WATER_(x) \
43 (int_data[NUM_INT_PROP_ + (NUM_REACT_ + NUM_PROD_) * NUM_AERO_PHASE_ + x] - 1)
44#define ACTIVITY_COEFF_(x) \
45 (int_data[NUM_INT_PROP_ + (NUM_REACT_ + NUM_PROD_ + 1) * NUM_AERO_PHASE_ + \
46 x] - \
47 1)
48#define DERIV_ID_(x) \
49 (int_data[NUM_INT_PROP_ + (NUM_REACT_ + NUM_PROD_ + 2) * NUM_AERO_PHASE_ + x])
50#define JAC_ID_(x) \
51 (int_data[NUM_INT_PROP_ + \
52 (2 * (NUM_REACT_ + NUM_PROD_) + 2) * NUM_AERO_PHASE_ + x])
53#define MASS_FRAC_TO_M_(x) (float_data[NUM_FLOAT_PROP_ + x])
54#define REACT_CONC_(x) \
55 (float_data[NUM_FLOAT_PROP_ + NUM_REACT_ + NUM_PROD_ + x])
56#define PROD_CONC_(x) \
57 (float_data[NUM_FLOAT_PROP_ + 2 * NUM_REACT_ + NUM_PROD_ + x])
58#define SMALL_WATER_CONC_(x) \
59 (float_data[NUM_FLOAT_PROP_ + 2 * NUM_REACT_ + 2 * NUM_PROD_ + x])
60#define SMALL_CONC_(x) \
61 (float_data[NUM_FLOAT_PROP_ + 2 * NUM_REACT_ + 2 * NUM_PROD_ + \
62 NUM_AERO_PHASE_ + x])
63
64/** \brief Flag Jacobian elements used by this reaction
65 *
66 * \param rxn_int_data Pointer to the reaction integer data
67 * \param rxn_float_data Pointer to the reaction floating-point data
68 * \param jac Jacobian
69 */
71 double *rxn_float_data,
72 Jacobian *jac) {
73 int *int_data = rxn_int_data;
74 double *float_data = rxn_float_data;
75
76 // Loop over all the instances of the specified phase
77 for (int i_phase = 0; i_phase < NUM_AERO_PHASE_; i_phase++) {
78 // Add dependence on reactants for reactants and products (forward reaction)
79 for (int i_react_ind = i_phase * NUM_REACT_;
80 i_react_ind < (i_phase + 1) * NUM_REACT_; i_react_ind++) {
81 for (int i_react_dep = i_phase * NUM_REACT_;
82 i_react_dep < (i_phase + 1) * NUM_REACT_; i_react_dep++)
83 jacobian_register_element(jac, REACT_(i_react_dep),
84 REACT_(i_react_ind));
85 for (int i_prod_dep = i_phase * NUM_PROD_;
86 i_prod_dep < (i_phase + 1) * NUM_PROD_; i_prod_dep++)
87 jacobian_register_element(jac, PROD_(i_prod_dep), REACT_(i_react_ind));
88 }
89
90 // Add dependence on products for reactants and products (reverse reaction)
91 for (int i_prod_ind = i_phase * NUM_PROD_;
92 i_prod_ind < (i_phase + 1) * NUM_PROD_; i_prod_ind++) {
93 for (int i_react_dep = i_phase * NUM_REACT_;
94 i_react_dep < (i_phase + 1) * NUM_REACT_; i_react_dep++)
95 jacobian_register_element(jac, REACT_(i_react_dep), PROD_(i_prod_ind));
96 for (int i_prod_dep = i_phase * NUM_PROD_;
97 i_prod_dep < (i_phase + 1) * NUM_PROD_; i_prod_dep++)
98 jacobian_register_element(jac, PROD_(i_prod_dep), PROD_(i_prod_ind));
99 }
100
101 // Add dependence on aerosol-phase water for reactants and products
102 for (int i_react_dep = i_phase * NUM_REACT_;
103 i_react_dep < (i_phase + 1) * NUM_REACT_; i_react_dep++)
104 jacobian_register_element(jac, REACT_(i_react_dep), WATER_(i_phase));
105 for (int i_prod_dep = i_phase * NUM_PROD_;
106 i_prod_dep < (i_phase + 1) * NUM_PROD_; i_prod_dep++)
107 jacobian_register_element(jac, PROD_(i_prod_dep), WATER_(i_phase));
108
109 // Add dependence on activity coefficients for reactants and products
110 if (ACTIVITY_COEFF_(i_phase) < 0) continue;
111 for (int i_react_dep = i_phase * NUM_REACT_;
112 i_react_dep < (i_phase + 1) * NUM_REACT_; ++i_react_dep)
113 jacobian_register_element(jac, REACT_(i_react_dep),
114 ACTIVITY_COEFF_(i_phase));
115 for (int i_prod_dep = i_phase * NUM_PROD_;
116 i_prod_dep < (i_phase + 1) * NUM_PROD_; ++i_prod_dep)
117 jacobian_register_element(jac, PROD_(i_prod_dep),
118 ACTIVITY_COEFF_(i_phase));
119 }
120
121 return;
122}
123
124/** \brief Update the time derivative and Jacbobian array indices
125 *
126 * \param model_data Pointer to the model data
127 * \param deriv_ids Id of each state variable in the derivative array
128 * \param jac Jacobian
129 * \param rxn_int_data Pointer to the reaction integer data
130 * \param rxn_float_data Pointer to the reaction floating-point data
131 */
132void rxn_aqueous_equilibrium_update_ids(ModelData *model_data, int *deriv_ids,
133 Jacobian jac, int *rxn_int_data,
134 double *rxn_float_data) {
135 int *int_data = rxn_int_data;
136 double *float_data = rxn_float_data;
137
138 // Update the time derivative ids
139 for (int i_phase = 0, i_deriv = 0; i_phase < NUM_AERO_PHASE_; i_phase++) {
140 for (int i_react = 0; i_react < NUM_REACT_; i_react++)
141 DERIV_ID_(i_deriv++) = deriv_ids[REACT_(i_phase * NUM_REACT_ + i_react)];
142 for (int i_prod = 0; i_prod < NUM_PROD_; i_prod++)
143 DERIV_ID_(i_deriv++) = deriv_ids[PROD_(i_phase * NUM_PROD_ + i_prod)];
144 }
145
146 // Update the Jacobian ids
147 for (int i_phase = 0, i_jac = 0; i_phase < NUM_AERO_PHASE_; i_phase++) {
148 // Add dependence on reactants for reactants and products (forward reaction)
149 for (int i_react_ind = i_phase * NUM_REACT_;
150 i_react_ind < (i_phase + 1) * NUM_REACT_; i_react_ind++) {
151 for (int i_react_dep = i_phase * NUM_REACT_;
152 i_react_dep < (i_phase + 1) * NUM_REACT_; i_react_dep++)
153 JAC_ID_(i_jac++) = jacobian_get_element_id(jac, REACT_(i_react_dep),
154 REACT_(i_react_ind));
155 for (int i_prod_dep = i_phase * NUM_PROD_;
156 i_prod_dep < (i_phase + 1) * NUM_PROD_; i_prod_dep++)
157 JAC_ID_(i_jac++) = jacobian_get_element_id(jac, PROD_(i_prod_dep),
158 REACT_(i_react_ind));
159 }
160
161 // Add dependence on products for reactants and products (reverse reaction)
162 for (int i_prod_ind = i_phase * NUM_PROD_;
163 i_prod_ind < (i_phase + 1) * NUM_PROD_; i_prod_ind++) {
164 for (int i_react_dep = i_phase * NUM_REACT_;
165 i_react_dep < (i_phase + 1) * NUM_REACT_; i_react_dep++)
166 JAC_ID_(i_jac++) = jacobian_get_element_id(jac, REACT_(i_react_dep),
167 PROD_(i_prod_ind));
168 for (int i_prod_dep = i_phase * NUM_PROD_;
169 i_prod_dep < (i_phase + 1) * NUM_PROD_; i_prod_dep++)
170 JAC_ID_(i_jac++) =
171 jacobian_get_element_id(jac, PROD_(i_prod_dep), PROD_(i_prod_ind));
172 }
173
174 // Add dependence on aerosol-phase water for reactants and products
175 for (int i_react_dep = i_phase * NUM_REACT_;
176 i_react_dep < (i_phase + 1) * NUM_REACT_; i_react_dep++)
177 JAC_ID_(i_jac++) =
178 jacobian_get_element_id(jac, REACT_(i_react_dep), WATER_(i_phase));
179 for (int i_prod_dep = i_phase * NUM_PROD_;
180 i_prod_dep < (i_phase + 1) * NUM_PROD_; i_prod_dep++)
181 JAC_ID_(i_jac++) =
182 jacobian_get_element_id(jac, PROD_(i_prod_dep), WATER_(i_phase));
183
184 // Add dependence on activity coefficients for reactants and products
185 if (ACTIVITY_COEFF_(i_phase) < 0) {
186 for (int i_react_dep = i_phase * NUM_REACT_;
187 i_react_dep < (i_phase + 1) * NUM_REACT_; ++i_react_dep)
188 JAC_ID_(i_jac++) = -1;
189 for (int i_prod_dep = i_phase * NUM_PROD_;
190 i_prod_dep < (i_phase + 1) * NUM_PROD_; ++i_prod_dep)
191 JAC_ID_(i_jac++) = -1;
192 } else {
193 for (int i_react_dep = i_phase * NUM_REACT_;
194 i_react_dep < (i_phase + 1) * NUM_REACT_; ++i_react_dep)
195 JAC_ID_(i_jac++) = jacobian_get_element_id(jac, REACT_(i_react_dep),
196 ACTIVITY_COEFF_(i_phase));
197 for (int i_prod_dep = i_phase * NUM_PROD_;
198 i_prod_dep < (i_phase + 1) * NUM_PROD_; ++i_prod_dep)
199 JAC_ID_(i_jac++) = jacobian_get_element_id(jac, PROD_(i_prod_dep),
200 ACTIVITY_COEFF_(i_phase));
201 }
202 }
203
204 // Calculate a small concentration for aerosol-phase species based on the
205 // integration tolerances to use during solving. TODO find a better place
206 // to do this
207 double *abs_tol = (double *)model_data->abs_tol;
208 for (int i_phase = 0; i_phase < NUM_AERO_PHASE_; i_phase++) {
209 SMALL_CONC_(i_phase) = 99999.0;
210 for (int i_react = 0; i_react < NUM_REACT_; i_react++) {
211 if (SMALL_CONC_(i_phase) >
212 abs_tol[REACT_(i_phase * NUM_REACT_ + i_react)] / 100.0)
213 SMALL_CONC_(i_phase) =
214 abs_tol[REACT_(i_phase * NUM_REACT_ + i_react)] / 100.0;
215 }
216 for (int i_prod = 0; i_prod < NUM_PROD_; i_prod++) {
217 if (SMALL_CONC_(i_phase) >
218 abs_tol[PROD_(i_phase * NUM_PROD_ + i_prod)] / 100.0)
219 SMALL_CONC_(i_phase) =
220 abs_tol[PROD_(i_phase * NUM_PROD_ + i_prod)] / 100.0;
221 }
222 }
223
224 // Calculate a small concentration for aerosol-phase water based on the
225 // integration tolerances to use during solving. TODO find a better place
226 // to do this
227 for (int i_phase = 0; i_phase < NUM_AERO_PHASE_; i_phase++) {
228 SMALL_WATER_CONC_(i_phase) = abs_tol[WATER_(i_phase)] / 10.0;
229 }
230
231 return;
232}
233
234/** \brief Update reaction data for new environmental conditions
235 *
236 * For Aqueous Equilibrium reaction this only involves recalculating the
237 * forward rate constant.
238 *
239 * \param model_data Pointer to the model data
240 * \param rxn_int_data Pointer to the reaction integer data
241 * \param rxn_float_data Pointer to the reaction floating-point data
242 * \param rxn_env_data Pointer to the environment-dependent parameters
243 */
245 int *rxn_int_data,
246 double *rxn_float_data,
247 double *rxn_env_data) {
248 int *int_data = rxn_int_data;
249 double *float_data = rxn_float_data;
250 double *env_data = model_data->grid_cell_env;
251
252 // Calculate the equilibrium constant
253 // (assumes reactant and product concentrations in M)
254 double equil_const;
255 if (C_ == 0.0) {
256 equil_const = A_;
257 } else {
258 equil_const = A_ * exp(C_ * (1.0 / TEMPERATURE_K_ - 1.0 / 298.0));
259 }
260
261 // Set the forward rate constant
263
264 return;
265}
266
267/** \brief Calculate the reaction rate for a set of conditions using the
268 * standard equation per mixing ratio of water [M_X/s*kg_H2O/m^3]
269 * \param rxn_int_data Pointer to the reaction integer data
270 * \param rxn_float_data Pointer to the reaction floating point data
271 * \param rxn_env_data Pointer to the environment-dependent parameters
272 * \param is_water_partial Flag indicating whether the calculation should
273 * return the partial derivative d_rate/d_H2O
274 * \param rate_forward [output] calculated forward rate
275 * \param rate_reverse [output] calculated reverse rate
276 * \return reaction rate per mixing ratio of water [M_X/s*kg_H2O/m^3]
277 */
278long double calc_standard_rate(int *rxn_int_data, double *rxn_float_data,
279 double *rxn_env_data, bool is_water_partial,
280 long double *rate_forward,
281 long double *rate_reverse) {
282 int *int_data = rxn_int_data;
283 double *float_data = rxn_float_data;
284
285 long double react_fact, prod_fact;
286 long double water = WATER_CONC_;
287
288 // Get the product of all reactants
289 react_fact = (long double)REACT_CONC_(0) * MASS_FRAC_TO_M_(0);
290 for (int i_react = 1; i_react < NUM_REACT_; i_react++) {
291 react_fact *= REACT_CONC_(i_react) * MASS_FRAC_TO_M_(i_react) / water;
292 }
293
294 // Get the product of all product
295 prod_fact = (long double)PROD_CONC_(0) * MASS_FRAC_TO_M_(NUM_REACT_);
296 prod_fact *= (long double)ACTIVITY_COEFF_VALUE_;
297 for (int i_prod = 1; i_prod < NUM_PROD_; i_prod++) {
298 prod_fact *=
299 PROD_CONC_(i_prod) * MASS_FRAC_TO_M_(NUM_REACT_ + i_prod) / water;
300 }
301
302 *rate_forward = RATE_CONST_FORWARD_ * react_fact;
303 *rate_reverse = RATE_CONST_REVERSE_ * prod_fact;
304
305 if (is_water_partial) {
306 return *rate_forward * (NUM_REACT_ - 1) - *rate_reverse * (NUM_PROD_ - 1);
307 } else {
308 return *rate_forward - *rate_reverse;
309 }
310}
311
312/** \brief Calculate contributions to the time derivative \f$f(t,y)\f$ from
313 * this reaction.
314 *
315 * \param model_data Pointer to the model data, including the state array
316 * \param time_deriv TimeDerivative object
317 * \param rxn_int_data Pointer to the reaction integer data
318 * \param rxn_float_data Pointer to the reaction floating-point data
319 * \param rxn_env_data Pointer to the environment-dependent parameters
320 * \param time_step Current time step of the itegrator (s)
321 */
322#ifdef CAMP_USE_SUNDIALS
324 ModelData *model_data, TimeDerivative time_deriv, int *rxn_int_data,
325 double *rxn_float_data, double *rxn_env_data, double time_step) {
326 int *int_data = rxn_int_data;
327 double *float_data = rxn_float_data;
328 double *state = model_data->grid_cell_state;
329 double *env_data = model_data->grid_cell_env;
330
331 // Calculate derivative contributions for each aerosol phase
332 for (int i_phase = 0, i_deriv = 0; i_phase < NUM_AERO_PHASE_; i_phase++) {
333 // If no aerosol water is present, no reaction occurs
334 long double water = state[WATER_(i_phase)];
335 if (water < MIN_WATER_ * SMALL_WATER_CONC_(i_phase)) {
336 i_deriv += NUM_REACT_ + NUM_PROD_;
337 continue;
338 }
339
340 // Set the concentrations for all species and the activity coefficient
341 for (int i_react = 0; i_react < NUM_REACT_; ++i_react)
342 REACT_CONC_(i_react) = state[REACT_(i_phase * NUM_REACT_ + i_react)];
343 for (int i_prod = 0; i_prod < NUM_PROD_; ++i_prod)
344 PROD_CONC_(i_prod) = state[PROD_(i_phase * NUM_PROD_ + i_prod)];
345 WATER_CONC_ = state[WATER_(i_phase)];
346 if (ACTIVITY_COEFF_(i_phase) >= 0) {
347 ACTIVITY_COEFF_VALUE_ = state[ACTIVITY_COEFF_(i_phase)];
348 } else {
350 }
351
352 // Get the rate using the standard calculation
353 long double rate_forward, rate_reverse;
354 long double rate =
355 calc_standard_rate(rxn_int_data, rxn_float_data, rxn_env_data, false,
356 &rate_forward, &rate_reverse);
357 if (rate == ZERO) {
358 i_deriv += NUM_REACT_ + NUM_PROD_;
359 continue;
360 }
361
362 // Reactants change as (reverse - forward) (kg/m3/s)
363 for (int i_react = 0; i_react < NUM_REACT_; i_react++) {
364 if (DERIV_ID_(i_deriv) < 0) {
365 i_deriv++;
366 continue;
367 }
368 time_derivative_add_value(time_deriv, DERIV_ID_(i_deriv),
369 -rate_forward / MASS_FRAC_TO_M_(i_react));
370 time_derivative_add_value(time_deriv, DERIV_ID_(i_deriv++),
371 rate_reverse / MASS_FRAC_TO_M_(i_react));
372 }
373
374 // Products change as (forward - reverse) (kg/m3/s)
375 for (int i_prod = 0; i_prod < NUM_PROD_; i_prod++) {
376 if (DERIV_ID_(i_deriv) < 0) {
377 i_deriv++;
378 continue;
379 }
381 time_deriv, DERIV_ID_(i_deriv),
382 rate_forward / MASS_FRAC_TO_M_(NUM_REACT_ + i_prod));
384 time_deriv, DERIV_ID_(i_deriv++),
385 -rate_reverse / MASS_FRAC_TO_M_(NUM_REACT_ + i_prod));
386 }
387 }
388
389 return;
390}
391#endif
392
393/** \brief Calculate contributions to the Jacobian from this reaction
394 *
395 * \param model_data Pointer to the model data
396 * \param jac Reaction Jacobian
397 * \param rxn_int_data Pointer to the reaction integer data
398 * \param rxn_float_data Pointer to the reaction floating-point data
399 * \param rxn_env_data Pointer to the environment-dependent parameters
400 * \param time_step Current time step of the itegrator (s)
401 */
402#ifdef CAMP_USE_SUNDIALS
404 Jacobian jac, int *rxn_int_data,
405 double *rxn_float_data,
406 double *rxn_env_data,
407 double time_step) {
408 int *int_data = rxn_int_data;
409 double *float_data = rxn_float_data;
410 double *state = model_data->grid_cell_state;
411 double *env_data = model_data->grid_cell_env;
412
413 // Calculate Jacobian contributions for each aerosol phase
414 for (int i_phase = 0, i_jac = 0; i_phase < NUM_AERO_PHASE_; i_phase++) {
415 // If not aerosol water is present, no reaction occurs
416 long double water = state[WATER_(i_phase)];
417 if (water < MIN_WATER_ * SMALL_WATER_CONC_(i_phase)) {
418 i_jac += (NUM_REACT_ + NUM_PROD_) * (NUM_REACT_ + NUM_PROD_ + 2);
419 continue;
420 }
421
422 // Calculate the forward rate (M/s)
423 long double forward_rate = RATE_CONST_FORWARD_;
424 for (int i_react = 0; i_react < NUM_REACT_; i_react++) {
425 forward_rate *= state[REACT_(i_phase * NUM_REACT_ + i_react)] *
426 MASS_FRAC_TO_M_(i_react) / water;
427 }
428
429 // Calculate the reverse rate (M/s)
430 long double reverse_rate = RATE_CONST_REVERSE_;
431 for (int i_prod = 0; i_prod < NUM_PROD_; i_prod++) {
432 reverse_rate *= state[PROD_(i_phase * NUM_PROD_ + i_prod)] *
433 MASS_FRAC_TO_M_(NUM_REACT_ + i_prod) / water;
434 }
435 if (ACTIVITY_COEFF_(i_phase) >= 0)
436 reverse_rate *= state[ACTIVITY_COEFF_(i_phase)];
437
438 // Add dependence on reactants for reactants and products (forward reaction)
439 for (int i_react_ind = 0; i_react_ind < NUM_REACT_; i_react_ind++) {
440 for (int i_react_dep = 0; i_react_dep < NUM_REACT_; i_react_dep++) {
441 if (JAC_ID_(i_jac) < 0 || forward_rate == 0.0) {
442 i_jac++;
443 continue;
444 }
446 jac, (unsigned int)JAC_ID_(i_jac++), JACOBIAN_LOSS,
447 forward_rate / state[REACT_(i_phase * NUM_REACT_ + i_react_ind)] /
448 MASS_FRAC_TO_M_(i_react_dep) * water);
449 }
450 for (int i_prod_dep = 0; i_prod_dep < NUM_PROD_; i_prod_dep++) {
451 if (JAC_ID_(i_jac) < 0 || forward_rate == 0.0) {
452 i_jac++;
453 continue;
454 }
456 jac, (unsigned int)JAC_ID_(i_jac++), JACOBIAN_PRODUCTION,
457 forward_rate / state[REACT_(i_phase * NUM_REACT_ + i_react_ind)] /
458 MASS_FRAC_TO_M_(NUM_REACT_ + i_prod_dep) * water);
459 }
460 }
461
462 // Add dependence on products for reactants and products (reverse reaction)
463 for (int i_prod_ind = 0; i_prod_ind < NUM_PROD_; i_prod_ind++) {
464 for (int i_react_dep = 0; i_react_dep < NUM_REACT_; i_react_dep++) {
465 if (JAC_ID_(i_jac) < 0 || reverse_rate == 0.0) {
466 i_jac++;
467 continue;
468 }
470 jac, (unsigned int)JAC_ID_(i_jac++), JACOBIAN_PRODUCTION,
471 reverse_rate / state[PROD_(i_phase * NUM_PROD_ + i_prod_ind)] /
472 MASS_FRAC_TO_M_(i_react_dep) * water);
473 }
474 for (int i_prod_dep = 0; i_prod_dep < NUM_PROD_; i_prod_dep++) {
475 if (JAC_ID_(i_jac) < 0 || reverse_rate == 0.0) {
476 i_jac++;
477 continue;
478 }
480 jac, (unsigned int)JAC_ID_(i_jac++), JACOBIAN_LOSS,
481 reverse_rate / state[PROD_(i_phase * NUM_PROD_ + i_prod_ind)] /
482 MASS_FRAC_TO_M_(NUM_REACT_ + i_prod_dep) * water);
483 }
484 }
485
486 // Add dependence on aerosol-phase water for reactants and products
487 for (int i_react_dep = 0; i_react_dep < NUM_REACT_; i_react_dep++) {
488 if (JAC_ID_(i_jac) < 0) {
489 i_jac++;
490 continue;
491 }
493 jac, (unsigned int)JAC_ID_(i_jac), JACOBIAN_LOSS,
494 -forward_rate / MASS_FRAC_TO_M_(i_react_dep) * (NUM_REACT_ - 1));
496 jac, (unsigned int)JAC_ID_(i_jac++), JACOBIAN_PRODUCTION,
497 -reverse_rate / MASS_FRAC_TO_M_(i_react_dep) * (NUM_PROD_ - 1));
498 }
499 for (int i_prod_dep = 0; i_prod_dep < NUM_PROD_; i_prod_dep++) {
500 if (JAC_ID_(i_jac) < 0) {
501 i_jac++;
502 continue;
503 }
504 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_jac), JACOBIAN_PRODUCTION,
505 -forward_rate /
506 MASS_FRAC_TO_M_(NUM_REACT_ + i_prod_dep) *
507 (NUM_REACT_ - 1));
508 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_jac++), JACOBIAN_LOSS,
509 -reverse_rate /
510 MASS_FRAC_TO_M_(NUM_REACT_ + i_prod_dep) *
511 (NUM_PROD_ - 1));
512 }
513
514 // Add dependence on activity coefficients for reactants and products
515 if (ACTIVITY_COEFF_(i_phase) < 0) {
516 i_jac += NUM_REACT_ + NUM_PROD_;
517 continue;
518 }
519 for (int i_react_dep = 0; i_react_dep < NUM_REACT_; i_react_dep++) {
520 if (JAC_ID_(i_jac) < 0) {
521 i_jac++;
522 continue;
523 }
524 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_jac++),
526 reverse_rate / state[ACTIVITY_COEFF_(i_phase)] /
527 MASS_FRAC_TO_M_(i_react_dep) * water);
528 }
529 for (int i_prod_dep = 0; i_prod_dep < NUM_PROD_; i_prod_dep++) {
530 if (JAC_ID_(i_jac) < 0) {
531 i_jac++;
532 continue;
533 }
534 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_jac++), JACOBIAN_LOSS,
535 reverse_rate / state[ACTIVITY_COEFF_(i_phase)] /
536 MASS_FRAC_TO_M_(NUM_REACT_ + i_prod_dep) * water);
537 }
538 }
539
540 return;
541}
542#endif
543
544/** \brief Print the Aqueous Equilibrium reaction parameters
545 *
546 * \param rxn_int_data Pointer to the reaction integer data
547 * \param rxn_float_data Pointer to the reaction floating-point data
548 */
549void rxn_aqueous_equilibrium_print(int *rxn_int_data, double *rxn_float_data) {
550 int *int_data = rxn_int_data;
551 double *float_data = rxn_float_data;
552
553 printf("\n\nAqueous Equilibrium reaction\n");
554
555 return;
556}
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_add_value(Jacobian jac, unsigned int elem_id, unsigned int prod_or_loss, long double jac_contribution)
Add a contribution to the Jacobian.
Definition Jacobian.c:234
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
#define JACOBIAN_LOSS
Definition Jacobian.h:19
#define JACOBIAN_PRODUCTION
Definition Jacobian.h:18
#define ZERO
Definition camp_common.h:42
void rxn_aqueous_equilibrium_update_env_state(ModelData *model_data, int *rxn_int_data, double *rxn_float_data, double *rxn_env_data)
Update reaction data for new environmental conditions.
#define NUM_REACT_
#define SMALL_WATER_CONC_(x)
#define WATER_(x)
void rxn_aqueous_equilibrium_calc_jac_contrib(ModelData *model_data, Jacobian jac, int *rxn_int_data, double *rxn_float_data, double *rxn_env_data, double time_step)
Calculate contributions to the Jacobian from this reaction.
#define MIN_WATER_
#define REACT_CONC_(x)
#define RATE_CONST_REVERSE_
#define RATE_CONST_FORWARD_
void rxn_aqueous_equilibrium_calc_deriv_contrib(ModelData *model_data, TimeDerivative time_deriv, int *rxn_int_data, double *rxn_float_data, double *rxn_env_data, double time_step)
Calculate contributions to the time derivative from this reaction.
#define A_
#define MASS_FRAC_TO_M_(x)
void rxn_aqueous_equilibrium_print(int *rxn_int_data, double *rxn_float_data)
Print the Aqueous Equilibrium reaction parameters.
#define WATER_CONC_
#define SMALL_CONC_(x)
#define ACTIVITY_COEFF_(x)
#define PROD_(x)
#define TEMPERATURE_K_
#define JAC_ID_(x)
void rxn_aqueous_equilibrium_get_used_jac_elem(int *rxn_int_data, double *rxn_float_data, Jacobian *jac)
Flag Jacobian elements used by this reaction.
#define NUM_PROD_
#define C_
#define ACTIVITY_COEFF_VALUE_
#define NUM_AERO_PHASE_
#define PROD_CONC_(x)
#define REACT_(x)
void rxn_aqueous_equilibrium_update_ids(ModelData *model_data, int *deriv_ids, Jacobian jac, int *rxn_int_data, double *rxn_float_data)
Update the time derivative and Jacbobian array indices.
#define DERIV_ID_(x)
long double calc_standard_rate(int *rxn_int_data, double *rxn_float_data, double *rxn_env_data, bool is_water_partial, long double *rate_forward, long double *rate_reverse)
Calculate the reaction rate for a set of conditions using the standard equation per mixing ratio of w...
double * grid_cell_env
double * grid_cell_state
double * abs_tol
Definition camp_common.h:72
void time_derivative_add_value(TimeDerivative time_deriv, unsigned int spec_id, long double rate_contribution)
Add a contribution to the time derivative.