To illustrate our questions, here is a MWE in the form of a simple one-equation ODE system:
$$\begin{aligned} & \dot y = \mathrm{mod}(t, 1)\\\ & y(t=0) = 0 \\\ & 0 \le t \le 10 \end{aligned}$$where $\mathrm{mod}(t, 1)$ stands for the fractional part of $t$.
The exact solution is a piece-wise parabola and we are mostly interested in the value at t=10 which is $y(t=10)=5$.
See the example code in the "To replicate" section below.
By default, CVode may give incorrect results because the ODE RHS is not continuous and therefore the solver may "step over" the discontinuity should it take a large enough step.
This is expected so we added a root function which triggers at each discontinuity of the RHS, that is for $t = k, k \in \mathbb N$:
static int root_fn(sunrealtype t, N_Vector y, sunrealtype *gout, void *user_data) { sunrealtype y1, b; y1 = Ith(y, 1); b = SUN_RCONST(1); // a jig-saw function which has roots at t = k, k being any integer *gout = fabs( fmod(t-b/2, 2*b) - b) - b/2; return 0; }
But now CVode()
returns CV_TOO_CLOSE
:
[ERROR][rank 0][/build/sundials-7.2.1/src/cvode/cvode.c:3710][cvHandleFailure] tout too close to t0 to start integration.
At t_out = 1.00e+01 t = 1.000000e+01 y1 = 5.0e+00 tcur = 1.0e+01 step = 0.0e+00 order = 0 err1 = -8.8e-07
retval = -27, return 1
t=10
. So we special cased CV_TOO_CLOSE
. At this point, if you're trying to reproduce the issue, you should uncomment this block at lines 153-159:else if (retval == CV_TOO_CLOSE) { /* This happens if tout is too close to t. In such a case, no solving was required; just continue as if solving succeeded. However, if the init step is set using CVodeSetInitStep, CVode DOES NOT RETURN CV_TOO_CLOSE, see below */ printf("retval == CV_TOO_CLOSE\n"); iout++; }
retval = CVodeSetInitStep(cvode_mem, INITSTEP); if (check_retval(&retval, "CVodeSetInitStep", 1)) { return (1); }
Now we have an infinite loop because CVode()
no longer returns CV_TOO_CLOSE
!
else if (retval == CV_ROOT_RETURN && t == tout) { /* See the above if the init step is set using CVodeSetInitStep, CVode DOES NOT RETURN CV_TOO_CLOSE when tout is too close to t In such a case, pretend that the root didn't happen, lest we keep handling it forever. */ printf("t == tout && retval == CV_ROOT_RETURN\n"); iout++; }
This seems to work but the results are actually incorrect since we have y(t=10) = 0.5 instead of 5:
At t_out = 1.00e+01 t = 1.000000e+01 y1 = 5.0e-01 tcur = 1.0e+01 step = 1.0e+00 order = 1 err1 = 0.0e+00
CVode()
does not return CV_TOO_CLOSE
when init step size is set?Sundials version: 7.2.1
example.zip contains an example.c
source file which you can compile with
gcc example.c -lsundials_cvode -lsundials_core -lm
and then run with
./a.out
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
To unsubscribe from the SUNDIALS-USERS list: write to: mailto:SUNDIALS-USERS-...@LISTSERV.LLNL.GOV
@sundials-users-github-account
Dear Alan, thank you for your answer
- Since the discontinuities in the RHS function occur at known times, the use of rootfinding is the wrong fix
The above was just an example, in general we do not know when the roots trigger, hence the need to use root finding. For fixed-time events (where we know in advance at what time they occur), we simply stop and re-init the solver as you explained.
- before restarting, the root function should be reset so that the same root is not seen twice
This is the part we were missing, thank you very much
- If the initial step is supplied, that error return is avoided. Perhaps this should be changed.
Since this was a surprise from a user perspective, I would say that indeed the same error should be returned when the initial step is supplied such that the behavior is consistent.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you were mentioned.