Skip to content

Commit 09b24f9

Browse files
committed
Added Kinsol solver source to cpp runtime
git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@11036 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
1 parent a13f06f commit 09b24f9

File tree

7 files changed

+517
-0
lines changed

7 files changed

+517
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
cmake_minimum_required (VERSION 2.6)
2+
3+
project(Kinsol)
4+
# add the solver default implementation library
5+
add_library(Kinsol SHARED KinsolCall.cpp KinsolCallSettings.cpp )
6+
target_link_libraries( Kinsol ${Boost_LIBRARIES})
7+
8+
9+
10+
install (TARGETS Kinsol DESTINATION bin)
11+
#install (FILES "../Interfaces/NewtonSettings.xml"
12+
# DESTINATION bin/config)
13+
14+
15+
16+
17+
18+
19+
20+
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
#include "stdafx.h"
2+
#include "KinsolCall.h"
3+
#include "KinsolSettings.h"
4+
5+
#include "Math/Interfaces/ILapack.h" // needed for solution of linear system with Lapack
6+
#include "Math/Implementation/Constants.h" // definition of constants like uround
7+
8+
KinsolCall::KinsolCall(IAlgLoop* algLoop, IKinsolSettings* settings)
9+
: _algLoop (algLoop)
10+
, _kinsolSettings ((IKinsolSettings*)settings)
11+
, _y (NULL)
12+
, _yHelp (NULL)
13+
, _f (NULL)
14+
, _fHelp (NULL)
15+
, _jac (NULL)
16+
, _dimSys (0)
17+
, _firstCall (true)
18+
, _iterationStatus (CONTINUE)
19+
{
20+
_data = ((void*)this);
21+
}
22+
23+
KinsolCall::~KinsolCall()
24+
{
25+
if(_y) delete [] _y;
26+
if(_yHelp) delete [] _yHelp;
27+
if(_f) delete [] _f;
28+
if(_fHelp) delete [] _fHelp;
29+
if(_jac) delete [] _jac;
30+
31+
N_VDestroy_Serial(_Kin_y);
32+
N_VDestroy_Serial(_Kin_yScale);
33+
N_VDestroy_Serial(_Kin_fScale);
34+
35+
KINFree(&_kinMem);
36+
}
37+
38+
void KinsolCall::init()
39+
{
40+
int idid;
41+
42+
_firstCall = false;
43+
44+
//(Re-) Initialization of algebraic loop
45+
_algLoop->init();
46+
47+
// Dimension of the system (number of variables)
48+
int
49+
dimDouble = _algLoop->getDimVars(IAlgLoop::REAL),
50+
dimInt = 0,
51+
dimBool = 0;
52+
53+
// Check system dimension
54+
if (dimDouble != _dimSys)
55+
{
56+
_dimSys = dimDouble;
57+
58+
if(_dimSys > 0)
59+
{
60+
// Initialization of vector of unknowns
61+
if(_y) delete [] _y;
62+
if(_f) delete [] _f;
63+
if(_yHelp) delete [] _yHelp;
64+
if(_fHelp) delete [] _fHelp;
65+
if(_jac) delete [] _jac;
66+
67+
_y = new double[_dimSys];
68+
_f = new double[_dimSys];
69+
_yHelp = new double[_dimSys];
70+
_fHelp = new double[_dimSys];
71+
_jac = new double[_dimSys*_dimSys];
72+
73+
_algLoop->giveVars(_y,NULL,NULL);
74+
memset(_f,0,_dimSys*sizeof(double));
75+
memset(_yHelp,0,_dimSys*sizeof(double));
76+
memset(_fHelp,0,_dimSys*sizeof(double));
77+
memset(_jac,0,_dimSys*_dimSys*sizeof(double)); // Wird nur benötigt, falls symbolisch vorhanden
78+
79+
for (int i=0;i<_dimSys;i++)
80+
_yHelp[i] = 1;
81+
82+
_Kin_y = N_VMake_Serial(_dimSys, _y);
83+
_Kin_yScale = N_VMake_Serial(_dimSys, _yHelp);
84+
_Kin_fScale = N_VMake_Serial(_dimSys, _yHelp);
85+
_kinMem = KINCreate();
86+
87+
//Set Options
88+
idid = KINSetNumMaxIters(_kinMem, _kinsolSettings->getNewtMax());
89+
idid = KINInit(_kinMem, kin_fCallback, _Kin_y);
90+
if (check_flag(&idid, "KINInit", 1))
91+
throw std::invalid_argument("KinsolCall::init()");
92+
idid = KINSetUserData(_kinMem, _data);
93+
if (check_flag(&idid, "KINSetUserData", 1))
94+
throw std::invalid_argument("KinsolCall::init()");
95+
//idid = KINDense(_kinMem, _dimSys);
96+
idid = KINSpgmr(_kinMem,_dimSys);
97+
if (check_flag(&idid, "KINSpgmr", 1))
98+
throw std::invalid_argument("KinsolCall::init()");
99+
}
100+
else
101+
{
102+
_iterationStatus = SOLVERERROR;
103+
}
104+
}
105+
106+
107+
}
108+
109+
void KinsolCall::solve(const IContinous::UPDATE command)
110+
{
111+
112+
int idid;
113+
idid = KINSol(_kinMem, _Kin_y, KIN_LINESEARCH, _Kin_yScale, _Kin_yScale);
114+
if (check_flag(&idid, "KINSol", 1))
115+
throw std::invalid_argument("KinsolCall::solve()");
116+
/*
117+
long int
118+
dimRHS = 1, // Dimension of right hand side of linear system (=b)
119+
irtrn = 0; // Retrun-flag of Fortran code
120+
121+
int
122+
totStps = 0; // Total number of steps
123+
124+
// If init() was not called yet
125+
if (_firstCall)
126+
init();
127+
128+
// Get initial values from system
129+
_algLoop->giveVars(_y,NULL,NULL);
130+
//_algLoop->update(command);
131+
_algLoop->giveRHS(_f,NULL,NULL);
132+
133+
134+
// Reset status flag
135+
_iterationStatus = CONTINUE;
136+
137+
while(_iterationStatus == CONTINUE)
138+
{
139+
_iterationStatus = DONE;
140+
141+
// Check stopping criterion
142+
if(totStps)
143+
{
144+
for(int i=0; i<_dimSys; ++i)
145+
{
146+
if(fabs(_f[i]) > _kinsolSettings->getRtol() * (_kinsolSettings->getAtol() + fabs(_f[i])))
147+
{
148+
_iterationStatus = CONTINUE;
149+
break;
150+
}
151+
}
152+
}
153+
else
154+
_iterationStatus = CONTINUE;
155+
156+
// New right hand side
157+
calcFunction(_y,_f);
158+
159+
if(_iterationStatus == CONTINUE)
160+
{
161+
if(totStps < _kinsolSettings->getNewtMax())
162+
{
163+
// Determination of Jacobian (Fortran-format)
164+
if(_algLoop->isLinear())
165+
{
166+
//calcFunction(_yHelp,_fHelp);
167+
_algLoop->giveAMatrix(_jac);
168+
//dgesv_(&_dimSys,&dimRHS,_jac,&_dimSys,_fHelp,_f,&_dimSys,&irtrn);
169+
memcpy(_y,_f,_dimSys*sizeof(double));
170+
_algLoop->setVars(_y,NULL,NULL);
171+
_iterationStatus = DONE;
172+
break;
173+
174+
}
175+
else
176+
{
177+
calcJacobian();
178+
}
179+
// Solve linear System
180+
//dgesv_(&_dimSys,&dimRHS,_jac,&_dimSys,_fHelp,_f,&_dimSys,&irtrn);
181+
182+
if(irtrn!=0)
183+
{
184+
// TODO: Throw an error message here.
185+
_iterationStatus = SOLVERERROR;
186+
break;
187+
}
188+
189+
// Increase counter
190+
++ totStps;
191+
192+
// New solution
193+
for(int i=0; i<_dimSys; ++i)
194+
_y[i] -= _kinsolSettings->getDelta() * _f[i];
195+
196+
}
197+
else
198+
_iterationStatus = SOLVERERROR;
199+
}
200+
}
201+
*/
202+
}
203+
204+
IAlgLoopSolver::ITERATIONSTATUS KinsolCall::getIterationStatus()
205+
{
206+
return _iterationStatus;
207+
}
208+
209+
210+
void KinsolCall::calcFunction(const double *y, double *residual)
211+
{
212+
_algLoop->setVars(y,NULL,NULL);
213+
_algLoop->update(IContinous::CONTINOUS);
214+
_algLoop->giveRHS(residual,NULL,NULL);
215+
}
216+
217+
int KinsolCall::kin_fCallback(N_Vector y,N_Vector fval, void *user_data)
218+
{
219+
((KinsolCall*) user_data)->calcFunction(NV_DATA_S(y),NV_DATA_S(fval));
220+
221+
return(0);
222+
}
223+
224+
225+
226+
void KinsolCall::calcJacobian()
227+
{
228+
for(int j=0; j<_dimSys; ++j)
229+
{
230+
// Reset variables for every column
231+
memcpy(_yHelp,_y,_dimSys*sizeof(double));
232+
233+
// Finite difference
234+
_yHelp[j] += 1e-6;
235+
236+
calcFunction(_yHelp,_fHelp);
237+
238+
// Build Jacobian in Fortran format
239+
for(int i=0; i<_dimSys; ++i)
240+
_jac[i+j*_dimSys] = (_fHelp[i] - _f[i]) / 1e-6;
241+
}
242+
243+
}
244+
245+
246+
int KinsolCall::check_flag(void *flagvalue, char *funcname, int opt)
247+
{
248+
int *errflag;
249+
250+
/* Check if SUNDIALS function returned NULL pointer - no memory allocated */
251+
if (opt == 0 && flagvalue == NULL) {
252+
fprintf(stderr,
253+
"\nSUNDIALS_ERROR: %s() failed - returned NULL pointer\n\n",
254+
funcname);
255+
return(1);
256+
}
257+
258+
/* Check if flag < 0 */
259+
else if (opt == 1) {
260+
errflag = (int *) flagvalue;
261+
if (*errflag < 0) {
262+
fprintf(stderr,
263+
"\nSUNDIALS_ERROR: %s() failed with flag = %d\n\n",
264+
funcname, *errflag);
265+
return(1);
266+
}
267+
}
268+
269+
/* Check if function returned NULL pointer - no memory allocated */
270+
else if (opt == 2 && flagvalue == NULL) {
271+
fprintf(stderr,
272+
"\nMEMORY_ERROR: %s() failed - returned NULL pointer\n\n",
273+
funcname);
274+
return(1);
275+
}
276+
277+
return(0);
278+
}
279+
280+
using boost::extensions::factory;
281+
282+
BOOST_EXTENSION_TYPE_MAP_FUNCTION {
283+
types.get<std::map<std::string, factory<IAlgLoopSolver,IAlgLoop*, IKinsolSettings*> > >()
284+
["KinsolCall"].set<KinsolCall>();
285+
types.get<std::map<std::string, factory<IKinsolSettings> > >()
286+
["KinsolSettings"].set<KinsolSettings>();
287+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
#pragma once
3+
4+
#include "System/Interfaces/IAlgLoop.h" // Interface to AlgLoop
5+
#include "System/Interfaces/IAlgLoopSolver.h" // Export function from dll
6+
7+
#include "System/Kinsol/Interfaces/IKinsolSettings.h"
8+
#include<kinsol.h>
9+
#include<nvector_serial.h>
10+
#include<kinsol_dense.h>
11+
12+
#include<kinsol_spgmr.h>
13+
14+
15+
16+
class KinsolCall : public IAlgLoopSolver
17+
{
18+
public:
19+
20+
KinsolCall(IAlgLoop* algLoop,IKinsolSettings* settings);
21+
22+
virtual ~KinsolCall();
23+
24+
/// (Re-) initialize the solver
25+
virtual void init();
26+
27+
/// Solution of a (non-)linear system of equations
28+
virtual void solve(const IContinous::UPDATE command = IContinous::UNDEF_UPDATE);
29+
30+
/// Returns the status of iteration
31+
virtual ITERATIONSTATUS getIterationStatus();
32+
33+
34+
private:
35+
/// Encapsulation of determination of residuals to given unknowns
36+
void calcFunction(const double* y, double* residual);
37+
38+
/// Encapsulation of determination of Jacobian
39+
void calcJacobian();
40+
int check_flag(void *flagvalue, char *funcname, int opt);
41+
static int kin_fCallback(N_Vector y, N_Vector fval, void *user_data);
42+
43+
44+
// Member variables
45+
//---------------------------------------------------------------
46+
IKinsolSettings
47+
*_kinsolSettings; ///< Settings for the solver
48+
49+
IAlgLoop
50+
*_algLoop; ///< Algebraic loop to be solved
51+
52+
ITERATIONSTATUS
53+
_iterationStatus; ///< Output - Denotes the status of iteration
54+
55+
long int
56+
_dimSys; ///< Temp - Number of unknowns (=dimension of system of equations)
57+
58+
bool
59+
_firstCall; ///< Temp - Denotes the first call to the solver, init() is called
60+
61+
double
62+
*_y, ///< Temp - Unknowns
63+
*_f, ///< Temp - Residuals
64+
*_yHelp, ///< Temp - Auxillary variables
65+
*_fHelp, ///< Temp - Auxillary variables
66+
*_jac; ///< Temp - Jacobian
67+
68+
N_Vector
69+
_Kin_y, ///< Temp - Initial values in the Sundials Format
70+
_Kin_yScale,
71+
_Kin_fScale;
72+
void
73+
*_kinMem, ///< Temp - Memory for the solver
74+
*_data; ///< Temp - User data. Contains pointer to KinsolCall
75+
};

0 commit comments

Comments
 (0)