-
Notifications
You must be signed in to change notification settings - Fork 164
Root function where g(x) = g(x + d) = 0 #881
Description
Hello.
General problem
In the sundial documentation, at least for IDA, it is noted that the root finding logic will generate an error if after finding a root such as g(x) = 0, sundials will try g(x + d) (where d is small) and if it is equal to 0 too, it will fail to ensure that at any point in time we know from which side of the root we are.
The documentation for IDASolve, https://sundials.readthedocs.io/en/latest/ida/Usage/index.html#c.IDASolve, states that it will return IDA_ILL_INPUT in this context.
What is the recommended way to handle such a case?
My context
I'm solving arbitrary problems: users provides a set of ode / algebraic rules, and my program use sundial to solve that.
The ode provided by the user may contain discontinuities (e.g. dx / dt = if g > 20 then y else z). In order to not miss some possibly important discontinuities, we use root finding in order to detect the discontinuity, stop the solver, change the relevant values, restart. Without this, we can miss important / short phenomenums. For example if we have dx/dt = if t > 20 and t < 20.1 then 10000 else 0 we expect an important change of x, however a step larger than 0.1 may miss it.
The root function are not provided by the user, we extract them from the different equations of the problem. For the two previous examples, we introduce roots functions r such as r_0 = g - 20 = 0, r_1 = t - 20 = 0 and r_2 = t - 20.1 = 0 as root functions and stop the solver accordingly.
Unfortunately, we can generate functions for which r(x) = r(x + d) = 0, this is a bit out of our hand (e.g. because it depends on user input) and until now I had not been able to find a robust solution.
Robust solution
The only idea I do have right now is to store in user data a context about the root value and sign and when the root function is called and a 0 is found, lookup in the context to see if a 0 was found previously at a close distance, and if yes, instead of returning a 0, return a small value of a different sign than the value observed in previous calls on the left of the current timepoint. This is impressively ugly.
Not robust solution, detecting IDASolve fail and ignoring the problem
So right now my only solution is to handle the problem when it arise, e.g. when IDASolve fails with IDA_ILL_INPUT.
I hence do have multiples questions:
a) When this happen, how do I detect that I'm in this context? I can get the error message and hope it matchs Root found at and very near, but that's not robust.
b) Am I guaranteed to be stopped at the root location? The documentation states that the value of tret is the farthest point reached during the integration.
c) How do I detect which condition is 0? IDAGetRootInfo tells me which function had changed sign or are ==0, but how can I detect which one have triggered the error? Is the result of IDAGetRootInfo even guranteed to be relevant?
d) Once I detected that I may be in a weird state, I may decide to restart the solver. If I restart it at the current time, I suppose it will fail (because the root function is =0, so it does not know how to initialize it). A hack could be to advance by a small amount and hope for the best. I may also disable the root function which are problematic, but I would want to reenable them as soon as possible.
Of course I can experiment with sundials to get most of the answer to these questions, but it will be implementation based and may not be robust, hence why I asking theses questions here.
In summary, do you have any suggestion to handle this very specific case?
Thank you.