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 5ea78f98cSLisandro Dalcin const char * const DMPlexInterpolatedFlags[] = {"none", "partial", "mixed", "full", "DMPlexInterpolatedFlag", "DMPLEX_INTERPOLATED_", NULL}; 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 20999739cfSJacob Faibussowitsch PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PETSC_HASH_MAP(HashIJKL, PetscHashIJKLKey, PetscInt, PetscHashIJKLKeyHash, PetscHashIJKLKeyEqual, -1)) 21e8f14785SLisandro Dalcin 223be36e83SMatthew G. Knepley static PetscSFNode _PetscInvalidSFNode = {-1, -1}; 233be36e83SMatthew G. Knepley 243be36e83SMatthew G. Knepley typedef struct _PetscHashIJKLRemoteKey { PetscSFNode i, j, k, l; } PetscHashIJKLRemoteKey; 253be36e83SMatthew G. Knepley 263be36e83SMatthew G. Knepley #define PetscHashIJKLRemoteKeyHash(key) \ 273be36e83SMatthew G. Knepley PetscHashCombine(PetscHashCombine(PetscHashInt((key).i.rank + (key).i.index),PetscHashInt((key).j.rank + (key).j.index)), \ 283be36e83SMatthew G. Knepley PetscHashCombine(PetscHashInt((key).k.rank + (key).k.index),PetscHashInt((key).l.rank + (key).l.index))) 293be36e83SMatthew G. Knepley 303be36e83SMatthew G. Knepley #define PetscHashIJKLRemoteKeyEqual(k1,k2) \ 313be36e83SMatthew 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) 323be36e83SMatthew G. Knepley 33999739cfSJacob Faibussowitsch PetscDisableStaticAnalyzerForExpressionUnderstandingThatThisIsDangerousAndBugprone(PETSC_HASH_MAP(HashIJKLRemote, PetscHashIJKLRemoteKey, PetscSFNode, PetscHashIJKLRemoteKeyHash, PetscHashIJKLRemoteKeyEqual, _PetscInvalidSFNode)) 343be36e83SMatthew G. Knepley 353be36e83SMatthew G. Knepley static PetscErrorCode PetscSortSFNode(PetscInt n, PetscSFNode A[]) 363be36e83SMatthew G. Knepley { 373be36e83SMatthew G. Knepley PetscInt i; 383be36e83SMatthew G. Knepley 393be36e83SMatthew G. Knepley PetscFunctionBegin; 403be36e83SMatthew G. Knepley for (i = 1; i < n; ++i) { 413be36e83SMatthew G. Knepley PetscSFNode x = A[i]; 423be36e83SMatthew G. Knepley PetscInt j; 433be36e83SMatthew G. Knepley 443be36e83SMatthew G. Knepley for (j = i-1; j >= 0; --j) { 453be36e83SMatthew G. Knepley if ((A[j].rank > x.rank) || (A[j].rank == x.rank && A[j].index > x.index)) break; 463be36e83SMatthew G. Knepley A[j+1] = A[j]; 473be36e83SMatthew G. Knepley } 483be36e83SMatthew G. Knepley A[j+1] = x; 493be36e83SMatthew G. Knepley } 503be36e83SMatthew G. Knepley PetscFunctionReturn(0); 513be36e83SMatthew G. Knepley } 529f074e33SMatthew G Knepley 539f074e33SMatthew G Knepley /* 54439ece16SMatthew G. Knepley DMPlexGetRawFaces_Internal - Gets groups of vertices that correspond to faces for the given cone 55439ece16SMatthew G. Knepley */ 56412e9a14SMatthew G. Knepley PetscErrorCode DMPlexGetRawFaces_Internal(DM dm, DMPolytopeType ct, const PetscInt cone[], PetscInt *numFaces, const DMPolytopeType *faceTypes[], const PetscInt *faceSizes[], const PetscInt *faces[]) 57439ece16SMatthew G. Knepley { 58412e9a14SMatthew G. Knepley DMPolytopeType *typesTmp; 59412e9a14SMatthew G. Knepley PetscInt *sizesTmp, *facesTmp; 60439ece16SMatthew G. Knepley PetscInt maxConeSize, maxSupportSize; 61439ece16SMatthew G. Knepley 62439ece16SMatthew G. Knepley PetscFunctionBegin; 63439ece16SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 64ba2698f1SMatthew G. Knepley if (cone) PetscValidIntPointer(cone, 3); 659566063dSJacob Faibussowitsch PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 669566063dSJacob Faibussowitsch if (faceTypes) PetscCall(DMGetWorkArray(dm, PetscMax(maxConeSize, maxSupportSize), MPIU_INT, &typesTmp)); 679566063dSJacob Faibussowitsch if (faceSizes) PetscCall(DMGetWorkArray(dm, PetscMax(maxConeSize, maxSupportSize), MPIU_INT, &sizesTmp)); 689566063dSJacob Faibussowitsch if (faces) PetscCall(DMGetWorkArray(dm, PetscSqr(PetscMax(maxConeSize, maxSupportSize)), MPIU_INT, &facesTmp)); 69ba2698f1SMatthew G. Knepley switch (ct) { 70ba2698f1SMatthew G. Knepley case DM_POLYTOPE_POINT: 71ba2698f1SMatthew G. Knepley if (numFaces) *numFaces = 0; 72ba2698f1SMatthew G. Knepley break; 73ba2698f1SMatthew G. Knepley case DM_POLYTOPE_SEGMENT: 74412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 2; 75412e9a14SMatthew G. Knepley if (faceTypes) { 76412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_POINT; typesTmp[1] = DM_POLYTOPE_POINT; 77412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 78412e9a14SMatthew G. Knepley } 79412e9a14SMatthew G. Knepley if (faceSizes) { 80412e9a14SMatthew G. Knepley sizesTmp[0] = 1; sizesTmp[1] = 1; 81412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 82412e9a14SMatthew G. Knepley } 83c49d9212SMatthew G. Knepley if (faces) { 84c49d9212SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; 85c49d9212SMatthew G. Knepley *faces = facesTmp; 86c49d9212SMatthew G. Knepley } 87412e9a14SMatthew G. Knepley break; 88412e9a14SMatthew G. Knepley case DM_POLYTOPE_POINT_PRISM_TENSOR: 89c49d9212SMatthew G. Knepley if (numFaces) *numFaces = 2; 90412e9a14SMatthew G. Knepley if (faceTypes) { 91412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_POINT; typesTmp[1] = DM_POLYTOPE_POINT; 92412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 93412e9a14SMatthew G. Knepley } 94412e9a14SMatthew G. Knepley if (faceSizes) { 95412e9a14SMatthew G. Knepley sizesTmp[0] = 1; sizesTmp[1] = 1; 96412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 97412e9a14SMatthew G. Knepley } 98412e9a14SMatthew G. Knepley if (faces) { 99412e9a14SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; 100412e9a14SMatthew G. Knepley *faces = facesTmp; 101412e9a14SMatthew G. Knepley } 102c49d9212SMatthew G. Knepley break; 103ba2698f1SMatthew G. Knepley case DM_POLYTOPE_TRIANGLE: 104412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 3; 105412e9a14SMatthew G. Knepley if (faceTypes) { 106412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_SEGMENT; typesTmp[1] = DM_POLYTOPE_SEGMENT; typesTmp[2] = DM_POLYTOPE_SEGMENT; 107412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 108412e9a14SMatthew G. Knepley } 109412e9a14SMatthew G. Knepley if (faceSizes) { 110412e9a14SMatthew G. Knepley sizesTmp[0] = 2; sizesTmp[1] = 2; sizesTmp[2] = 2; 111412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 112412e9a14SMatthew G. Knepley } 1139a5b13a2SMatthew G Knepley if (faces) { 1149a5b13a2SMatthew G Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; 1159a5b13a2SMatthew G Knepley facesTmp[2] = cone[1]; facesTmp[3] = cone[2]; 1169a5b13a2SMatthew G Knepley facesTmp[4] = cone[2]; facesTmp[5] = cone[0]; 1179a5b13a2SMatthew G Knepley *faces = facesTmp; 1189a5b13a2SMatthew G Knepley } 1199f074e33SMatthew G Knepley break; 120ba2698f1SMatthew G. Knepley case DM_POLYTOPE_QUADRILATERAL: 1219a5b13a2SMatthew G Knepley /* Vertices follow right hand rule */ 122412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 4; 123412e9a14SMatthew G. Knepley if (faceTypes) { 124412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_SEGMENT; typesTmp[1] = DM_POLYTOPE_SEGMENT; typesTmp[2] = DM_POLYTOPE_SEGMENT; typesTmp[3] = DM_POLYTOPE_SEGMENT; 125412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 126412e9a14SMatthew G. Knepley } 127412e9a14SMatthew G. Knepley if (faceSizes) { 128412e9a14SMatthew G. Knepley sizesTmp[0] = 2; sizesTmp[1] = 2; sizesTmp[2] = 2; sizesTmp[3] = 2; 129412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 130412e9a14SMatthew G. Knepley } 1319a5b13a2SMatthew G Knepley if (faces) { 1329a5b13a2SMatthew G Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; 1339a5b13a2SMatthew G Knepley facesTmp[2] = cone[1]; facesTmp[3] = cone[2]; 1349a5b13a2SMatthew G Knepley facesTmp[4] = cone[2]; facesTmp[5] = cone[3]; 1359a5b13a2SMatthew G Knepley facesTmp[6] = cone[3]; facesTmp[7] = cone[0]; 1369a5b13a2SMatthew G Knepley *faces = facesTmp; 1379a5b13a2SMatthew G Knepley } 138412e9a14SMatthew G. Knepley break; 139412e9a14SMatthew G. Knepley case DM_POLYTOPE_SEG_PRISM_TENSOR: 1409a5b13a2SMatthew G Knepley if (numFaces) *numFaces = 4; 141412e9a14SMatthew G. Knepley if (faceTypes) { 142412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_SEGMENT; typesTmp[1] = DM_POLYTOPE_SEGMENT; typesTmp[2] = DM_POLYTOPE_POINT_PRISM_TENSOR; typesTmp[3] = DM_POLYTOPE_POINT_PRISM_TENSOR; 143412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 144412e9a14SMatthew G. Knepley } 145412e9a14SMatthew G. Knepley if (faceSizes) { 146412e9a14SMatthew G. Knepley sizesTmp[0] = 2; sizesTmp[1] = 2; sizesTmp[2] = 2; sizesTmp[3] = 2; 147412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 148412e9a14SMatthew G. Knepley } 149412e9a14SMatthew G. Knepley if (faces) { 150412e9a14SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; 151412e9a14SMatthew G. Knepley facesTmp[2] = cone[2]; facesTmp[3] = cone[3]; 152412e9a14SMatthew G. Knepley facesTmp[4] = cone[0]; facesTmp[5] = cone[2]; 153412e9a14SMatthew G. Knepley facesTmp[6] = cone[1]; facesTmp[7] = cone[3]; 154412e9a14SMatthew G. Knepley *faces = facesTmp; 155412e9a14SMatthew G. Knepley } 1569f074e33SMatthew G Knepley break; 157ba2698f1SMatthew G. Knepley case DM_POLYTOPE_TETRAHEDRON: 1582e1b13c2SMatthew G. Knepley /* Vertices of first face follow right hand rule and normal points away from last vertex */ 159412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 4; 160412e9a14SMatthew G. Knepley if (faceTypes) { 161412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_TRIANGLE; typesTmp[1] = DM_POLYTOPE_TRIANGLE; typesTmp[2] = DM_POLYTOPE_TRIANGLE; typesTmp[3] = DM_POLYTOPE_TRIANGLE; 162412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 163412e9a14SMatthew G. Knepley } 164412e9a14SMatthew G. Knepley if (faceSizes) { 165412e9a14SMatthew G. Knepley sizesTmp[0] = 3; sizesTmp[1] = 3; sizesTmp[2] = 3; sizesTmp[3] = 3; 166412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 167412e9a14SMatthew G. Knepley } 1689a5b13a2SMatthew G Knepley if (faces) { 1692e1b13c2SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; facesTmp[2] = cone[2]; 1702e1b13c2SMatthew G. Knepley facesTmp[3] = cone[0]; facesTmp[4] = cone[3]; facesTmp[5] = cone[1]; 1712e1b13c2SMatthew G. Knepley facesTmp[6] = cone[0]; facesTmp[7] = cone[2]; facesTmp[8] = cone[3]; 1722e1b13c2SMatthew G. Knepley facesTmp[9] = cone[2]; facesTmp[10] = cone[1]; facesTmp[11] = cone[3]; 1739a5b13a2SMatthew G Knepley *faces = facesTmp; 1749a5b13a2SMatthew G Knepley } 1759a5b13a2SMatthew G Knepley break; 176ba2698f1SMatthew G. Knepley case DM_POLYTOPE_HEXAHEDRON: 177e368ef20SMatthew G. Knepley /* 7--------6 178e368ef20SMatthew G. Knepley /| /| 179e368ef20SMatthew G. Knepley / | / | 180e368ef20SMatthew G. Knepley 4--------5 | 181e368ef20SMatthew G. Knepley | | | | 182e368ef20SMatthew G. Knepley | | | | 183e368ef20SMatthew G. Knepley | 1--------2 184e368ef20SMatthew G. Knepley | / | / 185e368ef20SMatthew G. Knepley |/ |/ 186e368ef20SMatthew G. Knepley 0--------3 187e368ef20SMatthew G. Knepley */ 188412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 6; 189412e9a14SMatthew G. Knepley if (faceTypes) { 190412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_QUADRILATERAL; typesTmp[1] = DM_POLYTOPE_QUADRILATERAL; typesTmp[2] = DM_POLYTOPE_QUADRILATERAL; 191412e9a14SMatthew G. Knepley typesTmp[3] = DM_POLYTOPE_QUADRILATERAL; typesTmp[4] = DM_POLYTOPE_QUADRILATERAL; typesTmp[5] = DM_POLYTOPE_QUADRILATERAL; 192412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 193412e9a14SMatthew G. Knepley } 194412e9a14SMatthew G. Knepley if (faceSizes) { 195412e9a14SMatthew G. Knepley sizesTmp[0] = 4; sizesTmp[1] = 4; sizesTmp[2] = 4; sizesTmp[3] = 4; sizesTmp[4] = 4; sizesTmp[5] = 4; 196412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 197412e9a14SMatthew G. Knepley } 1989a5b13a2SMatthew G Knepley if (faces) { 19951cfd6a4SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; facesTmp[2] = cone[2]; facesTmp[3] = cone[3]; /* Bottom */ 20051cfd6a4SMatthew G. Knepley facesTmp[4] = cone[4]; facesTmp[5] = cone[5]; facesTmp[6] = cone[6]; facesTmp[7] = cone[7]; /* Top */ 20151cfd6a4SMatthew G. Knepley facesTmp[8] = cone[0]; facesTmp[9] = cone[3]; facesTmp[10] = cone[5]; facesTmp[11] = cone[4]; /* Front */ 20251cfd6a4SMatthew G. Knepley facesTmp[12] = cone[2]; facesTmp[13] = cone[1]; facesTmp[14] = cone[7]; facesTmp[15] = cone[6]; /* Back */ 20351cfd6a4SMatthew G. Knepley facesTmp[16] = cone[3]; facesTmp[17] = cone[2]; facesTmp[18] = cone[6]; facesTmp[19] = cone[5]; /* Right */ 20451cfd6a4SMatthew G. Knepley facesTmp[20] = cone[0]; facesTmp[21] = cone[4]; facesTmp[22] = cone[7]; facesTmp[23] = cone[1]; /* Left */ 2059a5b13a2SMatthew G Knepley *faces = facesTmp; 2069a5b13a2SMatthew G Knepley } 20799836e0eSStefano Zampini break; 208ba2698f1SMatthew G. Knepley case DM_POLYTOPE_TRI_PRISM: 209412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 5; 210412e9a14SMatthew G. Knepley if (faceTypes) { 211412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_TRIANGLE; typesTmp[1] = DM_POLYTOPE_TRIANGLE; 212412e9a14SMatthew G. Knepley typesTmp[2] = DM_POLYTOPE_QUADRILATERAL; typesTmp[3] = DM_POLYTOPE_QUADRILATERAL; typesTmp[4] = DM_POLYTOPE_QUADRILATERAL; 213412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 214412e9a14SMatthew G. Knepley } 215412e9a14SMatthew G. Knepley if (faceSizes) { 216412e9a14SMatthew G. Knepley sizesTmp[0] = 3; sizesTmp[1] = 3; 217412e9a14SMatthew G. Knepley sizesTmp[2] = 4; sizesTmp[3] = 4; sizesTmp[4] = 4; 218412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 219412e9a14SMatthew G. Knepley } 220ba2698f1SMatthew G. Knepley if (faces) { 221412e9a14SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; facesTmp[2] = cone[2]; /* Bottom */ 222412e9a14SMatthew G. Knepley facesTmp[3] = cone[3]; facesTmp[4] = cone[4]; facesTmp[5] = cone[5]; /* Top */ 223412e9a14SMatthew G. Knepley facesTmp[6] = cone[0]; facesTmp[7] = cone[2]; facesTmp[8] = cone[4]; facesTmp[9] = cone[3]; /* Back left */ 224412e9a14SMatthew G. Knepley facesTmp[10] = cone[2]; facesTmp[11] = cone[1]; facesTmp[12] = cone[5]; facesTmp[13] = cone[4]; /* Front */ 225412e9a14SMatthew G. Knepley facesTmp[14] = cone[1]; facesTmp[15] = cone[0]; facesTmp[16] = cone[3]; facesTmp[17] = cone[5]; /* Back right */ 226ba2698f1SMatthew G. Knepley *faces = facesTmp; 22799836e0eSStefano Zampini } 22899836e0eSStefano Zampini break; 229ba2698f1SMatthew G. Knepley case DM_POLYTOPE_TRI_PRISM_TENSOR: 230412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 5; 231412e9a14SMatthew G. Knepley if (faceTypes) { 232412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_TRIANGLE; typesTmp[1] = DM_POLYTOPE_TRIANGLE; 233412e9a14SMatthew G. Knepley typesTmp[2] = DM_POLYTOPE_SEG_PRISM_TENSOR; typesTmp[3] = DM_POLYTOPE_SEG_PRISM_TENSOR; typesTmp[4] = DM_POLYTOPE_SEG_PRISM_TENSOR; 234412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 235412e9a14SMatthew G. Knepley } 236412e9a14SMatthew G. Knepley if (faceSizes) { 237412e9a14SMatthew G. Knepley sizesTmp[0] = 3; sizesTmp[1] = 3; 238412e9a14SMatthew G. Knepley sizesTmp[2] = 4; sizesTmp[3] = 4; sizesTmp[4] = 4; 239412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 240412e9a14SMatthew G. Knepley } 24199836e0eSStefano Zampini if (faces) { 242412e9a14SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; facesTmp[2] = cone[2]; /* Bottom */ 243412e9a14SMatthew G. Knepley facesTmp[3] = cone[3]; facesTmp[4] = cone[4]; facesTmp[5] = cone[5]; /* Top */ 244412e9a14SMatthew G. Knepley facesTmp[6] = cone[0]; facesTmp[7] = cone[1]; facesTmp[8] = cone[3]; facesTmp[9] = cone[4]; /* Back left */ 245412e9a14SMatthew G. Knepley facesTmp[10] = cone[1]; facesTmp[11] = cone[2]; facesTmp[12] = cone[4]; facesTmp[13] = cone[5]; /* Back right */ 246412e9a14SMatthew G. Knepley facesTmp[14] = cone[2]; facesTmp[15] = cone[0]; facesTmp[16] = cone[5]; facesTmp[17] = cone[3]; /* Front */ 24799836e0eSStefano Zampini *faces = facesTmp; 24899836e0eSStefano Zampini } 249412e9a14SMatthew G. Knepley break; 250412e9a14SMatthew G. Knepley case DM_POLYTOPE_QUAD_PRISM_TENSOR: 251412e9a14SMatthew G. Knepley /* 7--------6 252412e9a14SMatthew G. Knepley /| /| 253412e9a14SMatthew G. Knepley / | / | 254412e9a14SMatthew G. Knepley 4--------5 | 255412e9a14SMatthew G. Knepley | | | | 256412e9a14SMatthew G. Knepley | | | | 257412e9a14SMatthew G. Knepley | 3--------2 258412e9a14SMatthew G. Knepley | / | / 259412e9a14SMatthew G. Knepley |/ |/ 260412e9a14SMatthew G. Knepley 0--------1 261412e9a14SMatthew G. Knepley */ 262412e9a14SMatthew G. Knepley if (numFaces) *numFaces = 6; 263412e9a14SMatthew G. Knepley if (faceTypes) { 264412e9a14SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_QUADRILATERAL; typesTmp[1] = DM_POLYTOPE_QUADRILATERAL; typesTmp[2] = DM_POLYTOPE_SEG_PRISM_TENSOR; 265412e9a14SMatthew G. Knepley typesTmp[3] = DM_POLYTOPE_SEG_PRISM_TENSOR; typesTmp[4] = DM_POLYTOPE_SEG_PRISM_TENSOR; typesTmp[5] = DM_POLYTOPE_SEG_PRISM_TENSOR; 266412e9a14SMatthew G. Knepley *faceTypes = typesTmp; 267412e9a14SMatthew G. Knepley } 268412e9a14SMatthew G. Knepley if (faceSizes) { 269412e9a14SMatthew G. Knepley sizesTmp[0] = 4; sizesTmp[1] = 4; sizesTmp[2] = 4; sizesTmp[3] = 4; sizesTmp[4] = 4; sizesTmp[5] = 4; 270412e9a14SMatthew G. Knepley *faceSizes = sizesTmp; 271412e9a14SMatthew G. Knepley } 272412e9a14SMatthew G. Knepley if (faces) { 273412e9a14SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; facesTmp[2] = cone[2]; facesTmp[3] = cone[3]; /* Bottom */ 274412e9a14SMatthew G. Knepley facesTmp[4] = cone[4]; facesTmp[5] = cone[5]; facesTmp[6] = cone[6]; facesTmp[7] = cone[7]; /* Top */ 275412e9a14SMatthew G. Knepley facesTmp[8] = cone[0]; facesTmp[9] = cone[1]; facesTmp[10] = cone[4]; facesTmp[11] = cone[5]; /* Front */ 276412e9a14SMatthew G. Knepley facesTmp[12] = cone[1]; facesTmp[13] = cone[2]; facesTmp[14] = cone[5]; facesTmp[15] = cone[6]; /* Right */ 277412e9a14SMatthew G. Knepley facesTmp[16] = cone[2]; facesTmp[17] = cone[3]; facesTmp[18] = cone[6]; facesTmp[19] = cone[7]; /* Back */ 278412e9a14SMatthew G. Knepley facesTmp[20] = cone[3]; facesTmp[21] = cone[0]; facesTmp[22] = cone[7]; facesTmp[23] = cone[4]; /* Left */ 279412e9a14SMatthew G. Knepley *faces = facesTmp; 280412e9a14SMatthew G. Knepley } 28199836e0eSStefano Zampini break; 282da9060c4SMatthew G. Knepley case DM_POLYTOPE_PYRAMID: 283da9060c4SMatthew G. Knepley /* 284da9060c4SMatthew G. Knepley 4---- 285da9060c4SMatthew G. Knepley |\-\ \----- 286da9060c4SMatthew G. Knepley | \ -\ \ 287da9060c4SMatthew G. Knepley | 1--\-----2 288da9060c4SMatthew G. Knepley | / \ / 289da9060c4SMatthew G. Knepley |/ \ / 290da9060c4SMatthew G. Knepley 0--------3 291da9060c4SMatthew G. Knepley */ 292da9060c4SMatthew G. Knepley if (numFaces) *numFaces = 5; 293da9060c4SMatthew G. Knepley if (faceTypes) { 294da9060c4SMatthew G. Knepley typesTmp[0] = DM_POLYTOPE_QUADRILATERAL; 295da9060c4SMatthew G. Knepley typesTmp[1] = DM_POLYTOPE_TRIANGLE; typesTmp[2] = DM_POLYTOPE_TRIANGLE; typesTmp[3] = DM_POLYTOPE_TRIANGLE; typesTmp[4] = DM_POLYTOPE_TRIANGLE; 296da9060c4SMatthew G. Knepley *faceTypes = typesTmp; 297da9060c4SMatthew G. Knepley } 298da9060c4SMatthew G. Knepley if (faceSizes) { 299da9060c4SMatthew G. Knepley sizesTmp[0] = 4; 300da9060c4SMatthew G. Knepley sizesTmp[1] = 3; sizesTmp[2] = 3; sizesTmp[3] = 3; sizesTmp[4] = 3; 301da9060c4SMatthew G. Knepley *faceSizes = sizesTmp; 302da9060c4SMatthew G. Knepley } 303da9060c4SMatthew G. Knepley if (faces) { 304da9060c4SMatthew G. Knepley facesTmp[0] = cone[0]; facesTmp[1] = cone[1]; facesTmp[2] = cone[2]; facesTmp[3] = cone[3]; /* Bottom */ 305da9060c4SMatthew G. Knepley facesTmp[4] = cone[0]; facesTmp[5] = cone[3]; facesTmp[6] = cone[4]; /* Front */ 306da9060c4SMatthew G. Knepley facesTmp[7] = cone[3]; facesTmp[8] = cone[2]; facesTmp[9] = cone[4]; /* Right */ 307da9060c4SMatthew G. Knepley facesTmp[10] = cone[2]; facesTmp[11] = cone[1]; facesTmp[12] = cone[4]; /* Back */ 308da9060c4SMatthew G. Knepley facesTmp[13] = cone[1]; facesTmp[14] = cone[0]; facesTmp[15] = cone[4]; /* Left */ 309da9060c4SMatthew G. Knepley *faces = facesTmp; 310da9060c4SMatthew G. Knepley } 311da9060c4SMatthew G. Knepley break; 31298921bdaSJacob Faibussowitsch default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No face description for cell type %s", DMPolytopeTypes[ct]); 31399836e0eSStefano Zampini } 31499836e0eSStefano Zampini PetscFunctionReturn(0); 31599836e0eSStefano Zampini } 31699836e0eSStefano Zampini 317412e9a14SMatthew G. Knepley PetscErrorCode DMPlexRestoreRawFaces_Internal(DM dm, DMPolytopeType ct, const PetscInt cone[], PetscInt *numFaces, const DMPolytopeType *faceTypes[], const PetscInt *faceSizes[], const PetscInt *faces[]) 31899836e0eSStefano Zampini { 31999836e0eSStefano Zampini PetscFunctionBegin; 3209566063dSJacob Faibussowitsch if (faceTypes) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *) faceTypes)); 3219566063dSJacob Faibussowitsch if (faceSizes) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *) faceSizes)); 3229566063dSJacob Faibussowitsch if (faces) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void *) faces)); 32399836e0eSStefano Zampini PetscFunctionReturn(0); 32499836e0eSStefano Zampini } 32599836e0eSStefano Zampini 3269a5b13a2SMatthew G Knepley /* This interpolates faces for cells at some stratum */ 3279a5b13a2SMatthew G Knepley static PetscErrorCode DMPlexInterpolateFaces_Internal(DM dm, PetscInt cellDepth, DM idm) 3289f074e33SMatthew G Knepley { 329412e9a14SMatthew G. Knepley DMLabel ctLabel; 3309a5b13a2SMatthew G Knepley PetscHashIJKL faceTable; 331412e9a14SMatthew G. Knepley PetscInt faceTypeNum[DM_NUM_POLYTOPES]; 3329318fe57SMatthew G. Knepley PetscInt depth, d, pStart, Np, cStart, cEnd, c, fStart, fEnd; 3339f074e33SMatthew G Knepley 3349f074e33SMatthew G Knepley PetscFunctionBegin; 3359566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepth(dm, &depth)); 3369566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLCreate(&faceTable)); 3379566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(faceTypeNum, DM_NUM_POLYTOPES)); 3389566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, cellDepth, &cStart, &cEnd)); 339412e9a14SMatthew G. Knepley /* Number new faces and save face vertices in hash table */ 3409566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, depth > cellDepth ? cellDepth : 0, NULL, &fStart)); 341412e9a14SMatthew G. Knepley fEnd = fStart; 342412e9a14SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 343412e9a14SMatthew G. Knepley const PetscInt *cone, *faceSizes, *faces; 344412e9a14SMatthew G. Knepley const DMPolytopeType *faceTypes; 345ba2698f1SMatthew G. Knepley DMPolytopeType ct; 346412e9a14SMatthew G. Knepley PetscInt numFaces, cf, foff = 0; 34799836e0eSStefano Zampini 3489566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, c, &ct)); 3499566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, c, &cone)); 3509566063dSJacob Faibussowitsch PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 351412e9a14SMatthew G. Knepley for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 352412e9a14SMatthew G. Knepley const PetscInt faceSize = faceSizes[cf]; 353412e9a14SMatthew G. Knepley const DMPolytopeType faceType = faceTypes[cf]; 354412e9a14SMatthew G. Knepley const PetscInt *face = &faces[foff]; 3559a5b13a2SMatthew G Knepley PetscHashIJKLKey key; 356e8f14785SLisandro Dalcin PetscHashIter iter; 357e8f14785SLisandro Dalcin PetscBool missing; 3589f074e33SMatthew G Knepley 3595f80ce2aSJacob Faibussowitsch PetscCheck(faceSize <= 4,PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 360412e9a14SMatthew G. Knepley key.i = face[0]; 361412e9a14SMatthew G. Knepley key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 362412e9a14SMatthew G. Knepley key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 363412e9a14SMatthew G. Knepley key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 3649566063dSJacob Faibussowitsch PetscCall(PetscSortInt(faceSize, (PetscInt *) &key)); 3659566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 366e9fa77a1SMatthew G. Knepley if (missing) { 3679566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLIterSet(faceTable, iter, fEnd++)); 368412e9a14SMatthew G. Knepley ++faceTypeNum[faceType]; 369e9fa77a1SMatthew G. Knepley } 3709a5b13a2SMatthew G Knepley } 3719566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 37299836e0eSStefano Zampini } 373412e9a14SMatthew G. Knepley /* We need to number faces contiguously among types */ 374412e9a14SMatthew G. Knepley { 375412e9a14SMatthew G. Knepley PetscInt faceTypeStart[DM_NUM_POLYTOPES], ct, numFT = 0; 37699836e0eSStefano Zampini 377412e9a14SMatthew G. Knepley for (ct = 0; ct < DM_NUM_POLYTOPES; ++ct) {if (faceTypeNum[ct]) ++numFT; faceTypeStart[ct] = 0;} 378412e9a14SMatthew G. Knepley if (numFT > 1) { 3799566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLClear(faceTable)); 380412e9a14SMatthew G. Knepley faceTypeStart[0] = fStart; 381412e9a14SMatthew G. Knepley for (ct = 1; ct < DM_NUM_POLYTOPES; ++ct) faceTypeStart[ct] = faceTypeStart[ct-1] + faceTypeNum[ct-1]; 382412e9a14SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 383412e9a14SMatthew G. Knepley const PetscInt *cone, *faceSizes, *faces; 384412e9a14SMatthew G. Knepley const DMPolytopeType *faceTypes; 385ba2698f1SMatthew G. Knepley DMPolytopeType ct; 386412e9a14SMatthew G. Knepley PetscInt numFaces, cf, foff = 0; 38799836e0eSStefano Zampini 3889566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, c, &ct)); 3899566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, c, &cone)); 3909566063dSJacob Faibussowitsch PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 391412e9a14SMatthew G. Knepley for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 392412e9a14SMatthew G. Knepley const PetscInt faceSize = faceSizes[cf]; 393412e9a14SMatthew G. Knepley const DMPolytopeType faceType = faceTypes[cf]; 394412e9a14SMatthew G. Knepley const PetscInt *face = &faces[foff]; 39599836e0eSStefano Zampini PetscHashIJKLKey key; 39699836e0eSStefano Zampini PetscHashIter iter; 39799836e0eSStefano Zampini PetscBool missing; 39899836e0eSStefano Zampini 3995f80ce2aSJacob Faibussowitsch PetscCheck(faceSize <= 4,PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 400412e9a14SMatthew G. Knepley key.i = face[0]; 401412e9a14SMatthew G. Knepley key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 402412e9a14SMatthew G. Knepley key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 403412e9a14SMatthew G. Knepley key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 4049566063dSJacob Faibussowitsch PetscCall(PetscSortInt(faceSize, (PetscInt *) &key)); 4059566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 4069566063dSJacob Faibussowitsch if (missing) PetscCall(PetscHashIJKLIterSet(faceTable, iter, faceTypeStart[faceType]++)); 40799836e0eSStefano Zampini } 4089566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 40999836e0eSStefano Zampini } 410412e9a14SMatthew G. Knepley for (ct = 1; ct < DM_NUM_POLYTOPES; ++ct) { 4111dca8a05SBarry Smith PetscCheck(faceTypeStart[ct] == faceTypeStart[ct-1] + faceTypeNum[ct],PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent numbering for cell type %s, %" PetscInt_FMT " != %" PetscInt_FMT " + %" PetscInt_FMT, DMPolytopeTypes[ct], faceTypeStart[ct], faceTypeStart[ct-1], faceTypeNum[ct]); 4129a5b13a2SMatthew G Knepley } 4139a5b13a2SMatthew G Knepley } 414412e9a14SMatthew G. Knepley } 415412e9a14SMatthew G. Knepley /* Add new points, always at the end of the numbering */ 4169566063dSJacob Faibussowitsch PetscCall(DMPlexGetChart(dm, &pStart, &Np)); 4179566063dSJacob Faibussowitsch PetscCall(DMPlexSetChart(idm, pStart, Np + (fEnd - fStart))); 4189a5b13a2SMatthew G Knepley /* Set cone sizes */ 419412e9a14SMatthew G. Knepley /* Must create the celltype label here so that we do not automatically try to compute the types */ 4209566063dSJacob Faibussowitsch PetscCall(DMCreateLabel(idm, "celltype")); 4219566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellTypeLabel(idm, &ctLabel)); 4229a5b13a2SMatthew G Knepley for (d = 0; d <= depth; ++d) { 423412e9a14SMatthew G. Knepley DMPolytopeType ct; 424412e9a14SMatthew G. Knepley PetscInt coneSize, pStart, pEnd, p; 4259f074e33SMatthew G Knepley 426412e9a14SMatthew G. Knepley if (d == cellDepth) continue; 4279566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 428412e9a14SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 4299566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4309566063dSJacob Faibussowitsch PetscCall(DMPlexSetConeSize(idm, p, coneSize)); 4319566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, p, &ct)); 4329566063dSJacob Faibussowitsch PetscCall(DMPlexSetCellType(idm, p, ct)); 4339f074e33SMatthew G Knepley } 4349f074e33SMatthew G Knepley } 435412e9a14SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 436412e9a14SMatthew G. Knepley const PetscInt *cone, *faceSizes, *faces; 437412e9a14SMatthew G. Knepley const DMPolytopeType *faceTypes; 438412e9a14SMatthew G. Knepley DMPolytopeType ct; 439412e9a14SMatthew G. Knepley PetscInt numFaces, cf, foff = 0; 440412e9a14SMatthew G. Knepley 4419566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, c, &ct)); 4429566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, c, &cone)); 4439566063dSJacob Faibussowitsch PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 4449566063dSJacob Faibussowitsch PetscCall(DMPlexSetCellType(idm, c, ct)); 4459566063dSJacob Faibussowitsch PetscCall(DMPlexSetConeSize(idm, c, numFaces)); 446412e9a14SMatthew G. Knepley for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 447412e9a14SMatthew G. Knepley const PetscInt faceSize = faceSizes[cf]; 448412e9a14SMatthew G. Knepley const DMPolytopeType faceType = faceTypes[cf]; 449412e9a14SMatthew G. Knepley const PetscInt *face = &faces[foff]; 450412e9a14SMatthew G. Knepley PetscHashIJKLKey key; 451412e9a14SMatthew G. Knepley PetscHashIter iter; 452412e9a14SMatthew G. Knepley PetscBool missing; 453412e9a14SMatthew G. Knepley PetscInt f; 454412e9a14SMatthew G. Knepley 45563a3b9bcSJacob Faibussowitsch PetscCheck(faceSize <= 4,PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 456412e9a14SMatthew G. Knepley key.i = face[0]; 457412e9a14SMatthew G. Knepley key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 458412e9a14SMatthew G. Knepley key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 459412e9a14SMatthew G. Knepley key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 4609566063dSJacob Faibussowitsch PetscCall(PetscSortInt(faceSize, (PetscInt *) &key)); 4619566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 46263a3b9bcSJacob Faibussowitsch PetscCheck(!missing,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing face (cell %" PetscInt_FMT ", lf %" PetscInt_FMT ")", c, cf); 4639566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLIterGet(faceTable, iter, &f)); 4649566063dSJacob Faibussowitsch PetscCall(DMPlexSetConeSize(idm, f, faceSize)); 4659566063dSJacob Faibussowitsch PetscCall(DMPlexSetCellType(idm, f, faceType)); 466412e9a14SMatthew G. Knepley } 4679566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 4689f074e33SMatthew G Knepley } 4699566063dSJacob Faibussowitsch PetscCall(DMSetUp(idm)); 470412e9a14SMatthew G. Knepley /* Initialize cones so we do not need the bash table to tell us that a cone has been set */ 471412e9a14SMatthew G. Knepley { 472412e9a14SMatthew G. Knepley PetscSection cs; 473412e9a14SMatthew G. Knepley PetscInt *cones, csize; 4749a5b13a2SMatthew G Knepley 4759566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSection(idm, &cs)); 4769566063dSJacob Faibussowitsch PetscCall(DMPlexGetCones(idm, &cones)); 4779566063dSJacob Faibussowitsch PetscCall(PetscSectionGetStorageSize(cs, &csize)); 478412e9a14SMatthew G. Knepley for (c = 0; c < csize; ++c) cones[c] = -1; 479412e9a14SMatthew G. Knepley } 480412e9a14SMatthew G. Knepley /* Set cones */ 481412e9a14SMatthew G. Knepley for (d = 0; d <= depth; ++d) { 482412e9a14SMatthew G. Knepley const PetscInt *cone; 483412e9a14SMatthew G. Knepley PetscInt pStart, pEnd, p; 484412e9a14SMatthew G. Knepley 485412e9a14SMatthew G. Knepley if (d == cellDepth) continue; 4869566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 487412e9a14SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 4889566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, p, &cone)); 4899566063dSJacob Faibussowitsch PetscCall(DMPlexSetCone(idm, p, cone)); 4909566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeOrientation(dm, p, &cone)); 4919566063dSJacob Faibussowitsch PetscCall(DMPlexSetConeOrientation(idm, p, cone)); 4929f074e33SMatthew G Knepley } 4939a5b13a2SMatthew G Knepley } 494412e9a14SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 495412e9a14SMatthew G. Knepley const PetscInt *cone, *faceSizes, *faces; 496412e9a14SMatthew G. Knepley const DMPolytopeType *faceTypes; 497ba2698f1SMatthew G. Knepley DMPolytopeType ct; 498412e9a14SMatthew G. Knepley PetscInt numFaces, cf, foff = 0; 49999836e0eSStefano Zampini 5009566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, c, &ct)); 5019566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, c, &cone)); 5029566063dSJacob Faibussowitsch PetscCall(DMPlexGetRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 503412e9a14SMatthew G. Knepley for (cf = 0; cf < numFaces; foff += faceSizes[cf], ++cf) { 504412e9a14SMatthew G. Knepley DMPolytopeType faceType = faceTypes[cf]; 505412e9a14SMatthew G. Knepley const PetscInt faceSize = faceSizes[cf]; 506412e9a14SMatthew G. Knepley const PetscInt *face = &faces[foff]; 507412e9a14SMatthew G. Knepley const PetscInt *fcone; 5089a5b13a2SMatthew G Knepley PetscHashIJKLKey key; 509e8f14785SLisandro Dalcin PetscHashIter iter; 510e8f14785SLisandro Dalcin PetscBool missing; 511412e9a14SMatthew G. Knepley PetscInt f; 5129f074e33SMatthew G Knepley 51363a3b9bcSJacob Faibussowitsch PetscCheck(faceSize <= 4,PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not support faces of size %" PetscInt_FMT " > 4", faceSize); 514412e9a14SMatthew G. Knepley key.i = face[0]; 515412e9a14SMatthew G. Knepley key.j = faceSize > 1 ? face[1] : PETSC_MAX_INT; 516412e9a14SMatthew G. Knepley key.k = faceSize > 2 ? face[2] : PETSC_MAX_INT; 517412e9a14SMatthew G. Knepley key.l = faceSize > 3 ? face[3] : PETSC_MAX_INT; 5189566063dSJacob Faibussowitsch PetscCall(PetscSortInt(faceSize, (PetscInt *) &key)); 5199566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLPut(faceTable, key, &iter, &missing)); 5209566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLIterGet(faceTable, iter, &f)); 5219566063dSJacob Faibussowitsch PetscCall(DMPlexInsertCone(idm, c, cf, f)); 5229566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(idm, f, &fcone)); 5239566063dSJacob Faibussowitsch if (fcone[0] < 0) PetscCall(DMPlexSetCone(idm, f, face)); 524412e9a14SMatthew G. Knepley { 525412e9a14SMatthew G. Knepley const PetscInt *cone; 526412e9a14SMatthew G. Knepley PetscInt coneSize, ornt; 527a74221b0SStefano Zampini 5289566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(idm, f, &coneSize)); 5299566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(idm, f, &cone)); 53063a3b9bcSJacob Faibussowitsch PetscCheck(coneSize == faceSize,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of face vertices %" PetscInt_FMT " for face %" PetscInt_FMT " should be %" PetscInt_FMT, coneSize, f, faceSize); 531d89e6e46SMatthew G. Knepley /* Notice that we have to use vertices here because the lower dimensional faces have not been created yet */ 5329566063dSJacob Faibussowitsch PetscCall(DMPolytopeGetVertexOrientation(faceType, cone, face, &ornt)); 5339566063dSJacob Faibussowitsch PetscCall(DMPlexInsertConeOrientation(idm, c, cf, ornt)); 53499836e0eSStefano Zampini } 53599836e0eSStefano Zampini } 5369566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, cone, &numFaces, &faceTypes, &faceSizes, &faces)); 53799836e0eSStefano Zampini } 5389566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLDestroy(&faceTable)); 5399566063dSJacob Faibussowitsch PetscCall(DMPlexSymmetrize(idm)); 5409566063dSJacob Faibussowitsch PetscCall(DMPlexStratify(idm)); 5419f074e33SMatthew G Knepley PetscFunctionReturn(0); 5429f074e33SMatthew G Knepley } 5439f074e33SMatthew G Knepley 544f80536cbSVaclav Hapla static PetscErrorCode SortRmineRremoteByRemote_Private(PetscSF sf, PetscInt *rmine1[], PetscInt *rremote1[]) 545f80536cbSVaclav Hapla { 546f80536cbSVaclav Hapla PetscInt nleaves; 547f80536cbSVaclav Hapla PetscInt nranks; 548a0d42dbcSVaclav Hapla const PetscMPIInt *ranks=NULL; 549a0d42dbcSVaclav Hapla const PetscInt *roffset=NULL, *rmine=NULL, *rremote=NULL; 550f80536cbSVaclav Hapla PetscInt n, o, r; 551f80536cbSVaclav Hapla 552f80536cbSVaclav Hapla PetscFunctionBegin; 5539566063dSJacob Faibussowitsch PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, &rmine, &rremote)); 554f80536cbSVaclav Hapla nleaves = roffset[nranks]; 5559566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nleaves, rmine1, nleaves, rremote1)); 556f80536cbSVaclav Hapla for (r=0; r<nranks; r++) { 557f80536cbSVaclav Hapla /* simultaneously sort rank-wise portions of rmine & rremote by values in rremote 558f80536cbSVaclav Hapla - to unify order with the other side */ 559f80536cbSVaclav Hapla o = roffset[r]; 560f80536cbSVaclav Hapla n = roffset[r+1] - o; 5619566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&(*rmine1)[o], &rmine[o], n)); 5629566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(&(*rremote1)[o], &rremote[o], n)); 5639566063dSJacob Faibussowitsch PetscCall(PetscSortIntWithArray(n, &(*rremote1)[o], &(*rmine1)[o])); 564f80536cbSVaclav Hapla } 565f80536cbSVaclav Hapla PetscFunctionReturn(0); 566f80536cbSVaclav Hapla } 567f80536cbSVaclav Hapla 56827d0e99aSVaclav Hapla PetscErrorCode DMPlexOrientInterface_Internal(DM dm) 5692e745bdaSMatthew G. Knepley { 570d89e6e46SMatthew G. Knepley PetscSF sf; 571d89e6e46SMatthew G. Knepley const PetscInt *locals; 572d89e6e46SMatthew G. Knepley const PetscSFNode *remotes; 573d89e6e46SMatthew G. Knepley const PetscMPIInt *ranks; 574d89e6e46SMatthew G. Knepley const PetscInt *roffset; 575d89e6e46SMatthew G. Knepley PetscInt *rmine1, *rremote1; /* rmine and rremote copies simultaneously sorted by rank and rremote */ 576d89e6e46SMatthew G. Knepley PetscInt nroots, p, nleaves, nranks, r, maxConeSize = 0; 577d89e6e46SMatthew G. Knepley PetscInt (*roots)[4], (*leaves)[4], mainCone[4]; 578d89e6e46SMatthew G. Knepley PetscMPIInt (*rootsRanks)[4], (*leavesRanks)[4]; 5792e745bdaSMatthew G. Knepley MPI_Comm comm; 58027d0e99aSVaclav Hapla PetscMPIInt rank, size; 5812e745bdaSMatthew G. Knepley PetscInt debug = 0; 5822e745bdaSMatthew G. Knepley 5832e745bdaSMatthew G. Knepley PetscFunctionBegin; 5849566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 5859566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5869566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 5879566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 5889566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(dm, NULL, "-before_orient_interface_dm_view")); 5899566063dSJacob Faibussowitsch if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm)); 5909566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &locals, &remotes)); 591d89e6e46SMatthew G. Knepley if (nroots < 0) PetscFunctionReturn(0); 5929566063dSJacob Faibussowitsch PetscCall(PetscSFSetUp(sf)); 5939566063dSJacob Faibussowitsch PetscCall(SortRmineRremoteByRemote_Private(sf, &rmine1, &rremote1)); 594d89e6e46SMatthew G. Knepley for (p = 0; p < nleaves; ++p) { 595d89e6e46SMatthew G. Knepley PetscInt coneSize; 5969566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, locals[p], &coneSize)); 597d89e6e46SMatthew G. Knepley maxConeSize = PetscMax(maxConeSize, coneSize); 598d89e6e46SMatthew G. Knepley } 59963a3b9bcSJacob Faibussowitsch PetscCheck(maxConeSize <= 4,comm, PETSC_ERR_SUP, "This method does not support cones of size %" PetscInt_FMT, maxConeSize); 6009566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(nroots, &roots, nroots, &leaves, nroots, &rootsRanks, nroots, &leavesRanks)); 6019e24d8a0SVaclav Hapla for (p = 0; p < nroots; ++p) { 602d89e6e46SMatthew G. Knepley const PetscInt *cone; 603d89e6e46SMatthew G. Knepley PetscInt coneSize, c, ind0; 604d89e6e46SMatthew G. Knepley 6059566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 6069566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, p, &cone)); 607d89e6e46SMatthew G. Knepley /* Ignore vertices */ 60827d0e99aSVaclav Hapla if (coneSize < 2) { 609d89e6e46SMatthew G. Knepley for (c = 0; c < 4; c++) { 61027d0e99aSVaclav Hapla roots[p][c] = -1; 61127d0e99aSVaclav Hapla rootsRanks[p][c] = -1; 61227d0e99aSVaclav Hapla } 61327d0e99aSVaclav Hapla continue; 61427d0e99aSVaclav Hapla } 6152e745bdaSMatthew G. Knepley /* Translate all points to root numbering */ 616d89e6e46SMatthew G. Knepley for (c = 0; c < PetscMin(coneSize, 4); c++) { 6179566063dSJacob Faibussowitsch PetscCall(PetscFindInt(cone[c], nleaves, locals, &ind0)); 6188a650c75SVaclav Hapla if (ind0 < 0) { 6198a650c75SVaclav Hapla roots[p][c] = cone[c]; 6208a650c75SVaclav Hapla rootsRanks[p][c] = rank; 621c8148b97SVaclav Hapla } else { 6228a650c75SVaclav Hapla roots[p][c] = remotes[ind0].index; 6238a650c75SVaclav Hapla rootsRanks[p][c] = remotes[ind0].rank; 6248a650c75SVaclav Hapla } 6252e745bdaSMatthew G. Knepley } 626d89e6e46SMatthew G. Knepley for (c = coneSize; c < 4; c++) { 627d89e6e46SMatthew G. Knepley roots[p][c] = -1; 628d89e6e46SMatthew G. Knepley rootsRanks[p][c] = -1; 629d89e6e46SMatthew G. Knepley } 6302e745bdaSMatthew G. Knepley } 6319e24d8a0SVaclav Hapla for (p = 0; p < nroots; ++p) { 632d89e6e46SMatthew G. Knepley PetscInt c; 633d89e6e46SMatthew G. Knepley for (c = 0; c < 4; c++) { 6348ccb905dSVaclav Hapla leaves[p][c] = -2; 6358ccb905dSVaclav Hapla leavesRanks[p][c] = -2; 6368ccb905dSVaclav Hapla } 637c8148b97SVaclav Hapla } 6389566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPIU_4INT, roots, leaves, MPI_REPLACE)); 6399566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPI_4INT, rootsRanks, leavesRanks, MPI_REPLACE)); 6409566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPIU_4INT, roots, leaves, MPI_REPLACE)); 6419566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPI_4INT, rootsRanks, leavesRanks, MPI_REPLACE)); 642d89e6e46SMatthew G. Knepley if (debug) { 6439566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedFlush(comm, NULL)); 6449566063dSJacob Faibussowitsch if (!rank) PetscCall(PetscSynchronizedPrintf(comm, "Referenced roots\n")); 645d89e6e46SMatthew G. Knepley } 6469566063dSJacob Faibussowitsch PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, NULL, NULL)); 6479e24d8a0SVaclav Hapla for (p = 0; p < nroots; ++p) { 648d89e6e46SMatthew G. Knepley DMPolytopeType ct; 649d89e6e46SMatthew G. Knepley const PetscInt *cone; 650d89e6e46SMatthew G. Knepley PetscInt coneSize, c, ind0, o; 651d89e6e46SMatthew G. Knepley 652d89e6e46SMatthew G. Knepley if (leaves[p][0] < 0) continue; /* Ignore vertices */ 6539566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, p, &ct)); 6549566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 6559566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, p, &cone)); 656d89e6e46SMatthew G. Knepley if (debug) { 65763a3b9bcSJacob Faibussowitsch PetscCall(PetscSynchronizedPrintf(comm, "[%d] %4" PetscInt_FMT ": cone=[%4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT "] roots=[(%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ")] leaves=[(%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ") (%d,%4" PetscInt_FMT ")]", 658d89e6e46SMatthew G. Knepley rank, p, cone[0], cone[1], cone[2], cone[3], 659d89e6e46SMatthew G. Knepley rootsRanks[p][0], roots[p][0], rootsRanks[p][1], roots[p][1], rootsRanks[p][2], roots[p][2], rootsRanks[p][3], roots[p][3], 6605f80ce2aSJacob Faibussowitsch leavesRanks[p][0], leaves[p][0], leavesRanks[p][1], leaves[p][1], leavesRanks[p][2], leaves[p][2], leavesRanks[p][3], leaves[p][3])); 661d89e6e46SMatthew G. Knepley } 662d89e6e46SMatthew G. Knepley if (leavesRanks[p][0] != rootsRanks[p][0] || leaves[p][0] != roots[p][0] || 663d89e6e46SMatthew G. Knepley leavesRanks[p][1] != rootsRanks[p][1] || leaves[p][1] != roots[p][1] || 664d89e6e46SMatthew G. Knepley leavesRanks[p][2] != rootsRanks[p][2] || leaves[p][2] != roots[p][2] || 665d89e6e46SMatthew G. Knepley leavesRanks[p][3] != rootsRanks[p][3] || leaves[p][3] != roots[p][3]) { 666d89e6e46SMatthew G. Knepley /* Translate these leaves to my cone points; mainCone means desired order p's cone points */ 667d89e6e46SMatthew G. Knepley for (c = 0; c < PetscMin(coneSize, 4); ++c) { 668d89e6e46SMatthew G. Knepley PetscInt rS, rN; 669d89e6e46SMatthew G. Knepley 67027d0e99aSVaclav Hapla if (leavesRanks[p][c] == rank) { 671d89e6e46SMatthew G. Knepley /* A local leaf is just taken as it is */ 6729dddd249SSatish Balay mainCone[c] = leaves[p][c]; 67327d0e99aSVaclav Hapla continue; 67427d0e99aSVaclav Hapla } 675f80536cbSVaclav Hapla /* Find index of rank leavesRanks[p][c] among remote ranks */ 676f80536cbSVaclav Hapla /* No need for PetscMPIIntCast because these integers were originally cast from PetscMPIInt. */ 6779566063dSJacob Faibussowitsch PetscCall(PetscFindMPIInt((PetscMPIInt) leavesRanks[p][c], nranks, ranks, &r)); 67863a3b9bcSJacob Faibussowitsch PetscCheck(r >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " cone[%" PetscInt_FMT "]=%" PetscInt_FMT " root (%d,%" PetscInt_FMT ") leaf (%d,%" PetscInt_FMT "): leaf rank not found among remote ranks", p, c, cone[c], rootsRanks[p][c], roots[p][c], leavesRanks[p][c], leaves[p][c]); 6791dca8a05SBarry Smith PetscCheck(ranks[r] >= 0 && ranks[r] < size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "p=%" PetscInt_FMT " c=%" PetscInt_FMT " commsize=%d: ranks[%" PetscInt_FMT "] = %d makes no sense", p, c, size, r, ranks[r]); 680f80536cbSVaclav Hapla /* Find point leaves[p][c] among remote points aimed at rank leavesRanks[p][c] */ 681d89e6e46SMatthew G. Knepley rS = roffset[r]; 682d89e6e46SMatthew G. Knepley rN = roffset[r+1] - rS; 6839566063dSJacob Faibussowitsch PetscCall(PetscFindInt(leaves[p][c], rN, &rremote1[rS], &ind0)); 68463a3b9bcSJacob Faibussowitsch PetscCheck(ind0 >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " cone[%" PetscInt_FMT "]=%" PetscInt_FMT " root (%d,%" PetscInt_FMT ") leave (%d,%" PetscInt_FMT "): 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]); 685f80536cbSVaclav Hapla /* Get the corresponding local point */ 6865f80ce2aSJacob Faibussowitsch mainCone[c] = rmine1[rS + ind0]; 687f80536cbSVaclav Hapla } 68863a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, " mainCone=[%4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT " %4" PetscInt_FMT "]\n", mainCone[0], mainCone[1], mainCone[2], mainCone[3])); 68927d0e99aSVaclav Hapla /* Set the desired order of p's cone points and fix orientations accordingly */ 6909566063dSJacob Faibussowitsch PetscCall(DMPolytopeGetOrientation(ct, cone, mainCone, &o)); 6919566063dSJacob Faibussowitsch PetscCall(DMPlexOrientPoint(dm, p, o)); 6929566063dSJacob Faibussowitsch } else if (debug) PetscCall(PetscSynchronizedPrintf(comm, " ==\n")); 69323aaf07bSVaclav Hapla } 69427d0e99aSVaclav Hapla if (debug) { 6959566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedFlush(comm, NULL)); 6969566063dSJacob Faibussowitsch PetscCallMPI(MPI_Barrier(comm)); 6972e745bdaSMatthew G. Knepley } 6989566063dSJacob Faibussowitsch PetscCall(DMViewFromOptions(dm, NULL, "-after_orient_interface_dm_view")); 6999566063dSJacob Faibussowitsch PetscCall(PetscFree4(roots, leaves, rootsRanks, leavesRanks)); 7009566063dSJacob Faibussowitsch PetscCall(PetscFree2(rmine1, rremote1)); 7012e745bdaSMatthew G. Knepley PetscFunctionReturn(0); 7022e745bdaSMatthew G. Knepley } 7032e745bdaSMatthew G. Knepley 7042e72742cSMatthew 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[]) 7057bffde78SMichael Lange { 7062e72742cSMatthew G. Knepley PetscInt idx; 7072e72742cSMatthew G. Knepley PetscMPIInt rank; 7082e72742cSMatthew G. Knepley PetscBool flg; 7097bffde78SMichael Lange 7107bffde78SMichael Lange PetscFunctionBegin; 7119566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, NULL, opt, &flg)); 7122e72742cSMatthew G. Knepley if (!flg) PetscFunctionReturn(0); 7139566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7149566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name)); 71563a3b9bcSJacob Faibussowitsch for (idx = 0; idx < n; ++idx) PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s %" PetscInt_FMT " %s %" PetscInt_FMT "\n", rank, idxname, idx, valname, a[idx])); 7169566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedFlush(comm, NULL)); 7172e72742cSMatthew G. Knepley PetscFunctionReturn(0); 7182e72742cSMatthew G. Knepley } 7192e72742cSMatthew G. Knepley 7202e72742cSMatthew G. Knepley static PetscErrorCode SFNodeArrayViewFromOptions(MPI_Comm comm, const char opt[], const char name[], const char idxname[], PetscInt n, const PetscSFNode a[]) 7212e72742cSMatthew G. Knepley { 7222e72742cSMatthew G. Knepley PetscInt idx; 7232e72742cSMatthew G. Knepley PetscMPIInt rank; 7242e72742cSMatthew G. Knepley PetscBool flg; 7252e72742cSMatthew G. Knepley 7262e72742cSMatthew G. Knepley PetscFunctionBegin; 7279566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, NULL, opt, &flg)); 7282e72742cSMatthew G. Knepley if (!flg) PetscFunctionReturn(0); 7299566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7309566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name)); 7312e72742cSMatthew G. Knepley if (idxname) { 73263a3b9bcSJacob Faibussowitsch for (idx = 0; idx < n; ++idx) PetscCall(PetscSynchronizedPrintf(comm, "[%d]%s %" PetscInt_FMT " rank %" PetscInt_FMT " index %" PetscInt_FMT "\n", rank, idxname, idx, a[idx].rank, a[idx].index)); 7332e72742cSMatthew G. Knepley } else { 73463a3b9bcSJacob Faibussowitsch for (idx = 0; idx < n; ++idx) PetscCall(PetscSynchronizedPrintf(comm, "[%d]rank %" PetscInt_FMT " index %" PetscInt_FMT "\n", rank, a[idx].rank, a[idx].index)); 7352e72742cSMatthew G. Knepley } 7369566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedFlush(comm, NULL)); 7372e72742cSMatthew G. Knepley PetscFunctionReturn(0); 7382e72742cSMatthew G. Knepley } 7392e72742cSMatthew G. Knepley 7405f80ce2aSJacob Faibussowitsch static PetscErrorCode DMPlexMapToLocalPoint(DM dm, PetscHMapIJ remotehash, PetscSFNode remotePoint, PetscInt *localPoint, PetscBool *mapFailed) 7412e72742cSMatthew G. Knepley { 7423be36e83SMatthew G. Knepley PetscSF sf; 7433be36e83SMatthew G. Knepley const PetscInt *locals; 7443be36e83SMatthew G. Knepley PetscMPIInt rank; 7452e72742cSMatthew G. Knepley 7462e72742cSMatthew G. Knepley PetscFunctionBegin; 7479566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 7489566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 7499566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, NULL, NULL, &locals, NULL)); 7505f80ce2aSJacob Faibussowitsch if (mapFailed) *mapFailed = PETSC_FALSE; 7512e72742cSMatthew G. Knepley if (remotePoint.rank == rank) { 7522e72742cSMatthew G. Knepley *localPoint = remotePoint.index; 7532e72742cSMatthew G. Knepley } else { 7542e72742cSMatthew G. Knepley PetscHashIJKey key; 7553be36e83SMatthew G. Knepley PetscInt l; 7562e72742cSMatthew G. Knepley 7572e72742cSMatthew G. Knepley key.i = remotePoint.index; 7582e72742cSMatthew G. Knepley key.j = remotePoint.rank; 7599566063dSJacob Faibussowitsch PetscCall(PetscHMapIJGet(remotehash, key, &l)); 7603be36e83SMatthew G. Knepley if (l >= 0) { 7613be36e83SMatthew G. Knepley *localPoint = locals[l]; 7625f80ce2aSJacob Faibussowitsch } else if (mapFailed) *mapFailed = PETSC_TRUE; 7632e72742cSMatthew G. Knepley } 7642e72742cSMatthew G. Knepley PetscFunctionReturn(0); 7652e72742cSMatthew G. Knepley } 7662e72742cSMatthew G. Knepley 7675f80ce2aSJacob Faibussowitsch static PetscErrorCode DMPlexMapToGlobalPoint(DM dm, PetscInt localPoint, PetscSFNode *remotePoint, PetscBool *mapFailed) 7683be36e83SMatthew G. Knepley { 7693be36e83SMatthew G. Knepley PetscSF sf; 7703be36e83SMatthew G. Knepley const PetscInt *locals, *rootdegree; 7713be36e83SMatthew G. Knepley const PetscSFNode *remotes; 7723be36e83SMatthew G. Knepley PetscInt Nl, l; 7733be36e83SMatthew G. Knepley PetscMPIInt rank; 7743be36e83SMatthew G. Knepley 7753be36e83SMatthew G. Knepley PetscFunctionBegin; 7765f80ce2aSJacob Faibussowitsch if (mapFailed) *mapFailed = PETSC_FALSE; 7779566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 7789566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 7799566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &locals, &remotes)); 7803be36e83SMatthew G. Knepley if (Nl < 0) goto owned; 7819566063dSJacob Faibussowitsch PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 7829566063dSJacob Faibussowitsch PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 7833be36e83SMatthew G. Knepley if (rootdegree[localPoint]) goto owned; 7849566063dSJacob Faibussowitsch PetscCall(PetscFindInt(localPoint, Nl, locals, &l)); 7855f80ce2aSJacob Faibussowitsch if (l < 0) {if (mapFailed) *mapFailed = PETSC_TRUE;} 7865f80ce2aSJacob Faibussowitsch else *remotePoint = remotes[l]; 7873be36e83SMatthew G. Knepley PetscFunctionReturn(0); 7883be36e83SMatthew G. Knepley owned: 7893be36e83SMatthew G. Knepley remotePoint->rank = rank; 7903be36e83SMatthew G. Knepley remotePoint->index = localPoint; 7913be36e83SMatthew G. Knepley PetscFunctionReturn(0); 7923be36e83SMatthew G. Knepley } 7933be36e83SMatthew G. Knepley 7943be36e83SMatthew G. Knepley static PetscErrorCode DMPlexPointIsShared(DM dm, PetscInt p, PetscBool *isShared) 7953be36e83SMatthew G. Knepley { 7963be36e83SMatthew G. Knepley PetscSF sf; 7973be36e83SMatthew G. Knepley const PetscInt *locals, *rootdegree; 7983be36e83SMatthew G. Knepley PetscInt Nl, idx; 7993be36e83SMatthew G. Knepley 8003be36e83SMatthew G. Knepley PetscFunctionBegin; 8013be36e83SMatthew G. Knepley *isShared = PETSC_FALSE; 8029566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sf)); 8039566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &locals, NULL)); 8043be36e83SMatthew G. Knepley if (Nl < 0) PetscFunctionReturn(0); 8059566063dSJacob Faibussowitsch PetscCall(PetscFindInt(p, Nl, locals, &idx)); 8063be36e83SMatthew G. Knepley if (idx >= 0) {*isShared = PETSC_TRUE; PetscFunctionReturn(0);} 8079566063dSJacob Faibussowitsch PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 8089566063dSJacob Faibussowitsch PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 8093be36e83SMatthew G. Knepley if (rootdegree[p] > 0) *isShared = PETSC_TRUE; 8103be36e83SMatthew G. Knepley PetscFunctionReturn(0); 8113be36e83SMatthew G. Knepley } 8123be36e83SMatthew G. Knepley 8133be36e83SMatthew G. Knepley static PetscErrorCode DMPlexConeIsShared(DM dm, PetscInt p, PetscBool *isShared) 8143be36e83SMatthew G. Knepley { 8153be36e83SMatthew G. Knepley const PetscInt *cone; 8163be36e83SMatthew G. Knepley PetscInt coneSize, c; 8173be36e83SMatthew G. Knepley PetscBool cShared = PETSC_TRUE; 8183be36e83SMatthew G. Knepley 8193be36e83SMatthew G. Knepley PetscFunctionBegin; 8209566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8219566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, p, &cone)); 8223be36e83SMatthew G. Knepley for (c = 0; c < coneSize; ++c) { 8233be36e83SMatthew G. Knepley PetscBool pointShared; 8243be36e83SMatthew G. Knepley 8259566063dSJacob Faibussowitsch PetscCall(DMPlexPointIsShared(dm, cone[c], &pointShared)); 8263be36e83SMatthew G. Knepley cShared = (PetscBool) (cShared && pointShared); 8273be36e83SMatthew G. Knepley } 8283be36e83SMatthew G. Knepley *isShared = coneSize ? cShared : PETSC_FALSE; 8293be36e83SMatthew G. Knepley PetscFunctionReturn(0); 8303be36e83SMatthew G. Knepley } 8313be36e83SMatthew G. Knepley 8323be36e83SMatthew G. Knepley static PetscErrorCode DMPlexGetConeMinimum(DM dm, PetscInt p, PetscSFNode *cpmin) 8333be36e83SMatthew G. Knepley { 8343be36e83SMatthew G. Knepley const PetscInt *cone; 8353be36e83SMatthew G. Knepley PetscInt coneSize, c; 8363be36e83SMatthew G. Knepley PetscSFNode cmin = {PETSC_MAX_INT, PETSC_MAX_INT}, missing = {-1, -1}; 8373be36e83SMatthew G. Knepley 8383be36e83SMatthew G. Knepley PetscFunctionBegin; 8399566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8409566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, p, &cone)); 8413be36e83SMatthew G. Knepley for (c = 0; c < coneSize; ++c) { 8423be36e83SMatthew G. Knepley PetscSFNode rcp; 8435f80ce2aSJacob Faibussowitsch PetscBool mapFailed; 8443be36e83SMatthew G. Knepley 8459566063dSJacob Faibussowitsch PetscCall(DMPlexMapToGlobalPoint(dm, cone[c], &rcp, &mapFailed)); 8465f80ce2aSJacob Faibussowitsch if (mapFailed) { 8473be36e83SMatthew G. Knepley cmin = missing; 8483be36e83SMatthew G. Knepley } else { 8493be36e83SMatthew G. Knepley cmin = (rcp.rank < cmin.rank) || (rcp.rank == cmin.rank && rcp.index < cmin.index) ? rcp : cmin; 8503be36e83SMatthew G. Knepley } 8513be36e83SMatthew G. Knepley } 8523be36e83SMatthew G. Knepley *cpmin = coneSize ? cmin : missing; 8533be36e83SMatthew G. Knepley PetscFunctionReturn(0); 8543be36e83SMatthew G. Knepley } 8553be36e83SMatthew G. Knepley 8563be36e83SMatthew G. Knepley /* 8573be36e83SMatthew G. Knepley Each shared face has an entry in the candidates array: 8583be36e83SMatthew G. Knepley (-1, coneSize-1), {(global cone point)} 8593be36e83SMatthew G. Knepley where the set is missing the point p which we use as the key for the face 8603be36e83SMatthew G. Knepley */ 8613be36e83SMatthew G. Knepley static PetscErrorCode DMPlexAddSharedFace_Private(DM dm, PetscSection candidateSection, PetscSFNode candidates[], PetscHMapIJ faceHash, PetscInt p, PetscBool debug) 8623be36e83SMatthew G. Knepley { 8633be36e83SMatthew G. Knepley MPI_Comm comm; 8643be36e83SMatthew G. Knepley const PetscInt *support; 865cf4dc471SVaclav Hapla PetscInt supportSize, s, off = 0, idx = 0, overlap, cellHeight, height; 8663be36e83SMatthew G. Knepley PetscMPIInt rank; 8673be36e83SMatthew G. Knepley 8683be36e83SMatthew G. Knepley PetscFunctionBegin; 8699566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8709566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8719566063dSJacob Faibussowitsch PetscCall(DMPlexGetOverlap(dm, &overlap)); 8729566063dSJacob Faibussowitsch PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8739566063dSJacob Faibussowitsch PetscCall(DMPlexGetPointHeight(dm, p, &height)); 874cf4dc471SVaclav Hapla if (!overlap && height <= cellHeight+1) { 875cf4dc471SVaclav Hapla /* cells can't be shared for non-overlapping meshes */ 87663a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Skipping face %" PetscInt_FMT " to avoid adding cell to hashmap since this is nonoverlapping mesh\n", rank, p)); 877cf4dc471SVaclav Hapla PetscFunctionReturn(0); 878cf4dc471SVaclav Hapla } 8799566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8809566063dSJacob Faibussowitsch PetscCall(DMPlexGetSupport(dm, p, &support)); 8819566063dSJacob Faibussowitsch if (candidates) PetscCall(PetscSectionGetOffset(candidateSection, p, &off)); 8823be36e83SMatthew G. Knepley for (s = 0; s < supportSize; ++s) { 8833be36e83SMatthew G. Knepley const PetscInt face = support[s]; 8843be36e83SMatthew G. Knepley const PetscInt *cone; 8853be36e83SMatthew G. Knepley PetscSFNode cpmin={-1,-1}, rp={-1,-1}; 8863be36e83SMatthew G. Knepley PetscInt coneSize, c, f; 8873be36e83SMatthew G. Knepley PetscBool isShared = PETSC_FALSE; 8883be36e83SMatthew G. Knepley PetscHashIJKey key; 8893be36e83SMatthew G. Knepley 8903be36e83SMatthew G. Knepley /* Only add point once */ 89163a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Support face %" PetscInt_FMT "\n", rank, face)); 8923be36e83SMatthew G. Knepley key.i = p; 8933be36e83SMatthew G. Knepley key.j = face; 8949566063dSJacob Faibussowitsch PetscCall(PetscHMapIJGet(faceHash, key, &f)); 8953be36e83SMatthew G. Knepley if (f >= 0) continue; 8969566063dSJacob Faibussowitsch PetscCall(DMPlexConeIsShared(dm, face, &isShared)); 8979566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeMinimum(dm, face, &cpmin)); 8989566063dSJacob Faibussowitsch PetscCall(DMPlexMapToGlobalPoint(dm, p, &rp, NULL)); 8993be36e83SMatthew G. Knepley if (debug) { 90063a3b9bcSJacob Faibussowitsch PetscCall(PetscSynchronizedPrintf(comm, "[%d] Face point %" PetscInt_FMT " is shared: %d\n", rank, face, (int) isShared)); 90163a3b9bcSJacob Faibussowitsch PetscCall(PetscSynchronizedPrintf(comm, "[%d] Global point (%" PetscInt_FMT ", %" PetscInt_FMT ") Min Cone Point (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, rp.rank, rp.index, cpmin.rank, cpmin.index)); 9023be36e83SMatthew G. Knepley } 9033be36e83SMatthew G. Knepley if (isShared && (rp.rank == cpmin.rank && rp.index == cpmin.index)) { 9049566063dSJacob Faibussowitsch PetscCall(PetscHMapIJSet(faceHash, key, p)); 9053be36e83SMatthew G. Knepley if (candidates) { 90663a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Adding shared face %" PetscInt_FMT " at idx %" PetscInt_FMT "\n[%d] ", rank, face, idx, rank)); 9079566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, face, &coneSize)); 9089566063dSJacob Faibussowitsch PetscCall(DMPlexGetCone(dm, face, &cone)); 9093be36e83SMatthew G. Knepley candidates[off+idx].rank = -1; 9103be36e83SMatthew G. Knepley candidates[off+idx++].index = coneSize-1; 9113be36e83SMatthew G. Knepley candidates[off+idx].rank = rank; 9123be36e83SMatthew G. Knepley candidates[off+idx++].index = face; 9133be36e83SMatthew G. Knepley for (c = 0; c < coneSize; ++c) { 9143be36e83SMatthew G. Knepley const PetscInt cp = cone[c]; 9153be36e83SMatthew G. Knepley 9163be36e83SMatthew G. Knepley if (cp == p) continue; 9179566063dSJacob Faibussowitsch PetscCall(DMPlexMapToGlobalPoint(dm, cp, &candidates[off+idx], NULL)); 91863a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, " (%" PetscInt_FMT ",%" PetscInt_FMT ")", candidates[off+idx].rank, candidates[off+idx].index)); 9193be36e83SMatthew G. Knepley ++idx; 9203be36e83SMatthew G. Knepley } 9219566063dSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "\n")); 9223be36e83SMatthew G. Knepley } else { 9233be36e83SMatthew G. Knepley /* Add cone size to section */ 92463a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Scheduling shared face %" PetscInt_FMT "\n", rank, face)); 9259566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, face, &coneSize)); 9269566063dSJacob Faibussowitsch PetscCall(PetscHMapIJSet(faceHash, key, p)); 9279566063dSJacob Faibussowitsch PetscCall(PetscSectionAddDof(candidateSection, p, coneSize+1)); 9283be36e83SMatthew G. Knepley } 9293be36e83SMatthew G. Knepley } 9303be36e83SMatthew G. Knepley } 9313be36e83SMatthew G. Knepley PetscFunctionReturn(0); 9323be36e83SMatthew G. Knepley } 9333be36e83SMatthew G. Knepley 9342e72742cSMatthew G. Knepley /*@ 9352e72742cSMatthew G. Knepley DMPlexInterpolatePointSF - Insert interpolated points in the overlap into the PointSF in parallel, following local interpolation 9362e72742cSMatthew G. Knepley 937d083f849SBarry Smith Collective on dm 9382e72742cSMatthew G. Knepley 9392e72742cSMatthew G. Knepley Input Parameters: 9402e72742cSMatthew G. Knepley + dm - The interpolated DM 9412e72742cSMatthew G. Knepley - pointSF - The initial SF without interpolated points 9422e72742cSMatthew G. Knepley 9432e72742cSMatthew G. Knepley Output Parameter: 9442e72742cSMatthew G. Knepley . pointSF - The SF including interpolated points 9452e72742cSMatthew G. Knepley 946f0cfc026SVaclav Hapla Level: developer 9472e72742cSMatthew G. Knepley 9482e72742cSMatthew 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 9492e72742cSMatthew G. Knepley 950db781477SPatrick Sanan .seealso: `DMPlexInterpolate()`, `DMPlexUninterpolate()` 9512e72742cSMatthew G. Knepley @*/ 952e53487d3SMatthew G. Knepley PetscErrorCode DMPlexInterpolatePointSF(DM dm, PetscSF pointSF) 9532e72742cSMatthew G. Knepley { 9543be36e83SMatthew G. Knepley MPI_Comm comm; 9553be36e83SMatthew G. Knepley PetscHMapIJ remoteHash; 9563be36e83SMatthew G. Knepley PetscHMapI claimshash; 9573be36e83SMatthew G. Knepley PetscSection candidateSection, candidateRemoteSection, claimSection; 9583be36e83SMatthew G. Knepley PetscSFNode *candidates, *candidatesRemote, *claims; 9592e72742cSMatthew G. Knepley const PetscInt *localPoints, *rootdegree; 9602e72742cSMatthew G. Knepley const PetscSFNode *remotePoints; 9613be36e83SMatthew G. Knepley PetscInt ov, Nr, r, Nl, l; 9623be36e83SMatthew G. Knepley PetscInt candidatesSize, candidatesRemoteSize, claimsSize; 9633be36e83SMatthew G. Knepley PetscBool flg, debug = PETSC_FALSE; 964f0cfc026SVaclav Hapla PetscMPIInt rank; 9652e72742cSMatthew G. Knepley 9662e72742cSMatthew G. Knepley PetscFunctionBegin; 967f0cfc026SVaclav Hapla PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 968064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 9699566063dSJacob Faibussowitsch PetscCall(DMPlexIsDistributed(dm, &flg)); 970f0cfc026SVaclav Hapla if (!flg) PetscFunctionReturn(0); 9713be36e83SMatthew G. Knepley /* Set initial SF so that lower level queries work */ 9729566063dSJacob Faibussowitsch PetscCall(DMSetPointSF(dm, pointSF)); 9739566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 9749566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 9759566063dSJacob Faibussowitsch PetscCall(DMPlexGetOverlap(dm, &ov)); 97628b400f6SJacob Faibussowitsch PetscCheck(!ov,comm, PETSC_ERR_SUP, "Interpolation of overlapped DMPlex not implemented yet"); 9779566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(NULL, ((PetscObject) dm)->prefix, "-dmplex_interp_debug", &debug)); 9789566063dSJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions((PetscObject) dm, NULL, "-dm_interp_pre_view")); 9799566063dSJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions((PetscObject) pointSF, NULL, "-petscsf_interp_pre_view")); 9809566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_InterpolateSF,dm,0,0,0)); 9813be36e83SMatthew G. Knepley /* Step 0: Precalculations */ 9829566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(pointSF, &Nr, &Nl, &localPoints, &remotePoints)); 98308401ef6SPierre Jolivet PetscCheck(Nr >= 0,comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but input PointSF has no graph set"); 9849566063dSJacob Faibussowitsch PetscCall(PetscHMapIJCreate(&remoteHash)); 9853be36e83SMatthew G. Knepley for (l = 0; l < Nl; ++l) { 9863be36e83SMatthew G. Knepley PetscHashIJKey key; 9872e72742cSMatthew G. Knepley key.i = remotePoints[l].index; 9882e72742cSMatthew G. Knepley key.j = remotePoints[l].rank; 9899566063dSJacob Faibussowitsch PetscCall(PetscHMapIJSet(remoteHash, key, l)); 9907bffde78SMichael Lange } 99166aa2a39SMatthew G. Knepley /* Compute root degree to identify shared points */ 9929566063dSJacob Faibussowitsch PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 9939566063dSJacob Faibussowitsch PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 9949566063dSJacob Faibussowitsch PetscCall(IntArrayViewFromOptions(comm, "-interp_root_degree_view", "Root degree", "point", "degree", Nr, rootdegree)); 9953be36e83SMatthew G. Knepley /* 9963be36e83SMatthew G. Knepley 1) Loop over each leaf point $p$ at depth $d$ in the SF 9973be36e83SMatthew G. Knepley \item Get set $F(p)$ of faces $f$ in the support of $p$ for which 9983be36e83SMatthew G. Knepley \begin{itemize} 9993be36e83SMatthew G. Knepley \item all cone points of $f$ are shared 10003be36e83SMatthew G. Knepley \item $p$ is the cone point with smallest canonical number 10013be36e83SMatthew G. Knepley \end{itemize} 10023be36e83SMatthew G. Knepley \item Send $F(p)$ and the cone of each face to the active root point $r(p)$ 10033be36e83SMatthew 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 10043be36e83SMatthew G. Knepley \item Send the root face from the root back to all leaf process 10053be36e83SMatthew G. Knepley \item Leaf processes add the shared face to the SF 10063be36e83SMatthew G. Knepley */ 10073be36e83SMatthew G. Knepley /* Step 1: Construct section+SFNode array 10083be36e83SMatthew G. Knepley The section has entries for all shared faces for which we have a leaf point in the cone 10093be36e83SMatthew G. Knepley The array holds candidate shared faces, each face is refered to by the leaf point */ 10109566063dSJacob Faibussowitsch PetscCall(PetscSectionCreate(comm, &candidateSection)); 10119566063dSJacob Faibussowitsch PetscCall(PetscSectionSetChart(candidateSection, 0, Nr)); 10127bffde78SMichael Lange { 10133be36e83SMatthew G. Knepley PetscHMapIJ faceHash; 10142e72742cSMatthew G. Knepley 10159566063dSJacob Faibussowitsch PetscCall(PetscHMapIJCreate(&faceHash)); 10163be36e83SMatthew G. Knepley for (l = 0; l < Nl; ++l) { 10173be36e83SMatthew G. Knepley const PetscInt p = localPoints[l]; 10182e72742cSMatthew G. Knepley 101963a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] First pass leaf point %" PetscInt_FMT "\n", rank, p)); 10209566063dSJacob Faibussowitsch PetscCall(DMPlexAddSharedFace_Private(dm, candidateSection, NULL, faceHash, p, debug)); 10212e72742cSMatthew G. Knepley } 10229566063dSJacob Faibussowitsch PetscCall(PetscHMapIJClear(faceHash)); 10239566063dSJacob Faibussowitsch PetscCall(PetscSectionSetUp(candidateSection)); 10249566063dSJacob Faibussowitsch PetscCall(PetscSectionGetStorageSize(candidateSection, &candidatesSize)); 10259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(candidatesSize, &candidates)); 10263be36e83SMatthew G. Knepley for (l = 0; l < Nl; ++l) { 10273be36e83SMatthew G. Knepley const PetscInt p = localPoints[l]; 10282e72742cSMatthew G. Knepley 102963a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Second pass leaf point %" PetscInt_FMT "\n", rank, p)); 10309566063dSJacob Faibussowitsch PetscCall(DMPlexAddSharedFace_Private(dm, candidateSection, candidates, faceHash, p, debug)); 10312e72742cSMatthew G. Knepley } 10329566063dSJacob Faibussowitsch PetscCall(PetscHMapIJDestroy(&faceHash)); 10339566063dSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL)); 10347bffde78SMichael Lange } 10359566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject) candidateSection, "Candidate Section")); 10369566063dSJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions((PetscObject) candidateSection, NULL, "-petscsection_interp_candidate_view")); 10379566063dSJacob Faibussowitsch PetscCall(SFNodeArrayViewFromOptions(comm, "-petscsection_interp_candidate_view", "Candidates", NULL, candidatesSize, candidates)); 10383be36e83SMatthew G. Knepley /* Step 2: Gather candidate section / array pair into the root partition via inverse(multi(pointSF)). */ 10392e72742cSMatthew G. Knepley /* Note that this section is indexed by offsets into leaves, not by point number */ 10407bffde78SMichael Lange { 10417bffde78SMichael Lange PetscSF sfMulti, sfInverse, sfCandidates; 10427bffde78SMichael Lange PetscInt *remoteOffsets; 10432e72742cSMatthew G. Knepley 10449566063dSJacob Faibussowitsch PetscCall(PetscSFGetMultiSF(pointSF, &sfMulti)); 10459566063dSJacob Faibussowitsch PetscCall(PetscSFCreateInverseSF(sfMulti, &sfInverse)); 10469566063dSJacob Faibussowitsch PetscCall(PetscSectionCreate(comm, &candidateRemoteSection)); 10479566063dSJacob Faibussowitsch PetscCall(PetscSFDistributeSection(sfInverse, candidateSection, &remoteOffsets, candidateRemoteSection)); 10489566063dSJacob Faibussowitsch PetscCall(PetscSFCreateSectionSF(sfInverse, candidateSection, remoteOffsets, candidateRemoteSection, &sfCandidates)); 10499566063dSJacob Faibussowitsch PetscCall(PetscSectionGetStorageSize(candidateRemoteSection, &candidatesRemoteSize)); 10509566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(candidatesRemoteSize, &candidatesRemote)); 10519566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sfCandidates, MPIU_2INT, candidates, candidatesRemote,MPI_REPLACE)); 10529566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sfCandidates, MPIU_2INT, candidates, candidatesRemote,MPI_REPLACE)); 10539566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sfInverse)); 10549566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sfCandidates)); 10559566063dSJacob Faibussowitsch PetscCall(PetscFree(remoteOffsets)); 10562e72742cSMatthew G. Knepley 10579566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject) candidateRemoteSection, "Remote Candidate Section")); 10589566063dSJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions((PetscObject) candidateRemoteSection, NULL, "-petscsection_interp_candidate_remote_view")); 10599566063dSJacob Faibussowitsch PetscCall(SFNodeArrayViewFromOptions(comm, "-petscsection_interp_candidate_remote_view", "Remote Candidates", NULL, candidatesRemoteSize, candidatesRemote)); 10607bffde78SMichael Lange } 10613be36e83SMatthew 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 */ 10627bffde78SMichael Lange { 10633be36e83SMatthew G. Knepley PetscHashIJKLRemote faceTable; 10643be36e83SMatthew G. Knepley PetscInt idx, idx2; 10653be36e83SMatthew G. Knepley 10669566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemoteCreate(&faceTable)); 10672e72742cSMatthew G. Knepley /* There is a section point for every leaf attached to a given root point */ 10683be36e83SMatthew G. Knepley for (r = 0, idx = 0, idx2 = 0; r < Nr; ++r) { 10692e72742cSMatthew G. Knepley PetscInt deg; 10703be36e83SMatthew G. Knepley 10712e72742cSMatthew G. Knepley for (deg = 0; deg < rootdegree[r]; ++deg, ++idx) { 10722e72742cSMatthew G. Knepley PetscInt offset, dof, d; 10732e72742cSMatthew G. Knepley 10749566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(candidateRemoteSection, idx, &dof)); 10759566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(candidateRemoteSection, idx, &offset)); 10763be36e83SMatthew G. Knepley /* dof may include many faces from the remote process */ 10772e72742cSMatthew G. Knepley for (d = 0; d < dof; ++d) { 10783be36e83SMatthew G. Knepley const PetscInt hidx = offset+d; 10793be36e83SMatthew G. Knepley const PetscInt Np = candidatesRemote[hidx].index+1; 10803be36e83SMatthew G. Knepley const PetscSFNode rface = candidatesRemote[hidx+1]; 10813be36e83SMatthew G. Knepley const PetscSFNode *fcone = &candidatesRemote[hidx+2]; 10823be36e83SMatthew G. Knepley PetscSFNode fcp0; 10833be36e83SMatthew G. Knepley const PetscSFNode pmax = {PETSC_MAX_INT, PETSC_MAX_INT}; 10842e72742cSMatthew G. Knepley const PetscInt *join = NULL; 10853be36e83SMatthew G. Knepley PetscHashIJKLRemoteKey key; 10863be36e83SMatthew G. Knepley PetscHashIter iter; 10875f80ce2aSJacob Faibussowitsch PetscBool missing,mapToLocalPointFailed = PETSC_FALSE; 10882e72742cSMatthew G. Knepley PetscInt points[1024], p, joinSize; 10892e72742cSMatthew G. Knepley 109063a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d] Checking face (%" PetscInt_FMT ", %" PetscInt_FMT ") at (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ") with cone size %" PetscInt_FMT "\n", rank, rface.rank, rface.index, r, idx, d, Np)); 109163a3b9bcSJacob Faibussowitsch PetscCheck(Np <= 4,PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle face (%" PetscInt_FMT ", %" PetscInt_FMT ") at (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ") with %" PetscInt_FMT " cone points", rface.rank, rface.index, r, idx, d, Np); 10923be36e83SMatthew G. Knepley fcp0.rank = rank; 10933be36e83SMatthew G. Knepley fcp0.index = r; 10943be36e83SMatthew G. Knepley d += Np; 10953be36e83SMatthew G. Knepley /* Put remote face in hash table */ 10963be36e83SMatthew G. Knepley key.i = fcp0; 10973be36e83SMatthew G. Knepley key.j = fcone[0]; 10983be36e83SMatthew G. Knepley key.k = Np > 2 ? fcone[1] : pmax; 10993be36e83SMatthew G. Knepley key.l = Np > 3 ? fcone[2] : pmax; 11009566063dSJacob Faibussowitsch PetscCall(PetscSortSFNode(Np, (PetscSFNode *) &key)); 11019566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemotePut(faceTable, key, &iter, &missing)); 11023be36e83SMatthew G. Knepley if (missing) { 110363a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d] Setting remote face (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, rface.index, rface.rank)); 11049566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemoteIterSet(faceTable, iter, rface)); 11053be36e83SMatthew G. Knepley } else { 11063be36e83SMatthew G. Knepley PetscSFNode oface; 11073be36e83SMatthew G. Knepley 11089566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemoteIterGet(faceTable, iter, &oface)); 11093be36e83SMatthew G. Knepley if ((rface.rank < oface.rank) || (rface.rank == oface.rank && rface.index < oface.index)) { 111063a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d] Replacing with remote face (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, rface.index, rface.rank)); 11119566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemoteIterSet(faceTable, iter, rface)); 11123be36e83SMatthew G. Knepley } 11133be36e83SMatthew G. Knepley } 11143be36e83SMatthew G. Knepley /* Check for local face */ 11152e72742cSMatthew G. Knepley points[0] = r; 11163be36e83SMatthew G. Knepley for (p = 1; p < Np; ++p) { 11179566063dSJacob Faibussowitsch PetscCall(DMPlexMapToLocalPoint(dm, remoteHash, fcone[p-1], &points[p], &mapToLocalPointFailed)); 11185f80ce2aSJacob Faibussowitsch if (mapToLocalPointFailed) break; /* We got a point not in our overlap */ 111963a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d] Checking local candidate %" PetscInt_FMT "\n", rank, points[p])); 11207bffde78SMichael Lange } 11215f80ce2aSJacob Faibussowitsch if (mapToLocalPointFailed) continue; 11229566063dSJacob Faibussowitsch PetscCall(DMPlexGetJoin(dm, Np, points, &joinSize, &join)); 11237bffde78SMichael Lange if (joinSize == 1) { 11243be36e83SMatthew G. Knepley PetscSFNode lface; 11253be36e83SMatthew G. Knepley PetscSFNode oface; 11263be36e83SMatthew G. Knepley 11273be36e83SMatthew G. Knepley /* Always replace with local face */ 11283be36e83SMatthew G. Knepley lface.rank = rank; 11293be36e83SMatthew G. Knepley lface.index = join[0]; 11309566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemoteIterGet(faceTable, iter, &oface)); 113163a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d] Replacing (%" PetscInt_FMT ", %" PetscInt_FMT ") with local face (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, oface.index, oface.rank, lface.index, lface.rank)); 11329566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemoteIterSet(faceTable, iter, lface)); 11337bffde78SMichael Lange } 11349566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreJoin(dm, Np, points, &joinSize, &join)); 11353be36e83SMatthew G. Knepley } 11363be36e83SMatthew G. Knepley } 11373be36e83SMatthew G. Knepley /* Put back faces for this root */ 11383be36e83SMatthew G. Knepley for (deg = 0; deg < rootdegree[r]; ++deg, ++idx2) { 11393be36e83SMatthew G. Knepley PetscInt offset, dof, d; 11403be36e83SMatthew G. Knepley 11419566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(candidateRemoteSection, idx2, &dof)); 11429566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(candidateRemoteSection, idx2, &offset)); 11433be36e83SMatthew G. Knepley /* dof may include many faces from the remote process */ 11443be36e83SMatthew G. Knepley for (d = 0; d < dof; ++d) { 11453be36e83SMatthew G. Knepley const PetscInt hidx = offset+d; 11463be36e83SMatthew G. Knepley const PetscInt Np = candidatesRemote[hidx].index+1; 11473be36e83SMatthew G. Knepley const PetscSFNode *fcone = &candidatesRemote[hidx+2]; 11483be36e83SMatthew G. Knepley PetscSFNode fcp0; 11493be36e83SMatthew G. Knepley const PetscSFNode pmax = {PETSC_MAX_INT, PETSC_MAX_INT}; 11503be36e83SMatthew G. Knepley PetscHashIJKLRemoteKey key; 11513be36e83SMatthew G. Knepley PetscHashIter iter; 11523be36e83SMatthew G. Knepley PetscBool missing; 11533be36e83SMatthew G. Knepley 115463a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d] Entering face at (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, r, idx)); 115563a3b9bcSJacob Faibussowitsch PetscCheck(Np <= 4,PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle faces with %" PetscInt_FMT " cone points", Np); 11563be36e83SMatthew G. Knepley fcp0.rank = rank; 11573be36e83SMatthew G. Knepley fcp0.index = r; 11583be36e83SMatthew G. Knepley d += Np; 11593be36e83SMatthew G. Knepley /* Find remote face in hash table */ 11603be36e83SMatthew G. Knepley key.i = fcp0; 11613be36e83SMatthew G. Knepley key.j = fcone[0]; 11623be36e83SMatthew G. Knepley key.k = Np > 2 ? fcone[1] : pmax; 11633be36e83SMatthew G. Knepley key.l = Np > 3 ? fcone[2] : pmax; 11649566063dSJacob Faibussowitsch PetscCall(PetscSortSFNode(Np, (PetscSFNode *) &key)); 116563a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d] key (%" PetscInt_FMT ", %" PetscInt_FMT ") (%" PetscInt_FMT ", %" PetscInt_FMT ") (%" PetscInt_FMT ", %" PetscInt_FMT ") (%" PetscInt_FMT ", %" PetscInt_FMT ")\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)); 11669566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemotePut(faceTable, key, &iter, &missing)); 116763a3b9bcSJacob Faibussowitsch PetscCheck(!missing,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Root %" PetscInt_FMT " Idx %" PetscInt_FMT " ought to have an associated face", r, idx2); 11689566063dSJacob Faibussowitsch else PetscCall(PetscHashIJKLRemoteIterGet(faceTable, iter, &candidatesRemote[hidx])); 11697bffde78SMichael Lange } 11707bffde78SMichael Lange } 11717bffde78SMichael Lange } 11729566063dSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedFlush(PetscObjectComm((PetscObject) dm), NULL)); 11739566063dSJacob Faibussowitsch PetscCall(PetscHashIJKLRemoteDestroy(&faceTable)); 11747bffde78SMichael Lange } 11753be36e83SMatthew G. Knepley /* Step 4: Push back owned faces */ 11767bffde78SMichael Lange { 11777bffde78SMichael Lange PetscSF sfMulti, sfClaims, sfPointNew; 11787bffde78SMichael Lange PetscSFNode *remotePointsNew; 11792e72742cSMatthew G. Knepley PetscInt *remoteOffsets, *localPointsNew; 11803be36e83SMatthew G. Knepley PetscInt pStart, pEnd, r, NlNew, p; 11812e72742cSMatthew G. Knepley 11823be36e83SMatthew G. Knepley /* 4) Push claims back to receiver via the MultiSF and derive new pointSF mapping on receiver */ 11839566063dSJacob Faibussowitsch PetscCall(PetscSFGetMultiSF(pointSF, &sfMulti)); 11849566063dSJacob Faibussowitsch PetscCall(PetscSectionCreate(comm, &claimSection)); 11859566063dSJacob Faibussowitsch PetscCall(PetscSFDistributeSection(sfMulti, candidateRemoteSection, &remoteOffsets, claimSection)); 11869566063dSJacob Faibussowitsch PetscCall(PetscSFCreateSectionSF(sfMulti, candidateRemoteSection, remoteOffsets, claimSection, &sfClaims)); 11879566063dSJacob Faibussowitsch PetscCall(PetscSectionGetStorageSize(claimSection, &claimsSize)); 11889566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(claimsSize, &claims)); 11893be36e83SMatthew G. Knepley for (p = 0; p < claimsSize; ++p) claims[p].rank = -1; 11909566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sfClaims, MPIU_2INT, candidatesRemote, claims,MPI_REPLACE)); 11919566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sfClaims, MPIU_2INT, candidatesRemote, claims,MPI_REPLACE)); 11929566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sfClaims)); 11939566063dSJacob Faibussowitsch PetscCall(PetscFree(remoteOffsets)); 11949566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject) claimSection, "Claim Section")); 11959566063dSJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions((PetscObject) claimSection, NULL, "-petscsection_interp_claim_view")); 11969566063dSJacob Faibussowitsch PetscCall(SFNodeArrayViewFromOptions(comm, "-petscsection_interp_claim_view", "Claims", NULL, claimsSize, claims)); 11973be36e83SMatthew G. Knepley /* Step 5) Walk the original section of local supports and add an SF entry for each updated item */ 11983be36e83SMatthew 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 */ 11999566063dSJacob Faibussowitsch PetscCall(PetscHMapICreate(&claimshash)); 12003be36e83SMatthew G. Knepley for (r = 0; r < Nr; ++r) { 12013be36e83SMatthew G. Knepley PetscInt dof, off, d; 12022e72742cSMatthew G. Knepley 120363a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Checking root for claims %" PetscInt_FMT "\n", rank, r)); 12049566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(candidateSection, r, &dof)); 12059566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(candidateSection, r, &off)); 12062e72742cSMatthew G. Knepley for (d = 0; d < dof;) { 12073be36e83SMatthew G. Knepley if (claims[off+d].rank >= 0) { 12083be36e83SMatthew G. Knepley const PetscInt faceInd = off+d; 12093be36e83SMatthew G. Knepley const PetscInt Np = candidates[off+d].index; 12102e72742cSMatthew G. Knepley const PetscInt *join = NULL; 12112e72742cSMatthew G. Knepley PetscInt joinSize, points[1024], c; 12122e72742cSMatthew G. Knepley 121363a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Found claim for remote point (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, claims[faceInd].rank, claims[faceInd].index)); 12143be36e83SMatthew G. Knepley points[0] = r; 121563a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] point %" PetscInt_FMT "\n", rank, points[0])); 12163be36e83SMatthew G. Knepley for (c = 0, d += 2; c < Np; ++c, ++d) { 12179566063dSJacob Faibussowitsch PetscCall(DMPlexMapToLocalPoint(dm, remoteHash, candidates[off+d], &points[c+1], NULL)); 121863a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] point %" PetscInt_FMT "\n", rank, points[c+1])); 12192e72742cSMatthew G. Knepley } 12209566063dSJacob Faibussowitsch PetscCall(DMPlexGetJoin(dm, Np+1, points, &joinSize, &join)); 12212e72742cSMatthew G. Knepley if (joinSize == 1) { 12223be36e83SMatthew G. Knepley if (claims[faceInd].rank == rank) { 122363a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Ignoring local face %" PetscInt_FMT " for non-remote partner\n", rank, join[0])); 12243be36e83SMatthew G. Knepley } else { 122563a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Found local face %" PetscInt_FMT "\n", rank, join[0])); 12269566063dSJacob Faibussowitsch PetscCall(PetscHMapISet(claimshash, join[0], faceInd)); 12272e72742cSMatthew G. Knepley } 12283be36e83SMatthew G. Knepley } else { 12299566063dSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] Failed to find face\n", rank)); 12303be36e83SMatthew G. Knepley } 12319566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreJoin(dm, Np+1, points, &joinSize, &join)); 12323be36e83SMatthew G. Knepley } else { 123363a3b9bcSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedPrintf(comm, "[%d] No claim for point %" PetscInt_FMT "\n", rank, r)); 12343be36e83SMatthew G. Knepley d += claims[off+d].index+1; 12357bffde78SMichael Lange } 12367bffde78SMichael Lange } 12373be36e83SMatthew G. Knepley } 12389566063dSJacob Faibussowitsch if (debug) PetscCall(PetscSynchronizedFlush(comm, NULL)); 12393be36e83SMatthew G. Knepley /* Step 6) Create new pointSF from hashed claims */ 12409566063dSJacob Faibussowitsch PetscCall(PetscHMapIGetSize(claimshash, &NlNew)); 12419566063dSJacob Faibussowitsch PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 12429566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nl + NlNew, &localPointsNew)); 12439566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nl + NlNew, &remotePointsNew)); 12443be36e83SMatthew G. Knepley for (l = 0; l < Nl; ++l) { 12453be36e83SMatthew G. Knepley localPointsNew[l] = localPoints[l]; 12463be36e83SMatthew G. Knepley remotePointsNew[l].index = remotePoints[l].index; 12473be36e83SMatthew G. Knepley remotePointsNew[l].rank = remotePoints[l].rank; 12487bffde78SMichael Lange } 12493be36e83SMatthew G. Knepley p = Nl; 12509566063dSJacob Faibussowitsch PetscCall(PetscHMapIGetKeys(claimshash, &p, localPointsNew)); 12513be36e83SMatthew G. Knepley /* We sort new points, and assume they are numbered after all existing points */ 12529566063dSJacob Faibussowitsch PetscCall(PetscSortInt(NlNew, &localPointsNew[Nl])); 12533be36e83SMatthew G. Knepley for (p = Nl; p < Nl + NlNew; ++p) { 12543be36e83SMatthew G. Knepley PetscInt off; 12559566063dSJacob Faibussowitsch PetscCall(PetscHMapIGet(claimshash, localPointsNew[p], &off)); 12561dca8a05SBarry Smith PetscCheck(claims[off].rank >= 0 && claims[off].index >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid claim for local point %" PetscInt_FMT ", (%" PetscInt_FMT ", %" PetscInt_FMT ")", localPointsNew[p], claims[off].rank, claims[off].index); 12573be36e83SMatthew G. Knepley remotePointsNew[p] = claims[off]; 12587bffde78SMichael Lange } 12599566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(comm, &sfPointNew)); 12609566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(sfPointNew, pEnd-pStart, Nl+NlNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER)); 12619566063dSJacob Faibussowitsch PetscCall(PetscSFSetUp(sfPointNew)); 12629566063dSJacob Faibussowitsch PetscCall(DMSetPointSF(dm, sfPointNew)); 12639566063dSJacob Faibussowitsch PetscCall(PetscObjectViewFromOptions((PetscObject) sfPointNew, NULL, "-petscsf_interp_view")); 12649566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sfPointNew)); 12659566063dSJacob Faibussowitsch PetscCall(PetscHMapIDestroy(&claimshash)); 12667bffde78SMichael Lange } 12679566063dSJacob Faibussowitsch PetscCall(PetscHMapIJDestroy(&remoteHash)); 12689566063dSJacob Faibussowitsch PetscCall(PetscSectionDestroy(&candidateSection)); 12699566063dSJacob Faibussowitsch PetscCall(PetscSectionDestroy(&candidateRemoteSection)); 12709566063dSJacob Faibussowitsch PetscCall(PetscSectionDestroy(&claimSection)); 12719566063dSJacob Faibussowitsch PetscCall(PetscFree(candidates)); 12729566063dSJacob Faibussowitsch PetscCall(PetscFree(candidatesRemote)); 12739566063dSJacob Faibussowitsch PetscCall(PetscFree(claims)); 12749566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_InterpolateSF,dm,0,0,0)); 12757bffde78SMichael Lange PetscFunctionReturn(0); 12767bffde78SMichael Lange } 12777bffde78SMichael Lange 1278248eb259SVaclav Hapla /*@ 127980330477SMatthew G. Knepley DMPlexInterpolate - Take in a cell-vertex mesh and return one with all intermediate faces, edges, etc. 128080330477SMatthew G. Knepley 1281d083f849SBarry Smith Collective on dm 128280330477SMatthew G. Knepley 1283e56d480eSMatthew G. Knepley Input Parameters: 1284e56d480eSMatthew G. Knepley + dm - The DMPlex object with only cells and vertices 128510a67516SMatthew G. Knepley - dmInt - The interpolated DM 128680330477SMatthew G. Knepley 128780330477SMatthew G. Knepley Output Parameter: 12884e3744c5SMatthew G. Knepley . dmInt - The complete DMPlex object 128980330477SMatthew G. Knepley 129080330477SMatthew G. Knepley Level: intermediate 129180330477SMatthew G. Knepley 129295452b02SPatrick Sanan Notes: 12937fb59074SVaclav Hapla Labels and coordinates are copied. 129443eeeb2dSStefano Zampini 12959ade3219SVaclav Hapla Developer Notes: 12969ade3219SVaclav Hapla It sets plex->interpolated = DMPLEX_INTERPOLATED_FULL. 12979ade3219SVaclav Hapla 1298db781477SPatrick Sanan .seealso: `DMPlexUninterpolate()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCopyCoordinates()` 129980330477SMatthew G. Knepley @*/ 13009f074e33SMatthew G Knepley PetscErrorCode DMPlexInterpolate(DM dm, DM *dmInt) 13019f074e33SMatthew G Knepley { 1302a7748839SVaclav Hapla DMPlexInterpolatedFlag interpolated; 13039a5b13a2SMatthew G Knepley DM idm, odm = dm; 13047bffde78SMichael Lange PetscSF sfPoint; 13052e1b13c2SMatthew G. Knepley PetscInt depth, dim, d; 130610a67516SMatthew G. Knepley const char *name; 1307b325530aSVaclav Hapla PetscBool flg=PETSC_TRUE; 13089f074e33SMatthew G Knepley 13099f074e33SMatthew G Knepley PetscFunctionBegin; 131010a67516SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 131110a67516SMatthew G. Knepley PetscValidPointer(dmInt, 2); 13129566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(DMPLEX_Interpolate,dm,0,0,0)); 13139566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepth(dm, &depth)); 13149566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 13159566063dSJacob Faibussowitsch PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 131608401ef6SPierre Jolivet PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes"); 1317827c4036SVaclav Hapla if (interpolated == DMPLEX_INTERPOLATED_FULL) { 13189566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject) dm)); 131976b791aaSMatthew G. Knepley idm = dm; 1320b21b8912SMatthew G. Knepley } else { 13219a5b13a2SMatthew G Knepley for (d = 1; d < dim; ++d) { 13229a5b13a2SMatthew G Knepley /* Create interpolated mesh */ 13239566063dSJacob Faibussowitsch PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &idm)); 13249566063dSJacob Faibussowitsch PetscCall(DMSetType(idm, DMPLEX)); 13259566063dSJacob Faibussowitsch PetscCall(DMSetDimension(idm, dim)); 13267bffde78SMichael Lange if (depth > 0) { 13279566063dSJacob Faibussowitsch PetscCall(DMPlexInterpolateFaces_Internal(odm, 1, idm)); 13289566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(odm, &sfPoint)); 132994488200SVaclav Hapla { 13303be36e83SMatthew G. Knepley /* TODO: We need to systematically fix cases of distributed Plexes with no graph set */ 133194488200SVaclav Hapla PetscInt nroots; 13329566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL)); 13339566063dSJacob Faibussowitsch if (nroots >= 0) PetscCall(DMPlexInterpolatePointSF(idm, sfPoint)); 133494488200SVaclav Hapla } 13357bffde78SMichael Lange } 13369566063dSJacob Faibussowitsch if (odm != dm) PetscCall(DMDestroy(&odm)); 13379a5b13a2SMatthew G Knepley odm = idm; 13389f074e33SMatthew G Knepley } 13399566063dSJacob Faibussowitsch PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 13409566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject) idm, name)); 13419566063dSJacob Faibussowitsch PetscCall(DMPlexCopyCoordinates(dm, idm)); 13429566063dSJacob Faibussowitsch PetscCall(DMCopyLabels(dm, idm, PETSC_COPY_VALUES, PETSC_FALSE, DM_COPY_LABELS_FAIL)); 13439566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_interpolate_orient_interfaces", &flg, NULL)); 13449566063dSJacob Faibussowitsch if (flg) PetscCall(DMPlexOrientInterface_Internal(idm)); 134584699f70SSatish Balay } 1346827c4036SVaclav Hapla /* This function makes the mesh fully interpolated on all ranks */ 1347827c4036SVaclav Hapla { 1348d6e9e4f7SVaclav Hapla DM_Plex *plex = (DM_Plex *) idm->data; 1349827c4036SVaclav Hapla plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_FULL; 1350827c4036SVaclav Hapla } 1351*5de52c6dSVaclav Hapla PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, idm)); 13529a5b13a2SMatthew G Knepley *dmInt = idm; 13539566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(DMPLEX_Interpolate,dm,0,0,0)); 13549f074e33SMatthew G Knepley PetscFunctionReturn(0); 13559f074e33SMatthew G Knepley } 135607b0a1fcSMatthew G Knepley 135780330477SMatthew G. Knepley /*@ 135880330477SMatthew G. Knepley DMPlexCopyCoordinates - Copy coordinates from one mesh to another with the same vertices 135980330477SMatthew G. Knepley 1360d083f849SBarry Smith Collective on dmA 136180330477SMatthew G. Knepley 136280330477SMatthew G. Knepley Input Parameter: 136380330477SMatthew G. Knepley . dmA - The DMPlex object with initial coordinates 136480330477SMatthew G. Knepley 136580330477SMatthew G. Knepley Output Parameter: 136680330477SMatthew G. Knepley . dmB - The DMPlex object with copied coordinates 136780330477SMatthew G. Knepley 136880330477SMatthew G. Knepley Level: intermediate 136980330477SMatthew G. Knepley 137080330477SMatthew G. Knepley Note: This is typically used when adding pieces other than vertices to a mesh 137180330477SMatthew G. Knepley 1372db781477SPatrick Sanan .seealso: `DMCopyLabels()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMGetCoordinateSection()` 137380330477SMatthew G. Knepley @*/ 137407b0a1fcSMatthew G Knepley PetscErrorCode DMPlexCopyCoordinates(DM dmA, DM dmB) 137507b0a1fcSMatthew G Knepley { 137607b0a1fcSMatthew G Knepley Vec coordinatesA, coordinatesB; 137743eeeb2dSStefano Zampini VecType vtype; 137807b0a1fcSMatthew G Knepley PetscSection coordSectionA, coordSectionB; 137907b0a1fcSMatthew G Knepley PetscScalar *coordsA, *coordsB; 13800bedd6beSMatthew G. Knepley PetscInt spaceDim, Nf, vStartA, vStartB, vEndA, vEndB, coordSizeB, v, d; 138190a8aa44SJed Brown PetscInt cStartA, cEndA, cStartB, cEndB, cS, cE, cdim; 138243eeeb2dSStefano Zampini PetscBool lc = PETSC_FALSE; 138307b0a1fcSMatthew G Knepley 138407b0a1fcSMatthew G Knepley PetscFunctionBegin; 138543eeeb2dSStefano Zampini PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 138643eeeb2dSStefano Zampini PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 138776b791aaSMatthew G. Knepley if (dmA == dmB) PetscFunctionReturn(0); 13889566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmA, &cdim)); 13899566063dSJacob Faibussowitsch PetscCall(DMSetCoordinateDim(dmB, cdim)); 13909566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dmA, 0, &vStartA, &vEndA)); 13919566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dmB, 0, &vStartB, &vEndB)); 139263a3b9bcSJacob Faibussowitsch PetscCheck((vEndA-vStartA) == (vEndB-vStartB),PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of vertices in first DM %" PetscInt_FMT " != %" PetscInt_FMT " in the second DM", vEndA-vStartA, vEndB-vStartB); 139361a622f3SMatthew G. Knepley /* Copy over discretization if it exists */ 139461a622f3SMatthew G. Knepley { 139561a622f3SMatthew G. Knepley DM cdmA, cdmB; 139661a622f3SMatthew G. Knepley PetscDS dsA, dsB; 139761a622f3SMatthew G. Knepley PetscObject objA, objB; 139861a622f3SMatthew G. Knepley PetscClassId idA, idB; 139961a622f3SMatthew G. Knepley const PetscScalar *constants; 140061a622f3SMatthew G. Knepley PetscInt cdim, Nc; 140161a622f3SMatthew G. Knepley 14029566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dmA, &cdmA)); 14039566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dmB, &cdmB)); 14049566063dSJacob Faibussowitsch PetscCall(DMGetField(cdmA, 0, NULL, &objA)); 14059566063dSJacob Faibussowitsch PetscCall(DMGetField(cdmB, 0, NULL, &objB)); 14069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objA, &idA)); 14079566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(objB, &idB)); 140861a622f3SMatthew G. Knepley if ((idA == PETSCFE_CLASSID) && (idA != idB)) { 14099566063dSJacob Faibussowitsch PetscCall(DMSetField(cdmB, 0, NULL, objA)); 14109566063dSJacob Faibussowitsch PetscCall(DMCreateDS(cdmB)); 14119566063dSJacob Faibussowitsch PetscCall(DMGetDS(cdmA, &dsA)); 14129566063dSJacob Faibussowitsch PetscCall(DMGetDS(cdmB, &dsB)); 14139566063dSJacob Faibussowitsch PetscCall(PetscDSGetCoordinateDimension(dsA, &cdim)); 14149566063dSJacob Faibussowitsch PetscCall(PetscDSSetCoordinateDimension(dsB, cdim)); 14159566063dSJacob Faibussowitsch PetscCall(PetscDSGetConstants(dsA, &Nc, &constants)); 14169566063dSJacob Faibussowitsch PetscCall(PetscDSSetConstants(dsB, Nc, (PetscScalar *) constants)); 141761a622f3SMatthew G. Knepley } 141861a622f3SMatthew G. Knepley } 14199566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmA, 0, &cStartA, &cEndA)); 14209566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dmB, 0, &cStartB, &cEndB)); 14219566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateSection(dmA, &coordSectionA)); 14229566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateSection(dmB, &coordSectionB)); 1423972bc18aSToby Isaac if (coordSectionA == coordSectionB) PetscFunctionReturn(0); 14249566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(coordSectionA, &Nf)); 14250bedd6beSMatthew G. Knepley if (!Nf) PetscFunctionReturn(0); 142663a3b9bcSJacob Faibussowitsch PetscCheck(Nf <= 1,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of coordinate fields must be 1, not %" PetscInt_FMT, Nf); 1427df26b574SMatthew G. Knepley if (!coordSectionB) { 1428df26b574SMatthew G. Knepley PetscInt dim; 1429df26b574SMatthew G. Knepley 14309566063dSJacob Faibussowitsch PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) coordSectionA), &coordSectionB)); 14319566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dmA, &dim)); 14329566063dSJacob Faibussowitsch PetscCall(DMSetCoordinateSection(dmB, dim, coordSectionB)); 14339566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject) coordSectionB)); 1434df26b574SMatthew G. Knepley } 14359566063dSJacob Faibussowitsch PetscCall(PetscSectionSetNumFields(coordSectionB, 1)); 14369566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldComponents(coordSectionA, 0, &spaceDim)); 14379566063dSJacob Faibussowitsch PetscCall(PetscSectionSetFieldComponents(coordSectionB, 0, spaceDim)); 14389566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(coordSectionA, &cS, &cE)); 143943eeeb2dSStefano Zampini if (cStartA <= cS && cS < cEndA) { /* localized coordinates */ 144063a3b9bcSJacob Faibussowitsch PetscCheck((cEndA-cStartA) == (cEndB-cStartB),PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cells in first DM %" PetscInt_FMT " != %" PetscInt_FMT " in the second DM", cEndA-cStartA, cEndB-cStartB); 144143eeeb2dSStefano Zampini cS = cS - cStartA + cStartB; 144243eeeb2dSStefano Zampini cE = vEndB; 144343eeeb2dSStefano Zampini lc = PETSC_TRUE; 144443eeeb2dSStefano Zampini } else { 144543eeeb2dSStefano Zampini cS = vStartB; 144643eeeb2dSStefano Zampini cE = vEndB; 144743eeeb2dSStefano Zampini } 14489566063dSJacob Faibussowitsch PetscCall(PetscSectionSetChart(coordSectionB, cS, cE)); 144907b0a1fcSMatthew G Knepley for (v = vStartB; v < vEndB; ++v) { 14509566063dSJacob Faibussowitsch PetscCall(PetscSectionSetDof(coordSectionB, v, spaceDim)); 14519566063dSJacob Faibussowitsch PetscCall(PetscSectionSetFieldDof(coordSectionB, v, 0, spaceDim)); 145207b0a1fcSMatthew G Knepley } 145343eeeb2dSStefano Zampini if (lc) { /* localized coordinates */ 145443eeeb2dSStefano Zampini PetscInt c; 145543eeeb2dSStefano Zampini 145643eeeb2dSStefano Zampini for (c = cS-cStartB; c < cEndB-cStartB; c++) { 145743eeeb2dSStefano Zampini PetscInt dof; 145843eeeb2dSStefano Zampini 14599566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(coordSectionA, c + cStartA, &dof)); 14609566063dSJacob Faibussowitsch PetscCall(PetscSectionSetDof(coordSectionB, c + cStartB, dof)); 14619566063dSJacob Faibussowitsch PetscCall(PetscSectionSetFieldDof(coordSectionB, c + cStartB, 0, dof)); 146243eeeb2dSStefano Zampini } 146343eeeb2dSStefano Zampini } 14649566063dSJacob Faibussowitsch PetscCall(PetscSectionSetUp(coordSectionB)); 14659566063dSJacob Faibussowitsch PetscCall(PetscSectionGetStorageSize(coordSectionB, &coordSizeB)); 14669566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dmA, &coordinatesA)); 14679566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &coordinatesB)); 14689566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject) coordinatesB, "coordinates")); 14699566063dSJacob Faibussowitsch PetscCall(VecSetSizes(coordinatesB, coordSizeB, PETSC_DETERMINE)); 14709566063dSJacob Faibussowitsch PetscCall(VecGetBlockSize(coordinatesA, &d)); 14719566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(coordinatesB, d)); 14729566063dSJacob Faibussowitsch PetscCall(VecGetType(coordinatesA, &vtype)); 14739566063dSJacob Faibussowitsch PetscCall(VecSetType(coordinatesB, vtype)); 14749566063dSJacob Faibussowitsch PetscCall(VecGetArray(coordinatesA, &coordsA)); 14759566063dSJacob Faibussowitsch PetscCall(VecGetArray(coordinatesB, &coordsB)); 147607b0a1fcSMatthew G Knepley for (v = 0; v < vEndB-vStartB; ++v) { 147743eeeb2dSStefano Zampini PetscInt offA, offB; 147843eeeb2dSStefano Zampini 14799566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(coordSectionA, v + vStartA, &offA)); 14809566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(coordSectionB, v + vStartB, &offB)); 148107b0a1fcSMatthew G Knepley for (d = 0; d < spaceDim; ++d) { 148243eeeb2dSStefano Zampini coordsB[offB+d] = coordsA[offA+d]; 148343eeeb2dSStefano Zampini } 148443eeeb2dSStefano Zampini } 148543eeeb2dSStefano Zampini if (lc) { /* localized coordinates */ 148643eeeb2dSStefano Zampini PetscInt c; 148743eeeb2dSStefano Zampini 148843eeeb2dSStefano Zampini for (c = cS-cStartB; c < cEndB-cStartB; c++) { 148943eeeb2dSStefano Zampini PetscInt dof, offA, offB; 149043eeeb2dSStefano Zampini 14919566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(coordSectionA, c + cStartA, &offA)); 14929566063dSJacob Faibussowitsch PetscCall(PetscSectionGetOffset(coordSectionB, c + cStartB, &offB)); 14939566063dSJacob Faibussowitsch PetscCall(PetscSectionGetDof(coordSectionA, c + cStartA, &dof)); 14949566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(coordsB + offB,coordsA + offA,dof)); 149507b0a1fcSMatthew G Knepley } 149607b0a1fcSMatthew G Knepley } 14979566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(coordinatesA, &coordsA)); 14989566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(coordinatesB, &coordsB)); 14999566063dSJacob Faibussowitsch PetscCall(DMSetCoordinatesLocal(dmB, coordinatesB)); 15009566063dSJacob Faibussowitsch PetscCall(VecDestroy(&coordinatesB)); 150107b0a1fcSMatthew G Knepley PetscFunctionReturn(0); 150207b0a1fcSMatthew G Knepley } 15035c386225SMatthew G. Knepley 15044e3744c5SMatthew G. Knepley /*@ 15054e3744c5SMatthew G. Knepley DMPlexUninterpolate - Take in a mesh with all intermediate faces, edges, etc. and return a cell-vertex mesh 15064e3744c5SMatthew G. Knepley 1507d083f849SBarry Smith Collective on dm 15084e3744c5SMatthew G. Knepley 15094e3744c5SMatthew G. Knepley Input Parameter: 15104e3744c5SMatthew G. Knepley . dm - The complete DMPlex object 15114e3744c5SMatthew G. Knepley 15124e3744c5SMatthew G. Knepley Output Parameter: 15134e3744c5SMatthew G. Knepley . dmUnint - The DMPlex object with only cells and vertices 15144e3744c5SMatthew G. Knepley 15154e3744c5SMatthew G. Knepley Level: intermediate 15164e3744c5SMatthew G. Knepley 151795452b02SPatrick Sanan Notes: 151895452b02SPatrick Sanan It does not copy over the coordinates. 151943eeeb2dSStefano Zampini 15209ade3219SVaclav Hapla Developer Notes: 15219ade3219SVaclav Hapla It sets plex->interpolated = DMPLEX_INTERPOLATED_NONE. 15229ade3219SVaclav Hapla 1523db781477SPatrick Sanan .seealso: `DMPlexInterpolate()`, `DMPlexCreateFromCellListPetsc()`, `DMPlexCopyCoordinates()` 15244e3744c5SMatthew G. Knepley @*/ 15254e3744c5SMatthew G. Knepley PetscErrorCode DMPlexUninterpolate(DM dm, DM *dmUnint) 15264e3744c5SMatthew G. Knepley { 1527827c4036SVaclav Hapla DMPlexInterpolatedFlag interpolated; 15284e3744c5SMatthew G. Knepley DM udm; 1529412e9a14SMatthew G. Knepley PetscInt dim, vStart, vEnd, cStart, cEnd, c, maxConeSize = 0, *cone; 15304e3744c5SMatthew G. Knepley 15314e3744c5SMatthew G. Knepley PetscFunctionBegin; 153243eeeb2dSStefano Zampini PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 153343eeeb2dSStefano Zampini PetscValidPointer(dmUnint, 2); 15349566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 15359566063dSJacob Faibussowitsch PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 153608401ef6SPierre Jolivet PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes"); 1537827c4036SVaclav Hapla if (interpolated == DMPLEX_INTERPOLATED_NONE || dim <= 1) { 1538827c4036SVaclav Hapla /* in case dim <= 1 just keep the DMPLEX_INTERPOLATED_FULL flag */ 15399566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject) dm)); 1540595d4abbSMatthew G. Knepley *dmUnint = dm; 1541595d4abbSMatthew G. Knepley PetscFunctionReturn(0); 15424e3744c5SMatthew G. Knepley } 15439566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 15449566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 15459566063dSJacob Faibussowitsch PetscCall(DMCreate(PetscObjectComm((PetscObject) dm), &udm)); 15469566063dSJacob Faibussowitsch PetscCall(DMSetType(udm, DMPLEX)); 15479566063dSJacob Faibussowitsch PetscCall(DMSetDimension(udm, dim)); 15489566063dSJacob Faibussowitsch PetscCall(DMPlexSetChart(udm, cStart, vEnd)); 15494e3744c5SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1550595d4abbSMatthew G. Knepley PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 15514e3744c5SMatthew G. Knepley 15529566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 15534e3744c5SMatthew G. Knepley for (cl = 0; cl < closureSize*2; cl += 2) { 15544e3744c5SMatthew G. Knepley const PetscInt p = closure[cl]; 15554e3744c5SMatthew G. Knepley 15564e3744c5SMatthew G. Knepley if ((p >= vStart) && (p < vEnd)) ++coneSize; 15574e3744c5SMatthew G. Knepley } 15589566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 15599566063dSJacob Faibussowitsch PetscCall(DMPlexSetConeSize(udm, c, coneSize)); 1560595d4abbSMatthew G. Knepley maxConeSize = PetscMax(maxConeSize, coneSize); 15614e3744c5SMatthew G. Knepley } 15629566063dSJacob Faibussowitsch PetscCall(DMSetUp(udm)); 15639566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(maxConeSize, &cone)); 15644e3744c5SMatthew G. Knepley for (c = cStart; c < cEnd; ++c) { 1565595d4abbSMatthew G. Knepley PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 15664e3744c5SMatthew G. Knepley 15679566063dSJacob Faibussowitsch PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 15684e3744c5SMatthew G. Knepley for (cl = 0; cl < closureSize*2; cl += 2) { 15694e3744c5SMatthew G. Knepley const PetscInt p = closure[cl]; 15704e3744c5SMatthew G. Knepley 15714e3744c5SMatthew G. Knepley if ((p >= vStart) && (p < vEnd)) cone[coneSize++] = p; 15724e3744c5SMatthew G. Knepley } 15739566063dSJacob Faibussowitsch PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 15749566063dSJacob Faibussowitsch PetscCall(DMPlexSetCone(udm, c, cone)); 15754e3744c5SMatthew G. Knepley } 15769566063dSJacob Faibussowitsch PetscCall(PetscFree(cone)); 15779566063dSJacob Faibussowitsch PetscCall(DMPlexSymmetrize(udm)); 15789566063dSJacob Faibussowitsch PetscCall(DMPlexStratify(udm)); 15795c7de58aSMatthew G. Knepley /* Reduce SF */ 15805c7de58aSMatthew G. Knepley { 15815c7de58aSMatthew G. Knepley PetscSF sfPoint, sfPointUn; 15825c7de58aSMatthew G. Knepley const PetscSFNode *remotePoints; 15835c7de58aSMatthew G. Knepley const PetscInt *localPoints; 15845c7de58aSMatthew G. Knepley PetscSFNode *remotePointsUn; 15855c7de58aSMatthew G. Knepley PetscInt *localPointsUn; 15865c7de58aSMatthew G. Knepley PetscInt vEnd, numRoots, numLeaves, l; 15875c7de58aSMatthew G. Knepley PetscInt numLeavesUn = 0, n = 0; 15885c7de58aSMatthew G. Knepley 15895c7de58aSMatthew G. Knepley /* Get original SF information */ 15909566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(dm, &sfPoint)); 15919566063dSJacob Faibussowitsch PetscCall(DMGetPointSF(udm, &sfPointUn)); 15929566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepthStratum(dm, 0, NULL, &vEnd)); 15939566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 15945c7de58aSMatthew G. Knepley /* Allocate space for cells and vertices */ 15955c7de58aSMatthew G. Knepley for (l = 0; l < numLeaves; ++l) if (localPoints[l] < vEnd) numLeavesUn++; 15965c7de58aSMatthew G. Knepley /* Fill in leaves */ 15975c7de58aSMatthew G. Knepley if (vEnd >= 0) { 15989566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numLeavesUn, &remotePointsUn)); 15999566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(numLeavesUn, &localPointsUn)); 16005c7de58aSMatthew G. Knepley for (l = 0; l < numLeaves; l++) { 16015c7de58aSMatthew G. Knepley if (localPoints[l] < vEnd) { 16025c7de58aSMatthew G. Knepley localPointsUn[n] = localPoints[l]; 16035c7de58aSMatthew G. Knepley remotePointsUn[n].rank = remotePoints[l].rank; 16045c7de58aSMatthew G. Knepley remotePointsUn[n].index = remotePoints[l].index; 16055c7de58aSMatthew G. Knepley ++n; 16065c7de58aSMatthew G. Knepley } 16075c7de58aSMatthew G. Knepley } 160863a3b9bcSJacob Faibussowitsch PetscCheck(n == numLeavesUn,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent number of leaves %" PetscInt_FMT " != %" PetscInt_FMT, n, numLeavesUn); 16099566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(sfPointUn, vEnd, numLeavesUn, localPointsUn, PETSC_OWN_POINTER, remotePointsUn, PETSC_OWN_POINTER)); 16105c7de58aSMatthew G. Knepley } 16115c7de58aSMatthew G. Knepley } 1612827c4036SVaclav Hapla /* This function makes the mesh fully uninterpolated on all ranks */ 1613827c4036SVaclav Hapla { 1614d6e9e4f7SVaclav Hapla DM_Plex *plex = (DM_Plex *) udm->data; 1615827c4036SVaclav Hapla plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_NONE; 1616827c4036SVaclav Hapla } 1617*5de52c6dSVaclav Hapla PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, udm)); 16184e3744c5SMatthew G. Knepley *dmUnint = udm; 16194e3744c5SMatthew G. Knepley PetscFunctionReturn(0); 16204e3744c5SMatthew G. Knepley } 1621a7748839SVaclav Hapla 1622a7748839SVaclav Hapla static PetscErrorCode DMPlexIsInterpolated_Internal(DM dm, DMPlexInterpolatedFlag *interpolated) 1623a7748839SVaclav Hapla { 1624a7748839SVaclav Hapla PetscInt coneSize, depth, dim, h, p, pStart, pEnd; 1625a7748839SVaclav Hapla MPI_Comm comm; 1626a7748839SVaclav Hapla 1627a7748839SVaclav Hapla PetscFunctionBegin; 16289566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 16299566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepth(dm, &depth)); 16309566063dSJacob Faibussowitsch PetscCall(DMGetDimension(dm, &dim)); 1631a7748839SVaclav Hapla 1632a7748839SVaclav Hapla if (depth == dim) { 1633a7748839SVaclav Hapla *interpolated = DMPLEX_INTERPOLATED_FULL; 1634a7748839SVaclav Hapla if (!dim) goto finish; 1635a7748839SVaclav Hapla 1636a7748839SVaclav Hapla /* Check points at height = dim are vertices (have no cones) */ 16379566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, dim, &pStart, &pEnd)); 1638a7748839SVaclav Hapla for (p=pStart; p<pEnd; p++) { 16399566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1640a7748839SVaclav Hapla if (coneSize) { 1641a7748839SVaclav Hapla *interpolated = DMPLEX_INTERPOLATED_PARTIAL; 1642a7748839SVaclav Hapla goto finish; 1643a7748839SVaclav Hapla } 1644a7748839SVaclav Hapla } 1645a7748839SVaclav Hapla 1646a7748839SVaclav Hapla /* Check points at height < dim have cones */ 1647a7748839SVaclav Hapla for (h=0; h<dim; h++) { 16489566063dSJacob Faibussowitsch PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 1649a7748839SVaclav Hapla for (p=pStart; p<pEnd; p++) { 16509566063dSJacob Faibussowitsch PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1651a7748839SVaclav Hapla if (!coneSize) { 1652a7748839SVaclav Hapla *interpolated = DMPLEX_INTERPOLATED_PARTIAL; 1653a7748839SVaclav Hapla goto finish; 1654a7748839SVaclav Hapla } 1655a7748839SVaclav Hapla } 1656a7748839SVaclav Hapla } 1657a7748839SVaclav Hapla } else if (depth == 1) { 1658a7748839SVaclav Hapla *interpolated = DMPLEX_INTERPOLATED_NONE; 1659a7748839SVaclav Hapla } else { 1660a7748839SVaclav Hapla *interpolated = DMPLEX_INTERPOLATED_PARTIAL; 1661a7748839SVaclav Hapla } 1662a7748839SVaclav Hapla finish: 1663a7748839SVaclav Hapla PetscFunctionReturn(0); 1664a7748839SVaclav Hapla } 1665a7748839SVaclav Hapla 1666a7748839SVaclav Hapla /*@ 16679ade3219SVaclav Hapla DMPlexIsInterpolated - Find out to what extent the DMPlex is topologically interpolated. 1668a7748839SVaclav Hapla 1669a7748839SVaclav Hapla Not Collective 1670a7748839SVaclav Hapla 1671a7748839SVaclav Hapla Input Parameter: 1672a7748839SVaclav Hapla . dm - The DM object 1673a7748839SVaclav Hapla 1674a7748839SVaclav Hapla Output Parameter: 1675a7748839SVaclav Hapla . interpolated - Flag whether the DM is interpolated 1676a7748839SVaclav Hapla 1677a7748839SVaclav Hapla Level: intermediate 1678a7748839SVaclav Hapla 1679a7748839SVaclav Hapla Notes: 16809ade3219SVaclav Hapla Unlike DMPlexIsInterpolatedCollective(), this is NOT collective 16819ade3219SVaclav Hapla so the results can be different on different ranks in special cases. 1682a7748839SVaclav Hapla However, DMPlexInterpolate() guarantees the result is the same on all. 16839ade3219SVaclav Hapla 1684a7748839SVaclav Hapla Unlike DMPlexIsInterpolatedCollective(), this cannot return DMPLEX_INTERPOLATED_MIXED. 1685a7748839SVaclav Hapla 16869ade3219SVaclav Hapla Developer Notes: 16879ade3219SVaclav Hapla Initially, plex->interpolated = DMPLEX_INTERPOLATED_INVALID. 16889ade3219SVaclav Hapla 16899ade3219SVaclav Hapla If plex->interpolated == DMPLEX_INTERPOLATED_INVALID, DMPlexIsInterpolated_Internal() is called. 16909ade3219SVaclav Hapla It checks the actual topology and sets plex->interpolated on each rank separately to one of 16919ade3219SVaclav Hapla DMPLEX_INTERPOLATED_NONE, DMPLEX_INTERPOLATED_PARTIAL or DMPLEX_INTERPOLATED_FULL. 16929ade3219SVaclav Hapla 16939ade3219SVaclav Hapla If plex->interpolated != DMPLEX_INTERPOLATED_INVALID, this function just returns plex->interpolated. 16949ade3219SVaclav Hapla 16959ade3219SVaclav Hapla DMPlexInterpolate() sets plex->interpolated = DMPLEX_INTERPOLATED_FULL, 16969ade3219SVaclav Hapla and DMPlexUninterpolate() sets plex->interpolated = DMPLEX_INTERPOLATED_NONE. 16979ade3219SVaclav Hapla 1698db781477SPatrick Sanan .seealso: `DMPlexInterpolate()`, `DMPlexIsInterpolatedCollective()` 1699a7748839SVaclav Hapla @*/ 1700a7748839SVaclav Hapla PetscErrorCode DMPlexIsInterpolated(DM dm, DMPlexInterpolatedFlag *interpolated) 1701a7748839SVaclav Hapla { 1702a7748839SVaclav Hapla DM_Plex *plex = (DM_Plex *) dm->data; 1703a7748839SVaclav Hapla 1704a7748839SVaclav Hapla PetscFunctionBegin; 1705a7748839SVaclav Hapla PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1706a7748839SVaclav Hapla PetscValidPointer(interpolated,2); 1707a7748839SVaclav Hapla if (plex->interpolated < 0) { 17089566063dSJacob Faibussowitsch PetscCall(DMPlexIsInterpolated_Internal(dm, &plex->interpolated)); 170976bd3646SJed Brown } else if (PetscDefined (USE_DEBUG)) { 1710a7748839SVaclav Hapla DMPlexInterpolatedFlag flg; 1711a7748839SVaclav Hapla 17129566063dSJacob Faibussowitsch PetscCall(DMPlexIsInterpolated_Internal(dm, &flg)); 171308401ef6SPierre Jolivet PetscCheck(flg == plex->interpolated,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Stashed DMPlexInterpolatedFlag %s is inconsistent with current %s", DMPlexInterpolatedFlags[plex->interpolated], DMPlexInterpolatedFlags[flg]); 1714a7748839SVaclav Hapla } 1715a7748839SVaclav Hapla *interpolated = plex->interpolated; 1716a7748839SVaclav Hapla PetscFunctionReturn(0); 1717a7748839SVaclav Hapla } 1718a7748839SVaclav Hapla 1719a7748839SVaclav Hapla /*@ 17209ade3219SVaclav Hapla DMPlexIsInterpolatedCollective - Find out to what extent the DMPlex is topologically interpolated (in collective manner). 1721a7748839SVaclav Hapla 17222666ff3cSVaclav Hapla Collective 1723a7748839SVaclav Hapla 1724a7748839SVaclav Hapla Input Parameter: 1725a7748839SVaclav Hapla . dm - The DM object 1726a7748839SVaclav Hapla 1727a7748839SVaclav Hapla Output Parameter: 1728a7748839SVaclav Hapla . interpolated - Flag whether the DM is interpolated 1729a7748839SVaclav Hapla 1730a7748839SVaclav Hapla Level: intermediate 1731a7748839SVaclav Hapla 1732a7748839SVaclav Hapla Notes: 17339ade3219SVaclav Hapla Unlike DMPlexIsInterpolated(), this is collective so the results are guaranteed to be the same on all ranks. 17349ade3219SVaclav Hapla 17359ade3219SVaclav Hapla This function will return DMPLEX_INTERPOLATED_MIXED if the results of DMPlexIsInterpolated() are different on different ranks. 17369ade3219SVaclav Hapla 17379ade3219SVaclav Hapla Developer Notes: 17389ade3219SVaclav Hapla Initially, plex->interpolatedCollective = DMPLEX_INTERPOLATED_INVALID. 17399ade3219SVaclav Hapla 17409ade3219SVaclav Hapla If plex->interpolatedCollective == DMPLEX_INTERPOLATED_INVALID, this function calls DMPlexIsInterpolated() which sets plex->interpolated. 17419ade3219SVaclav Hapla MPI_Allreduce() is then called and collectively consistent flag plex->interpolatedCollective is set and returned; 17429ade3219SVaclav Hapla if plex->interpolated varies on different ranks, plex->interpolatedCollective = DMPLEX_INTERPOLATED_MIXED, 17439ade3219SVaclav Hapla otherwise sets plex->interpolatedCollective = plex->interpolated. 17449ade3219SVaclav Hapla 17459ade3219SVaclav Hapla If plex->interpolatedCollective != DMPLEX_INTERPOLATED_INVALID, this function just returns plex->interpolatedCollective. 1746a7748839SVaclav Hapla 1747db781477SPatrick Sanan .seealso: `DMPlexInterpolate()`, `DMPlexIsInterpolated()` 1748a7748839SVaclav Hapla @*/ 1749a7748839SVaclav Hapla PetscErrorCode DMPlexIsInterpolatedCollective(DM dm, DMPlexInterpolatedFlag *interpolated) 1750a7748839SVaclav Hapla { 1751a7748839SVaclav Hapla DM_Plex *plex = (DM_Plex *) dm->data; 1752a7748839SVaclav Hapla PetscBool debug=PETSC_FALSE; 1753a7748839SVaclav Hapla 1754a7748839SVaclav Hapla PetscFunctionBegin; 1755a7748839SVaclav Hapla PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1756a7748839SVaclav Hapla PetscValidPointer(interpolated,2); 17579566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_is_interpolated_collective_debug", &debug, NULL)); 1758a7748839SVaclav Hapla if (plex->interpolatedCollective < 0) { 1759a7748839SVaclav Hapla DMPlexInterpolatedFlag min, max; 1760a7748839SVaclav Hapla MPI_Comm comm; 1761a7748839SVaclav Hapla 17629566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 17639566063dSJacob Faibussowitsch PetscCall(DMPlexIsInterpolated(dm, &plex->interpolatedCollective)); 17649566063dSJacob Faibussowitsch PetscCallMPI(MPI_Allreduce(&plex->interpolatedCollective, &min, 1, MPIU_ENUM, MPI_MIN, comm)); 17659566063dSJacob Faibussowitsch PetscCallMPI(MPI_Allreduce(&plex->interpolatedCollective, &max, 1, MPIU_ENUM, MPI_MAX, comm)); 1766a7748839SVaclav Hapla if (min != max) plex->interpolatedCollective = DMPLEX_INTERPOLATED_MIXED; 1767a7748839SVaclav Hapla if (debug) { 1768a7748839SVaclav Hapla PetscMPIInt rank; 1769a7748839SVaclav Hapla 17709566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 17719566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedPrintf(comm, "[%d] interpolated=%s interpolatedCollective=%s\n", rank, DMPlexInterpolatedFlags[plex->interpolated], DMPlexInterpolatedFlags[plex->interpolatedCollective])); 17729566063dSJacob Faibussowitsch PetscCall(PetscSynchronizedFlush(comm, PETSC_STDOUT)); 1773a7748839SVaclav Hapla } 1774a7748839SVaclav Hapla } 1775a7748839SVaclav Hapla *interpolated = plex->interpolatedCollective; 1776a7748839SVaclav Hapla PetscFunctionReturn(0); 1777a7748839SVaclav Hapla } 1778