[petsc-users] orientation of DMPLEX for tetrehedral meshes
Jed Brown
jed at jedbrown.org
Thu Jul 2 10:34:43 CDT 2026
See DMPlexCreateReferenceCell_Internal (in plexcreate.c), and look at the coordinates. One common convention for the reference line segment is (-1, 1), which is the natural domain for Legendre polynomials and quadrature. Some packages use this, and some use (0, 1). There is a similar choice of reference element for triangles and tetrahedra.
Matteo Semplice <matteo.semplice at uninsubria.it> writes:
> Thanks!
>
> is there a document explaining the DMPLex internal ordering?
>
> (and by the way what's the reason to have the factors 0.5 in the
> jacobians? I would not expect them if the reference tet is (0,0,0),
> (1,0,0), etc
>
> if (J) {
> for (d = 0; d < dim; d++) {
> /* I orient with outward face normals */
> J[d * dim + 0] =*0.5* * (PetscRealPart(coords[2 * dim + d]) -
> PetscRealPart(coords[0 * dim + d]));
> J[d * dim + 1] =*0.5* * (PetscRealPart(coords[1 * dim + d]) -
> PetscRealPart(coords[0 * dim + d]));
> J[d * dim + 2] =*0.5* * (PetscRealPart(coords[3 * dim + d]) -
> PetscRealPart(coords[0 * dim + d]));
> }
> }
>
> Thanks
>
> Matteo
>
> Il 02/07/26 17:22, Jed Brown ha scritto:
>> DMPlex internal ordering is not the same as VTK ordering. The code you supply will have an inward-facing normal (as evaluated by DMPlex geometry routines). The IO routines translate to the internal ordering convention. If you are creating a mesh manually or writing a new file reader, you should use (or convert to) the DMPlex convention.
>>
>> Matteo Semplice via petsc-users<petsc-users at mcs.anl.gov> writes:
>>
>>> Dear PETSc,
>>>
>>> I am a bit puzzled by the 3d tet mesh representations as DMPlex. I
>>> boiled it down to a mesh of a single tet. More specifically,
>>>
>>> * if a I create the mesh as
>>>
>>> const PetscInt dim=3;
>>> const PetscInt numCells=1; // The number of cells, only on
>>> process 0
>>> const PetscInt numVertices=4; // The number of vertices owned
>>> by this process, or PETSC_DECIDE, only on process 0
>>> const PetscInt numCorners=4; // The number of vertices for
>>> each cell, only on process 0
>>> const PetscBool interpolate=PETSC_TRUE; // should
>>> intermediate mesh entities (faces, edges) be created?
>>> // An array of numCells×numCornersnumCells×numCorners
>>> numbers, the vertices for each cell, only on process 0
>>> const PetscInt cells[] = {0,1,2,3 };
>>> const PetscInt spaceDim=3; // The spatial dimension used for
>>> coordinates
>>> // An array of numVertices×spaceDimnumVertices×spaceDim
>>> numbers, the coordinates of each vertex, only on process 0
>>> const PetscReal vertexCoords[] = { 0,0,0,
>>> 1,0,0,
>>> 0,1,0,
>>> 0,0,1 };
>>> PetscCall( DMPlexCreateFromCellListPetsc(MPI_COMM_WORLD, dim,
>>> numCells, numVertices, numCorners, interpolate, cells,
>>> spaceDim, vertexCoords, dmMesh) );
>>>
>>> I get the representation that I would expect:
>>>
>>> DM Object: Mesh 1 MPI process
>>> type: plex
>>> Mesh in 3 dimensions:
>>> Number of 0-cells per rank: 4
>>> Number of 1-cells per rank: 6
>>> Number of 2-cells per rank: 4
>>> Number of 3-cells per rank: 1
>>> Labels:
>>> celltype: 4 strata with value/size (0 (4), 1 (6), 3 (4), 6 (1))
>>> depth: 4 strata with value/size (0 (4), 1 (6), 2 (4), 3 (1))
>>> Mesh with 1 cells
>>>
>>> with DMPlexGetCellCoordinates giving me the coordinates
>>>
>>> CELL 0 with vertices at
>>> ( 0.000, 0, 0.000 )
>>> ( 1.000, 0, 0.000 )
>>> ( 0.000, 1, 0.000 )
>>> ( 0.000, 0, 1.000 )
>>>
>>> * on the other hand, if I load the MSH file
>>>
>>> $MeshFormat
>>> 2.2 0 8
>>> $EndMeshFormat
>>> $Nodes
>>> 4
>>> 1 0.0 0.0 0.0
>>> 2 1.0 0.0 0.0
>>> 3 0.0 1.0 0.0
>>> 4 0.0 0.0 1.0
>>> $EndNodes
>>> $Elements
>>> 1
>>> 1 4 2 0 1 1 2 3 4
>>> $EndElements
>>>
>>> with DMPlexCreateGmshFromFile, the first and second vertices are
>>> swapped and I get
>>>
>>> DM Object: Mesh 1 MPI process
>>> type: plex
>>> Mesh in 3 dimensions:
>>> Number of 0-cells per rank: 4
>>> Number of 1-cells per rank: 6
>>> Number of 2-cells per rank: 4
>>> Number of 3-cells per rank: 1
>>> Labels:
>>> celltype: 4 strata with value/size (0 (4), 1 (6), 3 (4), 6 (1))
>>> depth: 4 strata with value/size (0 (4), 1 (6), 2 (4), 3 (1))
>>> Cell Sets: 1 strata with value/size (0 (1))
>>> Mesh with 1 cells
>>>
>>> with DMPlexGetCellCoordinates giving me
>>>
>>> CELL 0 with vertices at
>>> ( 1.000, 0, 0.000 )
>>> ( 0.000, 0, 0.000 )
>>> ( 0.000, 1, 0.000 )
>>> ( 0.000, 0, 1.000 )
>>>
>>> I understand that this behaviour is somehow consistent with the formulas
>>> in DMPlexComputeTetrahedronGeometry_Internal, where you compute the
>>> Jacobians swappnig the order of vertices (and with 0.5 factors that I do
>>> not understand at all... it looks as if your reference element was not
>>> the unit simplex)
>>>
>>> if (J) {
>>> for (d = 0; d < dim; d++) {
>>> /* I orient with outward face normals */
>>> J[d * dim + 0] = 0.5 * (PetscRealPart(coords[2 * dim + d]) -
>>> PetscRealPart(coords[0 * dim + d]));
>>> J[d * dim + 1] = 0.5 * (PetscRealPart(coords[1 * dim + d]) -
>>> PetscRealPart(coords[0 * dim + d]));
>>> J[d * dim + 2] = 0.5 * (PetscRealPart(coords[3 * dim + d]) -
>>> PetscRealPart(coords[0 * dim + d]));
>>> }
>>> }
>>>
>>> but still I am worried by this fact that different ways of creating a
>>> mesh gives a DMPlex with different orientations.
>>>
>>> Can you explain the rationale behind this or refer me to some
>>> documentation?
>>>
>>> Best
>>>
>>> Matteo
>>>
>>> --
>>> Prof. Matteo Semplice
>>> Università degli Studi dell’Insubria
>>> Dipartimento di Scienza e Alta Tecnologia – DiSAT
>>> Professore Associato
>>> Via Valleggio, 11 – 22100 Como (CO) – Italia
>>> tel.: +39 031 2386316
>
> --
> Prof. Matteo Semplice
> Università degli Studi dell’Insubria
> Dipartimento di Scienza e Alta Tecnologia – DiSAT
> Professore Associato
> Via Valleggio, 11 – 22100 Como (CO) – Italia
> tel.: +39 031 2386316
More information about the petsc-users
mailing list