-
Notifications
You must be signed in to change notification settings - Fork 7
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
Potential enhancement to Mask interface to help avoid FPEs #117
Comments
Jim, would you point to an example of this pattern in the code? Thanks. |
@ambrad , sure. Here's a change I had to make in my dev branch:
This was one of a dozen or so similar changes I needed to make. |
Jim, would you point me to your branch? I'm curious if all of the cases involve clipping with min and max. |
Here's a crazy idea, which you guys might deem too "bulky": we could wrap binary ops results into a "pack expression", which is only evaluated when it's accessed. Something along the line of:
The struct PackExpression can simply hold references to the args. I think Sacado in Trilinos had a similar issue, which is due to expressions in function calls being evaluated before passing control to the fcn. |
@ambrad , I am about to make a PR; my branch is |
One of my concerns here is it's not clear to me the original F90 is quite what we want. Then again, I might just be confused. Here is the original F90 corresponding to the C++ above: relvar(:,:) = 1.0_r8
relvarmax = 10.0_r8
where (rcm(:ncol,:pver) /= 0.0 .and. rcm2(:ncol,:pver) /= 0.0) &
relvar(:ncol,:pver) = min(relvarmax,max(0.001_r8,rcm(:ncol,:pver)**2.0/rcm2(:ncol,:pver))) For simplicity, assume these are all scalars, not arrays. Suppose rcm2 = 0 and rcm = 1. Then rcm/rcm2 = +Inf. In that case, one would think relvar should be set to relvarmax = 10. But, instead, the above code makes relvar = 1. Yet if rcm2 were just a bit above 0, say rcm2 = 1e-6, the above code would indeed make it 10. So that makes the overall function discontinuous. A similar situation occurs when rcm = 0 but rcm2 != 0. relvar is set to 1 but if rcm were just a bit above 0, it would instead be 0.001. Someone please correct me if I'm just confused. I'd like to look at the other cases to see if similar strange things are happening. |
@ambrad what you say seems right to me, but it has to do with the algorithm, rather than the impl. In general, the question is how to deal with "compute x=f(a,b), then set y=x only where condition(a,b) is satisfied". It seems to me that the two issues are related, but could be tackled independently. In the example above, e.g., the solution might be to init |
@ambrad , i think maybe i picked one that was more complicated than necessary. Most of the cases are very simple where you have a zero if check in fortran and a != mask on the C++ side. Here's a simpler one: C++:
F90:
|
This case seems to have the same issue as above. If testvar = 0, then r_qwthl_1 = 0. But if it deviates from 0 by a tiny bit, then r_qwthl_1 = 1 or -1. So again this divide-by-0 situation arises in a context where something bad is happening. |
Wait, doesn't this evaluate |
@bartgol I'm not convinced yet that code that properly implements the evaluation of a continuous function will necessarily require delayed evaluation to look cleaner. Re: the question you just asked, the issue here is when pack size = 1 in an FPE build, so the macro above does accomplish what is intended. |
I think the issue of the continuous fcn is separate. Meaning, even if you init relvar=relvarmax int he 1st example (hence, it's continuous w.r.t rcm2), you still have the FPE generated by evaluating I agree that the fact that relvar is not continuous w.r.t. rcm2 might be an issue, but I think that has nothing to do with FPEs. |
Ah, yes, you are right, for pack size 1 it would be fine. |
Luca, I don't disagree and have no opinion re: Jim's macro, your suggestions, etc. Obviously please feel free to introduce those additional mechanisms. My point is only that in the course of implementing a continuous function with clipping, it's likely the |
As I'm cleaning up FPEs in SHOC, I'm encountering this pattern over and over (this pattern is widespread in P3 too):
... which needs to be changed in over to avoid the FPE (if they are on) to:
Because, even if pack2 is protected from getting infs by the mask, the divide-by-zero still occurs when
val/pack1
gets evaluated. The code that needed to protect against this makes the code uglier and may impact performance since it introduces another branch.I was thinking a macro like this would be nice:
Which would be used like this:
Thoughts?
The text was updated successfully, but these errors were encountered: