Path: blob/main/src/solvers/dgsem_p4est/containers_3d.jl
5616 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::Union{P4estMesh{3}, T8codeMesh{3}},9basis::LobattoLegendreBasis)10@unpack node_coordinates, jacobian_matrix,11contravariant_vectors, inverse_jacobian = elements1213calc_node_coordinates!(node_coordinates, mesh, basis)1415for element in 1:ncells(mesh)16calc_jacobian_matrix!(jacobian_matrix, element, node_coordinates, basis)1718calc_contravariant_vectors!(contravariant_vectors, element, jacobian_matrix,19node_coordinates, basis)2021calc_inverse_jacobian!(inverse_jacobian, element, jacobian_matrix, basis)22end2324return nothing25end2627# Interpolate tree_node_coordinates to each quadrant at the nodes of the specified basis28function calc_node_coordinates!(node_coordinates,29mesh::Union{P4estMesh{3}, T8codeMesh{3}},30basis::LobattoLegendreBasis)31# Hanging nodes will cause holes in the mesh if its polydeg is higher32# than the polydeg of the solver.33@assert length(basis.nodes)>=length(mesh.nodes) "The solver can't have a lower polydeg than the mesh"3435return calc_node_coordinates!(node_coordinates, mesh, basis.nodes)36end3738# Interpolate tree_node_coordinates to each quadrant at the specified nodes39function calc_node_coordinates!(node_coordinates,40mesh::P4estMesh{3},41nodes::AbstractVector)42# Macros from `p4est`43p4est_root_len = 1 << P4EST_MAXLEVEL44p4est_quadrant_len(l) = 1 << (P4EST_MAXLEVEL - l)4546trees = unsafe_wrap_sc(p8est_tree_t, mesh.p4est.trees)4748for tree in eachindex(trees)49offset = trees[tree].quadrants_offset50quadrants = unsafe_wrap_sc(p8est_quadrant_t, trees[tree].quadrants)5152for i in eachindex(quadrants)53element = offset + i54quad = quadrants[i]5556quad_length = p4est_quadrant_len(quad.level) / p4est_root_len5758nodes_out_x = 2 * (quad_length * 1 / 2 * (nodes .+ 1) .+59quad.x / p4est_root_len) .- 160nodes_out_y = 2 * (quad_length * 1 / 2 * (nodes .+ 1) .+61quad.y / p4est_root_len) .- 162nodes_out_z = 2 * (quad_length * 1 / 2 * (nodes .+ 1) .+63quad.z / p4est_root_len) .- 16465matrix1 = polynomial_interpolation_matrix(mesh.nodes, nodes_out_x)66matrix2 = polynomial_interpolation_matrix(mesh.nodes, nodes_out_y)67matrix3 = polynomial_interpolation_matrix(mesh.nodes, nodes_out_z)6869multiply_dimensionwise!(view(node_coordinates, :, :, :, :, element),70matrix1, matrix2, matrix3,71view(mesh.tree_node_coordinates, :, :, :, :, tree))72end73end7475return node_coordinates76end7778# Not yet implemented and needed for 3D79function init_normal_directions!(interfaces::P4estInterfaceContainer{3},80basis::LobattoLegendreBasis, elements)81return nothing82end8384# Initialize node_indices of interface container85@inline function init_interface_node_indices!(interfaces::P4estInterfaceContainer{3},86faces, orientation, interface_id)87# Iterate over primary and secondary element88for side in 1:289# Align interface at the primary element (primary element has surface indices (:i_forward, :j_forward)).90# The secondary element needs to be indexed differently.91if side == 192surface_index1 = :i_forward93surface_index2 = :j_forward94else95surface_index1, surface_index2 = orientation_to_indices_p4est(faces[2],96faces[1],97orientation)98end99100if faces[side] == 0101# Index face in negative x-direction102interfaces.node_indices[side, interface_id] = (:begin, surface_index1,103surface_index2)104elseif faces[side] == 1105# Index face in positive x-direction106interfaces.node_indices[side, interface_id] = (:end, surface_index1,107surface_index2)108elseif faces[side] == 2109# Index face in negative y-direction110interfaces.node_indices[side, interface_id] = (surface_index1, :begin,111surface_index2)112elseif faces[side] == 3113# Index face in positive y-direction114interfaces.node_indices[side, interface_id] = (surface_index1, :end,115surface_index2)116elseif faces[side] == 4117# Index face in negative z-direction118interfaces.node_indices[side, interface_id] = (surface_index1,119surface_index2, :begin)120else # faces[side] == 5121# Index face in positive z-direction122interfaces.node_indices[side, interface_id] = (surface_index1,123surface_index2, :end)124end125end126127return interfaces128end129130# Initialize node_indices of boundary container131@inline function init_boundary_node_indices!(boundaries::P4estBoundaryContainer{3},132face, boundary_id)133if face == 0134# Index face in negative x-direction135boundaries.node_indices[boundary_id] = (:begin, :i_forward, :j_forward)136elseif face == 1137# Index face in positive x-direction138boundaries.node_indices[boundary_id] = (:end, :i_forward, :j_forward)139elseif face == 2140# Index face in negative y-direction141boundaries.node_indices[boundary_id] = (:i_forward, :begin, :j_forward)142elseif face == 3143# Index face in positive y-direction144boundaries.node_indices[boundary_id] = (:i_forward, :end, :j_forward)145elseif face == 4146# Index face in negative z-direction147boundaries.node_indices[boundary_id] = (:i_forward, :j_forward, :begin)148else # face == 5149# Index face in positive z-direction150boundaries.node_indices[boundary_id] = (:i_forward, :j_forward, :end)151end152153return boundaries154end155156# Initialize node_indices of mortar container157# faces[1] is expected to be the face of the small side.158@inline function init_mortar_node_indices!(mortars::P4estMortarContainer{3},159faces, orientation, mortar_id)160for side in 1:2161# Align mortar at small side.162# The large side needs to be indexed differently.163if side == 1164surface_index1 = :i_forward165surface_index2 = :j_forward166else167surface_index1, surface_index2 = orientation_to_indices_p4est(faces[2],168faces[1],169orientation)170end171172if faces[side] == 0173# Index face in negative x-direction174mortars.node_indices[side, mortar_id] = (:begin, surface_index1,175surface_index2)176elseif faces[side] == 1177# Index face in positive x-direction178mortars.node_indices[side, mortar_id] = (:end, surface_index1,179surface_index2)180elseif faces[side] == 2181# Index face in negative y-direction182mortars.node_indices[side, mortar_id] = (surface_index1, :begin,183surface_index2)184elseif faces[side] == 3185# Index face in positive y-direction186mortars.node_indices[side, mortar_id] = (surface_index1, :end,187surface_index2)188elseif faces[side] == 4189# Index face in negative z-direction190mortars.node_indices[side, mortar_id] = (surface_index1, surface_index2,191:begin)192else # faces[side] == 5193# Index face in positive z-direction194mortars.node_indices[side, mortar_id] = (surface_index1, surface_index2,195:end)196end197end198199return mortars200end201202# Convert `p4est` orientation code to node indices.203# Return node indices that index "my side" wrt "other side",204# i.e., i and j are indices of other side.205function orientation_to_indices_p4est(my_face, other_face, orientation_code)206# my_face and other_face are the face directions (zero-based)207# of "my side" and "other side" respectively.208# Face corner 0 of the face with the lower face direction connects to a corner of the other face.209# The number of this corner is the orientation code in `p4est`.210lower = my_face <= other_face211212# x_pos, y_neg, and z_pos are the directions in which the face has right-handed coordinates213# when looked at from the outside.214my_right_handed = my_face in (1, 2, 5)215other_right_handed = other_face in (1, 2, 5)216217# If both or none are right-handed when looked at from the outside, they will have different218# orientations when looked at from the same side of the interface.219flipped = my_right_handed == other_right_handed220221# In the following illustrations, the face corner numbering of `p4est` is shown.222# ξ and η are the local coordinates of the respective face.223# We're looking at both faces from the same side of the interface, so that "other side"224# (in the illustrations on the left) has right-handed coordinates.225if !flipped226if orientation_code == 0227# Corner 0 of other side matches corner 0 of my side228# 2┌──────┐3 2┌──────┐3229# │ │ │ │230# │ │ │ │231# 0└──────┘1 0└──────┘1232# η η233# ↑ ↑234# │ │235# └───> ξ └───> ξ236surface_index1 = :i_forward237surface_index2 = :j_forward238elseif ((lower && orientation_code == 2) # Corner 0 of my side matches corner 2 of other side239||240(!lower && orientation_code == 1)) # Corner 0 of other side matches corner 1 of my side241# 2┌──────┐3 0┌──────┐2242# │ │ │ │243# │ │ │ │244# 0└──────┘1 1└──────┘3245# η ┌───> η246# ↑ │247# │ ↓248# └───> ξ ξ249surface_index1 = :j_backward250surface_index2 = :i_forward251elseif ((lower && orientation_code == 1) # Corner 0 of my side matches corner 1 of other side252||253(!lower && orientation_code == 2)) # Corner 0 of other side matches corner 2 of my side254# 2┌──────┐3 3┌──────┐1255# │ │ │ │256# │ │ │ │257# 0└──────┘1 2└──────┘0258# η ξ259# ↑ ↑260# │ │261# └───> ξ η <───┘262surface_index1 = :j_forward263surface_index2 = :i_backward264else # orientation_code == 3265# Corner 0 of my side matches corner 3 of other side and266# corner 0 of other side matches corner 3 of my side.267# 2┌──────┐3 1┌──────┐0268# │ │ │ │269# │ │ │ │270# 0└──────┘1 3└──────┘2271# η ξ <───┐272# ↑ │273# │ ↓274# └───> ξ η275surface_index1 = :i_backward276surface_index2 = :j_backward277end278else # flipped279if orientation_code == 0280# Corner 0 of other side matches corner 0 of my side281# 2┌──────┐3 1┌──────┐3282# │ │ │ │283# │ │ │ │284# 0└──────┘1 0└──────┘2285# η ξ286# ↑ ↑287# │ │288# └───> ξ └───> η289surface_index1 = :j_forward290surface_index2 = :i_forward291elseif orientation_code == 2292# Corner 0 of my side matches corner 2 of other side and293# corner 0 of other side matches corner 2 of my side.294# 2┌──────┐3 0┌──────┐1295# │ │ │ │296# │ │ │ │297# 0└──────┘1 2└──────┘3298# η ┌───> ξ299# ↑ │300# │ ↓301# └───> ξ η302surface_index1 = :i_forward303surface_index2 = :j_backward304elseif orientation_code == 1305# Corner 0 of my side matches corner 1 of other side and306# corner 0 of other side matches corner 1 of my side.307# 2┌──────┐3 3┌──────┐2308# │ │ │ │309# │ │ │ │310# 0└──────┘1 1└──────┘0311# η η312# ↑ ↑313# │ │314# └───> ξ ξ <───┘315surface_index1 = :i_backward316surface_index2 = :j_forward317else # orientation_code == 3318# Corner 0 of my side matches corner 3 of other side and319# corner 0 of other side matches corner 3 of my side.320# 2┌──────┐3 2┌──────┐0321# │ │ │ │322# │ │ │ │323# 0└──────┘1 3└──────┘1324# η η <───┐325# ↑ │326# │ ↓327# └───> ξ ξ328surface_index1 = :j_backward329surface_index2 = :i_backward330end331end332333return surface_index1, surface_index2334end335end # @muladd336337338