P4est-based mesh
The P4estMesh is an unstructured, curvilinear, nonconforming mesh type for quadrilateral (2D) and hexahedral (3D) cells. It supports quadtree/octree-based adaptive mesh refinement (AMR) via the C library p4est. See AMRCallback for further information.
Due to its curvilinear nature, (numerical) fluxes need to implement methods dispatching on the normal::AbstractVector. Rotationally invariant equations such as the compressible Euler equations can use FluxRotated to wrap numerical fluxes implemented only for Cartesian meshes. This simplifies the re-use of existing functionality for the TreeMesh but is usually less efficient, cf. PR #550.
Construction of a P4estMesh from an Abaqus file
One available option to construct a P4estMesh is to read in an Abaqus (.inp) mesh file. We briefly describe the structure of this file, the conventions it uses, and how the mesh file is parsed to create an initial unstructured, curvilinear, and conforming mesh.
Mesh in two spatial dimensions
For this discussion we use the following two-dimensional unstructured curved mesh with three elements:

We note that the corner and element connectivity information parsed from the Abaqus file creates a straight sided (linear) mesh. From this linear mesh there are two strategies available to make the mesh curvilinear:
Apply a
mappingfunction to describe a transformation of the linear mesh to another physical domain. The mapping is approximated using interpolation polynomial of a user specified polynomial degree. The default value of this polynomial degree is1that corresponds to an uncurved geometry.High-order boundary information is available in the
.inpmesh file because it was created with the HOHQMesh mesh generator, which is available via the Julia package HOHQMesh.jl. This information is used to create appropriate transfinite mappings during the mesh construction.
We divide our discussion into two parts. The first part discusses the standard corner and element information contained in the .inp mesh file. The second part specifically deals with the mesh file parsing of an Abaqus file created by HOHQMesh.jl.
Mesh file header
An Abaqus .inp mesh file typically begins with a *Heading. Though optional, the *Heading is helpful to give users some information about the mesh described by the mesh file. In particular, a .inp mesh file created with HOHQMesh will contain the header
This heading is used to indicate to the mesh constructor which of the above mapping strategies to apply in order to create a curvilinear mesh. If the Abaqus file header is not present then the P4estMesh is created with the first strategy above.
[List of corner nodes](@id corner-node-list)
Next, prefaced with *NODE, comes a list of the physical (x,y,z) coordinates of all the corners. The first integer in the list of the corners provides its id number. Thus, for the two-dimensional example mesh this block of corner information is
[List of elements](@id element-list)
The element connectivity is given after the list of corners. The header for this information block is
The Abaqus element type CPS4 corresponds to a quadrilateral element. Each quadrilateral element in the unstructured mesh is dictated by four corner points with indexing taken from the numbering given by the corner list above. The elements connect a set of four corner points (starting from the bottom left) in an anti-clockwise fashion; making the element right-handed. This element handedness is indicated using the circular arrow in the figure above. Just as with the corner list, the first integer in the element connectivity list indicates the element id number. Thus, the element connectivity list for the three element example mesh is
Element neighbor connectivity
The construction of the element neighbor ids and identifying physical boundary surfaces is done using functionality directly from the p4est library. For example, the neighbor connectivity is created in the mesh constructor using the wrapper read_inp_p4est function.
Encoding of boundaries
HOHQMesh boundary information
If present, any additional information in the mesh file that was created by HOHQMesh is prefaced with ** to make it an Abaqus comment. This ensures that the read in of the file by a standard Abaqus file parser, as done in the read_inp_p4est function, is done correctly.
The high-order, curved boundary information and labels of the physical boundary created by HOHQMesh is found below the comment line
Next comes the polynomial degree that the mesh will use to represent any curved sides
The mesh file then, again, provides the element connectivity as well as information for curved surfaces either interior to the domain or along the physical boundaries. A set of check digits are included directly below the four corner indexes to indicate whether the local surface index (-y, +x, +y, or -x) within the element is straight sided, 0, or is curved, 1. If the local surface is straight sided no additional information is necessary during the mesh file read in. But for any curved surfaces the mesh file provides (x,y,z) coordinate values in order to construct an interpolant of this surface with the mesh polynomial order at the Chebyshev-Gauss-Lobatto nodes. This list of (x,y,z) data will be given in the direction of the local coordinate system. Given below is the element curvature information for the example mesh:
The last piece of information provided by HOHQMesh are labels for the different surfaces of an element. These labels are useful to set boundary conditions along physical surfaces. The labels can be short descriptive words up to 32 characters in length. The label --- indicates an internal surface where no boundary condition is required.
It is important to note that these labels are given in the following order according to the local surface index -x +x -y +y as required by the p4est library.
For completeness, we provide the entire Abaqus mesh file for the example mesh in the figure above:
Standard Abaqus format boundary information
As an alternative to an Abaqus mesh generated by HOHQMesh, .inp files with boundary information encoded as nodesets *NSET,NSET= can be used to construct a p4est mesh. This is especially useful for usage of existing meshes (consisting of bilinear elements) which could stem from the popular gmsh meshing software.
In addition to the list of [nodes](@ref corner-node-list) and [elements](@ref element-list) given above, there are nodesets of the form
present which are used to associate the edges defined through their corner nodes with a label. In this case it is called PhysicalLine1. By looping over every element and its associated edges, consisting of two nodes, we query the read in NSETs if the current node pair is present.
To prevent that every nodeset following *NSET,NSET= is treated as a boundary, the user must supply a boundary_symbols keyword to the P4estMesh constructor:
By doing so, only nodesets with a label present in boundary_symbols are treated as physical boundaries. Other nodesets that could be used for diagnostics are not treated as external boundaries. Note that there is a leading colon : compared to the label in the .inp mesh file. This is required to turn the label into a Symbol. Important: In Julia, a symbol cannot contain a hyphen/dash -, i.e., :BC-1 is not a valid symbol. Keep this in mind when importing boundaries, you might have to convert hyphens/dashes - to underscores _ in the .inp mesh file, i.e., BC_1 instead of BC-1.
A 2D example for this mesh, which is read-in for an unstructured mesh file created with gmsh, is presented in examples/p4est_2d_dgsem/elixir_euler_NACA6412airfoil_mach2.jl.
Mesh in three spatial dimensions
HOHQMesh-Extended Abaqus format
The 3D Abaqus file format with high-order boundary information from HOHQMesh is very similar to the 2D version discussed above. There are only three changes:
The element connectivity would be given in terms of the eight corners that define a hexahedron. The corners are numbered as shown in the figure below. The header of the element list changes to be
where
C3D8corresponds to a Abaqus hexahedral element.There are six check digits included directly below the eight corner indexes to indicate whether the local face within the element is straight sided,
0, or is curved,1. For curved faces(x,y,z)coordinate values are available in order to construct an face interpolant with the mesh polynomial order at the Chebyshev-Gauss-Lobatto nodes.The boundary labels are given in the following order according to the local surface index
-x+x-y+y-z+zas required by thep4estlibrary.
For completeness, we also give a short description and derivation of the three-dimensional transfinite mapping formulas used to compute the physical coordinates of a (possibly curved) hexahedral element give the reference coordinates which lie in . That is, we will create an expression .
Below we provide a sketch of a single hexahedral element with curved faces. This is done to introduce the numbering conventions for corners, edges, and faces of the element.

When the hexahedron is a straight sided (linear) element we compute the transfinite mapping directly from the element corner points according to
Next, we create a transfinite mapping function, , for a hexahedron that has one or more curved faces. For this we assume that have a set of six interpolating polynomials that approximate the faces. The interpolating polynomial for any curved faces is provided by the information in a HOHQMesh Abaqus mesh file or is constructed on the fly via a bi-linear interpolation routine for any linear faces. Explicitly, these six face interpolation polynomials depend on the computational coordinates as follows
To determine the form of the mapping we first create linear interpolations between two opposing faces, e.g., and and sum them together to have
Unfortunately, the linear interpolations no longer match at the faces, e.g., evaluating at we have
which is the desired face plus four edge error terms. Analogous edge error terms occur at the other faces evaluating at , , and . In order to match the faces, we subtract a linear interpolant in the , , and directions of the edge error terms, e.g., the terms in braces in the above equation. So, continuing the example above, the correction term to be subtracted for face to match would be
For clarity, and to allow an easier comparison to the implementation, we introduce auxiliary notation for the 12 edge values present in the complete correction term. That is, for given values of , , and we have
With this notation for the edge terms (and after some algebraic manipulation) we write the complete edge correction term, , as
However, subtracting the edge correction terms from removes the interior element contributions twice. Thus, to complete the construction of the transfinite mapping we add the transfinite map of the straight sided hexahedral element to find
Construction from standard Abaqus
Also for a mesh in standard Abaqus format there are no qualitative changes when going from 2D to 3D. The most notable difference is that boundaries are formed in 3D by faces defined by four nodes while in 2D boundaries are edges consisting of two elements. Note that standard Abaqus also defines quadratic element types. In Trixi.jl, these higher-order elements are currently only supported in 2D, i.e., 8-node quadrilaterals. A simple mesh file, which is used also in examples/p4est_3d_dgsem/elixir_euler_free_stream_boundaries.jl, is given below:
Interfacing with the p4est mesh backend
Sometimes it is necessary to exchange data between the solver and the mesh. In the case of the P4estMesh and its p4est, this is more intricate than with other mesh types, since the p4est backend is comparatively opaque to the rest of the code due to being a compiled C library.
As a disclaimer: This is neither complete nor self-contained, and is meant as a first orientation guide. To implement own features, you likely need to take a look at the documentation of p4est, its Julia wrapper P4est.jl, and relevant parts of the Trixi.jl source code. Additionally, the Julia manual for interfacing C code and the documentation of the Julia C interface are also helpful.
First, we go through the implementation of adaptive mesh refinement (AMR) with p4est. Second, we show how a custom mesh partitioning based on a weighting function can be implemented.
Adaptive Mesh Refinement (AMR)
In a simulation that uses adaptive mesh refinement (AMR), cells are assigned an indicator value that denotes whether the cell should be coarsened (), kept at the current level (), or be refined ().
For realizing AMR there are now in principle two possibilities:
First, the solver could receive the connectivity information from the mesh backend and then handle the refinement and coarsening of the mesh.
Second, the solver could send the indicator values to the mesh backend and let it handle the refinement and coarsening of the mesh.
For the p4est mesh, Trixi.jl uses the latter approach to benefit from the highly efficient implementation of the p4est library.
The first step involves sending the indicator values to the mesh backend. The indicator values lambda are obtained from a "controller" in the AMRCallback
and need now to be sent to the mesh backend. To this end, a number of helper functions are required. First, a Julia function with two arguments info, user_data is defined that copies the indicator values from user_data to a field in info. The info is a field from the p4est mesh (precisely p4est_iter_volume_info_t - for details see the p4est documentation):
This function is then converted to a C function to match the required syntax of the p4est_iter_volume_t/p8est_iter_volume_t function:
For these functions documentation is provided for both 2D and 3D.
To handle both 2D (which is the canonical p4est) and 3D (which is within the p4est library referred to as p8est), we need to construct dispatching functions. The dispatching is performed on the number of spatial dimensions:
The correct function is then selected via
and by calling iterate_p4est the indicator values are finally copied to the cells (quadrants or octants) of the mesh:
Now, during the refine! or coarsen! calls (which eventually call refine_fn/coarsen_fn from p4est) the indicator values are available in the user data of the mesh cells. In particular, again a function needs to be provided that matches the signature of the p4est_refine_t [Documentation, Implementation]/p8est_refine_t[Documentation, Implementation] function
which is implemented as
Again, dimensional dispatching is used to handle both 2D and 3D meshes:
These are then handed over to refine_p4est!, which eventually calls refine_fn.
Custom mesh partitioning
Analogous to the AMR example above, we now discuss how to implement a custom mesh partitioning based on custom cell weighting. This might be required for distributed memory (i.e., MPI-parallelized simulations) to achieve a more uniform distribution of the computational work across the different processes. This is important to maintain scalability and to avoid load imbalance.
We begin again by copying the solver data. Here we assume that the weighting should be done based on the user data rhs_per_element, which arises for instance in multirate/local time-stepping solvers where the computational work per cell is no longer uniform, but can be estimated by the number of right-hand-side (RHS) evaluations per cell. Thus, a function, which saves this user data to the mesh, could look like this:
Again, dimensional dispatching is used to handle both 2D and 3D meshes:
Similar to the refine_fn function, p4est requires a weighting function with the same signature [Documentation, Implementation]:
Again, the 3D version [Documentation, Implementation] is very similar:
The equivalent Julia function is then very simply implemented as
Then, a different balance function could look like this:
This redistributes the mesh among the MPI ranks. Now, the same needs to be done for the solver (recall that mesh and solver are quite decoupled for p4est meshes). Thus, the call to partition! needs to be followed by a call to rebalance_solver! to rebalance the solver data. Overall, this non-standard partitioning can be realized as
This code could then be placed in the resize! function of a corresponding multirate integrator to ensure load-balancing for simulations involving AMR.
Boundary conditions
For P4estMeshes, boundary conditions must be defined using named tuples (see, for example, examples/p4est_2d_dgsem/elixir_advection_diffusion_nonperiodic_amr.jl).