idas_interface.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "idas_interface.hpp"
27 #include "casadi/core/casadi_misc.hpp"
28 
29 // Macro for error handling
30 #define THROWING(fcn, ...) \
31 idas_error(CASADI_STR(fcn), fcn(__VA_ARGS__))
32 
33 namespace casadi {
34 
35 extern "C"
36 int CASADI_INTEGRATOR_IDAS_EXPORT
37  casadi_register_integrator_idas(Integrator::Plugin* plugin) {
38  plugin->creator = IdasInterface::creator;
39  plugin->name = "idas";
40  plugin->doc = IdasInterface::meta_doc.c_str();
41  plugin->version = CASADI_VERSION;
42  plugin->options = &IdasInterface::options_;
43  plugin->deserialize = &IdasInterface::deserialize;
44  return 0;
45 }
46 
47 extern "C"
48 void CASADI_INTEGRATOR_IDAS_EXPORT casadi_load_integrator_idas() {
50 }
51 
52 IdasInterface::IdasInterface(const std::string& name, const Function& dae,
53  double t0, const std::vector<double>& tout) : SundialsInterface(name, dae, t0, tout) {
54 }
55 
57  clear_mem();
58 }
59 
62  {{"suppress_algebraic",
63  {OT_BOOL,
64  "Suppress algebraic variables in the error testing"}},
65  {"calc_ic",
66  {OT_BOOL,
67  "Use IDACalcIC to get consistent initial conditions."}},
68  {"constraints",
69  {OT_INTVECTOR,
70  "Constrain the solution y=[x,z]. 0 (default): no constraint on yi, "
71  "1: yi >= 0.0, -1: yi <= 0.0, 2: yi > 0.0, -2: yi < 0.0."}},
72  {"calc_icB",
73  {OT_BOOL,
74  "Use IDACalcIC to get consistent initial conditions for "
75  "backwards system [default: equal to calc_ic]."}},
76  {"abstolv",
78  "Absolute tolerarance for each component"}},
79  {"max_step_size",
80  {OT_DOUBLE,
81  "Maximim step size"}},
82  {"first_time",
83  {OT_DOUBLE,
84  "First requested time as a fraction of the time interval"}},
85  {"cj_scaling",
86  {OT_BOOL,
87  "IDAS scaling on cj for the user-defined linear solver module"}},
88  {"init_xdot",
90  "Initial values for the state derivatives"}}
91  }
92 };
93 
94 void IdasInterface::init(const Dict& opts) {
95  if (verbose_) casadi_message(name_ + "::init");
96 
97  // Call the base class init
99 
100  // Default options
101  cj_scaling_ = true;
102  calc_ic_ = true;
103  suppress_algebraic_ = false;
104 
105  // Read options
106  for (auto&& op : opts) {
107  if (op.first=="init_xdot") {
108  init_xdot_ = op.second;
109  } else if (op.first=="cj_scaling") {
110  cj_scaling_ = op.second;
111  } else if (op.first=="calc_ic") {
112  calc_ic_ = op.second;
113  } else if (op.first=="suppress_algebraic") {
114  suppress_algebraic_ = op.second;
115  } else if (op.first=="constraints") {
116  y_c_ = op.second;
117  } else if (op.first=="abstolv") {
118  abstolv_ = op.second;
119  }
120  }
121 
122  // Default dependent options
124  first_time_ = tout_.back();
125 
126  // Read dependent options
127  for (auto&& op : opts) {
128  if (op.first=="calc_icB") {
129  calc_icB_ = op.second;
130  } else if (op.first=="first_time") {
131  first_time_ = op.second;
132  }
133  }
134 
135  // Get initial conditions for the state derivatives
136  if (init_xdot_.empty()) {
137  init_xdot_.resize(nx_, 0);
138  } else {
139  casadi_assert(
140  init_xdot_.size()==nx_,
141  "Option \"init_xdot\" has incorrect length. Expecting " + str(nx_) + ", "
142  "but got " + str(init_xdot_.size()) + ". "
143  "Note that this message may actually be generated by the augmented integrator. "
144  "In that case, make use of the 'augmented_options' options "
145  "to correct 'init_xdot' for the augmented integrator.");
146  }
147 
148  // Leave forward sensitivity states unconstrained.
149  if (nfwd_ > 0 && !y_c_.empty() && y_c_.size() == nx1_ + nz1_) {
150  y_c_.insert(y_c_.begin() + nx1_, nx_ - nx1_, 0);
151  y_c_.resize(nx_ + nz_, 0);
152  opts_["constraints"] = y_c_;
153  }
154 
155  // Constraints
156  casadi_assert(y_c_.size() == nx_+nz_ || y_c_.empty(),
157  "Constraint vector if supplied, must be of length nx+nz, but got "
158  + str(y_c_.size()) + " and nx+nz = " + str(nx_+nz_) + ".");
159 
160  // For Jacobian calculation
161  alloc_w(nx_ + nz_); // casadi_copy_block
162 }
163 
164 int IdasInterface::resF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr, void *user_data) {
165  try {
166  auto m = to_mem(user_data);
167  auto& s = m->self;
168  if (s.calc_daeF(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_,
169  NV_DATA_S(rr), NV_DATA_S(rr) + s.nx_)) return 1;
170 
171  // Subtract state derivative to get residual
172  casadi_axpy(s.nx_, -1., NV_DATA_S(xzdot), NV_DATA_S(rr));
173  return 0;
174  } catch(std::exception& e) { // non-recoverable error
175  uerr() << "res failed: " << e.what() << std::endl;
176  return -1;
177  }
178 }
179 
180 void IdasInterface::ehfun(int error_code, const char *module, const char *function,
181  char *msg, void *eh_data) {
182  try {
183  //auto m = to_mem(eh_data);
184  //auto& s = m->self;
185  uerr() << msg << std::endl;
186  } catch(std::exception& e) {
187  uerr() << "ehfun failed: " << e.what() << std::endl;
188  }
189 }
190 
191 int IdasInterface::jtimesF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr, N_Vector v,
192  N_Vector Jv, double cj, void *user_data, N_Vector tmp1, N_Vector tmp2) {
193  try {
194  auto m = to_mem(user_data);
195  auto& s = m->self;
196  if (s.calc_jtimesF(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_,
197  NV_DATA_S(v), NV_DATA_S(v) + s.nx_,
198  NV_DATA_S(Jv), NV_DATA_S(Jv) + s.nx_)) return 1;
199 
200  // Subtract state derivative to get residual
201  casadi_axpy(s.nx_, -cj, NV_DATA_S(v), NV_DATA_S(Jv));
202 
203  return 0;
204  } catch(std::exception& e) { // non-recoverable error
205  uerr() << "jtimesF failed: " << e.what() << std::endl;
206  return -1;
207  }
208 }
209 
210 int IdasInterface::jtimesB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz,
211  N_Vector rxzdot, N_Vector resvalB, N_Vector v, N_Vector Jv,
212  double cjB, void *user_data, N_Vector tmp1B, N_Vector tmp2B) {
213  try {
214  auto m = to_mem(user_data);
215  auto& s = m->self;
216  // The function is linear so the Jacobian-times-vector function is the function itself
217  if (s.calc_daeB(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_,
218  NV_DATA_S(v), NV_DATA_S(v) + s.nrx_, nullptr,
219  NV_DATA_S(Jv), NV_DATA_S(Jv) + s.nrx_)) return 1;
220  // Subtract state derivative to get residual
221  casadi_axpy(s.nrx_, cjB, NV_DATA_S(v), NV_DATA_S(Jv));
222 
223  return 0;
224  } catch(std::exception& e) { // non-recoverable error
225  uerr() << "jtimesB failed: " << e.what() << std::endl;
226  return -1;
227  }
228 }
229 
230 int IdasInterface::init_mem(void* mem) const {
231  if (SundialsInterface::init_mem(mem)) return 1;
232  auto m = to_mem(mem);
233 
234  // Create IDAS memory block
235  m->mem = IDACreate();
236  casadi_assert(m->mem!=nullptr, "IDACreate: Creation failed");
237 
238  // Set error handler function
239  THROWING(IDASetErrHandlerFn, m->mem, ehfun, m);
240 
241  // Set user data
242  THROWING(IDASetUserData, m->mem, m);
243 
244  // Allocate n-vectors for ivp
245  m->v_xzdot = N_VNew_Serial(nx_+nz_);
246 
247  // Initialize Idas
248  double t0 = 0;
249  N_VConst(0.0, m->v_xz);
250  N_VConst(0.0, m->v_xzdot);
251  IDAInit(m->mem, resF, t0, m->v_xz, m->v_xzdot);
252  if (verbose_) casadi_message("IDA initialized");
253 
254  // Include algebraic variables in error testing
255  THROWING(IDASetSuppressAlg, m->mem, suppress_algebraic_);
256 
257  // Maxinum order for the multistep method
258  THROWING(IDASetMaxOrd, m->mem, max_multistep_order_);
259 
260  // Initial step size
261  if (step0_!=0) THROWING(IDASetInitStep, m->mem, step0_);
262 
263  // Set maximum step size
264  if (max_step_size_!=0) THROWING(IDASetMaxStep, m->mem, max_step_size_);
265 
266  // Set constraints
267  if (!y_c_.empty()) {
268  N_Vector domain = N_VNew_Serial(nx_+nz_);
269  std::copy(y_c_.begin(), y_c_.end(), NV_DATA_S(domain));
270 
271  // Pass to IDA
272  int flag = IDASetConstraints(m->mem, domain);
273  casadi_assert_dev(flag==IDA_SUCCESS);
274 
275  // Free the temporary vector
276  N_VDestroy_Serial(domain);
277  }
278 
279  // Maximum order of method
280  if (max_order_) THROWING(IDASetMaxOrd, m->mem, max_order_);
281 
282  // Coeff. in the nonlinear convergence test
283  if (nonlin_conv_coeff_!=0) THROWING(IDASetNonlinConvCoef, m->mem, nonlin_conv_coeff_);
284 
285  // Scaling
286  if (!abstolv_.empty()) {
287  // Vector absolute tolerances
288  N_Vector nv_abstol = N_VNew_Serial(static_cast<long>(abstolv_.size()));
289  std::copy(abstolv_.begin(), abstolv_.end(), NV_DATA_S(nv_abstol));
290  THROWING(IDASVtolerances, m->mem, reltol_, nv_abstol);
291  N_VDestroy_Serial(nv_abstol);
292  } else if (scale_abstol_) {
293  // Scale absolute tolerances with nominal values
294  THROWING(IDASVtolerances, m->mem, reltol_, m->abstolv);
295  } else {
296  // Scalar absolute tolerances
297  THROWING(IDASStolerances, m->mem, reltol_, abstol_);
298  }
299 
300  // Maximum number of steps
301  THROWING(IDASetMaxNumSteps, m->mem, max_num_steps_);
302 
303  // Set algebraic components
304  N_Vector id = N_VNew_Serial(nx_+nz_);
305  std::fill_n(NV_DATA_S(id), nx_, 1);
306  std::fill_n(NV_DATA_S(id)+nx_, nz_, 0);
307 
308  // Pass this information to IDAS
309  THROWING(IDASetId, m->mem, id);
310 
311  // Delete the allocated memory
312  N_VDestroy_Serial(id);
313 
314  // attach a linear solver
315  if (newton_scheme_==SD_DIRECT) {
316  // Direct scheme
317  IDAMem IDA_mem = IDAMem(m->mem);
318  IDA_mem->ida_lmem = m;
319  IDA_mem->ida_lsetup = lsetupF;
320  IDA_mem->ida_lsolve = lsolveF;
321  IDA_mem->ida_setupNonNull = TRUE;
322  } else {
323  // Iterative scheme
324  switch (newton_scheme_) {
325  case SD_DIRECT: casadi_assert_dev(0);
326  case SD_GMRES: THROWING(IDASpgmr, m->mem, max_krylov_); break;
327  case SD_BCGSTAB: THROWING(IDASpbcg, m->mem, max_krylov_); break;
328  case SD_TFQMR: THROWING(IDASptfqmr, m->mem, max_krylov_); break;
329  }
330  THROWING(IDASpilsSetJacTimesVecFn, m->mem, jtimesF);
331  if (use_precon_) THROWING(IDASpilsSetPreconditioner, m->mem, psetupF, psolveF);
332  }
333 
334  // Quadrature equations
335  if (nq1_ > 0) {
336 
337  // Initialize quadratures in IDAS
338  THROWING(IDAQuadInit, m->mem, rhsQF, m->v_q);
339 
340  // Should the quadrature errors be used for step size control?
341  if (quad_err_con_) {
342  THROWING(IDASetQuadErrCon, m->mem, true);
343 
344  // Quadrature error tolerances
345  // TODO(Joel): vector absolute tolerances
346  THROWING(IDAQuadSStolerances, m->mem, reltol_, abstol_);
347  }
348  }
349 
350  if (verbose_) casadi_message("Attached linear solver");
351 
352  // Adjoint sensitivity problem
353  if (nadj_ > 0) {
354  m->v_adj_xzdot = N_VNew_Serial(nrx_+nrz_);
355  N_VConst(0.0, m->v_adj_xz);
356  N_VConst(0.0, m->v_adj_xzdot);
357  }
358  if (verbose_) casadi_message("Initialized adjoint sensitivities");
359 
360  // Initialize adjoint sensitivities
361  if (nadj_ > 0) {
362  int interpType = interp_==SD_HERMITE ? IDA_HERMITE : IDA_POLYNOMIAL;
363  THROWING(IDAAdjInit, m->mem, steps_per_checkpoint_, interpType);
364  }
365 
366  m->first_callB = true;
367  return 0;
368 }
369 
370 void IdasInterface::reset(IntegratorMemory* mem, bool first_call) const {
371  if (verbose_) casadi_message(name_ + "::reset");
372  auto m = to_mem(mem);
373 
374  // Reset the base classes
375  SundialsInterface::reset(mem, first_call);
376 
377  // Only reinitialize solver at first call
378  // May want to change this after more testing
379  if (first_call) {
380  // Re-initialize
381  N_VConst(0.0, m->v_xzdot);
382  std::copy(init_xdot_.begin(), init_xdot_.end(), NV_DATA_S(m->v_xzdot));
383 
384  THROWING(IDAReInit, m->mem, m->t, m->v_xz, m->v_xzdot);
385 
386  // Re-initialize quadratures
387  if (nq1_ > 0) THROWING(IDAQuadReInit, m->mem, m->v_q);
388 
389  // Correct initial conditions, if necessary
390  if (calc_ic_) {
391  THROWING(IDACalcIC, m->mem, IDA_YA_YDP_INIT , first_time_);
392  THROWING(IDAGetConsistentIC, m->mem, m->v_xz, m->v_xzdot);
393  }
394 
395  // Re-initialize backward integration
396  if (nadj_ > 0) THROWING(IDAAdjReInit, m->mem);
397  }
398 }
399 
401  auto m = to_mem(mem);
402 
403  // Do not integrate past change in input signals or past the end
404  // The event handling may cause the stop time to become smaller than internal time reached,
405  // in which case the stop time cannot be enforced
406  if (m->t_stop >= m->tcur) {
407  THROWING(IDASetStopTime, m->mem, m->t_stop);
408  }
409 
410  // Integrate, unless already at desired time
411  double ttol = 1e-9; // tolerance
412  if (fabs(m->t - m->t_next) >= ttol) {
413  // Integrate forward ...
414  double tret = m->t;
415  if (nrx_>0) { // ... with taping
416  THROWING(IDASolveF, m->mem, m->t_next, &tret, m->v_xz, m->v_xzdot, IDA_NORMAL, &m->ncheck);
417  } else { // ... without taping
418  THROWING(IDASolve, m->mem, m->t_next, &tret, m->v_xz, m->v_xzdot, IDA_NORMAL);
419  }
420  // Get quadratures
421  if (nq1_ > 0) THROWING(IDAGetQuad, m->mem, &tret, m->v_q);
422  }
423 
424  // Set function outputs
425  casadi_copy(NV_DATA_S(m->v_xz), nx_ + nz_, m->x);
426  casadi_copy(NV_DATA_S(m->v_q), nq_, m->q);
427 
428  // Get stats
429  THROWING(IDAGetIntegratorStats, m->mem, &m->nsteps, &m->nfevals, &m->nlinsetups,
430  &m->netfails, &m->qlast, &m->qcur, &m->hinused, &m->hlast, &m->hcur, &m->tcur);
431  THROWING(IDAGetNonlinSolvStats, m->mem, &m->nniters, &m->nncfails);
432 
433  return 0;
434 }
435 
437  if (verbose_) casadi_message(name_ + "::resetB");
438  auto m = to_mem(mem);
439 
440  // Reset initial guess
441  N_VConst(0.0, m->v_adj_xz);
442 
443  // Reset the base classes
445 
446  // Reset initial guess
447  N_VConst(0.0, m->v_adj_xzdot);
448 }
449 
450 void IdasInterface::z_impulseB(IdasMemory* m, const double* adj_z) const {
451  // Quick return if nothing to propagate
452  if (all_zero(adj_z, nrz_)) return;
453  // We have the following solved nonlinear system of equations:
454  // f_alg(x, z) == 0,
455  // which implicitly defines z as a function of x
456  // Linearize w.r.t. x:
457  // df_alg/dz * dz/dx + df_alg/dx == 0 <=> dz/dx = -inv(df_alg/dz)*df_alg/dx
458  // Want to calculate:
459  // adj_x = (dz/dx)^T * adj_z = -(df_alg/dx)^T * inv((df_alg/dz)^T) * adj_z
460  // = -(df_alg/dx)^T * w,
461  // where
462  // (df_alg/dz)^T * w = adj_z
463  // Augment linear system to get the system we are able to factorize
464  // [(df_ode/dx)^T - cj*I, (df_alg/dx)^T; (df_ode/dz)^T, (df_alg/dz)^T] * [v; w] = [0; adj_z]
465  // (Re)factorize linear system
466  if (psetupF(m->t, m->v_xz, m->v_xzdot, nullptr, m->cj_last, m, nullptr, nullptr, nullptr))
467  casadi_error("Linear system factorization for backwards initial conditions failed");
468  // Right-hand-side for linear system in m->tmp2
469  casadi_clear(m->tmp2, nrx_);
470  casadi_copy(adj_z, nrz_, m->tmp2 + nrx_);
471  // Solve transposed linear system of equations (Note: m->tmp2 not used since rxz null)
472  if (solve_transposed(m, m->t, NV_DATA_S(m->v_xz), nullptr, m->tmp2, m->tmp2)) {
473  casadi_error("Linear system solve for backwards initial conditions failed");
474  }
475  // Calculate: -adj_x = (df_alg/dx)^T * w
476  casadi_clear(m->tmp2, nrx_);
477  if (calc_daeB(m, m->t, NV_DATA_S(m->v_xz), NV_DATA_S(m->v_xz) + nx_,
478  m->tmp2, m->tmp2 + nrx_, nullptr, m->tmp1, m->tmp1 + nrx_)) {
479  casadi_error("Adjoint seed propagation for backwards initial conditions failed");
480  }
481  // Add contribution to backward state
482  casadi_axpy(nrx_, -1., m->tmp1, NV_DATA_S(m->v_adj_xz));
483 }
484 
486  const double* adj_x, const double* adj_z, const double* adj_q) const {
487  auto m = to_mem(mem);
488 
489  // Call method in base class
490  SundialsInterface::impulseB(mem, adj_x, adj_z, adj_q);
491 
492  // Propagate impulse from adj_z to adj_x
493  z_impulseB(m, adj_z);
494 
495  if (m->first_callB) {
496  // Create backward problem
497  THROWING(IDACreateB, m->mem, &m->whichB);
498  THROWING(IDAInitB, m->mem, m->whichB, resB, m->t, m->v_adj_xz, m->v_adj_xzdot);
499  THROWING(IDASStolerancesB, m->mem, m->whichB, reltol_, abstol_);
500  THROWING(IDASetUserDataB, m->mem, m->whichB, m);
501  THROWING(IDASetMaxNumStepsB, m->mem, m->whichB, max_num_steps_);
502 
503 
504  // Set algebraic components
505  N_Vector id = N_VNew_Serial(nrx_+nrz_);
506  std::fill_n(NV_DATA_S(id), nrx_, 1);
507  std::fill_n(NV_DATA_S(id)+nrx_, nrz_, 0);
508  THROWING(IDASetIdB, m->mem, m->whichB, id);
509  N_VDestroy_Serial(id);
510 
511  // attach linear solver
512  if (newton_scheme_==SD_DIRECT) {
513  // Direct scheme
514  IDAMem IDA_mem = IDAMem(m->mem);
515  IDAadjMem IDAADJ_mem = IDA_mem->ida_adj_mem;
516  IDABMem IDAB_mem = IDAADJ_mem->IDAB_mem;
517  IDAB_mem->ida_lmem = m;
518  IDAB_mem->IDA_mem->ida_lmem = m;
519  IDAB_mem->IDA_mem->ida_lsetup = lsetupB;
520  IDAB_mem->IDA_mem->ida_lsolve = lsolveB;
521  IDAB_mem->IDA_mem->ida_setupNonNull = TRUE;
522  } else {
523  // Iterative scheme
524  switch (newton_scheme_) {
525  case SD_DIRECT: casadi_assert_dev(0);
526  case SD_GMRES: THROWING(IDASpgmrB, m->mem, m->whichB, max_krylov_); break;
527  case SD_BCGSTAB: THROWING(IDASpbcgB, m->mem, m->whichB, max_krylov_); break;
528  case SD_TFQMR: THROWING(IDASptfqmrB, m->mem, m->whichB, max_krylov_); break;
529  }
530  THROWING(IDASpilsSetJacTimesVecFnB, m->mem, m->whichB, jtimesB);
531  if (use_precon_) THROWING(IDASpilsSetPreconditionerB, m->mem, m->whichB, psetupB, psolveB);
532  }
533 
534  // Quadratures for the adjoint problem
535  if (nrq_ > 0 || nuq_ > 0) {
536  THROWING(IDAQuadInitB, m->mem, m->whichB, rhsQB, m->v_adj_pu);
537  if (quad_err_con_) {
538  THROWING(IDASetQuadErrConB, m->mem, m->whichB, true);
539  THROWING(IDAQuadSStolerancesB, m->mem, m->whichB, reltol_, abstol_);
540  }
541  }
542 
543  // Mark initialized
544  m->first_callB = false;
545  } else {
546  // Re-initialize
547  THROWING(IDAReInitB, m->mem, m->whichB, m->t, m->v_adj_xz, m->v_adj_xzdot);
548  if (nrq_ > 0 || nuq_ > 0) {
549  // Workaround (bug in SUNDIALS)
550  // THROWING(IDAQuadReInitB, m->mem, m->whichB[dir], m->rq[dir]);
551  void* memB = IDAGetAdjIDABmem(m->mem, m->whichB);
552  THROWING(IDAQuadReInit, memB, m->v_adj_pu);
553  }
554  }
555 
556  // Correct initial values for the integration if necessary
557  if (calc_icB_ && m->k == nt() - 1) {
558  THROWING(IDACalcICB, m->mem, m->whichB, t0_, m->v_xz, m->v_xzdot);
559  THROWING(IDAGetConsistentICB, m->mem, m->whichB, m->v_adj_xz, m->v_adj_xzdot);
560  }
561 }
562 
563 void IdasInterface::retreat(IntegratorMemory* mem, const double* u,
564  double* adj_x, double* adj_p, double* adj_u) const {
565  auto m = to_mem(mem);
566 
567  // Set controls
568  casadi_copy(u, nu_, m->u);
569 
570  // Integrate, unless already at desired time
571  if (m->t_next < m->t) {
572  double tret = m->t;
573  THROWING(IDASolveB, m->mem, m->t_next, IDA_NORMAL);
574  THROWING(IDAGetB, m->mem, m->whichB, &tret, m->v_adj_xz, m->v_adj_xzdot);
575  if (nrq_ > 0 || nuq_ > 0) {
576  THROWING(IDAGetQuadB, m->mem, m->whichB, &tret, m->v_adj_pu);
577  }
578  // Interpolate to get current state
579  THROWING(IDAGetAdjY, m->mem, m->t_next, m->v_xz, m->v_xzdot);
580  }
581 
582  // Save outputs
583  casadi_copy(NV_DATA_S(m->v_adj_xz), nrx_, adj_x);
584  casadi_copy(NV_DATA_S(m->v_adj_pu), nrq_, adj_p);
585  casadi_copy(NV_DATA_S(m->v_adj_pu) + nrq_, nuq_, adj_u);
586 
587  // Get stats
588  IDAMem IDA_mem = IDAMem(m->mem);
589  IDAadjMem IDAADJ_mem = IDA_mem->ida_adj_mem;
590  IDABMem IDAB_mem = IDAADJ_mem->IDAB_mem;
591  THROWING(IDAGetIntegratorStats, IDAB_mem->IDA_mem, &m->nstepsB, &m->nfevalsB,
592  &m->nlinsetupsB, &m->netfailsB, &m->qlastB, &m->qcurB, &m->hinusedB,
593  &m->hlastB, &m->hcurB, &m->tcurB);
594  THROWING(IDAGetNonlinSolvStats, IDAB_mem->IDA_mem, &m->nnitersB, &m->nncfailsB);
595 
596  // Add offset corresponding to counters that were set to zero at reinitializations
597  add_offsets(m);
598 }
599 
600 void IdasInterface::idas_error(const char* module, int flag) {
601  // Successfull return or warning
602  if (flag>=IDA_SUCCESS) return;
603  // Construct error message
604  char* flagname = IDAGetReturnFlagName(flag);
605  std::stringstream ss;
606  ss << module << " returned \"" << flagname << "\". Consult IDAS documentation.";
607  free(flagname); // NOLINT
608  casadi_error(ss.str());
609 }
610 
611 int IdasInterface::rhsQF(double t, N_Vector xz, N_Vector xzdot, N_Vector qdot, void *user_data) {
612  try {
613  auto m = to_mem(user_data);
614  auto& s = m->self;
615  if (s.calc_quadF(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_, NV_DATA_S(qdot))) return 1;
616 
617  return 0;
618  } catch(std::exception& e) { // non-recoverable error
619  uerr() << "rhsQ failed: " << e.what() << std::endl;
620  return -1;
621  }
622 }
623 
624 int IdasInterface::resB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz,
625  N_Vector rxzdot, N_Vector rr, void *user_data) {
626  try {
627  auto m = to_mem(user_data);
628  auto& s = m->self;
629  if (s.calc_daeB(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_,
630  NV_DATA_S(rxz), NV_DATA_S(rxz) + s.nrx_, m->adj_q,
631  NV_DATA_S(rr), NV_DATA_S(rr) + s.nrx_)) return 1;
632 
633  // Subtract state derivative to get residual
634  casadi_axpy(s.nrx_, 1., NV_DATA_S(rxzdot), NV_DATA_S(rr));
635 
636  return 0;
637  } catch(std::exception& e) { // non-recoverable error
638  uerr() << "resB failed: " << e.what() << std::endl;
639  return -1;
640  }
641 }
642 
643 int IdasInterface::rhsQB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz,
644  N_Vector rxzdot, N_Vector ruqdot, void *user_data) {
645  try {
646  auto m = to_mem(user_data);
647  auto& s = m->self;
648  if (s.calc_quadB(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_,
649  NV_DATA_S(rxz), NV_DATA_S(rxz) + s.nrx_,
650  NV_DATA_S(ruqdot), NV_DATA_S(ruqdot) + s.nrq_)) return 1;
651 
652  // Negate (note definition of g)
653  casadi_scal(s.nrq_ + s.nuq_, -1., NV_DATA_S(ruqdot));
654 
655  return 0;
656  } catch(std::exception& e) { // non-recoverable error
657  uerr() << "resQB failed: " << e.what() << std::endl;
658  return -1;
659  }
660 }
661 
662 int IdasInterface::psolveF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr,
663  N_Vector rvec, N_Vector zvec, double cj, double delta, void *user_data, N_Vector tmp) {
664  try {
665  auto m = to_mem(user_data);
666  auto& s = m->self;
667 
668  // Get right-hand sides in m->tmp1, ordered by sensitivity directions
669  double* vx = NV_DATA_S(rvec);
670  double* vz = vx + s.nx_;
671  double* v_it = m->tmp1;
672  for (int d = 0; d <= s.nfwd_; ++d) {
673  casadi_copy(vx + d * s.nx1_, s.nx1_, v_it);
674  v_it += s.nx1_;
675  casadi_copy(vz + d * s.nz1_, s.nz1_, v_it);
676  v_it += s.nz1_;
677  }
678 
679  // Solve for undifferentiated right-hand-side, save to output
680  if (s.linsolF_.solve(m->jacF, m->tmp1, 1, false, m->mem_linsolF))
681  return 1;
682  vx = NV_DATA_S(zvec); // possibly different from rvec
683  vz = vx + s.nx_;
684  casadi_copy(m->tmp1, s.nx1_, vx);
685  casadi_copy(m->tmp1 + s.nx1_, s.nz1_, vz);
686 
687  // Sensitivity equations
688  if (s.nfwd_ > 0) {
689  // Second order correction
690  if (s.second_order_correction_) {
691  // The outputs will double as seeds for jtimesF
692  casadi_clear(vx + s.nx1_, s.nx_ - s.nx1_);
693  casadi_clear(vz + s.nz1_, s.nz_ - s.nz1_);
694  if (s.calc_jtimesF(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_,
695  vx, vz, m->tmp2, m->tmp2 + s.nx_)) return 1;
696 
697  // Subtract m->tmp2 (reordered) from m->tmp1
698  v_it = m->tmp1 + s.nx1_ + s.nz1_;
699  for (int d = 1; d <= s.nfwd_; ++d) {
700  casadi_axpy(s.nx1_, -1., m->tmp2 + d*s.nx1_, v_it);
701  v_it += s.nx1_;
702  casadi_axpy(s.nz1_, -1., m->tmp2 + s.nx_ + d*s.nz1_, v_it);
703  v_it += s.nz1_;
704  }
705  }
706 
707  // Solve for sensitivity right-hand-sides
708  if (s.linsolF_.solve(m->jacF, m->tmp1 + s.nx1_ + s.nz1_, s.nfwd_,
709  false, m->mem_linsolF)) return 1;
710 
711  // Save to output, reordered
712  v_it = m->tmp1 + s.nx1_ + s.nz1_;
713  for (int d = 1; d <= s.nfwd_; ++d) {
714  casadi_copy(v_it, s.nx1_, vx + d * s.nx1_);
715  v_it += s.nx1_;
716  casadi_copy(v_it, s.nz1_, vz + d * s.nz1_);
717  v_it += s.nz1_;
718  }
719  }
720 
721  return 0;
722  } catch(std::exception& e) { // non-recoverable error
723  uerr() << "psolve failed: " << e.what() << std::endl;
724  return -1;
725  }
726 }
727 
728 int IdasInterface::solve_transposed(IdasMemory* m, double t, const double* xz, const double* rxz,
729  const double* rhs, double* sol) const {
730  // Get right-hand sides in m->tmp1, ordered by sensitivity directions
731  double* v_it = m->tmp1;
732  for (int d = 0; d <= nfwd_; ++d) {
733  for (int a = 0; a < nadj_; ++a) {
734  casadi_copy(rhs + (d * nadj_ + a) * nrx1_, nrx1_, v_it);
735  v_it += nrx1_;
736  casadi_copy(rhs + nrx_ + (d * nadj_ + a) * nrz1_, nrz1_, v_it);
737  v_it += nrz1_;
738  }
739  }
740 
741  // Solve for undifferentiated right-hand-side, save to output
742  if (linsolF_.solve(m->jacF, m->tmp1, nadj_, true, m->mem_linsolF)) return 1;
743  for (int a = 0; a < nadj_; ++a) {
744  casadi_copy(m->tmp1 + a * (nrx1_ + nrz1_), nrx1_, sol + a * nrx1_);
745  casadi_copy(m->tmp1 + a * (nrx1_ + nrz1_) + nrx1_, nrz1_, sol + nrx_ + a * nrz1_);
746  }
747 
748  // Sensitivity equations
749  if (nfwd_ > 0) {
750  // Second order correction
751  if (second_order_correction_ && rxz) {
752  // The outputs will double as seeds for calc_daeB
753  casadi_clear(sol + nrx1_ * nadj_, nrx_ - nrx1_ * nadj_);
754  casadi_clear(sol + nrx_ + nrz1_ * nadj_, nrz_ - nrz1_ * nadj_);
755 
756  // Get second-order-correction, save to m->tmp2
757  if (calc_daeB(m, t, xz, xz + nx_, sol, sol + nrx_, nullptr,
758  m->tmp2, m->tmp2 + nrx_)) return 1;
759 
760  // Subtract m->tmp2 (reordered) from m->tmp1
761  v_it = m->tmp1 + (nrx1_ + nrz1_) * nadj_;
762  for (int d = 1; d <= nfwd_; ++d) {
763  for (int a = 0; a < nadj_; ++a) {
764  casadi_axpy(nrx1_, -1., m->tmp2 + nrx1_ * (d * nadj_ + a), v_it);
765  v_it += nrx1_;
766  casadi_axpy(nrz1_, -1., m->tmp2 + nrx_ + nrz1_ * (d * nadj_ + a), v_it);
767  v_it += nrz1_;
768  }
769  }
770  }
771 
772  // Solve for sensitivity right-hand-sides
773  if (linsolF_.solve(m->jacF, m->tmp1 + nrx1_ * nadj_ + nrz1_ * nadj_,
774  nadj_ * nfwd_, true, m->mem_linsolF)) return 1;
775 
776  // Save to output, reordered
777  v_it = m->tmp1 + (nrx1_ + nrz1_) * nadj_;
778  for (int d = 1; d <= nfwd_; ++d) {
779  for (int a = 0; a < nadj_; ++a) {
780  casadi_copy(v_it, nrx1_, sol + nrx1_ * (d * nadj_ + a));
781  v_it += nrx1_;
782  casadi_copy(v_it, nrz1_, sol + nrx_ + nrz1_ * (d * nadj_ + a));
783  v_it += nrz1_;
784  }
785  }
786  }
787 
788  return 0;
789 }
790 
791 int IdasInterface::psolveB(double t, N_Vector xz, N_Vector xzdot, N_Vector xzB,
792  N_Vector xzdotB, N_Vector resvalB, N_Vector rvecB,
793  N_Vector zvecB, double cjB, double deltaB,
794  void *user_data, N_Vector tmpB) {
795  try {
796  auto m = to_mem(user_data);
797  auto& s = m->self;
798  return s.solve_transposed(m, t, NV_DATA_S(xz), NV_DATA_S(xzB),
799  NV_DATA_S(rvecB), NV_DATA_S(zvecB));
800 
801  } catch(std::exception& e) { // non-recoverable error
802  uerr() << "psolveB failed: " << e.what() << std::endl;
803  return -1;
804  }
805 }
806 
807 template<typename T1>
808 void casadi_copy_block(const T1* x, const casadi_int* sp_x, T1* y, const casadi_int* sp_y,
809  casadi_int r_begin, casadi_int c_begin, T1* w) {
810  // x and y should be distinct
811  casadi_int nrow_x, ncol_x, ncol_y, i_x, i_y, j, el, r_end;
812  const casadi_int *colind_x, *row_x, *colind_y, *row_y;
813  nrow_x = sp_x[0];
814  ncol_x = sp_x[1];
815  colind_x = sp_x+2; row_x = sp_x + 2 + ncol_x+1;
816  ncol_y = sp_y[1];
817  colind_y = sp_y+2; row_y = sp_y + 2 + ncol_y+1;
818  // End of the rows to be copied
819  r_end = r_begin + nrow_x;
820  // w will correspond to a column of x, initialize to zero
821  casadi_clear(w, nrow_x);
822  // Loop over columns in x
823  for (i_x = 0; i_x < ncol_x; ++i_x) {
824  // Corresponding row in y
825  i_y = i_x + c_begin;
826  // Copy x entries to w
827  for (el=colind_x[i_x]; el<colind_x[i_x + 1]; ++el) w[row_x[el]] = x[el];
828  // Copy entries to y, if in interval
829  for (el=colind_y[i_y]; el<colind_y[i_y + 1]; ++el) {
830  j = row_y[el];
831  if (j >= r_begin && j < r_end) y[el] = w[j - r_begin];
832  }
833  // Restore w
834  for (el=colind_x[i_x]; el<colind_x[i_x + 1]; ++el) w[row_x[el]] = 0;
835  }
836 }
837 
838 int IdasInterface::psetupF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr,
839  double cj, void* user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3) {
840  try {
841  auto m = to_mem(user_data);
842  auto& s = m->self;
843 
844  // Sparsity patterns
845  const Function& jacF = s.get_function("jacF");
846  const Sparsity& sp_jac_ode_x = jacF.sparsity_out(JACF_ODE_X);
847  const Sparsity& sp_jac_alg_x = jacF.sparsity_out(JACF_ALG_X);
848  const Sparsity& sp_jac_ode_z = jacF.sparsity_out(JACF_ODE_Z);
849  const Sparsity& sp_jac_alg_z = jacF.sparsity_out(JACF_ALG_Z);
850  const Sparsity& sp_jacF = s.linsolF_.sparsity();
851 
852  // Calculate Jacobian blocks
853  if (s.calc_jacF(m, t, NV_DATA_S(xz), NV_DATA_S(xz) + s.nx_,
854  m->jac_ode_x, m->jac_alg_x, m->jac_ode_z, m->jac_alg_z)) return 1;
855 
856  // Copy to jacF structure
857  casadi_int nx_jac = sp_jac_ode_x.size1(); // excludes sensitivity equations
858  casadi_copy_block(m->jac_ode_x, sp_jac_ode_x, m->jacF, sp_jacF, 0, 0, m->w);
859  casadi_copy_block(m->jac_alg_x, sp_jac_alg_x, m->jacF, sp_jacF, nx_jac, 0, m->w);
860  casadi_copy_block(m->jac_ode_z, sp_jac_ode_z, m->jacF, sp_jacF, 0, nx_jac, m->w);
861  casadi_copy_block(m->jac_alg_z, sp_jac_alg_z, m->jacF, sp_jacF, nx_jac, nx_jac, m->w);
862 
863  // Shift diagonal corresponding to jac_ode_x
864  const casadi_int *colind = sp_jacF.colind(), *row = sp_jacF.row();
865  for (casadi_int c = 0; c < nx_jac; ++c) {
866  for (casadi_int k = colind[c]; k < colind[c + 1]; ++k) {
867  if (row[k] == c) m->jacF[k] -= cj;
868  }
869  }
870 
871  // Factorize the linear system
872  if (s.linsolF_.nfact(m->jacF, m->mem_linsolF)) return 1;
873  m->cj_last = cj;
874 
875  return 0;
876  } catch(std::exception& e) { // non-recoverable error
877  uerr() << "psetup failed: " << e.what() << std::endl;
878  return -1;
879  }
880 }
881 
882 int IdasInterface::psetupB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz, N_Vector rxzdot,
883  N_Vector rresval, double cj, void *user_data, N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B) {
884  try {
885  // We use the same linear solver for the forward problem as for the backward problem
886  return psetupF(t, xz, nullptr, nullptr, -cj, user_data, tmp1B, tmp2B, tmp3B);
887 
888  } catch(std::exception& e) { // non-recoverable error
889  uerr() << "psetupB failed: " << e.what() << std::endl;
890  return -1;
891  }
892 }
893 
894 int IdasInterface::lsetupF(IDAMem IDA_mem, N_Vector xz, N_Vector xzdot, N_Vector resp,
895  N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) {
896  // Current time
897  double t = IDA_mem->ida_tn;
898 
899  // Multiple of df_dydot to be added to the matrix
900  double cj = IDA_mem->ida_cj;
901 
902  // Call the preconditioner setup function (which sets up the linear solver)
903  return psetupF(t, xz, xzdot, nullptr, cj, IDA_mem->ida_lmem,
904  vtemp1, vtemp1, vtemp3);
905 }
906 
907 int IdasInterface::lsetupB(IDAMem IDA_mem, N_Vector xzB, N_Vector xzdotB, N_Vector respB,
908  N_Vector vtemp1B, N_Vector vtemp2B, N_Vector vtemp3B) {
909  try {
910  auto m = to_mem(IDA_mem->ida_lmem);
911  //auto& s = m->self;
912  IDAadjMem IDAADJ_mem;
913  //IDABMem IDAB_mem;
914 
915  // Current time
916  double t = IDA_mem->ida_tn; // TODO(Joel): is this correct?
917  // Multiple of df_dydot to be added to the matrix
918  double cj = IDA_mem->ida_cj;
919 
920  IDA_mem = static_cast<IDAMem>(IDA_mem->ida_user_data);
921 
922  IDAADJ_mem = IDA_mem->ida_adj_mem;
923  //IDAB_mem = IDAADJ_mem->ia_bckpbCrt;
924 
925  // Get FORWARD solution from interpolation.
926  if (IDAADJ_mem->ia_noInterp==FALSE) {
927  int flag = IDAADJ_mem->ia_getY(IDA_mem, t, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp,
928  nullptr, nullptr);
929  if (flag != IDA_SUCCESS) casadi_error("Could not interpolate forward states");
930  }
931  // Call the preconditioner setup function (which sets up the linear solver)
932  return psetupB(t, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp,
933  xzB, xzdotB, nullptr, cj, static_cast<void*>(m), vtemp1B, vtemp1B, vtemp3B);
934 
935  } catch(std::exception& e) { // non-recoverable error
936  uerr() << "lsetupB failed: " << e.what() << std::endl;
937  return -1;
938  }
939 }
940 
941 int IdasInterface::lsolveF(IDAMem IDA_mem, N_Vector b, N_Vector weight, N_Vector xz,
942  N_Vector xzdot, N_Vector rr) {
943  try {
944  auto m = to_mem(IDA_mem->ida_lmem);
945  auto& s = m->self;
946 
947  // Current time
948  double t = IDA_mem->ida_tn;
949 
950  // Multiple of df_dydot to be added to the matrix
951  double cj = IDA_mem->ida_cj;
952 
953  // Accuracy
954  double delta = 0.0;
955 
956  // Call the preconditioner solve function (which solves the linear system)
957  int flag = psolveF(t, xz, xzdot, rr, b, b, cj,
958  delta, static_cast<void*>(m), nullptr);
959  if (flag) return flag;
960 
961  // Scale the correction to account for change in cj
962  if (s.cj_scaling_) {
963  double cjratio = IDA_mem->ida_cjratio;
964  if (cjratio != 1.0) N_VScale(2.0/(1.0 + cjratio), b, b);
965  }
966 
967  return 0;
968  } catch(std::exception& e) { // non-recoverable error
969  uerr() << "lsolve failed: " << e.what() << std::endl;
970  return -1;
971  }
972 }
973 
974 int IdasInterface::lsolveB(IDAMem IDA_mem, N_Vector b, N_Vector weight, N_Vector xzB,
975  N_Vector xzdotB, N_Vector rrB) {
976  try {
977  auto m = to_mem(IDA_mem->ida_lmem);
978  auto& s = m->self;
979  IDAadjMem IDAADJ_mem;
980  //IDABMem IDAB_mem;
981  int flag;
982 
983  // Current time
984  double t = IDA_mem->ida_tn; // TODO(Joel): is this correct?
985  // Multiple of df_dydot to be added to the matrix
986  double cj = IDA_mem->ida_cj;
987  double cjratio = IDA_mem->ida_cjratio;
988 
989  IDA_mem = (IDAMem) IDA_mem->ida_user_data;
990  IDAADJ_mem = IDA_mem->ida_adj_mem;
991  //IDAB_mem = IDAADJ_mem->ia_bckpbCrt;
992 
993  // Get FORWARD solution from interpolation.
994  if (IDAADJ_mem->ia_noInterp==FALSE) {
995  flag = IDAADJ_mem->ia_getY(IDA_mem, t, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp,
996  nullptr, nullptr);
997  if (flag != IDA_SUCCESS) casadi_error("Could not interpolate forward states");
998  }
999 
1000  // Accuracy
1001  double delta = 0.0;
1002 
1003  // Call the preconditioner solve function (which solves the linear system)
1004  flag = psolveB(t, IDAADJ_mem->ia_yyTmp, IDAADJ_mem->ia_ypTmp, xzB, xzdotB,
1005  rrB, b, b, cj, delta, static_cast<void*>(m), nullptr);
1006  if (flag) return flag;
1007 
1008  // Scale the correction to account for change in cj
1009  if (s.cj_scaling_) {
1010  if (cjratio != 1.0) N_VScale(2.0/(1.0 + cjratio), b, b);
1011  }
1012  return 0;
1013  } catch(std::exception& e) { // non-recoverable error
1014  uerr() << "lsolveB failed: " << e.what() << std::endl;
1015  return -1;
1016  }
1017 }
1018 
1020  this->mem = nullptr;
1021  this->v_xzdot = nullptr;
1022  this->v_adj_xzdot = nullptr;
1023  this->cj_last = nan;
1024 
1025  // Reset checkpoints counter
1026  this->ncheck = 0;
1027 }
1028 
1030  if (this->mem) IDAFree(&this->mem);
1031  if (this->v_xzdot) N_VDestroy_Serial(this->v_xzdot);
1032  if (this->v_adj_xzdot) N_VDestroy_Serial(this->v_adj_xzdot);
1033  if (this->mem_linsolF >= 0) self.linsolF_.release(this->mem_linsolF);
1034 }
1035 
1037  int version = s.version("IdasInterface", 1, 2);
1038  s.unpack("IdasInterface::cj_scaling", cj_scaling_);
1039  s.unpack("IdasInterface::calc_ic", calc_ic_);
1040  s.unpack("IdasInterface::calc_icB", calc_icB_);
1041  s.unpack("IdasInterface::suppress_algebraic", suppress_algebraic_);
1042  s.unpack("IdasInterface::abstolv", abstolv_);
1043  s.unpack("IdasInterface::first_time", first_time_);
1044  s.unpack("IdasInterface::init_xdot", init_xdot_);
1045 
1046  if (version>=2) {
1047  s.unpack("IdasInterface::max_step_size", max_step_size_);
1048  s.unpack("IdasInterface::y_c", y_c_);
1049  } else {
1050  max_step_size_ = 0;
1051  }
1052 }
1053 
1056  s.version("IdasInterface", 2);
1057  s.pack("IdasInterface::cj_scaling", cj_scaling_);
1058  s.pack("IdasInterface::calc_ic", calc_ic_);
1059  s.pack("IdasInterface::calc_icB", calc_icB_);
1060  s.pack("IdasInterface::suppress_algebraic", suppress_algebraic_);
1061  s.pack("IdasInterface::abstolv", abstolv_);
1062  s.pack("IdasInterface::first_time", first_time_);
1063  s.pack("IdasInterface::init_xdot", init_xdot_);
1064  s.pack("IdasInterface::max_step_size", max_step_size_);
1065  s.pack("IdasInterface::y_c", y_c_);
1066 }
1067 
1068 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
Function object.
Definition: function.hpp:60
std::vector< std::string > get_function() const
Get a list of all functions.
Definition: function.cpp:2041
const Sparsity & sparsity_out(casadi_int ind) const
Get sparsity of a given output.
Definition: function.cpp:1183
'idas' plugin for Integrator
static int rhsQF(double t, N_Vector xz, N_Vector xzdot, N_Vector qdot, void *user_data)
static int jtimesB(double t, N_Vector xz, N_Vector xzdot, N_Vector xzB, N_Vector xzdotB, N_Vector resvalB, N_Vector vB, N_Vector JvB, double cjB, void *user_data, N_Vector tmp1B, N_Vector tmp2B)
int init_mem(void *mem) const override
Initalize memory block.
static int resF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr, void *user_data)
void retreat(IntegratorMemory *mem, const double *u, double *adj_x, double *adj_p, double *adj_u) const override
Retreat solution in time.
void resetB(IntegratorMemory *mem) const override
Reset the backward problem and take time to tf.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
int solve_transposed(IdasMemory *m, double t, const double *xz, const double *rxz, const double *rhs, double *sol) const
Solve transposed linear system.
void impulseB(IntegratorMemory *mem, const double *adj_x, const double *adj_z, const double *adj_q) const override
Introduce an impulse into the backwards integration at the current time.
static void idas_error(const char *module, int flag)
std::vector< double > init_xdot_
static int psetupB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz, N_Vector rxzdot, N_Vector resvalB, double cjB, void *user_dataB, N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B)
static int lsolveB(IDAMem IDA_mem, N_Vector b, N_Vector weight, N_Vector ycur, N_Vector xzdotcur, N_Vector rescur)
static int lsetupF(IDAMem IDA_mem, N_Vector xz, N_Vector xzdot, N_Vector resp, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
static const std::string meta_doc
A documentation string.
static int lsolveF(IDAMem IDA_mem, N_Vector b, N_Vector weight, N_Vector ycur, N_Vector xzdotcur, N_Vector rescur)
static int resB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz, N_Vector rxzdot, N_Vector rr, void *user_data)
IdasInterface(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Constructor.
static int rhsQB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz, N_Vector rxzdot, N_Vector ruqdot, void *user_data)
std::vector< double > abstolv_
static const Options options_
Options.
void reset(IntegratorMemory *mem, bool first_call) const override
Reset the forward solver at the start or after an event.
static int psolveF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr, N_Vector rvec, N_Vector zvec, double cj, double delta, void *user_data, N_Vector tmp)
static Integrator * creator(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Create a new integrator.
void init(const Dict &opts) override
Initialize.
static int psetupF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr, double cj, void *user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
static void ehfun(int error_code, const char *module, const char *function, char *msg, void *eh_data)
~IdasInterface() override
Destructor.
static int lsetupB(IDAMem IDA_mem, N_Vector xz, N_Vector xzdot, N_Vector resp, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
static IdasMemory * to_mem(void *mem)
Cast to memory object.
static int psolveB(double t, N_Vector xz, N_Vector xzdot, N_Vector rxz, N_Vector rxzdot, N_Vector resvalB, N_Vector rvecB, N_Vector zvecB, double cjB, double deltaB, void *user_dataB, N_Vector tmpB)
void z_impulseB(IdasMemory *m, const double *adj_z) const
Propagate impulse from adj_z to adj_x.
std::vector< casadi_int > y_c_
int advance_noevent(IntegratorMemory *mem) const override
Advance solution in time.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
static int jtimesF(double t, N_Vector xz, N_Vector xzdot, N_Vector rr, N_Vector v, N_Vector Jv, double cj, void *user_data, N_Vector tmp1, N_Vector tmp2)
casadi_int nfwd_
Number of sensitivities.
casadi_int nrx_
Number of states for the backward integration.
casadi_int nt() const
Number of output times.
Dict opts_
Copy of the options.
static bool all_zero(const double *v, casadi_int n)
Helper function: Vector has only zeros?
std::vector< double > tout_
Output time grid.
double t0_
Initial time.
casadi_int nu_
Number of controls.
casadi_int nx_
Number of states for the forward integration.
DM solve(const DM &A, const DM &B, bool tr=false) const
Definition: linsol.cpp:73
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
General sparsity class.
Definition: sparsity.hpp:106
casadi_int size1() const
Get the number of rows.
Definition: sparsity.cpp:124
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:164
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:168
Linsol linsolF_
Linear solver.
enum casadi::SundialsInterface::InterpType interp_
void impulseB(IntegratorMemory *mem, const double *adj_x, const double *adj_z, const double *adj_q) const override
Introduce an impulse into the backwards integration at the current time.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
enum casadi::SundialsInterface::NewtonScheme newton_scheme_
void reset(IntegratorMemory *mem, bool first_call) const override
Reset the forward solver at the start or after an event.
int init_mem(void *mem) const override
Initalize memory block.
void add_offsets(SundialsMemory *m) const
Add stats offsets to stats.
void init(const Dict &opts) override
Initialize.
void resetB(IntegratorMemory *mem) const override
Reset the backward problem and take time to tf.
int calc_daeB(SundialsMemory *m, double t, const double *x, const double *z, const double *adj_ode, const double *adj_alg, const double *adj_quad, double *adj_x, double *adj_z) const
static const Options options_
Options.
The casadi namespace.
Definition: archiver.cpp:28
int CASADI_INTEGRATOR_IDAS_EXPORT casadi_register_integrator_idas(Integrator::Plugin *plugin)
std::ostream & uerr()
void CASADI_INTEGRATOR_IDAS_EXPORT casadi_load_integrator_idas()
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
@ OT_INTVECTOR
@ OT_DOUBLEVECTOR
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void casadi_copy_block(const T1 *x, const casadi_int *sp_x, T1 *y, const casadi_int *sp_y, casadi_int r_begin, casadi_int c_begin, T1 *w)
const double nan
Not a number.
Definition: calculus.hpp:53
void casadi_scal(casadi_int n, T1 alpha, T1 *x)
SCAL: x <- alpha*x.
void casadi_axpy(casadi_int n, T1 alpha, const T1 *x, T1 *y)
AXPY: y <- a*x + y.
void casadi_clear(T1 *x, casadi_int n)
CLEAR: x <- 0.
void * mem
Idas memory block.
~IdasMemory()
Destructor.
double cj_last
cj used in the last factorization
IdasMemory(const IdasInterface &s)
Constructor.
Options metadata for a class.
Definition: options.hpp:40
int mem_linsolF
Linear solver memory objects.
int ncheck
number of checkpoints stored so far