Skip to content
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

Fix BoundaryAdjacentMean #4189

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Fix BoundaryAdjacentMean #4189

wants to merge 5 commits into from

Conversation

jagoosw
Copy link
Collaborator

@jagoosw jagoosw commented Mar 10, 2025

Addresses concerns in #4183 and bug

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we call this boundary_adjacent_mean to match the type name?

flux_field :: FF
value :: BV
struct BoundaryAdjacentMean{NI, BV}
boundary_normal_integral :: NI
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the idea is that we compute an integral first and then divide by area to get the mean?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the type doesn't say anything about "normal" and I think this works on scalars right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, I guess boundary_parallel_integral is more accurate? boundary normal integal is actually wrong

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think merely integral is enough. The name of the type is "boundary adjacent mean". If we compute the mean by first taking the integral and dividing by area, then integral combined with the name of the type give you what yo uneed to know.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first rule is "do no harm"

import Oceananigans.BoundaryConditions: update_boundary_condition!

"""
BoundaryAdjacentMean
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the function signature is missing arguments

An = boundary_normal_area(val_side, grid)

# get the total flux
sum!(bam.boundary_parallel_integral, (@at (Face, Center, Center) u) * An)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments:

  1. It might be nicer to preform this operation --- that way users can look at it, and potentially verify its correctness.
  2. Why don't we use Average here?
  3. sum! is incorrect if the grid is stretched, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to return the operation and let the user do it?

I can't exactly remember how I ended up with this design but I think I did it this was so that we don't have to allocate a new average field (since you can't do in place averaging right?)

And I think sum is correct since it is multiplied by the area right?

new{NI, BV}(boundary_parallel_integral, value)
end

@inline (bam::BoundaryAdjacentMean)(args...) = bam.value[]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed this. I would offer that this code is surprising and hard to understand.

@glwagner
Copy link
Member

glwagner commented Mar 11, 2025

I'm no longer sure that we need the type BoundaryAdjacentMean. Can't we construct a Field directly with all of the information it needs, and then call compute! on that field within update_boundary_condition!? What we need is a function boundary_adjacent_mean(side, field) which constructs the appropriate Reduction. getbc then works correctly (I think); for example the needed value is stored in field.data.

A disadvantage is that we need to use regularize_boundary_condition to set it up for users, because users won't have access to field before they build the model.

However, there are some significant advantages:

  1. More code re-use; no extra type needed.
  2. The way the code works is easier to understand, provided that you already understand reductions.
  3. The type is specific to the boundary and its value can be computed without dependencies via compute!(field).
  4. Because it is a Field, users can use an output writer to write its value as a diagnostic. It can also participate in additional operations; for example to compute a flux across the boundary.
  5. We can simplify update_boundary_condition!.

@jagoosw
Copy link
Collaborator Author

jagoosw commented Mar 11, 2025

I'm no longer sure that we need the type BoundaryAdjacentMean. Can't we construct a Field directly with all of the information it needs, and then call compute! on that field within update_boundary_condition!? What we need is a function boundary_adjacent_mean(side, field) which constructs the appropriate Reduction. getbc then works correctly (I think); for example the needed value is stored in field.data.

A disadvantage is that we need to use regularize_boundary_condition to set it up for users, because users won't have access to field before they build the model.

However, there are some significant advantages:

1. More code re-use; no extra type needed.

2. The way the code works is easier to understand, provided that you already understand reductions.

3. The type is specific to the boundary and its value can be computed without dependencies via `compute!(field)`.

4. Because it is a `Field`, users can use an output writer to write its value as a diagnostic. It can also participate in additional operations; for example to compute a flux across the boundary.

5. We can simplify `update_boundary_condition!`.

I think the reason I ended up with this was to avoid using regularize_boundary_condition but that seems like a reasonable solution. I think we would also need to add a method for update_boundary_condition! when the BC has a compute field in the condition.

@glwagner
Copy link
Member

Ok, so we have to decide which is best: adopt complication of regularize_boundary_condition but simplify what we get out. Probably the main thing is that Field can participate in abstract operations, so if we think that matters we should use it. Also it might be easier to generalize to open boundary velocities that vary in space (eg not a mean over the whole boundary) ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants