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+ " \n SUNDIALS_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+ " \n SUNDIALS_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+ " \n MEMORY_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+ }
0 commit comments