Path: blob/main/src/callbacks_step/amr_dg1d.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# Refine elements in the DG solver based on a list of cell_ids that should be refined8function refine!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1},9equations, dg::DGSEM, cache, elements_to_refine)10# Return early if there is nothing to do11if isempty(elements_to_refine)12return13end1415# Determine for each existing element whether it needs to be refined16needs_refinement = falses(nelements(dg, cache))17needs_refinement[elements_to_refine] .= true1819# Retain current solution data20old_n_elements = nelements(dg, cache)21old_u_ode = copy(u_ode)22GC.@preserve old_u_ode begin # OBS! If we don't GC.@preserve old_u_ode, it might be GC'ed23old_u = wrap_array(old_u_ode, mesh, equations, dg, cache)2425# Get new list of leaf cells26leaf_cell_ids = local_leaf_cells(mesh.tree)2728# re-initialize elements container29@unpack elements = cache30resize!(elements, length(leaf_cell_ids))31init_elements!(elements, leaf_cell_ids, mesh, dg.basis)32@assert nelements(dg, cache) > old_n_elements3334resize!(u_ode,35nvariables(equations) * nnodes(dg)^ndims(mesh) * nelements(dg, cache))36u = wrap_array(u_ode, mesh, equations, dg, cache)3738# Loop over all elements in old container and either copy them or refine them39element_id = 140for old_element_id in 1:old_n_elements41if needs_refinement[old_element_id]42# Refine element and store solution directly in new data structure43refine_element!(u, element_id, old_u, old_element_id,44adaptor, equations, dg)45element_id += 2^ndims(mesh)46else47# Copy old element data to new element container48@views u[:, .., element_id] .= old_u[:, .., old_element_id]49element_id += 150end51end52# If everything is correct, we should have processed all elements.53# Depending on whether the last element processed above had to be refined or not,54# the counter `element_id` can have two different values at the end.55@assert element_id ==56nelements(dg, cache) +571||element_id == nelements(dg, cache) + 2^ndims(mesh) "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))"58end # GC.@preserve old_u_ode5960# re-initialize interfaces container61@unpack interfaces = cache62resize!(interfaces, count_required_interfaces(mesh, leaf_cell_ids))63init_interfaces!(interfaces, elements, mesh)6465# re-initialize boundaries container66@unpack boundaries = cache67resize!(boundaries, count_required_boundaries(mesh, leaf_cell_ids))68init_boundaries!(boundaries, elements, mesh)6970# Sanity check71if isperiodic(mesh.tree)72@assert ninterfaces(interfaces)==1 * nelements(dg, cache) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements")73end7475return nothing76end7778function refine!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1},79equations, dg::DGSEM, cache, cache_parabolic,80elements_to_refine)81# Call `refine!` for the hyperbolic part, which does the heavy lifting of82# actually transferring the solution to the refined cells83refine!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_refine)8485# Resize parabolic helper variables86@unpack viscous_container = cache_parabolic87resize!(viscous_container, equations, dg, cache)88reinitialize_containers!(mesh, equations, dg, cache_parabolic)8990# Sanity check91@unpack interfaces = cache_parabolic92if isperiodic(mesh.tree)93@assert ninterfaces(interfaces)==1 * nelements(dg, cache_parabolic) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements")94end9596return nothing97end9899# TODO: Taal compare performance of different implementations100# Refine solution data u for an element, using L2 projection (interpolation)101function refine_element!(u::AbstractArray{<:Any, 3}, element_id,102old_u, old_element_id,103adaptor::LobattoLegendreAdaptorL2, equations, dg)104@unpack forward_upper, forward_lower = adaptor105106# Store new element ids107left_id = element_id108right_id = element_id + 1109110@boundscheck begin111@assert old_element_id >= 1112@assert size(old_u, 1) == nvariables(equations)113@assert size(old_u, 2) == nnodes(dg)114@assert size(old_u, 3) >= old_element_id115@assert element_id >= 1116@assert size(u, 1) == nvariables(equations)117@assert size(u, 2) == nnodes(dg)118@assert size(u, 3) >= element_id + 1119end120121# Interpolate to left element122for i in eachnode(dg)123acc = zero(get_node_vars(u, equations, dg, i, element_id))124for k in eachnode(dg)125acc += get_node_vars(old_u, equations, dg, k, old_element_id) *126forward_lower[i, k]127end128set_node_vars!(u, acc, equations, dg, i, left_id)129end130131# Interpolate to right element132for i in eachnode(dg)133acc = zero(get_node_vars(u, equations, dg, i, element_id))134for k in eachnode(dg)135acc += get_node_vars(old_u, equations, dg, k, old_element_id) *136forward_upper[i, k]137end138set_node_vars!(u, acc, equations, dg, i, right_id)139end140141return nothing142end143144# Coarsen elements in the DG solver based on a list of cell_ids that should be removed145function coarsen!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1},146equations, dg::DGSEM, cache, elements_to_remove)147# Return early if there is nothing to do148if isempty(elements_to_remove)149return150end151152# Determine for each old element whether it needs to be removed153to_be_removed = falses(nelements(dg, cache))154to_be_removed[elements_to_remove] .= true155156# Retain current solution data157old_n_elements = nelements(dg, cache)158old_u_ode = copy(u_ode)159GC.@preserve old_u_ode begin # OBS! If we don't GC.@preserve old_u_ode, it might be GC'ed160old_u = wrap_array(old_u_ode, mesh, equations, dg, cache)161162# Get new list of leaf cells163leaf_cell_ids = local_leaf_cells(mesh.tree)164165# re-initialize elements container166@unpack elements = cache167resize!(elements, length(leaf_cell_ids))168init_elements!(elements, leaf_cell_ids, mesh, dg.basis)169@assert nelements(dg, cache) < old_n_elements170171resize!(u_ode,172nvariables(equations) * nnodes(dg)^ndims(mesh) * nelements(dg, cache))173u = wrap_array(u_ode, mesh, equations, dg, cache)174175# Loop over all elements in old container and either copy them or coarsen them176skip = 0177element_id = 1178for old_element_id in 1:old_n_elements179# If skip is non-zero, we just coarsened 2^ndims elements and need to omit the following elements180if skip > 0181skip -= 1182continue183end184185if to_be_removed[old_element_id]186# If an element is to be removed, sanity check if the following elements187# are also marked - otherwise there would be an error in the way the188# cells/elements are sorted189@assert all(to_be_removed[old_element_id:(old_element_id + 2^ndims(mesh) - 1)]) "bad cell/element order"190191# Coarsen elements and store solution directly in new data structure192coarsen_elements!(u, element_id, old_u, old_element_id,193adaptor, equations, dg)194element_id += 1195skip = 2^ndims(mesh) - 1196else197# Copy old element data to new element container198@views u[:, .., element_id] .= old_u[:, .., old_element_id]199element_id += 1200end201end202# If everything is correct, we should have processed all elements.203@assert element_id==nelements(dg, cache) + 1 "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))"204end # GC.@preserve old_u_ode205206# re-initialize interfaces container207@unpack interfaces = cache208resize!(interfaces, count_required_interfaces(mesh, leaf_cell_ids))209init_interfaces!(interfaces, elements, mesh)210211# re-initialize boundaries container212@unpack boundaries = cache213resize!(boundaries, count_required_boundaries(mesh, leaf_cell_ids))214init_boundaries!(boundaries, elements, mesh)215216# Sanity check217if isperiodic(mesh.tree)218@assert ninterfaces(interfaces)==1 * nelements(dg, cache) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements")219end220221return nothing222end223224function coarsen!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1},225equations, dg::DGSEM, cache, cache_parabolic,226elements_to_remove)227# Call `coarsen!` for the hyperbolic part, which does the heavy lifting of228# actually transferring the solution to the coarsened cells229coarsen!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_remove)230231# Resize parabolic helper variables232@unpack viscous_container = cache_parabolic233resize!(viscous_container, equations, dg, cache)234reinitialize_containers!(mesh, equations, dg, cache_parabolic)235236# Sanity check237@unpack interfaces = cache_parabolic238if isperiodic(mesh.tree)239@assert ninterfaces(interfaces)==1 * nelements(dg, cache_parabolic) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements")240end241242return nothing243end244245# TODO: Taal compare performance of different implementations246# Coarsen solution data u for two elements, using L2 projection247function coarsen_elements!(u::AbstractArray{<:Any, 3}, element_id,248old_u, old_element_id,249adaptor::LobattoLegendreAdaptorL2, equations, dg)250@unpack reverse_upper, reverse_lower = adaptor251252# Store old element ids253left_id = old_element_id254right_id = old_element_id + 1255256@boundscheck begin257@assert old_element_id >= 1258@assert size(old_u, 1) == nvariables(equations)259@assert size(old_u, 2) == nnodes(dg)260@assert size(old_u, 3) >= old_element_id + 1261@assert element_id >= 1262@assert size(u, 1) == nvariables(equations)263@assert size(u, 2) == nnodes(dg)264@assert size(u, 3) >= element_id265end266267for i in eachnode(dg)268acc = zero(get_node_vars(u, equations, dg, i, element_id))269270# Project from lower left element271for k in eachnode(dg)272acc += get_node_vars(old_u, equations, dg, k, left_id) * reverse_lower[i, k]273end274275# Project from lower right element276for k in eachnode(dg)277acc += get_node_vars(old_u, equations, dg, k, right_id) *278reverse_upper[i, k]279end280281# Update value282set_node_vars!(u, acc, equations, dg, i, element_id)283end284285return nothing286end287end # @muladd288289290