13#include <camp/aero_phase_solver.h>
14#include <camp/aero_reps.h>
15#include <camp/camp_solver.h>
18#define TEMPERATURE_K_ env_data[0]
19#define PRESSURE_PA_ env_data[1]
21#define UPDATE_NUMBER 0
23#define NUM_LAYERS_ int_data[0]
24#define AERO_REP_ID_ int_data[1]
25#define MAX_PARTICLES_ int_data[2]
26#define PARTICLE_STATE_SIZE_ int_data[3]
27#define NUMBER_CONC_(x) aero_rep_env_data[x]
28#define NUM_INT_PROP_ 4
29#define NUM_FLOAT_PROP_ 0
30#define NUM_ENV_PARAM_ MAX_PARTICLES_
31#define LAYER_PHASE_START_(l) (int_data[NUM_INT_PROP_+l]-1)
32#define LAYER_PHASE_END_(l) (int_data[NUM_INT_PROP_+NUM_LAYERS_+l]-1)
33#define TOTAL_NUM_PHASES_ (LAYER_PHASE_END_(NUM_LAYERS_-1)-LAYER_PHASE_START_(0)+1)
34#define NUM_PHASES_(l) (LAYER_PHASE_END_(l)-LAYER_PHASE_START_(l)+1)
35#define PHASE_STATE_ID_(l,p) (int_data[NUM_INT_PROP_+2*NUM_LAYERS_+LAYER_PHASE_START_(l)+p]-1)
36#define PHASE_MODEL_DATA_ID_(l,p) (int_data[NUM_INT_PROP_+2*NUM_LAYERS_+TOTAL_NUM_PHASES_+LAYER_PHASE_START_(l)+p]-1)
37#define PHASE_NUM_JAC_ELEM_(l,p) int_data[NUM_INT_PROP_+2*NUM_LAYERS_+2*TOTAL_NUM_PHASES_+LAYER_PHASE_START_(l)+p]
54 int *aero_rep_int_data,
55 double *aero_rep_float_data,
57 int *int_data = aero_rep_int_data;
58 double *float_data = aero_rep_float_data;
64 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
65 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
87 double *aero_rep_float_data,
89 int *int_data = aero_rep_int_data;
90 double *float_data = aero_rep_float_data;
109 int *aero_rep_int_data,
110 double *aero_rep_float_data,
111 double *aero_rep_env_data) {
112 int *int_data = aero_rep_int_data;
113 double *float_data = aero_rep_float_data;
114 double *env_data = model_data->grid_cell_env;
130 int *aero_rep_int_data,
131 double *aero_rep_float_data,
132 double *aero_rep_env_data) {
133 int *int_data = aero_rep_int_data;
134 double *float_data = aero_rep_float_data;
154 ModelData *model_data,
int aero_phase_idx,
double *layer_radius,
155 double *partial_deriv,
int *aero_rep_int_data,
double *aero_rep_float_data,
156 double *aero_rep_env_data) {
158 int *int_data = aero_rep_int_data;
159 double *float_data = aero_rep_float_data;
161 double *curr_partial = NULL;
162 int aero_phase_idx_temp = aero_phase_idx;
165 int i_layer_radius = -1;
166 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
169 i_layer_radius = i_layer;
175 if (partial_deriv) curr_partial = partial_deriv;
176 for (
int i_layer = 0; i_layer <= i_layer_radius; ++i_layer) {
177 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
178 double *state = (
double *)(model_data->grid_cell_state);
184 state, &(volume), curr_partial);
186 *layer_radius += volume;
189 *layer_radius = pow(((*layer_radius) * 3.0 / 4.0 / 3.14159265359), 1.0 / 3.0);
190 if (!partial_deriv)
return;
191 for (
int i_layer = 0; i_layer <= i_layer_radius; ++i_layer) {
192 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
195 1.0 / 4.0 / 3.14159265359 * pow(*layer_radius, -2.0) * (*partial_deriv);
219 ModelData *model_data,
int aero_phase_idx,
double *radius,
220 double *partial_deriv,
int *aero_rep_int_data,
double *aero_rep_float_data,
221 double *aero_rep_env_data) {
223 int *int_data = aero_rep_int_data;
224 double *float_data = aero_rep_float_data;
225 double *curr_partial = NULL;
230 aero_phase_idx += offset;
258 ModelData *model_data,
int aero_phase_idx,
double *phase_volume,
259 double *partial_deriv,
int *aero_rep_int_data,
double *aero_rep_float_data,
260 double *aero_rep_env_data) {
262 int *int_data = aero_rep_int_data;
263 double *float_data = aero_rep_float_data;
265 double *curr_partial = NULL;
266 int aero_phase_idx_temp = aero_phase_idx;
269 int i_layer_phase = -1;
270 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
273 i_layer_phase = i_layer;
278 if (i_layer_phase == -1) {
279 printf(
"\n\nERROR: aero_rep_single_particle_get_phase_volume__m3_m3: Could not determine i_layer_phase ");
280 printf(
"for aero_phase_idx=%d.\n\n", aero_phase_idx);
284 int total_phases_previous_layers = 0;
285 for (
int i_layer = 0; i_layer < i_layer_phase; ++i_layer) {
286 total_phases_previous_layers +=
NUM_PHASES_(i_layer);
288 int i_phase = aero_phase_idx_temp - total_phases_previous_layers;
290 if (partial_deriv) curr_partial = partial_deriv;
291 double *state = (
double *)(model_data->grid_cell_state);
294 state, phase_volume, curr_partial);
321 ModelData *model_data,
int aero_phase_idx_first,
int aero_phase_idx_second,
322 double *surface_area,
double *partial_deriv,
323 int *aero_rep_int_data,
double *aero_rep_float_data,
double *aero_rep_env_data) {
325 int *int_data = aero_rep_int_data;
326 double *float_data = aero_rep_float_data;
327 double *curr_partial = NULL;
328 int layer_first = -1;
329 int layer_second = -1;
330 int layer_interface = -1;
331 int phase_model_data_id_first = -1;
332 int phase_model_data_id_second = -1;
339 int i_phase_count = 0;
340 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
341 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
344 i_phase_count == aero_phase_idx_first) {
345 layer_first = i_layer;
349 i_phase_count == aero_phase_idx_second) {
350 layer_second = i_layer;
356 if (layer_first == -1 || layer_second == -1) {
357 printf(
"\n\nERROR: aero_rep_single_particle_get_interface_surface_area__m2: ");
358 printf(
"Could not determine layer_first and layer_second for ");
359 printf(
"aero_phase_idx_first=%d and aero_phase_idx_second=%d.\n\n", aero_phase_idx_first, aero_phase_idx_second);
363 if (layer_second < layer_first) {
364 printf(
"\n\nERROR: aero_rep_single_particle_get_interface_surface_area__m2: ");
365 printf(
"layer_second is less than layer_first for ");
366 printf(
"aero_phase_idx_first=%d and aero_phase_idx_second=%d.\n\n", aero_phase_idx_first, aero_phase_idx_second);
371 layer_interface = layer_first > layer_second ? layer_second : layer_first;
377 double interface_volume = 0.0;
378 double total_volume_layer_first = 0.0;
379 double total_volume_layer_second = 0.0;
380 double volume_phase_first = 0.0;
381 double volume_phase_second = 0.0;
383 if (partial_deriv) curr_partial = partial_deriv;
384 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
385 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
386 double *state = (
double *)(model_data->grid_cell_state);
390 state, &(volume), curr_partial);
391 if (i_layer == layer_first) total_volume_layer_first += volume;
392 if (i_phase_count == aero_phase_idx_first &&
394 phase_model_data_id_first) volume_phase_first = volume;
395 if (i_layer == layer_second) total_volume_layer_second += volume;
396 if (i_phase_count == aero_phase_idx_second &&
398 phase_model_data_id_second) volume_phase_second = volume;
399 if (i_layer <= layer_interface) interface_volume += volume;
409 double f_first = volume_phase_first / total_volume_layer_first;
410 double f_second = volume_phase_second / total_volume_layer_second;
411 radius = pow(((interface_volume) * 3.0 / 4.0 / M_PI), 1.0 / 3.0);
412 *surface_area = f_first * f_second * 4 * M_PI * pow(radius, 2.0);
416 if (!partial_deriv)
return;
418 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
419 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
420 double *state = (
double *)(model_data->grid_cell_state);
424 state, &(volume_phase), NULL);
427 if (i_layer == layer_first && i_phase_count == aero_phase_idx_first) {
429 (((total_volume_layer_first - volume_phase_first) *
430 pow(total_volume_layer_first, -2.0) * f_second * (*surface_area)) +
431 2.0 * f_first * f_second * pow(radius, -1.0)) * (*partial_deriv);
435 else if (i_layer == layer_first && i_phase_count != aero_phase_idx_first) {
437 (((-1 * volume_phase) * pow(total_volume_layer_first, -2.0) *
438 f_second * (*surface_area)) + 2.0 * f_first * f_second *
439 pow(radius, -1.0)) * (*partial_deriv);
443 else if (i_layer == layer_second && i_phase_count == aero_phase_idx_second) {
445 (((total_volume_layer_second - volume_phase_second) *
446 pow(total_volume_layer_second, -2.0) * f_first * (*surface_area)) +
447 2.0 * f_first * f_second * pow(radius, -1.0)) * (*partial_deriv);
451 else if (i_layer == layer_second && i_phase_count != aero_phase_idx_second) {
453 (((-1 * volume_phase) * pow(total_volume_layer_second, -2.0) *
454 f_first * (*surface_area)) + 2.0 * f_first * f_second *
455 pow(radius, -1.0)) * (*partial_deriv);
458 else if (i_layer < layer_first) {
459 *partial_deriv = 2.0 * f_first * f_second * pow(radius, -1.0) * (*partial_deriv);
463 else if (i_layer > layer_second) {
464 *(partial_deriv++) = ZERO;
467 printf(
"\n\nERROR No conditions met for surface area partial derivative.\n\n");
492 ModelData *model_data,
int aero_phase_idx,
double *layer_thickness,
493 double *partial_deriv,
int *aero_rep_int_data,
double *aero_rep_float_data,
494 double *aero_rep_env_data) {
496 int *int_data = aero_rep_int_data;
497 double *float_data = aero_rep_float_data;
499 double radius_inner, radius_outer;
501 int aero_phase_idx_temp = aero_phase_idx;
505 double *jac_inner = NULL;
506 double *jac_outer = NULL;
509 jac_inner = (
double *)calloc(jac_size,
sizeof(
double));
510 jac_outer = (
double *)calloc(jac_size,
sizeof(
double));
511 if (jac_inner == NULL || jac_outer == NULL) {
512 printf(
"\n\nERROR: Memory allocation failed for jacobian arrays in ");
513 printf(
"aero_rep_single_particle_get_layer_thickness__m.\n\n");
518 int i_layer_inner = -1;
519 int i_layer_outer = -1;
520 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
523 i_layer_outer = i_layer;
524 i_layer_inner = (i_layer > 0) ? (i_layer - 1) : i_layer;
528 if (i_layer_outer < 0) {
529 printf(
"ERROR: Could not determine layer for aero_phase_idx=%d (temp=%d)\n",
530 aero_phase_idx, aero_phase_idx_temp);
534 int aero_phase_idx_inner = -1;
535 if (i_layer_inner == i_layer_outer) {
536 aero_phase_idx_inner = aero_phase_idx;
538 aero_phase_idx_inner = aero_phase_idx - (offset+1);
553 aero_phase_idx_inner,
560 if (i_layer_inner == i_layer_outer) {
561 *layer_thickness = radius_outer;
563 *layer_thickness = radius_outer - radius_inner;
567 for (
int i = 0; i < jac_size; ++i) {
568 if (i_layer_inner == i_layer_outer) {
569 partial_deriv[i] = jac_outer[i];
571 partial_deriv[i] = jac_outer[i] - jac_inner[i];
604 ModelData *model_data,
int aero_phase_idx,
double *number_conc,
605 double *partial_deriv,
int *aero_rep_int_data,
double *aero_rep_float_data,
606 double *aero_rep_env_data) {
609 int *int_data = aero_rep_int_data;
610 double *float_data = aero_rep_float_data;
616 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
617 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
619 *(partial_deriv++) = ZERO;
643 int *aero_rep_int_data,
644 double *aero_rep_float_data,
645 double *aero_rep_env_data) {
646 int *int_data = aero_rep_int_data;
647 double *float_data = aero_rep_float_data;
674 ModelData *model_data,
int aero_phase_idx,
double *aero_phase_mass,
675 double *partial_deriv,
int *aero_rep_int_data,
double *aero_rep_float_data,
676 double *aero_rep_env_data) {
678 int *int_data = aero_rep_int_data;
679 double *float_data = aero_rep_float_data;
683 int i_total_phase = 0;
684 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
685 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
686 if ( i_total_phase == aero_phase_idx ) {
687 double *state = (
double *)(model_data->grid_cell_state);
691 state, aero_phase_mass, &mw, partial_deriv, NULL);
693 }
else if (partial_deriv) {
695 *(partial_deriv++) = ZERO;
723 ModelData *model_data,
int aero_phase_idx,
double *aero_phase_avg_MW,
724 double *partial_deriv,
int *aero_rep_int_data,
double *aero_rep_float_data,
725 double *aero_rep_env_data) {
727 int *int_data = aero_rep_int_data;
728 double *float_data = aero_rep_float_data;
732 int i_total_phase = 0;
733 for (
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer) {
734 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
735 if ( i_total_phase == aero_phase_idx ) {
736 double *state = (
double *)(model_data->grid_cell_state);
740 state, &mass, aero_phase_avg_MW, NULL, partial_deriv);
742 }
else if (partial_deriv) {
744 *(partial_deriv++) = ZERO;
775 int *aero_rep_int_data,
776 double *aero_rep_float_data,
777 double *aero_rep_env_data) {
778 int *int_data = aero_rep_int_data;
779 double *float_data = aero_rep_float_data;
781 int *aero_rep_id = (
int *)update_data;
782 int *update_type = (
int *)&(aero_rep_id[1]);
783 int *particle_id = (
int *)&(update_type[1]);
784 double *new_value = (
double *)&(update_type[2]);
806 double *aero_rep_float_data) {
807 int *int_data = aero_rep_int_data;
808 double *float_data = aero_rep_float_data;
810 printf(
"\n\nSingle particle aerosol representation\n");
812 printf(
"\nAerosol representation id: %d",
AERO_REP_ID_);
815 for(
int i_layer = 0; i_layer <
NUM_LAYERS_; ++i_layer){
816 printf(
"\nLayer: %d", i_layer);
818 printf(
"\n Number of phases: %d",
NUM_PHASES_(i_layer));
819 printf(
"\n\n - Phases -");
820 for (
int i_phase = 0; i_phase <
NUM_PHASES_(i_layer); ++i_phase) {
821 printf(
"\n state id: %d model data id: %d num Jac elements: %d",
826 printf(
"\n\nEnd single particle aerosol representation\n");
836 int *update_data = (
int *)malloc(3 *
sizeof(
int) +
sizeof(double));
837 if (update_data == NULL) {
838 printf(
"\n\nERROR allocating space for number update data\n\n");
841 return (
void *)update_data;
854 double number_conc) {
855 int *new_aero_rep_id = (
int *)update_data;
856 int *update_type = (
int *)&(new_aero_rep_id[1]);
857 int *new_particle_id = (
int *)&(update_type[1]);
858 double *new_number_conc = (
double *)&(update_type[2]);
859 *new_aero_rep_id = aero_rep_id;
861 *new_particle_id = particle_id;
862 *new_number_conc = number_conc;
void aero_phase_get_volume__m3_m3(ModelData *model_data, int aero_phase_idx, double *state_var, double *volume, double *jac_elem)
Get the volume of an aerosol phase.
int aero_phase_get_used_jac_elem(ModelData *model_data, int aero_phase_idx, int state_var_id, bool *jac_struct)
Flag Jacobian elements used in calculations of mass and volume.
void aero_phase_get_mass__kg_m3(ModelData *model_data, int aero_phase_idx, double *state_var, double *mass, double *MW, double *jac_elem_mass, double *jac_elem_MW)
Get the mass and average MW in an aerosol phase.
int aero_rep_single_particle_get_used_jac_elem(ModelData *model_data, int aero_phase_idx, int *aero_rep_int_data, double *aero_rep_float_data, bool *jac_struct)
Flag Jacobian elements used in calcualtions of mass and volume.
void aero_rep_single_particle_get_aero_phase_avg_MW__kg_mol(ModelData *model_data, int aero_phase_idx, double *aero_phase_avg_MW, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the average molecular weight in an aerosol phase ( )
void aero_rep_single_particle_get_effective_radius__m(ModelData *model_data, int aero_phase_idx, double *radius, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the effective particle radius (m) Finds the radius of the largest layer in specified particle.
#define PARTICLE_STATE_SIZE_
void aero_rep_single_particle_get_aero_conc_type(int aero_phase_idx, int *aero_conc_type, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the type of aerosol concentration used.
void * aero_rep_single_particle_create_number_update_data()
Create update data for new particle number.
#define PHASE_NUM_JAC_ELEM_(l, p)
void aero_rep_single_particle_get_interface_surface_area__m2(ModelData *model_data, int aero_phase_idx_first, int aero_phase_idx_second, double *surface_area, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the surface area of specified particle layer (m)
void aero_rep_single_particle_print(int *aero_rep_int_data, double *aero_rep_float_data)
Print the Single Particle reaction parameters.
#define LAYER_PHASE_START_(l)
#define PHASE_MODEL_DATA_ID_(l, p)
#define TOTAL_NUM_PHASES_
#define PHASE_STATE_ID_(l, p)
void aero_rep_single_particle_get_phase_volume__m3_m3(ModelData *model_data, int aero_phase_idx, double *phase_volume, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the volume of a specified phase in the corresponding layer.
void aero_rep_single_particle_update_env_state(ModelData *model_data, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Update aerosol representation data for new environmental conditions.
void aero_rep_single_particle_get_layer_thickness__m(ModelData *model_data, int aero_phase_idx, double *layer_thickness, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the thickness of a particle layer (m)
bool aero_rep_single_particle_update_data(void *update_data, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Update aerosol representation data.
void aero_rep_single_particle_get_dependencies(int *aero_rep_int_data, double *aero_rep_float_data, bool *state_flags)
Flag elements on the state array used by this aerosol representation.
void aero_rep_single_particle_get_aero_phase_mass__kg_m3(ModelData *model_data, int aero_phase_idx, double *aero_phase_mass, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the total mass in an aerosol phase ( )
#define LAYER_PHASE_END_(l)
void aero_rep_single_particle_get_effective_layer_radius__m(ModelData *model_data, int aero_phase_idx, double *layer_radius, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the effective radius of a specified layer (m)
void aero_rep_single_particle_get_number_conc__n_m3(ModelData *model_data, int aero_phase_idx, double *number_conc, double *partial_deriv, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Get the particle number concentration ( )
void aero_rep_single_particle_set_number_update_data__n_m3(void *update_data, int aero_rep_id, int particle_id, double number_conc)
Set number update data (#/m3)
void aero_rep_single_particle_update_state(ModelData *model_data, int *aero_rep_int_data, double *aero_rep_float_data, double *aero_rep_env_data)
Update aerosol representation data for a new state.