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

[Breaking Change] Make Mesh-Level Boundary Conditions Usable without "User" flag (now without bitrot) #1177

Merged
merged 20 commits into from
Oct 16, 2024

Conversation

Yurlungur
Copy link
Collaborator

NOTICE

This is my second attempt at #989 . The code has changed so much since my original implementation that it was easier to start from scratch rather than trying to merge with develop. Some notes:

API Breaking change

When registering user boundary functions, the mechanism changes from assigning the function pointer to an array. You now must call ApplicationInput::RegisterBoundaryCondition and give the custom boundary condition a name. This also eliminates the need for the user boundary flag in the input file, although that flag is implicitly still supported.

PR Summary

A discussion on the new downstream code headed by @brryan @pdmullen indicated a desire to set mesh-level boundary conditions without using the user flag. Here I implement this feature. The changes I made are:

  1. ApplicationInput now has a registration function where you register either a grid or particle boundary condition, with a function pointer (or a class in the case of swarm bounds) and a name.
  2. ALL boundary conditions (except periodic) use this mechanism. Reflecting boundaries are, for example, registered in the constructor for ApplicationInput with the "reflecting" name.
  3. BoundaryFlags are dramatically simplified, indicating (essentially) only whether or not boundaries are periodic.
  4. The mesh no longer uses flags to set function pointers. Instead, it just pulls the functions from ApplicationInput.
  5. For (sort of) backwards compatibility, if you register a function without naming it, it's named "user."
  6. Swarm boundaries are now decoupled from mesh boundaries. Although by default, they are set to the same value as the mesh.

The advantage of this is that you can now call (in your main function)

pman->app_input.RegisterBoundaryCondition(parthenon::BoundaryFace::inner_x1, "my_bc", &my_bc_func);

and then in the input file just use

<parthenon/mesh>
ix1_bc = my_bc

I think the refactored code is also significantly cleaner and easier to read. Also I put a link to the parthenon paper in the readme.

PR Checklist

  • Code passes cpplint
  • New features are documented.
  • Adds a test for any bugs fixed. Adds tests for new features.
  • Code is formatted
  • Changes are summarized in CHANGELOG.md
  • Change is breaking (API, behavior, ...)
    • Change is additionally added to CHANGELOG.md in the breaking section
    • PR is marked as breaking
    • Short summary API changes at the top of the PR (plus optionally with an automated update/fix script)
  • CI has been triggered on Darwin for performance regression tests.
  • Docs build
  • (@lanl.gov employees) Update copyright on changed files

@Yurlungur Yurlungur self-assigned this Sep 13, 2024
@Yurlungur
Copy link
Collaborator Author

Ping @pgrete, @brryan , @bprather and @adamdempsey90 you guys asked for this. Please review when you get the chance. :)

@@ -1,4 +1,4 @@
.. _sphinx-doc:
.. _boundary-conds:
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think this was an error. The hyperlink never should have been _sphinx_doc

Comment on lines +106 to +112
A per-variable reflecting boundary condition is available, but you
must register it manually. To do so, simply call
``app_in->RegisterDefaultReflectingBoundaryConditions()`` and it
will be available as a mesh boundary with the name ``reflecting``.
The reason manual registration is required is to support custom
reflecting boundary conditions in the case where a single variable
is used as the state vector.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As requested by @pgrete in the prior MR.

Comment on lines -79 to +80
forest_def.AddBC(edge_t({n[0], n[1]}), parthenon::BoundaryFlag::outflow);
forest_def.AddBC(edge_t({n[0], n[3]}), parthenon::BoundaryFlag::outflow);
forest_def.AddBC(edge_t({n[0], n[1]}));
forest_def.AddBC(edge_t({n[0], n[3]}));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The default flag is now user which then uses the boundary function pointer selected in the input deck. Explicitly specifying the boundary flag is thus unnecessary.

Comment on lines +52 to +59
pman.app_input->RegisterBoundaryCondition(BoundaryFace::inner_x1,
parthenon::BoundaryFunction::OutflowInnerX1);
pman.app_input->RegisterBoundaryCondition(BoundaryFace::outer_x1,
parthenon::BoundaryFunction::OutflowOuterX1);
pman.app_input->RegisterSwarmBoundaryCondition(BoundaryFace::inner_x1,
SwarmUserInnerX1);
pman.app_input->RegisterSwarmBoundaryCondition(BoundaryFace::outer_x1,
SwarmUserOuterX1);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because I don't specify a name, these get added as "user"

Comment on lines -31 to +37
struct ApplicationInput {
class ApplicationInput {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There's more private scope now, so this seemed like an appropriate change.

Comment on lines 1179 to 1191
mesh_bc_names = {pin->GetOrAddString("parthenon/mesh", "ix1_bc", "outflow"),
pin->GetOrAddString("parthenon/mesh", "ox1_bc", "outflow"),
pin->GetOrAddString("parthenon/mesh", "ix2_bc", "outflow"),
pin->GetOrAddString("parthenon/mesh", "ox2_bc", "outflow"),
pin->GetOrAddString("parthenon/mesh", "ix3_bc", "outflow"),
pin->GetOrAddString("parthenon/mesh", "ox3_bc", "outflow")};
mesh_swarm_bc_names = {
pin->GetOrAddString("parthenon/swarm", "ix1_bc", mesh_bc_names[0]),
pin->GetOrAddString("parthenon/swarm", "ox1_bc", mesh_bc_names[1]),
pin->GetOrAddString("parthenon/swarm", "ix2_bc", mesh_bc_names[2]),
pin->GetOrAddString("parthenon/swarm", "ox2_bc", mesh_bc_names[3]),
pin->GetOrAddString("parthenon/swarm", "ix3_bc", mesh_bc_names[4]),
pin->GetOrAddString("parthenon/swarm", "ox3_bc", mesh_bc_names[5])};
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@brryan does this seem reasonable to you?

Comment on lines -154 to +155
mesh_bcs = {
GetBoundaryFlag(pin->GetOrAddString("parthenon/mesh", "ix1_bc", "reflecting")),
GetBoundaryFlag(pin->GetOrAddString("parthenon/mesh", "ox1_bc", "reflecting")),
GetBoundaryFlag(pin->GetOrAddString("parthenon/mesh", "ix2_bc", "reflecting")),
GetBoundaryFlag(pin->GetOrAddString("parthenon/mesh", "ox2_bc", "reflecting")),
GetBoundaryFlag(pin->GetOrAddString("parthenon/mesh", "ix3_bc", "reflecting")),
GetBoundaryFlag(pin->GetOrAddString("parthenon/mesh", "ox3_bc", "reflecting"))};
SetBCNames_(pin);
mesh_bcs = GetBCsFromNames_(mesh_bc_names);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The mesh_bcs logic is repeated in the initializer list for each constructor. This is silly. I moved it to a standalone function.

Comment on lines +223 to +224
and key != "BoundaryConditions"
and key != "SwarmBoundaryConditions"
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is safe to exclude from metadata checks becuase it was always unused by the infrastructure and this MR (dramatically) changes what this output looks like.

doc/sphinx/src/boundary_conditions.rst Show resolved Hide resolved
auto maybe = [](const std::string &s) {
return ((s == "outflow") || (s == "periodic")) ? s : "outflow";
};
mesh_swarm_bc_names = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Cool. I think this API is more flexible when needing to specify different boundary conditions for fields vs swarms.

Just for my understanding, can you help me work through the scenario that I want to specify user defined boundary conditions that are unique for swarms and fields. I would do

parthenon/mesh/ix1_bc=custom_mesh_ix1
parthenon/swarm/ix1_bc=custom_swarm_ix1

with

pman.app_input->RegisterBoundaryCondition(parthenon::BoundaryFace::inner_x1, "custom_mesh_ix1", MyMeshBoundaryInnerX1);
pman.app_input->RegisterSwarmBoundaryCondition(parthenon::BoundaryFace::inner_x1, "custom_swarm_ix1", MySwarmBoundaryInnerX1);

or equivalently

parthenon/mesh/ix1_bc=user

with

pman.app_input->RegisterBoundaryCondition(parthenon::BoundaryFace::inner_x1, MyMeshBoundaryInnerX1);
pman.app_input->RegisterSwarmBoundaryCondition(parthenon::BoundaryFace::inner_x1, MySwarmBoundaryInnerX1);

is that 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.

Yep that's right!

Copy link
Collaborator

@lroberts36 lroberts36 left a comment

Choose a reason for hiding this comment

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

LGTM

@Yurlungur Yurlungur merged commit 79d5d30 into develop Oct 16, 2024
53 checks passed
@BenWibking BenWibking mentioned this pull request Oct 16, 2024
12 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaks-downstream enhancement New feature or request refactor An improvement to existing code.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants