-
Notifications
You must be signed in to change notification settings - Fork 221
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
Optimize masking xy planes #4040
Conversation
…l into ss/optimize-masking
I would favor not having an interface where one of the arguments is a function. It doesn't really help that much compared to the pattern we usually implement based on types and dispatch. Also I don't see the point of being able to change |
It is the previous pattern we had, this PR does not change it. We can think about a new interface. However, being able to change the mask is quite important to define the behavior of the |
This PR adds |
Where do we use different "masking functions"? |
I'm really just worried that this is an example of poor design. Obviously, if we never need to develop or change this code, it doesn't matter. But it could lead to problems down the line because it is not well thought out. The first issue is that this pattern of passing a function to a function, while valid, is atypical in our source code. It's a nice informal "trick" for getting what we want with less code. The other annoying thing to me is that this pattern effectively defines what a "masking function" is. This code will fail unless a mask can be called with It always seemed like a temporary hack for |
Why don't we just start by identifying where we have to call |
The problem stems from the masking of the free surface. |
So let's maybe do this, we remove the masking function and use only the |
It's wrong that Nz+1 is a peripheral node when we have a free surface, right? The problem is not actually |
Right, it might be a bit difficult to enforce because the function needs to be model-dependent |
I disagree. It's not that it's difficult to enforce. It's that the definition of "peripheral" is associated with the topology, and we may not have a topology to properly represent this concept. It also seems wrong that "mask immersed field" masks all inactive nodes. It should be rather The confusion in this conversation is, I think, a symptom of the fact that the abstraction isn't quite right here. It's not holding up to logical analysis. |
A few more points:
|
exactly, we mask to have zero velocities on the boundary, otherwise velocities will have a value probably. So masking is required for velocities (unless we really make sure that tendencies are zero on immersed peripheral nodes but that is quite difficult to ensure for every new parameterization and sounds like it would be a bit brittle) but not for tracers. For tracers it's only required for outputs |
We could do that, it would be a little bit more code but I would be ok with it. |
Only the tendencies / vertical tridiagonal solve update the velocities I guess. But why do we only mask on immersed peripheral nodes? Is this again assuming that we redundantly satisfy boundary conditions? I think that algorithm is sort of overcomplicated. I can say that because I implemented as a simple thing to do on first try so long ago and we are still using it! |
Ok, I think we can merge this to fix the inference issue and think about a better interface for masking immersed fields. |
There is a problem at the moment with the
mask_immersed_field_xy!
function. The implementation leverages ascalar_mask
which receives amask
optional argument that seems to create problems with inference on the CPU.this PR removes the scalar mask function and restructures the masking function such that we remove all the extra allocation (that causes GC time).
For example within the following MWE
on main we get
In this PR we get
This PR also unifies the interface for
mask_immersed_field_xy!
with the one formask_immersed_field!
by providing amask
keyword argument also for themask_immersed_field!
function