Path: blob/main/src/callbacks_step/analysis_dg3d_parallel.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: noindent67function calc_error_norms(func, u, t, analyzer,8mesh::Union{ParallelP4estMesh{3}, ParallelT8codeMesh{3}},9equations,10initial_condition, dg::DGSEM, cache, cache_analysis)11@unpack vandermonde, weights = analyzer12@unpack node_coordinates, inverse_jacobian = cache.elements13@unpack u_local, u_tmp1, u_tmp2, x_local, x_tmp1, x_tmp2, jacobian_local, jacobian_tmp1, jacobian_tmp2 = cache_analysis1415# Set up data structures16l2_error = zero(func(get_node_vars(u, equations, dg, 1, 1, 1, 1), equations))17linf_error = copy(l2_error)18volume = zero(real(mesh))1920# Iterate over all elements for error calculations21for element in eachelement(dg, cache)22# Interpolate solution and node locations to analysis nodes23multiply_dimensionwise!(u_local, vandermonde, view(u, :, :, :, :, element),24u_tmp1, u_tmp2)25multiply_dimensionwise!(x_local, vandermonde,26view(node_coordinates, :, :, :, :, element), x_tmp1,27x_tmp2)28multiply_scalar_dimensionwise!(jacobian_local, vandermonde,29inv.(view(inverse_jacobian, :, :, :, element)),30jacobian_tmp1, jacobian_tmp2)3132# Calculate errors at each analysis node33for k in eachnode(analyzer), j in eachnode(analyzer), i in eachnode(analyzer)34u_exact = initial_condition(get_node_coords(x_local, equations, dg, i, j,35k), t, equations)36diff = func(u_exact, equations) -37func(get_node_vars(u_local, equations, dg, i, j, k), equations)38# We take absolute value as we need the Jacobian here for the volume calculation39abs_jacobian_local_ijk = abs(jacobian_local[i, j, k])4041l2_error += diff .^ 2 *42(weights[i] * weights[j] * weights[k] * abs_jacobian_local_ijk)43linf_error = @. max(linf_error, abs(diff))44volume += weights[i] * weights[j] * weights[k] * abs_jacobian_local_ijk45end46end4748# Accumulate local results on root process49global_l2_error = Vector(l2_error)50global_linf_error = Vector(linf_error)51MPI.Reduce!(global_l2_error, +, mpi_root(), mpi_comm())52# Base.max instead of max needed, see comment in src/auxiliary/math.jl53MPI.Reduce!(global_linf_error, Base.max, mpi_root(), mpi_comm())54total_volume = MPI.Reduce(volume, +, mpi_root(), mpi_comm())55if mpi_isroot()56l2_error = convert(typeof(l2_error), global_l2_error)57linf_error = convert(typeof(linf_error), global_linf_error)58# For L2 error, divide by total volume59l2_error = @. sqrt(l2_error / total_volume)60else61l2_error = convert(typeof(l2_error), NaN * global_l2_error)62linf_error = convert(typeof(linf_error), NaN * global_linf_error)63end6465return l2_error, linf_error66end6768function integrate_via_indices(func::Func, u,69mesh::Union{ParallelP4estMesh{3}, ParallelT8codeMesh{3}},70equations,71dg::DGSEM, cache, args...; normalize = true) where {Func}72@unpack weights = dg.basis7374# Initialize integral with zeros of the right shape75# Pass `zeros(eltype(u), nvariables(equations), nnodes(dg), nnodes(dg), nnodes(dg), 1)`76# to `func` since `u` might be empty, if the current rank has no elements.77# See also https://github.com/trixi-framework/Trixi.jl/issues/1096, and78# https://github.com/trixi-framework/Trixi.jl/pull/2126/files/7cbc57cfcba93e67353566e10fce1f3edac27330#r1814483243.79integral = zero(func(zeros(eltype(u), nvariables(equations), nnodes(dg), nnodes(dg),80nnodes(dg), 1), 1, 1, 1, 1, equations, dg, args...))81volume = zero(real(mesh))8283# Use quadrature to numerically integrate over entire domain84@batch reduction=((+, integral), (+, volume)) for element in eachelement(dg, cache)85for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)86volume_jacobian = abs(inv(cache.elements.inverse_jacobian[i, j, k, element]))87integral += volume_jacobian * weights[i] * weights[j] * weights[k] *88func(u, i, j, k, element, equations, dg, args...)89volume += volume_jacobian * weights[i] * weights[j] * weights[k]90end91end9293global_integral = MPI.Reduce!(Ref(integral), +, mpi_root(), mpi_comm())94total_volume = MPI.Reduce(volume, +, mpi_root(), mpi_comm())95if mpi_isroot()96integral = convert(typeof(integral), global_integral[])97else98integral = convert(typeof(integral), NaN * integral)99total_volume = volume # non-root processes receive nothing from reduce -> overwrite100end101102# Normalize with total volume103if normalize104integral = integral / total_volume105end106107return integral108end109end # @muladd110111112