Path: blob/main/src/meshes/parallel_tree_mesh.jl
2055 views
# By default, Julia/LLVM does not use fused multiply-add operations (FMAs).1# Since these FMAs can increase the performance of many numerical algorithms,2# we need to opt-in explicitly.3# See https://ranocha.de/blog/Optimizing_EC_Trixi for further details.4@muladd begin5#! format: noindent67"""8partition!(mesh::ParallelTreeMesh, allow_coarsening=true)910Partition `mesh` using a static domain decomposition algorithm11based on leaf cell count and tree structure.12If `allow_coarsening` is `true`, the algorithm will keep leaf cells together13on one rank when needed for local coarsening (i.e. when all children of a cell are leaves).14"""15function partition!(mesh::ParallelTreeMesh; allow_coarsening = true)16# Determine number of leaf cells per rank17leaves = leaf_cells(mesh.tree)18@assert length(leaves)>mpi_nranks() "Too many ranks to properly partition the mesh!"19n_leaves_per_rank = OffsetArray(fill(div(length(leaves), mpi_nranks()),20mpi_nranks()),210:(mpi_nranks() - 1))22for rank in 0:(rem(length(leaves), mpi_nranks()) - 1)23n_leaves_per_rank[rank] += 124end25@assert sum(n_leaves_per_rank) == length(leaves)2627# Assign MPI ranks to all cells such that all ancestors of each cell - if not yet assigned to a28# rank - belong to the same rank29mesh.first_cell_by_rank = similar(n_leaves_per_rank)30mesh.n_cells_by_rank = similar(n_leaves_per_rank)3132leaf_count = 033# Assign first cell to rank 0 (employ depth-first indexing of cells)34mesh.first_cell_by_rank[0] = 135# Iterate over all ranks36for rank in 0:(mpi_nranks() - 1)37leaf_count += n_leaves_per_rank[rank]38last_id = leaves[leaf_count]39parent_id = mesh.tree.parent_ids[last_id]4041# If coarsening is allowed, we need to make sure that parents of leaves42# are on the same rank as the leaves when coarsened.43if allow_coarsening &&44# Check if all children of the last parent are leaves45all(id -> is_leaf(mesh.tree, id), @view mesh.tree.child_ids[:, parent_id]) &&46rank < length(n_leaves_per_rank) - 1 # Make sure there is another rank4748# To keep children of parent together if they are all leaves,49# all children are added to this rank50additional_cells = (last_id + 1):mesh.tree.child_ids[end, parent_id]51if length(additional_cells) > 052last_id = additional_cells[end]5354additional_leaves = count(id -> is_leaf(mesh.tree, id),55additional_cells)56leaf_count += additional_leaves57# Add leaves to this rank, remove from next rank58n_leaves_per_rank[rank] += additional_leaves59n_leaves_per_rank[rank + 1] -= additional_leaves60end61end6263@assert all(n -> n > 0, n_leaves_per_rank) "Too many ranks to properly partition the mesh!"6465mesh.n_cells_by_rank[rank] = last_id - mesh.first_cell_by_rank[rank] + 166# Use depth-first indexing of cells again to assign also non leaf cells67mesh.tree.mpi_ranks[mesh.first_cell_by_rank[rank]:last_id] .= rank6869# Set first cell of next rank70if rank < length(n_leaves_per_rank) - 1 # Make sure there is another rank71mesh.first_cell_by_rank[rank + 1] = mesh.first_cell_by_rank[rank] +72mesh.n_cells_by_rank[rank]73end74end7576@assert all(x -> x >= 0, mesh.tree.mpi_ranks[1:length(mesh.tree)])77@assert sum(mesh.n_cells_by_rank) == length(mesh.tree)7879return nothing80end8182function get_restart_mesh_filename(restart_filename, mpi_parallel::True)83# Get directory name84dirname, _ = splitdir(restart_filename)8586if mpi_isroot()87# Read mesh filename from restart file88mesh_file = ""89h5open(restart_filename, "r") do file90mesh_file = read(attributes(file)["mesh_file"])91end9293buffer = Vector{UInt8}(mesh_file)94MPI.Bcast!(Ref(length(buffer)), mpi_root(), mpi_comm())95MPI.Bcast!(buffer, mpi_root(), mpi_comm())96else # non-root ranks97count = MPI.Bcast!(Ref(0), mpi_root(), mpi_comm())98buffer = Vector{UInt8}(undef, count[])99MPI.Bcast!(buffer, mpi_root(), mpi_comm())100mesh_file = String(buffer)101end102103# Construct and return filename104return joinpath(dirname, mesh_file)105end106end # @muladd107108109