-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Look into BackTracking effect on new test model #1705
Comments
I guess it's possible that storage still ends up just barely negative somehow and one of the |
We reject any timesteps that lead to negative storage #1406. Or perhaps that is too late for this, which is triggered during nonlinear iterations? |
Hmm good point. It shouldn't be too late: if it converges with a negative storage, it should still be rejected. Maybe some term that isn't smooth enough around S = 0? Does any other water balance term jump? |
Yeah perhaps we are stepping completely over a reduction factor here. The inflow is 29 m3/s and the outflow 62 m3/s. The outflow should go down to the inflow due to the reduction factors, but all I see is a brief minor dip in the outflow over the Outlet (50 m3/s), and no reduced flow to the UserDemand (12 m3/s). The complete water balance at the start of the anomaly:
The model looks like this: And can be downloaded here: The results with v2024.10.0 look much better. When in > out, the storage is going up from 0, when out > in, the storage goes down to 0. When storage is 0, out will never go above in, so they are the same. |
A few more observations. QNDF, TRBDF2 and KenCarp4 all have similar issues. If you reduce the tolerances you get an unstable error. ImplicitEuler does seem to produce the correct results with backtracking. On the HWS model I couldn't directly eyeball large convergence issues with QNDF, though there are no empty Basins there. HWS with backtracking runs in 47s for QNDF and in 2m19 for ImplicitEuler. Perhaps for now we should make backtracking opt-in for now while we explore this issue. Perhaps we can look at what is happening with backtracking more in detail, based on SciML/OrdinaryDiffEq.jl#1792. This made me realize #1413 needs a v1.0 label, because that helps to just error out on these issues to protect users. |
@visr you can also try different linesearch algorithms for relaxation (https://github.com/JuliaNLSolvers/LineSearches.jl) but some more insight would be very helpful. Also, we've probably discussed this before, but what about incorporating the water balance error in |
Yeah I can do that next week. I think the water balance error is important to address, #1413., Not sure if |
Just to make sure I'm reading properly: the upper plots show timeseries that are totally wrong? It flies off course immediately, right? And secondly: the same solver doesn't run into this problem when there's no relaxation? In my understanding, the relaxation only limits the update of the Newton-Rhapson step. The check for convergence should be the same -- so I don't understand how it finds such a radically different solution. |
@Huite you say limits the step and I thought so too, but I haven't seen anything in the linesearch code that indicates that the step cannot be bigger than the original Newton step |
Doing some homework on the solvers:
The DiffEq docs mention:
Curious whether CVODE_BDF or lsoda fail in a similar way. |
I think it's this in: α is the size of the update, default size is 1: α_0::Tα = real(T)(1) α = 1 is a standard Newton step. Then it's updated: α_0 = min(α_0, min(alphamax, ls.maxstep / norm(s, Inf))) So α_0 shouldn't exceed 1.0 (unless you fiddle with it?). Then in the actual function, it's doing interpolation via either a quadratic or a cubic and finding the zero for it. α_1, α_2 = αinitial, αinitial
# interpolation
# ...
α_tmp = NaNMath.min(α_tmp, α_2*ρ_hi) # avoid too small reductions
α_2 = NaNMath.max(α_tmp, α_2*ρ_lo) # avoid too big reductions Defined above: ρ_hi::TF = 0.5
ρ_lo::TF = 0.1 So after the first iteration 0.1 <= α_2 <= 0.5. Afterwards, it should only get smaller. (Unless something's changing defaults.) |
To get a slightly better feeling for these methods: https://www.stochasticlifestyle.com/differences-between-methods-for-solving-stiff-odes/ |
TL;DR: I still think we should give this a try.
@visr that is not how it is implemented now, but that is what is suggested here. Currently outflows of a basin don't depend on inflows (only on the storage), but to me it makes sense that that would be the case. Note that this adds new non-zeros to the Jacobian, which is much easier to play with with #1606 in place (at least we can test with dense Jacobians). Additionally, with the current implementation it is much more finnicky to find a steady state solution for depleted basins with in- and outflow (the solver has to find exactly that storage where the reduction factor makes the outflow match the inflow, in hindsight that's probably what you meant Martijn) than with the aforementioned suggestion. I played around a bit with writing a custom line search algorithm, from which I learned that:
I also learned (with the help of claude.ai) that |
But the storage does depend on the inflows, and outflows depends on the storage. So in the (linearized) system of equations outflows clearly do depend on the inflows.
So the result of a Newton iteration might contain negative storages? Does this mean it's calling the rhs function (
I don't follow why is is more finnicky? Isn't a basin always above depletion if there's still outflow? The outflow is distributed across different terms, each very small. The linearized problem provides enough information that the linear solver can find such a point, although it may result in negative storage. If the next rhs evaluation results in setting all outflows to 0, the next iteration should result in a small positive storage again. Apparently the solver will dip into negative storage, re-formulate, and then converge with (wrong) positive storages -- otherwise the solution would be rejected. Shouldn't that go away it outflow becomes zero with negative storage then? |
Might be relevant, docstring of the PositiveDomain callback (sorry for the garbled math statements):
|
Good point, I remember reading this. The Shampine paper is this one: https://www.sciencedirect.com/science/article/abs/pii/S0096300304009683 From the PDF, with non-garbled math: My first suggestion now would be to add some unit tests to enforce |
Ha, we had implemented that advice but removed it when we started using EDIT: For the test model I see negative storage, but not with a negative du, so it had no effect. |
Uh I think setting the total Instead, I think you should allow positive individual terms (inflow e.g. precipitation), but truncate individual negative terms. That way, if you end up below zero it can still go back in the positive. EDIT: pretty sure this is what MODFLOW 6 does for the NPF (internodal flows) Newton formulation too. |
Fixed by #1761. |
#1697 increased the performance considerably, and passed the tests with only slightly higher tolerances.
Surprisingly @Fati-Mon observed this behavior on a Basin running dry:
We need to look into what is going on here.
The text was updated successfully, but these errors were encountered: