/[ascend]/branches/harry/solvers/ida/prepare_integrator.c
ViewVC logotype

Contents of /branches/harry/solvers/ida/prepare_integrator.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3032 - (show annotations) (download) (as text)
Wed Jul 29 03:30:04 2015 UTC (8 years, 1 month ago) by raymondj
File MIME type: text/x-csrc
File size: 18464 byte(s)
Debugging and testing completely changed ida solver
1 /* ASCEND modelling environment
2 Copyright (C) 2011 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20
21 *//*
22 by Harry, 4th June 2015
23
24 This file contains an implmentation of the prepare_integrator function
25 that sets up the integration engine to perform event guided integration.
26 The various tasks it performs include: allocate memory (ida_mem), obtain
27 integrator configuration, analyse equations and configure IDA to setup
28 sufficient memory for the derivative and non-derivative variables.
29
30 */
31
32
33
34
35
36 #define _GNU_SOURCE
37
38 #include "ida.h"
39 #include "idalinear.h"
40 #include "idaanalyse.h"
41 #include "idatypes.h" /* The list of includes needs cleaning up! Once basic files are written,
42 #include "idaprec.h" all commonly called functions can be added in just one header file.
43 #include "idacalc.h" Once that's done, these includes must be revisited*/
44 #include "idaio.h"
45 #include "idaboundary.h"
46
47 #include <signal.h> /*Check if these includes are necessary*/
48 #include <setjmp.h>
49 #include <fenv.h>
50 #include <math.h>
51
52 #ifdef ASC_WITH_MMIO
53 # include <mmio.h>
54 #endif
55
56 #include <ascend/general/platform.h>
57 #include <ascend/utilities/error.h>
58 #include <ascend/utilities/ascSignal.h>
59 #include <ascend/general/panic.h>
60 #include <ascend/compiler/instance_enum.h>
61
62
63 #include <ascend/system/slv_client.h>
64 #include <ascend/system/relman.h>
65 #include <ascend/system/block.h>
66 #include <ascend/system/slv_stdcalls.h>
67 #include <ascend/system/jacobian.h>
68 #include <ascend/system/bndman.h>
69
70 #include <ascend/utilities/config.h>
71 #include <ascend/integrator/integrator.h>
72
73
74 int ida_prepare_integrator(IntegratorSystem *integ){
75 flag = IDAInit(ida_mem, &integrator_ida_fex, t0, y0 ,yp0);
76
77 /*------------------- RECORDING INTEGRATOR PREFERENCES --------------------*
78 The following block sets several preferences based on user choices.
79 The code implemented in this block was initially obtained from
80 ida.c in the Ksenija2 directory.
81 *-----------------------------------------------------------------------------------------------------------*/
82
83
84
85
86
87
88
89
90
91
92
93 /*Takes in a host of parameters for specifying integrator preferences*/
94 static int integrator_ida_params_default(IntegratorSystem *integ) {
95 asc_assert(integ!=NULL);
96 asc_assert(integ->engine==INTEG_IDA);
97 slv_parameters_t *p;
98 p = &(integ->params);
99 slv_destroy_parms(p);
100 if (p->parms == NULL) {
101 //CONSOLE_DEBUG("params NULL");
102 p->parms = ASC_NEW_ARRAY(struct slv_parameter, IDA_PARAMS_SIZE);
103 return -1;
104 p->dynamic_parms = 1;
105 }else{
106 //CONSOLE_DEBUG("params not NULL");
107 }
108 /* reset the number of parameters to zero so that we can check it at the end */
109 p->num_parms = 0;
110 /*The following calls to slv_param_* specify several preferences. See integrator manual for choice of available preferences in IDA*/
111 slv_param_bool(p, IDA_PARAM_AUTODIFF,
112 (SlvParameterInitBool){{"autodiff"
113 ,"Use auto-diff?",1
114 ,"Use automatic differentiation of expressions (1) or use numerical derivatives (0)"
115 }, TRUE});
116
117 slv_param_char(p,IDA_PARAM_CALCIC
118 ,(SlvParameterInitChar){{"calcic"
119 ,"Initial conditions calcuation",1
120 ,"Use specified values of ydot to solve for inital y (Y),"
121 " or use the the values of the differential variables (yd) to solve"
122 " for the pure algebraic variables (ya) along with the derivatives"
123 " of the differential variables (yddot) (YA_YDP), or else don't solve"
124 " the intial conditions at all (NONE). See IDA manual p 41 (IDASetId)"
125 }, "YA_YDP"}, (char *[]) {"Y", "YA_YDP", "NONE",NULL});
126
127
128 slv_param_bool(p,IDA_PARAM_SAFEEVAL
129 ,(SlvParameterInitBool){{"safeeval"
130 ,"Use safe evaluation?",1
131 ,"Use 'safe' function evaluation routines (TRUE) or allow ASCEND to "
132 "throw SIGFPE errors which will then halt integration."
133 }, FALSE});
134
135 slv_param_bool(p,IDA_PARAM_ATOLVECT
136 ,(SlvParameterInitBool){{"atolvect"
137 ,"Use 'ode_atol' values as specified?",1
138 ,"If TRUE, values of 'ode_atol' are taken from your model and used "
139 " in the integration. If FALSE, a scalar absolute tolerance value"
140 " is shared by all variables. See IDA manual, section 5.5.1"
141 }, TRUE});
142
143 slv_param_real(p,IDA_PARAM_ATOL
144 ,(SlvParameterInitReal){{"atol"
145 ,"Scalar absolute error tolerance",1
146 ,"Value of the scalar absolute error tolerance. See also 'atolvect'."
147 " See IDA manual, sections 5.5.1 and 5.5.2 'Advice on choice and use of tolerances'"
148 }, 1e-5, 0, 1e10});
149
150 slv_param_real(p,IDA_PARAM_RTOL
151 ,(SlvParameterInitReal){{"rtol"
152 ,"Scalar relative error tolerance",1
153 ,"Value of the scalar relative error tolerance. (Note that for IDA,"
154 " it's not possible to set per-variable relative tolerances as it is"
155 " with LSODE)."
156 " See IDA manual, section 5.5.2 'Advice on choice and use of tolerances'"
157 }, 1e-4, 0, 1});
158
159 slv_param_char(p,IDA_PARAM_LINSOLVER
160 ,(SlvParameterInitChar){{"linsolver"
161 ,"Linear solver",1
162 ,"See IDA manual, section 5.5.3. Choose 'ASCEND' to use the linsolqr"
163 " direct linear solver bundled with ASCEND, 'DENSE' to use the dense"
164 " solver bundled with IDA, or one of the Krylov solvers SPGMR, SPBCG"
165 " or SPTFQMR (which still need preconditioners to be implemented"
166 " before they can be very useful."},"DENSE"},(char *[]){"ASCEND","DENSE","BAND","SPGMR","SPBCG","SPTFQMR",NULL});
167
168 slv_param_int(p,IDA_PARAM_MAXL
169 ,(SlvParameterInitInt){{"maxl"
170 ,"Maximum Krylov dimension",0
171 ,"The maximum dimension of Krylov space used by the linear solver"
172 " (for SPGMR, SPBCG, SPTFQMR) with IDA. See IDA manual section 5.5."
173 " The default of 0 results in IDA using its internal default, which"
174 " is currently a value of 5."
175 }, 0, 0, 20});
176
177 slv_param_int(p,IDA_PARAM_MAXORD
178 ,(SlvParameterInitInt){{"maxord"
179 ,"Maximum order of linear multistep method",0
180 ,"The maximum order of the linear multistep method with IDA. See"
181 " IDA manual p 38."
182 }, 5, 1, 5});
183
184 slv_param_bool(p,IDA_PARAM_GSMODIFIED
185 ,(SlvParameterInitBool){{"gsmodified"
186 ,"Gram-Schmidt Orthogonalisation Scheme", 2
187 ,"TRUE = GS_MODIFIED, FALSE = GS_CLASSICAL. See IDA manual section"
188 " 5.5.6.6. Only applies when linsolve=SPGMR is selected."
189 }, TRUE});
190
191 slv_param_int(p,IDA_PARAM_MAXNCF
192 ,(SlvParameterInitInt){{"maxncf"
193 ,"Max nonlinear solver convergence failures per step", 2
194 ,"Maximum number of allowable nonlinear solver convergence failures"
195 " on one step. See IDA manual section 5.5.6.1."
196 }, 10,0,1000});
197
198 slv_param_char(p,IDA_PARAM_PREC
199 ,(SlvParameterInitChar){{"prec"
200 ,"Preconditioner",1
201 ,"See IDA manual, section section 5.6.8."
202 },"NONE"}, (char *[]) {"NONE","DIAG",NULL});
203
204 /*Check to verify the number of parameters are correct*/
205 asc_assert(p->num_parms == IDA_PARAMS_SIZE);
206 //CONSOLE_DEBUG("Created %d params", p->num_parms);
207
208
209
210
211
212
213
214
215
216
217 /*------------------- PASSING ON USER PREFERENCES TO INTEGRATOR --------------------*
218 In the following block, the user preferences for several integrator
219 settings are passed on to the integrator engine.
220
221 *-----------------------------------------------------------------------------------------------------------*/
222
223
224
225
226
227
228
229
230
231
232
233
234 /*Passing initial calculation details*/
235 /*Passing initial calculation details*/
236 icopt = 0;
237 if (strcmp(SLV_PARAM_CHAR(&integ->params,IDA_PARAM_CALCIC), "Y") == 0) {
238 CONSOLE_DEBUG("Solving initial conditions using values of yddot");
239 icopt = IDA_Y_INIT;
240 asc_assert(icopt!=0);
241 }else if (strcmp(SLV_PARAM_CHAR(&integ->params,IDA_PARAM_CALCIC), "YA_YDP") == 0){
242 CONSOLE_DEBUG("Solving initial conditions using values of yd");
243 icopt = IDA_YA_YDP_INIT;
244 asc_assert(icopt!=0);
245 flag = IDACalcIC(ida_mem, icopt, tout1);
246
247 /*Passing safe-evaluation option*/ /*Passing safe-evaluation option*/
248
249 #ifdef ASC_SIGNAL_TRAPS /*Fix Dependencies here? Re-visit!*/
250 if(enginedata->safeeval) {
251 CONSOLE_DEBUG("SETTING TO IGNORE SIGFPE...");
252 Asc_SignalHandlerPush(SIGFPE, SIG_DFL);
253 }else{
254 #ifdef FEX_DEBUG
255 CONSOLE_DEBUG("SETTING TO CATCH SIGFPE...");
256 #endif
257 Asc_SignalHandlerPushDefault(SIGFPE);
258 }
259
260 /*Passing tolerance preferences*/ /*Passing tolerance preferences*/
261
262 int ida_malloc(IntegratorSystem *integ, void *ida_mem, realtype t0,
263 N_Vector y0, N_Vector yp0) {
264 int flag;
265 N_Vector abstolvect;
266 realtype reltol, abstol;
267 /* relative error tolerance */
268 reltol = SLV_PARAM_REAL(&(integ->params),IDA_PARAM_RTOL);
269 //CONSOLE_DEBUG("rtol = %8.2e",reltol);
270 #if SUNDIALS_VERSION_MAJOR==2 && SUNDIALS_VERSION_MINOR>=4
271 flag = IDAInit(ida_mem, &integrator_ida_fex, t0, y0 ,yp0);
272 #else
273 if(SLV_PARAM_BOOL(&(integ->params),IDA_PARAM_ATOLVECT)) {
274 /* vector of absolute tolerances */
275 CONSOLE_DEBUG("USING VECTOR OF ATOL VALUES");
276 abstolvect = N_VNew_Serial(integ->n_y);
277 integrator_get_atol(integ, NV_DATA_S(abstolvect));
278 flag = IDAMalloc(ida_mem, &integrator_ida_fex, t0, y0, yp0, IDA_SV,
279 reltol, abstolvect);
280 N_VDestroy_Serial(abstolvect);
281 }else{
282 /* scalar absolute tolerance (one value for all) */
283 abstol = SLV_PARAM_REAL(&(integ->params),IDA_PARAM_ATOL);
284 CONSOLE_DEBUG("USING SCALAR ATOL VALUE = %8.2e",abstol);
285 flag = IDAMalloc(ida_mem, &integrator_ida_fex, t0, y0, yp0, IDA_SS,
286 reltol, &abstol);
287 }
288 #endif
289
290 /*Passing solver-type preferences*/ /*Passing solver-type preferences*/
291 linsolver = SLV_PARAM_CHAR(&(integ->params),IDA_PARAM_LINSOLVER);
292 //CONSOLE_DEBUG("ASSIGNING LINEAR SOLVER '%s'",linsolver);
293 if(strcmp(linsolver, "ASCEND") == 0) {
294 CONSOLE_DEBUG("ASCEND DIRECT SOLVER, size = %d",integ->n_y);
295 IDAASCEND(ida_mem, integ->n_y);
296 IDAASCENDSetJacFn(ida_mem, &integrator_ida_sjex, (void *) integ);
297 enginedata->flagfntype = "IDAASCEND";
298 enginedata->flagfn = &IDAASCENDGetLastFlag;
299 enginedata->flagnamefn = &IDAASCENDGetReturnFlagName;
300 }else if (strcmp(linsolver, "DENSE") == 0){
301 //CONSOLE_DEBUG("DENSE DIRECT SOLVER, size = %d",integ->n_y);
302 flag = IDADense(ida_mem, integ->n_y);
303 switch(flag){
304 case IDADENSE_SUCCESS:
305 break;
306 case IDADENSE_MEM_NULL:
307 ERROR_REPORTER_HERE(ASC_PROG_ERR,"ida_mem is NULL");
308 return 5;
309 case IDADENSE_ILL_INPUT:
310 ERROR_REPORTER_HERE(ASC_PROG_ERR,"IDADENSE is not compatible with current nvector module");
311 return 5;
312 case IDADENSE_MEM_FAIL:
313 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Memory allocation failed for IDADENSE");
314 return 5;
315 default:
316 ERROR_REPORTER_HERE(ASC_PROG_ERR,"bad return");
317 return 5;
318 }
319
320 if(SLV_PARAM_BOOL(&(integ->params),IDA_PARAM_AUTODIFF)) {
321 //CONSOLE_DEBUG("USING AUTODIFF");
322 #if SUNDIALS_VERSION_MAJOR==2 && SUNDIALS_VERSION_MINOR>=4
323 flag = IDADlsSetDenseJacFn(ida_mem, &integrator_ida_djex);
324 #else
325 flag = IDADenseSetJacFn(ida_mem, &integrator_ida_djex,
326 (void *) integ);
327 #endif
328 switch (flag) {
329 case IDADENSE_SUCCESS:
330 break;
331 default:
332 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed IDADenseSetJacFn");
333 return 6;
334 }
335 }else{
336 CONSOLE_DEBUG("USING NUMERICAL DIFF");
337 }
338
339 enginedata->flagfntype = "IDADENSE";
340 #if SUNDIALS_VERSION_MAJOR==2 && SUNDIALS_VERSION_MINOR>=4
341 enginedata->flagfn = &IDADlsGetLastFlag;
342 enginedata->flagnamefn = &IDADlsGetReturnFlagName;
343 #else
344 enginedata->flagfn = &IDADenseGetLastFlag;
345 enginedata->flagnamefn = &IDADenseGetReturnFlagName;
346 #endif
347 }else{
348 /* remaining methods are all SPILS */
349 CONSOLE_DEBUG("IDA SPILS");
350 maxl = SLV_PARAM_INT(&(integ->params),IDA_PARAM_MAXL);
351 CONSOLE_DEBUG("maxl = %d",maxl);
352
353 /* what preconditioner for SPILS solver? */
354
355 pname = SLV_PARAM_CHAR(&(integ->params),IDA_PARAM_PREC);
356 if(strcmp(pname, "NONE") == 0){
357 prec = NULL;
358 }else if(strcmp(pname, "JACOBI") == 0){
359 prec = &prec_jacobi;
360 }else{
361 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Invalid preconditioner choice '%s'",pname);
362 return 7;
363 }
364
365 /* which SPILS linear solver? */
366 if(strcmp(linsolver, "SPGMR") == 0){
367 CONSOLE_DEBUG("IDA SPGMR");
368 flag = IDASpgmr(ida_mem, maxl); /* 0 means use the default max Krylov dimension of 5 */
369 }else if(strcmp(linsolver, "SPBCG") == 0){
370 CONSOLE_DEBUG("IDA SPBCG");
371 flag = IDASpbcg(ida_mem, maxl);
372 }else if(strcmp(linsolver, "SPTFQMR") == 0){
373 CONSOLE_DEBUG("IDA SPTFQMR");
374 flag = IDASptfqmr(ida_mem, maxl);
375 }else{
376 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unknown IDA linear solver choice '%s'",linsolver);
377 return 8;
378 }
379
380 if(prec){
381 /* assign the preconditioner to the linear solver */
382 (prec->pcreate)(integ);
383 #if SUNDIALS_VERSION_MAJOR==2 && SUNDIALS_VERSION_MINOR>=4
384 IDASpilsSetPreconditioner(ida_mem,prec->psetup,prec->psolve);
385 #else
386 IDASpilsSetPreconditioner(ida_mem, prec->psetup, prec->psolve,
387 (void *) integ);
388 #endif
389 CONSOLE_DEBUG("PRECONDITIONER = %s",pname);
390 }else{
391 CONSOLE_DEBUG("No preconditioner");
392 }
393
394 enginedata->flagfntype = "IDASPILS";
395 enginedata->flagfn = &IDASpilsGetLastFlag;
396 enginedata->flagnamefn = &IDASpilsGetReturnFlagName;
397 if(flag == IDASPILS_MEM_NULL){
398 ERROR_REPORTER_HERE(ASC_PROG_ERR,"ida_mem is NULL");
399 return 9;
400 }else if (flag == IDASPILS_MEM_FAIL) {
401 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to allocate memory (IDASpgmr)");
402 return 9;
403 }/* else success */
404 /* assign the J*v function */
405 if(SLV_PARAM_BOOL(&(integ->params),IDA_PARAM_AUTODIFF)) {
406 CONSOLE_DEBUG("USING AUTODIFF");
407 #if SUNDIALS_VERSION_MAJOR==2 && SUNDIALS_VERSION_MINOR>=4
408 flag = IDASpilsSetJacTimesVecFn(ida_mem, &integrator_ida_jvex);
409 #else
410 flag = IDASpilsSetJacTimesVecFn(ida_mem, &integrator_ida_jvex,
411 (void *) integ);
412 #endif
413 if(flag == IDASPILS_MEM_NULL) {
414 ERROR_REPORTER_HERE(ASC_PROG_ERR,"ida_mem is NULL");
415 return 10;
416 }else if (flag == IDASPILS_LMEM_NULL) {
417 ERROR_REPORTER_HERE(ASC_PROG_ERR,"IDASPILS linear solver has not been initialized");
418 return 10;
419 }/* else success */
420 }else{
421 CONSOLE_DEBUG("USING NUMERICAL DIFF");
422 }
423 if(strcmp(linsolver, "SPGMR") == 0) {
424 /* select Gram-Schmidt orthogonalisation */
425 if(SLV_PARAM_BOOL(&(integ->params),IDA_PARAM_GSMODIFIED)) {
426 CONSOLE_DEBUG("USING MODIFIED GS");
427 flag = IDASpilsSetGSType(ida_mem, MODIFIED_GS);
428 if(flag != IDASPILS_SUCCESS) {
429 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to set GS_MODIFIED");
430 return 11;
431 }
432 }else{
433 CONSOLE_DEBUG("USING CLASSICAL GS");
434 flag = IDASpilsSetGSType(ida_mem, CLASSICAL_GS);
435 if(flag != IDASPILS_SUCCESS) {
436 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to set GS_MODIFIED");
437 return 11;
438 }
439 }
440 }
441 }
442
443 /*Passing Maxord and Maxncf values*/ /*Passing Maxord and Maxncf values*/
444
445 #if SUNDIALS_VERSION_MAJOR==2 && SUNDIALS_VERSION_MINOR>=4
446 IDASetUserData(ida_mem, (void *)integ);
447 #else
448 IDASetRdata(ida_mem, (void *) integ);
449 #endif
450 IDASetMaxStep(ida_mem, integrator_get_maxstep(integ));
451 IDASetInitStep(ida_mem, integrator_get_stepzero(integ));
452 IDASetMaxNumSteps(ida_mem, integrator_get_maxsubsteps(integ));
453 if (integrator_get_minstep(integ) > 0) {
454 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"IDA does not support minstep (ignored)\n");
455 }
456 //CONSOLE_DEBUG("MAXNCF = %d",SLV_PARAM_INT(&integ->params,IDA_PARAM_MAXNCF));
457 IDASetMaxConvFails(ida_mem, SLV_PARAM_INT(&integ->params,IDA_PARAM_MAXNCF));
458 //CONSOLE_DEBUG("MAXORD = %d",SLV_PARAM_INT(&integ->params,IDA_PARAM_MAXORD));
459 IDASetMaxOrd(ida_mem, SLV_PARAM_INT(&integ->params,IDA_PARAM_MAXORD));
460
461
462
463
464
465
466
467
468 /*------------------- ANALYSE EQUATIONS --------------------*
469 The following block analyses the equations passed on from the
470 GUI to aid integration. This block runs a series of checks, the
471 process is stopped when flag takes a non-zero value.
472 *-----------------------------------------------------------------------------------------------------------*/
473
474 flag = integrator_ida_check_vars(integ) + integrator_ida_flag_rels(integ)
475 + integrator_ida_sort_rels_and_vars(integ) + integrator_ida_create_lists(integ) +
476 integrator_ida_analyse(integ) + integrator_ida_check_partitioning(integ)+
477 integrator_ida_check_diffindex(integ);
478
479 if(flag!=0){
480 return -2; /*Failed analysis*/
481 }
482
483
484
485
486
487
488
489 /*------------------- ALLOCATE MEMORY FOR YDOT, Y ETC --------------------*
490 The following block analyses the equations passed on from the
491 GUI to aid integration. This block runs a series of checks, the
492 process is stopped when flag takes a non-zero value.
493 *-----------------------------------------------------------------------------------------------------------*/
494
495
496
497 /*This block has to be discussed with Ksenija before implamentation. Is this block necessary?
498 The IDA Manual says that most memory allocation procedures are taken care of. Also there's the
499 implementation of IDAMalloc, which needs to be cleared up. Also ida_malloc has already been called above
500 this does the same job of allocating ydot and ypdot. Anything else needs to be done here? */
501
502
503
504
505
506
507 return 0; /*prepare_integrator successful!*/
508 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22