CAMP 1.0.0
Chemistry Across Multiple Phases
rxn_photolysis.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 * Photolysis reaction solver functions
6 *
7 */
8/** \file
9 * \brief Photolysis 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 RXN_ID_ int_data[2]
23#define SCALING_ float_data[0]
24#define RATE_CONSTANT_ (rxn_env_data[0])
25#define BASE_RATE_ (rxn_env_data[1])
26#define NUM_INT_PROP_ 3
27#define NUM_FLOAT_PROP_ 1
28#define NUM_ENV_PARAM_ 2
29#define REACT_(x) (int_data[NUM_INT_PROP_ + x] - 1)
30#define PROD_(x) (int_data[NUM_INT_PROP_ + NUM_REACT_ + x] - 1)
31#define DERIV_ID_(x) int_data[NUM_INT_PROP_ + NUM_REACT_ + NUM_PROD_ + x]
32#define JAC_ID_(x) int_data[NUM_INT_PROP_ + 2 * (NUM_REACT_ + NUM_PROD_) + x]
33#define YIELD_(x) float_data[NUM_FLOAT_PROP_ + x]
34
35/** \brief Flag Jacobian elements used by this reaction
36 *
37 * \param rxn_int_data Pointer to the reaction integer data
38 * \param rxn_float_data Pointer to the reaction floating-point data
39 * \param jac Jacobian
40 */
41void rxn_photolysis_get_used_jac_elem(int *rxn_int_data, double *rxn_float_data,
42 Jacobian *jac) {
43 int *int_data = rxn_int_data;
44 double *float_data = rxn_float_data;
45
46 for (int i_ind = 0; i_ind < NUM_REACT_; i_ind++) {
47 for (int i_dep = 0; i_dep < NUM_REACT_; i_dep++) {
48 jacobian_register_element(jac, REACT_(i_dep), REACT_(i_ind));
49 }
50 for (int i_dep = 0; i_dep < NUM_PROD_; i_dep++) {
51 jacobian_register_element(jac, PROD_(i_dep), REACT_(i_ind));
52 }
53 }
54
55 return;
56}
57
58/** \brief Update the time derivative and Jacbobian array indices
59 *
60 * \param model_data Pointer to the model data
61 * \param deriv_ids Id of each state variable in the derivative array
62 * \param jac Jacobian
63 * \param rxn_int_data Pointer to the reaction integer data
64 * \param rxn_float_data Pointer to the reaction floating-point data
65 */
66void rxn_photolysis_update_ids(ModelData *model_data, int *deriv_ids,
67 Jacobian jac, int *rxn_int_data,
68 double *rxn_float_data) {
69 int *int_data = rxn_int_data;
70 double *float_data = rxn_float_data;
71
72 // Update the time derivative ids
73 for (int i = 0; i < NUM_REACT_; i++) DERIV_ID_(i) = deriv_ids[REACT_(i)];
74 for (int i = 0; i < NUM_PROD_; i++)
75 DERIV_ID_(i + NUM_REACT_) = deriv_ids[PROD_(i)];
76
77 // Update the Jacobian ids
78 int i_jac = 0;
79 for (int i_ind = 0; i_ind < NUM_REACT_; i_ind++) {
80 for (int i_dep = 0; i_dep < NUM_REACT_; i_dep++) {
81 JAC_ID_(i_jac++) =
82 jacobian_get_element_id(jac, REACT_(i_dep), REACT_(i_ind));
83 }
84 for (int i_dep = 0; i_dep < NUM_PROD_; i_dep++) {
85 JAC_ID_(i_jac++) =
86 jacobian_get_element_id(jac, PROD_(i_dep), REACT_(i_ind));
87 }
88 }
89 return;
90}
91
92/** \brief Update reaction data
93 *
94 * Photolysis reactions can have their base (pre-scaling) rate constants updated
95 * from the host model based on the calculations of an external photolysis
96 * module. The structure of the update data is:
97 *
98 * - \b int photo_id (Id of one or more photolysis reactions set by the host
99 * model using the camp_rxn_photolysis::rxn_photolysis_t::set_photo_id
100 * function prior to initializing the solver.)
101 * - \b double rate_const (New pre-scaling rate constant.)
102 *
103 * \param update_data Pointer to the updated reaction data
104 * \param rxn_int_data Pointer to the reaction integer data
105 * \param rxn_float_data Pointer to the reaction floating-point data
106 * \param rxn_env_data Pointer to the environment-dependent data
107 * \return Flag indicating whether this is the reaction to update
108 */
109bool rxn_photolysis_update_data(void *update_data, int *rxn_int_data,
110 double *rxn_float_data, double *rxn_env_data) {
111 int *int_data = rxn_int_data;
112 double *float_data = rxn_float_data;
113
114 int *photo_id = (int *)update_data;
115 double *base_rate = (double *)&(photo_id[1]);
116
117 // Set the base photolysis rate constants for matching reactions
118 if (*photo_id == RXN_ID_ && RXN_ID_ > 0) {
119 BASE_RATE_ = (double)*base_rate;
121 return true;
122 }
123
124 return false;
125}
126
127/** \brief Update reaction data for new environmental conditions
128 *
129 * For Photolysis reaction this only involves recalculating the rate
130 * constant.
131 *
132 * \param model_data Pointer to the model data
133 * \param rxn_int_data Pointer to the reaction integer data
134 * \param rxn_float_data Pointer to the reaction floating-point data
135 * \param rxn_env_data Pointer to the environment-dependent parameters
136 */
137void rxn_photolysis_update_env_state(ModelData *model_data, int *rxn_int_data,
138 double *rxn_float_data,
139 double *rxn_env_data) {
140 int *int_data = rxn_int_data;
141 double *float_data = rxn_float_data;
142 double *env_data = model_data->grid_cell_env;
143
144 // Calculate the rate constant in (1/s)
146
147 return;
148}
149
150/** \brief Calculate contributions to the time derivative \f$f(t,y)\f$ from
151 * this reaction.
152 *
153 * \param model_data Pointer to the model data, including the state array
154 * \param time_deriv TimeDerivative object
155 * \param rxn_int_data Pointer to the reaction integer data
156 * \param rxn_float_data Pointer to the reaction floating-point data
157 * \param rxn_env_data Pointer to the environment-dependent parameters
158 * \param time_step Current time step being computed (s)
159 */
160#ifdef CAMP_USE_SUNDIALS
162 ModelData *model_data, TimeDerivative time_deriv, int *rxn_int_data,
163 double *rxn_float_data, double *rxn_env_data, realtype time_step) {
164 int *int_data = rxn_int_data;
165 double *float_data = rxn_float_data;
166 double *state = model_data->grid_cell_state;
167 double *env_data = model_data->grid_cell_env;
168
169 // Calculate the reaction rate
170 long double rate = RATE_CONSTANT_;
171 for (int i_spec = 0; i_spec < NUM_REACT_; i_spec++)
172 rate *= state[REACT_(i_spec)];
173
174 // Add contributions to the time derivative
175 if (rate != ZERO) {
176 int i_dep_var = 0;
177 for (int i_spec = 0; i_spec < NUM_REACT_; i_spec++, i_dep_var++) {
178 if (DERIV_ID_(i_dep_var) < 0) continue;
179 time_derivative_add_value(time_deriv, DERIV_ID_(i_dep_var), -rate);
180 }
181 for (int i_spec = 0; i_spec < NUM_PROD_; i_spec++, i_dep_var++) {
182 if (DERIV_ID_(i_dep_var) < 0) continue;
183
184 // Negative yields are allowed, but prevented from causing negative
185 // concentrations that lead to solver failures
186 if (-rate * YIELD_(i_spec) * time_step <= state[PROD_(i_spec)]) {
187 time_derivative_add_value(time_deriv, DERIV_ID_(i_dep_var),
188 rate * YIELD_(i_spec));
189 }
190 }
191 }
192
193 return;
194}
195#endif
196
197/** \brief Calculate contributions to the Jacobian from this reaction
198 *
199 * \param model_data Pointer to the model data
200 * \param jac Reaction Jacobian
201 * \param rxn_int_data Pointer to the reaction integer data
202 * \param rxn_float_data Pointer to the reaction floating-point data
203 * \param rxn_env_data Pointer to the environment-dependent parameters
204 * \param time_step Current time step being calculated (s)
205 */
206#ifdef CAMP_USE_SUNDIALS
208 int *rxn_int_data, double *rxn_float_data,
209 double *rxn_env_data, realtype time_step) {
210 int *int_data = rxn_int_data;
211 double *float_data = rxn_float_data;
212 double *state = model_data->grid_cell_state;
213 double *env_data = model_data->grid_cell_env;
214
215 // Add contributions to the Jacobian
216 int i_elem = 0;
217 for (int i_ind = 0; i_ind < NUM_REACT_; i_ind++) {
218 // Calculate d_rate / d_i_ind
219 realtype rate = RATE_CONSTANT_;
220 for (int i_spec = 0; i_spec < NUM_REACT_; i_spec++)
221 if (i_spec != i_ind) rate *= state[REACT_(i_spec)];
222
223 for (int i_dep = 0; i_dep < NUM_REACT_; i_dep++, i_elem++) {
224 if (JAC_ID_(i_elem) < 0) continue;
225 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_elem), JACOBIAN_LOSS,
226 rate);
227 }
228 for (int i_dep = 0; i_dep < NUM_PROD_; i_dep++, i_elem++) {
229 if (JAC_ID_(i_elem) < 0) continue;
230 // Negative yields are allowed, but prevented from causing negative
231 // concentrations that lead to solver failures
232 if (-rate * state[REACT_(i_ind)] * YIELD_(i_dep) * time_step <=
233 state[PROD_(i_dep)]) {
234 jacobian_add_value(jac, (unsigned int)JAC_ID_(i_elem),
235 JACOBIAN_PRODUCTION, YIELD_(i_dep) * rate);
236 }
237 }
238 }
239
240 return;
241}
242#endif
243
244/** \brief Print the Photolysis reaction parameters
245 *
246 * \param rxn_int_data Pointer to the reaction integer data
247 * \param rxn_float_data Pointer to the reaction floating-point data
248 */
249void rxn_photolysis_print(int *rxn_int_data, double *rxn_float_data) {
250 int *int_data = rxn_int_data;
251 double *float_data = rxn_float_data;
252
253 printf("\n\nPhotolysis reaction\n");
254
255 return;
256}
257
258/** \brief Create update data for new photolysis rates
259 *
260 * \return Pointer to a new rate update data object
261 */
263 int *update_data = (int *)malloc(sizeof(int) + sizeof(double));
264 if (update_data == NULL) {
265 printf("\n\nERROR allocating space for photolysis update data\n\n");
266 exit(1);
267 }
268 return (void *)update_data;
269}
270
271/** \brief Set rate update data
272 *
273 * \param update_data Pointer to an allocated rate update data object
274 * \param photo_id Id of photolysis reactions to update
275 * \param base_rate New pre-scaling photolysis rate
276 */
277void rxn_photolysis_set_rate_update_data(void *update_data, int photo_id,
278 double base_rate) {
279 int *new_photo_id = (int *)update_data;
280 double *new_base_rate = (double *)&(new_photo_id[1]);
281 *new_photo_id = photo_id;
282 *new_base_rate = base_rate;
283}
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_
void rxn_photolysis_calc_jac_contrib(ModelData *model_data, Jacobian jac, int *rxn_int_data, double *rxn_float_data, double *rxn_env_data, realtype time_step)
Calculate contributions to the Jacobian from this reaction.
#define SCALING_
bool rxn_photolysis_update_data(void *update_data, int *rxn_int_data, double *rxn_float_data, double *rxn_env_data)
Update reaction data.
#define RATE_CONSTANT_
void rxn_photolysis_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.
void * rxn_photolysis_create_rate_update_data()
Create update data for new photolysis rates.
void rxn_photolysis_calc_deriv_contrib(ModelData *model_data, TimeDerivative time_deriv, int *rxn_int_data, double *rxn_float_data, double *rxn_env_data, realtype time_step)
Calculate contributions to the time derivative from this reaction.
#define BASE_RATE_
#define RXN_ID_
#define YIELD_(x)
#define PROD_(x)
void rxn_photolysis_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_
#define REACT_(x)
void rxn_photolysis_print(int *rxn_int_data, double *rxn_float_data)
Print the Photolysis reaction parameters.
void rxn_photolysis_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)
void rxn_photolysis_set_rate_update_data(void *update_data, int photo_id, double base_rate)
Set rate update data.
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.