15#include <camp/aero_rep_solver.h>
16#include <camp/camp_debug.h>
17#include <camp/camp_solver.h>
18#include <camp/rxn_solver.h>
19#include <camp/sub_model_solver.h>
25#include <camp/cuda/camp_gpu_solver.h>
29#define DEFAULT_TIME_STEP 1.0
31#define JAC_CHECK_ADV_MAX 1.0E-00
32#define JAC_CHECK_ADV_MIN 1.0E-12
34#define MAX_TIMESTEP_WARNINGS -1
36#define GUESS_MAX_ITER 5
39#define CAMP_SOLVER_SUCCESS 0
40#define CAMP_SOLVER_FAIL 1
73void *
solver_new(
int n_state_var,
int n_cells,
int *var_type,
int n_rxn,
74 int n_rxn_int_param,
int n_rxn_float_param,
75 int n_rxn_env_param,
int n_aero_phase,
76 int n_aero_phase_int_param,
int n_aero_phase_float_param,
77 int n_aero_rep,
int n_aero_rep_int_param,
78 int n_aero_rep_float_param,
int n_aero_rep_env_param,
79 int n_sub_model,
int n_sub_model_int_param,
80 int n_sub_model_float_param,
int n_sub_model_env_param) {
82 SolverData *sd = (SolverData *)malloc(
sizeof(SolverData));
84 printf(
"\n\nERROR allocating space for SolverData\n\n");
88#ifdef CAMP_USE_SUNDIALS
91 sd->debug_out = SUNFALSE;
94 sd->eval_Jac = SUNFALSE;
99 sd->output_precision = 0;
102 sd->use_deriv_est = 1;
105 sd->model_data.n_per_cell_state_var = n_state_var;
108 sd->model_data.n_cells = n_cells;
111 sd->model_data.var_type = (
int *)malloc(n_state_var *
sizeof(
int));
112 if (sd->model_data.var_type == NULL) {
113 printf(
"\n\nERROR allocating space for variable types\n\n");
116 for (
int i = 0; i < n_state_var; i++)
117 sd->model_data.var_type[i] = var_type[i];
121 for (
int i = 0; i < n_state_var; i++)
125 sd->model_data.n_per_cell_dep_var = n_dep_var;
127#ifdef CAMP_USE_SUNDIALS
130 printf(
"\n\nERROR initializing the TimeDerivative\n\n");
135 sd->y = N_VNew_Serial(n_dep_var * n_cells);
136 sd->deriv = N_VNew_Serial(n_dep_var * n_cells);
142 sd->model_data.rxn_int_data =
143 (
int *)malloc((n_rxn_int_param + n_rxn) *
sizeof(
int));
144 if (sd->model_data.rxn_int_data == NULL) {
145 printf(
"\n\nERROR allocating space for reaction integer data\n\n");
148 sd->model_data.rxn_float_data =
149 (
double *)malloc(n_rxn_float_param *
sizeof(
double));
150 if (sd->model_data.rxn_float_data == NULL) {
151 printf(
"\n\nERROR allocating space for reaction float data\n\n");
154 sd->model_data.rxn_env_data =
155 (
double *)calloc(n_cells * n_rxn_env_param,
sizeof(
double));
156 if (sd->model_data.rxn_env_data == NULL) {
158 "\n\nERROR allocating space for environment-dependent "
164 sd->model_data.rxn_int_indices = (
int *)malloc((n_rxn + 1) *
sizeof(
int *));
165 if (sd->model_data.rxn_int_indices == NULL) {
166 printf(
"\n\nERROR allocating space for reaction integer indices\n\n");
169 sd->model_data.rxn_float_indices = (
int *)malloc((n_rxn + 1) *
sizeof(
int *));
170 if (sd->model_data.rxn_float_indices == NULL) {
171 printf(
"\n\nERROR allocating space for reaction float indices\n\n");
174 sd->model_data.rxn_env_idx = (
int *)malloc((n_rxn + 1) *
sizeof(
int));
175 if (sd->model_data.rxn_env_idx == NULL) {
177 "\n\nERROR allocating space for reaction environment-dependent "
178 "data pointers\n\n");
182 sd->model_data.n_rxn = n_rxn;
183 sd->model_data.n_added_rxns = 0;
184 sd->model_data.n_rxn_env_data = 0;
185 sd->model_data.rxn_int_indices[0] = 0;
186 sd->model_data.rxn_float_indices[0] = 0;
187 sd->model_data.rxn_env_idx[0] = 0;
190 sd->no_solve = (n_rxn == 0);
195 sd->model_data.aero_phase_int_data =
196 (
int *)malloc(n_aero_phase_int_param *
sizeof(
int));
197 if (sd->model_data.aero_phase_int_data == NULL) {
198 printf(
"\n\nERROR allocating space for aerosol phase integer data\n\n");
201 sd->model_data.aero_phase_float_data =
202 (
double *)malloc(n_aero_phase_float_param *
sizeof(
double));
203 if (sd->model_data.aero_phase_float_data == NULL) {
205 "\n\nERROR allocating space for aerosol phase floating-point "
211 sd->model_data.aero_phase_int_indices =
212 (
int *)malloc((n_aero_phase + 1) *
sizeof(
int *));
213 if (sd->model_data.aero_phase_int_indices == NULL) {
214 printf(
"\n\nERROR allocating space for reaction integer indices\n\n");
217 sd->model_data.aero_phase_float_indices =
218 (
int *)malloc((n_aero_phase + 1) *
sizeof(
int *));
219 if (sd->model_data.aero_phase_float_indices == NULL) {
220 printf(
"\n\nERROR allocating space for reaction float indices\n\n");
224 sd->model_data.n_aero_phase = n_aero_phase;
225 sd->model_data.n_added_aero_phases = 0;
226 sd->model_data.aero_phase_int_indices[0] = 0;
227 sd->model_data.aero_phase_float_indices[0] = 0;
234 sd->model_data.aero_rep_int_data =
235 (
int *)malloc((n_aero_rep_int_param + n_aero_rep) *
sizeof(
int));
236 if (sd->model_data.aero_rep_int_data == NULL) {
238 "\n\nERROR allocating space for aerosol representation integer "
242 sd->model_data.aero_rep_float_data =
243 (
double *)malloc(n_aero_rep_float_param *
sizeof(
double));
244 if (sd->model_data.aero_rep_float_data == NULL) {
246 "\n\nERROR allocating space for aerosol representation "
247 "floating-point data\n\n");
250 sd->model_data.aero_rep_env_data =
251 (
double *)calloc(n_cells * n_aero_rep_env_param,
sizeof(
double));
252 if (sd->model_data.aero_rep_env_data == NULL) {
254 "\n\nERROR allocating space for aerosol representation "
255 "environmental parameters\n\n");
260 sd->model_data.aero_rep_int_indices =
261 (
int *)malloc((n_aero_rep + 1) *
sizeof(
int *));
262 if (sd->model_data.aero_rep_int_indices == NULL) {
263 printf(
"\n\nERROR allocating space for reaction integer indices\n\n");
266 sd->model_data.aero_rep_float_indices =
267 (
int *)malloc((n_aero_rep + 1) *
sizeof(
int *));
268 if (sd->model_data.aero_rep_float_indices == NULL) {
269 printf(
"\n\nERROR allocating space for reaction float indices\n\n");
272 sd->model_data.aero_rep_env_idx =
273 (
int *)malloc((n_aero_rep + 1) *
sizeof(
int));
274 if (sd->model_data.aero_rep_env_idx == NULL) {
276 "\n\nERROR allocating space for aerosol representation "
277 "environment-dependent data pointers\n\n");
281 sd->model_data.n_aero_rep = n_aero_rep;
282 sd->model_data.n_added_aero_reps = 0;
283 sd->model_data.n_aero_rep_env_data = 0;
284 sd->model_data.aero_rep_int_indices[0] = 0;
285 sd->model_data.aero_rep_float_indices[0] = 0;
286 sd->model_data.aero_rep_env_idx[0] = 0;
291 sd->model_data.sub_model_int_data =
292 (
int *)malloc((n_sub_model_int_param + n_sub_model) *
sizeof(
int));
293 if (sd->model_data.sub_model_int_data == NULL) {
294 printf(
"\n\nERROR allocating space for sub model integer data\n\n");
297 sd->model_data.sub_model_float_data =
298 (
double *)malloc(n_sub_model_float_param *
sizeof(
double));
299 if (sd->model_data.sub_model_float_data == NULL) {
300 printf(
"\n\nERROR allocating space for sub model floating-point data\n\n");
303 sd->model_data.sub_model_env_data =
304 (
double *)calloc(n_cells * n_sub_model_env_param,
sizeof(
double));
305 if (sd->model_data.sub_model_env_data == NULL) {
307 "\n\nERROR allocating space for sub model environment-dependent "
313 sd->model_data.sub_model_int_indices =
314 (
int *)malloc((n_sub_model + 1) *
sizeof(
int *));
315 if (sd->model_data.sub_model_int_indices == NULL) {
316 printf(
"\n\nERROR allocating space for reaction integer indices\n\n");
319 sd->model_data.sub_model_float_indices =
320 (
int *)malloc((n_sub_model + 1) *
sizeof(
int *));
321 if (sd->model_data.sub_model_float_indices == NULL) {
322 printf(
"\n\nERROR allocating space for reaction float indices\n\n");
325 sd->model_data.sub_model_env_idx =
326 (
int *)malloc((n_sub_model + 1) *
sizeof(
int));
327 if (sd->model_data.sub_model_env_idx == NULL) {
329 "\n\nERROR allocating space for sub model environment-dependent "
330 "data pointers\n\n");
334 sd->model_data.n_sub_model = n_sub_model;
335 sd->model_data.n_added_sub_models = 0;
336 sd->model_data.n_sub_model_env_data = 0;
337 sd->model_data.sub_model_int_indices[0] = 0;
338 sd->model_data.sub_model_float_indices[0] = 0;
339 sd->model_data.sub_model_env_idx[0] = 0;
342 solver_new_gpu_cu(n_dep_var, n_state_var, n_rxn, n_rxn_int_param,
343 n_rxn_float_param, n_rxn_env_param, n_cells);
347 if (sd->debug_out) print_data_sizes(&(sd->model_data));
365 int max_steps,
int max_conv_fails) {
366#ifdef CAMP_USE_SUNDIALS
377 srand((
unsigned int)100);
380 sd = (SolverData *)solver_data;
383 sd->cvode_mem = CVodeCreate(CV_BDF
384#ifndef SUNDIALS_VERSION_MAJOR
385# error SUNDIALS_VERSION_MAJOR not defined
386#elif SUNDIALS_VERSION_MAJOR < 4
394 n_state_var = sd->model_data.n_per_cell_state_var;
395 n_dep_var = sd->model_data.n_per_cell_dep_var;
396 var_type = sd->model_data.var_type;
397 n_cells = sd->model_data.n_cells;
400 flag = CVodeSetUserData(sd->cvode_mem, sd);
406 flag = CVodeInit(sd->cvode_mem,
f, (realtype)0.0, sd->y);
410 sd->abs_tol_nv = N_VNew_Serial(n_dep_var * n_cells);
412 for (
int i_cell = 0; i_cell < n_cells; ++i_cell)
413 for (
int i_spec = 0; i_spec < n_state_var; ++i_spec)
415 NV_Ith_S(sd->abs_tol_nv, i_dep_var++) = (realtype)abs_tol[i_spec];
416 flag = CVodeSVtolerances(sd->cvode_mem, (realtype)rel_tol, sd->abs_tol_nv);
421 sd->model_data.abs_tol = abs_tol;
424 flag = CVodeSetMaxNumSteps(sd->cvode_mem, max_steps);
428 flag = CVodeSetMaxConvFails(sd->cvode_mem, max_conv_fails);
432 flag = CVodeSetMaxErrTestFails(sd->cvode_mem, max_conv_fails);
441 sd->model_data.J_init = SUNMatClone(sd->J);
442 SUNMatCopy(sd->J, sd->model_data.J_init);
446 sd->J_guess = SUNMatClone(sd->J);
447 SUNMatCopy(sd->J, sd->J_guess);
450 sd->ls = SUNKLU(sd->y, sd->J);
454 flag = CVDlsSetLinearSolver(sd->cvode_mem, sd->ls, sd->J);
458 flag = CVDlsSetJacFn(sd->cvode_mem,
Jac);
461#ifdef CAMP_CUSTOM_CVODE
463 flag = CVodeSetDlsGuessHelper(sd->cvode_mem, guess_helper);
469 allocate_jac_gpu(sd->model_data.n_per_cell_solver_jac_elem, n_cells);
474 solver_set_rxn_data_gpu(&(sd->model_data));
477#ifndef FAILURE_DETAIL
479 flag = CVodeSetErrHandlerFn(sd->cvode_mem,
error_handler, (
void *)sd);
492int solver_set_debug_out(
void *solver_data,
bool do_output) {
493#ifdef CAMP_USE_SUNDIALS
494 SolverData *sd = (SolverData *)solver_data;
496 sd->debug_out = do_output ==
true ? SUNTRUE : SUNFALSE;
512int solver_set_eval_jac(
void *solver_data,
bool eval_Jac) {
513#ifdef CAMP_USE_SUNDIALS
514 SolverData *sd = (SolverData *)solver_data;
516 sd->eval_Jac = eval_Jac ==
true ? SUNTRUE : SUNFALSE;
534int solver_run(
void *solver_data,
double *state,
double *env,
double t_initial,
536#ifdef CAMP_USE_SUNDIALS
537 SolverData *sd = (SolverData *)solver_data;
538 ModelData *md = &(sd->model_data);
539 int n_state_var = sd->model_data.n_per_cell_state_var;
540 int n_cells = sd->model_data.n_cells;
545 for (
int i_cell = 0; i_cell < n_cells; i_cell++)
546 for (
int i_spec = 0; i_spec < n_state_var; i_spec++)
548 NV_Ith_S(sd->y, i_dep_var++) =
549 state[i_spec + i_cell * n_state_var] > TINY
550 ? (realtype)state[i_spec + i_cell * n_state_var]
553 state[i_spec + i_cell * n_state_var] =
554 state[i_spec + i_cell * n_state_var] > TINY
555 ? state[i_spec + i_cell * n_state_var]
560 sd->model_data.total_state = state;
561 sd->model_data.total_env = env;
565 flag = CVodeSetDebugOut(sd->cvode_mem, sd->debug_out);
567 flag = SUNKLUSetDebugOut(sd->ls, sd->debug_out);
572 sd->Jac_eval_fails = 0;
577 for (
int i_cell = 0; i_cell < md->n_cells; ++i_cell) {
579 md->grid_cell_id = i_cell;
580 md->grid_cell_state = &(md->total_state[i_cell * md->n_per_cell_state_var]);
581 md->grid_cell_env = &(md->total_env[i_cell * CAMP_NUM_ENV_PARAM_]);
582 md->grid_cell_rxn_env_data =
583 &(md->rxn_env_data[i_cell * md->n_rxn_env_data]);
584 md->grid_cell_aero_rep_env_data =
585 &(md->aero_rep_env_data[i_cell * md->n_aero_rep_env_data]);
586 md->grid_cell_sub_model_env_data =
587 &(md->sub_model_env_data[i_cell * md->n_sub_model_env_data]);
595 CAMP_DEBUG_JAC_STRUCT(sd->model_data.J_init,
"Begin solving");
598 sd->curr_J_guess =
false;
609 flag = CVodeReInit(sd->cvode_mem, t_initial, sd->y);
613 flag = SUNKLUReInit(sd->ls, sd->J, SM_NNZ_S(sd->J), SUNKLU_REINIT_PARTIAL);
617 flag = CVodeSetInitStep(sd->cvode_mem, sd->init_time_step);
621 realtype t_rt = (realtype)t_initial;
623 flag = CVode(sd->cvode_mem, (realtype)t_final, sd->y, &t_rt, CV_NORMAL);
624 sd->solver_flag = flag;
625#ifndef FAILURE_DETAIL
631 int lastflag = CVDlsGetLastFlag(sd->cvode_mem, &lsflag);
632 printf(
"\nLinear Solver Setup Fail: %d %ld", lastflag, lsflag);
634 N_Vector deriv = N_VClone(sd->y);
635 flag =
f(t_initial, sd->y, deriv, sd);
637 printf(
"\nCall to f() at failed state failed with flag %d\n", flag);
638 for (
int i_cell = 0; i_cell < md->n_cells; ++i_cell) {
639 printf(
"\n Cell: %d ", i_cell);
640 printf(
"temp = %le pressure = %le\n", env[i_cell * CAMP_NUM_ENV_PARAM_],
641 env[i_cell * CAMP_NUM_ENV_PARAM_ + 1]);
642 for (
int i_spec = 0, i_dep_var = 0; i_spec < md->n_per_cell_state_var;
646 "spec %d = %le deriv = %le\n", i_spec,
647 NV_Ith_S(sd->y, i_cell * md->n_per_cell_dep_var + i_dep_var),
648 NV_Ith_S(deriv, i_cell * md->n_per_cell_dep_var + i_dep_var));
651 printf(
"spec %d = %le\n", i_spec,
652 state[i_cell * md->n_per_cell_state_var + i_spec]);
663 for (
int i_cell = 0; i_cell < n_cells; i_cell++) {
664 for (
int i_spec = 0; i_spec < n_state_var; i_spec++) {
666 state[i_spec + i_cell * n_state_var] =
667 (double)(NV_Ith_S(sd->y, i_dep_var) > 0.0
668 ? NV_Ith_S(sd->y, i_dep_var)
716 int *RHS_evals,
int *LS_setups,
717 int *error_test_fails,
int *NLS_iters,
718 int *NLS_convergence_fails,
int *DLS_Jac_evals,
719 int *DLS_RHS_evals,
double *last_time_step__s,
720 double *next_time_step__s,
int *Jac_eval_fails,
721 int *RHS_evals_total,
int *Jac_evals_total,
722 double *RHS_time__s,
double *Jac_time__s,
723 double *max_loss_precision) {
724#ifdef CAMP_USE_SUNDIALS
725 SolverData *sd = (SolverData *)solver_data;
726 long int nst, nfe, nsetups, nje, nfeLS, nni, ncfn, netf, nge;
727 realtype last_h, curr_h;
730 *solver_flag = sd->solver_flag;
731 flag = CVodeGetNumSteps(sd->cvode_mem, &nst);
733 *num_steps = (int)nst;
734 flag = CVodeGetNumRhsEvals(sd->cvode_mem, &nfe);
736 *RHS_evals = (int)nfe;
737 flag = CVodeGetNumLinSolvSetups(sd->cvode_mem, &nsetups);
740 *LS_setups = (int)nsetups;
741 flag = CVodeGetNumErrTestFails(sd->cvode_mem, &netf);
744 *error_test_fails = (int)netf;
745 flag = CVodeGetNumNonlinSolvIters(sd->cvode_mem, &nni);
748 *NLS_iters = (int)nni;
749 flag = CVodeGetNumNonlinSolvConvFails(sd->cvode_mem, &ncfn);
750 if (
check_flag(&flag,
"CVodeGetNumNonlinSolvConvFails", 1) ==
753 *NLS_convergence_fails = ncfn;
754 flag = CVDlsGetNumJacEvals(sd->cvode_mem, &nje);
756 *DLS_Jac_evals = (int)nje;
757 flag = CVDlsGetNumRhsEvals(sd->cvode_mem, &nfeLS);
759 *DLS_RHS_evals = (int)nfeLS;
760 flag = CVodeGetLastStep(sd->cvode_mem, &last_h);
762 *last_time_step__s = (double)last_h;
763 flag = CVodeGetCurrentStep(sd->cvode_mem, &curr_h);
765 *next_time_step__s = (double)curr_h;
766 *Jac_eval_fails = sd->Jac_eval_fails;
768 *RHS_evals_total = sd->counterDeriv;
769 *Jac_evals_total = sd->counterJac;
770 *RHS_time__s = ((double)sd->timeDeriv) / CLOCKS_PER_SEC;
771 *Jac_time__s = ((double)sd->timeJac) / CLOCKS_PER_SEC;
772 *max_loss_precision = sd->max_loss_precision;
774 *RHS_evals_total = -1;
775 *Jac_evals_total = -1;
778 *max_loss_precision = 0.0;
783#ifdef CAMP_USE_SUNDIALS
797 realtype replacement_value) {
798 int n_state_var = model_data->n_per_cell_state_var;
799 int n_dep_var = model_data->n_per_cell_dep_var;
800 int n_cells = model_data->n_cells;
803 for (
int i_cell = 0; i_cell < n_cells; i_cell++) {
804 for (
int i_spec = 0; i_spec < n_state_var; ++i_spec) {
806 if (NV_DATA_S(solver_state)[i_dep_var] < -SMALL) {
808 printf(
"\nFailed model state update: [spec %d] = %le", i_spec,
809 NV_DATA_S(solver_state)[i_dep_var]);
814 model_data->total_state[i_spec + i_cell * n_state_var] =
815 NV_DATA_S(solver_state)[i_dep_var] > threshhold
816 ? NV_DATA_S(solver_state)[i_dep_var]
833int f(realtype t, N_Vector y, N_Vector deriv,
void *solver_data) {
834 SolverData *sd = (SolverData *)solver_data;
835 ModelData *md = &(sd->model_data);
843 double *deriv_data = N_VGetArrayPointer(deriv);
846 double *jac_deriv_data = N_VGetArrayPointer(md->J_tmp);
849 int n_cells = md->n_cells;
850 int n_state_var = md->n_per_cell_state_var;
851 int n_dep_var = md->n_per_cell_dep_var;
854 CVodeGetCurrentStep(sd->cvode_mem, &time_step);
858 time_step = time_step > ZERO ? time_step : sd->init_time_step;
867 N_VLinearSum(1.0, y, -1.0, md->J_state, md->J_tmp);
868 SUNMatMatvec(md->J_solver, md->J_tmp, md->J_tmp2);
869 N_VLinearSum(1.0, md->J_deriv, 1.0, md->J_tmp2, md->J_tmp);
873 clock_t start = clock();
878 N_VConst(ZERO, deriv);
882 rxn_calc_deriv_gpu(md, deriv, (
double)time_step);
886 clock_t end = clock();
887 sd->timeDeriv += (end - start);
891 for (
int i_cell = 0; i_cell < n_cells; ++i_cell) {
893 md->grid_cell_id = i_cell;
894 md->grid_cell_state = &(md->total_state[i_cell * n_state_var]);
895 md->grid_cell_env = &(md->total_env[i_cell * CAMP_NUM_ENV_PARAM_]);
896 md->grid_cell_rxn_env_data =
897 &(md->rxn_env_data[i_cell * md->n_rxn_env_data]);
898 md->grid_cell_aero_rep_env_data =
899 &(md->aero_rep_env_data[i_cell * md->n_aero_rep_env_data]);
900 md->grid_cell_sub_model_env_data =
901 &(md->sub_model_env_data[i_cell * md->n_sub_model_env_data]);
911 clock_t start2 = clock();
922 if (sd->use_deriv_est == 1) {
924 sd->output_precision);
927 sd->output_precision);
936 clock_t end2 = clock();
937 sd->timeDeriv += (end2 - start2);
938 sd->max_loss_precision = time_derivative_max_loss_precision(sd->time_deriv);
942 deriv_data += n_dep_var;
943 jac_deriv_data += n_dep_var;
962int Jac(realtype t, N_Vector y, N_Vector deriv, SUNMatrix J,
void *solver_data,
963 N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) {
964 SolverData *sd = (SolverData *)solver_data;
965 ModelData *md = &(sd->model_data);
973 int n_state_var = md->n_per_cell_state_var;
974 int n_dep_var = md->n_per_cell_dep_var;
975 int n_cells = md->n_cells;
978 double *J_param_data = SM_DATA_S(md->J_params);
979 double *J_rxn_data = SM_DATA_S(md->J_rxn);
996 sd->use_deriv_est = 0;
997 if (
f(t, y, deriv, solver_data) != 0) {
998 printf(
"\n Derivative calculation failed.\n");
999 sd->use_deriv_est = 1;
1002 sd->use_deriv_est = 1;
1011 CVodeGetCurrentStep(sd->cvode_mem, &time_step);
1016 SM_NNZ_S(J) = SM_NNZ_S(md->J_init);
1017 for (
int i = 0; i <= SM_NP_S(J); i++) {
1018 (SM_INDEXPTRS_S(J))[i] = (SM_INDEXPTRS_S(md->J_init))[i];
1020 for (
int i = 0; i < SM_NNZ_S(J); i++) {
1021 (SM_INDEXVALS_S(J))[i] = (SM_INDEXVALS_S(md->J_init))[i];
1022 (SM_DATA_S(J))[i] = (realtype)0.0;
1026 clock_t start2 = clock();
1031 rxn_calc_jac_gpu(md, J, time_step);
1035 clock_t end2 = clock();
1036 sd->timeJac += (end2 - start2);
1042 for (
int i_cell = 0; i_cell < n_cells; ++i_cell) {
1044 md->grid_cell_id = i_cell;
1045 md->grid_cell_state = &(md->total_state[i_cell * n_state_var]);
1046 md->grid_cell_env = &(md->total_env[i_cell * CAMP_NUM_ENV_PARAM_]);
1047 md->grid_cell_rxn_env_data =
1048 &(md->rxn_env_data[i_cell * md->n_rxn_env_data]);
1049 md->grid_cell_aero_rep_env_data =
1050 &(md->aero_rep_env_data[i_cell * md->n_aero_rep_env_data]);
1051 md->grid_cell_sub_model_env_data =
1052 &(md->sub_model_env_data[i_cell * md->n_sub_model_env_data]);
1055 for (
int i = 0; i < SM_NNZ_S(md->J_params); ++i)
1056 SM_DATA_S(md->J_params)[i] = 0.0;
1065 CAMP_DEBUG_JAC(md->J_params,
"sub-model Jacobian");
1068 clock_t start = clock();
1081 clock_t end = clock();
1082 sd->timeJac += (end - start);
1087 CAMP_DEBUG_JAC(md->J_rxn,
"reaction Jacobian");
1090 JacMap *jac_map = md->jac_map;
1091 SM_DATA_S(md->J_params)[0] = 1.0;
1092 for (
int i_map = 0; i_map < md->n_mapped_values; ++i_map)
1094 [i_cell * md->n_per_cell_solver_jac_elem + jac_map[i_map].solver_id] +=
1095 SM_DATA_S(md->J_rxn)[jac_map[i_map].rxn_id] *
1096 SM_DATA_S(md->J_params)[jac_map[i_map].param_id];
1097 CAMP_DEBUG_JAC(J,
"solver Jacobian");
1101 for (
int i_elem = 0; i_elem < SM_NNZ_S(J); ++i_elem)
1102 SM_DATA_S(md->J_solver)[i_elem] = SM_DATA_S(J)[i_elem];
1103 N_VScale(1.0, y, md->J_state);
1104 N_VScale(1.0, deriv, md->J_deriv);
1108 if (sd->eval_Jac == SUNTRUE) {
1109 if (!
check_Jac(t, y, J, deriv, tmp1, tmp3, solver_data)) {
1110 ++(sd->Jac_eval_fails);
1136bool check_Jac(realtype t, N_Vector y, SUNMatrix J, N_Vector deriv,
1137 N_Vector tmp, N_Vector tmp1,
void *solver_data) {
1138 realtype *d_state = NV_DATA_S(y);
1139 realtype *d_deriv = NV_DATA_S(deriv);
1143 if (
f(t, y, deriv, solver_data) != 0) {
1144 printf(
"\n Derivative calculation failed.\n");
1181#ifdef CAMP_CUSTOM_CVODE
1182int guess_helper(
const realtype t_n,
const realtype h_n, N_Vector y_n,
1183 N_Vector y_n1, N_Vector hf,
void *solver_data, N_Vector tmp1,
1185 SolverData *sd = (SolverData *)solver_data;
1186 realtype *ay_n = NV_DATA_S(y_n);
1187 realtype *ay_n1 = NV_DATA_S(y_n1);
1188 realtype *atmp1 = NV_DATA_S(tmp1);
1189 realtype *acorr = NV_DATA_S(corr);
1190 realtype *ahf = NV_DATA_S(hf);
1191 int n_elem = NV_LENGTH_S(y_n);
1194 if (N_VMin(y_n) > -SMALL)
return 0;
1196 CAMP_DEBUG_PRINT_FULL(
"Trying to improve guess");
1199 N_VScale(ONE, y_n1, tmp1);
1203 N_VScale(ONE / h_n, hf, corr);
1205 N_VScale(ONE, hf, corr);
1207 CAMP_DEBUG_PRINT(
"Got f0");
1210 realtype t_0 = h_n > ZERO ? t_n - h_n : t_n - ONE;
1211 realtype t_j = ZERO;
1215 realtype h_j = t_n - (t_0 + t_j);
1217 for (
int i = 0; i < n_elem; i++) {
1218 realtype t_star = -atmp1[i] / acorr[i];
1219 if ((t_star > ZERO || (t_star == ZERO && acorr[i] < ZERO)) &&
1227 if (i_fast >= 0 && h_n > ZERO)
1229 h_j = t_n < t_0 + t_j + h_j ? t_n - (t_0 + t_j) : h_j;
1233 t_n - (h_j + t_j + t_0) > ((CVodeMem)sd->cvode_mem)->cv_reltol)
1237 N_VLinearSum(ONE, tmp1, h_j, corr, tmp1);
1238 CAMP_DEBUG_PRINT_FULL(
"Advanced state");
1244 if (
f(t_0 + t_j, tmp1, corr, solver_data) != 0) {
1245 CAMP_DEBUG_PRINT(
"Unexpected failure in guess helper!");
1246 N_VConst(ZERO, corr);
1249 ((CVodeMem)sd->cvode_mem)->cv_nfe++;
1252 CAMP_DEBUG_PRINT(
"Max guess iterations reached!");
1253 if (h_n == ZERO)
return -1;
1257 CAMP_DEBUG_PRINT_INT(
"Guessed y_h in steps:", iter);
1260 N_VLinearSum(ONE, tmp1, -ONE, y_n, corr);
1263 if (h_n > ZERO) N_VScale(0.999, corr, corr);
1266 N_VLinearSum(ONE, tmp1, -ONE, y_n1, hf);
1281 sunindextype n_jac_elem_rxn;
1283 sunindextype n_jac_elem_param;
1285 sunindextype n_jac_elem_solver;
1288 int n_cells = solver_data->model_data.n_cells;
1292 int n_state_var = solver_data->model_data.n_per_cell_state_var;
1295 int n_state_var_total = n_state_var * n_cells;
1299 int n_dep_var = solver_data->model_data.n_per_cell_dep_var;
1302 int n_dep_var_total = n_dep_var * n_cells;
1306 (
unsigned int)n_state_var) != 1) {
1307 printf(
"\n\nERROR allocating Jacobian structure\n\n");
1312 for (
unsigned int i_spec = 0; i_spec < n_state_var; ++i_spec) {
1322 printf(
"\n\nERROR building sparse full-state Jacobian\n\n");
1330 solver_data->model_data.n_per_cell_rxn_jac_elem = (int)n_jac_elem_rxn;
1333 solver_data->model_data.J_rxn =
1334 SUNSparseMatrix(n_state_var, n_state_var, n_jac_elem_rxn, CSC_MAT);
1337 for (
unsigned int i_col = 0; i_col <= n_state_var; ++i_col) {
1338 (SM_INDEXPTRS_S(solver_data->model_data.J_rxn))[i_col] =
1341 for (
unsigned int i_elem = 0; i_elem < n_jac_elem_rxn; ++i_elem) {
1342 (SM_DATA_S(solver_data->model_data.J_rxn))[i_elem] = (realtype)0.0;
1343 (SM_INDEXVALS_S(solver_data->model_data.J_rxn))[i_elem] =
1348 int *deriv_ids = (
int *)malloc(
sizeof(
int) * n_state_var);
1350 if (deriv_ids == NULL) {
1351 printf(
"\n\nERROR allocating space for derivative ids\n\n");
1355 for (
int i_spec = 0; i_spec < n_state_var; i_spec++) {
1357 deriv_ids[i_spec] = i_dep_var++;
1359 deriv_ids[i_spec] = -1;
1364 rxn_update_ids(&(solver_data->model_data), deriv_ids, solver_data->jac);
1373 printf(
"\n\nERROR allocating sub-model Jacobian structure\n\n");
1386 printf(
"\n\nERROR building sparse Jacobian for sub-model parameters\n\n");
1392 solver_data->model_data.n_per_cell_param_jac_elem = (int)n_jac_elem_param;
1398 solver_data->model_data.J_params =
1399 SUNSparseMatrix(n_state_var, n_state_var, n_jac_elem_param, CSC_MAT);
1402 for (
unsigned int i_col = 0; i_col <= n_state_var; ++i_col) {
1403 (SM_INDEXPTRS_S(solver_data->model_data.J_params))[i_col] =
1406 for (
unsigned int i_elem = 0; i_elem < n_jac_elem_param; ++i_elem) {
1407 (SM_DATA_S(solver_data->model_data.J_params))[i_elem] = (realtype)0.0;
1408 (SM_INDEXVALS_S(solver_data->model_data.J_params))[i_elem] =
1420 Jacobian solver_jac;
1422 printf(
"\n\nERROR allocating solver Jacobian structure\n\n");
1427 int n_mapped_values = 0;
1428 for (
int i_ind = 0; i_ind < n_state_var; ++i_ind) {
1429 for (
int i_dep = 0; i_dep < n_state_var; ++i_dep) {
1445 for (
int j_ind = 0; j_ind < n_state_var; ++j_ind) {
1457 printf(
"\n\nERROR building sparse Jacobian for the solver\n\n");
1463 solver_data->model_data.n_per_cell_solver_jac_elem = (int)n_jac_elem_solver;
1466 SUNMatrix M = SUNSparseMatrix(n_dep_var_total, n_dep_var_total,
1467 n_jac_elem_solver * n_cells, CSC_MAT);
1468 solver_data->model_data.J_solver = SUNSparseMatrix(
1469 n_dep_var_total, n_dep_var_total, n_jac_elem_solver * n_cells, CSC_MAT);
1472 for (
unsigned int i_cell = 0; i_cell < n_cells; ++i_cell) {
1473 for (
unsigned int cell_col = 0; cell_col < n_state_var; ++cell_col) {
1474 if (deriv_ids[cell_col] == -1)
continue;
1475 unsigned int i_col = deriv_ids[cell_col] + i_cell * n_dep_var;
1476 (SM_INDEXPTRS_S(M))[i_col] =
1477 (SM_INDEXPTRS_S(solver_data->model_data.J_solver))[i_col] =
1479 i_cell * n_jac_elem_solver;
1481 for (
unsigned int cell_elem = 0; cell_elem < n_jac_elem_solver;
1483 unsigned int i_elem = cell_elem + i_cell * n_jac_elem_solver;
1484 (SM_DATA_S(M))[i_elem] =
1485 (SM_DATA_S(solver_data->model_data.J_solver))[i_elem] = (realtype)0.0;
1486 (SM_INDEXVALS_S(M))[i_elem] =
1487 (SM_INDEXVALS_S(solver_data->model_data.J_solver))[i_elem] =
1492 (SM_INDEXPTRS_S(M))[n_cells * n_dep_var] =
1493 (SM_INDEXPTRS_S(solver_data->model_data.J_solver))[n_cells * n_dep_var] =
1494 n_cells * n_jac_elem_solver;
1497 solver_data->model_data.n_mapped_values = n_mapped_values;
1498 solver_data->model_data.jac_map =
1499 (JacMap *)malloc(
sizeof(JacMap) * n_mapped_values);
1500 if (solver_data->model_data.jac_map == NULL) {
1501 printf(
"\n\nERROR allocating space for jacobian map\n\n");
1504 JacMap *map = solver_data->model_data.jac_map;
1508 int i_mapped_value = 0;
1509 for (
unsigned int i_ind = 0; i_ind < n_state_var; ++i_ind) {
1510 for (
unsigned int i_elem =
1523 map[i_mapped_value].solver_id =
1525 map[i_mapped_value].rxn_id = i_elem;
1526 map[i_mapped_value].param_id = 0;
1532 for (
int j_ind = 0; j_ind < n_state_var; ++j_ind) {
1535 map[i_mapped_value].solver_id =
1537 map[i_mapped_value].rxn_id = i_elem;
1538 map[i_mapped_value].param_id =
1546 SolverData *sd = solver_data;
1547 CAMP_DEBUG_JAC_STRUCT(sd->model_data.J_params,
"Param struct");
1548 CAMP_DEBUG_JAC_STRUCT(sd->model_data.J_rxn,
"Reaction struct");
1549 CAMP_DEBUG_JAC_STRUCT(M,
"Solver struct");
1551 if (i_mapped_value != n_mapped_values) {
1552 printf(
"[ERROR-340355266] Internal error");
1557 solver_data->model_data.J_state = N_VClone(solver_data->y);
1558 solver_data->model_data.J_deriv = N_VClone(solver_data->y);
1559 solver_data->model_data.J_tmp = N_VClone(solver_data->y);
1560 solver_data->model_data.J_tmp2 = N_VClone(solver_data->y);
1564 N_VConst(0.0, solver_data->model_data.J_state);
1565 N_VConst(0.0, solver_data->model_data.J_deriv);
1588 if (opt == 0 && flag_value == NULL) {
1589 fprintf(stderr,
"\nSUNDIALS_ERROR: %s() failed - returned NULL pointer\n\n",
1595 else if (opt == 1) {
1596 err_flag = (
int *)flag_value;
1597 if (*err_flag < 0) {
1598 fprintf(stderr,
"\nSUNDIALS_ERROR: %s() failed with flag = %d\n\n",
1599 func_name, *err_flag);
1624#ifdef CAMP_USE_SUNDIALS
1626 SolverData *sd = (SolverData *)solver_data;
1629 sd->counterDeriv = 0;
1642 long int nst, nfe, nsetups, nje, nfeLS, nni, ncfn, netf, nge;
1643 realtype last_h, curr_h;
1646 flag = CVodeGetNumSteps(cvode_mem, &nst);
1648 flag = CVodeGetNumRhsEvals(cvode_mem, &nfe);
1650 flag = CVodeGetNumLinSolvSetups(cvode_mem, &nsetups);
1653 flag = CVodeGetNumErrTestFails(cvode_mem, &netf);
1656 flag = CVodeGetNumNonlinSolvIters(cvode_mem, &nni);
1659 flag = CVodeGetNumNonlinSolvConvFails(cvode_mem, &ncfn);
1660 if (
check_flag(&flag,
"CVodeGetNumNonlinSolvConvFails", 1) ==
1663 flag = CVDlsGetNumJacEvals(cvode_mem, &nje);
1665 flag = CVDlsGetNumRhsEvals(cvode_mem, &nfeLS);
1667 flag = CVodeGetNumGEvals(cvode_mem, &nge);
1669 flag = CVodeGetLastStep(cvode_mem, &last_h);
1671 flag = CVodeGetCurrentStep(cvode_mem, &curr_h);
1674 printf(
"\nSUNDIALS Solver Statistics:\n");
1675 printf(
"number of steps = %-6ld RHS evals = %-6ld LS setups = %-6ld\n", nst,
1677 printf(
"error test fails = %-6ld LS iters = %-6ld NLS iters = %-6ld\n", netf,
1680 "NL conv fails = %-6ld Dls Jac evals = %-6ld Dls RHS evals = %-6ld G "
1683 ncfn, nje, nfeLS, nge);
1684 printf(
"Last time step = %le Next time step = %le\n", last_h, curr_h);
1694 SolverData *sd = (SolverData *)solver_data;
1696#ifdef CAMP_USE_SUNDIALS
1698 CVodeFree(&(sd->cvode_mem));
1701 N_VDestroy(sd->abs_tol_nv);
1711 N_VDestroy(sd->deriv);
1714 SUNMatDestroy(sd->J);
1717 SUNMatDestroy(sd->J_guess);
1720 SUNLinSolFree(sd->ls);
1730#ifdef CAMP_USE_SUNDIALS
1738 ModelData *md = &(sd->model_data);
1740 if (
f(t_initial, sd->y, sd->deriv, sd)) {
1742 for (
int i_cell = 0; i_cell < md->n_cells; ++i_cell) {
1743 for (
int i_spec = 0; i_spec < md->n_per_cell_state_var; ++i_spec) {
1745 if (NV_Ith_S(sd->y, i_dep_var) >
1746 NV_Ith_S(sd->abs_tol_nv, i_dep_var) * 1.0e-10)
1748 if (NV_Ith_S(sd->deriv, i_dep_var) * (t_final - t_initial) >
1749 NV_Ith_S(sd->abs_tol_nv, i_dep_var) * 1.0e-10)
1768 char *msg,
void *sd) {
1781#ifdef CAMP_USE_SUNDIALS
1783 SUNMatDestroy(model_data.J_init);
1784 SUNMatDestroy(model_data.J_rxn);
1785 SUNMatDestroy(model_data.J_params);
1786 SUNMatDestroy(model_data.J_solver);
1787 N_VDestroy(model_data.J_state);
1788 N_VDestroy(model_data.J_deriv);
1789 N_VDestroy(model_data.J_tmp);
1790 N_VDestroy(model_data.J_tmp2);
1792 free(model_data.jac_map);
1793 free(model_data.jac_map_params);
1794 free(model_data.var_type);
1795 free(model_data.rxn_int_data);
1796 free(model_data.rxn_float_data);
1797 free(model_data.rxn_env_data);
1798 free(model_data.rxn_int_indices);
1799 free(model_data.rxn_float_indices);
1800 free(model_data.rxn_env_idx);
1801 free(model_data.aero_phase_int_data);
1802 free(model_data.aero_phase_float_data);
1803 free(model_data.aero_phase_int_indices);
1804 free(model_data.aero_phase_float_indices);
1805 free(model_data.aero_rep_int_data);
1806 free(model_data.aero_rep_float_data);
1807 free(model_data.aero_rep_env_data);
1808 free(model_data.aero_rep_int_indices);
1809 free(model_data.aero_rep_float_indices);
1810 free(model_data.aero_rep_env_idx);
1811 free(model_data.sub_model_int_data);
1812 free(model_data.sub_model_float_data);
1813 free(model_data.sub_model_env_data);
1814 free(model_data.sub_model_int_indices);
1815 free(model_data.sub_model_float_indices);
1816 free(model_data.sub_model_env_idx);
unsigned int jacobian_column_pointer_value(Jacobian jac, unsigned int col_id)
void jacobian_free(Jacobian *jac)
unsigned int jacobian_build_matrix(Jacobian *jac)
int jacobian_initialize_empty(Jacobian *jac, unsigned int num_spec)
unsigned int jacobian_number_of_elements(Jacobian jac)
unsigned int jacobian_get_element_id(Jacobian jac, unsigned int dep_id, unsigned int ind_id)
void jacobian_reset(Jacobian jac)
void jacobian_register_element(Jacobian *jac, unsigned int dep_id, unsigned int ind_id)
void jacobian_output(Jacobian jac, double *dest_array)
unsigned int jacobian_row_index(Jacobian jac, unsigned int elem_id)
#define CHEM_SPEC_VARIABLE
#define CHEM_SPEC_CONSTANT
void aero_rep_update_env_state(ModelData *model_data)
Update the aerosol representations for new environmental conditions.
void aero_rep_update_state(ModelData *model_data)
Update the aerosol representations for a new state.
void model_free(ModelData model_data)
Free a ModelData object.
int check_flag(void *flag_value, char *func_name, int opt)
Check the return value of a SUNDIALS function.
void solver_get_statistics(void *solver_data, int *solver_flag, int *num_steps, int *RHS_evals, int *LS_setups, int *error_test_fails, int *NLS_iters, int *NLS_convergence_fails, int *DLS_Jac_evals, int *DLS_RHS_evals, double *last_time_step__s, double *next_time_step__s, int *Jac_eval_fails, int *RHS_evals_total, int *Jac_evals_total, double *RHS_time__s, double *Jac_time__s, double *max_loss_precision)
Get solver statistics after an integration attempt.
int Jac(realtype t, N_Vector y, N_Vector deriv, SUNMatrix J, void *solver_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
Compute the Jacobian.
int camp_solver_update_model_state(N_Vector solver_state, ModelData *model_data, realtype threshhold, realtype replacement_value)
Update the model state from the current solver state.
#define MAX_TIMESTEP_WARNINGS
bool is_anything_going_on_here(SolverData *sd, realtype t_initial, realtype t_final)
Determine if there is anything to solve.
void solver_initialize(void *solver_data, double *abs_tol, double rel_tol, int max_steps, int max_conv_fails)
Solver initialization.
SUNMatrix get_jac_init(SolverData *solver_data)
Try to improve guesses of y sent to the linear solver.
void * solver_new(int n_state_var, int n_cells, int *var_type, int n_rxn, int n_rxn_int_param, int n_rxn_float_param, int n_rxn_env_param, int n_aero_phase, int n_aero_phase_int_param, int n_aero_phase_float_param, int n_aero_rep, int n_aero_rep_int_param, int n_aero_rep_float_param, int n_aero_rep_env_param, int n_sub_model, int n_sub_model_int_param, int n_sub_model_float_param, int n_sub_model_env_param)
Get a new solver object.
void check_flag_fail(void *flag_value, char *func_name, int opt)
Check the return value of a SUNDIALS function and exit on failure.
#define DEFAULT_TIME_STEP
void solver_free(void *solver_data)
Free a SolverData object.
void solver_free_update_data(void *update_data)
Free update data.
static void solver_print_stats(void *cvode_mem)
Print solver statistics.
#define CAMP_SOLVER_SUCCESS
void error_handler(int error_code, const char *module, const char *function, char *msg, void *sd)
Custom error handling function.
int f(realtype t, N_Vector y, N_Vector deriv, void *solver_data)
Compute the time derivative f(t,y)
bool check_Jac(realtype t, N_Vector y, SUNMatrix J, N_Vector deriv, N_Vector tmp, N_Vector tmp1, void *solver_data)
Check a Jacobian for accuracy.
void solver_reset_timers(void *solver_data)
Reset the timers for solver functions.
int solver_run(void *solver_data, double *state, double *env, double t_initial, double t_final)
Solve for a given timestep.
void rxn_update_ids(ModelData *model_data, int *deriv_ids, Jacobian jac)
Update the time derivative and Jacobian array ids.
void rxn_calc_deriv_specific_types(ModelData *model_data, TimeDerivative time_deriv, realtype time_step)
Calculate the time derivative for only some specific types.
void rxn_calc_jac_specific_types(ModelData *model_data, Jacobian jac, realtype time_step)
Calculate the Jacobian for only some specific types.
void rxn_get_used_jac_elem(ModelData *model_data, Jacobian *jac)
Get the Jacobian elements used by a particular reaction.
void rxn_update_env_state(ModelData *model_data)
Update reaction data for new environmental state.
void rxn_calc_jac(ModelData *model_data, Jacobian jac, realtype time_step)
Calculate the Jacobian.
void rxn_calc_deriv(ModelData *model_data, TimeDerivative time_deriv, realtype time_step)
Calculate the time derivative .
void sub_model_update_ids(ModelData *model_data, int *deriv_ids, Jacobian jac)
Update the time derivative and Jacobian array ids.
void sub_model_get_used_jac_elem(ModelData *model_data, Jacobian *jac)
Get the Jacobian elements used by a particular sub model.
void sub_model_update_env_state(ModelData *model_data)
Update sub model data for a new environmental state.
void sub_model_calculate(ModelData *model_data)
Perform the sub model calculations for the current model state.
void sub_model_get_jac_contrib(ModelData *model_data, double *J_data, realtype time_step)
Calculate the Jacobian constributions from sub model calculations.
void time_derivative_free(TimeDerivative time_deriv)
int time_derivative_initialize(TimeDerivative *time_deriv, unsigned int num_spec)
void time_derivative_reset(TimeDerivative time_deriv)
void time_derivative_output(TimeDerivative time_deriv, double *dest_array, double *deriv_est, unsigned int output_precision)