@muladd begin
"""
P4estMeshView{NDIMS, NDIMS_AMBIENT, RealT <: Real, Parent} <: AbstractMesh{NDIMS}
A view on a [`P4estMesh`](@ref).
"""
mutable struct P4estMeshView{NDIMS, NDIMS_AMBIENT, RealT <: Real, Parent} <:
AbstractMesh{NDIMS}
const parent::Parent
const cell_ids::Vector{Int}
unsaved_changes::Bool
current_filename::String
end
"""
P4estMeshView(parent; cell_ids)
Create a `P4estMeshView` on a [`P4estMesh`](@ref) parent.
# Arguments
- `parent`: the parent `P4estMesh`.
- `cell_ids`: array of cell ids that are part of this view.
"""
function P4estMeshView(parent::P4estMesh{NDIMS, NDIMS_AMBIENT, RealT},
cell_ids::Vector) where {NDIMS, NDIMS_AMBIENT, RealT}
return P4estMeshView{NDIMS, NDIMS_AMBIENT, RealT, typeof(parent)}(parent, cell_ids,
parent.unsaved_changes,
parent.current_filename)
end
@inline Base.ndims(::P4estMeshView{NDIMS}) where {NDIMS} = NDIMS
@inline Base.real(::P4estMeshView{NDIMS, NDIMS_AMBIENT, RealT}) where {NDIMS,
NDIMS_AMBIENT,
RealT} = RealT
function extract_p4est_mesh_view(elements_parent,
interfaces_parent,
boundaries_parent,
mortars_parent,
mesh,
equations,
dg,
::Type{uEltype}) where {uEltype <: Real}
elements = deepcopy(elements_parent)
resize!(elements, length(mesh.cell_ids))
@views elements.inverse_jacobian .= elements_parent.inverse_jacobian[..,
mesh.cell_ids]
@views elements.jacobian_matrix .= elements_parent.jacobian_matrix[..,
mesh.cell_ids]
@views elements.node_coordinates .= elements_parent.node_coordinates[..,
mesh.cell_ids]
@views elements.contravariant_vectors .= elements_parent.contravariant_vectors[..,
mesh.cell_ids]
@views elements.surface_flux_values .= elements_parent.surface_flux_values[..,
mesh.cell_ids]
interfaces = extract_interfaces(mesh, interfaces_parent)
boundaries = extract_boundaries(mesh, boundaries_parent, interfaces_parent,
interfaces)
neighbor_ids_parent = extract_neighbor_ids_parent(mesh, boundaries_parent,
interfaces_parent,
boundaries)
return elements, interfaces, boundaries, mortars_parent, neighbor_ids_parent
end
function extract_interfaces(mesh::P4estMeshView, interfaces_parent)
mask = BitArray(undef, ninterfaces(interfaces_parent))
for interface in 1:size(interfaces_parent.neighbor_ids)[2]
mask[interface] = (interfaces_parent.neighbor_ids[1,
interface] in mesh.cell_ids) &&
(interfaces_parent.neighbor_ids[2,
interface] in mesh.cell_ids)
end
interfaces = deepcopy(interfaces_parent)
resize!(interfaces, sum(mask))
@views interfaces.u .= interfaces_parent.u[.., mask]
if interfaces.normal_directions !== nothing
@views interfaces.normal_directions .= interfaces_parent.normal_directions[..,
mask]
end
@views interfaces.node_indices .= interfaces_parent.node_indices[.., mask]
@views neighbor_ids = interfaces_parent.neighbor_ids[.., mask]
interfaces.neighbor_ids = zeros(Int, size(neighbor_ids))
for interface in 1:size(neighbor_ids)[2]
interfaces.neighbor_ids[1, interface] = findall(id -> id ==
neighbor_ids[1,
interface],
mesh.cell_ids)[1]
interfaces.neighbor_ids[2, interface] = findall(id -> id ==
neighbor_ids[2,
interface],
mesh.cell_ids)[1]
end
return interfaces
end
function extract_boundaries(mesh::P4estMeshView{2},
boundaries_parent, interfaces_parent,
interfaces)
boundaries = deepcopy(boundaries_parent)
mask = BitArray(undef, nboundaries(boundaries_parent))
for boundary in 1:nboundaries(boundaries_parent)
mask[boundary] = boundaries_parent.neighbor_ids[boundary] in mesh.cell_ids
end
boundaries.neighbor_ids = parent_cell_id_to_view(boundaries_parent.neighbor_ids[mask],
mesh)
boundaries.name = boundaries_parent.name[mask]
boundaries.node_indices = boundaries_parent.node_indices[mask]
for interface in 1:ninterfaces(interfaces_parent)
if ((interfaces_parent.neighbor_ids[1, interface] in mesh.cell_ids) ⊻
(interfaces_parent.neighbor_ids[2, interface] in mesh.cell_ids))
if interfaces_parent.neighbor_ids[1, interface] in mesh.cell_ids
neighbor_id = interfaces_parent.neighbor_ids[1, interface]
view_idx = 1
else
neighbor_id = interfaces_parent.neighbor_ids[2, interface]
view_idx = 2
end
push!(boundaries.neighbor_ids,
parent_cell_id_to_view(neighbor_id, mesh))
if (interfaces_parent.node_indices[view_idx, interface] ==
(:end, :i_forward))
push!(boundaries.name, :x_pos)
elseif (interfaces_parent.node_indices[view_idx, interface] ==
(:begin, :i_forward))
push!(boundaries.name, :x_neg)
elseif (interfaces_parent.node_indices[view_idx, interface] ==
(:i_forward, :end))
push!(boundaries.name, :y_pos)
else
push!(boundaries.name, :y_neg)
end
push!(boundaries.node_indices,
interfaces_parent.node_indices[view_idx, interface])
end
end
n_dims = ndims(boundaries)
n_nodes = size(boundaries.u, 2)
n_variables = size(boundaries.u, 1)
capacity = length(boundaries.neighbor_ids)
resize!(boundaries._u, n_variables * n_nodes^(n_dims - 1) * capacity)
boundaries.u = unsafe_wrap(Array, pointer(boundaries._u),
(n_variables, ntuple(_ -> n_nodes, n_dims - 1)...,
capacity))
return boundaries
end
function extract_neighbor_ids_parent(mesh::P4estMeshView,
boundaries_parent, interfaces_parent,
boundaries)
neighbor_ids_parent = similar(boundaries.neighbor_ids)
for (idx, id) in enumerate(boundaries.neighbor_ids)
parent_id = mesh.cell_ids[id]
for interface in eachindex(interfaces_parent.neighbor_ids[1, :])
if (parent_id == interfaces_parent.neighbor_ids[1, interface] ||
parent_id == interfaces_parent.neighbor_ids[2, interface])
if parent_id == interfaces_parent.neighbor_ids[1, interface]
matching_boundary = 1
else
matching_boundary = 2
end
if (boundaries.name[idx] ==
node_indices_to_name(interfaces_parent.node_indices[matching_boundary,
interface]))
if parent_id == interfaces_parent.neighbor_ids[1, interface]
neighbor_ids_parent[idx] = interfaces_parent.neighbor_ids[2,
interface]
else
neighbor_ids_parent[idx] = interfaces_parent.neighbor_ids[1,
interface]
end
end
end
end
parent_xneg_cell_ids = boundaries_parent.neighbor_ids[boundaries_parent.name .== :x_neg]
parent_xpos_cell_ids = boundaries_parent.neighbor_ids[boundaries_parent.name .== :x_pos]
parent_yneg_cell_ids = boundaries_parent.neighbor_ids[boundaries_parent.name .== :y_neg]
parent_ypos_cell_ids = boundaries_parent.neighbor_ids[boundaries_parent.name .== :y_pos]
for (parent_idx, boundary) in enumerate(boundaries_parent.neighbor_ids)
if parent_id == boundary
if boundaries.name[idx] == boundaries_parent.name[parent_idx]
if boundaries_parent.name[parent_idx] == :x_neg
neighbor_ids_parent[idx] = parent_xpos_cell_ids[findfirst(parent_xneg_cell_ids .==
boundary)]
elseif boundaries_parent.name[parent_idx] == :x_pos
neighbor_ids_parent[idx] = parent_xneg_cell_ids[findfirst(parent_xpos_cell_ids .==
boundary)]
elseif boundaries_parent.name[parent_idx] == :y_neg
neighbor_ids_parent[idx] = parent_ypos_cell_ids[findfirst(parent_yneg_cell_ids .==
boundary)]
elseif boundaries_parent.name[parent_idx] == :y_pos
neighbor_ids_parent[idx] = parent_yneg_cell_ids[findfirst(parent_ypos_cell_ids .==
boundary)]
else
error("Unknown boundary name: $(boundaries_parent.name[parent_idx])")
end
end
end
end
end
return neighbor_ids_parent
end
function node_indices_to_name(node_index)
if node_index == (:end, :i_forward)
return :x_pos
elseif node_index == (:begin, :i_forward)
return :x_neg
elseif node_index == (:i_forward, :end)
return :y_pos
elseif node_index == (:i_forward, :begin)
return :y_neg
else
error("Unknown node index: $node_index")
end
end
function parent_cell_id_to_view(id::Integer, mesh::P4estMeshView)
view_id = searchsortedfirst(mesh.cell_ids, id)
return view_id
end
function parent_cell_id_to_view(ids::AbstractArray, mesh::P4estMeshView)
view_id = zeros(Int, length(ids))
for i in eachindex(ids)
view_id[i] = parent_cell_id_to_view(ids[i], mesh)
end
return view_id
end
function save_mesh_file(mesh::P4estMeshView, output_directory; system = "",
timestep = 0)
mkpath(output_directory)
filename = joinpath(output_directory, "mesh.h5")
p4est_filename = "p4est_data"
p4est_file = joinpath(output_directory, p4est_filename)
save_p4est!(p4est_file, mesh.parent.p4est)
h5open(filename, "w") do file
attributes(file)["mesh_type"] = get_name(mesh)
attributes(file)["ndims"] = ndims(mesh)
attributes(file)["p4est_file"] = p4est_filename
attributes(file)["cell_ids"] = mesh.cell_ids
file["tree_node_coordinates"] = mesh.parent.tree_node_coordinates
file["nodes"] = Vector(mesh.parent.nodes)
file["boundary_names"] = mesh.parent.boundary_names .|> String
return nothing
end
return filename
end
function calc_node_coordinates!(node_coordinates,
mesh::P4estMeshView{2, NDIMS_AMBIENT},
nodes::AbstractVector) where {NDIMS_AMBIENT}
tmp1 = StrideArray(undef, real(mesh),
StaticInt(NDIMS_AMBIENT), static_length(nodes),
static_length(mesh.parent.nodes))
matrix1 = StrideArray(undef, real(mesh),
static_length(nodes), static_length(mesh.parent.nodes))
matrix2 = similar(matrix1)
baryweights_in = barycentric_weights(mesh.parent.nodes)
p4est_root_len = 1 << P4EST_MAXLEVEL
p4est_quadrant_len(l) = 1 << (P4EST_MAXLEVEL - l)
trees = unsafe_wrap_sc(p4est_tree_t, mesh.parent.p4est.trees)
mesh_view_cell_id = 0
for tree_id in eachindex(trees)
tree_offset = trees[tree_id].quadrants_offset
quadrants = unsafe_wrap_sc(p4est_quadrant_t, trees[tree_id].quadrants)
for i in eachindex(quadrants)
parent_mesh_cell_id = tree_offset + i
if !(parent_mesh_cell_id in mesh.cell_ids)
continue
end
mesh_view_cell_id += 1
quad = quadrants[i]
quad_length = p4est_quadrant_len(quad.level) / p4est_root_len
nodes_out_x = 2 * (quad_length * 1 / 2 * (nodes .+ 1) .+
quad.x / p4est_root_len) .- 1
nodes_out_y = 2 * (quad_length * 1 / 2 * (nodes .+ 1) .+
quad.y / p4est_root_len) .- 1
polynomial_interpolation_matrix!(matrix1, mesh.parent.nodes, nodes_out_x,
baryweights_in)
polynomial_interpolation_matrix!(matrix2, mesh.parent.nodes, nodes_out_y,
baryweights_in)
multiply_dimensionwise!(view(node_coordinates, :, :, :, mesh_view_cell_id),
matrix1, matrix2,
view(mesh.parent.tree_node_coordinates, :, :, :,
tree_id),
tmp1)
end
end
return node_coordinates
end
@inline mpi_parallel(mesh::P4estMeshView) = False()
end