Path: blob/main/src/solvers/dgsem_structured/containers_3d.jl
5590 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# Initialize data structures in element container8function init_elements!(elements, mesh::StructuredMesh{3}, basis::LobattoLegendreBasis)9@unpack node_coordinates, left_neighbors,10jacobian_matrix, contravariant_vectors, inverse_jacobian = elements1112linear_indices = LinearIndices(size(mesh))1314# Calculate node coordinates, Jacobian matrix, and inverse Jacobian determinant15for cell_z in 1:size(mesh, 3), cell_y in 1:size(mesh, 2), cell_x in 1:size(mesh, 1)16element = linear_indices[cell_x, cell_y, cell_z]1718calc_node_coordinates!(node_coordinates, element, cell_x, cell_y, cell_z,19mesh.mapping, mesh, basis)2021calc_jacobian_matrix!(jacobian_matrix, element, node_coordinates, basis)2223calc_contravariant_vectors!(contravariant_vectors, element, jacobian_matrix,24node_coordinates, basis)2526calc_inverse_jacobian!(inverse_jacobian, element, jacobian_matrix, basis)27end2829initialize_left_neighbor_connectivity!(left_neighbors, mesh, linear_indices)3031return nothing32end3334# Calculate physical coordinates to which every node of the reference element is mapped35# `mesh.mapping` is passed as an additional argument for type stability (function barrier)36function calc_node_coordinates!(node_coordinates, element,37cell_x, cell_y, cell_z,38mapping, mesh::StructuredMesh{3},39basis::LobattoLegendreBasis)40@unpack nodes = basis4142# Get cell length in reference mesh43dx = 2 / size(mesh, 1)44dy = 2 / size(mesh, 2)45dz = 2 / size(mesh, 3)4647# Calculate node coordinates of reference mesh48cell_x_offset = -1 + (cell_x - 1) * dx + dx / 249cell_y_offset = -1 + (cell_y - 1) * dy + dy / 250cell_z_offset = -1 + (cell_z - 1) * dz + dz / 25152for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)53# node_coordinates are the mapped reference node_coordinates54node_coordinates[:, i, j, k, element] .= mapping(cell_x_offset +55dx / 2 * nodes[i],56cell_y_offset +57dy / 2 * nodes[j],58cell_z_offset +59dz / 2 * nodes[k])60end6162return nothing63end6465# Calculate Jacobian matrix of the mapping from the reference element to the element in the physical domain66function calc_jacobian_matrix!(jacobian_matrix::AbstractArray{<:Any, 6}, element,67node_coordinates, basis)68# The code below is equivalent to the following matrix multiplications but much faster.69#70# for dim in 1:3, j in eachnode(basis), i in eachnode(basis)71# # ∂/∂ξ72# jacobian_matrix[dim, 1, :, i, j, element] = basis.derivative_matrix * node_coordinates[dim, :, i, j, element]73# # ∂/∂η74# jacobian_matrix[dim, 2, i, :, j, element] = basis.derivative_matrix * node_coordinates[dim, i, :, j, element]75# # ∂/∂ζ76# jacobian_matrix[dim, 3, i, j, :, element] = basis.derivative_matrix * node_coordinates[dim, i, j, :, element]77# end7879@turbo for dim in 1:3, k in eachnode(basis), j in eachnode(basis),80i in eachnode(basis)8182result = zero(eltype(jacobian_matrix))8384for ii in eachnode(basis)85result += basis.derivative_matrix[i, ii] *86node_coordinates[dim, ii, j, k, element]87end8889jacobian_matrix[dim, 1, i, j, k, element] = result90end9192@turbo for dim in 1:3, k in eachnode(basis), j in eachnode(basis),93i in eachnode(basis)9495result = zero(eltype(jacobian_matrix))9697for ii in eachnode(basis)98result += basis.derivative_matrix[j, ii] *99node_coordinates[dim, i, ii, k, element]100end101102jacobian_matrix[dim, 2, i, j, k, element] = result103end104105@turbo for dim in 1:3, k in eachnode(basis), j in eachnode(basis),106i in eachnode(basis)107108result = zero(eltype(jacobian_matrix))109110for ii in eachnode(basis)111result += basis.derivative_matrix[k, ii] *112node_coordinates[dim, i, j, ii, element]113end114115jacobian_matrix[dim, 3, i, j, k, element] = result116end117118return jacobian_matrix119end120121# Calculate contravariant vectors, multiplied by the Jacobian determinant J of the transformation mapping,122# using the invariant curl form.123# These are called Ja^i in Kopriva's blue book.124function calc_contravariant_vectors!(contravariant_vectors::AbstractArray{<:Any, 6},125element,126jacobian_matrix, node_coordinates,127basis::LobattoLegendreBasis)128@unpack derivative_matrix = basis129130# The general form is131# Jaⁱₙ = 0.5 * ( ∇ × (Xₘ ∇ Xₗ - Xₗ ∇ Xₘ) )ᵢ where (n, m, l) cyclic and ∇ = (∂/∂ξ, ∂/∂η, ∂/∂ζ)ᵀ132133for n in 1:3134# (n, m, l) cyclic135m = (n % 3) + 1136l = ((n + 1) % 3) + 1137138# Calculate Ja¹ₙ = 0.5 * [ (Xₘ Xₗ_ζ - Xₗ Xₘ_ζ)_η - (Xₘ Xₗ_η - Xₗ Xₘ_η)_ζ ]139# For each of these, the first and second summand are computed in separate loops140# for performance reasons.141142# First summand 0.5 * (Xₘ Xₗ_ζ - Xₗ Xₘ_ζ)_η143@turbo for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)144result = zero(eltype(contravariant_vectors))145146for ii in eachnode(basis)147# Multiply derivative_matrix to j-dimension to differentiate wrt η148result += 0.5f0 * derivative_matrix[j, ii] *149(node_coordinates[m, i, ii, k, element] *150jacobian_matrix[l, 3, i, ii, k, element] -151node_coordinates[l, i, ii, k, element] *152jacobian_matrix[m, 3, i, ii, k, element])153end154155contravariant_vectors[n, 1, i, j, k, element] = result156end157158# Second summand -0.5 * (Xₘ Xₗ_η - Xₗ Xₘ_η)_ζ159@turbo for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)160result = zero(eltype(contravariant_vectors))161162for ii in eachnode(basis)163# Multiply derivative_matrix to k-dimension to differentiate wrt ζ164result += 0.5f0 * derivative_matrix[k, ii] *165(node_coordinates[m, i, j, ii, element] *166jacobian_matrix[l, 2, i, j, ii, element] -167node_coordinates[l, i, j, ii, element] *168jacobian_matrix[m, 2, i, j, ii, element])169end170171contravariant_vectors[n, 1, i, j, k, element] -= result172end173174# Calculate Ja²ₙ = 0.5 * [ (Xₘ Xₗ_ξ - Xₗ Xₘ_ξ)_ζ - (Xₘ Xₗ_ζ - Xₗ Xₘ_ζ)_ξ ]175176# First summand 0.5 * (Xₘ Xₗ_ξ - Xₗ Xₘ_ξ)_ζ177@turbo for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)178result = zero(eltype(contravariant_vectors))179180for ii in eachnode(basis)181# Multiply derivative_matrix to k-dimension to differentiate wrt ζ182result += 0.5f0 * derivative_matrix[k, ii] *183(node_coordinates[m, i, j, ii, element] *184jacobian_matrix[l, 1, i, j, ii, element] -185node_coordinates[l, i, j, ii, element] *186jacobian_matrix[m, 1, i, j, ii, element])187end188189contravariant_vectors[n, 2, i, j, k, element] = result190end191192# Second summand -0.5 * (Xₘ Xₗ_ζ - Xₗ Xₘ_ζ)_ξ193@turbo for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)194result = zero(eltype(contravariant_vectors))195196for ii in eachnode(basis)197# Multiply derivative_matrix to i-dimension to differentiate wrt ξ198result += 0.5f0 * derivative_matrix[i, ii] *199(node_coordinates[m, ii, j, k, element] *200jacobian_matrix[l, 3, ii, j, k, element] -201node_coordinates[l, ii, j, k, element] *202jacobian_matrix[m, 3, ii, j, k, element])203end204205contravariant_vectors[n, 2, i, j, k, element] -= result206end207208# Calculate Ja³ₙ = 0.5 * [ (Xₘ Xₗ_η - Xₗ Xₘ_η)_ξ - (Xₘ Xₗ_ξ - Xₗ Xₘ_ξ)_η ]209210# First summand 0.5 * (Xₘ Xₗ_η - Xₗ Xₘ_η)_ξ211@turbo for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)212result = zero(eltype(contravariant_vectors))213214for ii in eachnode(basis)215# Multiply derivative_matrix to i-dimension to differentiate wrt ξ216result += 0.5f0 * derivative_matrix[i, ii] *217(node_coordinates[m, ii, j, k, element] *218jacobian_matrix[l, 2, ii, j, k, element] -219node_coordinates[l, ii, j, k, element] *220jacobian_matrix[m, 2, ii, j, k, element])221end222223contravariant_vectors[n, 3, i, j, k, element] = result224end225226# Second summand -0.5 * (Xₘ Xₗ_ξ - Xₗ Xₘ_ξ)_η227@turbo for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)228result = zero(eltype(contravariant_vectors))229230for ii in eachnode(basis)231# Multiply derivative_matrix to j-dimension to differentiate wrt η232result += 0.5f0 * derivative_matrix[j, ii] *233(node_coordinates[m, i, ii, k, element] *234jacobian_matrix[l, 1, i, ii, k, element] -235node_coordinates[l, i, ii, k, element] *236jacobian_matrix[m, 1, i, ii, k, element])237end238239contravariant_vectors[n, 3, i, j, k, element] -= result240end241end242243return contravariant_vectors244end245246# Calculate inverse Jacobian (determinant of Jacobian matrix of the mapping) in each node247function calc_inverse_jacobian!(inverse_jacobian::AbstractArray{<:Any, 4}, element,248jacobian_matrix, basis)249@turbo for k in eachnode(basis), j in eachnode(basis), i in eachnode(basis)250# Calculate Determinant by using Sarrus formula (about 100 times faster than LinearAlgebra.det())251inverse_jacobian[i, j, k, element] = inv(jacobian_matrix[1, 1, i, j, k,252element] *253jacobian_matrix[2, 2, i, j, k,254element] *255jacobian_matrix[3, 3, i, j, k, element] +256jacobian_matrix[1, 2, i, j, k,257element] *258jacobian_matrix[2, 3, i, j, k,259element] *260jacobian_matrix[3, 1, i, j, k, element] +261jacobian_matrix[1, 3, i, j, k,262element] *263jacobian_matrix[2, 1, i, j, k,264element] *265jacobian_matrix[3, 2, i, j, k, element] -266jacobian_matrix[3, 1, i, j, k,267element] *268jacobian_matrix[2, 2, i, j, k,269element] *270jacobian_matrix[1, 3, i, j, k, element] -271jacobian_matrix[3, 2, i, j, k,272element] *273jacobian_matrix[2, 3, i, j, k,274element] *275jacobian_matrix[1, 1, i, j, k, element] -276jacobian_matrix[3, 3, i, j, k,277element] *278jacobian_matrix[2, 1, i, j, k,279element] *280jacobian_matrix[1, 2, i, j, k, element])281end282283return inverse_jacobian284end285286# Save id of left neighbor of every element287function initialize_left_neighbor_connectivity!(left_neighbors, mesh::StructuredMesh{3},288linear_indices)289# Neighbors in x-direction290for cell_z in 1:size(mesh, 3), cell_y in 1:size(mesh, 2)291# Inner elements292for cell_x in 2:size(mesh, 1)293element = linear_indices[cell_x, cell_y, cell_z]294left_neighbors[1, element] = linear_indices[cell_x - 1, cell_y, cell_z]295end296297if isperiodic(mesh, 1)298# Periodic boundary299left_neighbors[1, linear_indices[1, cell_y, cell_z]] = linear_indices[end,300cell_y,301cell_z]302else303left_neighbors[1, linear_indices[1, cell_y, cell_z]] = 0304end305end306307# Neighbors in y-direction308for cell_z in 1:size(mesh, 3), cell_x in 1:size(mesh, 1)309# Inner elements310for cell_y in 2:size(mesh, 2)311element = linear_indices[cell_x, cell_y, cell_z]312left_neighbors[2, element] = linear_indices[cell_x, cell_y - 1, cell_z]313end314315if isperiodic(mesh, 2)316# Periodic boundary317left_neighbors[2, linear_indices[cell_x, 1, cell_z]] = linear_indices[cell_x,318end,319cell_z]320else321left_neighbors[2, linear_indices[cell_x, 1, cell_z]] = 0322end323end324325# Neighbors in z-direction326for cell_y in 1:size(mesh, 2), cell_x in 1:size(mesh, 1)327# Inner elements328for cell_z in 2:size(mesh, 3)329element = linear_indices[cell_x, cell_y, cell_z]330left_neighbors[3, element] = linear_indices[cell_x, cell_y, cell_z - 1]331end332333if isperiodic(mesh, 3)334# Periodic boundary335left_neighbors[3, linear_indices[cell_x, cell_y, 1]] = linear_indices[cell_x,336cell_y,337end]338else339left_neighbors[3, linear_indices[cell_x, cell_y, 1]] = 0340end341end342343return left_neighbors344end345346# Compute the normal vectors for freestream-preserving FV method on curvilinear subcells, see347# equations (14) and (B.53) in:348# - Hennemann, Rueda-Ramírez, Hindenlang, Gassner (2020)349# A provably entropy stable subcell shock capturing approach for high order split form DG for the compressible Euler equations350# [arXiv: 2008.12044v2](https://arxiv.org/pdf/2008.12044)351function calc_normalvectors_subcell_fv!(normal_vectors_1, normal_vectors_2,352normal_vectors_3,353mesh::Union{StructuredMesh{3},354P4estMesh{3}, T8codeMesh{3}},355dg, cache_containers)356@unpack contravariant_vectors = cache_containers.elements357@unpack weights, derivative_matrix = dg.basis358359@threaded for element in eachelement(dg, cache_containers)360# First contravariant vector/direction361for k in eachnode(dg), j in eachnode(dg)362# We do not store i = 1, as it is never used, see `calcflux_fv!`.363# => Store i = 2 at position 1364@views normal_vectors_1[:, 1, j, k, element] .= get_contravariant_vector(1,365contravariant_vectors,3661,367j,368k,369element)370for m in eachnode(dg)371wD_im = weights[1] * derivative_matrix[1, m]372@views normal_vectors_1[:, 1, j, k, element] .+= wD_im *373get_contravariant_vector(1,374contravariant_vectors,375m,376j,377k,378element)379end380381for i in 2:(nnodes(dg) - 1) # Actual indices: 3 to nnodes(dg)382@views normal_vectors_1[:, i, j, k, element] .= normal_vectors_1[:,383i - 1,384j,385k,386element]387for m in eachnode(dg)388wD_im = weights[i] * derivative_matrix[i, m]389@views normal_vectors_1[:, i, j, k, element] .+= wD_im *390get_contravariant_vector(1,391contravariant_vectors,392m,393j,394k,395element)396end397end398end399400# Second contravariant vector/direction401for k in eachnode(dg), i in eachnode(dg)402# We do not store j = 1, as it is never used.403# => Store physical j = 2 at position 1404@views normal_vectors_2[:, i, 1, k, element] .= get_contravariant_vector(2,405contravariant_vectors,406i,4071,408k,409element)410for m in eachnode(dg)411wD_jm = weights[1] * derivative_matrix[1, m]412@views normal_vectors_2[:, i, 1, k, element] .+= wD_jm *413get_contravariant_vector(2,414contravariant_vectors,415i,416m,417k,418element)419end420421for j in 2:(nnodes(dg) - 1) # Actual indices: 3 to nnodes(dg)422@views normal_vectors_2[:, i, j, k, element] .= normal_vectors_2[:,423i,424j - 1,425k,426element]427428for m in eachnode(dg)429wD_jm = weights[j] * derivative_matrix[j, m]430@views normal_vectors_2[:, i, j, k, element] .+= wD_jm *431get_contravariant_vector(2,432contravariant_vectors,433i,434m,435k,436element)437end438end439end440441# Third contravariant vector/direction442for j in eachnode(dg), i in eachnode(dg)443# We do not store k = 1, as it is never used.444# => Store physical k = 2 at position 1445@views normal_vectors_3[:, i, j, 1, element] .= get_contravariant_vector(3,446contravariant_vectors,447i,448j,4491,450element)451for m in eachnode(dg)452wD_km = weights[1] * derivative_matrix[1, m]453@views normal_vectors_3[:, i, j, 1, element] .+= wD_km *454get_contravariant_vector(3,455contravariant_vectors,456i,457j,458m,459element)460end461462for k in 2:(nnodes(dg) - 1) # Actual indices: 3 to nnodes(dg)463@views normal_vectors_3[:, i, j, k, element] .= normal_vectors_3[:,464i,465j,466k - 1,467element]468for m in eachnode(dg)469wD_km = weights[k] * derivative_matrix[k, m]470@views normal_vectors_3[:, i, j, k, element] .+= wD_km *471get_contravariant_vector(3,472contravariant_vectors,473i,474j,475m,476element)477end478end479end480end481482return nothing483end484485# Used for both fixed (`StructuredMesh{3}`)486# and adaptive meshes (`P4estMesh{3}` or `T8codeMesh{3}`)487mutable struct NormalVectorContainer3D{RealT <: Real} <:488AbstractNormalVectorContainer489const n_nodes::Int490# For normal vectors computed from first contravariant vectors491normal_vectors_1::Array{RealT, 5} # [NDIMS, NNODES - 1, NNODES, NNODES, NELEMENTS]492# For normal vectors computed from second contravariant vectors493normal_vectors_2::Array{RealT, 5} # [NDIMS, NNODES, NNODES - 1, NNODES, NELEMENTS]494# For normal vectors computed from third contravariant vectors495normal_vectors_3::Array{RealT, 5} # [NDIMS, NNODES, NNODES, NNODES - 1, NELEMENTS]496497# internal `resize!`able storage498_normal_vectors_1::Vector{RealT}499_normal_vectors_2::Vector{RealT}500_normal_vectors_3::Vector{RealT}501end502503function NormalVectorContainer3D(mesh::Union{StructuredMesh{3},504P4estMesh{3}, T8codeMesh{3}},505dg, cache_containers)506@unpack contravariant_vectors = cache_containers.elements507RealT = eltype(contravariant_vectors)508n_elements = nelements(dg, cache_containers)509n_nodes = nnodes(dg.basis)510511_normal_vectors_1 = Vector{RealT}(undef,5123 * (n_nodes - 1) * n_nodes * n_nodes *513n_elements)514normal_vectors_1 = unsafe_wrap(Array, pointer(_normal_vectors_1),515(3, n_nodes - 1, n_nodes, n_nodes,516n_elements))517518_normal_vectors_2 = Vector{RealT}(undef,5193 * n_nodes * (n_nodes - 1) * n_nodes *520n_elements)521normal_vectors_2 = unsafe_wrap(Array, pointer(_normal_vectors_2),522(3, n_nodes, n_nodes - 1, n_nodes,523n_elements))524525_normal_vectors_3 = Vector{RealT}(undef,5263 * n_nodes * n_nodes * (n_nodes - 1) *527n_elements)528normal_vectors_3 = unsafe_wrap(Array, pointer(_normal_vectors_3),529(3, n_nodes, n_nodes, n_nodes - 1,530n_elements))531532calc_normalvectors_subcell_fv!(normal_vectors_1, normal_vectors_2, normal_vectors_3,533mesh, dg, cache_containers)534535return NormalVectorContainer3D{RealT}(n_nodes,536normal_vectors_1, normal_vectors_2,537normal_vectors_3,538_normal_vectors_1, _normal_vectors_2,539_normal_vectors_3)540end541542# Required only for adaptive meshes (`P4estMesh` or `T8codeMesh`)543function Base.resize!(normal_vectors::NormalVectorContainer3D, capacity)544@unpack n_nodes, _normal_vectors_1, _normal_vectors_2, _normal_vectors_3 = normal_vectors545ArrayType = storage_type(normal_vectors)546547resize!(_normal_vectors_1, 3 * (n_nodes - 1) * n_nodes * n_nodes * capacity)548normal_vectors.normal_vectors_1 = unsafe_wrap_or_alloc(ArrayType, _normal_vectors_1,549(3,550n_nodes - 1,551n_nodes,552n_nodes,553capacity))554555resize!(_normal_vectors_2, 3 * n_nodes * (n_nodes - 1) * n_nodes * capacity)556normal_vectors.normal_vectors_2 = unsafe_wrap_or_alloc(ArrayType, _normal_vectors_2,557(3,558n_nodes,559n_nodes - 1,560n_nodes,561capacity))562563resize!(_normal_vectors_3, 3 * n_nodes * n_nodes * (n_nodes - 1) * capacity)564normal_vectors.normal_vectors_3 = unsafe_wrap_or_alloc(ArrayType, _normal_vectors_3,565(3,566n_nodes,567n_nodes,568n_nodes - 1,569capacity))570571return nothing572end573574# Required only for adaptive meshes (`P4estMesh` or `T8codeMesh`)575function init_normal_vectors!(normal_vectors::NormalVectorContainer3D,576mesh::Union{P4estMesh{3}, T8codeMesh{3}}, dg, cache)577@unpack normal_vectors_1, normal_vectors_2, normal_vectors_3 = normal_vectors578calc_normalvectors_subcell_fv!(normal_vectors_1, normal_vectors_2, normal_vectors_3,579mesh, dg, cache)580581return nothing582end583end # @muladd584585586