14#include <camp/aero_rep_solver.h>
16#include <camp/sub_model_solver.h>
20#define TEMPERATURE_K_ env_data[0]
21#define PRESSURE_PA_ env_data[1]
28#define PER_PARTICLE_MASS 0
29#define TOTAL_PARTICLE_MASS 1
31#define DELTA_H_ float_data[0]
32#define DELTA_S_ float_data[1]
33#define DIFF_COEFF_ float_data[2]
34#define PRE_C_AVG_ float_data[3]
35#define B1_ float_data[4]
36#define B2_ float_data[5]
37#define B3_ float_data[6]
38#define B4_ float_data[7]
39#define CONV_ float_data[8]
40#define MW_ float_data[9]
41#define NUM_AERO_PHASE_ int_data[0]
42#define GAS_SPEC_ (int_data[1] - 1)
43#define MFP_M_ rxn_env_data[0]
44#define ALPHA_ rxn_env_data[1]
45#define EQUIL_CONST_ rxn_env_data[2]
46#define KGM3_TO_PPM_ rxn_env_data[3]
47#define NUM_INT_PROP_ 2
48#define NUM_FLOAT_PROP_ 10
49#define NUM_ENV_PARAM_ 4
50#define AERO_SPEC_(x) (int_data[NUM_INT_PROP_ + x] - 1)
51#define AERO_ACT_ID_(x) (int_data[NUM_INT_PROP_ + NUM_AERO_PHASE_ + x] - 1)
52#define AERO_PHASE_ID_(x) \
53 (int_data[NUM_INT_PROP_ + 2 * (NUM_AERO_PHASE_) + x] - 1)
54#define AERO_REP_ID_(x) \
55 (int_data[NUM_INT_PROP_ + 3 * (NUM_AERO_PHASE_) + x] - 1)
56#define DERIV_ID_(x) (int_data[NUM_INT_PROP_ + 4 * (NUM_AERO_PHASE_) + x])
57#define GAS_ACT_JAC_ID_(x) \
58 int_data[NUM_INT_PROP_ + 1 + 5 * (NUM_AERO_PHASE_) + x]
59#define AERO_ACT_JAC_ID_(x) \
60 int_data[NUM_INT_PROP_ + 1 + 6 * (NUM_AERO_PHASE_) + x]
61#define JAC_ID_(x) (int_data[NUM_INT_PROP_ + 1 + 7 * (NUM_AERO_PHASE_) + x])
62#define PHASE_INT_LOC_(x) \
63 (int_data[NUM_INT_PROP_ + 2 + 10 * (NUM_AERO_PHASE_) + x] - 1)
64#define PHASE_FLOAT_LOC_(x) \
65 (int_data[NUM_INT_PROP_ + 2 + 11 * (NUM_AERO_PHASE_) + x] - 1)
66#define NUM_AERO_PHASE_JAC_ELEM_(x) (int_data[PHASE_INT_LOC_(x)])
67#define PHASE_JAC_ID_(x, s, e) \
68 int_data[PHASE_INT_LOC_(x) + 1 + (s) * NUM_AERO_PHASE_JAC_ELEM_(x) + e]
69#define EFF_RAD_JAC_ELEM_(x, e) float_data[PHASE_FLOAT_LOC_(x) + e]
70#define NUM_CONC_JAC_ELEM_(x, e) \
71 float_data[PHASE_FLOAT_LOC_(x) + NUM_AERO_PHASE_JAC_ELEM_(x) + e]
72#define MASS_JAC_ELEM_(x, e) \
73 float_data[PHASE_FLOAT_LOC_(x) + 2 * NUM_AERO_PHASE_JAC_ELEM_(x) + e]
74#define MW_JAC_ELEM_(x, e) \
75 float_data[PHASE_FLOAT_LOC_(x) + 3 * NUM_AERO_PHASE_JAC_ELEM_(x) + e]
86 double *rxn_float_data,
88 int *int_data = rxn_int_data;
89 double *float_data = rxn_float_data;
95 (
bool *)malloc(
sizeof(
bool) * model_data->n_per_cell_state_var);
96 if (aero_jac_elem == NULL) {
98 "\n\nERROR allocating space for 1D Jacobian structure array for "
99 "SIMPOL phase transfer reaction\n\n");
104 for (
int i_aero_phase = 0; i_aero_phase <
NUM_AERO_PHASE_; i_aero_phase++) {
117 for (
int i_elem = 0; i_elem < model_data->n_per_cell_state_var; ++i_elem)
118 aero_jac_elem[i_elem] =
false;
134 "\n\nERROR Received more Jacobian elements than expected for SIMPOL "
135 "partitioning reaction. Got %d, expected <= %d",
148 for (
int i_elem = 0; i_elem < model_data->n_per_cell_state_var; ++i_elem) {
149 if (aero_jac_elem[i_elem] ==
true) {
167 if (i_used_elem != n_jac_elem) {
169 "\n\nERROR setting used Jacobian elements in SIMPOL phase "
170 "transfer reaction %d %d\n\n",
171 i_used_elem, n_jac_elem);
190 Jacobian jac,
int *rxn_int_data,
191 double *rxn_float_data) {
192 int *int_data = rxn_int_data;
193 double *float_data = rxn_float_data;
206 for (
int i_aero_phase = 0; i_aero_phase <
NUM_AERO_PHASE_; i_aero_phase++) {
259 double *rxn_float_data,
260 double *rxn_env_data) {
261 int *int_data = rxn_int_data;
262 double *float_data = rxn_float_data;
263 double *env_data = model_data->grid_cell_env;
286 vp = 101325.0 * pow(10, vp);
315#ifdef CAMP_USE_SUNDIALS
317 ModelData *model_data, TimeDerivative time_deriv,
int *rxn_int_data,
318 double *rxn_float_data,
double *rxn_env_data, realtype time_step) {
319 int *int_data = rxn_int_data;
320 double *float_data = rxn_float_data;
321 double *state = model_data->grid_cell_state;
322 double *env_data = model_data->grid_cell_env;
343 realtype number_conc;
352 realtype aero_phase_mass;
361 realtype aero_phase_avg_MW;
372 long double cond_rate =
373 ((
long double)1.0) / (radius * radius / (3.0 *
DIFF_COEFF_) +
374 4.0 * radius / (3.0 *
MFP_M_));
379 long double cond_rate =
383 long double evap_rate =
384 cond_rate * (
EQUIL_CONST_ * aero_phase_avg_MW / aero_phase_mass);
387 long double act_coeff = 1.0;
393 evap_rate *= act_coeff;
404 number_conc * evap_rate);
406 -number_conc * cond_rate);
423 number_conc * evap_rate);
425 -number_conc * cond_rate);
451#ifdef CAMP_USE_SUNDIALS
453 Jacobian jac,
int *rxn_int_data,
454 double *rxn_float_data,
455 double *rxn_env_data,
456 realtype time_step) {
457 int *int_data = rxn_int_data;
458 double *float_data = rxn_float_data;
459 double *state = model_data->grid_cell_state;
460 double *env_data = model_data->grid_cell_env;
481 realtype number_conc;
490 realtype aero_phase_mass;
499 realtype aero_phase_avg_MW;
510 long double cond_rate =
511 ((
long double)1.0) / (radius * radius / (3.0 *
DIFF_COEFF_) +
512 4.0 * radius / (3.0 *
MFP_M_));
517 long double cond_rate =
521 long double evap_rate =
522 cond_rate * (
EQUIL_CONST_ * aero_phase_avg_MW / aero_phase_mass);
525 long double act_coeff = 1.0;
533 if (
JAC_ID_(1 + i_phase * 3 + 1) >= 0) {
536 number_conc * evap_rate * act_coeff);
540 number_conc * cond_rate);
545 if (
JAC_ID_(1 + i_phase * 3) >= 0) {
549 if (
JAC_ID_(1 + i_phase * 3 + 2) >= 0) {
558 number_conc * evap_rate * state[
AERO_SPEC_(i_phase)]);
569 if (
JAC_ID_(1 + i_phase * 3 + 1) >= 0) {
572 number_conc * evap_rate * act_coeff);
576 number_conc * cond_rate);
581 if (
JAC_ID_(1 + i_phase * 3) >= 0) {
586 if (
JAC_ID_(1 + i_phase * 3 + 2) >= 0) {
596 number_conc * evap_rate * state[
AERO_SPEC_(i_phase)]);
607 evap_rate *= act_coeff;
615 realtype d_cond_d_radius =
617 cond_rate * cond_rate / state[
GAS_SPEC_];
619 realtype d_cond_d_radius = d_gas_aerosol_transition_rxn_rate_constant_d_radius(
622 realtype d_evap_d_radius = d_cond_d_radius / state[
GAS_SPEC_] *
625 realtype d_evap_d_mass = -evap_rate / aero_phase_mass;
626 realtype d_evap_d_MW = evap_rate / aero_phase_avg_MW;
639 number_conc * d_evap_d_radius *
644 number_conc * d_cond_d_radius *
666 number_conc * d_evap_d_MW *
MW_JAC_ELEM_(i_phase, i_elem));
708 number_conc * d_evap_d_radius *
713 number_conc * d_cond_d_radius *
735 number_conc * d_evap_d_MW *
MW_JAC_ELEM_(i_phase, i_elem));
789 double *rxn_float_data) {
790 int *int_data = rxn_int_data;
791 double *float_data = rxn_float_data;
793 printf(
"\n\nSIMPOL.1 Phase Transfer reaction\n");
794 printf(
"\ndelta H: %le delta S: %le diffusion coeff: %le Pre C_avg: %le",
796 printf(
"\nB1: %le B2: %le B3:%le B4: %le",
B1_,
B2_,
B3_,
B4_);
797 printf(
"\nconv: %le MW: %le",
CONV_,
MW_);
799 printf(
"\nGas-phase species id: %d",
GAS_SPEC_);
800 printf(
"\nGas-phase derivative id: %d",
DERIV_ID_(0));
801 printf(
"\ndGas/dGas Jac id: %d",
JAC_ID_(0));
802 printf(
"\n*** Aerosol phase data ***");
804 printf(
"\n Aerosol species id: %d",
AERO_SPEC_(i));
805 printf(
"\n Activity coefficient id: %d",
AERO_ACT_ID_(i));
807 printf(
"\n Aerosol representation id: %d",
AERO_REP_ID_(i));
808 printf(
"\n Aerosol species derivative id: %d",
DERIV_ID_(i + 1));
811 printf(
"\n dAero/dGas Jac id: %d",
JAC_ID_(1 + i * 3));
812 printf(
"\n dGas/dAero Jac id: %d",
JAC_ID_(2 + i * 3));
813 printf(
"\n dAero/dAero Jac id: %d",
JAC_ID_(3 + i * 3));
814 printf(
"\n Number of aerosol-phase species Jac elements: %d",
816 printf(
"\n dGas/dx ids:");
819 printf(
"\n dAero/dx ids:");
822 printf(
"\n Effective radius Jac elem:");
825 printf(
"\n Number concentration Jac elem:");
828 printf(
"\n Aerosol mass Jac elem:");
831 printf(
"\n Average MW Jac elem:");
unsigned int jacobian_get_element_id(Jacobian jac, unsigned int dep_id, unsigned int ind_id)
void jacobian_add_value(Jacobian jac, unsigned int elem_id, unsigned int prod_or_loss, long double jac_contribution)
void jacobian_register_element(Jacobian *jac, unsigned int dep_id, unsigned int ind_id)
int aero_rep_get_aero_conc_type(ModelData *model_data, int aero_rep_idx, int aero_phase_idx)
Check whether aerosol concentrations are per-particle or total for each phase.
int aero_rep_get_used_jac_elem(ModelData *model_data, int aero_rep_idx, int aero_phase_idx, bool *jac_struct)
Flag Jacobian elements used to calculated mass, volume, etc.
void aero_rep_get_aero_phase_mass__kg_m3(ModelData *model_data, int aero_rep_idx, int aero_phase_idx, double *aero_phase_mass, double *partial_deriv)
Get the total mass of an aerosol phase in this representation ( )
void aero_rep_get_aero_phase_avg_MW__kg_mol(ModelData *model_data, int aero_rep_idx, int aero_phase_idx, double *aero_phase_avg_MW, double *partial_deriv)
Get the average molecular weight of an aerosol phase in this representation ( )
void aero_rep_get_number_conc__n_m3(ModelData *model_data, int aero_rep_idx, int aero_phase_idx, double *number_conc, double *partial_deriv)
Get the particle number concentration ( )
void aero_rep_get_effective_radius__m(ModelData *model_data, int aero_rep_idx, int aero_phase_idx, double *radius, double *partial_deriv)
Get the effective particle radius, (m)
#define MW_JAC_ELEM_(x, e)
void rxn_SIMPOL_phase_transfer_get_used_jac_elem(ModelData *model_data, int *rxn_int_data, double *rxn_float_data, Jacobian *jac)
Flag Jacobian elements used by this reaction.
void rxn_SIMPOL_phase_transfer_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_SIMPOL_phase_transfer_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 AERO_PHASE_ID_(x)
void rxn_SIMPOL_phase_transfer_print(int *rxn_int_data, double *rxn_float_data)
Print the Phase Transfer reaction parameters.
void rxn_SIMPOL_phase_transfer_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 GAS_ACT_JAC_ID_(x)
#define PER_PARTICLE_MASS
#define PHASE_JAC_ID_(x, s, e)
void rxn_SIMPOL_phase_transfer_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 AERO_ACT_JAC_ID_(x)
#define MASS_JAC_ELEM_(x, e)
#define NUM_AERO_PHASE_JAC_ELEM_(x)
#define EFF_RAD_JAC_ELEM_(x, e)
#define NUM_CONC_JAC_ELEM_(x, e)
void time_derivative_add_value(TimeDerivative time_deriv, unsigned int spec_id, long double rate_contribution)