CAMP 1.0.0
Chemistry Across Multiple Phases
rxn_arrhenius.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 * Arrhenius reaction solver functions
6 *
7 */
8/** \file
9 * \brief Arrhenius 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#define NUM_REACT_ int_data[0]
21#define NUM_PROD_ int_data[1]
22#define A_ float_data[0]
23#define B_ float_data[1]
24#define C_ float_data[2]
25#define D_ float_data[3]
26#define E_ float_data[4]
27#define CONV_ float_data[5]
28#define RATE_CONSTANT_ rxn_env_data[0]
29#define NUM_INT_PROP_ 2
30#define NUM_FLOAT_PROP_ 6
31#define NUM_ENV_PARAM_ 1
32#define REACT_(x) (int_data[NUM_INT_PROP_ + x] - 1)
33#define PROD_(x) (int_data[NUM_INT_PROP_ + NUM_REACT_ + x] - 1)
34#define DERIV_ID_(x) int_data[NUM_INT_PROP_ + NUM_REACT_ + NUM_PROD_ + x]
35#define JAC_ID_(x) int_data[NUM_INT_PROP_ + 2 * (NUM_REACT_ + NUM_PROD_) + x]
36#define YIELD_(x) float_data[NUM_FLOAT_PROP_ + x]
37
38/** \brief Flag Jacobian elements used by this reaction
39 *
40 * \param rxn_int_data Pointer to the reaction integer data
41 * \param rxn_float_data Pointer to the reaction floating-point data
42 * \param jac Jacobian
43 */
44void rxn_arrhenius_get_used_jac_elem(int *rxn_int_data, double *rxn_float_data,
45 Jacobian *jac) {
46 int *int_data = rxn_int_data;
47 double *float_data = rxn_float_data;
48
49 for (int i_ind = 0; i_ind < NUM_REACT_; i_ind++) {
50 for (int i_dep = 0; i_dep < NUM_REACT_; i_dep++) {
51 jacobian_register_element(jac, REACT_(i_dep), REACT_(i_ind));
52 }
53 for (int i_dep = 0; i_dep < NUM_PROD_; i_dep++) {
54 jacobian_register_element(jac, PROD_(i_dep), REACT_(i_ind));
55 }
56 }
57
58 return;
59}
60
61/** \brief Update the time derivative and Jacbobian array indices
62 *
63 * \param model_data Pointer to the model data
64 * \param deriv_ids Id of each state variable in the derivative array
65 * \param jac Jacobian
66 * \param rxn_int_data Pointer to the reaction integer data
67 * \param rxn_float_data Pointer to the reaction floating-point data
68 */
69void rxn_arrhenius_update_ids(ModelData *model_data, int *deriv_ids,
70 Jacobian jac, int *rxn_int_data,
71 double *rxn_float_data) {
72 int *int_data = rxn_int_data;
73 double *float_data = rxn_float_data;
74
75 // Update the time derivative ids
76 for (int i = 0; i < NUM_REACT_; i++) DERIV_ID_(i) = deriv_ids[REACT_(i)];
77 for (int i = 0; i < NUM_PROD_; i++)
78 DERIV_ID_(i + NUM_REACT_) = deriv_ids[PROD_(i)];
79
80 // Update the Jacobian ids
81 int i_jac = 0;
82 for (int i_ind = 0; i_ind < NUM_REACT_; i_ind++) {
83 for (int i_dep = 0; i_dep < NUM_REACT_; i_dep++)
84 JAC_ID_(i_jac++) =
85 jacobian_get_element_id(jac, REACT_(i_dep), REACT_(i_ind));
86 for (int i_dep = 0; i_dep < NUM_PROD_; i_dep++)
87 JAC_ID_(i_jac++) =
88 jacobian_get_element_id(jac, PROD_(i_dep), REACT_(i_ind));
89 }
90 return;
91}
92
93/** \brief Update reaction data for new environmental conditions
94 *
95 * For Arrhenius reaction this only involves recalculating the rate
96 * constant.
97 *
98 * \param model_data Pointer to the model data
99 * \param rxn_int_data Pointer to the reaction integer data
100 * \param rxn_float_data Pointer to the reaction floating-point data
101 * \param rxn_env_data Pointer to the environment-dependent parameters
102 */
103void rxn_arrhenius_update_env_state(ModelData *model_data, int *rxn_int_data,
104 double *rxn_float_data,
105 double *rxn_env_data) {
106 int *int_data = rxn_int_data;
107 double *float_data = rxn_float_data;
108 double *env_data = model_data->grid_cell_env;
109
110 // Calculate the rate constant in (#/cc)
111 // k = A*exp(C/T) * (T/D)^B * (1+E*P)
113 (B_ == 0.0 ? 1.0 : pow(TEMPERATURE_K_ / D_, B_)) *
114 (E_ == 0.0 ? 1.0 : (1.0 + E_ * PRESSURE_PA_)) *
116
117 return;
118}
119
120/** \brief Calculate contributions to the time derivative \f$f(t,y)\f$ from
121 * this reaction.
122 *
123 * \param model_data Model data
124 * \param time_deriv TimeDerivative object
125 * \param rxn_int_data Pointer to the reaction integer data
126 * \param rxn_float_data Pointer to the reaction floating-point data
127 * \param rxn_env_data Pointer to the environment-dependent parameters
128 * \param time_step Current time step being computed (s)
129 */
130#ifdef CAMP_USE_SUNDIALS
132 TimeDerivative time_deriv,
133 int *rxn_int_data, double *rxn_float_data,
134 double *rxn_env_data, double time_step) {
135 int *int_data = rxn_int_data;
136 double *float_data = rxn_float_data;
137 double *state = model_data->grid_cell_state;
138 double *env_data = model_data->grid_cell_env;
139
140 // Calculate the reaction rate
141 long double rate = RATE_CONSTANT_;
142 for (int i_spec = 0; i_spec < NUM_REACT_; i_spec++)
143 rate *= state[REACT_(i_spec)];
144
145 // Add contributions to the time derivative
146 if (rate != ZERO) {
147 int i_dep_var = 0;
148 for (int i_spec = 0; i_spec < NUM_REACT_; i_spec++, i_dep_var++) {
149 if (DERIV_ID_(i_dep_var) < 0) continue;
150 time_derivative_add_value(time_deriv, DERIV_ID_(i_dep_var), -rate);
151 }
152 for (int i_spec = 0; i_spec < NUM_PROD_; i_spec++, i_dep_var++) {
153 if (DERIV_ID_(i_dep_var) < 0) continue;
154
155 // Negative yields are allowed, but prevented from causing negative
156 // concentrations that lead to solver failures
157 if (-rate * YIELD_(i_spec) * time_step <= state[PROD_(i_spec)]) {
158 time_derivative_add_value(time_deriv, DERIV_ID_(i_dep_var),
159 rate * YIELD_(i_spec));
160 }
161 }
162 }
163
164 return;
165}
166#endif
167
168/** \brief Calculate contributions to the Jacobian from this reaction
169 *
170 * \param model_data Model data
171 * \param jac Reaction Jacobian
172 * \param rxn_int_data Pointer to the reaction integer data
173 * \param rxn_float_data Pointer to the reaction floating-point data
174 * \param rxn_env_data Pointer to the environment-dependent parameters
175 * \param time_step Current time step being calculated (s)
176 */
177#ifdef CAMP_USE_SUNDIALS
179 int *rxn_int_data, double *rxn_float_data,
180 double *rxn_env_data, double time_step) {
181 int *int_data = rxn_int_data;
182 double *float_data = rxn_float_data;
183 double *state = model_data->grid_cell_state;
184 double *env_data = model_data->grid_cell_env;
185
186 // Add contributions to the Jacobian
187 int i_elem = 0;
188 for (int i_ind = 0; i_ind < NUM_REACT_; i_ind++) {
189 // Calculate d_rate / d_i_ind
190 realtype rate = RATE_CONSTANT_;
191 for (int i_spec = 0; i_spec < NUM_REACT_; i_spec++)
192 if (i_spec != i_ind) rate *= state[REACT_(i_spec)];
193
194 for (int i_dep = 0; i_dep < NUM_REACT_; i_dep++, i_elem++) {
195 if (JAC_ID_(i_elem) < 0) continue;
196 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_elem), JACOBIAN_LOSS,
197 rate);
198 }
199 for (int i_dep = 0; i_dep < NUM_PROD_; i_dep++, i_elem++) {
200 if (JAC_ID_(i_elem) < 0) continue;
201 // Negative yields are allowed, but prevented from causing negative
202 // concentrations that lead to solver failures
203 if (-rate * state[REACT_(i_ind)] * YIELD_(i_dep) * time_step <=
204 state[PROD_(i_dep)]) {
205 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_elem),
206 JACOBIAN_PRODUCTION, YIELD_(i_dep) * rate);
207 }
208 }
209 }
210
211 return;
212}
213#endif
214
215/** \brief Print the Arrhenius reaction parameters
216 *
217 * \param rxn_int_data Pointer to the reaction integer data
218 * \param rxn_float_data Pointer to the reaction floating-point data
219 */
220void rxn_arrhenius_print(int *rxn_int_data, double *rxn_float_data) {
221 int *int_data = rxn_int_data;
222 double *float_data = rxn_float_data;
223
224 printf("\n\nArrhenius reaction\n");
225
226 return;
227}
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
#define NUM_REACT_
#define PRESSURE_PA_
#define RATE_CONSTANT_
#define A_
void rxn_arrhenius_get_used_jac_elem(int *rxn_int_data, double *rxn_float_data, Jacobian *jac)
Flag Jacobian elements used by this reaction.
void rxn_arrhenius_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 E_
void rxn_arrhenius_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 CONV_
void rxn_arrhenius_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 B_
#define YIELD_(x)
#define PROD_(x)
void rxn_arrhenius_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 TEMPERATURE_K_
#define JAC_ID_(x)
#define D_
#define NUM_PROD_
#define C_
#define REACT_(x)
#define DERIV_ID_(x)
void rxn_arrhenius_print(int *rxn_int_data, double *rxn_float_data)
Print the Arrhenius reaction parameters.
double * grid_cell_env
double * grid_cell_state
void time_derivative_add_value(TimeDerivative time_deriv, unsigned int spec_id, long double rate_contribution)
Add a contribution to the time derivative.