/[ascend]/trunk/base/generic/solver/ida.c
ViewVC logotype

Contents of /trunk/base/generic/solver/ida.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 970 - (show annotations) (download) (as text)
Tue Dec 19 02:39:54 2006 UTC (16 years, 5 months ago) by johnpye
File MIME type: text/x-csrc
File size: 29973 byte(s)
Adding missing 'aww.*' files for Art's DAE integrator.
Adding 'maxl' (Maximum Krylov dimension) option to IDA.
1 /* ASCEND modelling environment
2 Copyright (C) 2006 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 *//**
19 @file
20 Access to the IDA integrator for ASCEND. IDA is a DAE solver that comes
21 as part of the GPL-licensed SUNDIALS solver package from LLNL.
22 @see http://www.llnl.gov/casc/sundials/
23 *//*
24 by John Pye, May 2006
25 */
26
27 /*
28 Be careful with the following. This file requires both the 'ida.h' from
29 SUNDIALS as well as the 'ida.h' from ASCEND. Make sure that we're getting
30 both of these; if you get problems check your build tool for the paths being
31 passed to the C preprocessor.
32 */
33
34 /* standard includes */
35 #include <signal.h>
36
37 /* ASCEND includes */
38 #include "ida.h"
39 #include <utilities/error.h>
40 #include <utilities/ascConfig.h>
41 #include <utilities/ascSignal.h>
42 #include <utilities/ascPanic.h>
43 #include <compiler/instance_enum.h>
44 #include "var.h"
45 #include "rel.h"
46 #include "discrete.h"
47 #include "conditional.h"
48 #include "logrel.h"
49 #include "bnd.h"
50 #include "linsol.h"
51 #include "linsolqr.h"
52 #include "slv_common.h"
53 #include "slv_client.h"
54 #include "relman.h"
55
56 /* SUNDIALS includes */
57 #ifdef ASC_WITH_IDA
58 # include <sundials/sundials_config.h>
59 # include <sundials/sundials_dense.h>
60 # include <ida/ida.h>
61 # include <nvector/nvector_serial.h>
62 # include <ida/ida_spgmr.h>
63 # include <ida/ida_spbcgs.h>
64 # include <ida/ida_sptfqmr.h>
65 # include <ida/ida_dense.h>
66 # ifndef IDA_SUCCESS
67 # error "Failed to include SUNDIALS IDA header file"
68 # endif
69 #endif
70
71 /*
72 for cases where we don't have SUNDIALS_VERSION_MINOR defined, guess version 2.2
73 */
74 #ifndef SUNDIALS_VERSION_MINOR
75 # ifdef __GNUC__
76 # warning "GUESSING SUNDIALS VERSION 2.2"
77 # endif
78 # define SUNDIALS_VERSION_MINOR 2
79 #endif
80 #ifndef SUNDIALS_VERSION_MAJOR
81 # define SUNDIALS_VERSION_MAJOR 2
82 #endif
83
84 /* check that we've got what we expect now */
85 #ifndef ASC_IDA_H
86 # error "Failed to include ASCEND IDA header file"
87 #endif
88
89 #define FEX_DEBUG
90 #define JEX_DEBUG
91
92 /**
93 Struct containing any stuff that IDA needs that doesn't fit into the
94 common IntegratorSystem struct.
95 */
96 typedef struct{
97 struct rel_relation **rellist; /**< NULL terminated list of rels */
98 struct var_variable **varlist; /**< NULL terminated list of vars. ONLY USED FOR DEBUGGING -- get rid of it! */
99 int nrels;
100 int safeeval; /**< whether to pass the 'safe' flag to relman_eval */
101 } IntegratorIdaData;
102
103 /*-------------------------------------------------------------
104 FORWARD DECLS
105 */
106 /* residual function forward declaration */
107 int integrator_ida_fex(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, void *res_data);
108
109 int integrator_ida_jvex(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr
110 , N_Vector v, N_Vector Jv, realtype c_j
111 , void *jac_data, N_Vector tmp1, N_Vector tmp2
112 );
113
114 /* error handler forward declaration */
115 void integrator_ida_error(int error_code
116 , const char *module, const char *function
117 , char *msg, void *eh_data
118 );
119
120 int integrator_ida_djex(long int Neq, realtype tt
121 , N_Vector yy, N_Vector yp, N_Vector rr
122 , realtype c_j, void *jac_data, DenseMat Jac
123 , N_Vector tmp1, N_Vector tmp2, N_Vector tmp3
124 );
125
126 /*-------------------------------------------------------------
127 SETUP/TEARDOWN ROUTINES
128 */
129 void integrator_ida_create(IntegratorSystem *blsys){
130 CONSOLE_DEBUG("ALLOCATING IDA ENGINE DATA");
131 IntegratorIdaData *enginedata;
132 enginedata = ASC_NEW(IntegratorIdaData);
133 enginedata->rellist = NULL;
134 enginedata->varlist = NULL;
135 enginedata->safeeval = 0;
136 blsys->enginedata = (void *)enginedata;
137 integrator_ida_params_default(blsys);
138 }
139
140 void integrator_ida_free(void *enginedata){
141 CONSOLE_DEBUG("DELETING IDA ENGINE DATA");
142 IntegratorIdaData *d = (IntegratorIdaData *)enginedata;
143 /* note, we don't own the rellist, so don't need to free it */
144 ASC_FREE(d);
145 }
146
147 IntegratorIdaData *integrator_ida_enginedata(IntegratorSystem *blsys){
148 IntegratorIdaData *d;
149 assert(blsys!=NULL);
150 assert(blsys->enginedata!=NULL);
151 assert(blsys->engine==INTEG_IDA);
152 d = ((IntegratorIdaData *)(blsys->enginedata));
153 return d;
154 }
155
156 /*-------------------------------------------------------------
157 PARAMETERS FOR IDA
158 */
159
160 enum ida_parameters{
161 IDA_PARAM_LINSOLVER
162 ,IDA_PARAM_MAXL
163 ,IDA_PARAM_AUTODIFF
164 ,IDA_PARAM_SAFEEVAL
165 ,IDA_PARAM_RTOL
166 ,IDA_PARAM_ATOL
167 ,IDA_PARAM_ATOLVECT
168 ,IDA_PARAM_GSMODIFIED
169 ,IDA_PARAMS_SIZE
170 };
171
172 /**
173 Here the full set of parameters is defined, along with upper/lower bounds,
174 etc. The values are stuck into the blsys->params structure.
175
176 @return 0 on success
177 */
178 int integrator_ida_params_default(IntegratorSystem *blsys){
179 asc_assert(blsys!=NULL);
180 asc_assert(blsys->engine==INTEG_IDA);
181 slv_parameters_t *p;
182 p = &(blsys->params);
183
184 slv_destroy_parms(p);
185
186 if(p->parms==NULL){
187 CONSOLE_DEBUG("params NULL");
188 p->parms = ASC_NEW_ARRAY(struct slv_parameter, IDA_PARAMS_SIZE);
189 if(p->parms==NULL)return -1;
190 p->dynamic_parms = 1;
191 }else{
192 CONSOLE_DEBUG("params not NULL");
193 }
194
195 /* reset the number of parameters to zero so that we can check it at the end */
196 p->num_parms = 0;
197
198 slv_param_bool(p,IDA_PARAM_AUTODIFF
199 ,(SlvParameterInitBool){{"autodiff"
200 ,"Use auto-diff?",1
201 ,"Use automatic differentiation of expressions (1) or use numerical derivatives (0)"
202 }, TRUE}
203 );
204
205 slv_param_bool(p,IDA_PARAM_SAFEEVAL
206 ,(SlvParameterInitBool){{"safeeval"
207 ,"Use safe evaluation?",1
208 ,"Use 'safe' function evaluation routines (TRUE) or allow ASCEND to "
209 "throw SIGFPE errors which will then halt integration."
210 }, FALSE}
211 );
212
213
214 slv_param_bool(p,IDA_PARAM_ATOLVECT
215 ,(SlvParameterInitBool){{"atolvect"
216 ,"Use 'ode_atol' values as specified?",1
217 ,"If TRUE, values of 'ode_atol' are taken from your model and used "
218 " in the integration. If FALSE, a scalar absolute tolerance value"
219 " is shared by all variables. See IDA manual, section 5.5.1"
220 }, TRUE }
221 );
222
223 slv_param_real(p,IDA_PARAM_ATOL
224 ,(SlvParameterInitReal){{"atol"
225 ,"Scalar absolute error tolerance",1
226 ,"Value of the scalar absolute error tolerance. See also 'atolvect'."
227 " See IDA manual, section 5.5.1"
228 }, 1e-5, DBL_MIN, DBL_MAX }
229 );
230
231 slv_param_real(p,IDA_PARAM_RTOL
232 ,(SlvParameterInitReal){{"rtol"
233 ,"Scalar relative error tolerance",1
234 ,"Value of the scalar relative error tolerance. (Note that for IDA,"
235 " it's not possible to set per-variable relative tolerances as it is"
236 " with LSODE)."
237 " See IDA manual, section 5.5.1"
238 }, 1e-4, 0, DBL_MAX }
239 );
240
241 slv_param_char(p,IDA_PARAM_LINSOLVER
242 ,(SlvParameterInitChar){{"linsolver"
243 ,"Linear solver",1
244 ,"See IDA manual, section 5.5.3."
245 }, "SPGMR"}, (char *[]){"DENSE","BAND","SPGMR","SPBCG","SPTFQMR",NULL}
246 );
247
248 slv_param_int(p,IDA_PARAM_MAXL
249 ,(SlvParameterInitInt){{"maxl"
250 ,"Maximum Krylov dimension",0
251 ,"The maximum dimension of Krylov space used by the linear solver"
252 " (for SPGMR, SPBCG, SPTFQMR) with IDA. See IDA manual section 5.5."
253 " The default of 0 results in IDA using its internal default, which"
254 " is currently a value of 5."
255 }, 0, 0, 20 }
256 );
257
258 slv_param_bool(p,IDA_PARAM_GSMODIFIED
259 ,(SlvParameterInitBool){{"gsmodified"
260 ,"Use modified Gram-Schmidt orthogonalisation in SPGMR?",2
261 ,"TRUE = GS_MODIFIED, FALSE = GS_CLASSICAL. See IDA manual section"
262 " 5.5.6.6. Only applies when linsolve=SPGMR is selected."
263 }, TRUE}
264 );
265
266 asc_assert(p->num_parms == IDA_PARAMS_SIZE);
267
268 CONSOLE_DEBUG("Created %d params", p->num_parms);
269
270 return 0;
271 }
272
273 /*-------------------------------------------------------------
274 MAIN IDA SOLVER ROUTINE, see IDA manual, sec 5.4, p. 27 ff.
275 */
276
277 /* return 1 on success */
278 int integrator_ida_solve(
279 IntegratorSystem *blsys
280 , unsigned long start_index
281 , unsigned long finish_index
282 ){
283 void *ida_mem;
284 int size, flag, t_index;
285 realtype t0, reltol, abstol, t, tret;
286 N_Vector y0, yp0, abstolvect, ypret, yret;
287 IntegratorIdaData *enginedata;
288 char *linsolver;
289
290 CONSOLE_DEBUG("STARTING IDA...");
291
292 enginedata = integrator_ida_enginedata(blsys);
293
294 enginedata->safeeval = SLV_PARAM_BOOL(&(blsys->params),IDA_PARAM_SAFEEVAL);
295 CONSOLE_DEBUG("safeeval = %d",enginedata->safeeval);
296
297 /* store reference to list of relations (in enginedata) */
298 enginedata->nrels = slv_get_num_solvers_rels(blsys->system);
299 enginedata->rellist = slv_get_solvers_rel_list(blsys->system);
300 enginedata->varlist = slv_get_solvers_var_list(blsys->system);
301 CONSOLE_DEBUG("Number of relations: %d",enginedata->nrels);
302 CONSOLE_DEBUG("Number of dependent vars: %ld",blsys->n_y);
303 size = blsys->n_y;
304
305 if(enginedata->nrels!=size){
306 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Integration problem is not square (%d rels, %d vars)", enginedata->nrels, size);
307 return 0; /* failure */
308 }
309
310 /* retrieve initial values from the system */
311
312 /** @TODO fix this, the starting time != first sample */
313 t0 = integrator_get_t(blsys);
314 CONSOLE_DEBUG("RETRIEVED t0 = %f",t0);
315
316 CONSOLE_DEBUG("RETRIEVING y0");
317
318 y0 = N_VNew_Serial(size);
319 integrator_get_y(blsys,NV_DATA_S(y0));
320
321 CONSOLE_DEBUG("RETRIEVING yp0");
322
323 yp0 = N_VNew_Serial(size);
324 integrator_get_ydot(blsys,NV_DATA_S(yp0));
325
326 N_VPrint_Serial(yp0);
327 CONSOLE_DEBUG("yp0 is at %p",&yp0);
328
329 /* create IDA object */
330 ida_mem = IDACreate();
331
332 /* relative error tolerance */
333 reltol = SLV_PARAM_REAL(&(blsys->params),IDA_PARAM_RTOL);
334 CONSOLE_DEBUG("rtol = %8.2e",reltol);
335
336 /* allocate internal memory */
337 if(SLV_PARAM_BOOL(&(blsys->params),IDA_PARAM_ATOLVECT)){
338 /* vector of absolute tolerances */
339 CONSOLE_DEBUG("USING VECTOR OF ATOL VALUES");
340 abstolvect = N_VNew_Serial(size);
341 integrator_get_atol(blsys,NV_DATA_S(abstolvect));
342
343 flag = IDAMalloc(ida_mem, &integrator_ida_fex, t0, y0, yp0, IDA_SV, reltol, abstolvect);
344
345 N_VDestroy_Serial(abstolvect);
346 }else{
347 /* scalar absolute tolerance (one value for all) */
348 CONSOLE_DEBUG("USING SCALAR ATOL VALUE = %8.2e",abstol);
349 abstol = SLV_PARAM_REAL(&(blsys->params),IDA_PARAM_ATOL);
350 flag = IDAMalloc(ida_mem, &integrator_ida_fex, t0, y0, yp0, IDA_SS, reltol, &abstol);
351 }
352
353 if(flag==IDA_MEM_NULL){
354 ERROR_REPORTER_HERE(ASC_PROG_ERR,"ida_mem is NULL");
355 return 0;
356 }else if(flag==IDA_MEM_FAIL){
357 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to allocate memory (IDAMalloc)");
358 return 0;
359 }else if(flag==IDA_ILL_INPUT){
360 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Invalid input to IDAMalloc");
361 return 0;
362 }/* else success */
363
364 /* set optional inputs... */
365 IDASetErrHandlerFn(ida_mem, &integrator_ida_error, (void *)blsys);
366 IDASetRdata(ida_mem, (void *)blsys);
367 IDASetMaxStep(ida_mem, integrator_get_maxstep(blsys));
368 IDASetInitStep(ida_mem, integrator_get_stepzero(blsys));
369 IDASetMaxNumSteps(ida_mem, integrator_get_maxsubsteps(blsys));
370 if(integrator_get_minstep(blsys)>0){
371 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"IDA does not support minstep (ignored)\n");
372 }
373 /* there's no capability for setting *minimum* step size in IDA */
374
375
376 /* attach linear solver module, using the default value of maxl */
377 linsolver = SLV_PARAM_CHAR(&(blsys->params),IDA_PARAM_LINSOLVER);
378 CONSOLE_DEBUG("ASSIGNING LINEAR SOLVER '%s'",linsolver);
379 if(strcmp(linsolver,"DENSE")==0){
380 CONSOLE_DEBUG("DENSE DIRECT SOLVER, size = %d",size);
381 flag = IDADense(ida_mem, size);
382 switch(flag){
383 case IDADENSE_SUCCESS: break;
384 case IDADENSE_MEM_NULL: ERROR_REPORTER_HERE(ASC_PROG_ERR,"ida_mem is NULL"); return 0;
385 case IDADENSE_ILL_INPUT: ERROR_REPORTER_HERE(ASC_PROG_ERR,"IDADENSE is not compatible with current nvector module"); return 0;
386 case IDADENSE_MEM_FAIL: ERROR_REPORTER_HERE(ASC_PROG_ERR,"Memory allocation failed for IDADENSE"); return 0;
387 default: ERROR_REPORTER_HERE(ASC_PROG_ERR,"bad return"); return 0;
388 }
389
390 if(SLV_PARAM_BOOL(&(blsys->params),IDA_PARAM_AUTODIFF)){
391 CONSOLE_DEBUG("USING AUTODIFF");
392 flag = IDADenseSetJacFn(ida_mem, &integrator_ida_djex, (void *)blsys);
393 switch(flag){
394 case IDADENSE_SUCCESS: break;
395 default: ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed IDADenseSetJacFn"); return 0;
396 }
397 }else{
398 CONSOLE_DEBUG("USING NUMERICAL DIFF");
399 }
400 }else{
401 /* remaining methods are all SPILS */
402 CONSOLE_DEBUG("IDA SPILS");
403
404 if(strcmp(linsolver,"SPGMR")==0){
405 CONSOLE_DEBUG("IDA SPGMR");
406 flag = IDASpgmr(ida_mem, 0); /* 0 means use the default max Krylov dimension of 5 */
407 }else if(strcmp(linsolver,"SPBCG")==0){
408 CONSOLE_DEBUG("IDA SPBCG");
409 flag = IDASpbcg(ida_mem, 0);
410 }else if(strcmp(linsolver,"SPTFQMR")==0){
411 CONSOLE_DEBUG("IDA SPTFQMR");
412 flag = IDASptfqmr(ida_mem,0);
413 }else{
414 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unknown IDA linear solver choice '%s'",linsolver);
415 return 0;
416 }
417
418 if(flag==IDASPILS_MEM_NULL){
419 ERROR_REPORTER_HERE(ASC_PROG_ERR,"ida_mem is NULL");
420 return 0;
421 }else if(flag==IDASPILS_MEM_FAIL){
422 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to allocate memory (IDASpgmr)");
423 return 0;
424 }/* else success */
425
426 /* assign the J*v function */
427 if(SLV_PARAM_BOOL(&(blsys->params),IDA_PARAM_AUTODIFF)){
428 CONSOLE_DEBUG("USING AUTODIFF");
429 flag = IDASpilsSetJacTimesVecFn(ida_mem, &integrator_ida_jvex, (void *)blsys);
430 if(flag==IDASPILS_MEM_NULL){
431 ERROR_REPORTER_HERE(ASC_PROG_ERR,"ida_mem is NULL");
432 return 0;
433 }else if(flag==IDASPILS_LMEM_NULL){
434 ERROR_REPORTER_HERE(ASC_PROG_ERR,"IDASPILS linear solver has not been initialized");
435 return 0;
436 }/* else success */
437 }else{
438 CONSOLE_DEBUG("USING NUMERICAL DIFF");
439 }
440
441 if(strcmp(linsolver,"SPGMR")==0){
442 /* select Gram-Schmidt orthogonalisation */
443 if(SLV_PARAM_BOOL(&(blsys->params),IDA_PARAM_GSMODIFIED)){
444 CONSOLE_DEBUG("USING MODIFIED GS");
445 flag = IDASpilsSetGSType(ida_mem,MODIFIED_GS);
446 if(flag!=IDASPILS_SUCCESS){
447 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to set GS_MODIFIED");
448 return 0;
449 }
450 }else{
451 CONSOLE_DEBUG("USING CLASSICAL GS");
452 flag = IDASpilsSetGSType(ida_mem,CLASSICAL_GS);
453 if(flag!=IDASPILS_SUCCESS){
454 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to set GS_MODIFIED");
455 return 0;
456 }
457 }
458 }
459 }
460
461 /* set linear solver optional inputs...
462
463 ...nothing here at the moment...
464
465 */
466
467 #if 0
468 /* correct initial values, given derivatives */
469 blsys->currentstep=0;
470 t_index=start_index;
471 tout1 = samplelist_get(blsys->samples, t_index);
472
473 CONSOLE_DEBUG("SOLVING INITIAL CONDITIONS IDACalcIC (tout1 = %f)", tout1);
474
475 # if SUNDIALS_VERSION_MAJOR==2 && SUNDIALS_VERSION_MINOR==3
476 /* note the new API from version 2.3 and onwards */
477 flag = IDACalcIC(ida_mem, IDA_Y_INIT, tout1);
478 # else
479 flag = IDACalcIC(ida_mem, t0, y0, yp0, IDA_Y_INIT, tout1);
480 # endif
481
482 if(flag!=IDA_SUCCESS){
483 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to solve initial values (IDACalcIC)");
484 return 0;
485 }/* else success */
486
487 CONSOLE_DEBUG("INITIAL CONDITIONS SOLVED :-)");
488 #endif
489
490 /* optionally, specify ROO-FINDING PROBLEM */
491
492 /* -- set up the IntegratorReporter */
493 integrator_output_init(blsys);
494
495 /* -- store the initial values of all the stuff */
496 integrator_output_write(blsys);
497 integrator_output_write_obs(blsys);
498
499 /* specify where the returned values should be stored */
500 yret = y0;
501 ypret = yp0;
502
503 /* advance solution in time, return values as yret and derivatives as ypret */
504 blsys->currentstep=1;
505 for(t_index=start_index;t_index <= finish_index;++t_index, ++blsys->currentstep){
506 t = samplelist_get(blsys->samples, t_index);
507
508 /* CONSOLE_DEBUG("SOLVING UP TO t = %f", t); */
509
510 flag = IDASolve(ida_mem, t, &tret, yret, ypret, IDA_NORMAL);
511
512 /* pass the values of everything back to the compiler */
513 integrator_set_t(blsys, (double)tret);
514 integrator_set_y(blsys, NV_DATA_S(yret));
515 integrator_set_ydot(blsys, NV_DATA_S(ypret));
516
517 if(flag<0){
518 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to solve t = %f (IDASolve), error %d", t, flag);
519 break;
520 }
521
522 /* -- do something so that blsys knows the values of tret, yret and ypret */
523
524 /* -- store the current values of all the stuff */
525 integrator_output_write(blsys);
526 integrator_output_write_obs(blsys);
527 }
528
529 /* -- close the IntegratorReporter */
530 integrator_output_close(blsys);
531
532 if(flag < 0){
533 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Solving aborted while attempting t = %f", t);
534 return 0;
535 }
536
537 /* get optional outputs */
538
539 /* free solution memory */
540 N_VDestroy_Serial(yret);
541 N_VDestroy_Serial(ypret);
542
543 /* free solver memory */
544 IDAFree(ida_mem);
545
546 /* all done */
547 return 1;
548 }
549
550 /*--------------------------------------------------
551 RESIDUALS AND JACOBIAN
552 */
553 /**
554 Function to evaluate system residuals, in the form required for IDA.
555
556 Given tt, yy and yp, we need to evaluate and return rr.
557
558 @param tt current value of indep variable (time)
559 @param yy current values of dependent variable vector
560 @param yp current values of derivatives of dependent variables
561 @param rr the output residual vector (is we're returning data to)
562 @param res_data pointer to our stuff (blsys in this case).
563
564 @return 0 on success, positive on recoverable error, and
565 negative on unrecoverable error.
566 */
567 int integrator_ida_fex(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr, void *res_data){
568 IntegratorSystem *blsys;
569 IntegratorIdaData *enginedata;
570 int i, calc_ok, is_error;
571 struct rel_relation** relptr;
572 double resid;
573 char *relname;
574 #ifdef FEX_DEBUG
575 char *varname;
576 #endif
577
578 blsys = (IntegratorSystem *)res_data;
579 enginedata = integrator_ida_enginedata(blsys);
580
581 #ifdef FEX_DEBUG
582 /* fprintf(stderr,"\n\n"); */
583 CONSOLE_DEBUG("EVALUTE RESIDUALS...");
584 #endif
585
586 /* pass the values of everything back to the compiler */
587 integrator_set_t(blsys, (double)tt);
588 integrator_set_y(blsys, NV_DATA_S(yy));
589 integrator_set_ydot(blsys, NV_DATA_S(yp));
590
591 if(NV_LENGTH_S(rr)!=enginedata->nrels){
592 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Invalid residuals nrels!=length(rr)");
593 return -1; /* unrecoverable */
594 }
595
596 /**
597 @TODO does this function (fex) do bounds checking already?
598 */
599
600 /* evaluate each residual in the rellist */
601 is_error = 0;
602 relptr = enginedata->rellist;
603
604 if(enginedata->safeeval){
605 Asc_SignalHandlerPush(SIGFPE,SIG_IGN);
606 }else{
607 ERROR_REPORTER_HERE(ASC_PROG_ERR,"SETTING TO CATCH SIGFPE...");
608 Asc_SignalHandlerPushDefault(SIGFPE);
609 }
610
611 if (setjmp(g_fpe_env)==0) {
612 for(i=0, relptr = enginedata->rellist;
613 i< enginedata->nrels && relptr != NULL;
614 ++i, ++relptr
615 ){
616 resid = relman_eval(*relptr, &calc_ok, enginedata->safeeval);
617
618 NV_Ith_S(rr,i) = resid;
619 if(!calc_ok){
620 relname = rel_make_name(blsys->system, *relptr);
621 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Calculation error in rel '%s'",relname);
622 ASC_FREE(relname);
623 /* presumable some output already made? */
624 is_error = 1;
625 }/*else{
626 CONSOLE_DEBUG("Calc OK");
627 }*/
628 }
629 }else{
630 relname = rel_make_name(blsys->system, *relptr);
631 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Floating point error (SIGFPE) in rel '%s'",relname);
632 ASC_FREE(relname);
633 is_error = 1;
634 }
635
636 if(enginedata->safeeval){
637 Asc_SignalHandlerPop(SIGFPE,SIG_IGN);
638 }else{
639 Asc_SignalHandlerPopDefault(SIGFPE);
640 }
641
642 #ifdef FEX_DEBUG
643 /* output residuals to console */
644 CONSOLE_DEBUG("RESIDUAL OUTPUT");
645 fprintf(stderr,"index\t%20s\t%20s\t%s\n","y","ydot","resid");
646 for(i=0; i<blsys->n_y; ++i){
647 varname = var_make_name(blsys->system,blsys->y[i]);
648 fprintf(stderr,"%d\t%10s=%10f\t",i,varname,NV_Ith_S(yy,i));
649 if(blsys->ydot[i]){
650 varname = var_make_name(blsys->system,blsys->ydot[i]);
651 fprintf(stderr,"%10s=%10f\t",varname,NV_Ith_S(yp,i));
652 }else{
653 fprintf(stderr,"diff(%4s)=%10f\t",varname,NV_Ith_S(yp,i));
654 }
655 ASC_FREE(varname);
656 relname = rel_make_name(blsys->system,enginedata->rellist[i]);
657 fprintf(stderr,"'%s'=%f\n",relname,NV_Ith_S(rr,i));
658 }
659 #endif
660
661 if(is_error){
662 return 1;
663 }
664
665 #ifdef FEX_DEBUG
666 CONSOLE_DEBUG("RESIDUAL OK");
667 #endif
668 return 0;
669 }
670
671 /**
672 Dense Jacobian evaluation. Only suitable for small problems!
673 */
674 int integrator_ida_djex(long int Neq, realtype tt
675 , N_Vector yy, N_Vector yp, N_Vector rr
676 , realtype c_j, void *jac_data, DenseMat Jac
677 , N_Vector tmp1, N_Vector tmp2, N_Vector tmp3
678 ){
679 IntegratorSystem *blsys;
680 IntegratorIdaData *enginedata;
681 char *relname;
682 #ifdef JEX_DEBUG
683 char *varname;
684 #endif
685 int status;
686 struct rel_relation **relptr;
687 int i;
688 var_filter_t filter = {VAR_SVAR, VAR_SVAR};
689 double *derivatives;
690 int *variables;
691 int count, j, var_yindex;
692
693 blsys = (IntegratorSystem *)jac_data;
694 enginedata = integrator_ida_enginedata(blsys);
695
696 /* allocate space for returns from relman_diff2: we *should* be able to use 'tmp1' and 'tmp2' here... */
697 variables = ASC_NEW_ARRAY(int, NV_LENGTH_S(yy) * 2);
698 derivatives = ASC_NEW_ARRAY(double, NV_LENGTH_S(yy) * 2);
699
700 /* pass the values of everything back to the compiler */
701 integrator_set_t(blsys, (double)tt);
702 integrator_set_y(blsys, NV_DATA_S(yy));
703 integrator_set_ydot(blsys, NV_DATA_S(yp));
704
705 #ifdef JEX_DEBUG
706 /* print vars */
707 for(i=0; i < blsys->n_y; ++i){
708 varname = var_make_name(blsys->system, blsys->y[i]);
709 CONSOLE_DEBUG("%s = %f = %f",varname,NV_Ith_S(yy,i),var_value(blsys->y[i]));
710 ASC_FREE(varname);
711 }
712
713 /* print derivatives */
714 for(i=0; i < blsys->n_y; ++i){
715 if(blsys->ydot[i]){
716 varname = var_make_name(blsys->system, blsys->ydot[i]);
717 CONSOLE_DEBUG("%s = %f =%f",varname,NV_Ith_S(yp,i),var_value(blsys->ydot[i]));
718 ASC_FREE(varname);
719 }else{
720 varname = var_make_name(blsys->system, blsys->y[i]);
721 CONSOLE_DEBUG("diff(%s) = %f",varname,NV_Ith_S(yp,i));
722 ASC_FREE(varname);
723 }
724 }
725
726 /* print step size */
727 CONSOLE_DEBUG("<c_j> = %f",c_j);
728 #endif
729
730 /* build up the dense jacobian matrix... */
731 status = 0;
732 for(i=0, relptr = enginedata->rellist;
733 i< enginedata->nrels && relptr != NULL;
734 ++i, ++relptr
735 ){
736 /* get derivatives for this particular relation */
737 status = relman_diff2(*relptr, &filter, derivatives, variables, &count, enginedata->safeeval);
738
739 if(status){
740 relname = rel_make_name(blsys->system, *relptr);
741 CONSOLE_DEBUG("ERROR calculating derivatives for relation '%s'",relname);
742 ASC_FREE(relname);
743 break;
744 }
745
746 /* output what's going on here ... */
747 #ifdef JEX_DEBUG
748 relname = rel_make_name(blsys->system, *relptr);
749 CONSOLE_DEBUG("RELATION %d '%s'",i,relname);
750 fprintf(stderr,"%d: '%s': ",i,relname);
751 ASC_FREE(relname);
752 for(j=0;j<count;++j){
753 varname = var_make_name(blsys->system, enginedata->varlist[variables[j]]);
754 var_yindex = blsys->y_id[variables[j]];
755 if(var_yindex >=0){
756 fprintf(stderr," var[%d]='%s'=y[%d]",variables[j],varname,var_yindex);
757 }else{
758 fprintf(stderr," var[%d]='%s'=ydot[%d]",variables[j],varname,-var_yindex-1);
759 }
760 ASC_FREE(varname);
761 }
762 fprintf(stderr,"\n");
763 #endif
764 /* insert values into the Jacobian row in appropriate spots (can assume Jac starts with zeros -- IDA manual) */
765 for(j=0; j < count; ++j){
766 var_yindex = blsys->y_id[variables[j]];
767 if(var_yindex >= 0){
768 asc_assert(blsys->y[var_yindex]==enginedata->varlist[variables[j]]);
769 DENSE_ELEM(Jac,i,var_yindex) += derivatives[j];
770 }else{
771 asc_assert(blsys->ydot[-var_yindex-1]==enginedata->varlist[variables[j]]);
772 DENSE_ELEM(Jac,i,-var_yindex-1) += derivatives[j] * c_j;
773 }
774 }
775 }
776
777 #ifdef JEX_DEBUG
778 CONSOLE_DEBUG("PRINTING JAC");
779 fprintf(stderr,"\t");
780 for(j=0; j < blsys->n_y; ++j){
781 if(j)fprintf(stderr,"\t");
782 varname = var_make_name(blsys->system,blsys->y[j]);
783 fprintf(stderr,"%11s",varname);
784 ASC_FREE(varname);
785 }
786 fprintf(stderr,"\n");
787 for(i=0; i < enginedata->nrels; ++i){
788 relname = rel_make_name(blsys->system, enginedata->rellist[i]);
789 fprintf(stderr,"%s\t",relname);
790 ASC_FREE(relname);
791
792 for(j=0; j < blsys->n_y; ++j){
793 if(j)fprintf(stderr,"\t");
794 fprintf(stderr,"%11.2e",DENSE_ELEM(Jac,i,j));
795 }
796 fprintf(stderr,"\n");
797 }
798 #endif
799
800 if(status){
801 ERROR_REPORTER_HERE(ASC_PROG_ERR,"There were derivative evaluation errors in the dense jacobian");
802 return 1;
803 }
804
805 #ifdef FEX_DEBUG
806 CONSOLE_DEBUG("DJEX RETURNING 0");
807 #endif
808 return 0;
809 }
810
811 /**
812 Function to evaluate the product J*v, in the form required for IDA (see IDASpilsSetJacTimesVecFn)
813
814 Given tt, yy, yp, rr and v, we need to evaluate and return Jv.
815
816 @param tt current value of the independent variable (time, t)
817 @param yy current value of the dependent variable vector, y(t).
818 @param yp current value of y'(t).
819 @param rr current value of the residual vector F(t, y, y').
820 @param v the vector by which the Jacobian must be multiplied to the right.
821 @param Jv the output vector computed
822 @param c_j the scalar in the system Jacobian, proportional to the inverse of the step size ($ \alpha$ in Eq. (3.5) ).
823 @param jac_data pointer to our stuff (blsys in this case, passed into IDA via IDASp*SetJacTimesVecFn.)
824 @param tmp1 @see tmp2
825 @param tmp2 (as well as tmp1) pointers to memory allocated for variables of type N_Vector for use here as temporary storage or work space.
826 @return 0 on success
827 */
828 int integrator_ida_jvex(realtype tt, N_Vector yy, N_Vector yp, N_Vector rr
829 , N_Vector v, N_Vector Jv, realtype c_j
830 , void *jac_data, N_Vector tmp1, N_Vector tmp2
831 ){
832 IntegratorSystem *blsys;
833 IntegratorIdaData *enginedata;
834 int i, j, is_error=0;
835 struct rel_relation** relptr;
836 char *relname;
837 int status;
838 double Jv_i;
839 int var_yindex;
840
841 int *variables;
842 double *derivatives;
843 var_filter_t filter;
844 int count;
845
846 #ifdef JEX_DEBUG
847 CONSOLE_DEBUG("EVALUATING JACOBIAN...");
848 #endif
849
850 blsys = (IntegratorSystem *)jac_data;
851 enginedata = integrator_ida_enginedata(blsys);
852
853 /* pass the values of everything back to the compiler */
854 integrator_set_t(blsys, (double)tt);
855 integrator_set_y(blsys, NV_DATA_S(yy));
856 integrator_set_ydot(blsys, NV_DATA_S(yp));
857 /* no real use for residuals (rr) here, I don't think? */
858
859 /* allocate space for returns from relman_diff2: we *should* be able to use 'tmp1' and 'tmp2' here... */
860 variables = ASC_NEW_ARRAY(int, NV_LENGTH_S(yy) * 2);
861 derivatives = ASC_NEW_ARRAY(double, NV_LENGTH_S(yy) * 2);
862
863 /* evaluate the derivatives... */
864 /* J = dG_dy = dF_dy + alpha * dF_dyp */
865
866 filter.matchbits = VAR_SVAR;
867 filter.matchvalue = VAR_SVAR;
868
869 Asc_SignalHandlerPushDefault(SIGFPE);
870 if (setjmp(g_fpe_env)==0) {
871 for(i=0, relptr = enginedata->rellist;
872 i< enginedata->nrels && relptr != NULL;
873 ++i, ++relptr
874 ){
875 /* get derivatives for this particular relation */
876 status = relman_diff2(*relptr, &filter, derivatives, variables, &count, enginedata->safeeval);
877 /* CONSOLE_DEBUG("Got derivatives against %d matching variables", count); */
878
879 if(status){
880 relname = rel_make_name(blsys->system, *relptr);
881 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Calculation error in rel '%s'",relname);
882 ASC_FREE(relname);
883 is_error = 1;
884 break;
885 }
886
887 /*
888 Now we have the derivatives wrt each alg/diff variable in the
889 present equation. variables[] points into the varlist. need
890 a mapping from the varlist to the y and ydot lists.
891 */
892
893 Jv_i = 0;
894 for(j=0; j < count; ++j){
895 /* CONSOLE_DEBUG("j = %d, variables[j] = %d, n_y = %ld", j, variables[j], blsys->n_y);
896 varname = var_make_name(blsys->system, enginedata->varlist[variables[j]]);
897 if(varname){
898 CONSOLE_DEBUG("Variable %d '%s' derivative = %f", variables[j],varname,derivatives[j]);
899 ASC_FREE(varname);
900 }else{
901 CONSOLE_DEBUG("Variable %d (UNKNOWN!): derivative = %f",variables[j],derivatives[j]);
902 }
903 */
904
905 var_yindex = blsys->y_id[variables[j]];
906 /* CONSOLE_DEBUG("j = %d: variables[j] = %d, y_id = %d",j,variables[j],var_yindex); */
907
908 if(var_yindex >= 0){
909 #ifdef JEX_DEBUG
910 asc_assert(blsys->y[var_yindex]==enginedata->varlist[variables[j]]);
911 fprintf(stderr,"Jv[%d] += %f (dF[%d]/dy[%d] = %f, v[%d] = %f)\n", i
912 , derivatives[j] * NV_Ith_S(v,var_yindex)
913 , i, var_yindex, derivatives[j]
914 , var_yindex, NV_Ith_S(v,var_yindex)
915 );
916 #endif
917 Jv_i += derivatives[j] * NV_Ith_S(v,var_yindex);
918 }else{
919 #ifdef JEX_DEBUG
920 fprintf(stderr,"Jv[%d] += %f (dF[%d]/dydot[%d] = %f, v[%d] = %f)\n", i
921 , derivatives[j] * NV_Ith_S(v,-var_yindex-1)
922 , i, -var_yindex-1, derivatives[j]
923 , -var_yindex-1, NV_Ith_S(v,-var_yindex-1)
924 );
925 #endif
926 asc_assert(blsys->ydot[-var_yindex-1]==enginedata->varlist[variables[j]]);
927 Jv_i += derivatives[j] * NV_Ith_S(v,-var_yindex-1) * c_j;
928 }
929 }
930
931 NV_Ith_S(Jv,i) = Jv_i;
932 #ifdef JEX_DEBUG
933 relname = rel_make_name(blsys->system, *relptr);
934 CONSOLE_DEBUG("'%s': Jv[%d] = %f", relname, i, NV_Ith_S(Jv,i));
935 ASC_FREE(relname);
936 return 1;
937 #endif
938 }
939 }else{
940 relname = rel_make_name(blsys->system, *relptr);
941 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Floating point error (SIGFPE) in rel '%s'",relname);
942 ASC_FREE(relname);
943 is_error = 1;
944 }
945 Asc_SignalHandlerPopDefault(SIGFPE);
946
947 if(is_error){
948 CONSOLE_DEBUG("SOME ERRORS FOUND IN EVALUATION");
949 return 1;
950 }
951 return 0;
952 }
953
954 /*----------------------------------------------
955 ERROR REPORTING
956 */
957 /**
958 Error message reporter function to be passed to IDA. All error messages
959 will trigger a call to this function, so we should find everything
960 appearing on the console (in the case of Tcl/Tk) or in the errors/warnings
961 panel (in the case of PyGTK).
962 */
963 void integrator_ida_error(int error_code
964 , const char *module, const char *function
965 , char *msg, void *eh_data
966 ){
967 IntegratorSystem *blsys;
968 error_severity_t sev;
969
970 /* cast back the IntegratorSystem, just in case we need it */
971 blsys = (IntegratorSystem *)eh_data;
972
973 /* severity depends on the sign of the error_code value */
974 if(error_code <= 0){
975 sev = ASC_PROG_ERR;
976 }else{
977 sev = ASC_PROG_WARNING;
978 }
979
980 /* use our all-purpose error reporting to get stuff back to the GUI */
981 error_reporter(sev,module,0,function,"%s (error %d)",msg,error_code);
982 }

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