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

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