Path: blob/main/src/callbacks_step/amr_dg1d.jl
5586 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@trixi_timeit timer() "reinitialize data structures" begin26reinitialize_containers!(mesh, equations, dg, cache)27end28@assert nelements(dg, cache) > old_n_elements2930resize!(u_ode,31nvariables(equations) * nnodes(dg)^ndims(mesh) * nelements(dg, cache))32u = wrap_array(u_ode, mesh, equations, dg, cache)3334# Loop over all elements in old container and either copy them or refine them35element_id = 136for old_element_id in 1:old_n_elements37if needs_refinement[old_element_id]38# Refine element and store solution directly in new data structure39refine_element!(u, element_id, old_u, old_element_id,40adaptor, equations, dg)41element_id += 2^ndims(mesh)42else43# Copy old element data to new element container44@views u[:, .., element_id] .= old_u[:, .., old_element_id]45element_id += 146end47end48# If everything is correct, we should have processed all elements.49# Depending on whether the last element processed above had to be refined or not,50# the counter `element_id` can have two different values at the end.51@assert element_id ==52nelements(dg, cache) +531||element_id == nelements(dg, cache) + 2^ndims(mesh) "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))"54end # GC.@preserve old_u_ode5556# Sanity check57if isperiodic(mesh.tree)58@assert ninterfaces(cache.interfaces)==1 * nelements(dg, cache) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements")59end6061return nothing62end6364function refine!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1},65equations, dg::DGSEM, cache, cache_parabolic,66elements_to_refine)67# Call `refine!` for the hyperbolic part, which does the heavy lifting of68# actually transferring the solution to the refined cells69refine!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_refine)7071# Resize parabolic helper variables72@unpack parabolic_container = cache_parabolic73resize!(parabolic_container, equations, dg, cache)7475return nothing76end7778# TODO: Taal compare performance of different implementations79# Refine solution data u for an element, using L2 projection (interpolation)80function refine_element!(u::AbstractArray{<:Any, 3}, element_id,81old_u, old_element_id,82adaptor::LobattoLegendreAdaptorL2, equations, dg)83@unpack forward_upper, forward_lower = adaptor8485# Store new element ids86left_id = element_id87right_id = element_id + 18889@boundscheck begin90@assert old_element_id >= 191@assert size(old_u, 1) == nvariables(equations)92@assert size(old_u, 2) == nnodes(dg)93@assert size(old_u, 3) >= old_element_id94@assert element_id >= 195@assert size(u, 1) == nvariables(equations)96@assert size(u, 2) == nnodes(dg)97@assert size(u, 3) >= element_id + 198end99100# Interpolate to left element101for i in eachnode(dg)102acc = zero(get_node_vars(u, equations, dg, i, element_id))103for k in eachnode(dg)104acc += get_node_vars(old_u, equations, dg, k, old_element_id) *105forward_lower[i, k]106end107set_node_vars!(u, acc, equations, dg, i, left_id)108end109110# Interpolate to right element111for i in eachnode(dg)112acc = zero(get_node_vars(u, equations, dg, i, element_id))113for k in eachnode(dg)114acc += get_node_vars(old_u, equations, dg, k, old_element_id) *115forward_upper[i, k]116end117set_node_vars!(u, acc, equations, dg, i, right_id)118end119120return nothing121end122123# Coarsen elements in the DG solver based on a list of cell_ids that should be removed124function coarsen!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1},125equations, dg::DGSEM, cache, elements_to_remove)126# Return early if there is nothing to do127if isempty(elements_to_remove)128return129end130131# Determine for each old element whether it needs to be removed132to_be_removed = falses(nelements(dg, cache))133to_be_removed[elements_to_remove] .= true134135# Retain current solution data136old_n_elements = nelements(dg, cache)137old_u_ode = copy(u_ode)138GC.@preserve old_u_ode begin # OBS! If we don't GC.@preserve old_u_ode, it might be GC'ed139old_u = wrap_array(old_u_ode, mesh, equations, dg, cache)140141@trixi_timeit timer() "reinitialize data structures" begin142reinitialize_containers!(mesh, equations, dg, cache)143end144@assert nelements(dg, cache) < old_n_elements145146resize!(u_ode,147nvariables(equations) * nnodes(dg)^ndims(mesh) * nelements(dg, cache))148u = wrap_array(u_ode, mesh, equations, dg, cache)149150# Loop over all elements in old container and either copy them or coarsen them151skip = 0152element_id = 1153for old_element_id in 1:old_n_elements154# If skip is non-zero, we just coarsened 2^ndims elements and need to omit the following elements155if skip > 0156skip -= 1157continue158end159160if to_be_removed[old_element_id]161# If an element is to be removed, sanity check if the following elements162# are also marked - otherwise there would be an error in the way the163# cells/elements are sorted164@assert all(to_be_removed[old_element_id:(old_element_id + 2^ndims(mesh) - 1)]) "bad cell/element order"165166# Coarsen elements and store solution directly in new data structure167coarsen_elements!(u, element_id, old_u, old_element_id,168adaptor, equations, dg)169element_id += 1170skip = 2^ndims(mesh) - 1171else172# Copy old element data to new element container173@views u[:, .., element_id] .= old_u[:, .., old_element_id]174element_id += 1175end176end177# If everything is correct, we should have processed all elements.178@assert element_id==nelements(dg, cache) + 1 "element_id = $element_id, nelements(dg, cache) = $(nelements(dg, cache))"179end # GC.@preserve old_u_ode180181# Sanity check182if isperiodic(mesh.tree)183@assert ninterfaces(cache.interfaces)==1 * nelements(dg, cache) ("For 1D and periodic domains, the number of interfaces must be the same as the number of elements")184end185186return nothing187end188189function coarsen!(u_ode::AbstractVector, adaptor, mesh::TreeMesh{1},190equations, dg::DGSEM, cache, cache_parabolic,191elements_to_remove)192# Call `coarsen!` for the hyperbolic part, which does the heavy lifting of193# actually transferring the solution to the coarsened cells194coarsen!(u_ode, adaptor, mesh, equations, dg, cache, elements_to_remove)195196# Resize parabolic helper variables197@unpack parabolic_container = cache_parabolic198resize!(parabolic_container, equations, dg, cache)199200return nothing201end202203# TODO: Taal compare performance of different implementations204# Coarsen solution data u for two elements, using L2 projection205function coarsen_elements!(u::AbstractArray{<:Any, 3}, element_id,206old_u, old_element_id,207adaptor::LobattoLegendreAdaptorL2, equations, dg)208@unpack reverse_upper, reverse_lower = adaptor209210# Store old element ids211left_id = old_element_id212right_id = old_element_id + 1213214@boundscheck begin215@assert old_element_id >= 1216@assert size(old_u, 1) == nvariables(equations)217@assert size(old_u, 2) == nnodes(dg)218@assert size(old_u, 3) >= old_element_id + 1219@assert element_id >= 1220@assert size(u, 1) == nvariables(equations)221@assert size(u, 2) == nnodes(dg)222@assert size(u, 3) >= element_id223end224225for i in eachnode(dg)226acc = zero(get_node_vars(u, equations, dg, i, element_id))227228# Project from lower left element229for k in eachnode(dg)230acc += get_node_vars(old_u, equations, dg, k, left_id) * reverse_lower[i, k]231end232233# Project from lower right element234for k in eachnode(dg)235acc += get_node_vars(old_u, equations, dg, k, right_id) *236reverse_upper[i, k]237end238239# Update value240set_node_vars!(u, acc, equations, dg, i, element_id)241end242243return nothing244end245end # @muladd246247248