1 /*
2 * -----------------------------------------------------------------
3 * $Revision:$
4 * $Date:$
5 * -----------------------------------------------------------------
6 * Programmer: Radu Serban @ LLNL
7 * -----------------------------------------------------------------
8 * Copyright (c) 2006, The Regents of the University of California.
9 * Produced at the Lawrence Livermore National Laboratory.
10 * All rights reserved.
11 * For details, see the LICENSE file.
12 * -----------------------------------------------------------------
13 * This is the implementation for the event detection for CPODES.
14 * -----------------------------------------------------------------
15 */
16
17 /*
18 * =================================================================
19 * Import Header Files
20 * =================================================================
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26
27 #include "cpodes_private.h"
28 #include <sundials/sundials_math.h>
29
30 /*
31 * =================================================================
32 * Private Function Prototypes
33 * =================================================================
34 */
35
36 static booleantype cpRootAlloc(CPodeMem cp_mem, int nrt);
37 static int cpRootfind(CPodeMem cp_mem, realtype ttol);
38
39 /*
40 * =================================================================
41 * EXPORTED FUNCTIONS
42 * =================================================================
43 */
44
45 /*
46 * CPodeRootInit
47 *
48 * CPodeRootInit initializes a rootfinding problem to be solved
49 * during the integration of the ODE system. It loads the root
50 * function pointer and the number of root functions, and allocates
51 * workspace memory. The return value is CP_SUCCESS = 0 if no errors
52 * occurred, or a negative value otherwise.
53 */
54
CPodeRootInit(void * cpode_mem,int nrtfn,CPRootFn gfun,void * g_data)55 int CPodeRootInit(void *cpode_mem, int nrtfn, CPRootFn gfun, void *g_data)
56 {
57 CPodeMem cp_mem;
58 booleantype allocOK;
59 int i;
60
61 /* Check cpode_mem pointer */
62 if (cpode_mem == NULL) {
63 cpProcessError(NULL, CP_MEM_NULL, "CPODES", "CPodeRootInit", MSGCP_NO_MEM);
64 return(CP_MEM_NULL);
65 }
66 cp_mem = (CPodeMem) cpode_mem;
67
68 /* If called with nrtfn <= 0, then disable rootfinding and return */
69 if (nrtfn <= 0) {
70 cp_mem->cp_doRootfinding = FALSE;
71 return(CP_SUCCESS);
72 }
73
74 /* Check for legal input parameters */
75 if (gfun == NULL) {
76 cpProcessError(cp_mem, CP_ILL_INPUT, "CPODES", "CPodeRootInit", MSGCP_NULL_G);
77 return(CP_ILL_INPUT);
78 }
79
80 /* If rerunning CPodeRootInit() with a different number of root
81 * functions (changing number of gfun components), then free
82 * currently held memory resources */
83 if ( (cp_mem->cp_rootMallocDone) && (nrtfn != cp_mem->cp_nrtfn) ) {
84 cpRootFree(cp_mem);
85 cp_mem->cp_rootMallocDone = FALSE;
86 }
87
88 /* Allocate necessary memory and return */
89 if (!cp_mem->cp_rootMallocDone) {
90 allocOK = cpRootAlloc(cp_mem, nrtfn);
91 if (!allocOK) {
92 cpProcessError(cp_mem, CP_MEM_FAIL, "CPODES", "CPodeRootInit", MSGCP_MEM_FAIL);
93 return(CP_MEM_FAIL);
94 }
95 cp_mem->cp_rootMallocDone = TRUE;
96 }
97
98 /* Set variable values in CPODES memory block */
99 cp_mem->cp_nrtfn = nrtfn;
100 cp_mem->cp_gfun = gfun;
101 cp_mem->cp_g_data = g_data;
102
103 /* Set default values for rootdir (both directions)
104 * and for gactive (all active) */
105 for(i=0; i<nrtfn; i++) {
106 cp_mem->cp_rootdir[i] = 0;
107 cp_mem->cp_gactive[i] = TRUE;
108 }
109
110 /* Rootfinding is now enabled */
111 cp_mem->cp_doRootfinding = TRUE;
112
113 return(CP_SUCCESS);
114 }
115
116
117 /*
118 * =================================================================
119 * Readibility Constants
120 * =================================================================
121 */
122
123 #define uround (cp_mem->cp_uround)
124 #define tn (cp_mem->cp_tn)
125 #define h (cp_mem->cp_h)
126 #define zn (cp_mem->cp_zn)
127 #define y (cp_mem->cp_y)
128 #define yp (cp_mem->cp_yp)
129
130 #define lrw (cp_mem->cp_lrw)
131 #define liw (cp_mem->cp_liw)
132
133 #define taskc (cp_mem->cp_taskc)
134 #define toutc (cp_mem->cp_toutc)
135
136 #define nrtfn (cp_mem->cp_nrtfn)
137 #define gfun (cp_mem->cp_gfun)
138 #define g_data (cp_mem->cp_g_data)
139 #define nge (cp_mem->cp_nge)
140
141 #define gactive (cp_mem->cp_gactive)
142 #define iroots (cp_mem->cp_iroots)
143 #define rootdir (cp_mem->cp_rootdir)
144 #define irfnd (cp_mem->cp_irfnd)
145 #define tlo (cp_mem->cp_tlo)
146 #define thi (cp_mem->cp_thi)
147 #define glo (cp_mem->cp_glo)
148 #define ghi (cp_mem->cp_ghi)
149 #define trout (cp_mem->cp_trout)
150 #define grout (cp_mem->cp_grout)
151
152 /*
153 * =================================================================
154 * INTERNAL FUNCTIONS
155 * =================================================================
156 */
157
158 /*
159 * -----------------------------------------------------------------
160 * Root finding functions
161 * cpRcheck1 |
162 * cpRcheck2 |-> interface functions to CPode
163 * cpRcheck3 |
164 * cpRootfind
165 * -----------------------------------------------------------------
166 * Memory allocation/deallocation for rootfinding
167 * cpRootAlloc
168 * cpRootFree
169 * -----------------------------------------------------------------
170 */
171
172 /*
173 * cpRcheck1
174 *
175 * This routine completes the initialization of rootfinding memory
176 * information (it is called only once, at the very first step),
177 * and checks whether g has any components that are zero BOTH at AND
178 * very near the initial time of the IVP. Those components of g are
179 * made inactive and will be later reactivated only when they move
180 * away from zero.
181 *
182 * sherm 111125:
183 * thi (output only) set to tn
184 * ghi (output only) set to g(thi)
185 * where we may have advanced time by smallh to see whether g's that were zero
186 * at tn and deactivated can be reactivated at tn+smallh.
187 *
188 * The return value will be
189 * CV_RTFUNC_FAIL < 0 if the g function failed
190 * CP_SUCCESS = 0 otherwise.
191 */
192
cpRcheck1(CPodeMem cp_mem)193 int cpRcheck1(CPodeMem cp_mem)
194 {
195 int i, retval;
196 realtype ttol, smallh, hratio;
197 booleantype zroot;
198
199 for (i = 0; i < nrtfn; i++) iroots[i] = 0;
200
201 thi = tlo = tn;
202 ttol = (ABS(tn) + ABS(h))*uround*FUZZ_FACTOR;
203
204 /*
205 * Evaluate g at initial t and check for zero values.
206 * Note that cpRcheck1 is called at the first step
207 * before scaling zn[1] and therefore, y'(t0)=zn[1].
208 */
209
210 retval = gfun(tlo, zn[0], zn[1], glo, g_data);
211 nge = 1;
212 if (retval != 0) return(CP_RTFUNC_FAIL);
213
214 /* Assume we won't find a root at the start. */
215 for (i = 0; i < nrtfn; i++) ghi[i] = glo[i];
216
217 zroot = FALSE;
218 for (i = 0; i < nrtfn; i++) {
219 if (ABS(glo[i]) == ZERO) {
220 zroot = TRUE;
221 gactive[i] = FALSE;
222 }
223 }
224 if (!zroot) return(CP_SUCCESS);
225
226 /*
227 * Some g_i is zero at t0; look at g at t0+(small increment).
228 * At the initial time and at order 1, we have:
229 * y(t0+smallh) = zn[0] + (smallh/h) * zn[1]
230 * y'(t0+smallh) = zn[1]
231 */
232
233 hratio = MAX(ttol/ABS(h), PT1);
234 smallh = hratio*h;
235 thi += smallh;
236 N_VLinearSum(ONE, zn[0], hratio, zn[1], y);
237 retval = gfun(thi, y, zn[1], ghi, g_data);
238 nge++;
239 if (retval != 0) return(CP_RTFUNC_FAIL);
240
241 /*
242 * We check now only the components of g which were exactly
243 * zero at t0 to see if we can 'activate' them.
244 */
245
246 for (i = 0; i < nrtfn; i++) {
247 if (!gactive[i] && ABS(ghi[i]) != ZERO) {
248 gactive[i] = TRUE;
249 }
250 }
251
252 return(CP_SUCCESS);
253 }
254
255
256 /*
257 * cpRcheck2
258 *
259 * This routine is called at the beginning of a step to find the beginning tlo
260 * of the next root search interval, which is usually the end (thi) of the
261 * previous search interval. But it first checks for exact zeros of any active
262 * g at thi. It then checks for a close pair of zeros (a condition that
263 * would trigger making inactive the corresponding components
264 * of g), and for a new root at a nearby point.
265 * The endpoint thi of the previous search interval is thus adjusted
266 * if necessary to assure that all active g_i are nonzero there,
267 * before returning to do a root search in the interval.
268 *
269 * On entry, thi = tretlast is the last value of tret returned by
270 * CPode. This may be the previous tn, the previous tout value, or
271 * the last root location.
272 *
273 * This routine returns an int equal to:
274 * CP_RTFUNC_FAIL < 0 if gfun failed
275 * RTFOUND > 0 if a new zero of g was found near tlo, or
276 * CP_SUCCESS = 0 otherwise.
277 */
278
cpRcheck2(CPodeMem cp_mem)279 int cpRcheck2(CPodeMem cp_mem)
280 {
281 int i, retval;
282 realtype ttol, smallh, hratio;
283 booleantype zroot;
284
285 /* Move tlo up to end of previous search interval in case we find a root
286 here. */
287 tlo = thi;
288 /* Evaluate g(tlo) */
289 (void) cpGetSolution(cp_mem, tlo, y, yp);
290 retval = gfun(tlo, y, yp, glo, g_data);
291 nge++;
292 if (retval != 0) return(CP_RTFUNC_FAIL);
293
294 /* Assume we won't find a root at the start. */
295 for (i = 0; i < nrtfn; i++) ghi[i] = glo[i];
296
297 /* Check if any active g function is exactly ZERO at tlo.
298 * If not, simply return CP_SUCCESS. */
299
300 zroot = FALSE;
301 for (i = 0; i < nrtfn; i++) iroots[i] = 0;
302 for (i = 0; i < nrtfn; i++) {
303 if (!gactive[i]) continue;
304 if (ABS(glo[i]) == ZERO) {
305 zroot = TRUE;
306 iroots[i] = 1;
307 }
308 }
309
310 /* If no root then tlo==thi, glo==ghi. */
311 if (!zroot) return(CP_SUCCESS);
312
313 /* One or more g_i has a zero at tlo.
314 * Evaluate g(thi=tlo+smallh). */
315
316 ttol = (ABS(tn) + ABS(h))*uround*FUZZ_FACTOR;
317 smallh = (h > ZERO) ? ttol : -ttol;
318 thi = tlo+smallh;
319 if ( (thi - tn)*h >= ZERO) {
320 hratio = smallh/h;
321 N_VLinearSum(ONE, y, hratio, zn[1], y);
322 } else {
323 (void) cpGetSolution(cp_mem, thi, y, yp);
324 }
325 retval = gfun(thi, y, yp, ghi, g_data);
326 nge++;
327 if (retval != 0) return(CP_RTFUNC_FAIL);
328
329 /* Check if any active function is ZERO at thi+smallh.
330 * Make inactive those that were also ZERO at thi.
331 * Report a root for those that only became ZERO at tlo+smallh. */
332
333 zroot = FALSE;
334 for (i = 0; i < nrtfn; i++) {
335 if (ABS(ghi[i]) == ZERO) {
336 if (!gactive[i]) continue;
337 if (iroots[i] == 1) { iroots[i] = 0; gactive[i] = FALSE; }
338 else { iroots[i] = 1; zroot = TRUE; }
339 }
340 }
341
342 if (zroot) return(RTFOUND);
343
344 return(CP_SUCCESS);
345 }
346
347 /*
348 * cpRcheck3
349 *
350 * This routine interfaces to cpRootfind to look for a root of g
351 * between tlo and either tn or tout, whichever comes first.
352 * Only roots beyond tlo in the direction of integration are sought.
353 *
354 * On entry, both thi and ghi=g(thi) should have been evaluated. We start by
355 * setting tlo=thi and glo=ghi, shiting the search interval to start at the
356 * end of the previous one.
357 * On return, if there is a root it is in (tlo,thi] which will have been
358 * adjusted to a very narrow bracket around the zero crossing. If there is no
359 * root then thi and ghi are at the end of the search interval, where they can
360 * serve as the start for the next one.
361 *
362 * This routine returns an int equal to:
363 * CP_RTFUNC_FAIL < 0 if the g function failed,
364 * RTFOUND > 0 if a root of g was found, or
365 * CP_SUCCESS = 0 otherwise.
366 */
367
cpRcheck3(CPodeMem cp_mem)368 int cpRcheck3(CPodeMem cp_mem)
369 {
370 int i, retval, ier;
371 realtype ttol;
372
373 /* Move start of search interval to end of previous one. */
374 tlo = thi;
375 for (i = 0; i < nrtfn; ++i) glo[i] = ghi[i];
376
377 /* Set thi = tn or tout, whichever comes first. */
378 switch (taskc) {
379 case CP_ONE_STEP:
380 thi = tn;
381 break;
382 case CP_NORMAL:
383 thi = ( (toutc - tn)*h >= ZERO) ? tn : toutc;
384 break;
385 }
386
387 /* Get y and y' at thi. */
388 (void) cpGetSolution(cp_mem, thi, y, yp);
389
390 /* Set ghi = g(thi) */
391 retval = gfun(thi, y, yp, ghi, g_data);
392 nge++;
393 if (retval != 0) return(CP_RTFUNC_FAIL);
394
395 /* Call cpRootfind to search (tlo,thi) for roots, and to modify tlo,thi
396 to create a very narrow bracket around the first root. */
397 ttol = (ABS(tn) + ABS(h))*uround*FUZZ_FACTOR;
398 ier = cpRootfind(cp_mem, ttol);
399
400 /* If the root function g failed, return now */
401 if (ier == CP_RTFUNC_FAIL) return(CP_RTFUNC_FAIL);
402
403 /* If any of the inactive components moved away from zero,
404 * activate them now. */
405 for(i=0; i<nrtfn; i++) {
406 if(!gactive[i] && grout[i] != ZERO) gactive[i] = TRUE;
407 }
408
409 /* If no root found, return CP_SUCCESS. */
410 if (ier == CP_SUCCESS) return(CP_SUCCESS);
411
412 /* If a root was found, interpolate to get y(trout) and return. */
413 (void) cpGetSolution(cp_mem, trout, y, yp);
414
415 return(RTFOUND);
416 }
417
418 /*
419 * cpRootFind
420 *
421 * This routine solves for a root of g(t) between tlo and thi, if
422 * one exists. Only roots of odd multiplicity (i.e. with a change
423 * of sign in one of the g_i), or exact zeros, are found.
424 * Here the sign of tlo - thi is arbitrary, but if multiple roots
425 * are found, the one closest to tlo is returned.
426 *
427 * The method used is the Illinois algorithm, a modified secant method.
428 * Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly
429 * Defined Output Points for Solutions of ODEs, Sandia National
430 * Laboratory Report SAND80-0180, February 1980.
431 *
432 * This routine uses the following parameters for communication:
433 *
434 * nrtfn = number of functions g_i, or number of components of
435 * the vector-valued function g(t). Input only.
436 *
437 * gfun = user-defined function for g(t). Its form is
438 * (void) gfun(t, y, gt, g_data)
439 *
440 * gactive = array specifying whether a component of g should
441 * or should not be monitored. gactive[i] is initially
442 * set to TRUE for all i=0,...,nrtfn-1, but it may be
443 * reset to FALSE if at the first step g[i] is 0.0
444 * both at the I.C. and at a small perturbation of them.
445 * gactive[i] is then set back on TRUE only after the
446 * corresponding g function moves away from 0.0.
447 *
448 * rootdir = array specifying the direction of zero-crossings.
449 * If rootdir[i] > 0, search for roots of g_i only if
450 * g_i is increasing; if rootdir[i] < 0, search for
451 * roots of g_i only if g_i is decreasing; otherwise
452 * always search for roots of g_i.
453 *
454 * nge = cumulative counter for gfun calls.
455 *
456 * ttol = a convergence tolerance for trout. Input only.
457 * When a root at trout is found, it is located in time only to
458 * within a tolerance of ttol. Typically, ttol should
459 * be set to a value on the order of
460 * 100 * UROUND * max (ABS(tlo), ABS(thi))
461 * where UROUND is the unit roundoff of the machine.
462 *
463 * tlo, thi = endpoints of the interval in which roots are sought.
464 * On input, they must be distinct, but tlo - thi may
465 * be of either sign. The direction of integration is
466 * assumed to be from tlo to thi. On return, tlo and thi
467 * are the endpoints of the final relevant interval (tlo,thi];
468 * that is, the root has not yet occurred at tlo but has
469 * definitely occurred by thi. The reported root time trout is
470 * always the same as thi.
471 *
472 * glo, ghi = arrays of length nrtfn containing the vectors g(tlo)
473 * and g(thi) respectively. Input and output. On input,
474 * none of the active glo[i] should be zero.
475 *
476 * trout = root location (same as thi), if a root was found, or the original
477 * value of thi if not. Output only. trout is the endpoint thi of
478 * the final interval (tlo,thi] bracketing the root, with |thi-tlo|
479 * at most ttol.
480 *
481 * grout = array of length nrtfn containing g(trout) (==ghi) on return.
482 *
483 * iroots = int array of length nrtfn with root information.
484 * Output only. If a root was found, iroots indicates
485 * which components g_i have a root at trout. For
486 * i = 0, ..., nrtfn-1, iroots[i] = 1 if g_i has a root
487 * and g_i is increasing, iroots[i] = -1 if g_i has a
488 * root and g_i is decreasing, and iroots[i] = 0 if g_i
489 * has no roots or g_i varies in the direction opposite
490 * to that indicated by rootdir[i].
491 *
492 * This routine returns an int equal to:
493 * CP_RTFUNC_FAIL < 0 if gfun faild
494 * RTFOUND > 0 if a root of g was found, or
495 * CP_SUCCESS = 0 otherwise.
496 */
cpRootfind(CPodeMem cp_mem,realtype ttol)497 static int cpRootfind(CPodeMem cp_mem, realtype ttol)
498 {
499 realtype alpha, tmid, my_tmid, tmid_saved, thi_saved, fracint, fracsub;
500 int i, retval, side, sideprev;
501 booleantype zroot;
502
503 /* alpha is a bias weight in the secant method.
504 * On the first two passes, set alpha = 1. Thereafter, reset alpha
505 * according to the side (low vs high) of the subinterval in which
506 * the sign change was found in the previous two passes.
507 * If the sides were opposite, set alpha = 1.
508 * If the sides were the same, then double alpha (if high side),
509 * or halve alpha (if low side).
510 * The next guess tmid is the secant method value if alpha = 1, but
511 * is closer to tlo if alpha < 1, and closer to thi if alpha > 1.
512 */
513 alpha = ONE;
514
515 /* First, for each active g function, check whether an event occurred in
516 * (tlo,thi). Since glo != 0 for an active component, this means we check for
517 * a sign change or for ghi = 0 (taking into account rootdir). For each
518 * component that triggers an event, we estimate a "proposal" mid point (by
519 * bisection if ghi=0 or with secant method otherwise) and select the one
520 * closest to tlo. */
521 zroot = FALSE;
522 tmid = thi;
523 for (i = 0; i < nrtfn; i++) {
524 if(!gactive[i]) continue;
525
526 if ( (glo[i]*ghi[i] <= ZERO) && (rootdir[i]*glo[i] <= ZERO) ) {
527 zroot = TRUE;
528 if (ghi[i] == ZERO) {
529 my_tmid = thi - HALF * (thi-tlo);
530 } else {
531 my_tmid = thi - (thi - tlo)*ghi[i]/(ghi[i] - alpha*glo[i]);
532 }
533 /* Pick my_tmid if it is closer to tlo than the current tmid. */
534 if ( (my_tmid-tmid)*h < ZERO ) tmid = my_tmid;
535 }
536 }
537
538 /* If no event was detected, set trout to thi and return CP_SUCCESS */
539 if (!zroot) {
540 trout = thi;
541 for (i = 0; i < nrtfn; i++) grout[i] = ghi[i];
542 return(CP_SUCCESS);
543 }
544
545 /* An event was detected. Loop to locate nearest root. */
546 side = 0;
547
548 loop {
549 sideprev = side;
550
551 /* If tmid is too close to tlo or thi, adjust it inward,
552 * by a fractional distance that is between 0.1 and 0.5. */
553 if (ABS(tmid - tlo) < HALF*ttol) {
554 fracint = ABS(thi - tlo)/ttol;
555 fracsub = (fracint > FIVE) ? PT1 : HALF/fracint;
556 tmid = tlo + fracsub*(thi - tlo);
557 }
558 if (ABS(thi - tmid) < HALF*ttol) {
559 fracint = ABS(thi - tlo)/ttol;
560 fracsub = (fracint > FIVE) ? PT1 : HALF/fracint;
561 tmid = thi - fracsub*(thi - tlo);
562 }
563
564 /* Get solution at tmid and evaluate g(tmid). */
565 (void) cpGetSolution(cp_mem, tmid, y, yp);
566 retval = gfun(tmid, y, yp, grout, g_data);
567 nge++;
568 if (retval != 0) return(CP_RTFUNC_FAIL);
569
570 /* Check (tlo, tmid) to see if an event occurred in the "low" side
571 * First make temporary copies of thi and tmid in case the event
572 * turns out to be on the "high" side. */
573 tmid_saved = tmid;
574 thi_saved = thi;
575 thi = tmid;
576 zroot = FALSE;
577 for (i = 0; i < nrtfn; i++) {
578 if(!gactive[i]) continue;
579
580 if ( (glo[i]*grout[i] <= ZERO) && (rootdir[i]*glo[i] <= ZERO) ) {
581 zroot = TRUE;
582 if (grout[i] == ZERO) {
583 my_tmid = thi - HALF * (thi-tlo);
584 } else {
585 my_tmid = thi - (thi - tlo)*grout[i]/(grout[i] - alpha*glo[i]);
586 }
587 if ( (my_tmid-tmid)*h < ZERO ) tmid = my_tmid;
588 }
589 }
590
591 /* If we detected an event in the "low" side:
592 - accept current value of thi
593 - set ghi <- grout
594 - test for convergence and break from loop if converged
595 - set side=1 (low); if previous side was also 1, scale alpha by 1/2
596 - continue looping to refine root location */
597 if (zroot) {
598 for (i = 0; i < nrtfn; i++) ghi[i] = grout[i];
599 if (ABS(thi - tlo) <= ttol) break;
600
601 side = 1;
602 if (sideprev == 1) alpha = alpha*HALF;
603 else alpha = ONE;
604
605 continue;
606 }
607
608 /* No event detected in "low" side; event must be in "high" side.
609 - restore previously saved values for thi and set tlo = tmid_saved
610 - set glo <- grout
611 - test for convergence and break from loop if converged
612 - set side=2 (high); if previous side was also 2, scale alpha by 2
613 - continue looping to refine root location */
614 thi = thi_saved;
615 tlo = tmid_saved;
616
617 for (i = 0; i < nrtfn; i++) glo[i] = grout[i];
618 if (ABS(thi - tlo) <= ttol) break;
619
620 tmid = thi;
621 for (i = 0; i < nrtfn; i++) {
622 if(!gactive[i]) continue;
623
624 if ( (glo[i]*ghi[i] <= ZERO) && (rootdir[i]*glo[i] <= ZERO) ) {
625 if (ghi[i] == ZERO) {
626 my_tmid = thi - HALF * (thi-tlo);
627 } else {
628 my_tmid = thi - (thi - tlo)*ghi[i]/(ghi[i] - alpha*glo[i]);
629 }
630 if ( (my_tmid-tmid)*h < ZERO ) tmid = my_tmid;
631 }
632 }
633
634 side = 2;
635 if (sideprev == 2) alpha = alpha*TWO;
636 else alpha = ONE;
637
638 } /* End of root-search loop */
639
640 /* Root has been isolated to (tlo,thi] and |thi-tlo| <= ttol. We'll declare
641 that the root was found at trout=thi.
642 - Reset trout and grout
643 - Set iroots
644 - Return RTFOUND. */
645 trout = thi;
646 for (i = 0; i < nrtfn; i++) {
647 grout[i] = ghi[i];
648 iroots[i] = 0;
649 if(!gactive[i]) continue;
650 if ( (glo[i]*ghi[i] <= ZERO) && (rootdir[i]*glo[i] <= ZERO) )
651 iroots[i] = glo[i] > 0 ? -1:1;
652 }
653
654 return(RTFOUND);
655 }
656
657
658
659 /*
660 * cpRootAlloc allocates memory for the rootfinding algorithm.
661 */
662
cpRootAlloc(CPodeMem cp_mem,int nrt)663 static booleantype cpRootAlloc(CPodeMem cp_mem, int nrt)
664 {
665 glo = NULL;
666 glo = (realtype *) malloc(nrt*sizeof(realtype));
667
668 ghi = NULL;
669 ghi = (realtype *) malloc(nrt*sizeof(realtype));
670 if (ghi == NULL) {
671 free(glo); glo = NULL;
672 return(FALSE);
673 }
674
675 grout = NULL;
676 grout = (realtype *) malloc(nrt*sizeof(realtype));
677 if (grout == NULL) {
678 free(glo); glo = NULL;
679 free(ghi); ghi = NULL;
680 return(FALSE);
681 }
682
683 iroots = NULL;
684 iroots = (int *) malloc(nrt*sizeof(int));
685 if (iroots == NULL) {
686 free(glo); glo = NULL;
687 free(ghi); ghi = NULL;
688 free(grout); grout = NULL;
689 return(FALSE);
690 }
691
692 rootdir = NULL;
693 rootdir = (int *) malloc(nrt*sizeof(int));
694 if (rootdir == NULL) {
695 free(glo); glo = NULL;
696 free(ghi); ghi = NULL;
697 free(grout); grout = NULL;
698 free(iroots); iroots = NULL;
699 }
700
701 gactive = NULL;
702 gactive = (booleantype *) malloc(nrt*sizeof(booleantype));
703 if (gactive == NULL) {
704 free(glo); glo = NULL;
705 free(ghi); ghi = NULL;
706 free(grout); grout = NULL;
707 free(iroots); iroots = NULL;
708 free(rootdir); rootdir = NULL;
709 }
710
711 lrw += 3*nrt;
712 liw += 3*nrt;
713
714 return(TRUE);
715 }
716
717
718 /*
719 * cpRootFree frees the memory allocated in cpRootAlloc.
720 */
721
cpRootFree(CPodeMem cp_mem)722 void cpRootFree(CPodeMem cp_mem)
723 {
724 free(glo); glo = NULL;
725 free(ghi); ghi = NULL;
726 free(grout); grout = NULL;
727 free(gactive); gactive = NULL;
728 free(iroots); iroots = NULL;
729 free(rootdir); rootdir = NULL;
730
731 lrw -= 3 * nrtfn;
732 liw -= 3 * nrtfn;
733 }
734
735