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