26 #include "kinsol_interface.hpp"
31 int CASADI_ROOTFINDER_KINSOL_EXPORT
34 plugin->name =
"kinsol";
36 plugin->version = CASADI_VERSION;
93 "Maximum number of Newton iterations. Putting 0 sets the default value of KinSol."}},
99 "Stopping criterion tolerance"}},
100 {
"linear_solver_type",
102 "dense|banded|iterative|user_defined"}},
105 "Upper bandwidth for banded linear solvers"}},
108 "Lower bandwidth for banded linear solvers"}},
111 "Maximum Krylov space dimension"}},
114 "Use exact Jacobian information"}},
117 "gmres|bcgstab|tfqmr"}},
120 "Equation scaling factors"}},
123 "Variable scaling factors"}},
126 "Type of preconditioner"}},
127 {
"use_preconditioner",
129 "Precondition an iterative solver"}},
132 "Globalization strategy"}},
133 {
"disable_internal_warnings",
135 "Disable KINSOL internal warning messages"}}
144 std::string strategy =
"none";
145 std::vector<double> u_scale;
146 std::vector<double> f_scale;
147 std::string linear_solver_type =
"dense";
148 std::string iterative_solver =
"gmres";
151 for (
auto&& op : opts) {
152 if (op.first==
"strategy") {
153 strategy = op.second.to_string();
154 }
else if (op.first==
"exact_jacobian") {
156 }
else if (op.first==
"u_scale") {
158 }
else if (op.first==
"f_scale") {
160 }
else if (op.first==
"disable_internal_warnings") {
162 }
else if (op.first==
"max_iter") {
164 }
else if (op.first==
"print_level") {
166 }
else if (op.first==
"linear_solver_type") {
167 linear_solver_type = op.second.to_string();
168 }
else if (op.first==
"max_krylov") {
170 }
else if (op.first==
"upper_bandwidth") {
172 }
else if (op.first==
"lower_bandwidth") {
174 }
else if (op.first==
"iterative_solver") {
175 iterative_solver = op.second.to_string();
176 }
else if (op.first==
"use_preconditioner") {
178 }
else if (op.first==
"abstol") {
184 if (strategy==
"linesearch") {
187 casadi_assert_dev(strategy==
"none");
198 if (!u_scale.empty()) {
199 casadi_assert_dev(u_scale.size()==NV_LENGTH_S(
u_scale_));
200 std::copy(u_scale.begin(), u_scale.end(), NV_DATA_S(
u_scale_));
206 if (!f_scale.empty()) {
207 casadi_assert_dev(f_scale.size()==NV_LENGTH_S(
f_scale_));
208 std::copy(f_scale.begin(), f_scale.end(), NV_DATA_S(
f_scale_));
214 if (linear_solver_type==
"dense") {
220 }
else if (linear_solver_type==
"banded") {
228 }
else if (linear_solver_type==
"iterative") {
230 if (iterative_solver==
"gmres") {
232 }
else if (iterative_solver==
"bcgstab") {
234 }
else if (iterative_solver==
"tfqmr") {
237 casadi_error(
"KINSOL: Unknown sparse solver");
242 }
else if (linear_solver_type==
"user_defined") {
251 casadi_error(
"Unknown linear solver");
256 casadi_int*& iw,
double*& w)
const {
278 m->success = flag>= KIN_SUCCESS;
284 if (flag!=KIN_SUCCESS)
kinsol_error(
"KINSol", flag,
false);
293 std::copy_n(m->iarg,
n_in_, m->arg);
294 m->arg[
iin_] = NV_DATA_S(m->u);
295 std::copy_n(m->ires,
n_out_, m->res);
296 m->res[
iout_] =
nullptr;
297 oracle_(m->arg, m->res, m->iw, m->w, 0);
304 const double *u_data = NV_DATA_S(u);
305 double *f_data = NV_DATA_S(fval);
315 for (
int k=0; k<
n_; ++k) {
317 casadi_assert(!isnan(f_data[k]),
318 "Nonzero " +
str(k) +
" is not-a-number");
319 casadi_assert(!isinf(f_data[k]),
320 "Nonzero " +
str(k) +
" is infinite");
321 }
catch(std::exception& ex) {
322 std::stringstream ss;
323 ss << ex.what() << std::endl;
325 uout() <<
"u = " << std::vector<double>(u_data, u_data +
n_) << std::endl;
326 uout() <<
"f = " << std::vector<double>(f_data, f_data +
n_) << std::endl;
335 casadi_assert_dev(user_data);
339 }
catch(std::exception& e) {
340 uerr() <<
"func failed: " << e.what() << std::endl;
346 void *user_data, N_Vector tmp1, N_Vector tmp2) {
348 casadi_assert_dev(user_data);
350 this_->
self.
djac(*this_, N, u, fu, J, tmp1, tmp2);
352 }
catch(std::exception& e) {
353 uerr() <<
"djac failed: " << e.what() << std::endl;;
359 N_Vector tmp1, N_Vector tmp2)
const {
373 for (casadi_int cc=0; cc<ncol; ++cc) {
375 for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
377 casadi_int rr = row[el];
380 DENSE_ELEM(J, rr, cc) = m.
jac[el];
386 N_Vector fu, DlsMat J,
void *user_data,
387 N_Vector tmp1, N_Vector tmp2) {
389 casadi_assert_dev(user_data);
391 this_->
self.
bjac(*this_, N, mupper, mlower, u, fu, J, tmp1, tmp2);
393 }
catch(std::exception& e) {
394 uerr() <<
"bjac failed: " << e.what() << std::endl;;
400 N_Vector fu, DlsMat J, N_Vector tmp1, N_Vector tmp2)
const {
414 for (casadi_int cc=0; cc<ncol; ++cc) {
416 for (casadi_int el=colind[cc]; el<colind[cc+1]; ++el) {
418 casadi_int rr = row[el];
421 if (rr-cc>=-mupper && rr-cc<=mlower) {
422 BAND_ELEM(J, rr, cc) = m.
jac[el];
431 casadi_assert_dev(user_data);
435 }
catch(std::exception& e) {
436 uerr() <<
"jtimes failed: " << e.what() << std::endl;;
442 N_Vector u,
int* new_u)
const {
447 m.
res[0] = NV_DATA_S(Jv);
452 psetup_wrapper(N_Vector u, N_Vector uscale, N_Vector fval, N_Vector fscale,
453 void* user_data, N_Vector tmp1, N_Vector tmp2) {
455 casadi_assert_dev(user_data);
457 this_->
self.
psetup(*this_, u, uscale, fval, fscale, tmp1, tmp2);
459 }
catch(std::exception& e) {
460 uerr() <<
"psetup failed: " << e.what() << std::endl;;
467 N_Vector fscale, N_Vector tmp1, N_Vector tmp2)
const {
473 if (
calc_function(&m,
"jac_g_x")) casadi_error(
"Jacobian calculation failed");
485 N_Vector fscale, N_Vector v,
void* user_data, N_Vector tmp) {
487 casadi_assert_dev(user_data);
489 this_->
self.
psolve(*this_, u, uscale, fval, fscale, v, tmp);
491 }
catch(std::exception& e) {
492 uerr() <<
"psolve failed: " << e.what() << std::endl;;
498 N_Vector fscale, N_Vector v, N_Vector tmp)
const {
500 if (
linsol_.
solve(m.
jac, NV_DATA_S(v))) casadi_error(
"'solve' failed");
505 auto m =
to_mem(kin_mem->kin_lmem);
508 N_Vector u = kin_mem->kin_uu;
509 N_Vector uscale = kin_mem->kin_uscale;
510 N_Vector fval = kin_mem->kin_fval;
511 N_Vector fscale = kin_mem->kin_fscale;
512 N_Vector tmp1 = kin_mem->kin_vtemp1;
513 N_Vector tmp2 = kin_mem->kin_vtemp2;
514 s.psetup(*m, u, uscale, fval, fscale, tmp1, tmp2);
517 }
catch(std::exception& e) {
518 uerr() <<
"lsetup failed: " << e.what() << std::endl;;
524 lsolve(KINMem kin_mem, N_Vector x, N_Vector b,
double *sJpnorm,
double *sFdotJp) {
526 auto m =
to_mem(kin_mem->kin_lmem);
530 N_Vector u = kin_mem->kin_uu;
531 N_Vector uscale = kin_mem->kin_uscale;
532 N_Vector fval = kin_mem->kin_fval;
533 N_Vector fscale = kin_mem->kin_fscale;
534 N_Vector tmp1 = kin_mem->kin_vtemp1;
539 s.psolve(*m, u, uscale, fval, fscale, x, tmp1);
542 int flag = KINSpilsAtimes(kin_mem, x, b);
543 if (flag)
return flag;
544 *sJpnorm = N_VWL2Norm(b, fscale);
545 N_VProd(b, fscale, b);
546 N_VProd(b, fscale, b);
547 *sFdotJp = N_VDotProd(fval, b);
550 }
catch(std::exception& e) {
551 uerr() <<
"lsolve failed: " << e.what() << std::endl;;
557 char *msg,
void *eh_data) {
561 if (!s.disable_internal_warnings_) {
562 uerr() << msg << std::endl;
564 }
catch(std::exception& e) {
565 uerr() <<
"ehfun failed: " << e.what() << std::endl;
573 uout() <<
"[" << module <<
"] " <<
function <<
"\n " << msg << std::endl;
574 }
catch(std::exception& e) {
575 uout() <<
"ihfun failed: " << e.what() << std::endl;
581 const char *id, *msg;
585 msg =
"KINSol succeeded; the scaled norm of F(u) is less than fnormtol";
587 case KIN_INITIAL_GUESS_OK:
588 id =
"KIN_INITIAL_GUESS_OK";
589 msg =
"The guess u = u0 satisfied the system F(u) = 0 within the tolerances specified.";
591 case KIN_STEP_LT_STPTOL:
592 id =
"KIN_STEP_LT_STPTOL";
593 msg =
"KINSol stopped based on scaled step length. This "
594 "means that the current iterate may be an approximate solution of the "
595 "given nonlinear system, but it is also quite possible that the algorithm"
596 " is 'stalled' (making insufficient progress) near an invalid solution, "
597 "or that the scalar scsteptol is too large.";
601 msg =
"The kinsol memory block pointer was NULL.";
604 id =
"KIN_ILL_INPUT";
605 msg =
"An input parameter was invalid.";
608 id =
"KIN_NO_MALLOC";
609 msg =
"The kinsol memory was not allocated by a call to KINCreate.";
611 case KIN_LINESEARCH_NONCONV:
612 id =
"KIN_LINESEARCH_NONCONV";
613 msg =
"The line search algorithm was unable to find "
614 "an iterate sufficiently distinct from the current iterate, or could not"
615 " find an iterate satisfying the sufficient decrease condition. Failure"
616 " to satisfy the sufficient decrease condition could mean the current "
617 "iterate is 'close' to an approximate solution of the given nonlinear "
618 "system, the difference approximation of the matrix-vector product J(u)v"
619 " is inaccurate, or the real scalar scsteptol is too large.";
621 case KIN_MAXITER_REACHED:
622 id =
"KIN_MAXITER_REACHED";
623 msg =
"The maximum number of nonlinear iterations "
626 case KIN_MXNEWT_5X_EXCEEDED:
627 id =
"KIN_MXNEWT_5X_EXCEEDED";
628 msg =
"Five consecutive steps have been taken that "
629 "satisfy the inequality || D_u p ||_L2 > 0.99 mxnewtstep, where p "
630 "denotes the current step and mxnewtstep is a scalar upper bound on the "
631 "scaled step length. Such a failure may mean that || D_F F(u)||_L2 "
632 "asymptotes from above to a positive value, or the real scalar "
633 "mxnewtstep is too small.";
635 case KIN_LINESEARCH_BCFAIL:
636 id =
"KIN_LINESEARCH_BCFAIL";
637 msg =
"The line search algorithm was unable to satisfy "
638 "the “beta-condition” for MXNBCF +1 nonlinear iterations (not necessarily "
639 "consecutive), which may indicate the algorithm is making poor progress.";
641 case KIN_LINSOLV_NO_RECOVERY:
642 id =
"KIN_LINSOLV_NO_RECOVERY";
643 msg =
"The user-supplied routine psolve encountered a"
644 " recoverable error, but the preconditioner is already current.";
647 id =
"KIN_LINIT_FAIL";
648 msg =
"The linear solver initialization routine (linit) encountered an error.";
650 case KIN_LSETUP_FAIL:
651 id =
"KIN_LSETUP_FAIL";
652 msg =
"The user-supplied routine pset (used to set up the "
653 "preconditioner data) encountered an unrecoverable error.";
655 case KIN_LSOLVE_FAIL:
656 id =
"KIN_LSOLVE_FAIL";
657 msg =
"Either the user-supplied routine psolve "
658 "(used to to solve the preconditioned linear system) encountered an "
659 "unrecoverable error, or the linear solver routine (lsolve) "
660 "encountered an error condition.";
662 case KIN_SYSFUNC_FAIL:
663 id =
"KIN_SYSFUNC_FAIL";
664 msg =
"The system function failed in an unrecoverable manner.";
666 case KIN_FIRST_SYSFUNC_ERR:
667 id =
"KIN_FIRST_SYSFUNC_ERR";
668 msg =
"The system function failed recoverably at the first call.";
670 case KIN_REPTD_SYSFUNC_ERR:
671 id =
"KIN_REPTD_SYSFUNC_ERR";
672 msg =
"The system function had repeated recoverable errors. "
673 "No recovery is possible.";
681 std::stringstream ss;
683 ss <<
"Unknown " << (fatal?
"error" :
"warning") <<
" (" << flag <<
")"
684 " from module \"" << module <<
"\".";
686 ss <<
"Module \"" << module <<
"\" returned flag \"" <<
id <<
"\"." << std::endl;
687 ss <<
"The description of this flag is: " << std::endl;
688 ss <<
"\"" << msg <<
"\"" << std::endl;
690 ss <<
"Consult KINSOL documentation for more information.";
692 casadi_error(
"nlpsol process failed. "
693 "Set 'error_on_fail' option to false to ignore this error. "
696 casadi_warning(ss.str());
706 if (this->
u) N_VDestroy_Serial(this->
u);
707 if (this->
mem) KINFree(&this->
mem);
715 m->
u = N_VNew_Serial(
n_);
718 m->mem = KINCreate();
721 KINMem kin_mem = KINMem(m->mem);
722 kin_mem->kin_inexact_ls = FALSE;
725 int flag = KINSetUserData(m->mem, m);
726 casadi_assert(flag==KIN_SUCCESS,
"KINSetUserData");
729 flag = KINSetErrHandlerFn(m->mem,
ehfun, m);
730 casadi_assert(flag==KIN_SUCCESS,
"KINSetErrHandlerFn");
733 flag = KINSetInfoHandlerFn(m->mem,
ihfun, m);
734 casadi_assert(flag==KIN_SUCCESS,
"KINSetInfoHandlerFn");
738 casadi_assert(flag==KIN_SUCCESS,
"KINSetPrintLevel");
742 casadi_assert_dev(flag==KIN_SUCCESS);
745 flag = KINSetMaxNewtonStep(m->mem,
max_iter_);
746 casadi_assert_dev(flag==KIN_SUCCESS);
750 N_Vector domain = N_VNew_Serial(
n_);
751 std::copy(
u_c_.begin(),
u_c_.end(), NV_DATA_S(domain));
754 flag = KINSetConstraints(m->mem, domain);
755 casadi_assert_dev(flag==KIN_SUCCESS);
758 N_VDestroy_Serial(domain);
764 flag = KINDense(m->mem,
n_);
765 casadi_assert(flag==KIN_SUCCESS,
"KINDense");
769 casadi_assert(flag==KIN_SUCCESS,
"KINDlsSetDenseJacFn");
775 casadi_assert(flag==KIN_SUCCESS,
"KINBand");
779 casadi_assert(flag==KIN_SUCCESS,
"KINDlsBandJacFn");
786 flag = KINSpgmr(m->mem,
maxl_);
787 casadi_assert(flag==KIN_SUCCESS,
"KINSpgmr");
790 flag = KINSpbcg(m->mem,
maxl_);
791 casadi_assert(flag==KIN_SUCCESS,
"KINSpbcg");
794 flag = KINSptfqmr(m->mem,
maxl_);
795 casadi_assert(flag==KIN_SUCCESS,
"KINSptfqmr");
802 casadi_assert(flag==KIN_SUCCESS,
"KINSpilsSetJacTimesVecFn");
808 casadi_assert_dev(flag==KIN_SUCCESS);
813 KINMem kin_mem = KINMem(m->mem);
814 kin_mem->kin_lmem = m;
815 kin_mem->kin_lsetup =
lsetup;
816 kin_mem->kin_lsolve =
lsolve;
817 kin_mem->kin_setupNonNull = TRUE;
822 flag = KINSetFuncNormTol(m->mem,
abstol_);
823 casadi_assert_dev(flag==KIN_SUCCESS);
size_t n_in_
Number of inputs and outputs.
casadi_int nnz_in() const
Number of input/output nonzeros.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
casadi_int nnz_out() const
Number of input/output nonzeros.
void alloc(const Function &f, bool persistent=false, int num_threads=1)
Ensure work vectors long enough to evaluate function.
const std::vector< std::string > & name_in() const
Get input scheme.
Function factory(const std::string &name, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const AuxOut &aux=AuxOut(), const Dict &opts=Dict()) const
const std::vector< std::string > & name_out() const
Get output scheme.
'kinsol' plugin for Rootfinder
void func(KinsolMemory &m, N_Vector u, N_Vector fval) const
Callback functions (to be updated)
void bjac(KinsolMemory &m, long N, long mupper, long mlower, N_Vector u, N_Vector fu, DlsMat J, N_Vector tmp1, N_Vector tmp2) const
static const std::string meta_doc
A documentation string.
static const Options options_
Options.
static KinsolMemory * to_mem(void *mem)
Cast to memory object.
void jtimes(KinsolMemory &m, N_Vector v, N_Vector Jv, N_Vector u, int *new_u) const
static int psolve_wrapper(N_Vector u, N_Vector uscale, N_Vector fval, N_Vector fscale, N_Vector v, void *user_data, N_Vector tmp)
int init_mem(void *mem) const override
Initalize memory block.
LinsolType linear_solver_type_
casadi_int strategy_
Globalization strategy.
static Rootfinder * creator(const std::string &name, const Function &f)
Create a new Rootfinder.
static void ehfun(int error_code, const char *module, const char *function, char *msg, void *eh_data)
static int jtimes_wrapper(N_Vector v, N_Vector Jv, N_Vector u, int *new_u, void *user_data)
void psolve(KinsolMemory &m, N_Vector u, N_Vector uscale, N_Vector fval, N_Vector fscale, N_Vector v, N_Vector tmp) const
IterativeSolver iterative_solver_
static void ihfun(const char *module, const char *function, char *msg, void *ih_data)
static int func_wrapper(N_Vector u, N_Vector fval, void *user_data)
Wrappers to callback functions.
static int djac_wrapper(long N, N_Vector u, N_Vector fu, DlsMat J, void *user_data, N_Vector tmp1, N_Vector tmp2)
void kinsol_error(const std::string &module, int flag, bool fatal=true) const
void psetup(KinsolMemory &m, N_Vector u, N_Vector uscale, N_Vector fval, N_Vector fscale, N_Vector tmp1, N_Vector tmp2) const
~KinsolInterface() override
Destructor.
int solve(void *mem) const override
Solve the system of equations and calculate derivatives.
KinsolInterface(const std::string &name, const Function &f)
Constructor.
static int lsetup(KINMem kin_mem)
Callback functions (updated)
casadi_int lower_bandwidth_
bool disable_internal_warnings_
void init(const Dict &opts) override
Initialize stage.
static int psetup_wrapper(N_Vector u, N_Vector uscale, N_Vector fval, N_Vector fscale, void *user_data, N_Vector tmp1, N_Vector tmp2)
static int bjac_wrapper(long N, long mupper, long mlower, N_Vector u, N_Vector fu, DlsMat J, void *user_data, N_Vector tmp1, N_Vector tmp2)
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
void djac(KinsolMemory &m, long N, N_Vector u, N_Vector fu, DlsMat J, N_Vector tmp1, N_Vector tmp2) const
casadi_int upper_bandwidth_
static int lsolve(KINMem kin_mem, N_Vector x, N_Vector b, double *sJpnorm, double *sFdotJp)
void nfact(const DM &A) const
Numeric factorization of the linear system.
DM solve(const DM &A, const DM &B, bool tr=false) const
Function oracle_
Oracle: Used to generate other functions.
int calc_function(OracleMemory *m, const std::string &fcn, const double *const *arg=nullptr, int thread_id=0) const
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool error_on_fail_
Throw an exception on failure?
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
int init_mem(void *mem) const override
Initalize memory block.
casadi_int n_
Number of equations.
std::vector< casadi_int > u_c_
Constraints on decision variables.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
casadi_int iin_
Indices of the input and output that correspond to the actual root-finding.
static const Options options_
Options.
Linsol linsol_
Linear solver.
void init(const Dict &opts) override
Initialize.
casadi_int nnz() const
Get the number of (structural) non-zeros.
casadi_int size2() const
Get the number of columns.
const casadi_int * row() const
Get a reference to row-vector,.
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
void CASADI_ROOTFINDER_KINSOL_EXPORT casadi_load_rootfinder_kinsol()
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
int CASADI_ROOTFINDER_KINSOL_EXPORT casadi_register_rootfinder_kinsol(Rootfinder::Plugin *plugin)
void * mem
KINSOL memory block.
~KinsolMemory()
Destructor.
KinsolMemory(const KinsolInterface &s)
Constructor.
const KinsolInterface & self
Function object.
Options metadata for a class.