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 Multigrid Solver in Forest #1035

Merged
merged 57 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1dafe26
move some stuff around
lroberts36 Mar 20, 2024
0229012
split into more, smaller files
lroberts36 Mar 20, 2024
7a43c76
format and lint
lroberts36 Mar 20, 2024
a9810f1
clarify that amr_loadbalance implements mesh members
lroberts36 Mar 20, 2024
993f512
Merge branch 'lroberts36/add-forest-of-octrees' into lroberts36/reorg…
lroberts36 Mar 26, 2024
5260f68
Merge branch 'lroberts36/add-forest-of-octrees' into lroberts36/reorg…
lroberts36 Mar 26, 2024
21372e5
changelog
lroberts36 Mar 26, 2024
dd6fbdc
start on adding two-level composite grids
lroberts36 Mar 26, 2024
a5e19a6
more work
lroberts36 Mar 26, 2024
3345de8
simplify level scheme for gmg
lroberts36 Mar 26, 2024
ab182ec
Merge branch 'temp-update-gmg-to-maps' into lroberts36/fix-forest-mul…
lroberts36 Mar 26, 2024
3a4da84
provide gids for the whole mesh
lroberts36 Mar 26, 2024
07d9e60
Merge branch 'lroberts36/add-forest-of-octrees' into lroberts36/reorg…
lroberts36 Mar 27, 2024
624d5f1
Merge branch 'lroberts36/reorganize' into lroberts36/fix-forest-multi…
lroberts36 Mar 27, 2024
102b012
bugfix
lroberts36 Mar 27, 2024
e3c6e81
format
lroberts36 Mar 27, 2024
71c6792
Start on refactor of building gmg block lists
lroberts36 Mar 27, 2024
bd73316
generalize neighbor finding to two-level composite grids
lroberts36 Mar 27, 2024
37b5557
seemingly working
lroberts36 Mar 27, 2024
e1c99d8
remove old gmg stuff
lroberts36 Mar 27, 2024
81e5a18
remove a bunch of uneccesary stuff
lroberts36 Mar 27, 2024
933f48d
Remove dead code
lroberts36 Mar 27, 2024
8966e48
Remove forest naming
lroberts36 Mar 27, 2024
d751b56
rename for clarity
lroberts36 Mar 27, 2024
9f20574
Split function into two
lroberts36 Mar 27, 2024
9329660
More cleanup
lroberts36 Mar 27, 2024
364d71a
Remove RootGridInfo
lroberts36 Mar 27, 2024
a4758a6
format
lroberts36 Mar 27, 2024
a5da7c9
remove unecessary location lists
lroberts36 Mar 27, 2024
c29147a
update changelog
lroberts36 Mar 27, 2024
b254187
update copyrights
lroberts36 Mar 27, 2024
59bfdd1
Move definitions out of header
lroberts36 Mar 27, 2024
a5c56d9
format
lroberts36 Mar 27, 2024
51bf560
fix neighbor tree index finding
lroberts36 Mar 28, 2024
96d91a3
Merge branch 'lroberts36/add-forest-of-octrees' into lroberts36/reorg…
lroberts36 Mar 28, 2024
820a135
Merge branch 'lroberts36/reorganize' into lroberts36/fix-forest-multi…
lroberts36 Mar 28, 2024
df545d2
cleanup
lroberts36 Mar 28, 2024
f1aba7a
not actually working
lroberts36 Mar 28, 2024
fa18d43
Merge branch 'lroberts36/add-forest-of-octrees' into lroberts36/reorg…
lroberts36 Apr 1, 2024
45b8b3d
format
lroberts36 Apr 1, 2024
d4daeeb
remove dead code
lroberts36 Apr 1, 2024
e4d235b
Merge branch 'lroberts36/reorganize' into lroberts36/fix-forest-multi…
lroberts36 Apr 1, 2024
c0624e9
fix merge bug
lroberts36 Apr 1, 2024
42fc5cf
correct morton numbers for negative levels
lroberts36 Apr 1, 2024
a5515c2
More carefully deal with negative levels
lroberts36 Apr 1, 2024
b767ba2
format
lroberts36 Apr 1, 2024
ae174ea
Merge branch 'lroberts36/add-forest-of-octrees' into lroberts36/reorg…
lroberts36 Apr 2, 2024
87e5cde
Merge branch 'lroberts36/reorganize' into lroberts36/fix-forest-multi…
lroberts36 Apr 2, 2024
a9060c0
add back gmg tests
lroberts36 Apr 2, 2024
339777c
Merge branch 'develop' into lroberts36/reorganize
lroberts36 Apr 3, 2024
8daa76c
Merge branch 'lroberts36/reorganize' into lroberts36/fix-forest-multi…
lroberts36 Apr 3, 2024
4ed5daf
Merge branch 'develop' into lroberts36/reorganize
lroberts36 Apr 10, 2024
b9ab262
fix possible gmg ownership bug
lroberts36 Apr 10, 2024
2bbe966
Merge branch 'develop' into lroberts36/reorganize
pgrete Apr 11, 2024
19d337a
Merge branch 'lroberts36/reorganize' into lroberts36/fix-forest-multi…
lroberts36 Apr 11, 2024
491bf79
Merge branch 'develop' into lroberts36/fix-forest-multigrid
lroberts36 Apr 11, 2024
baa0b0a
Merge branch 'develop' into lroberts36/fix-forest-multigrid
lroberts36 Apr 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci-extended.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ jobs:
cd build
# Pick GPU with most available memory
export CUDA_VISIBLE_DEVICES=$(nvidia-smi --query-gpu=memory.free,index --format=csv,nounits,noheader | sort -nr | head -1 | awk '{ print $NF }')
ctest -L performance -LE perf-reg -E gmg
ctest -L performance -LE perf-reg

# run regression tests
- name: Regression tests
run: |
cd build
# Pick GPU with most available memory
export CUDA_VISIBLE_DEVICES=$(nvidia-smi --query-gpu=memory.free,index --format=csv,nounits,noheader | sort -nr | head -1 | awk '{ print $NF }')
ctest -L regression -L ${{ matrix.parallel }} -LE perf-reg -E gmg --timeout 3600
ctest -L regression -L ${{ matrix.parallel }} -LE perf-reg --timeout 3600

# Test Ascent integration (only most complex setup with MPI and on device)
- name: Ascent tests
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- [[PR 1031]](https://github.com/parthenon-hpc-lab/parthenon/pull/1031) Fix bug in non-cell centered AMR

### Infrastructure (changes irrelevant to downstream codes)
- [[PR 1035]](https://github.com/parthenon-hpc-lab/parthenon/pull/1035) Fix multigrid infrastructure to work with forest
- [[PR 1048]](https://github.com/parthenon-hpc-lab/parthenon/pull/1048) Tiny fixes to custom coords logic
- [[PR 1028]](https://github.com/parthenon-hpc-lab/parthenon/pull/1028) Internal reorganization of LogicalLocation files
- [[PR 1009]](https://github.com/parthenon-hpc-lab/parthenon/pull/1009) Move from a single octree to a forest of octrees
Expand Down
5 changes: 4 additions & 1 deletion doc/sphinx/src/mesh/mesh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ level that are neighbors to finer blocks, which implies that below the root grid
level the blocks may not cover the entire mesh. For levels above the root grid,
blocks may change shape so that they only cover the domain of the root grid. Note
that leaf blocks may be contained in multiple blocklists, and the lists all point
to the same block (not a separate copy). To be explicit, when ``parthenon/mesh/multigrid`` is set to ``true`` blocks corresponding to *all* internal nodes of the refinement tree are created, in addition to the leaf node blocks that are normally created.
to the same block (not a separate copy). To be explicit, when
``parthenon/mesh/multigrid`` is set to ``true`` blocks corresponding to *all*
internal nodes of the refinement tree are created, in addition to the leaf node blocks
that are normally created.

*GMG Implementation Note:*
The reason for including two levels in the GMG block lists is for dealing with
Expand Down
11 changes: 11 additions & 0 deletions src/basic_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ enum class BoundaryType : int {
gmg_prolongate_recv
};

enum class GridType { none, leaf, two_level_composite, single_level_with_internal };
struct GridIdentifier {
GridType type = GridType::none;
int logical_level = 0;

static GridIdentifier leaf() { return GridIdentifier{GridType::leaf, 0}; }
static GridIdentifier two_level_composite(int level) {
return GridIdentifier{GridType::two_level_composite, level};
}
};

constexpr bool IsSender(BoundaryType btype) {
if (btype == BoundaryType::flxcor_recv) return false;
if (btype == BoundaryType::gmg_restrict_recv) return false;
Expand Down
6 changes: 3 additions & 3 deletions src/driver/driver.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//========================================================================================
// (C) (or copyright) 2020-2021. Triad National Security, LLC. All rights reserved.
// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved.
//
// This program was produced under U.S. Government contract 89233218CNA000001 for Los
// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC
Expand Down Expand Up @@ -191,8 +191,8 @@ void EvolutionDriver::InitializeBlockTimeStepsAndBoundaries() {
auto &mbase = pmesh->mesh_data.GetOrAdd("base", i);
Update::EstimateTimestep(mbase.get());
BuildBoundaryBuffers(mbase);
for (int gmg_level = 0; gmg_level < pmesh->gmg_mesh_data.size(); ++gmg_level) {
auto &mdg = pmesh->gmg_mesh_data[gmg_level].GetOrAdd(gmg_level, "base", i);
for (auto &[gmg_level, mdc] : pmesh->gmg_mesh_data) {
auto &mdg = mdc.GetOrAdd(gmg_level, "base", i);
BuildBoundaryBuffers(mdg);
BuildGMGBoundaryBuffers(mdg);
}
Expand Down
18 changes: 8 additions & 10 deletions src/interface/data_collection.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//========================================================================================
// (C) (or copyright) 2020-2023. Triad National Security, LLC. All rights reserved.
// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved.
//
// This program was produced under U.S. Government contract 89233218CNA000001 for Los
// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC
Expand Down Expand Up @@ -58,9 +58,9 @@ std::shared_ptr<MeshData<Real>> &
GetOrAdd_impl(Mesh *pmy_mesh_,
std::map<std::string, std::shared_ptr<MeshData<Real>>> &containers_,
BlockList_t &block_list, const std::string &mbd_label,
const int &partition_id, const int gmg_level) {
const int &partition_id, const std::optional<int> gmg_level) {
std::string label = mbd_label + "_part-" + std::to_string(partition_id);
if (gmg_level >= 0) label = label + "_gmg-" + std::to_string(gmg_level);
if (gmg_level) label = label + "_gmg-" + std::to_string(*gmg_level);
auto it = containers_.find(label);
if (it == containers_.end()) {
// TODO(someone) add caching of partitions to Mesh at some point
Expand All @@ -70,15 +70,13 @@ GetOrAdd_impl(Mesh *pmy_mesh_,
if (partitions.size() == 0) partitions = std::vector<BlockList_t>(1);
for (auto i = 0; i < partitions.size(); i++) {
std::string md_label = mbd_label + "_part-" + std::to_string(i);
if (gmg_level >= 0) md_label = md_label + "_gmg-" + std::to_string(gmg_level);
if (gmg_level) md_label = md_label + "_gmg-" + std::to_string(*gmg_level);
containers_[md_label] = std::make_shared<MeshData<Real>>(mbd_label);
containers_[md_label]->Set(partitions[i], pmy_mesh_);
if (gmg_level >= 0) {
int min_gmg_logical_level = pmy_mesh_->GetGMGMinLogicalLevel();
containers_[md_label]->grid = GridIdentifier{GridType::two_level_composite,
gmg_level + min_gmg_logical_level};
if (gmg_level) {
containers_[md_label]->grid = GridIdentifier::two_level_composite(*gmg_level);
} else {
containers_[md_label]->grid = GridIdentifier{GridType::leaf, 0};
containers_[md_label]->grid = GridIdentifier::leaf();
lroberts36 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand All @@ -90,7 +88,7 @@ std::shared_ptr<MeshData<Real>> &
DataCollection<MeshData<Real>>::GetOrAdd(const std::string &mbd_label,
const int &partition_id) {
return GetOrAdd_impl(pmy_mesh_, containers_, pmy_mesh_->block_list, mbd_label,
partition_id, -1);
partition_id, {});
}

template <>
Expand Down
6 changes: 3 additions & 3 deletions src/interface/mesh_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ void MeshData<T>::Initialize(const MeshData<T> *src,

grid = src->grid;
if (grid.type == GridType::two_level_composite) {
int gmg_level = src->grid.logical_level - pmy_mesh_->GetGMGMinLogicalLevel();
for (int i = 0; i < nblocks; i++) {
block_data_[i] = pmy_mesh_->gmg_block_lists[gmg_level][i]->meshblock_data.Add(
stage_name_, src->GetBlockData(i), names, shallow);
block_data_[i] =
pmy_mesh_->gmg_block_lists[src->grid.logical_level][i]->meshblock_data.Add(
stage_name_, src->GetBlockData(i), names, shallow);
}
} else {
for (int i = 0; i < nblocks; i++) {
Expand Down
8 changes: 1 addition & 7 deletions src/interface/mesh_data.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//========================================================================================
// (C) (or copyright) 2020-2023. Triad National Security, LLC. All rights reserved.
// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved.
//
// This program was produced under U.S. Government contract 89233218CNA000001 for Los
// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC
Expand Down Expand Up @@ -181,12 +181,6 @@ const MeshBlockPack<P> &PackOnMesh(M &map, BlockDataList_t<Real> &block_data_,

} // namespace pack_on_mesh_impl

enum class GridType { none, leaf, two_level_composite, single_level_with_internal };
struct GridIdentifier {
GridType type = GridType::none;
int logical_level = 0;
};

/// The MeshData class is a container for cached MeshBlockPacks, i.e., it
/// contains both the pointers to the MeshBlockData of the MeshBlocks contained
/// in the object as well as maps to the cached MeshBlockPacks of VariablePacks or
Expand Down
50 changes: 4 additions & 46 deletions src/mesh/forest/block_ownership.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
// Licensed under the 3-clause BSD License, see LICENSE file for details
//========================================================================================
// Parthenon performance portable AMR framework
// Copyright(C) 2020-2023 The Parthenon collaboration
// Copyright(C) 2020-2024 The Parthenon collaboration
// Licensed under the 3-clause BSD License, see LICENSE file for details
//========================================================================================
// (C) (or copyright) 2020-2023. Triad National Security, LLC. All rights reserved.
// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved.
//
// This program was produced under U.S. Government contract 89233218CNA000001 for Los
// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC
Expand Down Expand Up @@ -37,11 +37,9 @@

namespace parthenon {

// TODO(LFR): Remove this
block_ownership_t
DetermineOwnership(const LogicalLocation &main_block,
const std::unordered_set<LogicalLocation> &allowed_neighbors,
const RootGridInfo &rg_info,
const std::vector<NeighborLocation> &allowed_neighbors,
const std::unordered_set<LogicalLocation> &newly_refined) {
block_ownership_t main_owns;

Expand All @@ -53,46 +51,6 @@ DetermineOwnership(const LogicalLocation &main_block,
return 2 * a.level();
};

auto ownership_less_than = [ownership_level](const LogicalLocation &a,
const LogicalLocation &b) {
// Ownership is first determined by block with the highest level, then by maximum
// Morton number this is reversed in precedence from the normal comparators where
// Morton number takes precedence
if (ownership_level(a) == ownership_level(b)) return a.morton() < b.morton();
return ownership_level(a) < ownership_level(b);
};

for (int ox1 : {-1, 0, 1}) {
for (int ox2 : {-1, 0, 1}) {
for (int ox3 : {-1, 0, 1}) {
main_owns(ox1, ox2, ox3) = true;
for (auto &n : allowed_neighbors) {
if (ownership_less_than(main_block, n) &&
main_block.IsNeighborOfTE(n, ox1, ox2, ox3, rg_info)) {
main_owns(ox1, ox2, ox3) = false;
break;
}
}
}
}
}
return main_owns;
}

block_ownership_t
DetermineOwnershipForest(const LogicalLocation &main_block,
const std::vector<NeighborLocation> &allowed_neighbors,
const std::unordered_set<LogicalLocation> &newly_refined) {
block_ownership_t main_owns;

auto ownership_level = [&](const LogicalLocation &a) {
// Newly-refined blocks are treated as higher-level than blocks at their
// parent level, but lower-level than previously-refined blocks at their
// current level.
if (newly_refined.count(a)) return 2 * a.level() - 1;
return 2 * a.level();
};

auto ownership_less_than = [ownership_level](const LogicalLocation &a,
const LogicalLocation &b) {
// Ownership is first determined by block with the highest level, then by maximum
Expand All @@ -110,7 +68,7 @@ DetermineOwnershipForest(const LogicalLocation &main_block,
main_owns(ox1, ox2, ox3) = true;
for (const auto &n : allowed_neighbors) {
if (ownership_less_than(main_block, n.global_loc) &&
main_block.IsNeighborOfTEForest(n.origin_loc, {ox1, ox2, ox3})) {
main_block.IsNeighborOfTE(n.origin_loc, {ox1, ox2, ox3})) {
main_owns(ox1, ox2, ox3) = false;
break;
}
Expand Down
8 changes: 1 addition & 7 deletions src/mesh/forest/block_ownership.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,9 @@ struct block_ownership_t {

block_ownership_t
DetermineOwnership(const LogicalLocation &main_block,
const std::unordered_set<LogicalLocation> &allowed_neighbors,
const RootGridInfo &rg_info = RootGridInfo(),
const std::vector<NeighborLocation> &allowed_neighbors,
const std::unordered_set<LogicalLocation> &newly_refined = {});

block_ownership_t
DetermineOwnershipForest(const LogicalLocation &main_block,
const std::vector<NeighborLocation> &allowed_neighbors,
const std::unordered_set<LogicalLocation> &newly_refined = {});

// Given a topological element, ownership array of the sending block, and offset indices
// defining the location of an index region within the block (i.e. the ghost zones passed
// across the x-face or the ghost zones passed across the z-edge), return the index range
Expand Down
11 changes: 10 additions & 1 deletion src/mesh/forest/forest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,22 @@ std::vector<LogicalLocation> Forest::GetMeshBlockListAndResolveGids() {
std::uint64_t gid{0};
for (auto &[id, tree] : trees) {
std::size_t start = mb_list.size();
auto tree_mbs = tree->GetMeshBlockList();
auto tree_mbs = tree->GetSortedMeshBlockList();
mb_list.insert(mb_list.end(), std::make_move_iterator(tree_mbs.begin()),
std::make_move_iterator(tree_mbs.end()));
std::size_t end = mb_list.size();
for (int i = start; i < end; ++i)
tree->InsertGid(mb_list[i], gid++);
}

// Assign gids to the internal nodes
for (auto &[id, tree] : trees) {
std::size_t start = mb_list.size();
auto tree_int_locs = tree->GetSortedInternalNodeList();
for (auto &loc : tree_int_locs)
tree->InsertGid(loc, gid++);
}

// The index of blocks in this list corresponds to their gid
gids_resolved = true;
return mb_list;
Expand Down
15 changes: 12 additions & 3 deletions src/mesh/forest/forest.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//========================================================================================
// (C) (or copyright) 2023. Triad National Security, LLC. All rights reserved.
// (C) (or copyright) 2023-2024. Triad National Security, LLC. All rights reserved.
//
// This program was produced under U.S. Government contract 89233218CNA000001 for Los
// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC
Expand Down Expand Up @@ -84,8 +84,10 @@ class Forest {
return trees.at(loc.tree())->FindNeighbors(loc, ox1, ox2, ox3);
}

std::vector<NeighborLocation> FindNeighbors(const LogicalLocation &loc) const {
return trees.at(loc.tree())->FindNeighbors(loc);
std::vector<NeighborLocation>
FindNeighbors(const LogicalLocation &loc,
GridIdentifier grid_id = GridIdentifier::leaf()) const {
return trees.at(loc.tree())->FindNeighbors(loc, grid_id);
}
std::size_t CountMeshBlock() const {
std::size_t count{0};
Expand Down Expand Up @@ -134,6 +136,13 @@ class Forest {
return trees.at(loc.tree())->GetGid(loc);
}

// Get the gid of the leaf block with the same Morton number
// as loc (on the same tree)
std::int64_t GetLeafGid(const LogicalLocation &loc) const {
PARTHENON_REQUIRE(gids_resolved, "Asking for GID in invalid state.");
return trees.at(loc.tree())->GetLeafGid(loc);
}

std::int64_t GetOldGid(const LogicalLocation &loc) const {
PARTHENON_REQUIRE(gids_resolved, "Asking for GID in invalid state.");
return trees.at(loc.tree())->GetOldGid(loc);
Expand Down
Loading
Loading