25 #include "rungeKutta.rcd" 26 #include "rungeKutta.xcd" 27 #include "simulation.rcd" 30 #include <gsl/gsl_errno.h> 31 #include <gsl/gsl_odeiv2.h> 36 #include <boost/thread.hpp> 50 int RungeKutta::RKfunction(
double t,
const double y[],
double f[],
void *params)
52 if (params==NULL)
return GSL_EBADFUNC;
57 catch (std::exception& e)
65 int RungeKutta::jacobian(
double t,
const double y[],
double * dfdy,
double dfdt[],
void * params)
67 if (params==NULL)
return GSL_EBADFUNC;
68 Matrix jac(stockVars.size(), dfdy);
73 catch (std::exception& e)
83 gsl_odeiv2_system
sys;
86 static void errHandler(
const char* reason,
const char* file,
int line,
int gsl_errno) {
87 throw ecolab::error(
"gsl: %s:%d: %s",file,line,reason);
91 gsl_set_error_handler(errHandler);
92 sys.function=RungeKutta::RKfunction;
93 sys.jacobian=RungeKutta::jacobian;
94 sys.dimension=
minsky->stockVars.size();
96 const gsl_odeiv2_step_type* stepper;
101 throw ecolab::error(
"First order explicit solver not available");
102 stepper=gsl_odeiv2_step_rk1imp;
105 stepper=
minsky->implicit? gsl_odeiv2_step_rk2imp: gsl_odeiv2_step_rk2;
108 stepper=
minsky->implicit? gsl_odeiv2_step_rk4imp: gsl_odeiv2_step_rkf45;
111 throw ecolab::error(
"order %d solver not supported",
minsky->order);
113 driver = gsl_odeiv2_driver_alloc_y_new
116 gsl_odeiv2_driver_set_hmax(driver,
minsky->stepMax);
117 gsl_odeiv2_driver_set_hmin(driver,
minsky->stepMin);
122 void RungeKutta::rkreset()
124 if (order==1 && !implicit)
127 ode.reset(
new RKdata(
this));
130 void RungeKutta::rkstep()
132 if (nSteps<1)
return;
138 auto stockVarsCopy(stockVars);
139 RKThreadRunning=
true;
142 boost::thread rkThread([&]() {
145 double tp=reverse? -t: t;
148 gsl_odeiv2_driver_set_nmax(ode->driver, nSteps);
151 err=gsl_odeiv2_driver_apply(ode->driver, &tp, numeric_limits<double>::max(),
152 stockVarsCopy.data());
156 vector<double> d(stockVarsCopy.size());
157 for (
int i=0; i<nSteps; ++i, tp+=stepMax)
159 evalEquations(d.data(), tp, stockVarsCopy.data());
160 for (
size_t j=0; j<d.size(); ++j)
161 stockVarsCopy[j]+=d[j];
166 catch (
const std::exception& ex)
169 threadErrMsg=ex.what();
173 threadErrMsg=
"Unknown exception thrown on ODE solver thread";
175 RKThreadRunning=
false;
178 while (RKThreadRunning)
186 if (!threadErrMsg.empty())
188 auto msg=std::move(threadErrMsg);
189 threadErrMsg.clear();
191 throw runtime_error(msg);
194 if (resetIfFlagged())
199 case GSL_SUCCESS:
case GSL_EMAXITER:
break;
201 throw error(
"unspecified error GSL_FAILURE returned");
203 gsl_odeiv2_driver_reset(ode->driver);
204 throw error(
"Invalid arithmetic operation detected");
206 throw error(
"gsl error: %s",gsl_strerror(err));
209 stockVars.swap(stockVarsCopy);
216 void RungeKutta::evalJacobian(
Matrix& jac,
double t,
const double sv[])
218 EvalOpBase::t=reverse? -t: t;
219 const double reverseFactor=reverse? -1: 1;
223 for (
size_t i=0; i<equations.size(); ++i)
224 equations[i]->eval(flow.data(), flow.size(), sv);
227 for (
size_t j=0; j<stockVars.size(); ++j)
229 vector<double> ds(stockVars.size()), df(flowVars.size());
231 for (
size_t i=0; i<equations.size(); ++i)
232 equations[i]->deriv(df.data(), df.size(), ds.data(), sv, flow.data());
233 vector<double> d(stockVars.size());
234 evalGodley.eval(d.data(), df.data());
235 for (vector<Integral>::iterator i=integrals.begin();
236 i!=integrals.end(); ++i)
238 assert(i->stock->idx()>=0 && i->input().idx()>=0);
240 i->input().isFlowVar()? df[i->input().idx()]: ds[i->input().idx()];
242 for (
size_t i=0; i<stockVars.size(); i++)
243 jac(i,j)=reverseFactor*d[i];
248 void RungeKutta::evalEquations(
double result[],
double t,
const double vars[])
250 EvalOpBase::t=reverse? -t: t;
251 const double reverseFactor=reverse? -1: 1;
255 for (
size_t i=0; i<equations.size(); ++i)
256 equations[i]->eval(flow.data(), flow.size(), vars);
259 for (
size_t i=0; i<stockVars.size(); ++i) result[i]=0;
260 evalGodley.eval(result, flow.data());
263 for (vector<Integral>::iterator i=integrals.begin(); i<integrals.end(); ++i)
265 if (i->input().idx()<0)
269 throw error(
"integral not wired");
272 assert(i->input().size()==i->stock->size());
273 for (
size_t j=0; j<i->input().size(); ++j)
274 result[i->stock->idx()+j] = reverseFactor *
275 (i->input().isFlowVar()? flow[i->input().idx()+j] : vars[i->input().idx()+j]);
void doOneEvent(bool idletasksOnly)
checks if any GUI events are waiting, and proces an event if so
void displayErrorItem(const Item &op) const
indicate operation item has error, if visible, otherwise contining group
convenience class for accessing matrix elements from a data array
static void errHandler(const char *reason, const char *file, int line, int gsl_errno)
gsl_odeiv2_driver * driver
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky's state cha...
RKdata(RungeKutta *minsky)
CLASSDESC_ACCESS_EXPLICIT_INSTANTIATION(minsky::RungeKutta)