sandbox/ecipriano/src/fsolve-gsl.h
Non-Linear System of Equations Solver
This module defines a function fsolve() which, in analogy with the MATLAB function, provides a high-level interface for the solution of non-linear systems of equations.
GSL Interface
We use gsl_multiroots to solve the non-linear system of equations.
#ifdef USE_GSL
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>
#pragma autolink -lgsl -lgslcblas
#ifndef FSOLVE_RELTOL
# define FSOLVE_RELTOL 0.
#endif
#ifndef FSOLVE_ABSTOL
# define FSOLVE_ABSTOL 1.e-7
#endif
typedef int (* nls_fun) (const gsl_vector * x, void * params, gsl_vector * f);
void fsolve_gsl (nls_fun fun,
* arrUnk,
Array void * params)
{
const gsl_multiroot_fsolver_type * T;
* s;
gsl_multiroot_fsolver
int status, iter = 0.;
int size = arrUnk->len / sizeof(double);
const size_t n = (size_t)(size);
= {fun, n, params};
gsl_multiroot_function f
double * x_init = (double *)arrUnk->p;
* x = gsl_vector_alloc (n);
gsl_vector
for (unsigned int i=0; i<size; i++)
(x, i, x_init[i]);
gsl_vector_set
= gsl_multiroot_fsolver_hybrids;
T = gsl_multiroot_fsolver_alloc (T, n);
s (s, &f, x);
gsl_multiroot_fsolver_set
do {
++;
iter= gsl_multiroot_fsolver_iterate (s);
status
if (status) /* check if solver is stuck */ {
fprintf (stderr, "WARNING: Non linear systems solver is stuck.\n");
break;
}
if (FSOLVE_RELTOL > 0.)
=
status (s->dx, s->x, FSOLVE_ABSTOL, FSOLVE_RELTOL);
gsl_multiroot_test_delta
else=
status (s->f, FSOLVE_ABSTOL);
gsl_multiroot_test_residual
}
while (status == GSL_CONTINUE && iter < 1000);
double * res = (double *)arrUnk->p;
for (unsigned int i=0; i<size; i++)
[i] = gsl_vector_get (s->x, i);
res
(s);
gsl_multiroot_fsolver_free (x);
gsl_vector_free }
void fsolve (nls_fun fun,
* arrUnk,
Array void * params)
{
fsolve_gsl (fun, arrUnk, params);
}
#endif // USE_GSL
KINSol Interface
if the SUNDIALS library is used, the function fsolve() relies on the KINSol solver. This implementation works with Sundials 5.8 and it is not updated for Sundials >= 6.0.
#ifdef USE_SUNDIALS
#include <kinsol/kinsol.h>
#include <nvector/nvector_serial.h>
#include <sunmatrix/sunmatrix_dense.h>
#include <sunlinsol/sunlinsol_dense.h>
#include <sundials/sundials_types.h>
#define KIN_FTOL 1.e-6 // function tolerance
#define KIN_STOL 1.e-6 // step tolerance
#pragma autolink -lsundials_kinsol
typedef int (* nls_fun)(N_Vector u, N_Vector fval, void *user_data);
void fsolve_sundials (nls_fun fun,
* arrUnk,
Array )
Point point{
, s;
N_Vector u;
SUNMatrix J;
SUNLinearSolver LS
= NULL;
u = NULL;
s = NULL;
J
int size = arrUnk->len / sizeof(double);
= N_VNew_Serial (size);
u = N_VNew_Serial (size);
s {
* udata = N_VGetArrayPointer (u);
realtype double * unk = (double *)arrUnk->p;
for (unsigned int jj=0; jj<size; jj++)
[jj] = unk[jj];
udata}
(1.0, s);
N_VConst
void * kmem;
= KINCreate();
kmem (kmem, params);
KINSetUserData (kmem, KIN_FTOL);
KINSetFuncNormTol (kmem, KIN_STOL);
KINSetScaledStepTol (kmem, fun, u);
KINInit = SUNDenseMatrix (size, size);
J = SUNLinSol_Dense (u, J);
LS (kmem, LS, J);
KINSetLinearSolver (kmem, 1);
KINSetMaxSetupCalls(kmem, 0);
KINSetPrintLevel
//TODO following two lines give problems
//{
// char name[80];
// sprintf (name, "KINSolErr");
// const FILE * fKinErr = fopen (name, "a");
// KINSetErrFile (kmem, fKinErr);
//}
Solve non-linear system of equations.
(kmem, u, KIN_NONE, s, s);
KINSol //KINSol (kmem, u, KIN_LINESEARCH, s, s);
Recover Nls solution.
{
* udata = N_VGetArrayPointer (u);
realtype double * unk = (double *)arrUnk->p;
for (unsigned jj=0; jj<size; jj++) {
[jj] = udata[jj];
unk}
}
Free memory.
(u);
N_VDestroy (s);
N_VDestroy (&kmem);
KINFree (LS);
SUNLinSolFree (J);
SUNMatDestroy free (data);
}
void fsolve (nls_fun fun,
* arrUnk,
Array )
Point point{
fsolve_sundials (fun, arrUnk, point);
}
#endif // USE_SUNDIALS