void ode_solver_free(ode_solver* solver){ free(solver->params); CVodeFree(&(solver->cvode_mem)); if (solver->yS != 0) { N_VDestroyVectorArray_Serial(solver->yS, solver->odeModel->P); } N_VDestroy_Serial(solver->y); free(solver); }
CVodesIntegrator::~CVodesIntegrator() { if (m_cvode_mem) { if (m_np > 0) { CVodeSensFree(m_cvode_mem); } CVodeFree(&m_cvode_mem); } if (m_y) { N_VDestroy_Serial(m_y); } if (m_abstol) { N_VDestroy_Serial(m_abstol); } if (m_yS) { N_VDestroyVectorArray_Serial(m_yS, static_cast<sd_size_t>(m_np)); } }
N_Vector *N_VNewVectorArrayEmpty_Serial(int count, long int length) { N_Vector *vs; int j; if (count <= 0) return(NULL); vs = (N_Vector *) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j=0; j<count; j++) { vs[j] = N_VNewEmpty_Serial(length); if (vs[j] == NULL) { N_VDestroyVectorArray_Serial(vs, j-1); return(NULL); } } return(vs); }
N_Vector *N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w) { N_Vector *vs; int j; if (count <= 0) return(NULL); vs = NULL; vs = (N_Vector *) malloc(count * sizeof(N_Vector)); if(vs == NULL) return(NULL); for (j = 0; j < count; j++) { vs[j] = NULL; vs[j] = N_VCloneEmpty_Serial(w); if (vs[j] == NULL) { N_VDestroyVectorArray_Serial(vs, j-1); return(NULL); } } return(vs); }
int main(int argc, char *argv[]) { void *cvode_mem; UserData data; realtype t, tout; N_Vector y; int iout, flag, nthreads, nnz; realtype pbar[NS]; int is; N_Vector *yS; booleantype sensi, err_con; int sensi_meth; cvode_mem = NULL; data = NULL; y = NULL; yS = NULL; /* Process arguments */ ProcessArgs(argc, argv, &sensi, &sensi_meth, &err_con); /* User data structure */ data = (UserData) malloc(sizeof *data); if (check_flag((void *)data, "malloc", 2)) return(1); data->p[0] = RCONST(0.04); data->p[1] = RCONST(1.0e4); data->p[2] = RCONST(3.0e7); /* Initial conditions */ y = N_VNew_Serial(NEQ); if (check_flag((void *)y, "N_VNew_Serial", 0)) return(1); Ith(y,1) = Y1; Ith(y,2) = Y2; Ith(y,3) = Y3; /* Call CVodeCreate to create the solver memory and specify the Backward Differentiation Formula and the use of a Newton iteration */ cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON); if (check_flag((void *)cvode_mem, "CVodeCreate", 0)) return(1); /* Call CVodeInit to initialize the integrator memory and specify the user's right hand side function in y'=f(t,y), the initial time T0, and the initial dependent variable vector y. */ flag = CVodeInit(cvode_mem, f, T0, y); if (check_flag(&flag, "CVodeInit", 1)) return(1); /* Call CVodeWFtolerances to specify a user-supplied function ewt that sets the multiplicative error weights W_i for use in the weighted RMS norm */ flag = CVodeWFtolerances(cvode_mem, ewt); if (check_flag(&flag, "CVodeSetEwtFn", 1)) return(1); /* Attach user data */ flag = CVodeSetUserData(cvode_mem, data); if (check_flag(&flag, "CVodeSetUserData", 1)) return(1); /* Call CVKLU to specify the CVKLU sparse direct linear solver */ nthreads = 1; /* no. of threads to use when factoring the system*/ nnz = NEQ * NEQ; /* max no. of nonzeros entries in the Jac */ flag = CVSuperLUMT(cvode_mem, nthreads, NEQ, nnz); if (check_flag(&flag, "CVSuperLUMT", 1)) return(1); /* Set the Jacobian routine to Jac (user-supplied) */ flag = CVSlsSetSparseJacFn(cvode_mem, Jac); if (check_flag(&flag, "CVSlsSetSparseJacFn", 1)) return(1); printf("\n3-species chemical kinetics problem\n"); /* Sensitivity-related settings */ if (sensi) { /* Set parameter scaling factor */ pbar[0] = data->p[0]; pbar[1] = data->p[1]; pbar[2] = data->p[2]; /* Set sensitivity initial conditions */ yS = N_VCloneVectorArray_Serial(NS, y); if (check_flag((void *)yS, "N_VCloneVectorArray_Serial", 0)) return(1); for (is=0;is<NS;is++) N_VConst(ZERO, yS[is]); /* Call CVodeSensInit1 to activate forward sensitivity computations and allocate internal memory for COVEDS related to sensitivity calculations. Computes the right-hand sides of the sensitivity ODE, one at a time */ flag = CVodeSensInit1(cvode_mem, NS, sensi_meth, fS, yS); if(check_flag(&flag, "CVodeSensInit", 1)) return(1); /* Call CVodeSensEEtolerances to estimate tolerances for sensitivity variables based on the rolerances supplied for states variables and the scaling factor pbar */ flag = CVodeSensEEtolerances(cvode_mem); if(check_flag(&flag, "CVodeSensEEtolerances", 1)) return(1); /* Set sensitivity analysis optional inputs */ /* Call CVodeSetSensErrCon to specify the error control strategy for sensitivity variables */ flag = CVodeSetSensErrCon(cvode_mem, err_con); if (check_flag(&flag, "CVodeSetSensErrCon", 1)) return(1); /* Call CVodeSetSensParams to specify problem parameter information for sensitivity calculations */ flag = CVodeSetSensParams(cvode_mem, NULL, pbar, NULL); if (check_flag(&flag, "CVodeSetSensParams", 1)) return(1); printf("Sensitivity: YES "); if(sensi_meth == CV_SIMULTANEOUS) printf("( SIMULTANEOUS +"); else if(sensi_meth == CV_STAGGERED) printf("( STAGGERED +"); else printf("( STAGGERED1 +"); if(err_con) printf(" FULL ERROR CONTROL )"); else printf(" PARTIAL ERROR CONTROL )"); } else { printf("Sensitivity: NO "); } /* In loop over output points, call CVode, print results, test for error */ printf("\n\n"); printf("==========================================="); printf("============================\n"); printf(" T Q H NST y1"); printf(" y2 y3 \n"); printf("==========================================="); printf("============================\n"); for (iout=1, tout=T1; iout <= NOUT; iout++, tout *= TMULT) { flag = CVode(cvode_mem, tout, y, &t, CV_NORMAL); if (check_flag(&flag, "CVode", 1)) break; PrintOutput(cvode_mem, t, y); /* Call CVodeGetSens to get the sensitivity solution vector after a successful return from CVode */ if (sensi) { flag = CVodeGetSens(cvode_mem, &t, yS); if (check_flag(&flag, "CVodeGetSens", 1)) break; PrintOutputS(yS); } printf("-----------------------------------------"); printf("------------------------------\n"); } /* Print final statistics */ PrintFinalStats(cvode_mem, sensi); /* Free memory */ N_VDestroy_Serial(y); /* Free y vector */ if (sensi) { N_VDestroyVectorArray_Serial(yS, NS); /* Free yS vector */ } free(data); /* Free user data */ CVodeFree(&cvode_mem); /* Free CVODES memory */ return(0); }
int main(int argc, char *argv[]) { void *cvode_mem; UserData data; realtype t, tout; N_Vector y; int iout, flag; realtype pbar[NS]; int is; N_Vector *yS; booleantype sensi, err_con; int sensi_meth; cvode_mem = NULL; data = NULL; y = NULL; yS = NULL; /* Process arguments */ ProcessArgs(argc, argv, &sensi, &sensi_meth, &err_con); /* User data structure */ data = (UserData) malloc(sizeof *data); if (check_flag((void *)data, "malloc", 2)) return(1); data->p[0] = RCONST(0.04); data->p[1] = RCONST(1.0e4); data->p[2] = RCONST(3.0e7); /* Initial conditions */ y = N_VNew_Serial(NEQ); if (check_flag((void *)y, "N_VNew_Serial", 0)) return(1); Ith(y,1) = Y1; Ith(y,2) = Y2; Ith(y,3) = Y3; /* Create CVODES object */ cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON); if (check_flag((void *)cvode_mem, "CVodeCreate", 0)) return(1); /* Allocate space for CVODES */ flag = CVodeMalloc(cvode_mem, f, T0, y, CV_WF, 0.0, NULL); if (check_flag(&flag, "CVodeMalloc", 1)) return(1); /* Use private function to compute error weights */ flag = CVodeSetEwtFn(cvode_mem, ewt, NULL); if (check_flag(&flag, "CVodeSetEwtFn", 1)) return(1); /* Attach user data */ flag = CVodeSetFdata(cvode_mem, data); if (check_flag(&flag, "CVodeSetFdata", 1)) return(1); /* Attach linear solver */ flag = CVDense(cvode_mem, NEQ); if (check_flag(&flag, "CVDense", 1)) return(1); flag = CVDenseSetJacFn(cvode_mem, Jac, data); if (check_flag(&flag, "CVDenseSetJacFn", 1)) return(1); printf("\n3-species chemical kinetics problem\n"); /* Sensitivity-related settings */ if (sensi) { pbar[0] = data->p[0]; pbar[1] = data->p[1]; pbar[2] = data->p[2]; yS = N_VNewVectorArray_Serial(NS, NEQ); if (check_flag((void *)yS, "N_VNewVectorArray_Serial", 0)) return(1); for (is=0;is<NS;is++) N_VConst(ZERO, yS[is]); flag = CVodeSensMalloc(cvode_mem, NS, sensi_meth, yS); if(check_flag(&flag, "CVodeSensMalloc", 1)) return(1); flag = CVodeSetSensRhs1Fn(cvode_mem, fS); if (check_flag(&flag, "CVodeSetSensRhs1Fn", 1)) return(1); flag = CVodeSetSensErrCon(cvode_mem, err_con); if (check_flag(&flag, "CVodeSetSensFdata", 1)) return(1); flag = CVodeSetSensFdata(cvode_mem, data); if (check_flag(&flag, "CVodeSetSensFdata", 1)) return(1); flag = CVodeSetSensParams(cvode_mem, NULL, pbar, NULL); if (check_flag(&flag, "CVodeSetSensParams", 1)) return(1); printf("Sensitivity: YES "); if(sensi_meth == CV_SIMULTANEOUS) printf("( SIMULTANEOUS +"); else if(sensi_meth == CV_STAGGERED) printf("( STAGGERED +"); else printf("( STAGGERED1 +"); if(err_con) printf(" FULL ERROR CONTROL )"); else printf(" PARTIAL ERROR CONTROL )"); } else { printf("Sensitivity: NO "); } /* In loop over output points, call CVode, print results, test for error */ printf("\n\n"); printf("==================================================="); printf("============================\n"); printf(" T Q H NST y1"); printf(" y2 y3 \n"); printf("==================================================="); printf("============================\n"); for (iout=1, tout=T1; iout <= NOUT; iout++, tout *= TMULT) { flag = CVode(cvode_mem, tout, y, &t, CV_NORMAL); if (check_flag(&flag, "CVode", 1)) break; PrintOutput(cvode_mem, t, y); if (sensi) { flag = CVodeGetSens(cvode_mem, t, yS); if (check_flag(&flag, "CVodeGetSens", 1)) break; PrintOutputS(yS); } printf("-------------------------------------------------"); printf("------------------------------\n"); } /* Print final statistics */ PrintFinalStats(cvode_mem, sensi); /* Free memory */ N_VDestroy_Serial(y); /* Free y vector */ if (sensi) { N_VDestroyVectorArray_Serial(yS, NS); /* Free yS vector */ } free(data); /* Free user data */ CVodeFree(cvode_mem); /* Free CVODES memory */ return(0); }
void handleError( void *cvode_mem, N_Vector y0, int flag, mxArray *plhs[], int nrhs, int sensitivity, N_Vector *yS0, realtype *sensitivities, struct mData *data ) { #ifdef DEBUG long int temp; realtype tempreal; #endif #ifdef DEBUG printf( "<<< DEBUG OUTPUT >>>\n" ); printf( "PARAMETERS: \n" ); for ( temp = 0; temp < N_PARAMS; temp++ ) { printf( "P(%d) = %f\n", temp, data->p[ temp ] ); } CVodeGetNumSteps(cvode_mem, &temp); printf( "Number of steps taken by the solver: %d\n", temp ); CVodeGetNumErrTestFails(cvode_mem, &temp); printf( "Number of local error test failures: %d\n", temp ); CVodeGetLastStep(cvode_mem, &tempreal); printf( "Last stepsize: %f\n", tempreal ); CVodeGetCurrentStep(cvode_mem, &tempreal); printf( "Last step: %f\n", tempreal ); #endif if ( sensitivity == 1 ) { if ( nrhs < 7 ) free( sensitivities ); free( data->p ); N_VDestroyVectorArray_Serial( yS0, N_STATES + N_PARAMS ); if ( plhs[2] != NULL ) mxDestroyArray(plhs[2]); } if ( plhs[1] != NULL ) mxDestroyArray(plhs[1]); if ( plhs[0] != NULL ) mxDestroyArray(plhs[0]); N_VDestroy_Serial( y0 ); /*printf( "Freeing..." );*/ /*CVodeFree( &cvode_mem );*/ /*printf( "Success!\n" );*/ switch( flag ) { case CV_MEM_NULL: printf( "ERROR: No memory was allocated for cvode_mem\n" ); break; case CV_NO_MALLOC: printf( "ERROR: Forgot or failed CVodeInit\n" ); break; case CV_ILL_INPUT: printf( "ERROR: Input for CVode was illegal\n" ); break; case CV_TOO_CLOSE: printf( "ERROR: Initial time too close to final time\n" ); break; case CV_TOO_MUCH_WORK: printf( "ERROR: Solver took maximum number of internal steps, but hasn't reached t_out\n" ); break; case CV_TOO_MUCH_ACC: printf( "ERROR: Could not attain desired accuracy\n" ); break; case CV_ERR_FAILURE: printf( "ERROR: Error tests failed too many times\n" ); break; case CV_CONV_FAILURE: printf( "ERROR: Convergence failure in solving the linear system\n" ); break; case CV_LINIT_FAIL: printf( "ERROR: Linear solver failed to initialize\n" ); break; case CV_LSETUP_FAIL: printf( "ERROR: Linear solver setup failed\n" ); break; case CV_RHSFUNC_FAIL: printf( "ERROR: Right hand side failed in an unrecoverable manner\n" ); break; case CV_REPTD_RHSFUNC_ERR: printf( "ERROR: Convergence test failures occured too many times in RHS\n" ); break; case CV_UNREC_RHSFUNC_ERR: printf( "ERROR: Unrecoverable error in the RHS\n" ); break; case CV_RTFUNC_FAIL: printf( "ERROR: Rootfinding function failed!\n" ); break; default: printf( "ERROR: I have no idea what's going on :(\n" ); break; } mexErrMsgTxt( "Aborting" ); }
int main(int argc, char *argv[]) { void *cvode_mem; UserData data; realtype abstol, reltol, t, tout; N_Vector y; int iout, flag; realtype *pbar; int is, *plist; N_Vector *uS; booleantype sensi, err_con; int sensi_meth; pbar = NULL; plist = NULL; uS = NULL; y = NULL; data = NULL; cvode_mem = NULL; /* Process arguments */ ProcessArgs(argc, argv, &sensi, &sensi_meth, &err_con); /* Problem parameters */ data = AllocUserData(); if(check_flag((void *)data, "AllocUserData", 2)) return(1); InitUserData(data); /* Initial states */ y = N_VNew_Serial(NEQ); if(check_flag((void *)y, "N_VNew_Serial", 0)) return(1); SetInitialProfiles(y, data->dx, data->dz); /* Tolerances */ abstol=ATOL; reltol=RTOL; /* Create CVODES object */ cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON); if(check_flag((void *)cvode_mem, "CVodeCreate", 0)) return(1); flag = CVodeSetFdata(cvode_mem, data); if(check_flag(&flag, "CVodeSetFdata", 1)) return(1); flag = CVodeSetMaxNumSteps(cvode_mem, 2000); if(check_flag(&flag, "CVodeSetMaxNumSteps", 1)) return(1); /* Allocate CVODES memory */ flag = CVodeMalloc(cvode_mem, f, T0, y, CV_SS, reltol, &abstol); if(check_flag(&flag, "CVodeMalloc", 1)) return(1); /* Attach CVSPGMR linear solver */ flag = CVSpgmr(cvode_mem, PREC_LEFT, 0); if(check_flag(&flag, "CVSpgmr", 1)) return(1); flag = CVSpilsSetPreconditioner(cvode_mem, Precond, PSolve, data); if(check_flag(&flag, "CVSpilsSetPreconditioner", 1)) return(1); printf("\n2-species diurnal advection-diffusion problem\n"); /* Forward sensitivity analysis */ if(sensi) { plist = (int *) malloc(NS * sizeof(int)); if(check_flag((void *)plist, "malloc", 2)) return(1); for(is=0; is<NS; is++) plist[is] = is; pbar = (realtype *) malloc(NS * sizeof(realtype)); if(check_flag((void *)pbar, "malloc", 2)) return(1); for(is=0; is<NS; is++) pbar[is] = data->p[plist[is]]; uS = N_VCloneVectorArray_Serial(NS, y); if(check_flag((void *)uS, "N_VCloneVectorArray_Serial", 0)) return(1); for(is=0;is<NS;is++) N_VConst(ZERO,uS[is]); flag = CVodeSensMalloc(cvode_mem, NS, sensi_meth, uS); if(check_flag(&flag, "CVodeSensMalloc", 1)) return(1); flag = CVodeSetSensErrCon(cvode_mem, err_con); if(check_flag(&flag, "CVodeSetSensErrCon", 1)) return(1); flag = CVodeSetSensRho(cvode_mem, ZERO); if(check_flag(&flag, "CVodeSetSensRho", 1)) return(1); flag = CVodeSetSensParams(cvode_mem, data->p, pbar, plist); if(check_flag(&flag, "CVodeSetSensParams", 1)) return(1); printf("Sensitivity: YES "); if(sensi_meth == CV_SIMULTANEOUS) printf("( SIMULTANEOUS +"); else if(sensi_meth == CV_STAGGERED) printf("( STAGGERED +"); else printf("( STAGGERED1 +"); if(err_con) printf(" FULL ERROR CONTROL )"); else printf(" PARTIAL ERROR CONTROL )"); } else { printf("Sensitivity: NO "); } /* In loop over output points, call CVode, print results, test for error */ printf("\n\n"); printf("========================================================================\n"); printf(" T Q H NST Bottom left Top right \n"); printf("========================================================================\n"); for (iout=1, tout = TWOHR; iout <= NOUT; iout++, tout += TWOHR) { flag = CVode(cvode_mem, tout, y, &t, CV_NORMAL); if(check_flag(&flag, "CVode", 1)) break; PrintOutput(cvode_mem, t, y); if (sensi) { flag = CVodeGetSens(cvode_mem, t, uS); if(check_flag(&flag, "CVodeGetSens", 1)) break; PrintOutputS(uS); } printf("------------------------------------------------------------------------\n"); } /* Print final statistics */ PrintFinalStats(cvode_mem, sensi); /* Free memory */ N_VDestroy_Serial(y); if (sensi) { N_VDestroyVectorArray_Serial(uS, NS); free(pbar); free(plist); } FreeUserData(data); CVodeFree(&cvode_mem); return(0); }
int main(int argc, char *argv[]) { void *cvode_mem; UserData data; realtype dx, reltol, abstol, t, tout; N_Vector u; int iout, flag; realtype *pbar; int is, *plist; N_Vector *uS; booleantype sensi, err_con; int sensi_meth; cvode_mem = NULL; data = NULL; u = NULL; pbar = NULL; plist = NULL; uS = NULL; /* Process arguments */ ProcessArgs(argc, argv, &sensi, &sensi_meth, &err_con); /* Set user data */ data = (UserData) malloc(sizeof *data); /* Allocate data memory */ if(check_flag((void *)data, "malloc", 2)) return(1); data->p = (realtype *) malloc(NP * sizeof(realtype)); dx = data->dx = XMAX/((realtype)(MX+1)); data->p[0] = RCONST(1.0); data->p[1] = RCONST(0.5); /* Allocate and set initial states */ u = N_VNew_Serial(NEQ); if(check_flag((void *)u, "N_VNew_Serial", 0)) return(1); SetIC(u, dx); /* Set integration tolerances */ reltol = ZERO; abstol = ATOL; /* Create CVODES object */ cvode_mem = CVodeCreate(CV_ADAMS, CV_FUNCTIONAL); if(check_flag((void *)cvode_mem, "CVodeCreate", 0)) return(1); flag = CVodeSetUserData(cvode_mem, data); if(check_flag(&flag, "CVodeSetUserData", 1)) return(1); /* Allocate CVODES memory */ flag = CVodeInit(cvode_mem, f, T0, u); if(check_flag(&flag, "CVodeInit", 1)) return(1); flag = CVodeSStolerances(cvode_mem, reltol, abstol); if(check_flag(&flag, "CVodeSStolerances", 1)) return(1); printf("\n1-D advection-diffusion equation, mesh size =%3d\n", MX); /* Sensitivity-related settings */ if(sensi) { plist = (int *) malloc(NS * sizeof(int)); if(check_flag((void *)plist, "malloc", 2)) return(1); for(is=0; is<NS; is++) plist[is] = is; pbar = (realtype *) malloc(NS * sizeof(realtype)); if(check_flag((void *)pbar, "malloc", 2)) return(1); for(is=0; is<NS; is++) pbar[is] = data->p[plist[is]]; uS = N_VCloneVectorArray_Serial(NS, u); if(check_flag((void *)uS, "N_VCloneVectorArray_Serial", 0)) return(1); for(is=0;is<NS;is++) N_VConst(ZERO, uS[is]); flag = CVodeSensInit1(cvode_mem, NS, sensi_meth, NULL, uS); if(check_flag(&flag, "CVodeSensInit1", 1)) return(1); flag = CVodeSensEEtolerances(cvode_mem); if(check_flag(&flag, "CVodeSensEEtolerances", 1)) return(1); flag = CVodeSetSensErrCon(cvode_mem, err_con); if(check_flag(&flag, "CVodeSetSensErrCon", 1)) return(1); flag = CVodeSetSensDQMethod(cvode_mem, CV_CENTERED, ZERO); if(check_flag(&flag, "CVodeSetSensDQMethod", 1)) return(1); flag = CVodeSetSensParams(cvode_mem, data->p, pbar, plist); if(check_flag(&flag, "CVodeSetSensParams", 1)) return(1); printf("Sensitivity: YES "); if(sensi_meth == CV_SIMULTANEOUS) printf("( SIMULTANEOUS +"); else if(sensi_meth == CV_STAGGERED) printf("( STAGGERED +"); else printf("( STAGGERED1 +"); if(err_con) printf(" FULL ERROR CONTROL )"); else printf(" PARTIAL ERROR CONTROL )"); } else { printf("Sensitivity: NO "); } /* In loop over output points, call CVode, print results, test for error */ printf("\n\n"); printf("============================================================\n"); printf(" T Q H NST Max norm \n"); printf("============================================================\n"); for (iout=1, tout=T1; iout <= NOUT; iout++, tout += DTOUT) { flag = CVode(cvode_mem, tout, u, &t, CV_NORMAL); if(check_flag(&flag, "CVode", 1)) break; PrintOutput(cvode_mem, t, u); if (sensi) { flag = CVodeGetSens(cvode_mem, &t, uS); if(check_flag(&flag, "CVodeGetSens", 1)) break; PrintOutputS(uS); } printf("------------------------------------------------------------\n"); } /* Print final statistics */ PrintFinalStats(cvode_mem, sensi); /* Free memory */ N_VDestroy_Serial(u); if (sensi) { N_VDestroyVectorArray_Serial(uS, NS); free(plist); free(pbar); } free(data); CVodeFree(&cvode_mem); return(0); }
/** * Solves an initial value problem using CVODES to integrate over a system of * ODEs with optional forward sensitivity analysis. The initial conditions for * the system and for the sensitivity analysis are expected to be in the first * rows of simdata and sensitivities, respectively. * * @param [in] rhs the right-hand side of the system of ODEs * @param [in] num_timepoints the number of timepoints * @param [in] num_species the number of independent variables * @param [in] num_sens the number of parameters to compute sensitivities * for (set to zero to disable sensitivity * calculations) * @param [in] timepoints the timepoints at which data is to be returned * @param [in] params parameters * @param [in] sensi the indices of the parameters to compute the * sensitivities for (may be NULL to compute the * sensitivities for all parameters) * @param [in] options additional options for the integrator * @param [out] simdata contains the state values for each species at * each timepoint in column-major order. * @param [out] sensitivities sensitivities of each parameter in sensi * with respect to each independent variable. * The sensitivity of parameter j with respect to * variable k at timepoint i is stored at * (j * num_species + k) * lds + i. * May be NULL if sensitivities are not to be * calculated. * @param [in] lds leading dimension of simdata and sensitivities * * @return 0 on success, * GMCMC_ENOMEM if there was not enough memory to create the solver, * GMCMC_EINVAL if there was an invalid argument to the function, * GMCMC_ELINAL if the solution could not be found. */ int cvodes_solve(gmcmc_ode_rhs rhs, size_t num_timepoints, size_t num_species, size_t num_params, size_t num_sens, const double * timepoints, const double * params, const size_t * sensi, const cvodes_options * options, double * simdata, double * sensitivities, size_t lds) { int error; // Set vector of initial values N_Vector y = N_VNew_Serial((long int)num_species); for (size_t j = 0; j < num_species; j++) NV_Ith_S(y, j) = simdata[j * lds]; // Create CVODES object void * cvode_mem; if ((cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON)) == NULL) GMCMC_ERROR("Failed to allocate ODE solver", GMCMC_ENOMEM); // Initialise CVODES solver if ((error = CVodeInit(cvode_mem, cvodes_rhs, timepoints[0], y)) != CV_SUCCESS) { CVodeFree(&cvode_mem); GMCMC_ERROR("Failed to initialise ODE solver", (error == CV_ILL_INPUT) ? GMCMC_EINVAL : GMCMC_ENOMEM); } // Set integration tolerances if ((error = CVodeSStolerances(cvode_mem, options->reltol, options->abstol)) != CV_SUCCESS) { CVodeFree(&cvode_mem); GMCMC_ERROR("Failed to set ODE solver integration tolerances", (error == CV_ILL_INPUT) ? GMCMC_EINVAL : GMCMC_ENOMEM); } // Create a copy of the parameters in case CVODES modifies them realtype * sens_params; if ((sens_params = malloc(num_params * sizeof(realtype))) == NULL) { CVodeFree(&cvode_mem); GMCMC_ERROR("Failed to allocate copy of parameter vector for sensitivity analysis", GMCMC_ENOMEM); } for (size_t i = 0; i < num_params; i++) sens_params[i] = (realtype)params[i]; // Set optional inputs cvodes_userdata userdata = { rhs, sens_params }; if ((error = CVodeSetUserData(cvode_mem, &userdata)) != CV_SUCCESS) { CVodeFree(&cvode_mem); free(sens_params); GMCMC_ERROR("Failed to set ODE solver user data", GMCMC_EINVAL); } // Attach linear solver module if ((error = CVLapackDense(cvode_mem, (int)num_species)) != CV_SUCCESS) { CVodeFree(&cvode_mem); free(sens_params); GMCMC_ERROR("Failed to attach ODE solver module", (error == CV_ILL_INPUT) ? GMCMC_EINVAL : GMCMC_ENOMEM); } N_Vector * yS = NULL; int * plist = NULL; if (num_sens > 0) { // Set sensitivity initial conditions yS = N_VCloneVectorArray_Serial((int)num_sens, y); for (size_t j = 0; j < num_sens; j++) { for (size_t i = 0; i < num_species; i++) NV_Ith_S(yS[j], i) = sensitivities[(j * num_species + i) * lds]; } // Activate sensitivity calculations // Use default finite differences if ((error = CVodeSensInit(cvode_mem, (int)num_sens, CV_SIMULTANEOUS, NULL, yS)) != CV_SUCCESS) { CVodeFree(&cvode_mem); free(sens_params); GMCMC_ERROR("Failed to activate ODE solver sensitivity calculations", (error == CV_ILL_INPUT) ? GMCMC_EINVAL : GMCMC_ENOMEM); } // Set sensitivity tolerances if ((error = CVodeSensEEtolerances(cvode_mem)) != CV_SUCCESS) { CVodeFree(&cvode_mem); free(sens_params); GMCMC_ERROR("Failed to set ODE solver sensitivity tolerances", (error == CV_ILL_INPUT) ? GMCMC_EINVAL : GMCMC_ENOMEM); } if (sensi != NULL) { if ((plist = malloc(num_sens * sizeof(int))) == NULL) { CVodeFree(&cvode_mem); free(sens_params); GMCMC_ERROR("Failed to allocate sensitivity parameter list", GMCMC_ENOMEM); } for (size_t i = 0; i < num_sens; i++) plist[i] = (int)sensi[i]; } // Set sensitivity analysis optional inputs if ((error = CVodeSetSensParams(cvode_mem, sens_params, NULL, plist)) != CV_SUCCESS) { CVodeFree(&cvode_mem); free(plist); free(sens_params); GMCMC_ERROR("Failed to set ODE solver sensitivity parameters", (error == CV_ILL_INPUT) ? GMCMC_EINVAL : GMCMC_ENOMEM); } } // Advance solution in time realtype tret; for (size_t i = 1; i < num_timepoints; i++) { if ((error = CVode(cvode_mem, timepoints[i], y, &tret, CV_NORMAL)) != CV_SUCCESS) { free(plist); free(sens_params); CVodeFree(&cvode_mem); GMCMC_ERROR("Failed to advance ODE solution", GMCMC_ELINAL); } for (size_t j = 0; j < num_species; j++) simdata[j * lds + i] = NV_Ith_S(y, j); // Extract the sensitivity solution if (yS != NULL) { if ((error = CVodeGetSens(cvode_mem, &tret, yS)) != CV_SUCCESS) { free(plist); free(sens_params); CVodeFree(&cvode_mem); GMCMC_ERROR("Failed to extract ODE sensitivity solution", GMCMC_ELINAL); } for (size_t j = 0; j < num_sens; j++) { for (size_t k = 0; k < num_species; k++) sensitivities[(j * num_species + k) * lds + i] = NV_Ith_S(yS[j], k); } } } N_VDestroy(y); if (yS != NULL) N_VDestroyVectorArray_Serial(yS, (int)num_sens); free(plist); free(sens_params); // Free solver memory CVodeFree(&cvode_mem); return 0; }