xref: /petsc/src/dm/impls/plex/plexinterpolate.c (revision 3be36e832c16e7ee81fc2e2bbc7a02f90407362d)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2e8f14785SLisandro Dalcin #include <petsc/private/hashmapi.h>
3e8f14785SLisandro Dalcin #include <petsc/private/hashmapij.h>
4e8f14785SLisandro Dalcin 
5a7748839SVaclav Hapla const char * const DMPlexInterpolatedFlags[] = {"none", "partial", "mixed", "full", "DMPlexInterpolatedFlag", "DMPLEX_INTERPOLATED_", 0};
6a7748839SVaclav Hapla 
7e8f14785SLisandro Dalcin /* HashIJKL */
8e8f14785SLisandro Dalcin 
9e8f14785SLisandro Dalcin #include <petsc/private/hashmap.h>
10e8f14785SLisandro Dalcin 
11e8f14785SLisandro Dalcin typedef struct _PetscHashIJKLKey { PetscInt i, j, k, l; } PetscHashIJKLKey;
12e8f14785SLisandro Dalcin 
13e8f14785SLisandro Dalcin #define PetscHashIJKLKeyHash(key) \
14e8f14785SLisandro Dalcin   PetscHashCombine(PetscHashCombine(PetscHashInt((key).i),PetscHashInt((key).j)), \
15e8f14785SLisandro Dalcin                    PetscHashCombine(PetscHashInt((key).k),PetscHashInt((key).l)))
16e8f14785SLisandro Dalcin 
17e8f14785SLisandro Dalcin #define PetscHashIJKLKeyEqual(k1,k2) \
18e8f14785SLisandro Dalcin   (((k1).i==(k2).i) ? ((k1).j==(k2).j) ? ((k1).k==(k2).k) ? ((k1).l==(k2).l) : 0 : 0 : 0)
19e8f14785SLisandro Dalcin 
20e8f14785SLisandro Dalcin PETSC_HASH_MAP(HashIJKL, PetscHashIJKLKey, PetscInt, PetscHashIJKLKeyHash, PetscHashIJKLKeyEqual, -1)
21e8f14785SLisandro Dalcin 
22*3be36e83SMatthew G. Knepley static PetscSFNode _PetscInvalidSFNode = {-1, -1};
23*3be36e83SMatthew G. Knepley 
24*3be36e83SMatthew G. Knepley typedef struct _PetscHashIJKLRemoteKey { PetscSFNode i, j, k, l; } PetscHashIJKLRemoteKey;
25*3be36e83SMatthew G. Knepley 
26*3be36e83SMatthew G. Knepley #define PetscHashIJKLRemoteKeyHash(key) \
27*3be36e83SMatthew G. Knepley   PetscHashCombine(PetscHashCombine(PetscHashInt((key).i.rank + (key).i.index),PetscHashInt((key).j.rank + (key).j.index)), \
28*3be36e83SMatthew G. Knepley                    PetscHashCombine(PetscHashInt((key).k.rank + (key).k.index),PetscHashInt((key).l.rank + (key).l.index)))
29*3be36e83SMatthew G. Knepley 
30*3be36e83SMatthew G. Knepley #define PetscHashIJKLRemoteKeyEqual(k1,k2) \
31*3be36e83SMatthew G. Knepley   (((k1).i.rank==(k2).i.rank) ? ((k1).i.index==(k2).i.index) ? ((k1).j.rank==(k2).j.rank) ? ((k1).j.index==(k2).j.index) ? ((k1).k.rank==(k2).k.rank) ? ((k1).k.index==(k2).k.index) ? ((k1).l.rank==(k2).l.rank) ? ((k1).l.index==(k2).l.index) : 0 : 0 : 0 : 0 : 0 : 0 : 0)
32*3be36e83SMatthew G. Knepley 
33*3be36e83SMatthew G. Knepley PETSC_HASH_MAP(HashIJKLRemote, PetscHashIJKLRemoteKey, PetscSFNode, PetscHashIJKLRemoteKeyHash, PetscHashIJKLRemoteKeyEqual, _PetscInvalidSFNode)
34*3be36e83SMatthew G. Knepley 
35*3be36e83SMatthew G. Knepley static PetscErrorCode PetscSortSFNode(PetscInt n, PetscSFNode A[])
36*3be36e83SMatthew G. Knepley {
37*3be36e83SMatthew G. Knepley   PetscInt i;
38*3be36e83SMatthew G. Knepley 
39*3be36e83SMatthew G. Knepley   PetscFunctionBegin;
40*3be36e83SMatthew G. Knepley   for (i = 1; i < n; ++i) {
41*3be36e83SMatthew G. Knepley     PetscSFNode x = A[i];
42*3be36e83SMatthew G. Knepley     PetscInt    j;
43*3be36e83SMatthew G. Knepley 
44*3be36e83SMatthew G. Knepley     for (j = i-1; j >= 0; --j) {
45*3be36e83SMatthew G. Knepley       if ((A[j].rank > x.rank) || (A[j].rank == x.rank && A[j].index > x.index)) break;
46*3be36e83SMatthew G. Knepley       A[j+1] = A[j];
47*3be36e83SMatthew G. Knepley     }
48*3be36e83SMatthew G. Knepley     A[j+1] = x;
49*3be36e83SMatthew G. Knepley   }
50*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
51*3be36e83SMatthew G. Knepley }
529f074e33SMatthew G Knepley 
539f074e33SMatthew G Knepley /*
549a5b13a2SMatthew G Knepley   DMPlexGetFaces_Internal - Gets groups of vertices that correspond to faces for the given cell
55cd921712SStefano Zampini   This assumes that the mesh is not interpolated from the depth of point p to the vertices
569f074e33SMatthew G Knepley */
57439ece16SMatthew G. Knepley PetscErrorCode DMPlexGetFaces_Internal(DM dm, PetscInt dim, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
589f074e33SMatthew G Knepley {
599f074e33SMatthew G Knepley   const PetscInt *cone = NULL;
60cd921712SStefano Zampini   PetscInt        coneSize;
619f074e33SMatthew G Knepley   PetscErrorCode  ierr;
629f074e33SMatthew G Knepley 
639f074e33SMatthew G Knepley   PetscFunctionBegin;
649f074e33SMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
659f074e33SMatthew G Knepley   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
669f074e33SMatthew G Knepley   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
67439ece16SMatthew G. Knepley   ierr = DMPlexGetRawFaces_Internal(dm, dim, coneSize, cone, numFaces, faceSize, faces);CHKERRQ(ierr);
68439ece16SMatthew G. Knepley   PetscFunctionReturn(0);
69439ece16SMatthew G. Knepley }
70439ece16SMatthew G. Knepley 
71439ece16SMatthew G. Knepley /*
72439ece16SMatthew G. Knepley   DMPlexRestoreFaces_Internal - Restores the array
73439ece16SMatthew G. Knepley */
74439ece16SMatthew G. Knepley PetscErrorCode DMPlexRestoreFaces_Internal(DM dm, PetscInt dim, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
75439ece16SMatthew G. Knepley {
76439ece16SMatthew G. Knepley   PetscErrorCode  ierr;
77439ece16SMatthew G. Knepley 
78439ece16SMatthew G. Knepley   PetscFunctionBegin;
79cd921712SStefano Zampini   if (faces) { ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void *) faces);CHKERRQ(ierr); }
80439ece16SMatthew G. Knepley   PetscFunctionReturn(0);
81439ece16SMatthew G. Knepley }
82439ece16SMatthew G. Knepley 
83439ece16SMatthew G. Knepley /*
84439ece16SMatthew G. Knepley   DMPlexGetRawFaces_Internal - Gets groups of vertices that correspond to faces for the given cone
85439ece16SMatthew G. Knepley */
86439ece16SMatthew G. Knepley PetscErrorCode DMPlexGetRawFaces_Internal(DM dm, PetscInt dim, PetscInt coneSize, const PetscInt cone[], PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
87439ece16SMatthew G. Knepley {
88439ece16SMatthew G. Knepley   PetscInt       *facesTmp;
89439ece16SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize;
90439ece16SMatthew G. Knepley   PetscErrorCode  ierr;
91439ece16SMatthew G. Knepley 
92439ece16SMatthew G. Knepley   PetscFunctionBegin;
93439ece16SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
94cd921712SStefano Zampini   if (faces && coneSize) PetscValidIntPointer(cone,4);
95439ece16SMatthew G. Knepley   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
9669291d52SBarry Smith   if (faces) {ierr = DMGetWorkArray(dm, PetscSqr(PetscMax(maxConeSize, maxSupportSize)), MPIU_INT, &facesTmp);CHKERRQ(ierr);}
979f074e33SMatthew G Knepley   switch (dim) {
98c49d9212SMatthew G. Knepley   case 1:
99c49d9212SMatthew G. Knepley     switch (coneSize) {
100c49d9212SMatthew G. Knepley     case 2:
101c49d9212SMatthew G. Knepley       if (faces) {
102c49d9212SMatthew G. Knepley         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
103c49d9212SMatthew G. Knepley         *faces = facesTmp;
104c49d9212SMatthew G. Knepley       }
105c49d9212SMatthew G. Knepley       if (numFaces) *numFaces = 2;
106c49d9212SMatthew G. Knepley       if (faceSize) *faceSize = 1;
107c49d9212SMatthew G. Knepley       break;
108c49d9212SMatthew G. Knepley     default:
10999836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
110c49d9212SMatthew G. Knepley     }
111c49d9212SMatthew G. Knepley     break;
1129f074e33SMatthew G Knepley   case 2:
1139f074e33SMatthew G Knepley     switch (coneSize) {
1149f074e33SMatthew G Knepley     case 3:
1159a5b13a2SMatthew G Knepley       if (faces) {
1169a5b13a2SMatthew G Knepley         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
1179a5b13a2SMatthew G Knepley         facesTmp[2] = cone[1]; facesTmp[3] = cone[2];
1189a5b13a2SMatthew G Knepley         facesTmp[4] = cone[2]; facesTmp[5] = cone[0];
1199a5b13a2SMatthew G Knepley         *faces = facesTmp;
1209a5b13a2SMatthew G Knepley       }
1219a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 3;
1229a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 2;
1239f074e33SMatthew G Knepley       break;
1249f074e33SMatthew G Knepley     case 4:
1259a5b13a2SMatthew G Knepley       /* Vertices follow right hand rule */
1269a5b13a2SMatthew G Knepley       if (faces) {
1279a5b13a2SMatthew G Knepley         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
1289a5b13a2SMatthew G Knepley         facesTmp[2] = cone[1]; facesTmp[3] = cone[2];
1299a5b13a2SMatthew G Knepley         facesTmp[4] = cone[2]; facesTmp[5] = cone[3];
1309a5b13a2SMatthew G Knepley         facesTmp[6] = cone[3]; facesTmp[7] = cone[0];
1319a5b13a2SMatthew G Knepley         *faces = facesTmp;
1329a5b13a2SMatthew G Knepley       }
1339a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 4;
1349a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 2;
1359f074e33SMatthew G Knepley       break;
1369f074e33SMatthew G Knepley     default:
13799836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1389f074e33SMatthew G Knepley     }
1399f074e33SMatthew G Knepley     break;
1409f074e33SMatthew G Knepley   case 3:
1419f074e33SMatthew G Knepley     switch (coneSize) {
1429f074e33SMatthew G Knepley     case 3:
1439a5b13a2SMatthew G Knepley       if (faces) {
1449a5b13a2SMatthew G Knepley         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
1459a5b13a2SMatthew G Knepley         facesTmp[2] = cone[1]; facesTmp[3] = cone[2];
1469a5b13a2SMatthew G Knepley         facesTmp[4] = cone[2]; facesTmp[5] = cone[0];
1479a5b13a2SMatthew G Knepley         *faces = facesTmp;
1489a5b13a2SMatthew G Knepley       }
1499a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 3;
1509a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 2;
1519f074e33SMatthew G Knepley       break;
1529f074e33SMatthew G Knepley     case 4:
1532e1b13c2SMatthew G. Knepley       /* Vertices of first face follow right hand rule and normal points away from last vertex */
1549a5b13a2SMatthew G Knepley       if (faces) {
1552e1b13c2SMatthew G. Knepley         facesTmp[0] = cone[0]; facesTmp[1]  = cone[1]; facesTmp[2]  = cone[2];
1562e1b13c2SMatthew G. Knepley         facesTmp[3] = cone[0]; facesTmp[4]  = cone[3]; facesTmp[5]  = cone[1];
1572e1b13c2SMatthew G. Knepley         facesTmp[6] = cone[0]; facesTmp[7]  = cone[2]; facesTmp[8]  = cone[3];
1582e1b13c2SMatthew G. Knepley         facesTmp[9] = cone[2]; facesTmp[10] = cone[1]; facesTmp[11] = cone[3];
1599a5b13a2SMatthew G Knepley         *faces = facesTmp;
1609a5b13a2SMatthew G Knepley       }
1619a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 4;
1629a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 3;
1639a5b13a2SMatthew G Knepley       break;
1649a5b13a2SMatthew G Knepley     case 8:
165e368ef20SMatthew G. Knepley       /*  7--------6
166e368ef20SMatthew G. Knepley          /|       /|
167e368ef20SMatthew G. Knepley         / |      / |
168e368ef20SMatthew G. Knepley        4--------5  |
169e368ef20SMatthew G. Knepley        |  |     |  |
170e368ef20SMatthew G. Knepley        |  |     |  |
171e368ef20SMatthew G. Knepley        |  1--------2
172e368ef20SMatthew G. Knepley        | /      | /
173e368ef20SMatthew G. Knepley        |/       |/
174e368ef20SMatthew G. Knepley        0--------3
175e368ef20SMatthew G. Knepley        */
1769a5b13a2SMatthew G Knepley       if (faces) {
17751cfd6a4SMatthew G. Knepley         facesTmp[0]  = cone[0]; facesTmp[1]  = cone[1]; facesTmp[2]  = cone[2]; facesTmp[3]  = cone[3]; /* Bottom */
17851cfd6a4SMatthew G. Knepley         facesTmp[4]  = cone[4]; facesTmp[5]  = cone[5]; facesTmp[6]  = cone[6]; facesTmp[7]  = cone[7]; /* Top */
17951cfd6a4SMatthew G. Knepley         facesTmp[8]  = cone[0]; facesTmp[9]  = cone[3]; facesTmp[10] = cone[5]; facesTmp[11] = cone[4]; /* Front */
18051cfd6a4SMatthew G. Knepley         facesTmp[12] = cone[2]; facesTmp[13] = cone[1]; facesTmp[14] = cone[7]; facesTmp[15] = cone[6]; /* Back */
18151cfd6a4SMatthew G. Knepley         facesTmp[16] = cone[3]; facesTmp[17] = cone[2]; facesTmp[18] = cone[6]; facesTmp[19] = cone[5]; /* Right */
18251cfd6a4SMatthew G. Knepley         facesTmp[20] = cone[0]; facesTmp[21] = cone[4]; facesTmp[22] = cone[7]; facesTmp[23] = cone[1]; /* Left */
1839a5b13a2SMatthew G Knepley         *faces = facesTmp;
1849a5b13a2SMatthew G Knepley       }
1859a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 6;
1869a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 4;
1879f074e33SMatthew G Knepley       break;
1889f074e33SMatthew G Knepley     default:
18999836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1909f074e33SMatthew G Knepley     }
1919f074e33SMatthew G Knepley     break;
1929f074e33SMatthew G Knepley   default:
19399836e0eSStefano Zampini     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1949f074e33SMatthew G Knepley   }
1959f074e33SMatthew G Knepley   PetscFunctionReturn(0);
1969f074e33SMatthew G Knepley }
1979f074e33SMatthew G Knepley 
19899836e0eSStefano Zampini /*
19999836e0eSStefano Zampini   DMPlexGetRawFacesHybrid_Internal - Gets groups of vertices that correspond to faces for the given cone using hybrid ordering (prisms)
20099836e0eSStefano Zampini */
20199836e0eSStefano Zampini static PetscErrorCode DMPlexGetRawFacesHybrid_Internal(DM dm, PetscInt dim, PetscInt coneSize, const PetscInt cone[], PetscInt *numFaces, PetscInt *numFacesNotH, PetscInt *faceSize, const PetscInt *faces[])
20299836e0eSStefano Zampini {
20399836e0eSStefano Zampini   PetscInt       *facesTmp;
20499836e0eSStefano Zampini   PetscInt        maxConeSize, maxSupportSize;
20599836e0eSStefano Zampini   PetscErrorCode  ierr;
20699836e0eSStefano Zampini 
20799836e0eSStefano Zampini   PetscFunctionBegin;
20899836e0eSStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
20999836e0eSStefano Zampini   if (faces && coneSize) PetscValidIntPointer(cone,4);
21099836e0eSStefano Zampini   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
21199836e0eSStefano Zampini   if (faces) {ierr = DMGetWorkArray(dm, PetscSqr(PetscMax(maxConeSize, maxSupportSize)), MPIU_INT, &facesTmp);CHKERRQ(ierr);}
21299836e0eSStefano Zampini   switch (dim) {
21399836e0eSStefano Zampini   case 1:
21499836e0eSStefano Zampini     switch (coneSize) {
21599836e0eSStefano Zampini     case 2:
21699836e0eSStefano Zampini       if (faces) {
21799836e0eSStefano Zampini         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
21899836e0eSStefano Zampini         *faces = facesTmp;
21999836e0eSStefano Zampini       }
22099836e0eSStefano Zampini       if (numFaces)     *numFaces = 2;
22199836e0eSStefano Zampini       if (numFacesNotH) *numFacesNotH = 2;
22299836e0eSStefano Zampini       if (faceSize)     *faceSize = 1;
22399836e0eSStefano Zampini       break;
22499836e0eSStefano Zampini     default:
22599836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
22699836e0eSStefano Zampini     }
22799836e0eSStefano Zampini     break;
22899836e0eSStefano Zampini   case 2:
22999836e0eSStefano Zampini     switch (coneSize) {
23099836e0eSStefano Zampini     case 4:
23199836e0eSStefano Zampini       if (faces) {
23299836e0eSStefano Zampini         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
23399836e0eSStefano Zampini         facesTmp[2] = cone[2]; facesTmp[3] = cone[3];
23499836e0eSStefano Zampini         facesTmp[4] = cone[0]; facesTmp[5] = cone[2];
23599836e0eSStefano Zampini         facesTmp[6] = cone[1]; facesTmp[7] = cone[3];
23699836e0eSStefano Zampini         *faces = facesTmp;
23799836e0eSStefano Zampini       }
23899836e0eSStefano Zampini       if (numFaces)     *numFaces = 4;
23999836e0eSStefano Zampini       if (numFacesNotH) *numFacesNotH = 2;
24099836e0eSStefano Zampini       if (faceSize)     *faceSize = 2;
24199836e0eSStefano Zampini       break;
24299836e0eSStefano Zampini     default:
24399836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
24499836e0eSStefano Zampini     }
24599836e0eSStefano Zampini     break;
24699836e0eSStefano Zampini   case 3:
24799836e0eSStefano Zampini     switch (coneSize) {
24899836e0eSStefano Zampini     case 6: /* triangular prism */
24999836e0eSStefano Zampini       if (faces) {
25099836e0eSStefano Zampini         facesTmp[0]  = cone[0]; facesTmp[1]  = cone[1]; facesTmp[2]  = cone[2]; facesTmp[3]  = -1;      /* Bottom */
25199836e0eSStefano Zampini         facesTmp[4]  = cone[3]; facesTmp[5]  = cone[4]; facesTmp[6]  = cone[5]; facesTmp[7]  = -1;      /* Top */
25299836e0eSStefano Zampini         facesTmp[8]  = cone[0]; facesTmp[9]  = cone[1]; facesTmp[10] = cone[3]; facesTmp[11] = cone[4]; /* Back left */
25399836e0eSStefano Zampini         facesTmp[12] = cone[1]; facesTmp[13] = cone[2]; facesTmp[14] = cone[4]; facesTmp[15] = cone[5]; /* Back right */
25499836e0eSStefano Zampini         facesTmp[16] = cone[2]; facesTmp[17] = cone[0]; facesTmp[18] = cone[5]; facesTmp[19] = cone[3]; /* Front */
25599836e0eSStefano Zampini         *faces = facesTmp;
25699836e0eSStefano Zampini       }
25799836e0eSStefano Zampini       if (numFaces)     *numFaces = 5;
25899836e0eSStefano Zampini       if (numFacesNotH) *numFacesNotH = 2;
25999836e0eSStefano Zampini       if (faceSize)     *faceSize = -4;
26099836e0eSStefano Zampini       break;
26199836e0eSStefano Zampini     default:
26299836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
26399836e0eSStefano Zampini     }
26499836e0eSStefano Zampini     break;
26599836e0eSStefano Zampini   default:
26699836e0eSStefano Zampini     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
26799836e0eSStefano Zampini   }
26899836e0eSStefano Zampini   PetscFunctionReturn(0);
26999836e0eSStefano Zampini }
27099836e0eSStefano Zampini 
27199836e0eSStefano Zampini static PetscErrorCode DMPlexRestoreRawFacesHybrid_Internal(DM dm, PetscInt dim, PetscInt coneSize, const PetscInt cone[], PetscInt *numFaces, PetscInt *numFacesNotH, PetscInt *faceSize, const PetscInt *faces[])
27299836e0eSStefano Zampini {
27399836e0eSStefano Zampini   PetscErrorCode  ierr;
27499836e0eSStefano Zampini 
27599836e0eSStefano Zampini   PetscFunctionBegin;
27699836e0eSStefano Zampini   if (faces) { ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void *) faces);CHKERRQ(ierr); }
27799836e0eSStefano Zampini   PetscFunctionReturn(0);
27899836e0eSStefano Zampini }
27999836e0eSStefano Zampini 
28099836e0eSStefano Zampini static PetscErrorCode DMPlexGetFacesHybrid_Internal(DM dm, PetscInt dim, PetscInt p, PetscInt *numFaces, PetscInt *numFacesNotH, PetscInt *faceSize, const PetscInt *faces[])
28199836e0eSStefano Zampini {
28299836e0eSStefano Zampini   const PetscInt *cone = NULL;
28399836e0eSStefano Zampini   PetscInt        coneSize;
28499836e0eSStefano Zampini   PetscErrorCode  ierr;
28599836e0eSStefano Zampini 
28699836e0eSStefano Zampini   PetscFunctionBegin;
28799836e0eSStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28899836e0eSStefano Zampini   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
28999836e0eSStefano Zampini   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
29099836e0eSStefano Zampini   ierr = DMPlexGetRawFacesHybrid_Internal(dm, dim, coneSize, cone, numFaces, numFacesNotH, faceSize, faces);CHKERRQ(ierr);
29199836e0eSStefano Zampini   PetscFunctionReturn(0);
29299836e0eSStefano Zampini }
29399836e0eSStefano Zampini 
2949a5b13a2SMatthew G Knepley /* This interpolates faces for cells at some stratum */
2959a5b13a2SMatthew G Knepley static PetscErrorCode DMPlexInterpolateFaces_Internal(DM dm, PetscInt cellDepth, DM idm)
2969f074e33SMatthew G Knepley {
297d4efc6f1SMatthew G. Knepley   DMLabel        subpointMap;
2989a5b13a2SMatthew G Knepley   PetscHashIJKL  faceTable;
2999a5b13a2SMatthew G Knepley   PetscInt      *pStart, *pEnd;
3009a5b13a2SMatthew G Knepley   PetscInt       cellDim, depth, faceDepth = cellDepth, numPoints = 0, faceSizeAll = 0, face, c, d;
301e9fa77a1SMatthew G. Knepley   PetscInt       coneSizeH = 0, faceSizeAllH = 0, faceSizeAllT = 0, numCellFacesH = 0, faceT = 0, faceH, pMax = -1, dim, outerloop;
30299836e0eSStefano Zampini   PetscInt       cMax, fMax, eMax, vMax;
3039f074e33SMatthew G Knepley   PetscErrorCode ierr;
3049f074e33SMatthew G Knepley 
3059f074e33SMatthew G Knepley   PetscFunctionBegin;
306c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &cellDim);CHKERRQ(ierr);
307d4efc6f1SMatthew G. Knepley   /* HACK: I need a better way to determine face dimension, or an alternative to GetFaces() */
308d4efc6f1SMatthew G. Knepley   ierr = DMPlexGetSubpointMap(dm, &subpointMap);CHKERRQ(ierr);
309d4efc6f1SMatthew G. Knepley   if (subpointMap) ++cellDim;
3109a5b13a2SMatthew G Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3119a5b13a2SMatthew G Knepley   ++depth;
3129a5b13a2SMatthew G Knepley   ++cellDepth;
3139a5b13a2SMatthew G Knepley   cellDim -= depth - cellDepth;
314dcca6d9dSJed Brown   ierr = PetscMalloc2(depth+1,&pStart,depth+1,&pEnd);CHKERRQ(ierr);
3159a5b13a2SMatthew G Knepley   for (d = depth-1; d >= faceDepth; --d) {
3169a5b13a2SMatthew G Knepley     ierr = DMPlexGetDepthStratum(dm, d, &pStart[d+1], &pEnd[d+1]);CHKERRQ(ierr);
3179f074e33SMatthew G Knepley   }
3189a5b13a2SMatthew G Knepley   ierr = DMPlexGetDepthStratum(dm, -1, NULL, &pStart[faceDepth]);CHKERRQ(ierr);
3199a5b13a2SMatthew G Knepley   pEnd[faceDepth] = pStart[faceDepth];
3209a5b13a2SMatthew G Knepley   for (d = faceDepth-1; d >= 0; --d) {
3219a5b13a2SMatthew G Knepley     ierr = DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);CHKERRQ(ierr);
3229f074e33SMatthew G Knepley   }
32399836e0eSStefano Zampini   cMax = fMax = eMax = vMax = PETSC_DETERMINE;
32499836e0eSStefano Zampini   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
32599836e0eSStefano Zampini   if (cellDim == dim) {
32699836e0eSStefano Zampini     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
32799836e0eSStefano Zampini     pMax = cMax;
32899836e0eSStefano Zampini   } else if (cellDim == dim -1) {
32999836e0eSStefano Zampini     ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
33099836e0eSStefano Zampini     pMax = fMax;
33199836e0eSStefano Zampini   }
33299836e0eSStefano Zampini   pMax = pMax < 0 ? pEnd[cellDepth] : pMax;
33399836e0eSStefano Zampini   if (pMax < pEnd[cellDepth]) {
33499836e0eSStefano Zampini     const PetscInt *cellFaces, *cone;
33599836e0eSStefano Zampini     PetscInt        numCellFacesT, faceSize, cf;
3369f074e33SMatthew G Knepley 
337e9fa77a1SMatthew G. Knepley     /* First get normal cell face size (we now allow hybrid cells to meet normal cells on either hybrid or normal faces */
3385ebdaad1SMatthew G. Knepley     if (pStart[cellDepth] < pMax) {ierr = DMPlexGetFaces_Internal(dm, cellDim, pStart[cellDepth], NULL, &faceSizeAll, NULL);CHKERRQ(ierr);}
339e9fa77a1SMatthew G. Knepley 
34099836e0eSStefano Zampini     ierr = DMPlexGetConeSize(dm, pMax, &coneSizeH);CHKERRQ(ierr);
34199836e0eSStefano Zampini     ierr = DMPlexGetCone(dm, pMax, &cone);CHKERRQ(ierr);
34299836e0eSStefano Zampini     ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSizeH, cone, &numCellFacesH, &numCellFacesT, &faceSize, &cellFaces);CHKERRQ(ierr);
34399836e0eSStefano Zampini     if (faceSize < 0) {
34499836e0eSStefano Zampini       PetscInt *sizes, minv, maxv;
34599836e0eSStefano Zampini 
34699836e0eSStefano Zampini       /* count vertices of hybrid and non-hybrid faces */
34799836e0eSStefano Zampini       ierr = PetscCalloc1(numCellFacesH, &sizes);CHKERRQ(ierr);
34899836e0eSStefano Zampini       for (cf = 0; cf < numCellFacesT; ++cf) { /* These are the non-hybrid faces */
34999836e0eSStefano Zampini         const PetscInt *cellFace = &cellFaces[-cf*faceSize];
35099836e0eSStefano Zampini         PetscInt       f;
35199836e0eSStefano Zampini 
35299836e0eSStefano Zampini         for (f = 0; f < -faceSize; ++f) sizes[cf] += (cellFace[f] >= 0 ? 1 : 0);
35399836e0eSStefano Zampini       }
35499836e0eSStefano Zampini       ierr = PetscSortInt(numCellFacesT, sizes);CHKERRQ(ierr);
35599836e0eSStefano Zampini       minv = sizes[0];
35699836e0eSStefano Zampini       maxv = sizes[PetscMax(numCellFacesT-1, 0)];
35799836e0eSStefano Zampini       if (minv != maxv) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Different number of vertices for non-hybrid face %D != %D", minv, maxv);
358e9fa77a1SMatthew G. Knepley       faceSizeAllT = minv;
359580bdb30SBarry Smith       ierr = PetscArrayzero(sizes, numCellFacesH);CHKERRQ(ierr);
36099836e0eSStefano Zampini       for (cf = numCellFacesT; cf < numCellFacesH; ++cf) { /* These are the hybrid faces */
36199836e0eSStefano Zampini         const PetscInt *cellFace = &cellFaces[-cf*faceSize];
36299836e0eSStefano Zampini         PetscInt       f;
36399836e0eSStefano Zampini 
36499836e0eSStefano Zampini         for (f = 0; f < -faceSize; ++f) sizes[cf-numCellFacesT] += (cellFace[f] >= 0 ? 1 : 0);
36599836e0eSStefano Zampini       }
36699836e0eSStefano Zampini       ierr = PetscSortInt(numCellFacesH - numCellFacesT, sizes);CHKERRQ(ierr);
36799836e0eSStefano Zampini       minv = sizes[0];
36899836e0eSStefano Zampini       maxv = sizes[PetscMax(numCellFacesH - numCellFacesT-1, 0)];
36999836e0eSStefano Zampini       ierr = PetscFree(sizes);CHKERRQ(ierr);
37099836e0eSStefano Zampini       if (minv != maxv) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Different number of vertices for hybrid face %D != %D", minv, maxv);
37199836e0eSStefano Zampini       faceSizeAllH = minv;
3725ebdaad1SMatthew G. Knepley       if (!faceSizeAll) faceSizeAll = faceSizeAllT;
37399836e0eSStefano Zampini     } else { /* the size of the faces in hybrid cells is the same */
374e9fa77a1SMatthew G. Knepley       faceSizeAll = faceSizeAllH = faceSizeAllT = faceSize;
37599836e0eSStefano Zampini     }
37699836e0eSStefano Zampini     ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSizeH, cone, &numCellFacesH, &numCellFacesT, &faceSize, &cellFaces);CHKERRQ(ierr);
37799836e0eSStefano Zampini   } else if (pEnd[cellDepth] > pStart[cellDepth]) {
37899836e0eSStefano Zampini     ierr = DMPlexGetFaces_Internal(dm, cellDim, pStart[cellDepth], NULL, &faceSizeAll, NULL);CHKERRQ(ierr);
379a1bcd873SMatthew G. Knepley     faceSizeAllH = faceSizeAllT = faceSizeAll;
38099836e0eSStefano Zampini   }
38199836e0eSStefano Zampini   if (faceSizeAll > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSizeAll);
38299836e0eSStefano Zampini 
383b135d7daSStefano Zampini   /* With hybrid grids, we first iterate on hybrid cells and start numbering the non-hybrid faces
38499836e0eSStefano Zampini      Then, faces for non-hybrid cells are numbered.
38599836e0eSStefano Zampini      This is to guarantee consistent orientations (all 0) of all the points in the cone of the hybrid cells */
38699836e0eSStefano Zampini   ierr = PetscHashIJKLCreate(&faceTable);CHKERRQ(ierr);
38799836e0eSStefano Zampini   for (outerloop = 0, face = pStart[faceDepth]; outerloop < 2; outerloop++) {
38899836e0eSStefano Zampini     PetscInt start, end;
38999836e0eSStefano Zampini 
39099836e0eSStefano Zampini     start = outerloop == 0 ? pMax : pStart[cellDepth];
39199836e0eSStefano Zampini     end = outerloop == 0 ? pEnd[cellDepth] : pMax;
39299836e0eSStefano Zampini     for (c = start; c < end; ++c) {
39399836e0eSStefano Zampini       const PetscInt *cellFaces;
394e9fa77a1SMatthew G. Knepley       PetscInt        numCellFaces, faceSize, faceSizeInc, faceSizeCheck, cf;
39599836e0eSStefano Zampini 
39699836e0eSStefano Zampini       if (c < pMax) {
3979a5b13a2SMatthew G Knepley         ierr = DMPlexGetFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
3989a5b13a2SMatthew G Knepley         if (faceSize != faceSizeAll) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent face for cell %D of size %D != %D", c, faceSize, faceSizeAll);
399e9fa77a1SMatthew G. Knepley         faceSizeCheck = faceSizeAll;
40099836e0eSStefano Zampini       } else { /* Hybrid cell */
40199836e0eSStefano Zampini         const PetscInt *cone;
40299836e0eSStefano Zampini         PetscInt        numCellFacesN, coneSize;
40399836e0eSStefano Zampini 
40499836e0eSStefano Zampini         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
40599836e0eSStefano Zampini         if (coneSize != coneSizeH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid coneSize %D != %D", coneSize, coneSizeH);
40699836e0eSStefano Zampini         ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
40799836e0eSStefano Zampini         ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
40899836e0eSStefano Zampini         if (numCellFaces != numCellFacesH) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected numCellFaces %D != %D for hybrid cell %D", numCellFaces, numCellFacesH, c);
40999836e0eSStefano Zampini         faceSize = PetscMax(faceSize, -faceSize);
41099836e0eSStefano Zampini         if (faceSize > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSize);
41199836e0eSStefano Zampini         numCellFaces = numCellFacesN; /* process only non-hybrid faces */
412e9fa77a1SMatthew G. Knepley         faceSizeCheck = faceSizeAllT;
41399836e0eSStefano Zampini       }
41499836e0eSStefano Zampini       faceSizeInc = faceSize;
4159f074e33SMatthew G Knepley       for (cf = 0; cf < numCellFaces; ++cf) {
41699836e0eSStefano Zampini         const PetscInt   *cellFace = &cellFaces[cf*faceSizeInc];
41799836e0eSStefano Zampini         PetscInt          faceSizeH = faceSize;
4189a5b13a2SMatthew G Knepley         PetscHashIJKLKey  key;
419e8f14785SLisandro Dalcin         PetscHashIter     iter;
420e8f14785SLisandro Dalcin         PetscBool         missing;
4219f074e33SMatthew G Knepley 
42299836e0eSStefano Zampini         if (faceSizeInc == 2) {
4239a5b13a2SMatthew G Knepley           key.i = PetscMin(cellFace[0], cellFace[1]);
4249a5b13a2SMatthew G Knepley           key.j = PetscMax(cellFace[0], cellFace[1]);
42599836e0eSStefano Zampini           key.k = PETSC_MAX_INT;
42699836e0eSStefano Zampini           key.l = PETSC_MAX_INT;
4279a5b13a2SMatthew G Knepley         } else {
42899836e0eSStefano Zampini           key.i = cellFace[0];
42999836e0eSStefano Zampini           key.j = cellFace[1];
43099836e0eSStefano Zampini           key.k = cellFace[2];
43199836e0eSStefano Zampini           key.l = faceSize > 3 ? (cellFace[3] < 0 ? faceSizeH = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
432302440fdSBarry Smith           ierr  = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr);
4339f074e33SMatthew G Knepley         }
43499836e0eSStefano Zampini         /* this check is redundant for non-hybrid meshes */
435e9fa77a1SMatthew G. Knepley         if (faceSizeH != faceSizeCheck) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected number of vertices for face %D of point %D -> %D != %D", cf, c, faceSizeH, faceSizeCheck);
436e8f14785SLisandro Dalcin         ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
437e9fa77a1SMatthew G. Knepley         if (missing) {
438e9fa77a1SMatthew G. Knepley           ierr = PetscHashIJKLIterSet(faceTable, iter, face++);CHKERRQ(ierr);
439e9fa77a1SMatthew G. Knepley           if (c >= pMax) ++faceT;
440e9fa77a1SMatthew G. Knepley         }
4419a5b13a2SMatthew G Knepley       }
44299836e0eSStefano Zampini       if (c < pMax) {
443439ece16SMatthew G. Knepley         ierr = DMPlexRestoreFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
44499836e0eSStefano Zampini       } else {
44599836e0eSStefano Zampini         ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSizeH, NULL, NULL, NULL, NULL, &cellFaces);CHKERRQ(ierr);
44699836e0eSStefano Zampini       }
44799836e0eSStefano Zampini     }
44899836e0eSStefano Zampini   }
44999836e0eSStefano Zampini   pEnd[faceDepth] = face;
45099836e0eSStefano Zampini 
45199836e0eSStefano Zampini   /* Second pass for hybrid meshes: number hybrid faces */
45299836e0eSStefano Zampini   for (c = pMax; c < pEnd[cellDepth]; ++c) {
45399836e0eSStefano Zampini     const PetscInt *cellFaces, *cone;
45499836e0eSStefano Zampini     PetscInt        numCellFaces, numCellFacesN, faceSize, cf, coneSize;
45599836e0eSStefano Zampini 
45699836e0eSStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
45799836e0eSStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
45899836e0eSStefano Zampini     ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
45999836e0eSStefano Zampini     if (numCellFaces != numCellFacesH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid numCellFaces %D != %D", numCellFaces, numCellFacesH);
46099836e0eSStefano Zampini     faceSize = PetscMax(faceSize, -faceSize);
46199836e0eSStefano Zampini     for (cf = numCellFacesN; cf < numCellFaces; ++cf) { /* These are the hybrid faces */
46299836e0eSStefano Zampini       const PetscInt   *cellFace = &cellFaces[cf*faceSize];
46399836e0eSStefano Zampini       PetscHashIJKLKey  key;
46499836e0eSStefano Zampini       PetscHashIter     iter;
46599836e0eSStefano Zampini       PetscBool         missing;
46699836e0eSStefano Zampini       PetscInt          faceSizeH = faceSize;
46799836e0eSStefano Zampini 
46899836e0eSStefano Zampini       if (faceSize == 2) {
46999836e0eSStefano Zampini         key.i = PetscMin(cellFace[0], cellFace[1]);
47099836e0eSStefano Zampini         key.j = PetscMax(cellFace[0], cellFace[1]);
47199836e0eSStefano Zampini         key.k = PETSC_MAX_INT;
47299836e0eSStefano Zampini         key.l = PETSC_MAX_INT;
47399836e0eSStefano Zampini       } else {
47499836e0eSStefano Zampini         key.i = cellFace[0];
47599836e0eSStefano Zampini         key.j = cellFace[1];
47699836e0eSStefano Zampini         key.k = cellFace[2];
47799836e0eSStefano Zampini         key.l = faceSize > 3 ? (cellFace[3] < 0 ? faceSizeH = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
47899836e0eSStefano Zampini         ierr  = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr);
47999836e0eSStefano Zampini       }
48099836e0eSStefano Zampini       if (faceSizeH != faceSizeAllH) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected number of vertices for hybrid face %D of point %D -> %D != %D", cf, c, faceSizeH, faceSizeAllH);
48199836e0eSStefano Zampini       ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
48299836e0eSStefano Zampini       if (missing) {ierr = PetscHashIJKLIterSet(faceTable, iter, face++);CHKERRQ(ierr);}
48399836e0eSStefano Zampini     }
48499836e0eSStefano Zampini     ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
48599836e0eSStefano Zampini   }
48699836e0eSStefano Zampini   faceH = face - pEnd[faceDepth];
48799836e0eSStefano Zampini   if (faceH) {
48899836e0eSStefano Zampini     if (fMax == PETSC_DETERMINE) fMax = pEnd[faceDepth];
48999836e0eSStefano Zampini     else if (eMax == PETSC_DETERMINE) eMax = pEnd[faceDepth];
49099836e0eSStefano Zampini     else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of unassigned hybrid facets %D for cellDim %D and dimension %D", faceH, cellDim, dim);
4919a5b13a2SMatthew G Knepley   }
4929a5b13a2SMatthew G Knepley   pEnd[faceDepth] = face;
4939a5b13a2SMatthew G Knepley   ierr = PetscHashIJKLDestroy(&faceTable);CHKERRQ(ierr);
4949a5b13a2SMatthew G Knepley   /* Count new points */
4959a5b13a2SMatthew G Knepley   for (d = 0; d <= depth; ++d) {
4969a5b13a2SMatthew G Knepley     numPoints += pEnd[d]-pStart[d];
4979a5b13a2SMatthew G Knepley   }
4989a5b13a2SMatthew G Knepley   ierr = DMPlexSetChart(idm, 0, numPoints);CHKERRQ(ierr);
4999a5b13a2SMatthew G Knepley   /* Set cone sizes */
5009a5b13a2SMatthew G Knepley   for (d = 0; d <= depth; ++d) {
5019a5b13a2SMatthew G Knepley     PetscInt coneSize, p;
5029f074e33SMatthew G Knepley 
5039a5b13a2SMatthew G Knepley     if (d == faceDepth) {
504e9fa77a1SMatthew G. Knepley       /* Now we have two cases: */
505e9fa77a1SMatthew G. Knepley       if (faceSizeAll == faceSizeAllT) {
5069a5b13a2SMatthew G Knepley         /* I see no way to do this if we admit faces of different shapes */
50799836e0eSStefano Zampini         for (p = pStart[d]; p < pEnd[d]-faceH; ++p) {
5089a5b13a2SMatthew G Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAll);CHKERRQ(ierr);
5099a5b13a2SMatthew G Knepley         }
51099836e0eSStefano Zampini         for (p = pEnd[d]-faceH; p < pEnd[d]; ++p) {
51199836e0eSStefano Zampini           ierr = DMPlexSetConeSize(idm, p, faceSizeAllH);CHKERRQ(ierr);
51299836e0eSStefano Zampini         }
513e9fa77a1SMatthew G. Knepley       } else if (faceSizeAll == faceSizeAllH) {
514e9fa77a1SMatthew G. Knepley         for (p = pStart[d]; p < pStart[d]+faceT; ++p) {
515e9fa77a1SMatthew G. Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAllT);CHKERRQ(ierr);
516e9fa77a1SMatthew G. Knepley         }
517e9fa77a1SMatthew G. Knepley         for (p = pStart[d]+faceT; p < pEnd[d]-faceH; ++p) {
518e9fa77a1SMatthew G. Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAll);CHKERRQ(ierr);
519e9fa77a1SMatthew G. Knepley         }
520e9fa77a1SMatthew G. Knepley         for (p = pEnd[d]-faceH; p < pEnd[d]; ++p) {
521e9fa77a1SMatthew G. Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAllH);CHKERRQ(ierr);
522e9fa77a1SMatthew G. Knepley         }
523e9fa77a1SMatthew G. Knepley       } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent faces sizes N: %D T: %D H: %D", faceSizeAll, faceSizeAllT, faceSizeAllH);
524a014044eSMatthew G Knepley     } else if (d == cellDepth) {
525a014044eSMatthew G Knepley       for (p = pStart[d]; p < pEnd[d]; ++p) {
526a014044eSMatthew G Knepley         /* Number of cell faces may be different from number of cell vertices*/
52799836e0eSStefano Zampini         if (p < pMax) {
528a014044eSMatthew G Knepley           ierr = DMPlexGetFaces_Internal(dm, cellDim, p, &coneSize, NULL, NULL);CHKERRQ(ierr);
52999836e0eSStefano Zampini         } else {
53099836e0eSStefano Zampini           ierr = DMPlexGetFacesHybrid_Internal(dm, cellDim, p, &coneSize, NULL, NULL, NULL);CHKERRQ(ierr);
53199836e0eSStefano Zampini         }
532a014044eSMatthew G Knepley         ierr = DMPlexSetConeSize(idm, p, coneSize);CHKERRQ(ierr);
533a014044eSMatthew G Knepley       }
5349a5b13a2SMatthew G Knepley     } else {
5359a5b13a2SMatthew G Knepley       for (p = pStart[d]; p < pEnd[d]; ++p) {
5369a5b13a2SMatthew G Knepley         ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5379a5b13a2SMatthew G Knepley         ierr = DMPlexSetConeSize(idm, p, coneSize);CHKERRQ(ierr);
5389f074e33SMatthew G Knepley       }
5399f074e33SMatthew G Knepley     }
5409f074e33SMatthew G Knepley   }
5419f074e33SMatthew G Knepley   ierr = DMSetUp(idm);CHKERRQ(ierr);
5429f074e33SMatthew G Knepley   /* Get face cones from subsets of cell vertices */
54399836e0eSStefano Zampini   if (faceSizeAll > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSizeAll);
5449a5b13a2SMatthew G Knepley   ierr = PetscHashIJKLCreate(&faceTable);CHKERRQ(ierr);
5459a5b13a2SMatthew G Knepley   for (d = depth; d > cellDepth; --d) {
5469a5b13a2SMatthew G Knepley     const PetscInt *cone;
5479a5b13a2SMatthew G Knepley     PetscInt        p;
5489a5b13a2SMatthew G Knepley 
5499a5b13a2SMatthew G Knepley     for (p = pStart[d]; p < pEnd[d]; ++p) {
5509a5b13a2SMatthew G Knepley       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5519a5b13a2SMatthew G Knepley       ierr = DMPlexSetCone(idm, p, cone);CHKERRQ(ierr);
5529a5b13a2SMatthew G Knepley       ierr = DMPlexGetConeOrientation(dm, p, &cone);CHKERRQ(ierr);
5539a5b13a2SMatthew G Knepley       ierr = DMPlexSetConeOrientation(idm, p, cone);CHKERRQ(ierr);
5549f074e33SMatthew G Knepley     }
5559a5b13a2SMatthew G Knepley   }
55699836e0eSStefano Zampini   for (outerloop = 0, face = pStart[faceDepth]; outerloop < 2; outerloop++) {
55799836e0eSStefano Zampini     PetscInt start, end;
5589f074e33SMatthew G Knepley 
55999836e0eSStefano Zampini     start = outerloop == 0 ? pMax : pStart[cellDepth];
56099836e0eSStefano Zampini     end = outerloop == 0 ? pEnd[cellDepth] : pMax;
56199836e0eSStefano Zampini     for (c = start; c < end; ++c) {
56299836e0eSStefano Zampini       const PetscInt *cellFaces;
56399836e0eSStefano Zampini       PetscInt        numCellFaces, faceSize, faceSizeInc, cf;
56499836e0eSStefano Zampini 
56599836e0eSStefano Zampini       if (c < pMax) {
5669a5b13a2SMatthew G Knepley         ierr = DMPlexGetFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
5679a5b13a2SMatthew G Knepley         if (faceSize != faceSizeAll) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent face for cell %D of size %D != %D", c, faceSize, faceSizeAll);
56899836e0eSStefano Zampini       } else {
56999836e0eSStefano Zampini         const PetscInt *cone;
57099836e0eSStefano Zampini         PetscInt        numCellFacesN, coneSize;
57199836e0eSStefano Zampini 
57299836e0eSStefano Zampini         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
57399836e0eSStefano Zampini         if (coneSize != coneSizeH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid coneSize %D != %D", coneSize, coneSizeH);
57499836e0eSStefano Zampini         ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
57599836e0eSStefano Zampini         ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
57699836e0eSStefano Zampini         if (numCellFaces != numCellFacesH) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected numCellFaces %D != %D for hybrid cell %D", numCellFaces, numCellFacesH, c);
57799836e0eSStefano Zampini         faceSize = PetscMax(faceSize, -faceSize);
57899836e0eSStefano Zampini         if (faceSize > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSize);
57999836e0eSStefano Zampini         numCellFaces = numCellFacesN; /* process only non-hybrid faces */
58099836e0eSStefano Zampini       }
58199836e0eSStefano Zampini       faceSizeInc = faceSize;
5829f074e33SMatthew G Knepley       for (cf = 0; cf < numCellFaces; ++cf) {
58399836e0eSStefano Zampini         const PetscInt  *cellFace = &cellFaces[cf*faceSizeInc];
5849a5b13a2SMatthew G Knepley         PetscHashIJKLKey key;
585e8f14785SLisandro Dalcin         PetscHashIter    iter;
586e8f14785SLisandro Dalcin         PetscBool        missing;
5879f074e33SMatthew G Knepley 
58899836e0eSStefano Zampini         if (faceSizeInc == 2) {
5899a5b13a2SMatthew G Knepley           key.i = PetscMin(cellFace[0], cellFace[1]);
5909a5b13a2SMatthew G Knepley           key.j = PetscMax(cellFace[0], cellFace[1]);
59199836e0eSStefano Zampini           key.k = PETSC_MAX_INT;
59299836e0eSStefano Zampini           key.l = PETSC_MAX_INT;
5939a5b13a2SMatthew G Knepley         } else {
594e8f14785SLisandro Dalcin           key.i = cellFace[0];
595e8f14785SLisandro Dalcin           key.j = cellFace[1];
596e8f14785SLisandro Dalcin           key.k = cellFace[2];
59799836e0eSStefano Zampini           key.l = faceSizeInc > 3 ? (cellFace[3] < 0 ? faceSize = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
59899836e0eSStefano Zampini           ierr  = PetscSortInt(faceSizeInc, (PetscInt *) &key);CHKERRQ(ierr);
5999f074e33SMatthew G Knepley         }
600e8f14785SLisandro Dalcin         ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
601735a0255SMatthew G. Knepley         if (missing) {
6029a5b13a2SMatthew G Knepley           ierr = DMPlexSetCone(idm, face, cellFace);CHKERRQ(ierr);
603e8f14785SLisandro Dalcin           ierr = PetscHashIJKLIterSet(faceTable, iter, face);CHKERRQ(ierr);
604735a0255SMatthew G. Knepley           ierr = DMPlexInsertCone(idm, c, cf, face++);CHKERRQ(ierr);
6059a5b13a2SMatthew G Knepley         } else {
6069a5b13a2SMatthew G Knepley           const PetscInt *cone;
607735a0255SMatthew G. Knepley           PetscInt        coneSize, ornt, i, j, f;
6089f074e33SMatthew G Knepley 
609e8f14785SLisandro Dalcin           ierr = PetscHashIJKLIterGet(faceTable, iter, &f);CHKERRQ(ierr);
6109a5b13a2SMatthew G Knepley           ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
6112e1b13c2SMatthew G. Knepley           /* Orient face: Do not allow reverse orientation at the first vertex */
6129f074e33SMatthew G Knepley           ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
6139f074e33SMatthew G Knepley           ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
6149a5b13a2SMatthew G Knepley           if (coneSize != faceSize) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of face vertices %D for face %D should be %D", coneSize, f, faceSize);
6159a5b13a2SMatthew G Knepley           /* - First find the initial vertex */
6169a5b13a2SMatthew G Knepley           for (i = 0; i < faceSize; ++i) if (cellFace[0] == cone[i]) break;
6179a5b13a2SMatthew G Knepley           /* - Try forward comparison */
6189a5b13a2SMatthew G Knepley           for (j = 0; j < faceSize; ++j) if (cellFace[j] != cone[(i+j)%faceSize]) break;
6199a5b13a2SMatthew G Knepley           if (j == faceSize) {
6209a5b13a2SMatthew G Knepley             if ((faceSize == 2) && (i == 1)) ornt = -2;
6219a5b13a2SMatthew G Knepley             else                             ornt = i;
6229a5b13a2SMatthew G Knepley           } else {
6239a5b13a2SMatthew G Knepley             /* - Try backward comparison */
6249a5b13a2SMatthew G Knepley             for (j = 0; j < faceSize; ++j) if (cellFace[j] != cone[(i+faceSize-j)%faceSize]) break;
6252e1b13c2SMatthew G. Knepley             if (j == faceSize) {
6262e1b13c2SMatthew G. Knepley               if (i == 0) ornt = -faceSize;
627dc1a705cSMatthew G. Knepley               else        ornt = -i;
628e9fa77a1SMatthew G. Knepley             } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not determine orientation of face %D in cell %D", f, c);
6299a5b13a2SMatthew G Knepley           }
6309a5b13a2SMatthew G Knepley           ierr = DMPlexInsertConeOrientation(idm, c, cf, ornt);CHKERRQ(ierr);
6319f074e33SMatthew G Knepley         }
6329f074e33SMatthew G Knepley       }
63399836e0eSStefano Zampini       if (c < pMax) {
634439ece16SMatthew G. Knepley         ierr = DMPlexRestoreFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
63599836e0eSStefano Zampini       } else {
63699836e0eSStefano Zampini         ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSizeH, NULL, NULL, NULL, NULL, &cellFaces);CHKERRQ(ierr);
6379f074e33SMatthew G Knepley       }
63899836e0eSStefano Zampini     }
63999836e0eSStefano Zampini   }
64099836e0eSStefano Zampini   /* Second pass for hybrid meshes: orient hybrid faces */
64199836e0eSStefano Zampini   for (c = pMax; c < pEnd[cellDepth]; ++c) {
64299836e0eSStefano Zampini     const PetscInt *cellFaces, *cone;
64399836e0eSStefano Zampini     PetscInt        numCellFaces, numCellFacesN, faceSize, cf, coneSize;
64499836e0eSStefano Zampini 
64599836e0eSStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
64699836e0eSStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
64799836e0eSStefano Zampini     ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
64899836e0eSStefano Zampini     if (numCellFaces != numCellFacesH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid numCellFaces %D != %D", numCellFaces, numCellFacesH);
64999836e0eSStefano Zampini     faceSize = PetscMax(faceSize, -faceSize);
65099836e0eSStefano Zampini     for (cf = numCellFacesN; cf < numCellFaces; ++cf) { /* These are the hybrid faces */
65199836e0eSStefano Zampini       const PetscInt   *cellFace = &cellFaces[cf*faceSize];
65299836e0eSStefano Zampini       PetscHashIJKLKey key;
65399836e0eSStefano Zampini       PetscHashIter    iter;
65499836e0eSStefano Zampini       PetscBool        missing;
65599836e0eSStefano Zampini       PetscInt         faceSizeH = faceSize;
65699836e0eSStefano Zampini 
65799836e0eSStefano Zampini       if (faceSize == 2) {
65899836e0eSStefano Zampini         key.i = PetscMin(cellFace[0], cellFace[1]);
65999836e0eSStefano Zampini         key.j = PetscMax(cellFace[0], cellFace[1]);
66099836e0eSStefano Zampini         key.k = PETSC_MAX_INT;
66199836e0eSStefano Zampini         key.l = PETSC_MAX_INT;
66299836e0eSStefano Zampini       } else {
66399836e0eSStefano Zampini         key.i = cellFace[0];
66499836e0eSStefano Zampini         key.j = cellFace[1];
66599836e0eSStefano Zampini         key.k = cellFace[2];
66699836e0eSStefano Zampini         key.l = faceSize > 3 ? (cellFace[3] < 0 ? faceSizeH = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
66799836e0eSStefano Zampini         ierr  = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr);
66899836e0eSStefano Zampini       }
66999836e0eSStefano Zampini       if (faceSizeH != faceSizeAllH) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected number of vertices for hybrid face %D of point %D -> %D != %D", cf, c, faceSizeH, faceSizeAllH);
67099836e0eSStefano Zampini       ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
67199836e0eSStefano Zampini       if (missing) {
67299836e0eSStefano Zampini         ierr = DMPlexSetCone(idm, face, cellFace);CHKERRQ(ierr);
67399836e0eSStefano Zampini         ierr = PetscHashIJKLIterSet(faceTable, iter, face);CHKERRQ(ierr);
67499836e0eSStefano Zampini         ierr = DMPlexInsertCone(idm, c, cf, face++);CHKERRQ(ierr);
67599836e0eSStefano Zampini       } else {
676e9fa77a1SMatthew G. Knepley         PetscInt        fv[4] = {0, 1, 2, 3};
67799836e0eSStefano Zampini         const PetscInt *cone;
67899836e0eSStefano Zampini         PetscInt        coneSize, ornt, i, j, f;
679a74221b0SStefano Zampini         PetscBool       q2h = PETSC_FALSE;
68099836e0eSStefano Zampini 
68199836e0eSStefano Zampini         ierr = PetscHashIJKLIterGet(faceTable, iter, &f);CHKERRQ(ierr);
68299836e0eSStefano Zampini         ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
68399836e0eSStefano Zampini         /* Orient face: Do not allow reverse orientation at the first vertex */
68499836e0eSStefano Zampini         ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
68599836e0eSStefano Zampini         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
68699836e0eSStefano Zampini         if (coneSize != faceSizeH) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of face vertices %D for face %D should be %D", coneSize, f, faceSizeH);
687e9fa77a1SMatthew G. Knepley         /* Hybrid faces are stored as tensor products of edges, so to compare them to normal faces, we have to flip */
688a74221b0SStefano Zampini         if (faceSize == 4 && c >= pMax && faceSizeAll != faceSizeAllT && f < pEnd[faceDepth] - faceH) {q2h = PETSC_TRUE; fv[2] = 3; fv[3] = 2;}
68999836e0eSStefano Zampini         /* - First find the initial vertex */
690e9fa77a1SMatthew G. Knepley         for (i = 0; i < faceSizeH; ++i) if (cellFace[fv[0]] == cone[i]) break;
691a74221b0SStefano Zampini         if (q2h) { /* Matt's case: hybrid faces meeting with non-hybrid faces. This is a case that is not (and will not be) supported in general by the refinements */
69299836e0eSStefano Zampini           /* - Try forward comparison */
693e9fa77a1SMatthew G. Knepley           for (j = 0; j < faceSizeH; ++j) if (cellFace[fv[j]] != cone[(i+j)%faceSizeH]) break;
69499836e0eSStefano Zampini           if (j == faceSizeH) {
69599836e0eSStefano Zampini             if ((faceSizeH == 2) && (i == 1)) ornt = -2;
69699836e0eSStefano Zampini             else                              ornt = i;
69799836e0eSStefano Zampini           } else {
69899836e0eSStefano Zampini             /* - Try backward comparison */
699e9fa77a1SMatthew G. Knepley             for (j = 0; j < faceSizeH; ++j) if (cellFace[fv[j]] != cone[(i+faceSizeH-j)%faceSizeH]) break;
70099836e0eSStefano Zampini             if (j == faceSizeH) {
70199836e0eSStefano Zampini               if (i == 0) ornt = -faceSizeH;
70299836e0eSStefano Zampini               else        ornt = -i;
703e9fa77a1SMatthew G. Knepley             } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not determine orientation of face %D in cell %D", f, c);
70499836e0eSStefano Zampini           }
705a74221b0SStefano Zampini         } else {
706a74221b0SStefano Zampini           /* when matching hybrid faces in 3D, only few cases are possible.
707a74221b0SStefano Zampini              Face traversal however can no longer follow the usual convention, this seems a serious issue to me */
708a74221b0SStefano Zampini           PetscInt tquad_map[4][4] = { {PETSC_MIN_INT,            0,PETSC_MIN_INT,PETSC_MIN_INT},
709a74221b0SStefano Zampini                                        {           -1,PETSC_MIN_INT,PETSC_MIN_INT,PETSC_MIN_INT},
710a74221b0SStefano Zampini                                        {PETSC_MIN_INT,PETSC_MIN_INT,PETSC_MIN_INT,            1},
711a74221b0SStefano Zampini                                        {PETSC_MIN_INT,PETSC_MIN_INT,           -2,PETSC_MIN_INT} };
712a74221b0SStefano Zampini           PetscInt i2;
713a74221b0SStefano Zampini 
714a74221b0SStefano Zampini           /* find the second vertex */
715a74221b0SStefano Zampini           for (i2 = 0; i2 < faceSizeH; ++i2) if (cellFace[fv[1]] == cone[i2]) break;
716a74221b0SStefano Zampini           switch (faceSizeH) {
717a74221b0SStefano Zampini           case 2:
718a74221b0SStefano Zampini             ornt = i ? -2 : 0;
719a74221b0SStefano Zampini             break;
720a74221b0SStefano Zampini           case 4:
721a74221b0SStefano Zampini             ornt = tquad_map[i][i2];
722a74221b0SStefano Zampini             break;
723a74221b0SStefano Zampini           default:
724a74221b0SStefano Zampini             SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unhandled face size %D for face %D in cell %D", faceSizeH, f, c);
725a74221b0SStefano Zampini 
726a74221b0SStefano Zampini           }
727a74221b0SStefano Zampini         }
72899836e0eSStefano Zampini         ierr = DMPlexInsertConeOrientation(idm, c, cf, ornt);CHKERRQ(ierr);
72999836e0eSStefano Zampini       }
73099836e0eSStefano Zampini     }
73199836e0eSStefano Zampini     ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
73299836e0eSStefano Zampini   }
73399836e0eSStefano Zampini   if (face != pEnd[faceDepth]) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-pStart[faceDepth], pEnd[faceDepth]-pStart[faceDepth]);
734c907b753SJed Brown   ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr);
7359a5b13a2SMatthew G Knepley   ierr = PetscHashIJKLDestroy(&faceTable);CHKERRQ(ierr);
7366551a8c7SMatthew G. Knepley   ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr);
73799836e0eSStefano Zampini   ierr = DMPlexSetHybridBounds(idm, cMax, fMax, eMax, vMax);CHKERRQ(ierr);
7389a5b13a2SMatthew G Knepley   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
7399a5b13a2SMatthew G Knepley   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
7409f074e33SMatthew G Knepley   PetscFunctionReturn(0);
7419f074e33SMatthew G Knepley }
7429f074e33SMatthew G Knepley 
743f80536cbSVaclav Hapla static PetscErrorCode SortRmineRremoteByRemote_Private(PetscSF sf, PetscInt *rmine1[], PetscInt *rremote1[])
744f80536cbSVaclav Hapla {
745f80536cbSVaclav Hapla   PetscInt            nleaves;
746f80536cbSVaclav Hapla   PetscInt            nranks;
747a0d42dbcSVaclav Hapla   const PetscMPIInt  *ranks=NULL;
748a0d42dbcSVaclav Hapla   const PetscInt     *roffset=NULL, *rmine=NULL, *rremote=NULL;
749f80536cbSVaclav Hapla   PetscInt            n, o, r;
750f80536cbSVaclav Hapla   PetscErrorCode      ierr;
751f80536cbSVaclav Hapla 
752f80536cbSVaclav Hapla   PetscFunctionBegin;
753dec1416fSJunchao Zhang   ierr = PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, &rmine, &rremote);CHKERRQ(ierr);
754f80536cbSVaclav Hapla   nleaves = roffset[nranks];
755f80536cbSVaclav Hapla   ierr = PetscMalloc2(nleaves, rmine1, nleaves, rremote1);CHKERRQ(ierr);
756f80536cbSVaclav Hapla   for (r=0; r<nranks; r++) {
757f80536cbSVaclav Hapla     /* simultaneously sort rank-wise portions of rmine & rremote by values in rremote
758f80536cbSVaclav Hapla        - to unify order with the other side */
759f80536cbSVaclav Hapla     o = roffset[r];
760f80536cbSVaclav Hapla     n = roffset[r+1] - o;
761580bdb30SBarry Smith     ierr = PetscArraycpy(&(*rmine1)[o], &rmine[o], n);CHKERRQ(ierr);
762580bdb30SBarry Smith     ierr = PetscArraycpy(&(*rremote1)[o], &rremote[o], n);CHKERRQ(ierr);
763f80536cbSVaclav Hapla     ierr = PetscSortIntWithArray(n, &(*rremote1)[o], &(*rmine1)[o]);CHKERRQ(ierr);
764f80536cbSVaclav Hapla   }
765f80536cbSVaclav Hapla   PetscFunctionReturn(0);
766f80536cbSVaclav Hapla }
767f80536cbSVaclav Hapla 
76827d0e99aSVaclav Hapla PetscErrorCode DMPlexOrientInterface_Internal(DM dm)
7692e745bdaSMatthew G. Knepley {
77027d0e99aSVaclav Hapla   /* Here we only compare first 2 points of the cone. Full cone size would lead to stronger self-checking. */
77127d0e99aSVaclav Hapla   PetscInt          masterCone[2];
772cae7fe92SVaclav Hapla   PetscInt          (*roots)[2], (*leaves)[2];
7738a650c75SVaclav Hapla   PetscMPIInt       (*rootsRanks)[2], (*leavesRanks)[2];
77427d0e99aSVaclav Hapla 
77527d0e99aSVaclav Hapla   PetscSF           sf=NULL;
776a0d42dbcSVaclav Hapla   const PetscInt    *locals=NULL;
777a0d42dbcSVaclav Hapla   const PetscSFNode *remotes=NULL;
7788a650c75SVaclav Hapla   PetscInt           nroots, nleaves, p, c;
779f80536cbSVaclav Hapla   PetscInt           nranks, n, o, r;
780a0d42dbcSVaclav Hapla   const PetscMPIInt *ranks=NULL;
781a0d42dbcSVaclav Hapla   const PetscInt    *roffset=NULL;
782a0d42dbcSVaclav Hapla   PetscInt          *rmine1=NULL, *rremote1=NULL; /* rmine and rremote copies simultaneously sorted by rank and rremote */
783a0d42dbcSVaclav Hapla   const PetscInt    *cone=NULL;
784adeface4SVaclav Hapla   PetscInt           coneSize, ind0;
7852e745bdaSMatthew G. Knepley   MPI_Comm           comm;
78627d0e99aSVaclav Hapla   PetscMPIInt        rank,size;
7872e745bdaSMatthew G. Knepley   PetscInt           debug = 0;
7882e745bdaSMatthew G. Knepley   PetscErrorCode     ierr;
7892e745bdaSMatthew G. Knepley 
7902e745bdaSMatthew G. Knepley   PetscFunctionBegin;
791df6a9fadSVaclav Hapla   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7922e745bdaSMatthew G. Knepley   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, &locals, &remotes);CHKERRQ(ierr);
7933ede9f65SMatthew G. Knepley   if (nroots < 0) PetscFunctionReturn(0);
794f80536cbSVaclav Hapla   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
795dec1416fSJunchao Zhang   ierr = PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, NULL, NULL);CHKERRQ(ierr);
796dc21a0bfSVaclav Hapla   ierr = DMViewFromOptions(dm, NULL, "-before_fix_dm_view");CHKERRQ(ierr);
79727d0e99aSVaclav Hapla #if defined(PETSC_USE_DEBUG)
798dc21a0bfSVaclav Hapla   ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);
799dc21a0bfSVaclav Hapla #endif
800f80536cbSVaclav Hapla   ierr = SortRmineRremoteByRemote_Private(sf, &rmine1, &rremote1);CHKERRQ(ierr);
8018a650c75SVaclav Hapla   ierr = PetscMalloc4(nroots, &roots, nroots, &leaves, nroots, &rootsRanks, nroots, &leavesRanks);CHKERRQ(ierr);
8022e745bdaSMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
8032e745bdaSMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
80427d0e99aSVaclav Hapla   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
8059e24d8a0SVaclav Hapla   for (p = 0; p < nroots; ++p) {
8069e24d8a0SVaclav Hapla     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
8079e24d8a0SVaclav Hapla     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
80827d0e99aSVaclav Hapla     if (coneSize < 2) {
80927d0e99aSVaclav Hapla       for (c = 0; c < 2; c++) {
81027d0e99aSVaclav Hapla         roots[p][c] = -1;
81127d0e99aSVaclav Hapla         rootsRanks[p][c] = -1;
81227d0e99aSVaclav Hapla       }
81327d0e99aSVaclav Hapla       continue;
81427d0e99aSVaclav Hapla     }
8152e745bdaSMatthew G. Knepley     /* Translate all points to root numbering */
8168a650c75SVaclav Hapla     for (c = 0; c < 2; c++) {
8178a650c75SVaclav Hapla       ierr = PetscFindInt(cone[c], nleaves, locals, &ind0);CHKERRQ(ierr);
8188a650c75SVaclav Hapla       if (ind0 < 0) {
8198a650c75SVaclav Hapla         roots[p][c] = cone[c];
8208a650c75SVaclav Hapla         rootsRanks[p][c] = rank;
821c8148b97SVaclav Hapla       } else {
8228a650c75SVaclav Hapla         roots[p][c] = remotes[ind0].index;
8238a650c75SVaclav Hapla         rootsRanks[p][c] = remotes[ind0].rank;
8248a650c75SVaclav Hapla       }
8252e745bdaSMatthew G. Knepley     }
8262e745bdaSMatthew G. Knepley   }
8279e24d8a0SVaclav Hapla   for (p = 0; p < nroots; ++p) {
8288ccb905dSVaclav Hapla     for (c = 0; c < 2; c++) {
8298ccb905dSVaclav Hapla       leaves[p][c] = -2;
8308ccb905dSVaclav Hapla       leavesRanks[p][c] = -2;
8318ccb905dSVaclav Hapla     }
832c8148b97SVaclav Hapla   }
8332e745bdaSMatthew G. Knepley   ierr = PetscSFBcastBegin(sf, MPIU_2INT, roots, leaves);CHKERRQ(ierr);
8348a650c75SVaclav Hapla   ierr = PetscSFBcastBegin(sf, MPI_2INT, rootsRanks, leavesRanks);CHKERRQ(ierr);
8352e745bdaSMatthew G. Knepley   ierr = PetscSFBcastEnd(sf, MPIU_2INT, roots, leaves);CHKERRQ(ierr);
8368a650c75SVaclav Hapla   ierr = PetscSFBcastEnd(sf, MPI_2INT, rootsRanks, leavesRanks);CHKERRQ(ierr);
837c8148b97SVaclav Hapla   if (debug) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
83827d0e99aSVaclav Hapla   if (debug && rank == 0) {ierr = PetscSynchronizedPrintf(comm, "Referenced roots\n");CHKERRQ(ierr);}
8399e24d8a0SVaclav Hapla   for (p = 0; p < nroots; ++p) {
8409e24d8a0SVaclav Hapla     if (leaves[p][0] < 0) continue;
8419e24d8a0SVaclav Hapla     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
8429e24d8a0SVaclav Hapla     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
84327d0e99aSVaclav Hapla     if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]  %4D: cone=[%4D %4D] roots=[(%d,%4D) (%d,%4D)] leaves=[(%d,%4D) (%d,%4D)]", rank, p, cone[0], cone[1], rootsRanks[p][0], roots[p][0], rootsRanks[p][1], roots[p][1], leavesRanks[p][0], leaves[p][0], leavesRanks[p][1], leaves[p][1]);CHKERRQ(ierr);}
84482f5c0aeSVaclav Hapla     if ((leaves[p][0] != roots[p][0]) || (leaves[p][1] != roots[p][1]) || (leavesRanks[p][0] != rootsRanks[p][0]) || (leavesRanks[p][1] != rootsRanks[p][1])) {
84527d0e99aSVaclav Hapla       /* Translate these two leaves to my cone points; masterCone means desired order p's cone points */
846f80536cbSVaclav Hapla       for (c = 0; c < 2; c++) {
84727d0e99aSVaclav Hapla         if (leavesRanks[p][c] == rank) {
84827d0e99aSVaclav Hapla           /* A local leave is just taken as it is */
84927d0e99aSVaclav Hapla           masterCone[c] = leaves[p][c];
85027d0e99aSVaclav Hapla           continue;
85127d0e99aSVaclav Hapla         }
852f80536cbSVaclav Hapla         /* Find index of rank leavesRanks[p][c] among remote ranks */
853f80536cbSVaclav Hapla         /* No need for PetscMPIIntCast because these integers were originally cast from PetscMPIInt. */
854f80536cbSVaclav Hapla         ierr = PetscFindMPIInt((PetscMPIInt)leavesRanks[p][c], nranks, ranks, &r);CHKERRQ(ierr);
85527d0e99aSVaclav Hapla         if (PetscUnlikely(r < 0)) SETERRQ7(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D cone[%D]=%D root (%d,%D) leave (%d,%D): leave rank not found among remote ranks",p,c,cone[c],rootsRanks[p][c],roots[p][c],leavesRanks[p][c],leaves[p][c]);
85627d0e99aSVaclav Hapla         if (PetscUnlikely(ranks[r] < 0 || ranks[r] >= size)) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_PLIB, "p=%D c=%D commsize=%d: ranks[%D] = %d makes no sense",p,c,size,r,ranks[r]);
857f80536cbSVaclav Hapla         /* Find point leaves[p][c] among remote points aimed at rank leavesRanks[p][c] */
858f80536cbSVaclav Hapla         o = roffset[r];
859f80536cbSVaclav Hapla         n = roffset[r+1] - o;
860f80536cbSVaclav Hapla         ierr = PetscFindInt(leaves[p][c], n, &rremote1[o], &ind0);CHKERRQ(ierr);
86127d0e99aSVaclav Hapla         if (PetscUnlikely(ind0 < 0)) SETERRQ7(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D cone[%D]=%D root (%d,%D) leave (%d,%D): corresponding remote point not found - it seems there is missing connection in point SF!",p,c,cone[c],rootsRanks[p][c],roots[p][c],leavesRanks[p][c],leaves[p][c]);
862f80536cbSVaclav Hapla         /* Get the corresponding local point */
863f80536cbSVaclav Hapla         masterCone[c] = rmine1[o+ind0];CHKERRQ(ierr);
864f80536cbSVaclav Hapla       }
86527d0e99aSVaclav Hapla       if (debug) {ierr = PetscSynchronizedPrintf(comm, " masterCone=[%4D %4D]\n", masterCone[0], masterCone[1]);CHKERRQ(ierr);}
86627d0e99aSVaclav Hapla       /* Set the desired order of p's cone points and fix orientations accordingly */
867f80536cbSVaclav Hapla       /* Vaclav's note: Here we only compare first 2 points of the cone. Full cone size would lead to stronger self-checking. */
868f80536cbSVaclav Hapla       ierr = DMPlexOrientCell(dm, p, 2, masterCone);CHKERRQ(ierr);
86927d0e99aSVaclav Hapla     } else if (debug) {ierr = PetscSynchronizedPrintf(comm, " ==\n");CHKERRQ(ierr);}
87023aaf07bSVaclav Hapla   }
87127d0e99aSVaclav Hapla   if (debug) {
87227d0e99aSVaclav Hapla     ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
87327d0e99aSVaclav Hapla     ierr = MPI_Barrier(comm);CHKERRQ(ierr);
8742e745bdaSMatthew G. Knepley   }
875adeface4SVaclav Hapla   ierr = DMViewFromOptions(dm, NULL, "-after_fix_dm_view");CHKERRQ(ierr);
8768a650c75SVaclav Hapla   ierr = PetscFree4(roots, leaves, rootsRanks, leavesRanks);CHKERRQ(ierr);
8777c7bb832SVaclav Hapla   ierr = PetscFree2(rmine1, rremote1);CHKERRQ(ierr);
8782e745bdaSMatthew G. Knepley   PetscFunctionReturn(0);
8792e745bdaSMatthew G. Knepley }
8802e745bdaSMatthew G. Knepley 
8812e72742cSMatthew G. Knepley static PetscErrorCode IntArrayViewFromOptions(MPI_Comm comm, const char opt[], const char name[], const char idxname[], const char valname[], PetscInt n, const PetscInt a[])
8827bffde78SMichael Lange {
8832e72742cSMatthew G. Knepley   PetscInt       idx;
8842e72742cSMatthew G. Knepley   PetscMPIInt    rank;
8852e72742cSMatthew G. Knepley   PetscBool      flg;
8867bffde78SMichael Lange   PetscErrorCode ierr;
8877bffde78SMichael Lange 
8887bffde78SMichael Lange   PetscFunctionBegin;
8892e72742cSMatthew G. Knepley   ierr = PetscOptionsHasName(NULL, NULL, opt, &flg);CHKERRQ(ierr);
8902e72742cSMatthew G. Knepley   if (!flg) PetscFunctionReturn(0);
8912e72742cSMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
8922e72742cSMatthew G. Knepley   ierr = PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name);CHKERRQ(ierr);
8932e72742cSMatthew G. Knepley   for (idx = 0; idx < n; ++idx) {ierr = PetscSynchronizedPrintf(comm, "[%d]%s %D %s %D\n", rank, idxname, idx, valname, a[idx]);CHKERRQ(ierr);}
8942e72742cSMatthew G. Knepley   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
8952e72742cSMatthew G. Knepley   PetscFunctionReturn(0);
8962e72742cSMatthew G. Knepley }
8972e72742cSMatthew G. Knepley 
8982e72742cSMatthew G. Knepley static PetscErrorCode SFNodeArrayViewFromOptions(MPI_Comm comm, const char opt[], const char name[], const char idxname[], PetscInt n, const PetscSFNode a[])
8992e72742cSMatthew G. Knepley {
9002e72742cSMatthew G. Knepley   PetscInt       idx;
9012e72742cSMatthew G. Knepley   PetscMPIInt    rank;
9022e72742cSMatthew G. Knepley   PetscBool      flg;
9032e72742cSMatthew G. Knepley   PetscErrorCode ierr;
9042e72742cSMatthew G. Knepley 
9052e72742cSMatthew G. Knepley   PetscFunctionBegin;
9062e72742cSMatthew G. Knepley   ierr = PetscOptionsHasName(NULL, NULL, opt, &flg);CHKERRQ(ierr);
9072e72742cSMatthew G. Knepley   if (!flg) PetscFunctionReturn(0);
9082e72742cSMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
9092e72742cSMatthew G. Knepley   ierr = PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name);CHKERRQ(ierr);
9102e72742cSMatthew G. Knepley   if (idxname) {
9112e72742cSMatthew G. Knepley     for (idx = 0; idx < n; ++idx) {ierr = PetscSynchronizedPrintf(comm, "[%d]%s %D rank %D index %D\n", rank, idxname, idx, a[idx].rank, a[idx].index);CHKERRQ(ierr);}
9122e72742cSMatthew G. Knepley   } else {
9132e72742cSMatthew G. Knepley     for (idx = 0; idx < n; ++idx) {ierr = PetscSynchronizedPrintf(comm, "[%d]rank %D index %D\n", rank, a[idx].rank, a[idx].index);CHKERRQ(ierr);}
9142e72742cSMatthew G. Knepley   }
9152e72742cSMatthew G. Knepley   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
9162e72742cSMatthew G. Knepley   PetscFunctionReturn(0);
9172e72742cSMatthew G. Knepley }
9182e72742cSMatthew G. Knepley 
919*3be36e83SMatthew G. Knepley static PetscErrorCode DMPlexMapToLocalPoint(DM dm, PetscHMapIJ remotehash, PetscSFNode remotePoint, PetscInt *localPoint)
9202e72742cSMatthew G. Knepley {
921*3be36e83SMatthew G. Knepley   PetscSF         sf;
922*3be36e83SMatthew G. Knepley   const PetscInt *locals;
923*3be36e83SMatthew G. Knepley   PetscMPIInt     rank;
9242e72742cSMatthew G. Knepley   PetscErrorCode  ierr;
9252e72742cSMatthew G. Knepley 
9262e72742cSMatthew G. Knepley   PetscFunctionBegin;
927*3be36e83SMatthew G. Knepley   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
928*3be36e83SMatthew G. Knepley   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
929*3be36e83SMatthew G. Knepley   ierr = PetscSFGetGraph(sf, NULL, NULL, &locals, NULL);CHKERRQ(ierr);
9302e72742cSMatthew G. Knepley   if (remotePoint.rank == rank) {
9312e72742cSMatthew G. Knepley     *localPoint = remotePoint.index;
9322e72742cSMatthew G. Knepley   } else {
9332e72742cSMatthew G. Knepley     PetscHashIJKey key;
934*3be36e83SMatthew G. Knepley     PetscInt       l;
9352e72742cSMatthew G. Knepley 
9362e72742cSMatthew G. Knepley     key.i = remotePoint.index;
9372e72742cSMatthew G. Knepley     key.j = remotePoint.rank;
938*3be36e83SMatthew G. Knepley     ierr = PetscHMapIJGet(remotehash, key, &l);CHKERRQ(ierr);
939*3be36e83SMatthew G. Knepley     if (l >= 0) {
940*3be36e83SMatthew G. Knepley       *localPoint = locals[l];
9412e72742cSMatthew G. Knepley     } else PetscFunctionReturn(1);
9422e72742cSMatthew G. Knepley   }
9432e72742cSMatthew G. Knepley   PetscFunctionReturn(0);
9442e72742cSMatthew G. Knepley }
9452e72742cSMatthew G. Knepley 
946*3be36e83SMatthew G. Knepley static PetscErrorCode DMPlexMapToGlobalPoint(DM dm, PetscInt localPoint, PetscSFNode *remotePoint)
947*3be36e83SMatthew G. Knepley {
948*3be36e83SMatthew G. Knepley   PetscSF            sf;
949*3be36e83SMatthew G. Knepley   const PetscInt    *locals, *rootdegree;
950*3be36e83SMatthew G. Knepley   const PetscSFNode *remotes;
951*3be36e83SMatthew G. Knepley   PetscInt           Nl, l;
952*3be36e83SMatthew G. Knepley   PetscMPIInt        rank;
953*3be36e83SMatthew G. Knepley   PetscErrorCode     ierr;
954*3be36e83SMatthew G. Knepley 
955*3be36e83SMatthew G. Knepley   PetscFunctionBegin;
956*3be36e83SMatthew G. Knepley   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
957*3be36e83SMatthew G. Knepley   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
958*3be36e83SMatthew G. Knepley   ierr = PetscSFGetGraph(sf, NULL, &Nl, &locals, &remotes);CHKERRQ(ierr);
959*3be36e83SMatthew G. Knepley   if (Nl < 0) goto owned;
960*3be36e83SMatthew G. Knepley   ierr = PetscSFComputeDegreeBegin(sf, &rootdegree);CHKERRQ(ierr);
961*3be36e83SMatthew G. Knepley   ierr = PetscSFComputeDegreeEnd(sf, &rootdegree);CHKERRQ(ierr);
962*3be36e83SMatthew G. Knepley   if (rootdegree[localPoint]) goto owned;
963*3be36e83SMatthew G. Knepley   ierr = PetscFindInt(localPoint, Nl, locals, &l);CHKERRQ(ierr);
964*3be36e83SMatthew G. Knepley   if (l < 0) PetscFunctionReturn(1);
965*3be36e83SMatthew G. Knepley   *remotePoint = remotes[l];
966*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
967*3be36e83SMatthew G. Knepley   owned:
968*3be36e83SMatthew G. Knepley   remotePoint->rank  = rank;
969*3be36e83SMatthew G. Knepley   remotePoint->index = localPoint;
970*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
971*3be36e83SMatthew G. Knepley }
972*3be36e83SMatthew G. Knepley 
973*3be36e83SMatthew G. Knepley 
974*3be36e83SMatthew G. Knepley static PetscErrorCode DMPlexPointIsShared(DM dm, PetscInt p, PetscBool *isShared)
975*3be36e83SMatthew G. Knepley {
976*3be36e83SMatthew G. Knepley   PetscSF         sf;
977*3be36e83SMatthew G. Knepley   const PetscInt *locals, *rootdegree;
978*3be36e83SMatthew G. Knepley   PetscInt        Nl, idx;
979*3be36e83SMatthew G. Knepley   PetscErrorCode  ierr;
980*3be36e83SMatthew G. Knepley 
981*3be36e83SMatthew G. Knepley   PetscFunctionBegin;
982*3be36e83SMatthew G. Knepley   *isShared = PETSC_FALSE;
983*3be36e83SMatthew G. Knepley   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
984*3be36e83SMatthew G. Knepley   ierr = PetscSFGetGraph(sf, NULL, &Nl, &locals, NULL);CHKERRQ(ierr);
985*3be36e83SMatthew G. Knepley   if (Nl < 0) PetscFunctionReturn(0);
986*3be36e83SMatthew G. Knepley   ierr = PetscFindInt(p, Nl, locals, &idx);CHKERRQ(ierr);
987*3be36e83SMatthew G. Knepley   if (idx >= 0) {*isShared = PETSC_TRUE; PetscFunctionReturn(0);}
988*3be36e83SMatthew G. Knepley   ierr = PetscSFComputeDegreeBegin(sf, &rootdegree);CHKERRQ(ierr);
989*3be36e83SMatthew G. Knepley   ierr = PetscSFComputeDegreeEnd(sf, &rootdegree);CHKERRQ(ierr);
990*3be36e83SMatthew G. Knepley   if (rootdegree[p] > 0) *isShared = PETSC_TRUE;
991*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
992*3be36e83SMatthew G. Knepley }
993*3be36e83SMatthew G. Knepley 
994*3be36e83SMatthew G. Knepley static PetscErrorCode DMPlexConeIsShared(DM dm, PetscInt p, PetscBool *isShared)
995*3be36e83SMatthew G. Knepley {
996*3be36e83SMatthew G. Knepley   const PetscInt *cone;
997*3be36e83SMatthew G. Knepley   PetscInt        coneSize, c;
998*3be36e83SMatthew G. Knepley   PetscBool       cShared = PETSC_TRUE;
999*3be36e83SMatthew G. Knepley   PetscErrorCode  ierr;
1000*3be36e83SMatthew G. Knepley 
1001*3be36e83SMatthew G. Knepley   PetscFunctionBegin;
1002*3be36e83SMatthew G. Knepley   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1003*3be36e83SMatthew G. Knepley   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1004*3be36e83SMatthew G. Knepley   for (c = 0; c < coneSize; ++c) {
1005*3be36e83SMatthew G. Knepley     PetscBool pointShared;
1006*3be36e83SMatthew G. Knepley 
1007*3be36e83SMatthew G. Knepley     ierr = DMPlexPointIsShared(dm, cone[c], &pointShared);CHKERRQ(ierr);
1008*3be36e83SMatthew G. Knepley     cShared = (PetscBool) (cShared && pointShared);
1009*3be36e83SMatthew G. Knepley   }
1010*3be36e83SMatthew G. Knepley   *isShared = coneSize ? cShared : PETSC_FALSE;
1011*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
1012*3be36e83SMatthew G. Knepley }
1013*3be36e83SMatthew G. Knepley 
1014*3be36e83SMatthew G. Knepley static PetscErrorCode DMPlexGetConeMinimum(DM dm, PetscInt p, PetscSFNode *cpmin)
1015*3be36e83SMatthew G. Knepley {
1016*3be36e83SMatthew G. Knepley   const PetscInt *cone;
1017*3be36e83SMatthew G. Knepley   PetscInt        coneSize, c;
1018*3be36e83SMatthew G. Knepley   PetscSFNode     cmin = {PETSC_MAX_INT, PETSC_MAX_INT}, missing = {-1, -1};
1019*3be36e83SMatthew G. Knepley   PetscErrorCode  ierr;
1020*3be36e83SMatthew G. Knepley 
1021*3be36e83SMatthew G. Knepley   PetscFunctionBegin;
1022*3be36e83SMatthew G. Knepley   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1023*3be36e83SMatthew G. Knepley   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1024*3be36e83SMatthew G. Knepley   for (c = 0; c < coneSize; ++c) {
1025*3be36e83SMatthew G. Knepley     PetscSFNode rcp;
1026*3be36e83SMatthew G. Knepley 
1027*3be36e83SMatthew G. Knepley     ierr = DMPlexMapToGlobalPoint(dm, cone[c], &rcp);
1028*3be36e83SMatthew G. Knepley     if (ierr) {
1029*3be36e83SMatthew G. Knepley       cmin = missing;
1030*3be36e83SMatthew G. Knepley     } else {
1031*3be36e83SMatthew G. Knepley       cmin = (rcp.rank < cmin.rank) || (rcp.rank == cmin.rank && rcp.index < cmin.index) ? rcp : cmin;
1032*3be36e83SMatthew G. Knepley     }
1033*3be36e83SMatthew G. Knepley   }
1034*3be36e83SMatthew G. Knepley   *cpmin = coneSize ? cmin : missing;
1035*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
1036*3be36e83SMatthew G. Knepley }
1037*3be36e83SMatthew G. Knepley 
1038*3be36e83SMatthew G. Knepley static PetscErrorCode DMPlexCheckSharedFaces(DM dm)
1039*3be36e83SMatthew G. Knepley {
1040*3be36e83SMatthew G. Knepley   PetscInt       fStart, fEnd, f;
1041*3be36e83SMatthew G. Knepley   PetscErrorCode ierr;
1042*3be36e83SMatthew G. Knepley 
1043*3be36e83SMatthew G. Knepley   PetscFunctionBegin;
1044*3be36e83SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1045*3be36e83SMatthew G. Knepley   for (f = fStart; f < fEnd; ++f) {
1046*3be36e83SMatthew G. Knepley     const PetscInt *cone;
1047*3be36e83SMatthew G. Knepley     PetscInt        coneSize, c;
1048*3be36e83SMatthew G. Knepley     PetscBool       faceShared, shouldShare = PETSC_TRUE;
1049*3be36e83SMatthew G. Knepley 
1050*3be36e83SMatthew G. Knepley     ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
1051*3be36e83SMatthew G. Knepley     ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1052*3be36e83SMatthew G. Knepley     for (c = 0; c < coneSize; ++c) {
1053*3be36e83SMatthew G. Knepley       PetscBool pointShared;
1054*3be36e83SMatthew G. Knepley 
1055*3be36e83SMatthew G. Knepley       ierr = DMPlexPointIsShared(dm, cone[c], &pointShared);CHKERRQ(ierr);
1056*3be36e83SMatthew G. Knepley       shouldShare = (PetscBool) (shouldShare && pointShared);
1057*3be36e83SMatthew G. Knepley     }
1058*3be36e83SMatthew G. Knepley     ierr = DMPlexPointIsShared(dm, f, &faceShared);CHKERRQ(ierr);
1059*3be36e83SMatthew G. Knepley     if (faceShared && !shouldShare) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Face %D is shared, but its cone is not completely shared", f);
1060*3be36e83SMatthew G. Knepley     if (!faceShared && shouldShare) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Face %D is not shared, but its cone is completely shared", f);
1061*3be36e83SMatthew G. Knepley   }
1062*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
1063*3be36e83SMatthew G. Knepley }
1064*3be36e83SMatthew G. Knepley 
1065*3be36e83SMatthew G. Knepley /*
1066*3be36e83SMatthew G. Knepley   Each shared face has an entry in the candidates array:
1067*3be36e83SMatthew G. Knepley     (-1, coneSize-1), {(global cone point)}
1068*3be36e83SMatthew G. Knepley   where the set is missing the point p which we use as the key for the face
1069*3be36e83SMatthew G. Knepley */
1070*3be36e83SMatthew G. Knepley static PetscErrorCode DMPlexAddSharedFace_Private(DM dm, PetscSection candidateSection, PetscSFNode candidates[], PetscHMapIJ faceHash, PetscInt p, PetscBool debug)
1071*3be36e83SMatthew G. Knepley {
1072*3be36e83SMatthew G. Knepley   MPI_Comm        comm;
1073*3be36e83SMatthew G. Knepley   const PetscInt *support;
1074*3be36e83SMatthew G. Knepley   PetscInt        supportSize, s, off = 0, idx = 0;
1075*3be36e83SMatthew G. Knepley   PetscMPIInt     rank;
1076*3be36e83SMatthew G. Knepley   PetscErrorCode  ierr;
1077*3be36e83SMatthew G. Knepley 
1078*3be36e83SMatthew G. Knepley   PetscFunctionBegin;
1079*3be36e83SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1080*3be36e83SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1081*3be36e83SMatthew G. Knepley   ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1082*3be36e83SMatthew G. Knepley   ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
1083*3be36e83SMatthew G. Knepley   if (candidates) {ierr = PetscSectionGetOffset(candidateSection, p, &off);CHKERRQ(ierr);}
1084*3be36e83SMatthew G. Knepley   for (s = 0; s < supportSize; ++s) {
1085*3be36e83SMatthew G. Knepley     const PetscInt  face = support[s];
1086*3be36e83SMatthew G. Knepley     const PetscInt *cone;
1087*3be36e83SMatthew G. Knepley     PetscSFNode     cpmin={-1,-1}, rp={-1,-1};
1088*3be36e83SMatthew G. Knepley     PetscInt        coneSize, c, f;
1089*3be36e83SMatthew G. Knepley     PetscBool       isShared = PETSC_FALSE;
1090*3be36e83SMatthew G. Knepley     PetscHashIJKey  key;
1091*3be36e83SMatthew G. Knepley 
1092*3be36e83SMatthew G. Knepley     /* Only add point once */
1093*3be36e83SMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    Support face %D\n", rank, face);CHKERRQ(ierr);}
1094*3be36e83SMatthew G. Knepley     key.i = p;
1095*3be36e83SMatthew G. Knepley     key.j = face;
1096*3be36e83SMatthew G. Knepley     ierr = PetscHMapIJGet(faceHash, key, &f);CHKERRQ(ierr);
1097*3be36e83SMatthew G. Knepley     if (f >= 0) continue;
1098*3be36e83SMatthew G. Knepley     ierr = DMPlexConeIsShared(dm, face, &isShared);CHKERRQ(ierr);
1099*3be36e83SMatthew G. Knepley     ierr = DMPlexGetConeMinimum(dm, face, &cpmin);CHKERRQ(ierr);
1100*3be36e83SMatthew G. Knepley     ierr = DMPlexMapToGlobalPoint(dm, p, &rp);CHKERRQ(ierr);
1101*3be36e83SMatthew G. Knepley     if (debug) {
1102*3be36e83SMatthew G. Knepley       ierr = PetscSynchronizedPrintf(comm, "[%d]      Face point %D is shared: %d\n", rank, face, (int) isShared);CHKERRQ(ierr);
1103*3be36e83SMatthew G. Knepley       ierr = PetscSynchronizedPrintf(comm, "[%d]      Global point (%D, %D) Min Cone Point (%D, %D)\n", rank, rp.rank, rp.index, cpmin.rank, cpmin.index);CHKERRQ(ierr);
1104*3be36e83SMatthew G. Knepley     }
1105*3be36e83SMatthew G. Knepley     if (isShared && (rp.rank == cpmin.rank && rp.index == cpmin.index)) {
1106*3be36e83SMatthew G. Knepley       ierr = PetscHMapIJSet(faceHash, key, p);CHKERRQ(ierr);
1107*3be36e83SMatthew G. Knepley       if (candidates) {
1108*3be36e83SMatthew G. Knepley         if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    Adding shared face %D at idx %D\n[%d]     ", rank, face, idx, rank);CHKERRQ(ierr);}
1109*3be36e83SMatthew G. Knepley         ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
1110*3be36e83SMatthew G. Knepley         ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
1111*3be36e83SMatthew G. Knepley         candidates[off+idx].rank    = -1;
1112*3be36e83SMatthew G. Knepley         candidates[off+idx++].index = coneSize-1;
1113*3be36e83SMatthew G. Knepley         candidates[off+idx].rank    = rank;
1114*3be36e83SMatthew G. Knepley         candidates[off+idx++].index = face;
1115*3be36e83SMatthew G. Knepley         for (c = 0; c < coneSize; ++c) {
1116*3be36e83SMatthew G. Knepley           const PetscInt cp = cone[c];
1117*3be36e83SMatthew G. Knepley 
1118*3be36e83SMatthew G. Knepley           if (cp == p) continue;
1119*3be36e83SMatthew G. Knepley           ierr = DMPlexMapToGlobalPoint(dm, cp, &candidates[off+idx]);CHKERRQ(ierr);
1120*3be36e83SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(comm, " (%D,%D)", candidates[off+idx].rank, candidates[off+idx].index);CHKERRQ(ierr);}
1121*3be36e83SMatthew G. Knepley           ++idx;
1122*3be36e83SMatthew G. Knepley         }
1123*3be36e83SMatthew G. Knepley         if (debug) {ierr = PetscSynchronizedPrintf(comm, "\n");CHKERRQ(ierr);}
1124*3be36e83SMatthew G. Knepley       } else {
1125*3be36e83SMatthew G. Knepley         /* Add cone size to section */
1126*3be36e83SMatthew G. Knepley         if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    Scheduling shared face %D\n", rank, face);CHKERRQ(ierr);}
1127*3be36e83SMatthew G. Knepley         ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
1128*3be36e83SMatthew G. Knepley         ierr = PetscHMapIJSet(faceHash, key, p);CHKERRQ(ierr);
1129*3be36e83SMatthew G. Knepley         ierr = PetscSectionAddDof(candidateSection, p, coneSize+1);CHKERRQ(ierr);
1130*3be36e83SMatthew G. Knepley       }
1131*3be36e83SMatthew G. Knepley     }
1132*3be36e83SMatthew G. Knepley   }
1133*3be36e83SMatthew G. Knepley   PetscFunctionReturn(0);
1134*3be36e83SMatthew G. Knepley }
1135*3be36e83SMatthew G. Knepley 
11362e72742cSMatthew G. Knepley /*@
11372e72742cSMatthew G. Knepley   DMPlexInterpolatePointSF - Insert interpolated points in the overlap into the PointSF in parallel, following local interpolation
11382e72742cSMatthew G. Knepley 
1139d083f849SBarry Smith   Collective on dm
11402e72742cSMatthew G. Knepley 
11412e72742cSMatthew G. Knepley   Input Parameters:
11422e72742cSMatthew G. Knepley + dm      - The interpolated DM
11432e72742cSMatthew G. Knepley - pointSF - The initial SF without interpolated points
11442e72742cSMatthew G. Knepley 
11452e72742cSMatthew G. Knepley   Output Parameter:
11462e72742cSMatthew G. Knepley . pointSF - The SF including interpolated points
11472e72742cSMatthew G. Knepley 
1148f0cfc026SVaclav Hapla   Level: developer
11492e72742cSMatthew G. Knepley 
11502e72742cSMatthew G. Knepley    Note: All debugging for this process can be turned on with the options: -dm_interp_pre_view -petscsf_interp_pre_view -petscsection_interp_candidate_view -petscsection_interp_candidate_remote_view -petscsection_interp_claim_view -petscsf_interp_pre_view -dmplex_interp_debug
11512e72742cSMatthew G. Knepley 
11522e72742cSMatthew G. Knepley .seealso: DMPlexInterpolate(), DMPlexUninterpolate()
11532e72742cSMatthew G. Knepley @*/
1154e53487d3SMatthew G. Knepley PetscErrorCode DMPlexInterpolatePointSF(DM dm, PetscSF pointSF)
11552e72742cSMatthew G. Knepley {
1156*3be36e83SMatthew G. Knepley   MPI_Comm           comm;
1157*3be36e83SMatthew G. Knepley   PetscHMapIJ        remoteHash;
1158*3be36e83SMatthew G. Knepley   PetscHMapI         claimshash;
1159*3be36e83SMatthew G. Knepley   PetscSection       candidateSection, candidateRemoteSection, claimSection;
1160*3be36e83SMatthew G. Knepley   PetscSFNode       *candidates, *candidatesRemote, *claims;
11612e72742cSMatthew G. Knepley   const PetscInt    *localPoints, *rootdegree;
11622e72742cSMatthew G. Knepley   const PetscSFNode *remotePoints;
1163*3be36e83SMatthew G. Knepley   PetscInt           ov, Nr, r, Nl, l;
1164*3be36e83SMatthew G. Knepley   PetscInt           candidatesSize, candidatesRemoteSize, claimsSize;
1165*3be36e83SMatthew G. Knepley   PetscBool          flg, debug = PETSC_FALSE;
1166f0cfc026SVaclav Hapla   PetscMPIInt        rank;
11672e72742cSMatthew G. Knepley   PetscErrorCode     ierr;
11682e72742cSMatthew G. Knepley 
11692e72742cSMatthew G. Knepley   PetscFunctionBegin;
1170f0cfc026SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1171*3be36e83SMatthew G. Knepley   PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 3);
1172f0cfc026SVaclav Hapla   ierr = DMPlexIsDistributed(dm, &flg);CHKERRQ(ierr);
1173f0cfc026SVaclav Hapla   if (!flg) PetscFunctionReturn(0);
1174*3be36e83SMatthew G. Knepley   /* Set initial SF so that lower level queries work */
1175*3be36e83SMatthew G. Knepley   ierr = DMSetPointSF(dm, pointSF);CHKERRQ(ierr);
1176*3be36e83SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
1177*3be36e83SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1178*3be36e83SMatthew G. Knepley   ierr = DMPlexGetOverlap(dm, &ov);CHKERRQ(ierr);
1179*3be36e83SMatthew G. Knepley   if (ov) SETERRQ(comm, PETSC_ERR_SUP, "Interpolation of overlapped DMPlex not implemented yet");
1180*3be36e83SMatthew G. Knepley   ierr = PetscOptionsHasName(NULL, ((PetscObject) dm)->prefix, "-dmplex_interp_debug", &debug);CHKERRQ(ierr);
11812e72742cSMatthew G. Knepley   ierr = PetscObjectViewFromOptions((PetscObject) dm, NULL, "-dm_interp_pre_view");CHKERRQ(ierr);
11822e72742cSMatthew G. Knepley   ierr = PetscObjectViewFromOptions((PetscObject) pointSF, NULL, "-petscsf_interp_pre_view");CHKERRQ(ierr);
118325afeb17SMatthew G. Knepley   ierr = PetscLogEventBegin(DMPLEX_InterpolateSF,dm,0,0,0);CHKERRQ(ierr);
1184*3be36e83SMatthew G. Knepley   /* Step 0: Precalculations */
1185*3be36e83SMatthew G. Knepley   ierr = PetscSFGetGraph(pointSF, &Nr, &Nl, &localPoints, &remotePoints);CHKERRQ(ierr);
1186*3be36e83SMatthew G. Knepley   if (Nr < 0) SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but input PointSF has no graph set");
1187*3be36e83SMatthew G. Knepley   ierr = PetscHMapIJCreate(&remoteHash);CHKERRQ(ierr);
1188*3be36e83SMatthew G. Knepley   for (l = 0; l < Nl; ++l) {
1189*3be36e83SMatthew G. Knepley     PetscHashIJKey key;
11902e72742cSMatthew G. Knepley     key.i = remotePoints[l].index;
11912e72742cSMatthew G. Knepley     key.j = remotePoints[l].rank;
1192*3be36e83SMatthew G. Knepley     ierr = PetscHMapIJSet(remoteHash, key, l);CHKERRQ(ierr);
11937bffde78SMichael Lange   }
119466aa2a39SMatthew G. Knepley   /*   Compute root degree to identify shared points */
11952e72742cSMatthew G. Knepley   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
11962e72742cSMatthew G. Knepley   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
1197*3be36e83SMatthew G. Knepley   ierr = IntArrayViewFromOptions(comm, "-interp_root_degree_view", "Root degree", "point", "degree", Nr, rootdegree);CHKERRQ(ierr);
1198*3be36e83SMatthew G. Knepley   /*
1199*3be36e83SMatthew G. Knepley   1) Loop over each leaf point $p$ at depth $d$ in the SF
1200*3be36e83SMatthew G. Knepley   \item Get set $F(p)$ of faces $f$ in the support of $p$ for which
1201*3be36e83SMatthew G. Knepley   \begin{itemize}
1202*3be36e83SMatthew G. Knepley     \item all cone points of $f$ are shared
1203*3be36e83SMatthew G. Knepley     \item $p$ is the cone point with smallest canonical number
1204*3be36e83SMatthew G. Knepley   \end{itemize}
1205*3be36e83SMatthew G. Knepley   \item Send $F(p)$ and the cone of each face to the active root point $r(p)$
1206*3be36e83SMatthew G. Knepley   \item At the root, if at least two faces with a given cone are present, including a local face, mark the face as shared \label{alg:rootStep} and choose the root face
1207*3be36e83SMatthew G. Knepley   \item Send the root face from the root back to all leaf process
1208*3be36e83SMatthew G. Knepley   \item Leaf processes add the shared face to the SF
1209*3be36e83SMatthew G. Knepley   */
1210*3be36e83SMatthew G. Knepley   /* Step 1: Construct section+SFNode array
1211*3be36e83SMatthew G. Knepley        The section has entries for all shared faces for which we have a leaf point in the cone
1212*3be36e83SMatthew G. Knepley        The array holds candidate shared faces, each face is refered to by the leaf point */
1213*3be36e83SMatthew G. Knepley   ierr = PetscSectionCreate(comm, &candidateSection);CHKERRQ(ierr);
1214*3be36e83SMatthew G. Knepley   ierr = PetscSectionSetChart(candidateSection, 0, Nr);CHKERRQ(ierr);
12157bffde78SMichael Lange   {
1216*3be36e83SMatthew G. Knepley     PetscHMapIJ faceHash;
12172e72742cSMatthew G. Knepley 
1218*3be36e83SMatthew G. Knepley     ierr = PetscHMapIJCreate(&faceHash);CHKERRQ(ierr);
1219*3be36e83SMatthew G. Knepley     for (l = 0; l < Nl; ++l) {
1220*3be36e83SMatthew G. Knepley       const PetscInt p = localPoints[l];
12212e72742cSMatthew G. Knepley 
1222*3be36e83SMatthew G. Knepley       if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]  First pass leaf point %D\n", rank, p);CHKERRQ(ierr);}
1223*3be36e83SMatthew G. Knepley       ierr = DMPlexAddSharedFace_Private(dm, candidateSection, NULL, faceHash, p, debug);CHKERRQ(ierr);
12242e72742cSMatthew G. Knepley     }
1225*3be36e83SMatthew G. Knepley     ierr = PetscHMapIJClear(faceHash);CHKERRQ(ierr);
12267bffde78SMichael Lange     ierr = PetscSectionSetUp(candidateSection);CHKERRQ(ierr);
12277bffde78SMichael Lange     ierr = PetscSectionGetStorageSize(candidateSection, &candidatesSize);CHKERRQ(ierr);
12287bffde78SMichael Lange     ierr = PetscMalloc1(candidatesSize, &candidates);CHKERRQ(ierr);
1229*3be36e83SMatthew G. Knepley     for (l = 0; l < Nl; ++l) {
1230*3be36e83SMatthew G. Knepley       const PetscInt p = localPoints[l];
12312e72742cSMatthew G. Knepley 
1232*3be36e83SMatthew G. Knepley       if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]  Second pass leaf point %D\n", rank, p);CHKERRQ(ierr);}
1233*3be36e83SMatthew G. Knepley       ierr = DMPlexAddSharedFace_Private(dm, candidateSection, candidates, faceHash, p, debug);CHKERRQ(ierr);
12342e72742cSMatthew G. Knepley     }
1235*3be36e83SMatthew G. Knepley     ierr = PetscHMapIJDestroy(&faceHash);CHKERRQ(ierr);
1236*3be36e83SMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
12377bffde78SMichael Lange   }
1238*3be36e83SMatthew G. Knepley   ierr = PetscObjectSetName((PetscObject) candidateSection, "Candidate Section");CHKERRQ(ierr);
12392e72742cSMatthew G. Knepley   ierr = PetscObjectViewFromOptions((PetscObject) candidateSection, NULL, "-petscsection_interp_candidate_view");CHKERRQ(ierr);
1240*3be36e83SMatthew G. Knepley   ierr = SFNodeArrayViewFromOptions(comm, "-petscsection_interp_candidate_view", "Candidates", NULL, candidatesSize, candidates);CHKERRQ(ierr);
1241*3be36e83SMatthew G. Knepley   /* Step 2: Gather candidate section / array pair into the root partition via inverse(multi(pointSF)). */
12422e72742cSMatthew G. Knepley   /*   Note that this section is indexed by offsets into leaves, not by point number */
12437bffde78SMichael Lange   {
12447bffde78SMichael Lange     PetscSF   sfMulti, sfInverse, sfCandidates;
12457bffde78SMichael Lange     PetscInt *remoteOffsets;
12462e72742cSMatthew G. Knepley 
12477bffde78SMichael Lange     ierr = PetscSFGetMultiSF(pointSF, &sfMulti);CHKERRQ(ierr);
12487bffde78SMichael Lange     ierr = PetscSFCreateInverseSF(sfMulti, &sfInverse);CHKERRQ(ierr);
1249*3be36e83SMatthew G. Knepley     ierr = PetscSectionCreate(comm, &candidateRemoteSection);CHKERRQ(ierr);
1250*3be36e83SMatthew G. Knepley     ierr = PetscSFDistributeSection(sfInverse, candidateSection, &remoteOffsets, candidateRemoteSection);CHKERRQ(ierr);
1251*3be36e83SMatthew G. Knepley     ierr = PetscSFCreateSectionSF(sfInverse, candidateSection, remoteOffsets, candidateRemoteSection, &sfCandidates);CHKERRQ(ierr);
1252*3be36e83SMatthew G. Knepley     ierr = PetscSectionGetStorageSize(candidateRemoteSection, &candidatesRemoteSize);CHKERRQ(ierr);
12537bffde78SMichael Lange     ierr = PetscMalloc1(candidatesRemoteSize, &candidatesRemote);CHKERRQ(ierr);
12547bffde78SMichael Lange     ierr = PetscSFBcastBegin(sfCandidates, MPIU_2INT, candidates, candidatesRemote);CHKERRQ(ierr);
12557bffde78SMichael Lange     ierr = PetscSFBcastEnd(sfCandidates, MPIU_2INT, candidates, candidatesRemote);CHKERRQ(ierr);
12567bffde78SMichael Lange     ierr = PetscSFDestroy(&sfInverse);CHKERRQ(ierr);
12577bffde78SMichael Lange     ierr = PetscSFDestroy(&sfCandidates);CHKERRQ(ierr);
12587bffde78SMichael Lange     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
12592e72742cSMatthew G. Knepley 
1260*3be36e83SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) candidateRemoteSection, "Remote Candidate Section");CHKERRQ(ierr);
1261*3be36e83SMatthew G. Knepley     ierr = PetscObjectViewFromOptions((PetscObject) candidateRemoteSection, NULL, "-petscsection_interp_candidate_remote_view");CHKERRQ(ierr);
1262*3be36e83SMatthew G. Knepley     ierr = SFNodeArrayViewFromOptions(comm, "-petscsection_interp_candidate_remote_view", "Remote Candidates", NULL, candidatesRemoteSize, candidatesRemote);CHKERRQ(ierr);
12637bffde78SMichael Lange   }
1264*3be36e83SMatthew G. Knepley   /* Step 3: At the root, if at least two faces with a given cone are present, including a local face, mark the face as shared and choose the root face */
12657bffde78SMichael Lange   {
1266*3be36e83SMatthew G. Knepley     PetscHashIJKLRemote faceTable;
1267*3be36e83SMatthew G. Knepley     PetscInt            idx, idx2;
1268*3be36e83SMatthew G. Knepley 
1269*3be36e83SMatthew G. Knepley     ierr = PetscHashIJKLRemoteCreate(&faceTable);CHKERRQ(ierr);
12702e72742cSMatthew G. Knepley     /* There is a section point for every leaf attached to a given root point */
1271*3be36e83SMatthew G. Knepley     for (r = 0, idx = 0, idx2 = 0; r < Nr; ++r) {
12722e72742cSMatthew G. Knepley       PetscInt deg;
1273*3be36e83SMatthew G. Knepley 
12742e72742cSMatthew G. Knepley       for (deg = 0; deg < rootdegree[r]; ++deg, ++idx) {
12752e72742cSMatthew G. Knepley         PetscInt offset, dof, d;
12762e72742cSMatthew G. Knepley 
1277*3be36e83SMatthew G. Knepley         ierr = PetscSectionGetDof(candidateRemoteSection, idx, &dof);CHKERRQ(ierr);
1278*3be36e83SMatthew G. Knepley         ierr = PetscSectionGetOffset(candidateRemoteSection, idx, &offset);CHKERRQ(ierr);
1279*3be36e83SMatthew G. Knepley         /* dof may include many faces from the remote process */
12802e72742cSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1281*3be36e83SMatthew G. Knepley           const PetscInt         hidx  = offset+d;
1282*3be36e83SMatthew G. Knepley           const PetscInt         Np    = candidatesRemote[hidx].index+1;
1283*3be36e83SMatthew G. Knepley           const PetscSFNode      rface = candidatesRemote[hidx+1];
1284*3be36e83SMatthew G. Knepley           const PetscSFNode     *fcone = &candidatesRemote[hidx+2];
1285*3be36e83SMatthew G. Knepley           PetscSFNode            fcp0;
1286*3be36e83SMatthew G. Knepley           const PetscSFNode      pmax  = {PETSC_MAX_INT, PETSC_MAX_INT};
12872e72742cSMatthew G. Knepley           const PetscInt        *join  = NULL;
1288*3be36e83SMatthew G. Knepley           PetscHashIJKLRemoteKey key;
1289*3be36e83SMatthew G. Knepley           PetscHashIter          iter;
1290*3be36e83SMatthew G. Knepley           PetscBool              missing;
12912e72742cSMatthew G. Knepley           PetscInt               points[1024], p, joinSize;
12922e72742cSMatthew G. Knepley 
1293*3be36e83SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Checking face (%D, %D) at (%D, %D, %D) with cone size %D\n", rank, rface.index, rface.rank, r, idx, d, Np);CHKERRQ(ierr);}
1294*3be36e83SMatthew G. Knepley           if (Np > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle faces with %D cone points", Np);
1295*3be36e83SMatthew G. Knepley           fcp0.rank  = rank;
1296*3be36e83SMatthew G. Knepley           fcp0.index = r;
1297*3be36e83SMatthew G. Knepley           d += Np;
1298*3be36e83SMatthew G. Knepley           /* Put remote face in hash table */
1299*3be36e83SMatthew G. Knepley           key.i = fcp0;
1300*3be36e83SMatthew G. Knepley           key.j = fcone[0];
1301*3be36e83SMatthew G. Knepley           key.k = Np > 2 ? fcone[1] : pmax;
1302*3be36e83SMatthew G. Knepley           key.l = Np > 3 ? fcone[2] : pmax;
1303*3be36e83SMatthew G. Knepley           ierr = PetscSortSFNode(Np, (PetscSFNode *) &key);CHKERRQ(ierr);
1304*3be36e83SMatthew G. Knepley           ierr = PetscHashIJKLRemotePut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
1305*3be36e83SMatthew G. Knepley           if (missing) {
1306*3be36e83SMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Setting remote face (%D, %D)\n", rank, rface.index, rface.rank);CHKERRQ(ierr);}
1307*3be36e83SMatthew G. Knepley             ierr = PetscHashIJKLRemoteIterSet(faceTable, iter, rface);CHKERRQ(ierr);
1308*3be36e83SMatthew G. Knepley           } else {
1309*3be36e83SMatthew G. Knepley             PetscSFNode oface;
1310*3be36e83SMatthew G. Knepley 
1311*3be36e83SMatthew G. Knepley             ierr = PetscHashIJKLRemoteIterGet(faceTable, iter, &oface);CHKERRQ(ierr);
1312*3be36e83SMatthew G. Knepley             if ((rface.rank < oface.rank) || (rface.rank == oface.rank && rface.index < oface.index)) {
1313*3be36e83SMatthew G. Knepley               if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Replacing with remote face (%D, %D)\n", rank, rface.index, rface.rank);CHKERRQ(ierr);}
1314*3be36e83SMatthew G. Knepley               ierr = PetscHashIJKLRemoteIterSet(faceTable, iter, rface);CHKERRQ(ierr);
1315*3be36e83SMatthew G. Knepley             }
1316*3be36e83SMatthew G. Knepley           }
1317*3be36e83SMatthew G. Knepley           /* Check for local face */
13182e72742cSMatthew G. Knepley           points[0] = r;
1319*3be36e83SMatthew G. Knepley           for (p = 1; p < Np; ++p) {
1320*3be36e83SMatthew G. Knepley             ierr = DMPlexMapToLocalPoint(dm, remoteHash, fcone[p-1], &points[p]);
1321*3be36e83SMatthew G. Knepley             if (ierr) break; /* We got a point not in our overlap */
1322*3be36e83SMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Checking local candidate %D\n", rank, points[p]);CHKERRQ(ierr);}
13237bffde78SMichael Lange           }
13242e72742cSMatthew G. Knepley           if (ierr) continue;
1325*3be36e83SMatthew G. Knepley           ierr = DMPlexGetJoin(dm, Np, points, &joinSize, &join);CHKERRQ(ierr);
13267bffde78SMichael Lange           if (joinSize == 1) {
1327*3be36e83SMatthew G. Knepley             PetscSFNode lface;
1328*3be36e83SMatthew G. Knepley             PetscSFNode oface;
1329*3be36e83SMatthew G. Knepley 
1330*3be36e83SMatthew G. Knepley             /* Always replace with local face */
1331*3be36e83SMatthew G. Knepley             lface.rank  = rank;
1332*3be36e83SMatthew G. Knepley             lface.index = join[0];
1333*3be36e83SMatthew G. Knepley             ierr = PetscHashIJKLRemoteIterGet(faceTable, iter, &oface);CHKERRQ(ierr);
1334*3be36e83SMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Replacing (%D, %D) with local face (%D, %D)\n", rank, oface.index, oface.rank, lface.index, lface.rank);CHKERRQ(ierr);}
1335*3be36e83SMatthew G. Knepley             ierr = PetscHashIJKLRemoteIterSet(faceTable, iter, lface);CHKERRQ(ierr);
13367bffde78SMichael Lange           }
1337*3be36e83SMatthew G. Knepley           ierr = DMPlexRestoreJoin(dm, Np, points, &joinSize, &join);CHKERRQ(ierr);
1338*3be36e83SMatthew G. Knepley         }
1339*3be36e83SMatthew G. Knepley       }
1340*3be36e83SMatthew G. Knepley       /* Put back faces for this root */
1341*3be36e83SMatthew G. Knepley       for (deg = 0; deg < rootdegree[r]; ++deg, ++idx2) {
1342*3be36e83SMatthew G. Knepley         PetscInt offset, dof, d;
1343*3be36e83SMatthew G. Knepley 
1344*3be36e83SMatthew G. Knepley         ierr = PetscSectionGetDof(candidateRemoteSection, idx2, &dof);CHKERRQ(ierr);
1345*3be36e83SMatthew G. Knepley         ierr = PetscSectionGetOffset(candidateRemoteSection, idx2, &offset);CHKERRQ(ierr);
1346*3be36e83SMatthew G. Knepley         /* dof may include many faces from the remote process */
1347*3be36e83SMatthew G. Knepley         for (d = 0; d < dof; ++d) {
1348*3be36e83SMatthew G. Knepley           const PetscInt         hidx  = offset+d;
1349*3be36e83SMatthew G. Knepley           const PetscInt         Np    = candidatesRemote[hidx].index+1;
1350*3be36e83SMatthew G. Knepley           const PetscSFNode     *fcone = &candidatesRemote[hidx+2];
1351*3be36e83SMatthew G. Knepley           PetscSFNode            fcp0;
1352*3be36e83SMatthew G. Knepley           const PetscSFNode      pmax  = {PETSC_MAX_INT, PETSC_MAX_INT};
1353*3be36e83SMatthew G. Knepley           PetscHashIJKLRemoteKey key;
1354*3be36e83SMatthew G. Knepley           PetscHashIter          iter;
1355*3be36e83SMatthew G. Knepley           PetscBool              missing;
1356*3be36e83SMatthew G. Knepley 
1357*3be36e83SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Entering face at (%D, %D)\n", rank, r, idx);CHKERRQ(ierr);}
1358*3be36e83SMatthew G. Knepley           if (Np > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle faces with %D cone points", Np);
1359*3be36e83SMatthew G. Knepley           fcp0.rank  = rank;
1360*3be36e83SMatthew G. Knepley           fcp0.index = r;
1361*3be36e83SMatthew G. Knepley           d += Np;
1362*3be36e83SMatthew G. Knepley           /* Find remote face in hash table */
1363*3be36e83SMatthew G. Knepley           key.i = fcp0;
1364*3be36e83SMatthew G. Knepley           key.j = fcone[0];
1365*3be36e83SMatthew G. Knepley           key.k = Np > 2 ? fcone[1] : pmax;
1366*3be36e83SMatthew G. Knepley           key.l = Np > 3 ? fcone[2] : pmax;
1367*3be36e83SMatthew G. Knepley           ierr = PetscSortSFNode(Np, (PetscSFNode *) &key);CHKERRQ(ierr);
1368*3be36e83SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    key (%D, %D) (%D, %D) (%D, %D) (%D, %D)\n", rank, key.i.rank, key.i.index, key.j.rank, key.j.index, key.k.rank, key.k.index, key.l.rank, key.l.index);CHKERRQ(ierr);}
1369*3be36e83SMatthew G. Knepley           ierr = PetscHashIJKLRemotePut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
1370*3be36e83SMatthew G. Knepley           if (missing) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Root %D Idx %D ought to have an assoicated face", r, idx2);
1371*3be36e83SMatthew G. Knepley           else        {ierr = PetscHashIJKLRemoteIterGet(faceTable, iter, &candidatesRemote[hidx]);CHKERRQ(ierr);}
13727bffde78SMichael Lange         }
13737bffde78SMichael Lange       }
13747bffde78SMichael Lange     }
13752e72742cSMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedFlush(PetscObjectComm((PetscObject) dm), NULL);CHKERRQ(ierr);}
1376*3be36e83SMatthew G. Knepley     ierr = PetscHashIJKLRemoteDestroy(&faceTable);CHKERRQ(ierr);
13777bffde78SMichael Lange   }
1378*3be36e83SMatthew G. Knepley   /* Step 4: Push back owned faces */
13797bffde78SMichael Lange   {
13807bffde78SMichael Lange     PetscSF      sfMulti, sfClaims, sfPointNew;
13817bffde78SMichael Lange     PetscSFNode *remotePointsNew;
13822e72742cSMatthew G. Knepley     PetscInt    *remoteOffsets, *localPointsNew;
1383*3be36e83SMatthew G. Knepley     PetscInt     pStart, pEnd, r, NlNew, p;
13842e72742cSMatthew G. Knepley 
1385*3be36e83SMatthew G. Knepley     /* 4) Push claims back to receiver via the MultiSF and derive new pointSF mapping on receiver */
13867bffde78SMichael Lange     ierr = PetscSFGetMultiSF(pointSF, &sfMulti);CHKERRQ(ierr);
1387*3be36e83SMatthew G. Knepley     ierr = PetscSectionCreate(comm, &claimSection);CHKERRQ(ierr);
1388*3be36e83SMatthew G. Knepley     ierr = PetscSFDistributeSection(sfMulti, candidateRemoteSection, &remoteOffsets, claimSection);CHKERRQ(ierr);
1389*3be36e83SMatthew G. Knepley     ierr = PetscSFCreateSectionSF(sfMulti, candidateRemoteSection, remoteOffsets, claimSection, &sfClaims);CHKERRQ(ierr);
13902e72742cSMatthew G. Knepley     ierr = PetscSectionGetStorageSize(claimSection, &claimsSize);CHKERRQ(ierr);
13912e72742cSMatthew G. Knepley     ierr = PetscMalloc1(claimsSize, &claims);CHKERRQ(ierr);
1392*3be36e83SMatthew G. Knepley     for (p = 0; p < claimsSize; ++p) claims[p].rank = -1;
13937bffde78SMichael Lange     ierr = PetscSFBcastBegin(sfClaims, MPIU_2INT, candidatesRemote, claims);CHKERRQ(ierr);
13947bffde78SMichael Lange     ierr = PetscSFBcastEnd(sfClaims, MPIU_2INT, candidatesRemote, claims);CHKERRQ(ierr);
13957bffde78SMichael Lange     ierr = PetscSFDestroy(&sfClaims);CHKERRQ(ierr);
13967bffde78SMichael Lange     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
1397*3be36e83SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) claimSection, "Claim Section");CHKERRQ(ierr);
13982e72742cSMatthew G. Knepley     ierr = PetscObjectViewFromOptions((PetscObject) claimSection, NULL, "-petscsection_interp_claim_view");CHKERRQ(ierr);
1399*3be36e83SMatthew G. Knepley     ierr = SFNodeArrayViewFromOptions(comm, "-petscsection_interp_claim_view", "Claims", NULL, claimsSize, claims);CHKERRQ(ierr);
1400*3be36e83SMatthew G. Knepley     /* Step 5) Walk the original section of local supports and add an SF entry for each updated item */
1401*3be36e83SMatthew G. Knepley     /* TODO I should not have to do a join here since I already put the face and its cone in the candidate section */
1402e8f14785SLisandro Dalcin     ierr = PetscHMapICreate(&claimshash);CHKERRQ(ierr);
1403*3be36e83SMatthew G. Knepley     for (r = 0; r < Nr; ++r) {
1404*3be36e83SMatthew G. Knepley       PetscInt dof, off, d;
14052e72742cSMatthew G. Knepley 
1406*3be36e83SMatthew G. Knepley       if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]  Checking root for claims %D\n", rank, r);CHKERRQ(ierr);}
1407*3be36e83SMatthew G. Knepley       ierr = PetscSectionGetDof(candidateSection, r, &dof);CHKERRQ(ierr);
1408*3be36e83SMatthew G. Knepley       ierr = PetscSectionGetOffset(candidateSection, r, &off);CHKERRQ(ierr);
14092e72742cSMatthew G. Knepley       for (d = 0; d < dof;) {
1410*3be36e83SMatthew G. Knepley         if (claims[off+d].rank >= 0) {
1411*3be36e83SMatthew G. Knepley           const PetscInt  faceInd = off+d;
1412*3be36e83SMatthew G. Knepley           const PetscInt  Np      = candidates[off+d].index;
14132e72742cSMatthew G. Knepley           const PetscInt *join    = NULL;
14142e72742cSMatthew G. Knepley           PetscInt        joinSize, points[1024], c;
14152e72742cSMatthew G. Knepley 
1416*3be36e83SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    Found claim for remote point (%D, %D)\n", rank, claims[faceInd].rank, claims[faceInd].index);CHKERRQ(ierr);}
1417*3be36e83SMatthew G. Knepley           points[0] = r;
1418*3be36e83SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]      point %D\n", rank, points[0]);CHKERRQ(ierr);}
1419*3be36e83SMatthew G. Knepley           for (c = 0, d += 2; c < Np; ++c, ++d) {
1420*3be36e83SMatthew G. Knepley             ierr = DMPlexMapToLocalPoint(dm, remoteHash, candidates[off+d], &points[c+1]);CHKERRQ(ierr);
1421*3be36e83SMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]      point %D\n", rank, points[c+1]);CHKERRQ(ierr);}
14222e72742cSMatthew G. Knepley           }
1423*3be36e83SMatthew G. Knepley           ierr = DMPlexGetJoin(dm, Np+1, points, &joinSize, &join);CHKERRQ(ierr);
14242e72742cSMatthew G. Knepley           if (joinSize == 1) {
1425*3be36e83SMatthew G. Knepley             if (claims[faceInd].rank == rank) {
1426*3be36e83SMatthew G. Knepley               if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    Ignoring local face %D for non-remote partner\n", rank, join[0]);CHKERRQ(ierr);}
1427*3be36e83SMatthew G. Knepley             } else {
1428*3be36e83SMatthew G. Knepley               if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    Found local face %D\n", rank, join[0]);CHKERRQ(ierr);}
14292e72742cSMatthew G. Knepley               ierr = PetscHMapISet(claimshash, join[0], faceInd);CHKERRQ(ierr);
14302e72742cSMatthew G. Knepley             }
1431*3be36e83SMatthew G. Knepley           } else {
1432*3be36e83SMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    Failed to find face\n", rank);CHKERRQ(ierr);}
1433*3be36e83SMatthew G. Knepley           }
1434*3be36e83SMatthew G. Knepley           ierr = DMPlexRestoreJoin(dm, Np+1, points, &joinSize, &join);CHKERRQ(ierr);
1435*3be36e83SMatthew G. Knepley         } else {
1436*3be36e83SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]    No claim for point %D\n", rank, r);CHKERRQ(ierr);}
1437*3be36e83SMatthew G. Knepley           d += claims[off+d].index+1;
14387bffde78SMichael Lange         }
14397bffde78SMichael Lange       }
1440*3be36e83SMatthew G. Knepley     }
1441*3be36e83SMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
1442*3be36e83SMatthew G. Knepley     /* Step 6) Create new pointSF from hashed claims */
1443*3be36e83SMatthew G. Knepley     ierr = PetscHMapIGetSize(claimshash, &NlNew);CHKERRQ(ierr);
14447bffde78SMichael Lange     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1445*3be36e83SMatthew G. Knepley     ierr = PetscMalloc1(Nl + NlNew, &localPointsNew);CHKERRQ(ierr);
1446*3be36e83SMatthew G. Knepley     ierr = PetscMalloc1(Nl + NlNew, &remotePointsNew);CHKERRQ(ierr);
1447*3be36e83SMatthew G. Knepley     for (l = 0; l < Nl; ++l) {
1448*3be36e83SMatthew G. Knepley       localPointsNew[l] = localPoints[l];
1449*3be36e83SMatthew G. Knepley       remotePointsNew[l].index = remotePoints[l].index;
1450*3be36e83SMatthew G. Knepley       remotePointsNew[l].rank  = remotePoints[l].rank;
14517bffde78SMichael Lange     }
1452*3be36e83SMatthew G. Knepley     p = Nl;
1453e8f14785SLisandro Dalcin     ierr = PetscHMapIGetKeys(claimshash, &p, localPointsNew);CHKERRQ(ierr);
1454*3be36e83SMatthew G. Knepley     /* We sort new points, and assume they are numbered after all existing points */
1455*3be36e83SMatthew G. Knepley     ierr = PetscSortInt(NlNew, &localPointsNew[Nl]);CHKERRQ(ierr);
1456*3be36e83SMatthew G. Knepley     for (p = Nl; p < Nl + NlNew; ++p) {
1457*3be36e83SMatthew G. Knepley       PetscInt off;
1458*3be36e83SMatthew G. Knepley       ierr = PetscHMapIGet(claimshash, localPointsNew[p], &off);CHKERRQ(ierr);
1459*3be36e83SMatthew G. Knepley       if (claims[off].rank < 0 || claims[off].index < 0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid claim for local point %D, (%D, %D)", localPointsNew[p], claims[off].rank, claims[off].index);
1460*3be36e83SMatthew G. Knepley       remotePointsNew[p] = claims[off];
14617bffde78SMichael Lange     }
1462*3be36e83SMatthew G. Knepley     ierr = PetscSFCreate(comm, &sfPointNew);CHKERRQ(ierr);
1463*3be36e83SMatthew G. Knepley     ierr = PetscSFSetGraph(sfPointNew, pEnd-pStart, Nl+NlNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
1464*3be36e83SMatthew G. Knepley     ierr = PetscSFSetUp(sfPointNew);CHKERRQ(ierr);
14657bffde78SMichael Lange     ierr = DMSetPointSF(dm, sfPointNew);CHKERRQ(ierr);
1466*3be36e83SMatthew G. Knepley     ierr = PetscObjectViewFromOptions((PetscObject) sfPointNew, NULL, "-petscsf_interp_view");CHKERRQ(ierr);
14677bffde78SMichael Lange     ierr = PetscSFDestroy(&sfPointNew);CHKERRQ(ierr);
1468e8f14785SLisandro Dalcin     ierr = PetscHMapIDestroy(&claimshash);CHKERRQ(ierr);
14697bffde78SMichael Lange   }
1470*3be36e83SMatthew G. Knepley   ierr = PetscHMapIJDestroy(&remoteHash);CHKERRQ(ierr);
14717bffde78SMichael Lange   ierr = PetscSectionDestroy(&candidateSection);CHKERRQ(ierr);
1472*3be36e83SMatthew G. Knepley   ierr = PetscSectionDestroy(&candidateRemoteSection);CHKERRQ(ierr);
14737bffde78SMichael Lange   ierr = PetscSectionDestroy(&claimSection);CHKERRQ(ierr);
14747bffde78SMichael Lange   ierr = PetscFree(candidates);CHKERRQ(ierr);
14757bffde78SMichael Lange   ierr = PetscFree(candidatesRemote);CHKERRQ(ierr);
14767bffde78SMichael Lange   ierr = PetscFree(claims);CHKERRQ(ierr);
147725afeb17SMatthew G. Knepley   ierr = PetscLogEventEnd(DMPLEX_InterpolateSF,dm,0,0,0);CHKERRQ(ierr);
14787bffde78SMichael Lange   PetscFunctionReturn(0);
14797bffde78SMichael Lange }
14807bffde78SMichael Lange 
1481248eb259SVaclav Hapla /*@
148280330477SMatthew G. Knepley   DMPlexInterpolate - Take in a cell-vertex mesh and return one with all intermediate faces, edges, etc.
148380330477SMatthew G. Knepley 
1484d083f849SBarry Smith   Collective on dm
148580330477SMatthew G. Knepley 
1486e56d480eSMatthew G. Knepley   Input Parameters:
1487e56d480eSMatthew G. Knepley + dm - The DMPlex object with only cells and vertices
148810a67516SMatthew G. Knepley - dmInt - The interpolated DM
148980330477SMatthew G. Knepley 
149080330477SMatthew G. Knepley   Output Parameter:
14914e3744c5SMatthew G. Knepley . dmInt - The complete DMPlex object
149280330477SMatthew G. Knepley 
149380330477SMatthew G. Knepley   Level: intermediate
149480330477SMatthew G. Knepley 
149595452b02SPatrick Sanan   Notes:
149695452b02SPatrick Sanan     It does not copy over the coordinates.
149743eeeb2dSStefano Zampini 
14989ade3219SVaclav Hapla   Developer Notes:
14999ade3219SVaclav Hapla     It sets plex->interpolated = DMPLEX_INTERPOLATED_FULL.
15009ade3219SVaclav Hapla 
150143eeeb2dSStefano Zampini .seealso: DMPlexUninterpolate(), DMPlexCreateFromCellList(), DMPlexCopyCoordinates()
150280330477SMatthew G. Knepley @*/
15039f074e33SMatthew G Knepley PetscErrorCode DMPlexInterpolate(DM dm, DM *dmInt)
15049f074e33SMatthew G Knepley {
1505a7748839SVaclav Hapla   DMPlexInterpolatedFlag interpolated;
15069a5b13a2SMatthew G Knepley   DM             idm, odm = dm;
15077bffde78SMichael Lange   PetscSF        sfPoint;
15082e1b13c2SMatthew G. Knepley   PetscInt       depth, dim, d;
150910a67516SMatthew G. Knepley   const char    *name;
1510b325530aSVaclav Hapla   PetscBool      flg=PETSC_TRUE;
15119f074e33SMatthew G Knepley   PetscErrorCode ierr;
15129f074e33SMatthew G Knepley 
15139f074e33SMatthew G Knepley   PetscFunctionBegin;
151410a67516SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
151510a67516SMatthew G. Knepley   PetscValidPointer(dmInt, 2);
1516a72f3261SMatthew G. Knepley   ierr = PetscLogEventBegin(DMPLEX_Interpolate,dm,0,0,0);CHKERRQ(ierr);
15172e1b13c2SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1518c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1519827c4036SVaclav Hapla   ierr = DMPlexIsInterpolated(dm, &interpolated);CHKERRQ(ierr);
1520827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_PARTIAL) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes");
1521827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_FULL) {
152276b791aaSMatthew G. Knepley     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
152376b791aaSMatthew G. Knepley     idm  = dm;
1524b21b8912SMatthew G. Knepley   } else {
15259a5b13a2SMatthew G Knepley     for (d = 1; d < dim; ++d) {
15269a5b13a2SMatthew G Knepley       /* Create interpolated mesh */
152710a67516SMatthew G. Knepley       ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
15289a5b13a2SMatthew G Knepley       ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
1529c73cfb54SMatthew G. Knepley       ierr = DMSetDimension(idm, dim);CHKERRQ(ierr);
15307bffde78SMichael Lange       if (depth > 0) {
15317bffde78SMichael Lange         ierr = DMPlexInterpolateFaces_Internal(odm, 1, idm);CHKERRQ(ierr);
15327bffde78SMichael Lange         ierr = DMGetPointSF(odm, &sfPoint);CHKERRQ(ierr);
153394488200SVaclav Hapla         {
1534*3be36e83SMatthew G. Knepley           /* TODO: We need to systematically fix cases of distributed Plexes with no graph set */
153594488200SVaclav Hapla           PetscInt nroots;
153694488200SVaclav Hapla           ierr = PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
153794488200SVaclav Hapla           if (nroots >= 0) {ierr = DMPlexInterpolatePointSF(idm, sfPoint);CHKERRQ(ierr);}
153894488200SVaclav Hapla         }
15397bffde78SMichael Lange       }
15409a5b13a2SMatthew G Knepley       if (odm != dm) {ierr = DMDestroy(&odm);CHKERRQ(ierr);}
15419a5b13a2SMatthew G Knepley       odm = idm;
15429f074e33SMatthew G Knepley     }
154310a67516SMatthew G. Knepley     ierr = PetscObjectGetName((PetscObject) dm,  &name);CHKERRQ(ierr);
154410a67516SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) idm,  name);CHKERRQ(ierr);
154510a67516SMatthew G. Knepley     ierr = DMPlexCopyCoordinates(dm, idm);CHKERRQ(ierr);
15465d80c0bfSVaclav Hapla     ierr = DMCopyLabels(dm, idm, PETSC_COPY_VALUES, PETSC_FALSE);CHKERRQ(ierr);
1547b325530aSVaclav Hapla     ierr = PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_interpolate_orient_interfaces", &flg, NULL);CHKERRQ(ierr);
154827d0e99aSVaclav Hapla     if (flg) {ierr = DMPlexOrientInterface_Internal(idm);CHKERRQ(ierr);}
154984699f70SSatish Balay   }
155043eeeb2dSStefano Zampini   {
155143eeeb2dSStefano Zampini     PetscBool            isper;
155243eeeb2dSStefano Zampini     const PetscReal      *maxCell, *L;
155343eeeb2dSStefano Zampini     const DMBoundaryType *bd;
155443eeeb2dSStefano Zampini 
155543eeeb2dSStefano Zampini     ierr = DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd);CHKERRQ(ierr);
155643eeeb2dSStefano Zampini     ierr = DMSetPeriodicity(idm,isper,maxCell,L,bd);CHKERRQ(ierr);
155743eeeb2dSStefano Zampini   }
1558827c4036SVaclav Hapla   /* This function makes the mesh fully interpolated on all ranks */
1559827c4036SVaclav Hapla   {
1560d6e9e4f7SVaclav Hapla     DM_Plex *plex = (DM_Plex *) idm->data;
1561827c4036SVaclav Hapla     plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_FULL;
1562827c4036SVaclav Hapla   }
15639a5b13a2SMatthew G Knepley   *dmInt = idm;
1564a72f3261SMatthew G. Knepley   ierr = PetscLogEventEnd(DMPLEX_Interpolate,dm,0,0,0);CHKERRQ(ierr);
15659f074e33SMatthew G Knepley   PetscFunctionReturn(0);
15669f074e33SMatthew G Knepley }
156707b0a1fcSMatthew G Knepley 
156880330477SMatthew G. Knepley /*@
156980330477SMatthew G. Knepley   DMPlexCopyCoordinates - Copy coordinates from one mesh to another with the same vertices
157080330477SMatthew G. Knepley 
1571d083f849SBarry Smith   Collective on dmA
157280330477SMatthew G. Knepley 
157380330477SMatthew G. Knepley   Input Parameter:
157480330477SMatthew G. Knepley . dmA - The DMPlex object with initial coordinates
157580330477SMatthew G. Knepley 
157680330477SMatthew G. Knepley   Output Parameter:
157780330477SMatthew G. Knepley . dmB - The DMPlex object with copied coordinates
157880330477SMatthew G. Knepley 
157980330477SMatthew G. Knepley   Level: intermediate
158080330477SMatthew G. Knepley 
158180330477SMatthew G. Knepley   Note: This is typically used when adding pieces other than vertices to a mesh
158280330477SMatthew G. Knepley 
158365f90189SJed Brown .seealso: DMCopyLabels(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
158480330477SMatthew G. Knepley @*/
158507b0a1fcSMatthew G Knepley PetscErrorCode DMPlexCopyCoordinates(DM dmA, DM dmB)
158607b0a1fcSMatthew G Knepley {
158707b0a1fcSMatthew G Knepley   Vec            coordinatesA, coordinatesB;
158843eeeb2dSStefano Zampini   VecType        vtype;
158907b0a1fcSMatthew G Knepley   PetscSection   coordSectionA, coordSectionB;
159007b0a1fcSMatthew G Knepley   PetscScalar   *coordsA, *coordsB;
15910bedd6beSMatthew G. Knepley   PetscInt       spaceDim, Nf, vStartA, vStartB, vEndA, vEndB, coordSizeB, v, d;
159243eeeb2dSStefano Zampini   PetscInt       cStartA, cEndA, cStartB, cEndB, cS, cE;
159343eeeb2dSStefano Zampini   PetscBool      lc = PETSC_FALSE;
159407b0a1fcSMatthew G Knepley   PetscErrorCode ierr;
159507b0a1fcSMatthew G Knepley 
159607b0a1fcSMatthew G Knepley   PetscFunctionBegin;
159743eeeb2dSStefano Zampini   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
159843eeeb2dSStefano Zampini   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
159976b791aaSMatthew G. Knepley   if (dmA == dmB) PetscFunctionReturn(0);
160007b0a1fcSMatthew G Knepley   ierr = DMPlexGetDepthStratum(dmA, 0, &vStartA, &vEndA);CHKERRQ(ierr);
160107b0a1fcSMatthew G Knepley   ierr = DMPlexGetDepthStratum(dmB, 0, &vStartB, &vEndB);CHKERRQ(ierr);
160207b0a1fcSMatthew G Knepley   if ((vEndA-vStartA) != (vEndB-vStartB)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of vertices in first DM %d != %d in the second DM", vEndA-vStartA, vEndB-vStartB);
160343eeeb2dSStefano Zampini   ierr = DMPlexGetHeightStratum(dmA, 0, &cStartA, &cEndA);CHKERRQ(ierr);
160443eeeb2dSStefano Zampini   ierr = DMPlexGetHeightStratum(dmB, 0, &cStartB, &cEndB);CHKERRQ(ierr);
160569d8a9ceSMatthew G. Knepley   ierr = DMGetCoordinateSection(dmA, &coordSectionA);CHKERRQ(ierr);
160669d8a9ceSMatthew G. Knepley   ierr = DMGetCoordinateSection(dmB, &coordSectionB);CHKERRQ(ierr);
1607972bc18aSToby Isaac   if (coordSectionA == coordSectionB) PetscFunctionReturn(0);
16080bedd6beSMatthew G. Knepley   ierr = PetscSectionGetNumFields(coordSectionA, &Nf);CHKERRQ(ierr);
16090bedd6beSMatthew G. Knepley   if (!Nf) PetscFunctionReturn(0);
16100bedd6beSMatthew G. Knepley   if (Nf > 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of coordinate fields must be 1, not %D", Nf);
1611df26b574SMatthew G. Knepley   if (!coordSectionB) {
1612df26b574SMatthew G. Knepley     PetscInt dim;
1613df26b574SMatthew G. Knepley 
1614df26b574SMatthew G. Knepley     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) coordSectionA), &coordSectionB);CHKERRQ(ierr);
1615df26b574SMatthew G. Knepley     ierr = DMGetCoordinateDim(dmA, &dim);CHKERRQ(ierr);
1616df26b574SMatthew G. Knepley     ierr = DMSetCoordinateSection(dmB, dim, coordSectionB);CHKERRQ(ierr);
1617df26b574SMatthew G. Knepley     ierr = PetscObjectDereference((PetscObject) coordSectionB);CHKERRQ(ierr);
1618df26b574SMatthew G. Knepley   }
161907b0a1fcSMatthew G Knepley   ierr = PetscSectionSetNumFields(coordSectionB, 1);CHKERRQ(ierr);
162007b0a1fcSMatthew G Knepley   ierr = PetscSectionGetFieldComponents(coordSectionA, 0, &spaceDim);CHKERRQ(ierr);
162107b0a1fcSMatthew G Knepley   ierr = PetscSectionSetFieldComponents(coordSectionB, 0, spaceDim);CHKERRQ(ierr);
162243eeeb2dSStefano Zampini   ierr = PetscSectionGetChart(coordSectionA, &cS, &cE);CHKERRQ(ierr);
162343eeeb2dSStefano Zampini   if (cStartA <= cS && cS < cEndA) { /* localized coordinates */
1624367003a6SStefano Zampini     if ((cEndA-cStartA) != (cEndB-cStartB)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cells in first DM %D != %D in the second DM", cEndA-cStartA, cEndB-cStartB);
162543eeeb2dSStefano Zampini     cS = cS - cStartA + cStartB;
162643eeeb2dSStefano Zampini     cE = vEndB;
162743eeeb2dSStefano Zampini     lc = PETSC_TRUE;
162843eeeb2dSStefano Zampini   } else {
162943eeeb2dSStefano Zampini     cS = vStartB;
163043eeeb2dSStefano Zampini     cE = vEndB;
163143eeeb2dSStefano Zampini   }
163243eeeb2dSStefano Zampini   ierr = PetscSectionSetChart(coordSectionB, cS, cE);CHKERRQ(ierr);
163307b0a1fcSMatthew G Knepley   for (v = vStartB; v < vEndB; ++v) {
163407b0a1fcSMatthew G Knepley     ierr = PetscSectionSetDof(coordSectionB, v, spaceDim);CHKERRQ(ierr);
163507b0a1fcSMatthew G Knepley     ierr = PetscSectionSetFieldDof(coordSectionB, v, 0, spaceDim);CHKERRQ(ierr);
163607b0a1fcSMatthew G Knepley   }
163743eeeb2dSStefano Zampini   if (lc) { /* localized coordinates */
163843eeeb2dSStefano Zampini     PetscInt c;
163943eeeb2dSStefano Zampini 
164043eeeb2dSStefano Zampini     for (c = cS-cStartB; c < cEndB-cStartB; c++) {
164143eeeb2dSStefano Zampini       PetscInt dof;
164243eeeb2dSStefano Zampini 
164343eeeb2dSStefano Zampini       ierr = PetscSectionGetDof(coordSectionA, c + cStartA, &dof);CHKERRQ(ierr);
164443eeeb2dSStefano Zampini       ierr = PetscSectionSetDof(coordSectionB, c + cStartB, dof);CHKERRQ(ierr);
164543eeeb2dSStefano Zampini       ierr = PetscSectionSetFieldDof(coordSectionB, c + cStartB, 0, dof);CHKERRQ(ierr);
164643eeeb2dSStefano Zampini     }
164743eeeb2dSStefano Zampini   }
164807b0a1fcSMatthew G Knepley   ierr = PetscSectionSetUp(coordSectionB);CHKERRQ(ierr);
164907b0a1fcSMatthew G Knepley   ierr = PetscSectionGetStorageSize(coordSectionB, &coordSizeB);CHKERRQ(ierr);
165007b0a1fcSMatthew G Knepley   ierr = DMGetCoordinatesLocal(dmA, &coordinatesA);CHKERRQ(ierr);
16518b9ced59SLisandro Dalcin   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesB);CHKERRQ(ierr);
165207b0a1fcSMatthew G Knepley   ierr = PetscObjectSetName((PetscObject) coordinatesB, "coordinates");CHKERRQ(ierr);
165307b0a1fcSMatthew G Knepley   ierr = VecSetSizes(coordinatesB, coordSizeB, PETSC_DETERMINE);CHKERRQ(ierr);
165443eeeb2dSStefano Zampini   ierr = VecGetBlockSize(coordinatesA, &d);CHKERRQ(ierr);
165543eeeb2dSStefano Zampini   ierr = VecSetBlockSize(coordinatesB, d);CHKERRQ(ierr);
165643eeeb2dSStefano Zampini   ierr = VecGetType(coordinatesA, &vtype);CHKERRQ(ierr);
165743eeeb2dSStefano Zampini   ierr = VecSetType(coordinatesB, vtype);CHKERRQ(ierr);
165807b0a1fcSMatthew G Knepley   ierr = VecGetArray(coordinatesA, &coordsA);CHKERRQ(ierr);
165907b0a1fcSMatthew G Knepley   ierr = VecGetArray(coordinatesB, &coordsB);CHKERRQ(ierr);
166007b0a1fcSMatthew G Knepley   for (v = 0; v < vEndB-vStartB; ++v) {
166143eeeb2dSStefano Zampini     PetscInt offA, offB;
166243eeeb2dSStefano Zampini 
166343eeeb2dSStefano Zampini     ierr = PetscSectionGetOffset(coordSectionA, v + vStartA, &offA);CHKERRQ(ierr);
166443eeeb2dSStefano Zampini     ierr = PetscSectionGetOffset(coordSectionB, v + vStartB, &offB);CHKERRQ(ierr);
166507b0a1fcSMatthew G Knepley     for (d = 0; d < spaceDim; ++d) {
166643eeeb2dSStefano Zampini       coordsB[offB+d] = coordsA[offA+d];
166743eeeb2dSStefano Zampini     }
166843eeeb2dSStefano Zampini   }
166943eeeb2dSStefano Zampini   if (lc) { /* localized coordinates */
167043eeeb2dSStefano Zampini     PetscInt c;
167143eeeb2dSStefano Zampini 
167243eeeb2dSStefano Zampini     for (c = cS-cStartB; c < cEndB-cStartB; c++) {
167343eeeb2dSStefano Zampini       PetscInt dof, offA, offB;
167443eeeb2dSStefano Zampini 
167543eeeb2dSStefano Zampini       ierr = PetscSectionGetOffset(coordSectionA, c + cStartA, &offA);CHKERRQ(ierr);
167643eeeb2dSStefano Zampini       ierr = PetscSectionGetOffset(coordSectionB, c + cStartB, &offB);CHKERRQ(ierr);
167743eeeb2dSStefano Zampini       ierr = PetscSectionGetDof(coordSectionA, c + cStartA, &dof);CHKERRQ(ierr);
1678580bdb30SBarry Smith       ierr = PetscArraycpy(coordsB + offB,coordsA + offA,dof);CHKERRQ(ierr);
167907b0a1fcSMatthew G Knepley     }
168007b0a1fcSMatthew G Knepley   }
168107b0a1fcSMatthew G Knepley   ierr = VecRestoreArray(coordinatesA, &coordsA);CHKERRQ(ierr);
168207b0a1fcSMatthew G Knepley   ierr = VecRestoreArray(coordinatesB, &coordsB);CHKERRQ(ierr);
168307b0a1fcSMatthew G Knepley   ierr = DMSetCoordinatesLocal(dmB, coordinatesB);CHKERRQ(ierr);
168407b0a1fcSMatthew G Knepley   ierr = VecDestroy(&coordinatesB);CHKERRQ(ierr);
168507b0a1fcSMatthew G Knepley   PetscFunctionReturn(0);
168607b0a1fcSMatthew G Knepley }
16875c386225SMatthew G. Knepley 
16884e3744c5SMatthew G. Knepley /*@
16894e3744c5SMatthew G. Knepley   DMPlexUninterpolate - Take in a mesh with all intermediate faces, edges, etc. and return a cell-vertex mesh
16904e3744c5SMatthew G. Knepley 
1691d083f849SBarry Smith   Collective on dm
16924e3744c5SMatthew G. Knepley 
16934e3744c5SMatthew G. Knepley   Input Parameter:
16944e3744c5SMatthew G. Knepley . dm - The complete DMPlex object
16954e3744c5SMatthew G. Knepley 
16964e3744c5SMatthew G. Knepley   Output Parameter:
16974e3744c5SMatthew G. Knepley . dmUnint - The DMPlex object with only cells and vertices
16984e3744c5SMatthew G. Knepley 
16994e3744c5SMatthew G. Knepley   Level: intermediate
17004e3744c5SMatthew G. Knepley 
170195452b02SPatrick Sanan   Notes:
170295452b02SPatrick Sanan     It does not copy over the coordinates.
170343eeeb2dSStefano Zampini 
17049ade3219SVaclav Hapla   Developer Notes:
17059ade3219SVaclav Hapla     It sets plex->interpolated = DMPLEX_INTERPOLATED_NONE.
17069ade3219SVaclav Hapla 
170743eeeb2dSStefano Zampini .seealso: DMPlexInterpolate(), DMPlexCreateFromCellList(), DMPlexCopyCoordinates()
17084e3744c5SMatthew G. Knepley @*/
17094e3744c5SMatthew G. Knepley PetscErrorCode DMPlexUninterpolate(DM dm, DM *dmUnint)
17104e3744c5SMatthew G. Knepley {
1711827c4036SVaclav Hapla   DMPlexInterpolatedFlag interpolated;
17124e3744c5SMatthew G. Knepley   DM             udm;
1713c9f63434SStefano Zampini   PetscInt       dim, vStart, vEnd, cStart, cEnd, cMax, c, maxConeSize = 0, *cone;
17144e3744c5SMatthew G. Knepley   PetscErrorCode ierr;
17154e3744c5SMatthew G. Knepley 
17164e3744c5SMatthew G. Knepley   PetscFunctionBegin;
171743eeeb2dSStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
171843eeeb2dSStefano Zampini   PetscValidPointer(dmUnint, 2);
1719c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1720827c4036SVaclav Hapla   ierr = DMPlexIsInterpolated(dm, &interpolated);CHKERRQ(ierr);
1721827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_PARTIAL) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes");
1722827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_NONE || dim <= 1) {
1723827c4036SVaclav Hapla     /* in case dim <= 1 just keep the DMPLEX_INTERPOLATED_FULL flag */
17244e3744c5SMatthew G. Knepley     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
1725595d4abbSMatthew G. Knepley     *dmUnint = dm;
1726595d4abbSMatthew G. Knepley     PetscFunctionReturn(0);
17274e3744c5SMatthew G. Knepley   }
1728595d4abbSMatthew G. Knepley   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1729595d4abbSMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1730c9f63434SStefano Zampini   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
17314e3744c5SMatthew G. Knepley   ierr = DMCreate(PetscObjectComm((PetscObject) dm), &udm);CHKERRQ(ierr);
17324e3744c5SMatthew G. Knepley   ierr = DMSetType(udm, DMPLEX);CHKERRQ(ierr);
1733c73cfb54SMatthew G. Knepley   ierr = DMSetDimension(udm, dim);CHKERRQ(ierr);
17344e3744c5SMatthew G. Knepley   ierr = DMPlexSetChart(udm, cStart, vEnd);CHKERRQ(ierr);
17354e3744c5SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1736595d4abbSMatthew G. Knepley     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
17374e3744c5SMatthew G. Knepley 
17384e3744c5SMatthew G. Knepley     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
17394e3744c5SMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
17404e3744c5SMatthew G. Knepley       const PetscInt p = closure[cl];
17414e3744c5SMatthew G. Knepley 
17424e3744c5SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++coneSize;
17434e3744c5SMatthew G. Knepley     }
17444e3744c5SMatthew G. Knepley     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
17454e3744c5SMatthew G. Knepley     ierr = DMPlexSetConeSize(udm, c, coneSize);CHKERRQ(ierr);
1746595d4abbSMatthew G. Knepley     maxConeSize = PetscMax(maxConeSize, coneSize);
17474e3744c5SMatthew G. Knepley   }
17484e3744c5SMatthew G. Knepley   ierr = DMSetUp(udm);CHKERRQ(ierr);
1749785e854fSJed Brown   ierr = PetscMalloc1(maxConeSize, &cone);CHKERRQ(ierr);
17504e3744c5SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1751595d4abbSMatthew G. Knepley     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
17524e3744c5SMatthew G. Knepley 
17534e3744c5SMatthew G. Knepley     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
17544e3744c5SMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
17554e3744c5SMatthew G. Knepley       const PetscInt p = closure[cl];
17564e3744c5SMatthew G. Knepley 
17574e3744c5SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) cone[coneSize++] = p;
17584e3744c5SMatthew G. Knepley     }
17594e3744c5SMatthew G. Knepley     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
17604e3744c5SMatthew G. Knepley     ierr = DMPlexSetCone(udm, c, cone);CHKERRQ(ierr);
17614e3744c5SMatthew G. Knepley   }
17624e3744c5SMatthew G. Knepley   ierr = PetscFree(cone);CHKERRQ(ierr);
1763c9f63434SStefano Zampini   ierr = DMPlexSetHybridBounds(udm, cMax, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
17644e3744c5SMatthew G. Knepley   ierr = DMPlexSymmetrize(udm);CHKERRQ(ierr);
17654e3744c5SMatthew G. Knepley   ierr = DMPlexStratify(udm);CHKERRQ(ierr);
17665c7de58aSMatthew G. Knepley   /* Reduce SF */
17675c7de58aSMatthew G. Knepley   {
17685c7de58aSMatthew G. Knepley     PetscSF            sfPoint, sfPointUn;
17695c7de58aSMatthew G. Knepley     const PetscSFNode *remotePoints;
17705c7de58aSMatthew G. Knepley     const PetscInt    *localPoints;
17715c7de58aSMatthew G. Knepley     PetscSFNode       *remotePointsUn;
17725c7de58aSMatthew G. Knepley     PetscInt          *localPointsUn;
17735c7de58aSMatthew G. Knepley     PetscInt           vEnd, numRoots, numLeaves, l;
17745c7de58aSMatthew G. Knepley     PetscInt           numLeavesUn = 0, n = 0;
17755c7de58aSMatthew G. Knepley     PetscErrorCode     ierr;
17765c7de58aSMatthew G. Knepley 
17775c7de58aSMatthew G. Knepley     /* Get original SF information */
17785c7de58aSMatthew G. Knepley     ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
17795c7de58aSMatthew G. Knepley     ierr = DMGetPointSF(udm, &sfPointUn);CHKERRQ(ierr);
17805c7de58aSMatthew G. Knepley     ierr = DMPlexGetDepthStratum(dm, 0, NULL, &vEnd);CHKERRQ(ierr);
17815c7de58aSMatthew G. Knepley     ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
17825c7de58aSMatthew G. Knepley     /* Allocate space for cells and vertices */
17835c7de58aSMatthew G. Knepley     for (l = 0; l < numLeaves; ++l) if (localPoints[l] < vEnd) numLeavesUn++;
17845c7de58aSMatthew G. Knepley     /* Fill in leaves */
17855c7de58aSMatthew G. Knepley     if (vEnd >= 0) {
17865c7de58aSMatthew G. Knepley       ierr = PetscMalloc1(numLeavesUn, &remotePointsUn);CHKERRQ(ierr);
17875c7de58aSMatthew G. Knepley       ierr = PetscMalloc1(numLeavesUn, &localPointsUn);CHKERRQ(ierr);
17885c7de58aSMatthew G. Knepley       for (l = 0; l < numLeaves; l++) {
17895c7de58aSMatthew G. Knepley         if (localPoints[l] < vEnd) {
17905c7de58aSMatthew G. Knepley           localPointsUn[n]        = localPoints[l];
17915c7de58aSMatthew G. Knepley           remotePointsUn[n].rank  = remotePoints[l].rank;
17925c7de58aSMatthew G. Knepley           remotePointsUn[n].index = remotePoints[l].index;
17935c7de58aSMatthew G. Knepley           ++n;
17945c7de58aSMatthew G. Knepley         }
17955c7de58aSMatthew G. Knepley       }
17965c7de58aSMatthew G. Knepley       if (n != numLeavesUn) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent number of leaves %d != %d", n, numLeavesUn);
17975c7de58aSMatthew G. Knepley       ierr = PetscSFSetGraph(sfPointUn, vEnd, numLeavesUn, localPointsUn, PETSC_OWN_POINTER, remotePointsUn, PETSC_OWN_POINTER);CHKERRQ(ierr);
17985c7de58aSMatthew G. Knepley     }
17995c7de58aSMatthew G. Knepley   }
180043eeeb2dSStefano Zampini   {
180143eeeb2dSStefano Zampini     PetscBool            isper;
180243eeeb2dSStefano Zampini     const PetscReal      *maxCell, *L;
180343eeeb2dSStefano Zampini     const DMBoundaryType *bd;
180443eeeb2dSStefano Zampini 
180543eeeb2dSStefano Zampini     ierr = DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd);CHKERRQ(ierr);
180643eeeb2dSStefano Zampini     ierr = DMSetPeriodicity(udm,isper,maxCell,L,bd);CHKERRQ(ierr);
180743eeeb2dSStefano Zampini   }
1808827c4036SVaclav Hapla   /* This function makes the mesh fully uninterpolated on all ranks */
1809827c4036SVaclav Hapla   {
1810d6e9e4f7SVaclav Hapla     DM_Plex *plex = (DM_Plex *) udm->data;
1811827c4036SVaclav Hapla     plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_NONE;
1812827c4036SVaclav Hapla   }
18134e3744c5SMatthew G. Knepley   *dmUnint = udm;
18144e3744c5SMatthew G. Knepley   PetscFunctionReturn(0);
18154e3744c5SMatthew G. Knepley }
1816a7748839SVaclav Hapla 
1817a7748839SVaclav Hapla static PetscErrorCode DMPlexIsInterpolated_Internal(DM dm, DMPlexInterpolatedFlag *interpolated)
1818a7748839SVaclav Hapla {
1819a7748839SVaclav Hapla   PetscInt       coneSize, depth, dim, h, p, pStart, pEnd;
1820a7748839SVaclav Hapla   MPI_Comm       comm;
1821a7748839SVaclav Hapla   PetscErrorCode ierr;
1822a7748839SVaclav Hapla 
1823a7748839SVaclav Hapla   PetscFunctionBegin;
1824a7748839SVaclav Hapla   ierr = PetscObjectGetComm((PetscObject)dm, &comm);CHKERRQ(ierr);
1825a7748839SVaclav Hapla   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1826a7748839SVaclav Hapla   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1827a7748839SVaclav Hapla 
1828a7748839SVaclav Hapla   if (depth == dim) {
1829a7748839SVaclav Hapla     *interpolated = DMPLEX_INTERPOLATED_FULL;
1830a7748839SVaclav Hapla     if (!dim) goto finish;
1831a7748839SVaclav Hapla 
1832a7748839SVaclav Hapla     /* Check points at height = dim are vertices (have no cones) */
1833a7748839SVaclav Hapla     ierr = DMPlexGetHeightStratum(dm, dim, &pStart, &pEnd);CHKERRQ(ierr);
1834a7748839SVaclav Hapla     for (p=pStart; p<pEnd; p++) {
1835a7748839SVaclav Hapla       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1836a7748839SVaclav Hapla       if (coneSize) {
1837a7748839SVaclav Hapla         *interpolated = DMPLEX_INTERPOLATED_PARTIAL;
1838a7748839SVaclav Hapla         goto finish;
1839a7748839SVaclav Hapla       }
1840a7748839SVaclav Hapla     }
1841a7748839SVaclav Hapla 
1842a7748839SVaclav Hapla     /* Check points at height < dim have cones */
1843a7748839SVaclav Hapla     for (h=0; h<dim; h++) {
1844a7748839SVaclav Hapla       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1845a7748839SVaclav Hapla       for (p=pStart; p<pEnd; p++) {
1846a7748839SVaclav Hapla         ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1847a7748839SVaclav Hapla         if (!coneSize) {
1848a7748839SVaclav Hapla           *interpolated = DMPLEX_INTERPOLATED_PARTIAL;
1849a7748839SVaclav Hapla           goto finish;
1850a7748839SVaclav Hapla         }
1851a7748839SVaclav Hapla       }
1852a7748839SVaclav Hapla     }
1853a7748839SVaclav Hapla   } else if (depth == 1) {
1854a7748839SVaclav Hapla     *interpolated = DMPLEX_INTERPOLATED_NONE;
1855a7748839SVaclav Hapla   } else {
1856a7748839SVaclav Hapla     *interpolated = DMPLEX_INTERPOLATED_PARTIAL;
1857a7748839SVaclav Hapla   }
1858a7748839SVaclav Hapla finish:
1859a7748839SVaclav Hapla   PetscFunctionReturn(0);
1860a7748839SVaclav Hapla }
1861a7748839SVaclav Hapla 
1862a7748839SVaclav Hapla /*@
18639ade3219SVaclav Hapla   DMPlexIsInterpolated - Find out to what extent the DMPlex is topologically interpolated.
1864a7748839SVaclav Hapla 
1865a7748839SVaclav Hapla   Not Collective
1866a7748839SVaclav Hapla 
1867a7748839SVaclav Hapla   Input Parameter:
1868a7748839SVaclav Hapla . dm      - The DM object
1869a7748839SVaclav Hapla 
1870a7748839SVaclav Hapla   Output Parameter:
1871a7748839SVaclav Hapla . interpolated - Flag whether the DM is interpolated
1872a7748839SVaclav Hapla 
1873a7748839SVaclav Hapla   Level: intermediate
1874a7748839SVaclav Hapla 
1875a7748839SVaclav Hapla   Notes:
18769ade3219SVaclav Hapla   Unlike DMPlexIsInterpolatedCollective(), this is NOT collective
18779ade3219SVaclav Hapla   so the results can be different on different ranks in special cases.
1878a7748839SVaclav Hapla   However, DMPlexInterpolate() guarantees the result is the same on all.
18799ade3219SVaclav Hapla 
1880a7748839SVaclav Hapla   Unlike DMPlexIsInterpolatedCollective(), this cannot return DMPLEX_INTERPOLATED_MIXED.
1881a7748839SVaclav Hapla 
18829ade3219SVaclav Hapla   Developer Notes:
18839ade3219SVaclav Hapla   Initially, plex->interpolated = DMPLEX_INTERPOLATED_INVALID.
18849ade3219SVaclav Hapla 
18859ade3219SVaclav Hapla   If plex->interpolated == DMPLEX_INTERPOLATED_INVALID, DMPlexIsInterpolated_Internal() is called.
18869ade3219SVaclav Hapla   It checks the actual topology and sets plex->interpolated on each rank separately to one of
18879ade3219SVaclav Hapla   DMPLEX_INTERPOLATED_NONE, DMPLEX_INTERPOLATED_PARTIAL or DMPLEX_INTERPOLATED_FULL.
18889ade3219SVaclav Hapla 
18899ade3219SVaclav Hapla   If plex->interpolated != DMPLEX_INTERPOLATED_INVALID, this function just returns plex->interpolated.
18909ade3219SVaclav Hapla 
18919ade3219SVaclav Hapla   DMPlexInterpolate() sets plex->interpolated = DMPLEX_INTERPOLATED_FULL,
18929ade3219SVaclav Hapla   and DMPlexUninterpolate() sets plex->interpolated = DMPLEX_INTERPOLATED_NONE.
18939ade3219SVaclav Hapla 
1894a7748839SVaclav Hapla .seealso: DMPlexInterpolate(), DMPlexIsInterpolatedCollective()
1895a7748839SVaclav Hapla @*/
1896a7748839SVaclav Hapla PetscErrorCode DMPlexIsInterpolated(DM dm, DMPlexInterpolatedFlag *interpolated)
1897a7748839SVaclav Hapla {
1898a7748839SVaclav Hapla   DM_Plex        *plex = (DM_Plex *) dm->data;
1899a7748839SVaclav Hapla   PetscErrorCode  ierr;
1900a7748839SVaclav Hapla 
1901a7748839SVaclav Hapla   PetscFunctionBegin;
1902a7748839SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1903a7748839SVaclav Hapla   PetscValidPointer(interpolated,2);
1904a7748839SVaclav Hapla   if (plex->interpolated < 0) {
1905a7748839SVaclav Hapla     ierr = DMPlexIsInterpolated_Internal(dm, &plex->interpolated);CHKERRQ(ierr);
1906a7748839SVaclav Hapla   } else {
1907a7748839SVaclav Hapla #if defined (PETSC_USE_DEBUG)
1908a7748839SVaclav Hapla     DMPlexInterpolatedFlag flg;
1909a7748839SVaclav Hapla 
1910a7748839SVaclav Hapla     ierr = DMPlexIsInterpolated_Internal(dm, &flg);CHKERRQ(ierr);
19117fc06600SVaclav Hapla     if (flg != plex->interpolated) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Stashed DMPlexInterpolatedFlag %s is inconsistent with current %s", DMPlexInterpolatedFlags[plex->interpolated], DMPlexInterpolatedFlags[flg]);
1912a7748839SVaclav Hapla #endif
1913a7748839SVaclav Hapla   }
1914a7748839SVaclav Hapla   *interpolated = plex->interpolated;
1915a7748839SVaclav Hapla   PetscFunctionReturn(0);
1916a7748839SVaclav Hapla }
1917a7748839SVaclav Hapla 
1918a7748839SVaclav Hapla /*@
19199ade3219SVaclav Hapla   DMPlexIsInterpolatedCollective - Find out to what extent the DMPlex is topologically interpolated (in collective manner).
1920a7748839SVaclav Hapla 
19212666ff3cSVaclav Hapla   Collective
1922a7748839SVaclav Hapla 
1923a7748839SVaclav Hapla   Input Parameter:
1924a7748839SVaclav Hapla . dm      - The DM object
1925a7748839SVaclav Hapla 
1926a7748839SVaclav Hapla   Output Parameter:
1927a7748839SVaclav Hapla . interpolated - Flag whether the DM is interpolated
1928a7748839SVaclav Hapla 
1929a7748839SVaclav Hapla   Level: intermediate
1930a7748839SVaclav Hapla 
1931a7748839SVaclav Hapla   Notes:
19329ade3219SVaclav Hapla   Unlike DMPlexIsInterpolated(), this is collective so the results are guaranteed to be the same on all ranks.
19339ade3219SVaclav Hapla 
19349ade3219SVaclav Hapla   This function will return DMPLEX_INTERPOLATED_MIXED if the results of DMPlexIsInterpolated() are different on different ranks.
19359ade3219SVaclav Hapla 
19369ade3219SVaclav Hapla   Developer Notes:
19379ade3219SVaclav Hapla   Initially, plex->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID.
19389ade3219SVaclav Hapla 
19399ade3219SVaclav Hapla   If plex->interpolatedCollective == DMPLEX_INTERPOLATED_INVALID, this function calls DMPlexIsInterpolated() which sets plex->interpolated.
19409ade3219SVaclav Hapla   MPI_Allreduce() is then called and collectively consistent flag plex->interpolatedCollective is set and returned;
19419ade3219SVaclav Hapla   if plex->interpolated varies on different ranks, plex->interpolatedCollective = DMPLEX_INTERPOLATED_MIXED,
19429ade3219SVaclav Hapla   otherwise sets plex->interpolatedCollective = plex->interpolated.
19439ade3219SVaclav Hapla 
19449ade3219SVaclav Hapla   If plex->interpolatedCollective != DMPLEX_INTERPOLATED_INVALID, this function just returns plex->interpolatedCollective.
1945a7748839SVaclav Hapla 
1946a7748839SVaclav Hapla .seealso: DMPlexInterpolate(), DMPlexIsInterpolated()
1947a7748839SVaclav Hapla @*/
1948a7748839SVaclav Hapla PetscErrorCode DMPlexIsInterpolatedCollective(DM dm, DMPlexInterpolatedFlag *interpolated)
1949a7748839SVaclav Hapla {
1950a7748839SVaclav Hapla   DM_Plex        *plex = (DM_Plex *) dm->data;
1951a7748839SVaclav Hapla   PetscBool       debug=PETSC_FALSE;
1952a7748839SVaclav Hapla   PetscErrorCode  ierr;
1953a7748839SVaclav Hapla 
1954a7748839SVaclav Hapla   PetscFunctionBegin;
1955a7748839SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1956a7748839SVaclav Hapla   PetscValidPointer(interpolated,2);
1957a7748839SVaclav Hapla   ierr = PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_is_interpolated_collective_debug", &debug, NULL);CHKERRQ(ierr);
1958a7748839SVaclav Hapla   if (plex->interpolatedCollective < 0) {
1959a7748839SVaclav Hapla     DMPlexInterpolatedFlag  min, max;
1960a7748839SVaclav Hapla     MPI_Comm                comm;
1961a7748839SVaclav Hapla 
1962a7748839SVaclav Hapla     ierr = PetscObjectGetComm((PetscObject)dm, &comm);CHKERRQ(ierr);
1963a7748839SVaclav Hapla     ierr = DMPlexIsInterpolated(dm, &plex->interpolatedCollective);CHKERRQ(ierr);
1964a7748839SVaclav Hapla     ierr = MPI_Allreduce(&plex->interpolatedCollective, &min, 1, MPIU_ENUM, MPI_MIN, comm);CHKERRQ(ierr);
1965a7748839SVaclav Hapla     ierr = MPI_Allreduce(&plex->interpolatedCollective, &max, 1, MPIU_ENUM, MPI_MAX, comm);CHKERRQ(ierr);
1966a7748839SVaclav Hapla     if (min != max) plex->interpolatedCollective = DMPLEX_INTERPOLATED_MIXED;
1967a7748839SVaclav Hapla     if (debug) {
1968a7748839SVaclav Hapla       PetscMPIInt rank;
1969a7748839SVaclav Hapla 
1970a7748839SVaclav Hapla       ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1971a7748839SVaclav Hapla       ierr = PetscSynchronizedPrintf(comm, "[%d] interpolated=%s interpolatedCollective=%s\n", rank, DMPlexInterpolatedFlags[plex->interpolated], DMPlexInterpolatedFlags[plex->interpolatedCollective]);CHKERRQ(ierr);
1972a7748839SVaclav Hapla       ierr = PetscSynchronizedFlush(comm, PETSC_STDOUT);CHKERRQ(ierr);
1973a7748839SVaclav Hapla     }
1974a7748839SVaclav Hapla   }
1975a7748839SVaclav Hapla   *interpolated = plex->interpolatedCollective;
1976a7748839SVaclav Hapla   PetscFunctionReturn(0);
1977a7748839SVaclav Hapla }
1978