Path: blob/main/src/meshes/unstructured_mesh.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"""8UnstructuredMesh2D <: AbstractMesh{2}910An unstructured (possibly curved) quadrilateral mesh.1112UnstructuredMesh2D(filename; RealT=Float64, periodicity=false)1314All mesh information, neighbour coupling, and boundary curve information is read in15from a mesh file `filename`.16"""17mutable struct UnstructuredMesh2D{RealT <: Real,18CurvedSurfaceT <: CurvedSurface{RealT}} <:19AbstractMesh{2}20filename :: String21n_corners :: Int22n_surfaces :: Int # total number of surfaces23n_interfaces :: Int # number of interior surfaces24n_boundaries :: Int # number of surfaces on the physical boundary25n_elements :: Int26polydeg :: Int27corners :: Array{RealT, 2} # [ndims, n_corners]28neighbour_information :: Array{Int, 2} # [neighbour node/element/edge ids, n_surfaces]29boundary_names :: Array{Symbol, 2} # [local sides, n_elements]30periodicity :: Bool31element_node_ids :: Array{Int, 2} # [node ids, n_elements]32element_is_curved :: Vector{Bool}33surface_curves :: Array{CurvedSurfaceT, 2} # [local sides, n_elements]34current_filename :: String35unsaved_changes :: Bool # if true, the mesh will be saved for plotting36end3738# constructor for an unstructured mesh read in from a file39# TODO: this mesh file parsing and construction of the mesh skeleton can likely be improved in terms40# of performance41function UnstructuredMesh2D(filename; RealT = Float64, periodicity = false,42unsaved_changes = true)4344# readin all the information from the mesh file into a string array45file_lines = readlines(open(filename))4647# readin the number of nodes, number of interfaces, number of elements and local polynomial degree48current_line = split(file_lines[2])49n_corners = parse(Int, current_line[1])50n_surfaces = parse(Int, current_line[2])51n_elements = parse(Int, current_line[3])52mesh_polydeg = parse(Int, current_line[4])5354mesh_nnodes = mesh_polydeg + 15556# The types of structs used in the following depend on information read from57# the mesh file. Thus, this cannot be type stable at all. Hence, we allocate58# the memory now and introduce a function barrier before continuing to read59# data from the file.60corner_nodes = Array{RealT}(undef, (2, n_corners))61interface_info = Array{Int}(undef, (6, n_surfaces))62element_node_ids = Array{Int}(undef, (4, n_elements))63curved_check = Vector{Int}(undef, 4)64quad_corners = Array{RealT}(undef, (4, 2))65quad_corners_flipped = Array{RealT}(undef, (4, 2))66curve_values = Array{RealT}(undef, (mesh_nnodes, 2))67element_is_curved = Array{Bool}(undef, n_elements)68CurvedSurfaceT = CurvedSurface{RealT}69surface_curves = Array{CurvedSurfaceT}(undef, (4, n_elements))70boundary_names = Array{Symbol}(undef, (4, n_elements))7172# create the Chebyshev-Gauss-Lobatto nodes used to represent any curved boundaries that are73# required to construct the sides74cheby_nodes_, _ = chebyshev_gauss_lobatto_nodes_weights(mesh_nnodes)75bary_weights_ = barycentric_weights(cheby_nodes_)76cheby_nodes = SVector{mesh_nnodes}(cheby_nodes_)77bary_weights = SVector{mesh_nnodes}(bary_weights_)7879arrays = (; corner_nodes, interface_info, element_node_ids, curved_check,80quad_corners, quad_corners_flipped, curve_values,81element_is_curved, surface_curves, boundary_names)82counters = (; n_corners, n_surfaces, n_elements)8384n_boundaries = parse_mesh_file!(arrays, RealT, CurvedSurfaceT, file_lines, counters,85cheby_nodes, bary_weights)8687# get the number of internal interfaces in the mesh88if periodicity89n_interfaces = n_surfaces90n_boundaries = 091else92n_interfaces = n_surfaces - n_boundaries93end9495return UnstructuredMesh2D{RealT, CurvedSurfaceT}(filename, n_corners, n_surfaces,96n_interfaces, n_boundaries,97n_elements, mesh_polydeg,98corner_nodes,99interface_info, boundary_names,100periodicity,101element_node_ids,102element_is_curved, surface_curves,103"", unsaved_changes)104end105106function parse_mesh_file!(arrays, RealT, CurvedSurfaceT, file_lines, counters,107cheby_nodes, bary_weights)108@unpack (corner_nodes, interface_info, element_node_ids, curved_check,109quad_corners, quad_corners_flipped, curve_values,110element_is_curved, surface_curves, boundary_names) = arrays111@unpack n_corners, n_surfaces, n_elements = counters112mesh_nnodes = length(cheby_nodes)113114# counter to step through the mesh file line by line115file_idx = 3116117# readin an store the nodes that dictate the corners of the elements needed to construct the118# element geometry terms119for j in 1:n_corners120current_line = split(file_lines[file_idx])121corner_nodes[1, j] = parse(RealT, current_line[1])122corner_nodes[2, j] = parse(RealT, current_line[2])123file_idx += 1124end125126# readin an store the nodes that dictate the interfaces, neighbour data, and orientations contains127# the following:128# interface_info[1] = start node ID129# interface_info[2] = end node ID130# interface_info[3] = ID of the primary element131# interface_info[4] = ID of the secondary element (if 0 then it is a physical boundary)132# interface_info[5] = local side ID on the primary element133# interface_info[6] = local side ID on the secondary element134# container to for the interface neighbour information and connectivity135n_boundaries = 0136for j in 1:n_surfaces137current_line = split(file_lines[file_idx])138interface_info[1, j] = parse(Int, current_line[1])139interface_info[2, j] = parse(Int, current_line[2])140interface_info[3, j] = parse(Int, current_line[3])141interface_info[4, j] = parse(Int, current_line[4])142interface_info[5, j] = parse(Int, current_line[5])143interface_info[6, j] = parse(Int, current_line[6])144145# count the number of physical boundaries146if interface_info[4, j] == 0147n_boundaries += 1148end149file_idx += 1150end151152# work arrays to pull to correct corners of a given element (agnostic to curvature) and local153# copies of the curved boundary information154155# readin an store the curved boundary information of the elements156157for j in 1:n_elements158# pull the corner node IDs159current_line = split(file_lines[file_idx])160element_node_ids[1, j] = parse(Int, current_line[1])161element_node_ids[2, j] = parse(Int, current_line[2])162element_node_ids[3, j] = parse(Int, current_line[3])163element_node_ids[4, j] = parse(Int, current_line[4])164for i in 1:4165# pull the (x,y) values of these corners out of the nodes array166quad_corners[i, :] .= corner_nodes[:, element_node_ids[i, j]]167end168# pull the information to check if boundary is curved in order to read in additional data169file_idx += 1170current_line = split(file_lines[file_idx])171curved_check[1] = parse(Int, current_line[1])172curved_check[2] = parse(Int, current_line[2])173curved_check[3] = parse(Int, current_line[3])174curved_check[4] = parse(Int, current_line[4])175if sum(curved_check) == 0176# quadrilateral element is straight sided177element_is_curved[j] = false178file_idx += 1179# read all the boundary names180boundary_names[:, j] = map(Symbol, split(file_lines[file_idx]))181else182# quadrilateral element has at least one curved side183element_is_curved[j] = true184185# flip node ordering to make sure the element is right-handed for the interpolations186m1 = 1187m2 = 2188@views quad_corners_flipped[1, :] .= quad_corners[4, :]189@views quad_corners_flipped[2, :] .= quad_corners[2, :]190@views quad_corners_flipped[3, :] .= quad_corners[3, :]191@views quad_corners_flipped[4, :] .= quad_corners[1, :]192for i in 1:4193if curved_check[i] == 0194# when curved_check[i] is 0 then the "curve" from corner `i` to corner `i+1` is a195# straight line. So we must construct the interpolant for this line196for k in 1:mesh_nnodes197curve_values[k, 1] = linear_interpolate(cheby_nodes[k],198quad_corners_flipped[m1,1991],200quad_corners_flipped[m2,2011])202curve_values[k, 2] = linear_interpolate(cheby_nodes[k],203quad_corners_flipped[m1,2042],205quad_corners_flipped[m2,2062])207end208else209# when curved_check[i] is 1 this curved boundary information is supplied by the mesh210# generator. So we just read it into a work array211for k in 1:mesh_nnodes212file_idx += 1213current_line = split(file_lines[file_idx])214curve_values[k, 1] = parse(RealT, current_line[1])215curve_values[k, 2] = parse(RealT, current_line[2])216end217end218# construct the curve interpolant for the current side219surface_curves[i, j] = CurvedSurfaceT(cheby_nodes, bary_weights,220copy(curve_values))221# indexing update that contains a "flip" to ensure correct element orientation222# if we need to construct the straight line "curves" when curved_check[i] == 0223m1 += 1224if i == 3225m2 = 1226else227m2 += 1228end229end230# finally read in the boundary names where "---" means an internal connection231file_idx += 1232boundary_names[:, j] = map(Symbol, split(file_lines[file_idx]))233end234# one last increment to the global index to read the next piece of element information235file_idx += 1236end237238return n_boundaries239end240241@inline Base.ndims(::UnstructuredMesh2D) = 2242@inline Base.real(::UnstructuredMesh2D{RealT}) where {RealT} = RealT243244# Check if mesh is periodic245isperiodic(mesh::UnstructuredMesh2D) = mesh.periodicity246247Base.length(mesh::UnstructuredMesh2D) = mesh.n_elements248249function Base.show(io::IO,250::UnstructuredMesh2D{RealT, CurvedSurfaceT}) where {RealT,251CurvedSurfaceT}252print(io, "UnstructuredMesh2D{2, ", RealT, ", ", CurvedSurfaceT, "}")253end254255function Base.show(io::IO, ::MIME"text/plain",256mesh::UnstructuredMesh2D{RealT, CurvedSurfaceT}) where {RealT,257CurvedSurfaceT258}259if get(io, :compact, false)260show(io, mesh)261else262summary_header(io,263"UnstructuredMesh2D{" * string(2) * ", " * string(RealT) * ", " *264string(CurvedSurfaceT) * "}")265summary_line(io, "mesh file", mesh.filename)266summary_line(io, "number of elements", length(mesh))267summary_line(io, "faces", mesh.n_surfaces)268summary_line(io, "mesh polynomial degree", mesh.polydeg)269summary_footer(io)270end271end272end # @muladd273274275