/* ----------------------------------------------------
NOTICE OF COPYRIGHT AND OWNERSHIP OF SOFTWARE
Copyright 2004, The Johns Hopkins University
School of Medicine. All rights reserved.
For research use only; commercial use prohibited.
Distribution without permission of Raimond L. Winslow
not permitted. rwinslow@bme.jhu.edu
Name of Program: Guinea Pig C++: Coupled, Algbraic, BB, MCA
Version: Documented Version, version 1.0.1
Date: August 2004
-----------------------------------------------------
*/
#include "integratorcvode.h"
//Define CVode F function
//Note: direct access of y, ydot is not constant
void func_f(long N, realtype time, N_Vector y, N_Vector ydot, void *f_data) {
((Model*)f_data)->F(time, N_VGetData(ydot), N_VGetData(y));
}
IntegratorCVode::IntegratorCVode(void) {
ropt = new double[OPT_SIZE];
iopt = new long[OPT_SIZE];
usingErrorWeights = true;
}
IntegratorCVode::~IntegratorCVode(void) {
N_VFree(cvode_y);
N_VFree(cvode_ic);
//N_VDispose(cvode_y);
N_VFree(ew);
CVodeFree(cvode_mem);
delete[] ropt;
delete[] iopt;
}
//Integrates the current problem, attempting to reach time
//State variables and actual time recorded in cvode_y, &cvode_t.
void IntegratorCVode::iterateToTime(double time) {
// call CVode to solve ydot(t)=f(y,t) with y(0) given
//Normal Mode
int flag = CVode(cvode_mem, time, cvode_y, &cvode_t, NORMAL);
//*
//One step mode: ONE_STEP
// int flag;
// while(cvode_t < time) {
// flag = CVode(cvode_mem, time, cvode_y, &cvode_t, ONE_STEP);
if (flag != SUCCESS) {
cout << "CVode failed, flag=" << flag << "." << endl;
// char c;
// cin >> c;
}
// }
}
//Initializes
void IntegratorCVode::setupCVode(Model *model) {
//Parameters: step_max, step_min, usingErrorWeights, start_time
N_Vector errweight;
machEnv = NULL;
machEnv = M_EnvInit_Serial(model->getProblemSize());
if (machEnv == NULL) {
cerr << "Trouble with MachEnv in CVODE" << endl;
exit(-3);
}
// Allocate memory for solution vector y(t)
cvode_y = N_VNew( model->getProblemSize(), machEnv);
// cvode_y = N_VMake( model->getProblemSize(), model->getStates(), machEnv);
// Allocate memory for solution vector ew(t)
ew = N_VNew( model->getProblemSize(), machEnv);
errweight = N_VMake( model->getProblemSize(), model->getErrorWeights(), machEnv);
// scale tolerance based on maximum value of state
N_VInv(errweight, ew);
N_VScale(abstol, ew, ew);
//Allocate and set cvode_ic
cvode_ic = N_VNew( model->getProblemSize(), machEnv);
N_Vector ic = N_VMake( model->getProblemSize(), model->getStates(), machEnv);
N_VAddConst(ic, 0.0, cvode_ic);
N_VDispose(ic);
// use default values for options
for(int i = 0; i < OPT_SIZE; i++) {
ropt[i]=0.0;
iopt[i]=0L;
}
//Set optional parameters
iopt[MXSTEP] = 1000000; //added by JT, taken from integrator.cpp of Canine model
ropt[HMAX] = step_max; // Largest step size
ropt[HMIN] = step_min; // Smallest step size
/* CVodeMalloc sets up initial settings for CVode. See
Integration method is BDF(Backward Differential Formula)
Other choice would be ADAMS but it is not as stable */
if (usingErrorWeights) {
// We wish to pass errorweight to CVODE
cvode_mem = CVodeMalloc(model->getProblemSize(), func_f, 0, cvode_ic, BDF,
NEWTON, SV, &reltol, ew , model, NULL, TRUE, iopt, ropt, machEnv);
} else {
// This method of calling CVODE does not pass error weights
cvode_mem = CVodeMalloc(model->getProblemSize(), func_f, 0, cvode_ic, BDF,
NEWTON, SS, &reltol, &abstol, model, NULL, TRUE, iopt, ropt, machEnv);
}
if ( cvode_mem == NULL ) {
cerr << "CVodeMalloc failed." << endl;
exit(1);
}
/* CVDense is needed by Newton algorithm for solving linear system
The second NULL tells the solver to compute an approximation of the Jacobian. */
CVDense(cvode_mem, NULL, NULL);
N_VDispose(errweight);
}
//Refresh the CVode integrator for another run
void IntegratorCVode::refreshCVode(Model *model) {
//Parameters: step_max, step_min, usingErrorWeights, start_time
int error;
N_Vector ic = N_VMake( model->getProblemSize(), model->getStates(), machEnv);
N_VAddConst(ic, 0.0, cvode_ic);
N_VDispose(ic);
/* CVodeMalloc sets up initial settings for CVode. See
Integration method is BDF(Backward Differential Formula)
Other choice would be ADAMS but it is not as stable */
if (usingErrorWeights) {
// We wish to pass errorweight to CVODE
error = CVReInit(cvode_mem, func_f, 0, cvode_ic, BDF,
NEWTON, SV, &reltol, ew , model, NULL, TRUE, iopt, ropt, machEnv);
} else {
// This method of calling CVODE does not pass error weights
error = CVReInit(cvode_mem, func_f, 0, cvode_ic, BDF,
NEWTON, SS, &reltol, &abstol, model, NULL, TRUE, iopt, ropt, machEnv);
}
if (SUCCESS != error) {
cout << "Error in IntegratorCVode::refreshCVode(), code :" << error << "." << endl;
exit(-1);
}
/* CVDense is needed by Newton algorithm for solving linear system
The second NULL tells the solver to compute an approximation of the Jacobian. */
CVDense(cvode_mem, NULL, NULL);
}
//Set all the parameters for the integrator
void IntegratorCVode::setParameters(fileIO& data) {
reltol = data["reltol"];
abstol = data["abstol"];
step_max = data["step_max"];
step_min = data["step_min"];
start_time = data["start_time"];
stepsize = data["stepsize"];
cvode_t = start_time;
usingErrorWeights = data.getBoolean("usingErrorWeights");
}
//Do a single integration of the model
void IntegratorCVode::integrateModel(Model *model, fileIO *out, int runNumber) {
//Some stimulas mode parameters
// model->setInitialConditions(*out);
model->setupIFmode(runNumber);
//CVode Refresh -> Initial conditions:
refreshCVode(model);
//during each iteration of this loop, an experiment object is set up. A set of statevalues
//is also computed.
double stopTime = model->getStopTime();
//Since we don't want to max out intermediate steps getting to time t
for(double t = stepsize; t < start_time; ) {
//Periodic output to let you know how it's going
for(int i = 0; (t < start_time) && (i < 1000); i++, t = cvode_t + stepsize) {
iterateToTime(t);
}
cout<<'.';
}
for(double t = start_time + stepsize; t < stopTime; ) {
//Periodic output to let you know how it's going
for(int i = 0; (t < stopTime) && (i < 1000); i++, t = cvode_t + stepsize) {
iterateToTime(t);
out->writeLnOutputFiles( N_VGetData(cvode_y), cvode_t, model);
}
cout<<'.';
}
cout << "Complete." << endl;
}