-
Notifications
You must be signed in to change notification settings - Fork 117
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
Fixed indexing error in PID controller #4855
base: master
Are you sure you want to change the base?
Conversation
jenkins build this please |
Hm, if this is indeed wrong–I don't have the reference on hand for easy verification–then it's an error that's been with us for a very long time. As far as I can tell this code was first introduced in OPM/opm-core#662 and has remained more or less unchanged, though moved and renamed a number of times, since then. |
After looking at it quite a few times, I'm more or less certain that the indexing was wrong in the original implementation. And yes, the PID controller in OPM has remained unchanged since at least 2015. The time stepping algorithm seems to have been adapted to the current PID controller implementation, so there might be a need to update other parts and/or default parameter values to make it work with the new implementation. That said, there is nothing inherently wrong with using the existing version, but as it stands now it is not a correct implementation of the PID controller as derived in the literature. |
Note that the PID controller has in my opinion never worked as intended. It was therefore removed as the default time-stepper long time ago. Thanks for looking into this. If you can make it to work, it would be great. |
benchmark please |
Our current default is "pid+newtoniteration" which still includes the erroneous pid implementation. I am very much in favour of merging this to correct it, but we must deal with the fallout including failed tests etc. and potentially also change other things as suggested by @erikhide:
Just a hunch: I cannot remember to have ever seen the verbose messages from the PID function. It might of course be activated in some places, but is it possible that it never was, and only after the current change is it relevant? If so, we could try to make the default TimeStepControl just "newtoniteration" and see if that is easier to deal with. |
Benchmark result overview:
View result details @ https://www.ytelses.com/opm/?page=result&id=2228 |
The benchmark results looks very promising.
My memory is getting worse. I remember looking into this 5 years ago and concluded that PID didn't work as expected but I never noticed the bug. I agree with @atgeirr that this should be merged and with @erikhide that we need to test this and possibly also tune the timestepping differently. Have you done any testing on only using "pid". The "newton" part have some issues at the moment. For some cases it can get stuck on very small timesteps due to some unlucky combinations of NUPCOL and group/well switching. |
I have tried to use only "pid" as input to I'm also working on some other alternatives (other heuristics than the PID controller, as well as other versions of the PID controller itself), and I'm trying to decide how best to compare different time stepping algorithms to ensure both fast computations and robust behaviour. This might take some time, but hopefully possible improvements will come sometime in the near future. |
This is very exciting news! Thank you so much for attacking this area 👍 |
@@ -206,7 +206,7 @@ namespace Opm | |||
const double kD = 0.01 ; | |||
const double newDt = (dt * std::pow( errors_[ 1 ] / errors_[ 2 ], kP ) * | |||
std::pow( tol_ / errors_[ 2 ], kI ) * | |||
std::pow( errors_[0]*errors_[0]/errors_[ 1 ]/errors_[ 2 ], kD )); | |||
std::pow( errors_[1]*errors_[1]/errors_[ 0 ]/errors_[ 2 ], kD )); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've looked a little bit closer at this. Suppose errors_[0] == 0
, which it theoretically could be since the conditional above only checks errors_[1]
and errors_[2]
. Then newDt
will be non-finite, typically inf
. Is that reasonable here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the errors_[1]
and errors[2]
were included in the conditional because they appeared in the denominators of the PID formula, and hence it was only relevant to check those. However, having changed indexing, errors_[0]
(and not errors_[1]
) appears in the denominator. It might therefore be reasonable to add errors[0]
to (and possibly just remove errors_[1]
from) the conditional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might therefore be reasonable to add
errors[0]
to [...] the conditional.
Yes, that's probably needed.
and possibly just remove
errors_[1]
from the conditional
I'd be wary of doing that. If errors_[1] = 0
we'll get newDt = 0
as well and that seems unexpected to me. Maybe I'm just misunderstanding something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're probably right. It appears that that might have been a problem earlier, though. Regardless, it certainly shouldn't hurt to add errors_[0] == 0
to the conditional.
I added it now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that that (
errors_[0] = 0
givingnewDt = 0
) might have been a problem earlier, though
Agreed. I only remarked on this possibility because we're in the area now so it's an opportunity to fix it. For what it's worth, I tried this PR on a field case and ran into that exact problem. Otherwise I might not have noticed it.
jenkins build this please |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the update. I think this is starting to look good so I'm running a build check to assess the impact of the change.
@@ -206,7 +206,7 @@ namespace Opm | |||
const double kD = 0.01 ; | |||
const double newDt = (dt * std::pow( errors_[ 1 ] / errors_[ 2 ], kP ) * | |||
std::pow( tol_ / errors_[ 2 ], kI ) * | |||
std::pow( errors_[0]*errors_[0]/errors_[ 1 ]/errors_[ 2 ], kD )); | |||
std::pow( errors_[1]*errors_[1]/errors_[ 0 ]/errors_[ 2 ], kD )); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that that (
errors_[0] = 0
givingnewDt = 0
) might have been a problem earlier, though
Agreed. I only remarked on this possibility because we're in the area now so it's an opportunity to fix it. For what it's worth, I tried this PR on a field case and ran into that exact problem. Otherwise I might not have noticed it.
Any chance we can get this in? |
There's absolutely a chance we can get it in. We're a little constrained by the way we handle updates to reference solutions in the time leading up to a new official release, so it'll definitely be easier to get it in once the new release is finalised. |
jenkins build this please |
Note to @erikhide : The above build request is just to refresh my memory of the impact of this PR. We are going to merge this regardless. |
The PID controller formula (see articles referred to in the comments in the OPM code, e.g. "D. Kuzmin and S. Turek, Numerical simulation of turbulent bubbly flows (2004)") as implemented in the current version of OPM contains an indexing error.
Comparing the implementation and PID controller formula,$e_{n-2}$ , $e_{n-1}$ , and $e_n$ .
errors_[0]
correspond toerrors_[1]
toerrors_[2]
to