Path: blob/main/src/meshes/transfinite_mappings_3d.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# Illustration of the corner (circled), edge (braces), and face index numbering convention8# used in these functions.9#10# ⑧────────────────────────{7}────────────────────────⑦11# ╱│ ╱│12# ╱ │ ╱ │13# ╱ │ ╱ │14# ╱ │ 5 (+z) ╱ │15# ╱ │ ╱ │16# ╱ │ ╱ │17# {12} │ {11} │18# ╱ │ ╱ │19# ╱ │ ╱ │20# ╱ │ 2 (+y) ╱ │21# ╱ │ ╱ │22# ╱ {8} ╱ {6}23# ╱ │ ╱ │24# ⑤─────────────────────────{3}───────────────────────⑥ 4 (+x) │25# │ │ │ │26# │ │ │ │27# │ │ │ │28# │ 6 (-x) │ │ │29# │ │ │ │30# │ │ │ │31# │ │ │ │32# │ │ │ │33# │ ④────────────────────────{5}──────────│─────────────③34# │ ╱ │ ╱35# │ ╱ 1 (-y) │ ╱36# {4} ╱ {2} ╱37# │ ╱ │ ╱38# │ ╱ │ ╱39# │ {9} │ {10}40# │ ╱ │ ╱41# │ ╱ │ ╱ Global coordinates:42# │ ╱ │ ╱ z43# │ ╱ 3 (-z) │ ╱ ↑ y44# │ ╱ │ ╱ │ ╱45# │ ╱ │ ╱ │ ╱46# │╱ │╱ └─────> x47# ①───────────────────────{1}─────────────────────────②4849# Transfinite mapping formula from a point (xi, eta, zeta) in reference space [-1,1]^3 to a50# physical coordinate (x, y, z) for a hexahedral element with straight sides51function straight_side_hex_map(xi, eta, zeta, corner_points)52coordinate = zeros(eltype(xi), 3)53for j in 1:354coordinate[j] += (0.125f0 *55(corner_points[j, 1] * (1 - xi) * (1 - eta) * (1 - zeta)56+ corner_points[j, 2] * (1 + xi) * (1 - eta) * (1 - zeta)57+ corner_points[j, 3] * (1 + xi) * (1 + eta) * (1 - zeta)58+ corner_points[j, 4] * (1 - xi) * (1 + eta) * (1 - zeta)59+ corner_points[j, 5] * (1 - xi) * (1 - eta) * (1 + zeta)60+ corner_points[j, 6] * (1 + xi) * (1 - eta) * (1 + zeta)61+ corner_points[j, 7] * (1 + xi) * (1 + eta) * (1 + zeta)62+ corner_points[j, 8] * (1 - xi) * (1 + eta) * (1 + zeta)))63end6465return coordinate66end6768# Construct the (x, y, z) node coordinates in the volume of a straight sided hexahedral element69function calc_node_coordinates!(node_coordinates::AbstractArray{<:Any, 5}, element,70nodes, corners)71for k in eachindex(nodes), j in eachindex(nodes), i in eachindex(nodes)72node_coordinates[:, i, j, k, element] .= straight_side_hex_map(nodes[i],73nodes[j],74nodes[k],75corners)76end7778return node_coordinates79end8081# Transfinite mapping formula from a point (xi, eta, zeta) in reference space [-1,1]^3 to a point82# (x,y,z) in physical coordinate space for a hexahedral element with general curved sides83# See Section 4.384# - Andrew R. Winters (2014)85# Discontinuous Galerkin spectral element approximations for the reflection and86# transmission of waves from moving material interfaces87# [PhD thesis, Florida State University](https://diginole.lib.fsu.edu/islandora/object/fsu%3A185342)88function transfinite_hex_map(xi, eta, zeta, face_curves::AbstractVector{<:CurvedFace})89coordinate = zeros(eltype(xi), 3)90face_values = zeros(eltype(xi), (3, 6))91edge_values = zeros(eltype(xi), (3, 12))92corners = zeros(eltype(xi), (3, 8))9394# Compute values along the face edges95edge_values[:, 1] .= evaluate_at(SVector(xi, -1), face_curves[1])96edge_values[:, 2] .= evaluate_at(SVector(1, zeta), face_curves[1])97edge_values[:, 3] .= evaluate_at(SVector(xi, 1), face_curves[1])98edge_values[:, 4] .= evaluate_at(SVector(-1, zeta), face_curves[1])99100edge_values[:, 5] .= evaluate_at(SVector(xi, -1), face_curves[2])101edge_values[:, 6] .= evaluate_at(SVector(1, zeta), face_curves[2])102edge_values[:, 7] .= evaluate_at(SVector(xi, 1), face_curves[2])103edge_values[:, 8] .= evaluate_at(SVector(-1, zeta), face_curves[2])104105edge_values[:, 9] .= evaluate_at(SVector(eta, -1), face_curves[6])106edge_values[:, 10] .= evaluate_at(SVector(eta, -1), face_curves[4])107edge_values[:, 11] .= evaluate_at(SVector(eta, 1), face_curves[4])108edge_values[:, 12] .= evaluate_at(SVector(eta, 1), face_curves[6])109110# Compute values on the face111face_values[:, 1] .= evaluate_at(SVector(xi, zeta), face_curves[1])112face_values[:, 2] .= evaluate_at(SVector(xi, zeta), face_curves[2])113face_values[:, 3] .= evaluate_at(SVector(xi, eta), face_curves[3])114face_values[:, 4] .= evaluate_at(SVector(eta, zeta), face_curves[4])115face_values[:, 5] .= evaluate_at(SVector(xi, eta), face_curves[5])116face_values[:, 6] .= evaluate_at(SVector(eta, zeta), face_curves[6])117118# Pull the eight corner values and compute the straight sided hex mapping119corners[:, 1] .= face_curves[1].coordinates[:, 1, 1]120corners[:, 2] .= face_curves[1].coordinates[:, end, 1]121corners[:, 3] .= face_curves[2].coordinates[:, end, 1]122corners[:, 4] .= face_curves[2].coordinates[:, 1, 1]123corners[:, 5] .= face_curves[1].coordinates[:, 1, end]124corners[:, 6] .= face_curves[1].coordinates[:, end, end]125corners[:, 7] .= face_curves[2].coordinates[:, end, end]126corners[:, 8] .= face_curves[2].coordinates[:, 1, end]127128coordinate_straight = straight_side_hex_map(xi, eta, zeta, corners)129130# Compute the transfinite mapping131for j in 1:3132# Linear interpolation between opposite faces133coordinate[j] = (0.5f0 *134(face_values[j, 6] * (1 - xi) + face_values[j, 4] * (1 + xi)135+ face_values[j, 1] * (1 - eta) +136face_values[j, 2] * (1 + eta)137+ face_values[j, 3] * (1 - zeta) +138face_values[j, 5] * (1 + zeta)))139140# Edge corrections to ensure faces match141coordinate[j] -= (0.25f0 * (edge_values[j, 1] * (1 - eta) * (1 - zeta)142+ edge_values[j, 2] * (1 + xi) * (1 - eta)143+ edge_values[j, 3] * (1 - eta) * (1 + zeta)144+ edge_values[j, 4] * (1 - xi) * (1 - eta)145+ edge_values[j, 5] * (1 + eta) * (1 - zeta)146+ edge_values[j, 6] * (1 + xi) * (1 + eta)147+ edge_values[j, 7] * (1 + eta) * (1 + zeta)148+ edge_values[j, 8] * (1 - xi) * (1 + eta)149+ edge_values[j, 9] * (1 - xi) * (1 - zeta)150+ edge_values[j, 10] * (1 + xi) * (1 - zeta)151+ edge_values[j, 11] * (1 + xi) * (1 + zeta)152+ edge_values[j, 12] * (1 - xi) * (1 + zeta)))153154# Subtracted interior twice, so add back the straight-sided hexahedral mapping155coordinate[j] += coordinate_straight[j]156end157158return coordinate159end160161# Construct the (x, y, z) node coordinates in the volume of a curved sided hexahedral element162function calc_node_coordinates!(node_coordinates::AbstractArray{<:Any, 5}, element,163nodes,164face_curves::AbstractVector{<:CurvedFace})165for k in eachindex(nodes), j in eachindex(nodes), i in eachindex(nodes)166node_coordinates[:, i, j, k, element] .= transfinite_hex_map(nodes[i], nodes[j],167nodes[k],168face_curves)169end170171return node_coordinates172end173end # @muladd174175176