xref: /petsc/src/dm/impls/plex/plexinterpolate.c (revision f0cfc026409476e9bc8bbc8fc904e2930eb9d6f4)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2e8f14785SLisandro Dalcin #include <petsc/private/hashmapi.h>
3e8f14785SLisandro Dalcin #include <petsc/private/hashmapij.h>
4e8f14785SLisandro Dalcin 
5a7748839SVaclav Hapla const char * const DMPlexInterpolatedFlags[] = {"none", "partial", "mixed", "full", "DMPlexInterpolatedFlag", "DMPLEX_INTERPOLATED_", 0};
6a7748839SVaclav Hapla 
7e8f14785SLisandro Dalcin /* HashIJKL */
8e8f14785SLisandro Dalcin 
9e8f14785SLisandro Dalcin #include <petsc/private/hashmap.h>
10e8f14785SLisandro Dalcin 
11e8f14785SLisandro Dalcin typedef struct _PetscHashIJKLKey { PetscInt i, j, k, l; } PetscHashIJKLKey;
12e8f14785SLisandro Dalcin 
13e8f14785SLisandro Dalcin #define PetscHashIJKLKeyHash(key) \
14e8f14785SLisandro Dalcin   PetscHashCombine(PetscHashCombine(PetscHashInt((key).i),PetscHashInt((key).j)), \
15e8f14785SLisandro Dalcin                    PetscHashCombine(PetscHashInt((key).k),PetscHashInt((key).l)))
16e8f14785SLisandro Dalcin 
17e8f14785SLisandro Dalcin #define PetscHashIJKLKeyEqual(k1,k2) \
18e8f14785SLisandro Dalcin   (((k1).i==(k2).i) ? ((k1).j==(k2).j) ? ((k1).k==(k2).k) ? ((k1).l==(k2).l) : 0 : 0 : 0)
19e8f14785SLisandro Dalcin 
20e8f14785SLisandro Dalcin PETSC_HASH_MAP(HashIJKL, PetscHashIJKLKey, PetscInt, PetscHashIJKLKeyHash, PetscHashIJKLKeyEqual, -1)
21e8f14785SLisandro Dalcin 
229f074e33SMatthew G Knepley 
239f074e33SMatthew G Knepley /*
249a5b13a2SMatthew G Knepley   DMPlexGetFaces_Internal - Gets groups of vertices that correspond to faces for the given cell
25cd921712SStefano Zampini   This assumes that the mesh is not interpolated from the depth of point p to the vertices
269f074e33SMatthew G Knepley */
27439ece16SMatthew G. Knepley PetscErrorCode DMPlexGetFaces_Internal(DM dm, PetscInt dim, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
289f074e33SMatthew G Knepley {
299f074e33SMatthew G Knepley   const PetscInt *cone = NULL;
30cd921712SStefano Zampini   PetscInt        coneSize;
319f074e33SMatthew G Knepley   PetscErrorCode  ierr;
329f074e33SMatthew G Knepley 
339f074e33SMatthew G Knepley   PetscFunctionBegin;
349f074e33SMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
359f074e33SMatthew G Knepley   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
369f074e33SMatthew G Knepley   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
37439ece16SMatthew G. Knepley   ierr = DMPlexGetRawFaces_Internal(dm, dim, coneSize, cone, numFaces, faceSize, faces);CHKERRQ(ierr);
38439ece16SMatthew G. Knepley   PetscFunctionReturn(0);
39439ece16SMatthew G. Knepley }
40439ece16SMatthew G. Knepley 
41439ece16SMatthew G. Knepley /*
42439ece16SMatthew G. Knepley   DMPlexRestoreFaces_Internal - Restores the array
43439ece16SMatthew G. Knepley */
44439ece16SMatthew G. Knepley PetscErrorCode DMPlexRestoreFaces_Internal(DM dm, PetscInt dim, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
45439ece16SMatthew G. Knepley {
46439ece16SMatthew G. Knepley   PetscErrorCode  ierr;
47439ece16SMatthew G. Knepley 
48439ece16SMatthew G. Knepley   PetscFunctionBegin;
49cd921712SStefano Zampini   if (faces) { ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void *) faces);CHKERRQ(ierr); }
50439ece16SMatthew G. Knepley   PetscFunctionReturn(0);
51439ece16SMatthew G. Knepley }
52439ece16SMatthew G. Knepley 
53439ece16SMatthew G. Knepley /*
54439ece16SMatthew G. Knepley   DMPlexGetRawFaces_Internal - Gets groups of vertices that correspond to faces for the given cone
55439ece16SMatthew G. Knepley */
56439ece16SMatthew G. Knepley PetscErrorCode DMPlexGetRawFaces_Internal(DM dm, PetscInt dim, PetscInt coneSize, const PetscInt cone[], PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
57439ece16SMatthew G. Knepley {
58439ece16SMatthew G. Knepley   PetscInt       *facesTmp;
59439ece16SMatthew G. Knepley   PetscInt        maxConeSize, maxSupportSize;
60439ece16SMatthew G. Knepley   PetscErrorCode  ierr;
61439ece16SMatthew G. Knepley 
62439ece16SMatthew G. Knepley   PetscFunctionBegin;
63439ece16SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
64cd921712SStefano Zampini   if (faces && coneSize) PetscValidIntPointer(cone,4);
65439ece16SMatthew G. Knepley   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
6669291d52SBarry Smith   if (faces) {ierr = DMGetWorkArray(dm, PetscSqr(PetscMax(maxConeSize, maxSupportSize)), MPIU_INT, &facesTmp);CHKERRQ(ierr);}
679f074e33SMatthew G Knepley   switch (dim) {
68c49d9212SMatthew G. Knepley   case 1:
69c49d9212SMatthew G. Knepley     switch (coneSize) {
70c49d9212SMatthew G. Knepley     case 2:
71c49d9212SMatthew G. Knepley       if (faces) {
72c49d9212SMatthew G. Knepley         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
73c49d9212SMatthew G. Knepley         *faces = facesTmp;
74c49d9212SMatthew G. Knepley       }
75c49d9212SMatthew G. Knepley       if (numFaces) *numFaces = 2;
76c49d9212SMatthew G. Knepley       if (faceSize) *faceSize = 1;
77c49d9212SMatthew G. Knepley       break;
78c49d9212SMatthew G. Knepley     default:
7999836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
80c49d9212SMatthew G. Knepley     }
81c49d9212SMatthew G. Knepley     break;
829f074e33SMatthew G Knepley   case 2:
839f074e33SMatthew G Knepley     switch (coneSize) {
849f074e33SMatthew G Knepley     case 3:
859a5b13a2SMatthew G Knepley       if (faces) {
869a5b13a2SMatthew G Knepley         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
879a5b13a2SMatthew G Knepley         facesTmp[2] = cone[1]; facesTmp[3] = cone[2];
889a5b13a2SMatthew G Knepley         facesTmp[4] = cone[2]; facesTmp[5] = cone[0];
899a5b13a2SMatthew G Knepley         *faces = facesTmp;
909a5b13a2SMatthew G Knepley       }
919a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 3;
929a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 2;
939f074e33SMatthew G Knepley       break;
949f074e33SMatthew G Knepley     case 4:
959a5b13a2SMatthew G Knepley       /* Vertices follow right hand rule */
969a5b13a2SMatthew G Knepley       if (faces) {
979a5b13a2SMatthew G Knepley         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
989a5b13a2SMatthew G Knepley         facesTmp[2] = cone[1]; facesTmp[3] = cone[2];
999a5b13a2SMatthew G Knepley         facesTmp[4] = cone[2]; facesTmp[5] = cone[3];
1009a5b13a2SMatthew G Knepley         facesTmp[6] = cone[3]; facesTmp[7] = cone[0];
1019a5b13a2SMatthew G Knepley         *faces = facesTmp;
1029a5b13a2SMatthew G Knepley       }
1039a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 4;
1049a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 2;
1059f074e33SMatthew G Knepley       break;
1069f074e33SMatthew G Knepley     default:
10799836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1089f074e33SMatthew G Knepley     }
1099f074e33SMatthew G Knepley     break;
1109f074e33SMatthew G Knepley   case 3:
1119f074e33SMatthew G Knepley     switch (coneSize) {
1129f074e33SMatthew G Knepley     case 3:
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       }
1199a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 3;
1209a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 2;
1219f074e33SMatthew G Knepley       break;
1229f074e33SMatthew G Knepley     case 4:
1232e1b13c2SMatthew G. Knepley       /* Vertices of first face follow right hand rule and normal points away from last vertex */
1249a5b13a2SMatthew G Knepley       if (faces) {
1252e1b13c2SMatthew G. Knepley         facesTmp[0] = cone[0]; facesTmp[1]  = cone[1]; facesTmp[2]  = cone[2];
1262e1b13c2SMatthew G. Knepley         facesTmp[3] = cone[0]; facesTmp[4]  = cone[3]; facesTmp[5]  = cone[1];
1272e1b13c2SMatthew G. Knepley         facesTmp[6] = cone[0]; facesTmp[7]  = cone[2]; facesTmp[8]  = cone[3];
1282e1b13c2SMatthew G. Knepley         facesTmp[9] = cone[2]; facesTmp[10] = cone[1]; facesTmp[11] = cone[3];
1299a5b13a2SMatthew G Knepley         *faces = facesTmp;
1309a5b13a2SMatthew G Knepley       }
1319a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 4;
1329a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 3;
1339a5b13a2SMatthew G Knepley       break;
1349a5b13a2SMatthew G Knepley     case 8:
135e368ef20SMatthew G. Knepley       /*  7--------6
136e368ef20SMatthew G. Knepley          /|       /|
137e368ef20SMatthew G. Knepley         / |      / |
138e368ef20SMatthew G. Knepley        4--------5  |
139e368ef20SMatthew G. Knepley        |  |     |  |
140e368ef20SMatthew G. Knepley        |  |     |  |
141e368ef20SMatthew G. Knepley        |  1--------2
142e368ef20SMatthew G. Knepley        | /      | /
143e368ef20SMatthew G. Knepley        |/       |/
144e368ef20SMatthew G. Knepley        0--------3
145e368ef20SMatthew G. Knepley        */
1469a5b13a2SMatthew G Knepley       if (faces) {
14751cfd6a4SMatthew G. Knepley         facesTmp[0]  = cone[0]; facesTmp[1]  = cone[1]; facesTmp[2]  = cone[2]; facesTmp[3]  = cone[3]; /* Bottom */
14851cfd6a4SMatthew G. Knepley         facesTmp[4]  = cone[4]; facesTmp[5]  = cone[5]; facesTmp[6]  = cone[6]; facesTmp[7]  = cone[7]; /* Top */
14951cfd6a4SMatthew G. Knepley         facesTmp[8]  = cone[0]; facesTmp[9]  = cone[3]; facesTmp[10] = cone[5]; facesTmp[11] = cone[4]; /* Front */
15051cfd6a4SMatthew G. Knepley         facesTmp[12] = cone[2]; facesTmp[13] = cone[1]; facesTmp[14] = cone[7]; facesTmp[15] = cone[6]; /* Back */
15151cfd6a4SMatthew G. Knepley         facesTmp[16] = cone[3]; facesTmp[17] = cone[2]; facesTmp[18] = cone[6]; facesTmp[19] = cone[5]; /* Right */
15251cfd6a4SMatthew G. Knepley         facesTmp[20] = cone[0]; facesTmp[21] = cone[4]; facesTmp[22] = cone[7]; facesTmp[23] = cone[1]; /* Left */
1539a5b13a2SMatthew G Knepley         *faces = facesTmp;
1549a5b13a2SMatthew G Knepley       }
1559a5b13a2SMatthew G Knepley       if (numFaces) *numFaces = 6;
1569a5b13a2SMatthew G Knepley       if (faceSize) *faceSize = 4;
1579f074e33SMatthew G Knepley       break;
1589f074e33SMatthew G Knepley     default:
15999836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1609f074e33SMatthew G Knepley     }
1619f074e33SMatthew G Knepley     break;
1629f074e33SMatthew G Knepley   default:
16399836e0eSStefano Zampini     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1649f074e33SMatthew G Knepley   }
1659f074e33SMatthew G Knepley   PetscFunctionReturn(0);
1669f074e33SMatthew G Knepley }
1679f074e33SMatthew G Knepley 
16899836e0eSStefano Zampini /*
16999836e0eSStefano Zampini   DMPlexGetRawFacesHybrid_Internal - Gets groups of vertices that correspond to faces for the given cone using hybrid ordering (prisms)
17099836e0eSStefano Zampini */
17199836e0eSStefano Zampini static PetscErrorCode DMPlexGetRawFacesHybrid_Internal(DM dm, PetscInt dim, PetscInt coneSize, const PetscInt cone[], PetscInt *numFaces, PetscInt *numFacesNotH, PetscInt *faceSize, const PetscInt *faces[])
17299836e0eSStefano Zampini {
17399836e0eSStefano Zampini   PetscInt       *facesTmp;
17499836e0eSStefano Zampini   PetscInt        maxConeSize, maxSupportSize;
17599836e0eSStefano Zampini   PetscErrorCode  ierr;
17699836e0eSStefano Zampini 
17799836e0eSStefano Zampini   PetscFunctionBegin;
17899836e0eSStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
17999836e0eSStefano Zampini   if (faces && coneSize) PetscValidIntPointer(cone,4);
18099836e0eSStefano Zampini   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
18199836e0eSStefano Zampini   if (faces) {ierr = DMGetWorkArray(dm, PetscSqr(PetscMax(maxConeSize, maxSupportSize)), MPIU_INT, &facesTmp);CHKERRQ(ierr);}
18299836e0eSStefano Zampini   switch (dim) {
18399836e0eSStefano Zampini   case 1:
18499836e0eSStefano Zampini     switch (coneSize) {
18599836e0eSStefano Zampini     case 2:
18699836e0eSStefano Zampini       if (faces) {
18799836e0eSStefano Zampini         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
18899836e0eSStefano Zampini         *faces = facesTmp;
18999836e0eSStefano Zampini       }
19099836e0eSStefano Zampini       if (numFaces)     *numFaces = 2;
19199836e0eSStefano Zampini       if (numFacesNotH) *numFacesNotH = 2;
19299836e0eSStefano Zampini       if (faceSize)     *faceSize = 1;
19399836e0eSStefano Zampini       break;
19499836e0eSStefano Zampini     default:
19599836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
19699836e0eSStefano Zampini     }
19799836e0eSStefano Zampini     break;
19899836e0eSStefano Zampini   case 2:
19999836e0eSStefano Zampini     switch (coneSize) {
20099836e0eSStefano Zampini     case 4:
20199836e0eSStefano Zampini       if (faces) {
20299836e0eSStefano Zampini         facesTmp[0] = cone[0]; facesTmp[1] = cone[1];
20399836e0eSStefano Zampini         facesTmp[2] = cone[2]; facesTmp[3] = cone[3];
20499836e0eSStefano Zampini         facesTmp[4] = cone[0]; facesTmp[5] = cone[2];
20599836e0eSStefano Zampini         facesTmp[6] = cone[1]; facesTmp[7] = cone[3];
20699836e0eSStefano Zampini         *faces = facesTmp;
20799836e0eSStefano Zampini       }
20899836e0eSStefano Zampini       if (numFaces)     *numFaces = 4;
20999836e0eSStefano Zampini       if (numFacesNotH) *numFacesNotH = 2;
21099836e0eSStefano Zampini       if (faceSize)     *faceSize = 2;
21199836e0eSStefano Zampini       break;
21299836e0eSStefano Zampini     default:
21399836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
21499836e0eSStefano Zampini     }
21599836e0eSStefano Zampini     break;
21699836e0eSStefano Zampini   case 3:
21799836e0eSStefano Zampini     switch (coneSize) {
21899836e0eSStefano Zampini     case 6: /* triangular prism */
21999836e0eSStefano Zampini       if (faces) {
22099836e0eSStefano Zampini         facesTmp[0]  = cone[0]; facesTmp[1]  = cone[1]; facesTmp[2]  = cone[2]; facesTmp[3]  = -1;      /* Bottom */
22199836e0eSStefano Zampini         facesTmp[4]  = cone[3]; facesTmp[5]  = cone[4]; facesTmp[6]  = cone[5]; facesTmp[7]  = -1;      /* Top */
22299836e0eSStefano Zampini         facesTmp[8]  = cone[0]; facesTmp[9]  = cone[1]; facesTmp[10] = cone[3]; facesTmp[11] = cone[4]; /* Back left */
22399836e0eSStefano Zampini         facesTmp[12] = cone[1]; facesTmp[13] = cone[2]; facesTmp[14] = cone[4]; facesTmp[15] = cone[5]; /* Back right */
22499836e0eSStefano Zampini         facesTmp[16] = cone[2]; facesTmp[17] = cone[0]; facesTmp[18] = cone[5]; facesTmp[19] = cone[3]; /* Front */
22599836e0eSStefano Zampini         *faces = facesTmp;
22699836e0eSStefano Zampini       }
22799836e0eSStefano Zampini       if (numFaces)     *numFaces = 5;
22899836e0eSStefano Zampini       if (numFacesNotH) *numFacesNotH = 2;
22999836e0eSStefano Zampini       if (faceSize)     *faceSize = -4;
23099836e0eSStefano Zampini       break;
23199836e0eSStefano Zampini     default:
23299836e0eSStefano Zampini       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
23399836e0eSStefano Zampini     }
23499836e0eSStefano Zampini     break;
23599836e0eSStefano Zampini   default:
23699836e0eSStefano Zampini     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
23799836e0eSStefano Zampini   }
23899836e0eSStefano Zampini   PetscFunctionReturn(0);
23999836e0eSStefano Zampini }
24099836e0eSStefano Zampini 
24199836e0eSStefano Zampini static PetscErrorCode DMPlexRestoreRawFacesHybrid_Internal(DM dm, PetscInt dim, PetscInt coneSize, const PetscInt cone[], PetscInt *numFaces, PetscInt *numFacesNotH, PetscInt *faceSize, const PetscInt *faces[])
24299836e0eSStefano Zampini {
24399836e0eSStefano Zampini   PetscErrorCode  ierr;
24499836e0eSStefano Zampini 
24599836e0eSStefano Zampini   PetscFunctionBegin;
24699836e0eSStefano Zampini   if (faces) { ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void *) faces);CHKERRQ(ierr); }
24799836e0eSStefano Zampini   PetscFunctionReturn(0);
24899836e0eSStefano Zampini }
24999836e0eSStefano Zampini 
25099836e0eSStefano Zampini static PetscErrorCode DMPlexGetFacesHybrid_Internal(DM dm, PetscInt dim, PetscInt p, PetscInt *numFaces, PetscInt *numFacesNotH, PetscInt *faceSize, const PetscInt *faces[])
25199836e0eSStefano Zampini {
25299836e0eSStefano Zampini   const PetscInt *cone = NULL;
25399836e0eSStefano Zampini   PetscInt        coneSize;
25499836e0eSStefano Zampini   PetscErrorCode  ierr;
25599836e0eSStefano Zampini 
25699836e0eSStefano Zampini   PetscFunctionBegin;
25799836e0eSStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25899836e0eSStefano Zampini   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
25999836e0eSStefano Zampini   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
26099836e0eSStefano Zampini   ierr = DMPlexGetRawFacesHybrid_Internal(dm, dim, coneSize, cone, numFaces, numFacesNotH, faceSize, faces);CHKERRQ(ierr);
26199836e0eSStefano Zampini   PetscFunctionReturn(0);
26299836e0eSStefano Zampini }
26399836e0eSStefano Zampini 
2649a5b13a2SMatthew G Knepley /* This interpolates faces for cells at some stratum */
2659a5b13a2SMatthew G Knepley static PetscErrorCode DMPlexInterpolateFaces_Internal(DM dm, PetscInt cellDepth, DM idm)
2669f074e33SMatthew G Knepley {
267d4efc6f1SMatthew G. Knepley   DMLabel        subpointMap;
2689a5b13a2SMatthew G Knepley   PetscHashIJKL  faceTable;
2699a5b13a2SMatthew G Knepley   PetscInt      *pStart, *pEnd;
2709a5b13a2SMatthew G Knepley   PetscInt       cellDim, depth, faceDepth = cellDepth, numPoints = 0, faceSizeAll = 0, face, c, d;
271e9fa77a1SMatthew G. Knepley   PetscInt       coneSizeH = 0, faceSizeAllH = 0, faceSizeAllT = 0, numCellFacesH = 0, faceT = 0, faceH, pMax = -1, dim, outerloop;
27299836e0eSStefano Zampini   PetscInt       cMax, fMax, eMax, vMax;
2739f074e33SMatthew G Knepley   PetscErrorCode ierr;
2749f074e33SMatthew G Knepley 
2759f074e33SMatthew G Knepley   PetscFunctionBegin;
276c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &cellDim);CHKERRQ(ierr);
277d4efc6f1SMatthew G. Knepley   /* HACK: I need a better way to determine face dimension, or an alternative to GetFaces() */
278d4efc6f1SMatthew G. Knepley   ierr = DMPlexGetSubpointMap(dm, &subpointMap);CHKERRQ(ierr);
279d4efc6f1SMatthew G. Knepley   if (subpointMap) ++cellDim;
2809a5b13a2SMatthew G Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2819a5b13a2SMatthew G Knepley   ++depth;
2829a5b13a2SMatthew G Knepley   ++cellDepth;
2839a5b13a2SMatthew G Knepley   cellDim -= depth - cellDepth;
284dcca6d9dSJed Brown   ierr = PetscMalloc2(depth+1,&pStart,depth+1,&pEnd);CHKERRQ(ierr);
2859a5b13a2SMatthew G Knepley   for (d = depth-1; d >= faceDepth; --d) {
2869a5b13a2SMatthew G Knepley     ierr = DMPlexGetDepthStratum(dm, d, &pStart[d+1], &pEnd[d+1]);CHKERRQ(ierr);
2879f074e33SMatthew G Knepley   }
2889a5b13a2SMatthew G Knepley   ierr = DMPlexGetDepthStratum(dm, -1, NULL, &pStart[faceDepth]);CHKERRQ(ierr);
2899a5b13a2SMatthew G Knepley   pEnd[faceDepth] = pStart[faceDepth];
2909a5b13a2SMatthew G Knepley   for (d = faceDepth-1; d >= 0; --d) {
2919a5b13a2SMatthew G Knepley     ierr = DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);CHKERRQ(ierr);
2929f074e33SMatthew G Knepley   }
29399836e0eSStefano Zampini   cMax = fMax = eMax = vMax = PETSC_DETERMINE;
29499836e0eSStefano Zampini   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
29599836e0eSStefano Zampini   if (cellDim == dim) {
29699836e0eSStefano Zampini     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
29799836e0eSStefano Zampini     pMax = cMax;
29899836e0eSStefano Zampini   } else if (cellDim == dim -1) {
29999836e0eSStefano Zampini     ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
30099836e0eSStefano Zampini     pMax = fMax;
30199836e0eSStefano Zampini   }
30299836e0eSStefano Zampini   pMax = pMax < 0 ? pEnd[cellDepth] : pMax;
30399836e0eSStefano Zampini   if (pMax < pEnd[cellDepth]) {
30499836e0eSStefano Zampini     const PetscInt *cellFaces, *cone;
30599836e0eSStefano Zampini     PetscInt        numCellFacesT, faceSize, cf;
3069f074e33SMatthew G Knepley 
307e9fa77a1SMatthew G. Knepley     /* First get normal cell face size (we now allow hybrid cells to meet normal cells on either hybrid or normal faces */
3085ebdaad1SMatthew G. Knepley     if (pStart[cellDepth] < pMax) {ierr = DMPlexGetFaces_Internal(dm, cellDim, pStart[cellDepth], NULL, &faceSizeAll, NULL);CHKERRQ(ierr);}
309e9fa77a1SMatthew G. Knepley 
31099836e0eSStefano Zampini     ierr = DMPlexGetConeSize(dm, pMax, &coneSizeH);CHKERRQ(ierr);
31199836e0eSStefano Zampini     ierr = DMPlexGetCone(dm, pMax, &cone);CHKERRQ(ierr);
31299836e0eSStefano Zampini     ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSizeH, cone, &numCellFacesH, &numCellFacesT, &faceSize, &cellFaces);CHKERRQ(ierr);
31399836e0eSStefano Zampini     if (faceSize < 0) {
31499836e0eSStefano Zampini       PetscInt *sizes, minv, maxv;
31599836e0eSStefano Zampini 
31699836e0eSStefano Zampini       /* count vertices of hybrid and non-hybrid faces */
31799836e0eSStefano Zampini       ierr = PetscCalloc1(numCellFacesH, &sizes);CHKERRQ(ierr);
31899836e0eSStefano Zampini       for (cf = 0; cf < numCellFacesT; ++cf) { /* These are the non-hybrid faces */
31999836e0eSStefano Zampini         const PetscInt *cellFace = &cellFaces[-cf*faceSize];
32099836e0eSStefano Zampini         PetscInt       f;
32199836e0eSStefano Zampini 
32299836e0eSStefano Zampini         for (f = 0; f < -faceSize; ++f) sizes[cf] += (cellFace[f] >= 0 ? 1 : 0);
32399836e0eSStefano Zampini       }
32499836e0eSStefano Zampini       ierr = PetscSortInt(numCellFacesT, sizes);CHKERRQ(ierr);
32599836e0eSStefano Zampini       minv = sizes[0];
32699836e0eSStefano Zampini       maxv = sizes[PetscMax(numCellFacesT-1, 0)];
32799836e0eSStefano Zampini       if (minv != maxv) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Different number of vertices for non-hybrid face %D != %D", minv, maxv);
328e9fa77a1SMatthew G. Knepley       faceSizeAllT = minv;
329580bdb30SBarry Smith       ierr = PetscArrayzero(sizes, numCellFacesH);CHKERRQ(ierr);
33099836e0eSStefano Zampini       for (cf = numCellFacesT; cf < numCellFacesH; ++cf) { /* These are the hybrid faces */
33199836e0eSStefano Zampini         const PetscInt *cellFace = &cellFaces[-cf*faceSize];
33299836e0eSStefano Zampini         PetscInt       f;
33399836e0eSStefano Zampini 
33499836e0eSStefano Zampini         for (f = 0; f < -faceSize; ++f) sizes[cf-numCellFacesT] += (cellFace[f] >= 0 ? 1 : 0);
33599836e0eSStefano Zampini       }
33699836e0eSStefano Zampini       ierr = PetscSortInt(numCellFacesH - numCellFacesT, sizes);CHKERRQ(ierr);
33799836e0eSStefano Zampini       minv = sizes[0];
33899836e0eSStefano Zampini       maxv = sizes[PetscMax(numCellFacesH - numCellFacesT-1, 0)];
33999836e0eSStefano Zampini       ierr = PetscFree(sizes);CHKERRQ(ierr);
34099836e0eSStefano Zampini       if (minv != maxv) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Different number of vertices for hybrid face %D != %D", minv, maxv);
34199836e0eSStefano Zampini       faceSizeAllH = minv;
3425ebdaad1SMatthew G. Knepley       if (!faceSizeAll) faceSizeAll = faceSizeAllT;
34399836e0eSStefano Zampini     } else { /* the size of the faces in hybrid cells is the same */
344e9fa77a1SMatthew G. Knepley       faceSizeAll = faceSizeAllH = faceSizeAllT = faceSize;
34599836e0eSStefano Zampini     }
34699836e0eSStefano Zampini     ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSizeH, cone, &numCellFacesH, &numCellFacesT, &faceSize, &cellFaces);CHKERRQ(ierr);
34799836e0eSStefano Zampini   } else if (pEnd[cellDepth] > pStart[cellDepth]) {
34899836e0eSStefano Zampini     ierr = DMPlexGetFaces_Internal(dm, cellDim, pStart[cellDepth], NULL, &faceSizeAll, NULL);CHKERRQ(ierr);
349a1bcd873SMatthew G. Knepley     faceSizeAllH = faceSizeAllT = faceSizeAll;
35099836e0eSStefano Zampini   }
35199836e0eSStefano Zampini   if (faceSizeAll > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSizeAll);
35299836e0eSStefano Zampini 
353b135d7daSStefano Zampini   /* With hybrid grids, we first iterate on hybrid cells and start numbering the non-hybrid faces
35499836e0eSStefano Zampini      Then, faces for non-hybrid cells are numbered.
35599836e0eSStefano Zampini      This is to guarantee consistent orientations (all 0) of all the points in the cone of the hybrid cells */
35699836e0eSStefano Zampini   ierr = PetscHashIJKLCreate(&faceTable);CHKERRQ(ierr);
35799836e0eSStefano Zampini   for (outerloop = 0, face = pStart[faceDepth]; outerloop < 2; outerloop++) {
35899836e0eSStefano Zampini     PetscInt start, end;
35999836e0eSStefano Zampini 
36099836e0eSStefano Zampini     start = outerloop == 0 ? pMax : pStart[cellDepth];
36199836e0eSStefano Zampini     end = outerloop == 0 ? pEnd[cellDepth] : pMax;
36299836e0eSStefano Zampini     for (c = start; c < end; ++c) {
36399836e0eSStefano Zampini       const PetscInt *cellFaces;
364e9fa77a1SMatthew G. Knepley       PetscInt        numCellFaces, faceSize, faceSizeInc, faceSizeCheck, cf;
36599836e0eSStefano Zampini 
36699836e0eSStefano Zampini       if (c < pMax) {
3679a5b13a2SMatthew G Knepley         ierr = DMPlexGetFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
3689a5b13a2SMatthew G Knepley         if (faceSize != faceSizeAll) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent face for cell %D of size %D != %D", c, faceSize, faceSizeAll);
369e9fa77a1SMatthew G. Knepley         faceSizeCheck = faceSizeAll;
37099836e0eSStefano Zampini       } else { /* Hybrid cell */
37199836e0eSStefano Zampini         const PetscInt *cone;
37299836e0eSStefano Zampini         PetscInt        numCellFacesN, coneSize;
37399836e0eSStefano Zampini 
37499836e0eSStefano Zampini         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
37599836e0eSStefano Zampini         if (coneSize != coneSizeH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid coneSize %D != %D", coneSize, coneSizeH);
37699836e0eSStefano Zampini         ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
37799836e0eSStefano Zampini         ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
37899836e0eSStefano Zampini         if (numCellFaces != numCellFacesH) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected numCellFaces %D != %D for hybrid cell %D", numCellFaces, numCellFacesH, c);
37999836e0eSStefano Zampini         faceSize = PetscMax(faceSize, -faceSize);
38099836e0eSStefano Zampini         if (faceSize > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSize);
38199836e0eSStefano Zampini         numCellFaces = numCellFacesN; /* process only non-hybrid faces */
382e9fa77a1SMatthew G. Knepley         faceSizeCheck = faceSizeAllT;
38399836e0eSStefano Zampini       }
38499836e0eSStefano Zampini       faceSizeInc = faceSize;
3859f074e33SMatthew G Knepley       for (cf = 0; cf < numCellFaces; ++cf) {
38699836e0eSStefano Zampini         const PetscInt   *cellFace = &cellFaces[cf*faceSizeInc];
38799836e0eSStefano Zampini         PetscInt          faceSizeH = faceSize;
3889a5b13a2SMatthew G Knepley         PetscHashIJKLKey  key;
389e8f14785SLisandro Dalcin         PetscHashIter     iter;
390e8f14785SLisandro Dalcin         PetscBool         missing;
3919f074e33SMatthew G Knepley 
39299836e0eSStefano Zampini         if (faceSizeInc == 2) {
3939a5b13a2SMatthew G Knepley           key.i = PetscMin(cellFace[0], cellFace[1]);
3949a5b13a2SMatthew G Knepley           key.j = PetscMax(cellFace[0], cellFace[1]);
39599836e0eSStefano Zampini           key.k = PETSC_MAX_INT;
39699836e0eSStefano Zampini           key.l = PETSC_MAX_INT;
3979a5b13a2SMatthew G Knepley         } else {
39899836e0eSStefano Zampini           key.i = cellFace[0];
39999836e0eSStefano Zampini           key.j = cellFace[1];
40099836e0eSStefano Zampini           key.k = cellFace[2];
40199836e0eSStefano Zampini           key.l = faceSize > 3 ? (cellFace[3] < 0 ? faceSizeH = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
402302440fdSBarry Smith           ierr  = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr);
4039f074e33SMatthew G Knepley         }
40499836e0eSStefano Zampini         /* this check is redundant for non-hybrid meshes */
405e9fa77a1SMatthew G. Knepley         if (faceSizeH != faceSizeCheck) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected number of vertices for face %D of point %D -> %D != %D", cf, c, faceSizeH, faceSizeCheck);
406e8f14785SLisandro Dalcin         ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
407e9fa77a1SMatthew G. Knepley         if (missing) {
408e9fa77a1SMatthew G. Knepley           ierr = PetscHashIJKLIterSet(faceTable, iter, face++);CHKERRQ(ierr);
409e9fa77a1SMatthew G. Knepley           if (c >= pMax) ++faceT;
410e9fa77a1SMatthew G. Knepley         }
4119a5b13a2SMatthew G Knepley       }
41299836e0eSStefano Zampini       if (c < pMax) {
413439ece16SMatthew G. Knepley         ierr = DMPlexRestoreFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
41499836e0eSStefano Zampini       } else {
41599836e0eSStefano Zampini         ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSizeH, NULL, NULL, NULL, NULL, &cellFaces);CHKERRQ(ierr);
41699836e0eSStefano Zampini       }
41799836e0eSStefano Zampini     }
41899836e0eSStefano Zampini   }
41999836e0eSStefano Zampini   pEnd[faceDepth] = face;
42099836e0eSStefano Zampini 
42199836e0eSStefano Zampini   /* Second pass for hybrid meshes: number hybrid faces */
42299836e0eSStefano Zampini   for (c = pMax; c < pEnd[cellDepth]; ++c) {
42399836e0eSStefano Zampini     const PetscInt *cellFaces, *cone;
42499836e0eSStefano Zampini     PetscInt        numCellFaces, numCellFacesN, faceSize, cf, coneSize;
42599836e0eSStefano Zampini 
42699836e0eSStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
42799836e0eSStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
42899836e0eSStefano Zampini     ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
42999836e0eSStefano Zampini     if (numCellFaces != numCellFacesH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid numCellFaces %D != %D", numCellFaces, numCellFacesH);
43099836e0eSStefano Zampini     faceSize = PetscMax(faceSize, -faceSize);
43199836e0eSStefano Zampini     for (cf = numCellFacesN; cf < numCellFaces; ++cf) { /* These are the hybrid faces */
43299836e0eSStefano Zampini       const PetscInt   *cellFace = &cellFaces[cf*faceSize];
43399836e0eSStefano Zampini       PetscHashIJKLKey  key;
43499836e0eSStefano Zampini       PetscHashIter     iter;
43599836e0eSStefano Zampini       PetscBool         missing;
43699836e0eSStefano Zampini       PetscInt          faceSizeH = faceSize;
43799836e0eSStefano Zampini 
43899836e0eSStefano Zampini       if (faceSize == 2) {
43999836e0eSStefano Zampini         key.i = PetscMin(cellFace[0], cellFace[1]);
44099836e0eSStefano Zampini         key.j = PetscMax(cellFace[0], cellFace[1]);
44199836e0eSStefano Zampini         key.k = PETSC_MAX_INT;
44299836e0eSStefano Zampini         key.l = PETSC_MAX_INT;
44399836e0eSStefano Zampini       } else {
44499836e0eSStefano Zampini         key.i = cellFace[0];
44599836e0eSStefano Zampini         key.j = cellFace[1];
44699836e0eSStefano Zampini         key.k = cellFace[2];
44799836e0eSStefano Zampini         key.l = faceSize > 3 ? (cellFace[3] < 0 ? faceSizeH = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
44899836e0eSStefano Zampini         ierr  = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr);
44999836e0eSStefano Zampini       }
45099836e0eSStefano Zampini       if (faceSizeH != faceSizeAllH) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected number of vertices for hybrid face %D of point %D -> %D != %D", cf, c, faceSizeH, faceSizeAllH);
45199836e0eSStefano Zampini       ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
45299836e0eSStefano Zampini       if (missing) {ierr = PetscHashIJKLIterSet(faceTable, iter, face++);CHKERRQ(ierr);}
45399836e0eSStefano Zampini     }
45499836e0eSStefano Zampini     ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
45599836e0eSStefano Zampini   }
45699836e0eSStefano Zampini   faceH = face - pEnd[faceDepth];
45799836e0eSStefano Zampini   if (faceH) {
45899836e0eSStefano Zampini     if (fMax == PETSC_DETERMINE) fMax = pEnd[faceDepth];
45999836e0eSStefano Zampini     else if (eMax == PETSC_DETERMINE) eMax = pEnd[faceDepth];
46099836e0eSStefano Zampini     else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of unassigned hybrid facets %D for cellDim %D and dimension %D", faceH, cellDim, dim);
4619a5b13a2SMatthew G Knepley   }
4629a5b13a2SMatthew G Knepley   pEnd[faceDepth] = face;
4639a5b13a2SMatthew G Knepley   ierr = PetscHashIJKLDestroy(&faceTable);CHKERRQ(ierr);
4649a5b13a2SMatthew G Knepley   /* Count new points */
4659a5b13a2SMatthew G Knepley   for (d = 0; d <= depth; ++d) {
4669a5b13a2SMatthew G Knepley     numPoints += pEnd[d]-pStart[d];
4679a5b13a2SMatthew G Knepley   }
4689a5b13a2SMatthew G Knepley   ierr = DMPlexSetChart(idm, 0, numPoints);CHKERRQ(ierr);
4699a5b13a2SMatthew G Knepley   /* Set cone sizes */
4709a5b13a2SMatthew G Knepley   for (d = 0; d <= depth; ++d) {
4719a5b13a2SMatthew G Knepley     PetscInt coneSize, p;
4729f074e33SMatthew G Knepley 
4739a5b13a2SMatthew G Knepley     if (d == faceDepth) {
474e9fa77a1SMatthew G. Knepley       /* Now we have two cases: */
475e9fa77a1SMatthew G. Knepley       if (faceSizeAll == faceSizeAllT) {
4769a5b13a2SMatthew G Knepley         /* I see no way to do this if we admit faces of different shapes */
47799836e0eSStefano Zampini         for (p = pStart[d]; p < pEnd[d]-faceH; ++p) {
4789a5b13a2SMatthew G Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAll);CHKERRQ(ierr);
4799a5b13a2SMatthew G Knepley         }
48099836e0eSStefano Zampini         for (p = pEnd[d]-faceH; p < pEnd[d]; ++p) {
48199836e0eSStefano Zampini           ierr = DMPlexSetConeSize(idm, p, faceSizeAllH);CHKERRQ(ierr);
48299836e0eSStefano Zampini         }
483e9fa77a1SMatthew G. Knepley       } else if (faceSizeAll == faceSizeAllH) {
484e9fa77a1SMatthew G. Knepley         for (p = pStart[d]; p < pStart[d]+faceT; ++p) {
485e9fa77a1SMatthew G. Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAllT);CHKERRQ(ierr);
486e9fa77a1SMatthew G. Knepley         }
487e9fa77a1SMatthew G. Knepley         for (p = pStart[d]+faceT; p < pEnd[d]-faceH; ++p) {
488e9fa77a1SMatthew G. Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAll);CHKERRQ(ierr);
489e9fa77a1SMatthew G. Knepley         }
490e9fa77a1SMatthew G. Knepley         for (p = pEnd[d]-faceH; p < pEnd[d]; ++p) {
491e9fa77a1SMatthew G. Knepley           ierr = DMPlexSetConeSize(idm, p, faceSizeAllH);CHKERRQ(ierr);
492e9fa77a1SMatthew G. Knepley         }
493e9fa77a1SMatthew G. Knepley       } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent faces sizes N: %D T: %D H: %D", faceSizeAll, faceSizeAllT, faceSizeAllH);
494a014044eSMatthew G Knepley     } else if (d == cellDepth) {
495a014044eSMatthew G Knepley       for (p = pStart[d]; p < pEnd[d]; ++p) {
496a014044eSMatthew G Knepley         /* Number of cell faces may be different from number of cell vertices*/
49799836e0eSStefano Zampini         if (p < pMax) {
498a014044eSMatthew G Knepley           ierr = DMPlexGetFaces_Internal(dm, cellDim, p, &coneSize, NULL, NULL);CHKERRQ(ierr);
49999836e0eSStefano Zampini         } else {
50099836e0eSStefano Zampini           ierr = DMPlexGetFacesHybrid_Internal(dm, cellDim, p, &coneSize, NULL, NULL, NULL);CHKERRQ(ierr);
50199836e0eSStefano Zampini         }
502a014044eSMatthew G Knepley         ierr = DMPlexSetConeSize(idm, p, coneSize);CHKERRQ(ierr);
503a014044eSMatthew G Knepley       }
5049a5b13a2SMatthew G Knepley     } else {
5059a5b13a2SMatthew G Knepley       for (p = pStart[d]; p < pEnd[d]; ++p) {
5069a5b13a2SMatthew G Knepley         ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
5079a5b13a2SMatthew G Knepley         ierr = DMPlexSetConeSize(idm, p, coneSize);CHKERRQ(ierr);
5089f074e33SMatthew G Knepley       }
5099f074e33SMatthew G Knepley     }
5109f074e33SMatthew G Knepley   }
5119f074e33SMatthew G Knepley   ierr = DMSetUp(idm);CHKERRQ(ierr);
5129f074e33SMatthew G Knepley   /* Get face cones from subsets of cell vertices */
51399836e0eSStefano Zampini   if (faceSizeAll > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSizeAll);
5149a5b13a2SMatthew G Knepley   ierr = PetscHashIJKLCreate(&faceTable);CHKERRQ(ierr);
5159a5b13a2SMatthew G Knepley   for (d = depth; d > cellDepth; --d) {
5169a5b13a2SMatthew G Knepley     const PetscInt *cone;
5179a5b13a2SMatthew G Knepley     PetscInt        p;
5189a5b13a2SMatthew G Knepley 
5199a5b13a2SMatthew G Knepley     for (p = pStart[d]; p < pEnd[d]; ++p) {
5209a5b13a2SMatthew G Knepley       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
5219a5b13a2SMatthew G Knepley       ierr = DMPlexSetCone(idm, p, cone);CHKERRQ(ierr);
5229a5b13a2SMatthew G Knepley       ierr = DMPlexGetConeOrientation(dm, p, &cone);CHKERRQ(ierr);
5239a5b13a2SMatthew G Knepley       ierr = DMPlexSetConeOrientation(idm, p, cone);CHKERRQ(ierr);
5249f074e33SMatthew G Knepley     }
5259a5b13a2SMatthew G Knepley   }
52699836e0eSStefano Zampini   for (outerloop = 0, face = pStart[faceDepth]; outerloop < 2; outerloop++) {
52799836e0eSStefano Zampini     PetscInt start, end;
5289f074e33SMatthew G Knepley 
52999836e0eSStefano Zampini     start = outerloop == 0 ? pMax : pStart[cellDepth];
53099836e0eSStefano Zampini     end = outerloop == 0 ? pEnd[cellDepth] : pMax;
53199836e0eSStefano Zampini     for (c = start; c < end; ++c) {
53299836e0eSStefano Zampini       const PetscInt *cellFaces;
53399836e0eSStefano Zampini       PetscInt        numCellFaces, faceSize, faceSizeInc, cf;
53499836e0eSStefano Zampini 
53599836e0eSStefano Zampini       if (c < pMax) {
5369a5b13a2SMatthew G Knepley         ierr = DMPlexGetFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
5379a5b13a2SMatthew G Knepley         if (faceSize != faceSizeAll) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent face for cell %D of size %D != %D", c, faceSize, faceSizeAll);
53899836e0eSStefano Zampini       } else {
53999836e0eSStefano Zampini         const PetscInt *cone;
54099836e0eSStefano Zampini         PetscInt        numCellFacesN, coneSize;
54199836e0eSStefano Zampini 
54299836e0eSStefano Zampini         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
54399836e0eSStefano Zampini         if (coneSize != coneSizeH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid coneSize %D != %D", coneSize, coneSizeH);
54499836e0eSStefano Zampini         ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
54599836e0eSStefano Zampini         ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
54699836e0eSStefano Zampini         if (numCellFaces != numCellFacesH) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected numCellFaces %D != %D for hybrid cell %D", numCellFaces, numCellFacesH, c);
54799836e0eSStefano Zampini         faceSize = PetscMax(faceSize, -faceSize);
54899836e0eSStefano Zampini         if (faceSize > 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not support interpolation of meshes with faces of %D vertices", faceSize);
54999836e0eSStefano Zampini         numCellFaces = numCellFacesN; /* process only non-hybrid faces */
55099836e0eSStefano Zampini       }
55199836e0eSStefano Zampini       faceSizeInc = faceSize;
5529f074e33SMatthew G Knepley       for (cf = 0; cf < numCellFaces; ++cf) {
55399836e0eSStefano Zampini         const PetscInt  *cellFace = &cellFaces[cf*faceSizeInc];
5549a5b13a2SMatthew G Knepley         PetscHashIJKLKey key;
555e8f14785SLisandro Dalcin         PetscHashIter    iter;
556e8f14785SLisandro Dalcin         PetscBool        missing;
5579f074e33SMatthew G Knepley 
55899836e0eSStefano Zampini         if (faceSizeInc == 2) {
5599a5b13a2SMatthew G Knepley           key.i = PetscMin(cellFace[0], cellFace[1]);
5609a5b13a2SMatthew G Knepley           key.j = PetscMax(cellFace[0], cellFace[1]);
56199836e0eSStefano Zampini           key.k = PETSC_MAX_INT;
56299836e0eSStefano Zampini           key.l = PETSC_MAX_INT;
5639a5b13a2SMatthew G Knepley         } else {
564e8f14785SLisandro Dalcin           key.i = cellFace[0];
565e8f14785SLisandro Dalcin           key.j = cellFace[1];
566e8f14785SLisandro Dalcin           key.k = cellFace[2];
56799836e0eSStefano Zampini           key.l = faceSizeInc > 3 ? (cellFace[3] < 0 ? faceSize = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
56899836e0eSStefano Zampini           ierr  = PetscSortInt(faceSizeInc, (PetscInt *) &key);CHKERRQ(ierr);
5699f074e33SMatthew G Knepley         }
570e8f14785SLisandro Dalcin         ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
571735a0255SMatthew G. Knepley         if (missing) {
5729a5b13a2SMatthew G Knepley           ierr = DMPlexSetCone(idm, face, cellFace);CHKERRQ(ierr);
573e8f14785SLisandro Dalcin           ierr = PetscHashIJKLIterSet(faceTable, iter, face);CHKERRQ(ierr);
574735a0255SMatthew G. Knepley           ierr = DMPlexInsertCone(idm, c, cf, face++);CHKERRQ(ierr);
5759a5b13a2SMatthew G Knepley         } else {
5769a5b13a2SMatthew G Knepley           const PetscInt *cone;
577735a0255SMatthew G. Knepley           PetscInt        coneSize, ornt, i, j, f;
5789f074e33SMatthew G Knepley 
579e8f14785SLisandro Dalcin           ierr = PetscHashIJKLIterGet(faceTable, iter, &f);CHKERRQ(ierr);
5809a5b13a2SMatthew G Knepley           ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
5812e1b13c2SMatthew G. Knepley           /* Orient face: Do not allow reverse orientation at the first vertex */
5829f074e33SMatthew G Knepley           ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
5839f074e33SMatthew G Knepley           ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
5849a5b13a2SMatthew G Knepley           if (coneSize != faceSize) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of face vertices %D for face %D should be %D", coneSize, f, faceSize);
5859a5b13a2SMatthew G Knepley           /* - First find the initial vertex */
5869a5b13a2SMatthew G Knepley           for (i = 0; i < faceSize; ++i) if (cellFace[0] == cone[i]) break;
5879a5b13a2SMatthew G Knepley           /* - Try forward comparison */
5889a5b13a2SMatthew G Knepley           for (j = 0; j < faceSize; ++j) if (cellFace[j] != cone[(i+j)%faceSize]) break;
5899a5b13a2SMatthew G Knepley           if (j == faceSize) {
5909a5b13a2SMatthew G Knepley             if ((faceSize == 2) && (i == 1)) ornt = -2;
5919a5b13a2SMatthew G Knepley             else                             ornt = i;
5929a5b13a2SMatthew G Knepley           } else {
5939a5b13a2SMatthew G Knepley             /* - Try backward comparison */
5949a5b13a2SMatthew G Knepley             for (j = 0; j < faceSize; ++j) if (cellFace[j] != cone[(i+faceSize-j)%faceSize]) break;
5952e1b13c2SMatthew G. Knepley             if (j == faceSize) {
5962e1b13c2SMatthew G. Knepley               if (i == 0) ornt = -faceSize;
597dc1a705cSMatthew G. Knepley               else        ornt = -i;
598e9fa77a1SMatthew G. Knepley             } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not determine orientation of face %D in cell %D", f, c);
5999a5b13a2SMatthew G Knepley           }
6009a5b13a2SMatthew G Knepley           ierr = DMPlexInsertConeOrientation(idm, c, cf, ornt);CHKERRQ(ierr);
6019f074e33SMatthew G Knepley         }
6029f074e33SMatthew G Knepley       }
60399836e0eSStefano Zampini       if (c < pMax) {
604439ece16SMatthew G. Knepley         ierr = DMPlexRestoreFaces_Internal(dm, cellDim, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
60599836e0eSStefano Zampini       } else {
60699836e0eSStefano Zampini         ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSizeH, NULL, NULL, NULL, NULL, &cellFaces);CHKERRQ(ierr);
6079f074e33SMatthew G Knepley       }
60899836e0eSStefano Zampini     }
60999836e0eSStefano Zampini   }
61099836e0eSStefano Zampini   /* Second pass for hybrid meshes: orient hybrid faces */
61199836e0eSStefano Zampini   for (c = pMax; c < pEnd[cellDepth]; ++c) {
61299836e0eSStefano Zampini     const PetscInt *cellFaces, *cone;
61399836e0eSStefano Zampini     PetscInt        numCellFaces, numCellFacesN, faceSize, cf, coneSize;
61499836e0eSStefano Zampini 
61599836e0eSStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
61699836e0eSStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
61799836e0eSStefano Zampini     ierr = DMPlexGetRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
61899836e0eSStefano Zampini     if (numCellFaces != numCellFacesH) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected hybrid numCellFaces %D != %D", numCellFaces, numCellFacesH);
61999836e0eSStefano Zampini     faceSize = PetscMax(faceSize, -faceSize);
62099836e0eSStefano Zampini     for (cf = numCellFacesN; cf < numCellFaces; ++cf) { /* These are the hybrid faces */
62199836e0eSStefano Zampini       const PetscInt   *cellFace = &cellFaces[cf*faceSize];
62299836e0eSStefano Zampini       PetscHashIJKLKey key;
62399836e0eSStefano Zampini       PetscHashIter    iter;
62499836e0eSStefano Zampini       PetscBool        missing;
62599836e0eSStefano Zampini       PetscInt         faceSizeH = faceSize;
62699836e0eSStefano Zampini 
62799836e0eSStefano Zampini       if (faceSize == 2) {
62899836e0eSStefano Zampini         key.i = PetscMin(cellFace[0], cellFace[1]);
62999836e0eSStefano Zampini         key.j = PetscMax(cellFace[0], cellFace[1]);
63099836e0eSStefano Zampini         key.k = PETSC_MAX_INT;
63199836e0eSStefano Zampini         key.l = PETSC_MAX_INT;
63299836e0eSStefano Zampini       } else {
63399836e0eSStefano Zampini         key.i = cellFace[0];
63499836e0eSStefano Zampini         key.j = cellFace[1];
63599836e0eSStefano Zampini         key.k = cellFace[2];
63699836e0eSStefano Zampini         key.l = faceSize > 3 ? (cellFace[3] < 0 ? faceSizeH = 3, PETSC_MAX_INT : cellFace[3]) : PETSC_MAX_INT;
63799836e0eSStefano Zampini         ierr  = PetscSortInt(faceSize, (PetscInt *) &key);CHKERRQ(ierr);
63899836e0eSStefano Zampini       }
63999836e0eSStefano Zampini       if (faceSizeH != faceSizeAllH) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unexpected number of vertices for hybrid face %D of point %D -> %D != %D", cf, c, faceSizeH, faceSizeAllH);
64099836e0eSStefano Zampini       ierr = PetscHashIJKLPut(faceTable, key, &iter, &missing);CHKERRQ(ierr);
64199836e0eSStefano Zampini       if (missing) {
64299836e0eSStefano Zampini         ierr = DMPlexSetCone(idm, face, cellFace);CHKERRQ(ierr);
64399836e0eSStefano Zampini         ierr = PetscHashIJKLIterSet(faceTable, iter, face);CHKERRQ(ierr);
64499836e0eSStefano Zampini         ierr = DMPlexInsertCone(idm, c, cf, face++);CHKERRQ(ierr);
64599836e0eSStefano Zampini       } else {
646e9fa77a1SMatthew G. Knepley         PetscInt        fv[4] = {0, 1, 2, 3};
64799836e0eSStefano Zampini         const PetscInt *cone;
64899836e0eSStefano Zampini         PetscInt        coneSize, ornt, i, j, f;
649a74221b0SStefano Zampini         PetscBool       q2h = PETSC_FALSE;
65099836e0eSStefano Zampini 
65199836e0eSStefano Zampini         ierr = PetscHashIJKLIterGet(faceTable, iter, &f);CHKERRQ(ierr);
65299836e0eSStefano Zampini         ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
65399836e0eSStefano Zampini         /* Orient face: Do not allow reverse orientation at the first vertex */
65499836e0eSStefano Zampini         ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
65599836e0eSStefano Zampini         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
65699836e0eSStefano Zampini         if (coneSize != faceSizeH) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of face vertices %D for face %D should be %D", coneSize, f, faceSizeH);
657e9fa77a1SMatthew G. Knepley         /* Hybrid faces are stored as tensor products of edges, so to compare them to normal faces, we have to flip */
658a74221b0SStefano Zampini         if (faceSize == 4 && c >= pMax && faceSizeAll != faceSizeAllT && f < pEnd[faceDepth] - faceH) {q2h = PETSC_TRUE; fv[2] = 3; fv[3] = 2;}
65999836e0eSStefano Zampini         /* - First find the initial vertex */
660e9fa77a1SMatthew G. Knepley         for (i = 0; i < faceSizeH; ++i) if (cellFace[fv[0]] == cone[i]) break;
661a74221b0SStefano Zampini         if (q2h) { /* Matt's case: hybrid faces meeting with non-hybrid faces. This is a case that is not (and will not be) supported in general by the refinements */
66299836e0eSStefano Zampini           /* - Try forward comparison */
663e9fa77a1SMatthew G. Knepley           for (j = 0; j < faceSizeH; ++j) if (cellFace[fv[j]] != cone[(i+j)%faceSizeH]) break;
66499836e0eSStefano Zampini           if (j == faceSizeH) {
66599836e0eSStefano Zampini             if ((faceSizeH == 2) && (i == 1)) ornt = -2;
66699836e0eSStefano Zampini             else                              ornt = i;
66799836e0eSStefano Zampini           } else {
66899836e0eSStefano Zampini             /* - Try backward comparison */
669e9fa77a1SMatthew G. Knepley             for (j = 0; j < faceSizeH; ++j) if (cellFace[fv[j]] != cone[(i+faceSizeH-j)%faceSizeH]) break;
67099836e0eSStefano Zampini             if (j == faceSizeH) {
67199836e0eSStefano Zampini               if (i == 0) ornt = -faceSizeH;
67299836e0eSStefano Zampini               else        ornt = -i;
673e9fa77a1SMatthew G. Knepley             } else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not determine orientation of face %D in cell %D", f, c);
67499836e0eSStefano Zampini           }
675a74221b0SStefano Zampini         } else {
676a74221b0SStefano Zampini           /* when matching hybrid faces in 3D, only few cases are possible.
677a74221b0SStefano Zampini              Face traversal however can no longer follow the usual convention, this seems a serious issue to me */
678a74221b0SStefano Zampini           PetscInt tquad_map[4][4] = { {PETSC_MIN_INT,            0,PETSC_MIN_INT,PETSC_MIN_INT},
679a74221b0SStefano Zampini                                        {           -1,PETSC_MIN_INT,PETSC_MIN_INT,PETSC_MIN_INT},
680a74221b0SStefano Zampini                                        {PETSC_MIN_INT,PETSC_MIN_INT,PETSC_MIN_INT,            1},
681a74221b0SStefano Zampini                                        {PETSC_MIN_INT,PETSC_MIN_INT,           -2,PETSC_MIN_INT} };
682a74221b0SStefano Zampini           PetscInt i2;
683a74221b0SStefano Zampini 
684a74221b0SStefano Zampini           /* find the second vertex */
685a74221b0SStefano Zampini           for (i2 = 0; i2 < faceSizeH; ++i2) if (cellFace[fv[1]] == cone[i2]) break;
686a74221b0SStefano Zampini           switch (faceSizeH) {
687a74221b0SStefano Zampini           case 2:
688a74221b0SStefano Zampini             ornt = i ? -2 : 0;
689a74221b0SStefano Zampini             break;
690a74221b0SStefano Zampini           case 4:
691a74221b0SStefano Zampini             ornt = tquad_map[i][i2];
692a74221b0SStefano Zampini             break;
693a74221b0SStefano Zampini           default:
694a74221b0SStefano Zampini             SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unhandled face size %D for face %D in cell %D", faceSizeH, f, c);
695a74221b0SStefano Zampini 
696a74221b0SStefano Zampini           }
697a74221b0SStefano Zampini         }
69899836e0eSStefano Zampini         ierr = DMPlexInsertConeOrientation(idm, c, cf, ornt);CHKERRQ(ierr);
69999836e0eSStefano Zampini       }
70099836e0eSStefano Zampini     }
70199836e0eSStefano Zampini     ierr = DMPlexRestoreRawFacesHybrid_Internal(dm, cellDim, coneSize, cone, &numCellFaces, &numCellFacesN, &faceSize, &cellFaces);CHKERRQ(ierr);
70299836e0eSStefano Zampini   }
70399836e0eSStefano Zampini   if (face != pEnd[faceDepth]) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-pStart[faceDepth], pEnd[faceDepth]-pStart[faceDepth]);
704c907b753SJed Brown   ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr);
7059a5b13a2SMatthew G Knepley   ierr = PetscHashIJKLDestroy(&faceTable);CHKERRQ(ierr);
7066551a8c7SMatthew G. Knepley   ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr);
70799836e0eSStefano Zampini   ierr = DMPlexSetHybridBounds(idm, cMax, fMax, eMax, vMax);CHKERRQ(ierr);
7089a5b13a2SMatthew G Knepley   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
7099a5b13a2SMatthew G Knepley   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
7109f074e33SMatthew G Knepley   PetscFunctionReturn(0);
7119f074e33SMatthew G Knepley }
7129f074e33SMatthew G Knepley 
713f80536cbSVaclav Hapla static PetscErrorCode SortRmineRremoteByRemote_Private(PetscSF sf, PetscInt *rmine1[], PetscInt *rremote1[])
714f80536cbSVaclav Hapla {
715f80536cbSVaclav Hapla   PetscInt            nleaves;
716f80536cbSVaclav Hapla   PetscInt            nranks;
717a0d42dbcSVaclav Hapla   const PetscMPIInt  *ranks=NULL;
718a0d42dbcSVaclav Hapla   const PetscInt     *roffset=NULL, *rmine=NULL, *rremote=NULL;
719f80536cbSVaclav Hapla   PetscInt            n, o, r;
720f80536cbSVaclav Hapla   PetscErrorCode      ierr;
721f80536cbSVaclav Hapla 
722f80536cbSVaclav Hapla   PetscFunctionBegin;
723dec1416fSJunchao Zhang   ierr = PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, &rmine, &rremote);CHKERRQ(ierr);
724f80536cbSVaclav Hapla   nleaves = roffset[nranks];
725f80536cbSVaclav Hapla   ierr = PetscMalloc2(nleaves, rmine1, nleaves, rremote1);CHKERRQ(ierr);
726f80536cbSVaclav Hapla   for (r=0; r<nranks; r++) {
727f80536cbSVaclav Hapla     /* simultaneously sort rank-wise portions of rmine & rremote by values in rremote
728f80536cbSVaclav Hapla        - to unify order with the other side */
729f80536cbSVaclav Hapla     o = roffset[r];
730f80536cbSVaclav Hapla     n = roffset[r+1] - o;
731580bdb30SBarry Smith     ierr = PetscArraycpy(&(*rmine1)[o], &rmine[o], n);CHKERRQ(ierr);
732580bdb30SBarry Smith     ierr = PetscArraycpy(&(*rremote1)[o], &rremote[o], n);CHKERRQ(ierr);
733f80536cbSVaclav Hapla     ierr = PetscSortIntWithArray(n, &(*rremote1)[o], &(*rmine1)[o]);CHKERRQ(ierr);
734f80536cbSVaclav Hapla   }
735f80536cbSVaclav Hapla   PetscFunctionReturn(0);
736f80536cbSVaclav Hapla }
737f80536cbSVaclav Hapla 
73827d0e99aSVaclav Hapla PetscErrorCode DMPlexOrientInterface_Internal(DM dm)
7392e745bdaSMatthew G. Knepley {
74027d0e99aSVaclav Hapla   /* Here we only compare first 2 points of the cone. Full cone size would lead to stronger self-checking. */
74127d0e99aSVaclav Hapla   PetscInt          masterCone[2];
742cae7fe92SVaclav Hapla   PetscInt          (*roots)[2], (*leaves)[2];
7438a650c75SVaclav Hapla   PetscMPIInt       (*rootsRanks)[2], (*leavesRanks)[2];
74427d0e99aSVaclav Hapla 
74527d0e99aSVaclav Hapla   PetscSF           sf=NULL;
746a0d42dbcSVaclav Hapla   const PetscInt    *locals=NULL;
747a0d42dbcSVaclav Hapla   const PetscSFNode *remotes=NULL;
7488a650c75SVaclav Hapla   PetscInt           nroots, nleaves, p, c;
749f80536cbSVaclav Hapla   PetscInt           nranks, n, o, r;
750a0d42dbcSVaclav Hapla   const PetscMPIInt *ranks=NULL;
751a0d42dbcSVaclav Hapla   const PetscInt    *roffset=NULL;
752a0d42dbcSVaclav Hapla   PetscInt          *rmine1=NULL, *rremote1=NULL; /* rmine and rremote copies simultaneously sorted by rank and rremote */
753a0d42dbcSVaclav Hapla   const PetscInt    *cone=NULL;
754adeface4SVaclav Hapla   PetscInt           coneSize, ind0;
7552e745bdaSMatthew G. Knepley   MPI_Comm           comm;
75627d0e99aSVaclav Hapla   PetscMPIInt        rank,size;
7572e745bdaSMatthew G. Knepley   PetscInt           debug = 0;
7582e745bdaSMatthew G. Knepley   PetscErrorCode     ierr;
7592e745bdaSMatthew G. Knepley 
7602e745bdaSMatthew G. Knepley   PetscFunctionBegin;
761df6a9fadSVaclav Hapla   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7622e745bdaSMatthew G. Knepley   ierr = PetscSFGetGraph(sf, &nroots, &nleaves, &locals, &remotes);CHKERRQ(ierr);
7633ede9f65SMatthew G. Knepley   if (nroots < 0) PetscFunctionReturn(0);
764f80536cbSVaclav Hapla   ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
765dec1416fSJunchao Zhang   ierr = PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, NULL, NULL);CHKERRQ(ierr);
766dc21a0bfSVaclav Hapla   ierr = DMViewFromOptions(dm, NULL, "-before_fix_dm_view");CHKERRQ(ierr);
76727d0e99aSVaclav Hapla #if defined(PETSC_USE_DEBUG)
768dc21a0bfSVaclav Hapla   ierr = DMPlexCheckPointSF(dm);CHKERRQ(ierr);
769dc21a0bfSVaclav Hapla #endif
770f80536cbSVaclav Hapla   ierr = SortRmineRremoteByRemote_Private(sf, &rmine1, &rremote1);CHKERRQ(ierr);
7718a650c75SVaclav Hapla   ierr = PetscMalloc4(nroots, &roots, nroots, &leaves, nroots, &rootsRanks, nroots, &leavesRanks);CHKERRQ(ierr);
7722e745bdaSMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
7732e745bdaSMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
77427d0e99aSVaclav Hapla   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
7759e24d8a0SVaclav Hapla   for (p = 0; p < nroots; ++p) {
7769e24d8a0SVaclav Hapla     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
7779e24d8a0SVaclav Hapla     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
77827d0e99aSVaclav Hapla     if (coneSize < 2) {
77927d0e99aSVaclav Hapla       for (c = 0; c < 2; c++) {
78027d0e99aSVaclav Hapla         roots[p][c] = -1;
78127d0e99aSVaclav Hapla         rootsRanks[p][c] = -1;
78227d0e99aSVaclav Hapla       }
78327d0e99aSVaclav Hapla       continue;
78427d0e99aSVaclav Hapla     }
7852e745bdaSMatthew G. Knepley     /* Translate all points to root numbering */
7868a650c75SVaclav Hapla     for (c = 0; c < 2; c++) {
7878a650c75SVaclav Hapla       ierr = PetscFindInt(cone[c], nleaves, locals, &ind0);CHKERRQ(ierr);
7888a650c75SVaclav Hapla       if (ind0 < 0) {
7898a650c75SVaclav Hapla         roots[p][c] = cone[c];
7908a650c75SVaclav Hapla         rootsRanks[p][c] = rank;
791c8148b97SVaclav Hapla       } else {
7928a650c75SVaclav Hapla         roots[p][c] = remotes[ind0].index;
7938a650c75SVaclav Hapla         rootsRanks[p][c] = remotes[ind0].rank;
7948a650c75SVaclav Hapla       }
7952e745bdaSMatthew G. Knepley     }
7962e745bdaSMatthew G. Knepley   }
7979e24d8a0SVaclav Hapla   for (p = 0; p < nroots; ++p) {
7988ccb905dSVaclav Hapla     for (c = 0; c < 2; c++) {
7998ccb905dSVaclav Hapla       leaves[p][c] = -2;
8008ccb905dSVaclav Hapla       leavesRanks[p][c] = -2;
8018ccb905dSVaclav Hapla     }
802c8148b97SVaclav Hapla   }
8032e745bdaSMatthew G. Knepley   ierr = PetscSFBcastBegin(sf, MPIU_2INT, roots, leaves);CHKERRQ(ierr);
8048a650c75SVaclav Hapla   ierr = PetscSFBcastBegin(sf, MPI_2INT, rootsRanks, leavesRanks);CHKERRQ(ierr);
8052e745bdaSMatthew G. Knepley   ierr = PetscSFBcastEnd(sf, MPIU_2INT, roots, leaves);CHKERRQ(ierr);
8068a650c75SVaclav Hapla   ierr = PetscSFBcastEnd(sf, MPI_2INT, rootsRanks, leavesRanks);CHKERRQ(ierr);
807c8148b97SVaclav Hapla   if (debug) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);}
80827d0e99aSVaclav Hapla   if (debug && rank == 0) {ierr = PetscSynchronizedPrintf(comm, "Referenced roots\n");CHKERRQ(ierr);}
8099e24d8a0SVaclav Hapla   for (p = 0; p < nroots; ++p) {
8109e24d8a0SVaclav Hapla     if (leaves[p][0] < 0) continue;
8119e24d8a0SVaclav Hapla     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
8129e24d8a0SVaclav Hapla     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
81327d0e99aSVaclav Hapla     if (debug) {ierr = PetscSynchronizedPrintf(comm, "[%d]  %4D: cone=[%4D %4D] roots=[(%d,%4D) (%d,%4D)] leaves=[(%d,%4D) (%d,%4D)]", rank, p, cone[0], cone[1], rootsRanks[p][0], roots[p][0], rootsRanks[p][1], roots[p][1], leavesRanks[p][0], leaves[p][0], leavesRanks[p][1], leaves[p][1]);CHKERRQ(ierr);}
81482f5c0aeSVaclav Hapla     if ((leaves[p][0] != roots[p][0]) || (leaves[p][1] != roots[p][1]) || (leavesRanks[p][0] != rootsRanks[p][0]) || (leavesRanks[p][1] != rootsRanks[p][1])) {
81527d0e99aSVaclav Hapla       /* Translate these two leaves to my cone points; masterCone means desired order p's cone points */
816f80536cbSVaclav Hapla       for (c = 0; c < 2; c++) {
81727d0e99aSVaclav Hapla         if (leavesRanks[p][c] == rank) {
81827d0e99aSVaclav Hapla           /* A local leave is just taken as it is */
81927d0e99aSVaclav Hapla           masterCone[c] = leaves[p][c];
82027d0e99aSVaclav Hapla           continue;
82127d0e99aSVaclav Hapla         }
822f80536cbSVaclav Hapla         /* Find index of rank leavesRanks[p][c] among remote ranks */
823f80536cbSVaclav Hapla         /* No need for PetscMPIIntCast because these integers were originally cast from PetscMPIInt. */
824f80536cbSVaclav Hapla         ierr = PetscFindMPIInt((PetscMPIInt)leavesRanks[p][c], nranks, ranks, &r);CHKERRQ(ierr);
82527d0e99aSVaclav Hapla         if (PetscUnlikely(r < 0)) SETERRQ7(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D cone[%D]=%D root (%d,%D) leave (%d,%D): leave rank not found among remote ranks",p,c,cone[c],rootsRanks[p][c],roots[p][c],leavesRanks[p][c],leaves[p][c]);
82627d0e99aSVaclav Hapla         if (PetscUnlikely(ranks[r] < 0 || ranks[r] >= size)) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_PLIB, "p=%D c=%D commsize=%d: ranks[%D] = %d makes no sense",p,c,size,r,ranks[r]);
827f80536cbSVaclav Hapla         /* Find point leaves[p][c] among remote points aimed at rank leavesRanks[p][c] */
828f80536cbSVaclav Hapla         o = roffset[r];
829f80536cbSVaclav Hapla         n = roffset[r+1] - o;
830f80536cbSVaclav Hapla         ierr = PetscFindInt(leaves[p][c], n, &rremote1[o], &ind0);CHKERRQ(ierr);
83127d0e99aSVaclav Hapla         if (PetscUnlikely(ind0 < 0)) SETERRQ7(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D cone[%D]=%D root (%d,%D) leave (%d,%D): corresponding remote point not found - it seems there is missing connection in point SF!",p,c,cone[c],rootsRanks[p][c],roots[p][c],leavesRanks[p][c],leaves[p][c]);
832f80536cbSVaclav Hapla         /* Get the corresponding local point */
833f80536cbSVaclav Hapla         masterCone[c] = rmine1[o+ind0];CHKERRQ(ierr);
834f80536cbSVaclav Hapla       }
83527d0e99aSVaclav Hapla       if (debug) {ierr = PetscSynchronizedPrintf(comm, " masterCone=[%4D %4D]\n", masterCone[0], masterCone[1]);CHKERRQ(ierr);}
83627d0e99aSVaclav Hapla       /* Set the desired order of p's cone points and fix orientations accordingly */
837f80536cbSVaclav Hapla       /* Vaclav's note: Here we only compare first 2 points of the cone. Full cone size would lead to stronger self-checking. */
838f80536cbSVaclav Hapla       ierr = DMPlexOrientCell(dm, p, 2, masterCone);CHKERRQ(ierr);
83927d0e99aSVaclav Hapla     } else if (debug) {ierr = PetscSynchronizedPrintf(comm, " ==\n");CHKERRQ(ierr);}
84023aaf07bSVaclav Hapla   }
84127d0e99aSVaclav Hapla   if (debug) {
84227d0e99aSVaclav Hapla     ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
84327d0e99aSVaclav Hapla     ierr = MPI_Barrier(comm);CHKERRQ(ierr);
8442e745bdaSMatthew G. Knepley   }
845adeface4SVaclav Hapla   ierr = DMViewFromOptions(dm, NULL, "-after_fix_dm_view");CHKERRQ(ierr);
8468a650c75SVaclav Hapla   ierr = PetscFree4(roots, leaves, rootsRanks, leavesRanks);CHKERRQ(ierr);
8477c7bb832SVaclav Hapla   ierr = PetscFree2(rmine1, rremote1);CHKERRQ(ierr);
8482e745bdaSMatthew G. Knepley   PetscFunctionReturn(0);
8492e745bdaSMatthew G. Knepley }
8502e745bdaSMatthew G. Knepley 
8512e72742cSMatthew 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[])
8527bffde78SMichael Lange {
8532e72742cSMatthew G. Knepley   PetscInt       idx;
8542e72742cSMatthew G. Knepley   PetscMPIInt    rank;
8552e72742cSMatthew G. Knepley   PetscBool      flg;
8567bffde78SMichael Lange   PetscErrorCode ierr;
8577bffde78SMichael Lange 
8587bffde78SMichael Lange   PetscFunctionBegin;
8592e72742cSMatthew G. Knepley   ierr = PetscOptionsHasName(NULL, NULL, opt, &flg);CHKERRQ(ierr);
8602e72742cSMatthew G. Knepley   if (!flg) PetscFunctionReturn(0);
8612e72742cSMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
8622e72742cSMatthew G. Knepley   ierr = PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name);CHKERRQ(ierr);
8632e72742cSMatthew G. Knepley   for (idx = 0; idx < n; ++idx) {ierr = PetscSynchronizedPrintf(comm, "[%d]%s %D %s %D\n", rank, idxname, idx, valname, a[idx]);CHKERRQ(ierr);}
8642e72742cSMatthew G. Knepley   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
8652e72742cSMatthew G. Knepley   PetscFunctionReturn(0);
8662e72742cSMatthew G. Knepley }
8672e72742cSMatthew G. Knepley 
8682e72742cSMatthew G. Knepley static PetscErrorCode SFNodeArrayViewFromOptions(MPI_Comm comm, const char opt[], const char name[], const char idxname[], PetscInt n, const PetscSFNode a[])
8692e72742cSMatthew G. Knepley {
8702e72742cSMatthew G. Knepley   PetscInt       idx;
8712e72742cSMatthew G. Knepley   PetscMPIInt    rank;
8722e72742cSMatthew G. Knepley   PetscBool      flg;
8732e72742cSMatthew G. Knepley   PetscErrorCode ierr;
8742e72742cSMatthew G. Knepley 
8752e72742cSMatthew G. Knepley   PetscFunctionBegin;
8762e72742cSMatthew G. Knepley   ierr = PetscOptionsHasName(NULL, NULL, opt, &flg);CHKERRQ(ierr);
8772e72742cSMatthew G. Knepley   if (!flg) PetscFunctionReturn(0);
8782e72742cSMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
8792e72742cSMatthew G. Knepley   ierr = PetscSynchronizedPrintf(comm, "[%d]%s:\n", rank, name);CHKERRQ(ierr);
8802e72742cSMatthew G. Knepley   if (idxname) {
8812e72742cSMatthew G. Knepley     for (idx = 0; idx < n; ++idx) {ierr = PetscSynchronizedPrintf(comm, "[%d]%s %D rank %D index %D\n", rank, idxname, idx, a[idx].rank, a[idx].index);CHKERRQ(ierr);}
8822e72742cSMatthew G. Knepley   } else {
8832e72742cSMatthew G. Knepley     for (idx = 0; idx < n; ++idx) {ierr = PetscSynchronizedPrintf(comm, "[%d]rank %D index %D\n", rank, a[idx].rank, a[idx].index);CHKERRQ(ierr);}
8842e72742cSMatthew G. Knepley   }
8852e72742cSMatthew G. Knepley   ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);
8862e72742cSMatthew G. Knepley   PetscFunctionReturn(0);
8872e72742cSMatthew G. Knepley }
8882e72742cSMatthew G. Knepley 
8892e72742cSMatthew G. Knepley static PetscErrorCode DMPlexMapToLocalPoint(PetscHMapIJ roothash, const PetscInt localPoints[], PetscMPIInt rank, PetscSFNode remotePoint, PetscInt *localPoint)
8902e72742cSMatthew G. Knepley {
8912e72742cSMatthew G. Knepley   PetscErrorCode ierr;
8922e72742cSMatthew G. Knepley 
8932e72742cSMatthew G. Knepley   PetscFunctionBegin;
8942e72742cSMatthew G. Knepley   if (remotePoint.rank == rank) {
8952e72742cSMatthew G. Knepley     *localPoint = remotePoint.index;
8962e72742cSMatthew G. Knepley   } else {
8972e72742cSMatthew G. Knepley     PetscHashIJKey key;
8982e72742cSMatthew G. Knepley     PetscInt       root;
8992e72742cSMatthew G. Knepley 
9002e72742cSMatthew G. Knepley     key.i = remotePoint.index;
9012e72742cSMatthew G. Knepley     key.j = remotePoint.rank;
9022e72742cSMatthew G. Knepley     ierr = PetscHMapIJGet(roothash, key, &root);CHKERRQ(ierr);
9032e72742cSMatthew G. Knepley     if (root >= 0) {
9042e72742cSMatthew G. Knepley       *localPoint = localPoints[root];
9052e72742cSMatthew G. Knepley     } else PetscFunctionReturn(1);
9062e72742cSMatthew G. Knepley   }
9072e72742cSMatthew G. Knepley   PetscFunctionReturn(0);
9082e72742cSMatthew G. Knepley }
9092e72742cSMatthew G. Knepley 
9102e72742cSMatthew G. Knepley /*@
9112e72742cSMatthew G. Knepley   DMPlexInterpolatePointSF - Insert interpolated points in the overlap into the PointSF in parallel, following local interpolation
9122e72742cSMatthew G. Knepley 
913d083f849SBarry Smith   Collective on dm
9142e72742cSMatthew G. Knepley 
9152e72742cSMatthew G. Knepley   Input Parameters:
9162e72742cSMatthew G. Knepley + dm      - The interpolated DM
9172e72742cSMatthew G. Knepley - pointSF - The initial SF without interpolated points
9182e72742cSMatthew G. Knepley 
9192e72742cSMatthew G. Knepley   Output Parameter:
9202e72742cSMatthew G. Knepley . pointSF - The SF including interpolated points
9212e72742cSMatthew G. Knepley 
922*f0cfc026SVaclav Hapla   Level: developer
9232e72742cSMatthew G. Knepley 
9242e72742cSMatthew 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
9252e72742cSMatthew G. Knepley 
9262e72742cSMatthew G. Knepley .seealso: DMPlexInterpolate(), DMPlexUninterpolate()
9272e72742cSMatthew G. Knepley @*/
928e53487d3SMatthew G. Knepley PetscErrorCode DMPlexInterpolatePointSF(DM dm, PetscSF pointSF)
9292e72742cSMatthew G. Knepley {
9302e72742cSMatthew G. Knepley   /*
9312e72742cSMatthew G. Knepley        Okay, the algorithm is:
9322e72742cSMatthew G. Knepley          - Take each point in the overlap (root)
9332e72742cSMatthew G. Knepley          - Look at the neighboring points in the overlap (candidates)
9342e72742cSMatthew G. Knepley          - Send these candidate points to neighbors
9352e72742cSMatthew G. Knepley          - Neighbor checks for edge between root and candidate
9362e72742cSMatthew G. Knepley          - If edge is found, it replaces candidate point with edge point
9372e72742cSMatthew G. Knepley          - Send back the overwritten candidates (claims)
9382e72742cSMatthew G. Knepley          - Original guy checks for edges, different from original candidate, and gets its own edge
9392e72742cSMatthew G. Knepley          - This pair is put into SF
9402e72742cSMatthew G. Knepley 
9412e72742cSMatthew G. Knepley        We need a new algorithm that tolerates groups larger than 2.
9422e72742cSMatthew G. Knepley          - Take each point in the overlap (root)
9432e72742cSMatthew G. Knepley          - Find all collections of points in the overlap which make faces (do early join)
9442e72742cSMatthew G. Knepley          - Send collections as candidates (add size as first number)
94566aa2a39SMatthew G. Knepley            - Make sure to send collection to all owners of all overlap points in collection
9462e72742cSMatthew G. Knepley          - Neighbor check for face in collections
9472e72742cSMatthew G. Knepley          - If face is found, it replaces candidate point with face point
9482e72742cSMatthew G. Knepley          - Send back the overwritten candidates (claims)
9492e72742cSMatthew G. Knepley          - Original guy checks for faces, different from original candidate, and gets its own face
9502e72742cSMatthew G. Knepley          - This pair is put into SF
9512e72742cSMatthew G. Knepley   */
9522e72742cSMatthew G. Knepley   PetscHMapI         leafhash;
9532e72742cSMatthew G. Knepley   PetscHMapIJ        roothash;
9542e72742cSMatthew G. Knepley   const PetscInt    *localPoints, *rootdegree;
9552e72742cSMatthew G. Knepley   const PetscSFNode *remotePoints;
9562e72742cSMatthew G. Knepley   PetscSFNode       *candidates, *candidatesRemote, *claims;
9572e72742cSMatthew G. Knepley   PetscSection       candidateSection, candidateSectionRemote, claimSection;
9582e72742cSMatthew G. Knepley   PetscInt           numLeaves, l, numRoots, r, candidatesSize, candidatesRemoteSize;
959*f0cfc026SVaclav Hapla   PetscMPIInt        rank;
9602e72742cSMatthew G. Knepley   PetscHashIJKey     key;
961*f0cfc026SVaclav Hapla   PetscBool          debug = PETSC_FALSE, flg;
9622e72742cSMatthew G. Knepley   PetscErrorCode     ierr;
9632e72742cSMatthew G. Knepley 
9642e72742cSMatthew G. Knepley   PetscFunctionBegin;
965*f0cfc026SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
966*f0cfc026SVaclav Hapla   PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2);
9672e72742cSMatthew G. Knepley   ierr = PetscOptionsHasName(NULL, ((PetscObject) dm)->prefix, "-dmplex_interp_debug", &debug);CHKERRQ(ierr);
9687bffde78SMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
969*f0cfc026SVaclav Hapla   ierr = DMPlexIsDistributed(dm, &flg);CHKERRQ(ierr);
970*f0cfc026SVaclav Hapla   if (!flg) PetscFunctionReturn(0);
971f240e3b7SVaclav Hapla   ierr = DMPlexGetOverlap(dm, &r);CHKERRQ(ierr);
972f240e3b7SVaclav Hapla   if (r) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Interpolation of overlapped DMPlex not implemented yet");
973*f0cfc026SVaclav Hapla   ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
974*f0cfc026SVaclav Hapla   if (numRoots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set");
9752e72742cSMatthew G. Knepley   ierr = PetscObjectViewFromOptions((PetscObject) dm, NULL, "-dm_interp_pre_view");CHKERRQ(ierr);
9762e72742cSMatthew G. Knepley   ierr = PetscObjectViewFromOptions((PetscObject) pointSF, NULL, "-petscsf_interp_pre_view");CHKERRQ(ierr);
97725afeb17SMatthew G. Knepley   ierr = PetscLogEventBegin(DMPLEX_InterpolateSF,dm,0,0,0);CHKERRQ(ierr);
9787bffde78SMichael Lange   /* Build hashes of points in the SF for efficient lookup */
979e8f14785SLisandro Dalcin   ierr = PetscHMapICreate(&leafhash);CHKERRQ(ierr);
980e8f14785SLisandro Dalcin   ierr = PetscHMapIJCreate(&roothash);CHKERRQ(ierr);
9812e72742cSMatthew G. Knepley   for (l = 0; l < numLeaves; ++l) {
9822e72742cSMatthew G. Knepley     key.i = remotePoints[l].index;
9832e72742cSMatthew G. Knepley     key.j = remotePoints[l].rank;
9842e72742cSMatthew G. Knepley     ierr = PetscHMapISet(leafhash, localPoints[l], l);CHKERRQ(ierr);
9852e72742cSMatthew G. Knepley     ierr = PetscHMapIJSet(roothash, key, l);CHKERRQ(ierr);
9867bffde78SMichael Lange   }
98766aa2a39SMatthew G. Knepley   /* Compute root degree to identify shared points */
9882e72742cSMatthew G. Knepley   ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr);
9892e72742cSMatthew G. Knepley   ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr);
9902e72742cSMatthew G. Knepley   ierr = IntArrayViewFromOptions(PetscObjectComm((PetscObject) dm), "-interp_root_degree_view", "Root degree", "point", "degree", numRoots, rootdegree);CHKERRQ(ierr);
99166aa2a39SMatthew G. Knepley   /* Build a section / SFNode array of candidate points (face bd points) in the cone(support(leaf)),
99266aa2a39SMatthew G. Knepley      where each candidate is defined by a set of remote points (roots) for the other points that define the face. */
9937bffde78SMichael Lange   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &candidateSection);CHKERRQ(ierr);
9947bffde78SMichael Lange   ierr = PetscSectionSetChart(candidateSection, 0, numRoots);CHKERRQ(ierr);
9957bffde78SMichael Lange   {
99666aa2a39SMatthew G. Knepley     PetscHMapIJ facehash;
9972e72742cSMatthew G. Knepley 
99866aa2a39SMatthew G. Knepley     ierr = PetscHMapIJCreate(&facehash);CHKERRQ(ierr);
9992e72742cSMatthew G. Knepley     for (l = 0; l < numLeaves; ++l) {
10002e72742cSMatthew G. Knepley       const PetscInt    localPoint = localPoints[l];
10012e72742cSMatthew G. Knepley       const PetscInt   *support;
10022e72742cSMatthew G. Knepley       PetscInt          supportSize, s;
10032e72742cSMatthew G. Knepley 
10042e72742cSMatthew G. Knepley       if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Checking local point %D\n", rank, localPoint);CHKERRQ(ierr);}
10052e72742cSMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, localPoint, &supportSize);CHKERRQ(ierr);
10062e72742cSMatthew G. Knepley       ierr = DMPlexGetSupport(dm, localPoint, &support);CHKERRQ(ierr);
10072e72742cSMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
10082e72742cSMatthew G. Knepley         const PetscInt  face = support[s];
10092e72742cSMatthew G. Knepley         const PetscInt *cone;
10102e72742cSMatthew G. Knepley         PetscInt        coneSize, c, f, root;
10112e72742cSMatthew G. Knepley         PetscBool       isFace = PETSC_TRUE;
10122e72742cSMatthew G. Knepley 
10132e72742cSMatthew G. Knepley         /* Only add face once */
10142e72742cSMatthew G. Knepley         if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    Support point %D\n", rank, face);CHKERRQ(ierr);}
101566aa2a39SMatthew G. Knepley         key.i = localPoint;
101666aa2a39SMatthew G. Knepley         key.j = face;
101766aa2a39SMatthew G. Knepley         ierr = PetscHMapIJGet(facehash, key, &f);CHKERRQ(ierr);
10182e72742cSMatthew G. Knepley         if (f >= 0) continue;
10192e72742cSMatthew G. Knepley         ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10202e72742cSMatthew G. Knepley         ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10212e72742cSMatthew G. Knepley         /* If a cone point does not map to leaves on any proc, then do not put face in SF */
10222e72742cSMatthew G. Knepley         for (c = 0; c < coneSize; ++c) {
10232e72742cSMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]      Cone point %D\n", rank, cone[c]);CHKERRQ(ierr);}
10242e72742cSMatthew G. Knepley           ierr = PetscHMapIGet(leafhash, cone[c], &root);CHKERRQ(ierr);
10252e72742cSMatthew G. Knepley           if (!rootdegree[cone[c]] && (root < 0)) {isFace = PETSC_FALSE; break;}
10262e72742cSMatthew G. Knepley         }
10272e72742cSMatthew G. Knepley         if (isFace) {
102866aa2a39SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    Found shared face %D\n", rank, face);CHKERRQ(ierr);}
102966aa2a39SMatthew G. Knepley           ierr = PetscHMapIJSet(facehash, key, l);CHKERRQ(ierr);
10302e72742cSMatthew G. Knepley           ierr = PetscSectionAddDof(candidateSection, localPoint, coneSize);CHKERRQ(ierr);
10317bffde78SMichael Lange         }
10327bffde78SMichael Lange       }
10332e72742cSMatthew G. Knepley     }
10342e72742cSMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedFlush(PetscObjectComm((PetscObject) dm), NULL);CHKERRQ(ierr);}
103566aa2a39SMatthew G. Knepley     ierr = PetscHMapIJClear(facehash);CHKERRQ(ierr);
10367bffde78SMichael Lange     ierr = PetscSectionSetUp(candidateSection);CHKERRQ(ierr);
10377bffde78SMichael Lange     ierr = PetscSectionGetStorageSize(candidateSection, &candidatesSize);CHKERRQ(ierr);
10387bffde78SMichael Lange     ierr = PetscMalloc1(candidatesSize, &candidates);CHKERRQ(ierr);
10392e72742cSMatthew G. Knepley     for (l = 0; l < numLeaves; ++l) {
10402e72742cSMatthew G. Knepley       const PetscInt    localPoint = localPoints[l];
10412e72742cSMatthew G. Knepley       const PetscInt   *support;
10422e72742cSMatthew G. Knepley       PetscInt          supportSize, s, offset, idx = 0;
10432e72742cSMatthew G. Knepley 
10442e72742cSMatthew G. Knepley       if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Checking local point %D\n", rank, localPoint);CHKERRQ(ierr);}
10452e72742cSMatthew G. Knepley       ierr = PetscSectionGetOffset(candidateSection, localPoint, &offset);CHKERRQ(ierr);
10462e72742cSMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, localPoint, &supportSize);CHKERRQ(ierr);
10472e72742cSMatthew G. Knepley       ierr = DMPlexGetSupport(dm, localPoint, &support);CHKERRQ(ierr);
10482e72742cSMatthew G. Knepley       for (s = 0; s < supportSize; ++s) {
10492e72742cSMatthew G. Knepley         const PetscInt  face = support[s];
10502e72742cSMatthew G. Knepley         const PetscInt *cone;
10512e72742cSMatthew G. Knepley         PetscInt        coneSize, c, f, root;
10522e72742cSMatthew G. Knepley         PetscBool       isFace = PETSC_TRUE;
10532e72742cSMatthew G. Knepley 
10542e72742cSMatthew G. Knepley         /* Only add face once */
10552e72742cSMatthew G. Knepley         if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    Support point %D\n", rank, face);CHKERRQ(ierr);}
105666aa2a39SMatthew G. Knepley         key.i = localPoint;
105766aa2a39SMatthew G. Knepley         key.j = face;
105866aa2a39SMatthew G. Knepley         ierr = PetscHMapIJGet(facehash, key, &f);CHKERRQ(ierr);
10592e72742cSMatthew G. Knepley         if (f >= 0) continue;
10602e72742cSMatthew G. Knepley         ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10612e72742cSMatthew G. Knepley         ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10622e72742cSMatthew G. Knepley         /* If a cone point does not map to leaves on any proc, then do not put face in SF */
10632e72742cSMatthew G. Knepley         for (c = 0; c < coneSize; ++c) {
10642e72742cSMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]      Cone point %D\n", rank, cone[c]);CHKERRQ(ierr);}
10652e72742cSMatthew G. Knepley           ierr = PetscHMapIGet(leafhash, cone[c], &root);CHKERRQ(ierr);
10662e72742cSMatthew G. Knepley           if (!rootdegree[cone[c]] && (root < 0)) {isFace = PETSC_FALSE; break;}
10672e72742cSMatthew G. Knepley         }
10682e72742cSMatthew G. Knepley         if (isFace) {
106966aa2a39SMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    Adding shared face %D at idx %D\n", rank, face, idx);CHKERRQ(ierr);}
107066aa2a39SMatthew G. Knepley           ierr = PetscHMapIJSet(facehash, key, l);CHKERRQ(ierr);
10712e72742cSMatthew G. Knepley           candidates[offset+idx].rank    = -1;
10722e72742cSMatthew G. Knepley           candidates[offset+idx++].index = coneSize-1;
10732e72742cSMatthew G. Knepley           for (c = 0; c < coneSize; ++c) {
10742e72742cSMatthew G. Knepley             if (cone[c] == localPoint) continue;
10752e72742cSMatthew G. Knepley             if (rootdegree[cone[c]]) {
10762e72742cSMatthew G. Knepley               candidates[offset+idx].rank    = rank;
10772e72742cSMatthew G. Knepley               candidates[offset+idx++].index = cone[c];
10782e72742cSMatthew G. Knepley             } else {
10792e72742cSMatthew G. Knepley               ierr = PetscHMapIGet(leafhash, cone[c], &root);CHKERRQ(ierr);
10802e72742cSMatthew G. Knepley               if (root < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot locate local point %D in SF", cone[c]);
10812e72742cSMatthew G. Knepley               candidates[offset+idx++] = remotePoints[root];
10827bffde78SMichael Lange             }
10837bffde78SMichael Lange           }
10842e72742cSMatthew G. Knepley         }
10852e72742cSMatthew G. Knepley       }
10862e72742cSMatthew G. Knepley     }
10872e72742cSMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedFlush(PetscObjectComm((PetscObject) dm), NULL);CHKERRQ(ierr);}
108866aa2a39SMatthew G. Knepley     ierr = PetscHMapIJDestroy(&facehash);CHKERRQ(ierr);
10892e72742cSMatthew G. Knepley     ierr = PetscObjectViewFromOptions((PetscObject) candidateSection, NULL, "-petscsection_interp_candidate_view");CHKERRQ(ierr);
10902e72742cSMatthew G. Knepley     ierr = SFNodeArrayViewFromOptions(PetscObjectComm((PetscObject) dm), "-petscsection_interp_candidate_view", "Candidates", NULL, candidatesSize, candidates);CHKERRQ(ierr);
10917bffde78SMichael Lange   }
10927bffde78SMichael Lange   /* Gather candidate section / array pair into the root partition via inverse(multi(pointSF)). */
10932e72742cSMatthew G. Knepley   /*   Note that this section is indexed by offsets into leaves, not by point number */
10947bffde78SMichael Lange   {
10957bffde78SMichael Lange     PetscSF   sfMulti, sfInverse, sfCandidates;
10967bffde78SMichael Lange     PetscInt *remoteOffsets;
10972e72742cSMatthew G. Knepley 
10987bffde78SMichael Lange     ierr = PetscSFGetMultiSF(pointSF, &sfMulti);CHKERRQ(ierr);
10997bffde78SMichael Lange     ierr = PetscSFCreateInverseSF(sfMulti, &sfInverse);CHKERRQ(ierr);
11007bffde78SMichael Lange     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &candidateSectionRemote);CHKERRQ(ierr);
11017bffde78SMichael Lange     ierr = PetscSFDistributeSection(sfInverse, candidateSection, &remoteOffsets, candidateSectionRemote);CHKERRQ(ierr);
11027bffde78SMichael Lange     ierr = PetscSFCreateSectionSF(sfInverse, candidateSection, remoteOffsets, candidateSectionRemote, &sfCandidates);CHKERRQ(ierr);
11037bffde78SMichael Lange     ierr = PetscSectionGetStorageSize(candidateSectionRemote, &candidatesRemoteSize);CHKERRQ(ierr);
11047bffde78SMichael Lange     ierr = PetscMalloc1(candidatesRemoteSize, &candidatesRemote);CHKERRQ(ierr);
11057bffde78SMichael Lange     ierr = PetscSFBcastBegin(sfCandidates, MPIU_2INT, candidates, candidatesRemote);CHKERRQ(ierr);
11067bffde78SMichael Lange     ierr = PetscSFBcastEnd(sfCandidates, MPIU_2INT, candidates, candidatesRemote);CHKERRQ(ierr);
11077bffde78SMichael Lange     ierr = PetscSFDestroy(&sfInverse);CHKERRQ(ierr);
11087bffde78SMichael Lange     ierr = PetscSFDestroy(&sfCandidates);CHKERRQ(ierr);
11097bffde78SMichael Lange     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
11102e72742cSMatthew G. Knepley 
11112e72742cSMatthew G. Knepley     ierr = PetscObjectViewFromOptions((PetscObject) candidateSectionRemote, NULL, "-petscsection_interp_candidate_remote_view");CHKERRQ(ierr);
11122e72742cSMatthew G. Knepley     ierr = SFNodeArrayViewFromOptions(PetscObjectComm((PetscObject) dm), "-petscsection_interp_candidate_remote_view", "Remote Candidates", NULL, candidatesRemoteSize, candidatesRemote);CHKERRQ(ierr);
11137bffde78SMichael Lange   }
11142e72742cSMatthew G. Knepley   /* */
11157bffde78SMichael Lange   {
11162e72742cSMatthew G. Knepley     PetscInt idx;
11172e72742cSMatthew G. Knepley     /* There is a section point for every leaf attached to a given root point */
11182e72742cSMatthew G. Knepley     for (r = 0, idx = 0; r < numRoots; ++r) {
11192e72742cSMatthew G. Knepley       PetscInt deg;
11202e72742cSMatthew G. Knepley       for (deg = 0; deg < rootdegree[r]; ++deg, ++idx) {
11212e72742cSMatthew G. Knepley         PetscInt offset, dof, d;
11222e72742cSMatthew G. Knepley 
11237bffde78SMichael Lange         ierr = PetscSectionGetDof(candidateSectionRemote, idx, &dof);CHKERRQ(ierr);
11247bffde78SMichael Lange         ierr = PetscSectionGetOffset(candidateSectionRemote, idx, &offset);CHKERRQ(ierr);
11252e72742cSMatthew G. Knepley         for (d = 0; d < dof; ++d) {
11262e72742cSMatthew G. Knepley           const PetscInt  sizeInd   = offset+d;
11272e72742cSMatthew G. Knepley           const PetscInt  numPoints = candidatesRemote[sizeInd].index;
11282e72742cSMatthew G. Knepley           const PetscInt *join      = NULL;
11292e72742cSMatthew G. Knepley           PetscInt        points[1024], p, joinSize;
11302e72742cSMatthew G. Knepley 
11312e72742cSMatthew G. Knepley           points[0] = r;
11322e72742cSMatthew G. Knepley           for (p = 0; p < numPoints; ++p) {
11332e72742cSMatthew G. Knepley             ierr = DMPlexMapToLocalPoint(roothash, localPoints, rank, candidatesRemote[offset+(++d)], &points[p+1]);
11342e72742cSMatthew G. Knepley             if (ierr) {d += numPoints-1 - p; break;} /* We got a point not in our overlap */
11352e72742cSMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Checking local candidate %D\n", rank, points[p+1]);CHKERRQ(ierr);}
11367bffde78SMichael Lange           }
11372e72742cSMatthew G. Knepley           if (ierr) continue;
11382e72742cSMatthew G. Knepley           ierr = DMPlexGetJoin(dm, numPoints+1, points, &joinSize, &join);CHKERRQ(ierr);
11397bffde78SMichael Lange           if (joinSize == 1) {
11402e72742cSMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    Adding face %D at idx %D\n", rank, join[0], sizeInd);CHKERRQ(ierr);}
11412e72742cSMatthew G. Knepley             candidatesRemote[sizeInd].rank  = rank;
11422e72742cSMatthew G. Knepley             candidatesRemote[sizeInd].index = join[0];
11437bffde78SMichael Lange           }
11442e72742cSMatthew G. Knepley           ierr = DMPlexRestoreJoin(dm, numPoints+1, points, &joinSize, &join);CHKERRQ(ierr);
11457bffde78SMichael Lange         }
11467bffde78SMichael Lange       }
11477bffde78SMichael Lange     }
11482e72742cSMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedFlush(PetscObjectComm((PetscObject) dm), NULL);CHKERRQ(ierr);}
11497bffde78SMichael Lange   }
11507bffde78SMichael Lange   /* Push claims back to receiver via the MultiSF and derive new pointSF mapping on receiver */
11517bffde78SMichael Lange   {
11527bffde78SMichael Lange     PetscSF         sfMulti, sfClaims, sfPointNew;
11537bffde78SMichael Lange     PetscSFNode    *remotePointsNew;
11542e72742cSMatthew G. Knepley     PetscHMapI      claimshash;
11552e72742cSMatthew G. Knepley     PetscInt       *remoteOffsets, *localPointsNew;
11562e72742cSMatthew G. Knepley     PetscInt        claimsSize, pStart, pEnd, root, numLocalNew, p, d;
11572e72742cSMatthew G. Knepley 
11587bffde78SMichael Lange     ierr = PetscSFGetMultiSF(pointSF, &sfMulti);CHKERRQ(ierr);
11597bffde78SMichael Lange     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &claimSection);CHKERRQ(ierr);
11607bffde78SMichael Lange     ierr = PetscSFDistributeSection(sfMulti, candidateSectionRemote, &remoteOffsets, claimSection);CHKERRQ(ierr);
11617bffde78SMichael Lange     ierr = PetscSFCreateSectionSF(sfMulti, candidateSectionRemote, remoteOffsets, claimSection, &sfClaims);CHKERRQ(ierr);
11622e72742cSMatthew G. Knepley     ierr = PetscSectionGetStorageSize(claimSection, &claimsSize);CHKERRQ(ierr);
11632e72742cSMatthew G. Knepley     ierr = PetscMalloc1(claimsSize, &claims);CHKERRQ(ierr);
11647bffde78SMichael Lange     ierr = PetscSFBcastBegin(sfClaims, MPIU_2INT, candidatesRemote, claims);CHKERRQ(ierr);
11657bffde78SMichael Lange     ierr = PetscSFBcastEnd(sfClaims, MPIU_2INT, candidatesRemote, claims);CHKERRQ(ierr);
11667bffde78SMichael Lange     ierr = PetscSFDestroy(&sfClaims);CHKERRQ(ierr);
11677bffde78SMichael Lange     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
11682e72742cSMatthew G. Knepley     ierr = PetscObjectViewFromOptions((PetscObject) claimSection, NULL, "-petscsection_interp_claim_view");CHKERRQ(ierr);
11692e72742cSMatthew G. Knepley     ierr = SFNodeArrayViewFromOptions(PetscObjectComm((PetscObject) dm), "-petscsection_interp_claim_view", "Claims", NULL, claimsSize, claims);CHKERRQ(ierr);
11707bffde78SMichael Lange     /* Walk the original section of local supports and add an SF entry for each updated item */
1171e8f14785SLisandro Dalcin     ierr = PetscHMapICreate(&claimshash);CHKERRQ(ierr);
11727bffde78SMichael Lange     for (p = 0; p < numRoots; ++p) {
11732e72742cSMatthew G. Knepley       PetscInt dof, offset;
11742e72742cSMatthew G. Knepley 
11752e72742cSMatthew G. Knepley       if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]  Checking root for claims %D\n", rank, p);CHKERRQ(ierr);}
11767bffde78SMichael Lange       ierr = PetscSectionGetDof(candidateSection, p, &dof);CHKERRQ(ierr);
11777bffde78SMichael Lange       ierr = PetscSectionGetOffset(candidateSection, p, &offset);CHKERRQ(ierr);
11782e72742cSMatthew G. Knepley       for (d = 0; d < dof;) {
11792e72742cSMatthew G. Knepley         if (claims[offset+d].rank >= 0) {
11802e72742cSMatthew G. Knepley           const PetscInt  faceInd   = offset+d;
11812e72742cSMatthew G. Knepley           const PetscInt  numPoints = candidates[faceInd].index;
11822e72742cSMatthew G. Knepley           const PetscInt *join      = NULL;
11832e72742cSMatthew G. Knepley           PetscInt        joinSize, points[1024], c;
11842e72742cSMatthew G. Knepley 
11852e72742cSMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    Found claim for remote point (%D, %D)\n", rank, claims[faceInd].rank, claims[faceInd].index);CHKERRQ(ierr);}
11862e72742cSMatthew G. Knepley           points[0] = p;
11872e72742cSMatthew G. Knepley           if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]      point %D\n", rank, points[0]);CHKERRQ(ierr);}
11882e72742cSMatthew G. Knepley           for (c = 0, ++d; c < numPoints; ++c, ++d) {
1189e8f14785SLisandro Dalcin             key.i = candidates[offset+d].index;
1190e8f14785SLisandro Dalcin             key.j = candidates[offset+d].rank;
1191e8f14785SLisandro Dalcin             ierr = PetscHMapIJGet(roothash, key, &root);CHKERRQ(ierr);
11922e72742cSMatthew G. Knepley             points[c+1] = localPoints[root];
11932e72742cSMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]      point %D\n", rank, points[c+1]);CHKERRQ(ierr);}
11942e72742cSMatthew G. Knepley           }
11952e72742cSMatthew G. Knepley           ierr = DMPlexGetJoin(dm, numPoints+1, points, &joinSize, &join);CHKERRQ(ierr);
11962e72742cSMatthew G. Knepley           if (joinSize == 1) {
11972e72742cSMatthew G. Knepley             if (debug) {ierr = PetscSynchronizedPrintf(PetscObjectComm((PetscObject) dm), "[%d]    Found local face %D\n", rank, join[0]);CHKERRQ(ierr);}
11982e72742cSMatthew G. Knepley             ierr = PetscHMapISet(claimshash, join[0], faceInd);CHKERRQ(ierr);
11992e72742cSMatthew G. Knepley           }
12002e72742cSMatthew G. Knepley           ierr = DMPlexRestoreJoin(dm, numPoints+1, points, &joinSize, &join);CHKERRQ(ierr);
12012e72742cSMatthew G. Knepley         } else d += claims[offset+d].index+1;
12027bffde78SMichael Lange       }
12037bffde78SMichael Lange     }
12042e72742cSMatthew G. Knepley     if (debug) {ierr = PetscSynchronizedFlush(PetscObjectComm((PetscObject) dm), NULL);CHKERRQ(ierr);}
12057bffde78SMichael Lange     /* Create new pointSF from hashed claims */
1206e8f14785SLisandro Dalcin     ierr = PetscHMapIGetSize(claimshash, &numLocalNew);CHKERRQ(ierr);
12077bffde78SMichael Lange     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
12087bffde78SMichael Lange     ierr = PetscMalloc1(numLeaves + numLocalNew, &localPointsNew);CHKERRQ(ierr);
12097bffde78SMichael Lange     ierr = PetscMalloc1(numLeaves + numLocalNew, &remotePointsNew);CHKERRQ(ierr);
12107bffde78SMichael Lange     for (p = 0; p < numLeaves; ++p) {
12117bffde78SMichael Lange       localPointsNew[p] = localPoints[p];
12127bffde78SMichael Lange       remotePointsNew[p].index = remotePoints[p].index;
12137bffde78SMichael Lange       remotePointsNew[p].rank  = remotePoints[p].rank;
12147bffde78SMichael Lange     }
1215f3190fc2SToby Isaac     p = numLeaves;
1216e8f14785SLisandro Dalcin     ierr = PetscHMapIGetKeys(claimshash, &p, localPointsNew);CHKERRQ(ierr);
1217f3190fc2SToby Isaac     ierr = PetscSortInt(numLocalNew, &localPointsNew[numLeaves]);CHKERRQ(ierr);
12187bffde78SMichael Lange     for (p = numLeaves; p < numLeaves + numLocalNew; ++p) {
12192e72742cSMatthew G. Knepley       PetscInt offset;
1220e8f14785SLisandro Dalcin       ierr = PetscHMapIGet(claimshash, localPointsNew[p], &offset);CHKERRQ(ierr);
12217bffde78SMichael Lange       remotePointsNew[p] = claims[offset];
12227bffde78SMichael Lange     }
12237bffde78SMichael Lange     ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), &sfPointNew);CHKERRQ(ierr);
12247bffde78SMichael Lange     ierr = PetscSFSetGraph(sfPointNew, pEnd-pStart, numLeaves+numLocalNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
12257bffde78SMichael Lange     ierr = DMSetPointSF(dm, sfPointNew);CHKERRQ(ierr);
12267bffde78SMichael Lange     ierr = PetscSFDestroy(&sfPointNew);CHKERRQ(ierr);
1227e8f14785SLisandro Dalcin     ierr = PetscHMapIDestroy(&claimshash);CHKERRQ(ierr);
12287bffde78SMichael Lange   }
1229e8f14785SLisandro Dalcin   ierr = PetscHMapIDestroy(&leafhash);CHKERRQ(ierr);
1230e8f14785SLisandro Dalcin   ierr = PetscHMapIJDestroy(&roothash);CHKERRQ(ierr);
12317bffde78SMichael Lange   ierr = PetscSectionDestroy(&candidateSection);CHKERRQ(ierr);
12327bffde78SMichael Lange   ierr = PetscSectionDestroy(&candidateSectionRemote);CHKERRQ(ierr);
12337bffde78SMichael Lange   ierr = PetscSectionDestroy(&claimSection);CHKERRQ(ierr);
12347bffde78SMichael Lange   ierr = PetscFree(candidates);CHKERRQ(ierr);
12357bffde78SMichael Lange   ierr = PetscFree(candidatesRemote);CHKERRQ(ierr);
12367bffde78SMichael Lange   ierr = PetscFree(claims);CHKERRQ(ierr);
123725afeb17SMatthew G. Knepley   ierr = PetscLogEventEnd(DMPLEX_InterpolateSF,dm,0,0,0);CHKERRQ(ierr);
12387bffde78SMichael Lange   PetscFunctionReturn(0);
12397bffde78SMichael Lange }
12407bffde78SMichael Lange 
1241248eb259SVaclav Hapla /*@
124280330477SMatthew G. Knepley   DMPlexInterpolate - Take in a cell-vertex mesh and return one with all intermediate faces, edges, etc.
124380330477SMatthew G. Knepley 
1244d083f849SBarry Smith   Collective on dm
124580330477SMatthew G. Knepley 
1246e56d480eSMatthew G. Knepley   Input Parameters:
1247e56d480eSMatthew G. Knepley + dm - The DMPlex object with only cells and vertices
124810a67516SMatthew G. Knepley - dmInt - The interpolated DM
124980330477SMatthew G. Knepley 
125080330477SMatthew G. Knepley   Output Parameter:
12514e3744c5SMatthew G. Knepley . dmInt - The complete DMPlex object
125280330477SMatthew G. Knepley 
125380330477SMatthew G. Knepley   Level: intermediate
125480330477SMatthew G. Knepley 
125595452b02SPatrick Sanan   Notes:
125695452b02SPatrick Sanan     It does not copy over the coordinates.
125743eeeb2dSStefano Zampini 
125843eeeb2dSStefano Zampini .seealso: DMPlexUninterpolate(), DMPlexCreateFromCellList(), DMPlexCopyCoordinates()
125980330477SMatthew G. Knepley @*/
12609f074e33SMatthew G Knepley PetscErrorCode DMPlexInterpolate(DM dm, DM *dmInt)
12619f074e33SMatthew G Knepley {
1262a7748839SVaclav Hapla   DMPlexInterpolatedFlag interpolated;
12639a5b13a2SMatthew G Knepley   DM             idm, odm = dm;
12647bffde78SMichael Lange   PetscSF        sfPoint;
12652e1b13c2SMatthew G. Knepley   PetscInt       depth, dim, d;
126610a67516SMatthew G. Knepley   const char    *name;
1267b325530aSVaclav Hapla   PetscBool      flg=PETSC_TRUE;
12689f074e33SMatthew G Knepley   PetscErrorCode ierr;
12699f074e33SMatthew G Knepley 
12709f074e33SMatthew G Knepley   PetscFunctionBegin;
127110a67516SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
127210a67516SMatthew G. Knepley   PetscValidPointer(dmInt, 2);
1273a72f3261SMatthew G. Knepley   ierr = PetscLogEventBegin(DMPLEX_Interpolate,dm,0,0,0);CHKERRQ(ierr);
12742e1b13c2SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1275c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1276827c4036SVaclav Hapla   ierr = DMPlexIsInterpolated(dm, &interpolated);CHKERRQ(ierr);
1277827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_PARTIAL) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes");
1278827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_FULL) {
127976b791aaSMatthew G. Knepley     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
128076b791aaSMatthew G. Knepley     idm  = dm;
1281b21b8912SMatthew G. Knepley   } else {
12829a5b13a2SMatthew G Knepley     for (d = 1; d < dim; ++d) {
12839a5b13a2SMatthew G Knepley       /* Create interpolated mesh */
128410a67516SMatthew G. Knepley       ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
12859a5b13a2SMatthew G Knepley       ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
1286c73cfb54SMatthew G. Knepley       ierr = DMSetDimension(idm, dim);CHKERRQ(ierr);
12877bffde78SMichael Lange       if (depth > 0) {
12887bffde78SMichael Lange         ierr = DMPlexInterpolateFaces_Internal(odm, 1, idm);CHKERRQ(ierr);
12897bffde78SMichael Lange         ierr = DMGetPointSF(odm, &sfPoint);CHKERRQ(ierr);
12902e72742cSMatthew G. Knepley         ierr = DMPlexInterpolatePointSF(idm, sfPoint);CHKERRQ(ierr);
12917bffde78SMichael Lange       }
12929a5b13a2SMatthew G Knepley       if (odm != dm) {ierr = DMDestroy(&odm);CHKERRQ(ierr);}
12939a5b13a2SMatthew G Knepley       odm = idm;
12949f074e33SMatthew G Knepley     }
129510a67516SMatthew G. Knepley     ierr = PetscObjectGetName((PetscObject) dm,  &name);CHKERRQ(ierr);
129610a67516SMatthew G. Knepley     ierr = PetscObjectSetName((PetscObject) idm,  name);CHKERRQ(ierr);
129710a67516SMatthew G. Knepley     ierr = DMPlexCopyCoordinates(dm, idm);CHKERRQ(ierr);
12985d80c0bfSVaclav Hapla     ierr = DMCopyLabels(dm, idm, PETSC_COPY_VALUES, PETSC_FALSE);CHKERRQ(ierr);
1299b325530aSVaclav Hapla     ierr = PetscOptionsGetBool(((PetscObject)dm)->options, ((PetscObject)dm)->prefix, "-dm_plex_interpolate_orient_interfaces", &flg, NULL);CHKERRQ(ierr);
130027d0e99aSVaclav Hapla     if (flg) {ierr = DMPlexOrientInterface_Internal(idm);CHKERRQ(ierr);}
130184699f70SSatish Balay   }
130243eeeb2dSStefano Zampini   {
130343eeeb2dSStefano Zampini     PetscBool            isper;
130443eeeb2dSStefano Zampini     const PetscReal      *maxCell, *L;
130543eeeb2dSStefano Zampini     const DMBoundaryType *bd;
130643eeeb2dSStefano Zampini 
130743eeeb2dSStefano Zampini     ierr = DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd);CHKERRQ(ierr);
130843eeeb2dSStefano Zampini     ierr = DMSetPeriodicity(idm,isper,maxCell,L,bd);CHKERRQ(ierr);
130943eeeb2dSStefano Zampini   }
1310827c4036SVaclav Hapla   /* This function makes the mesh fully interpolated on all ranks */
1311827c4036SVaclav Hapla   {
1312827c4036SVaclav Hapla     DM_Plex *plex = (DM_Plex *) dm->data;
1313827c4036SVaclav Hapla     plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_FULL;
1314827c4036SVaclav Hapla   }
13159a5b13a2SMatthew G Knepley   *dmInt = idm;
1316a72f3261SMatthew G. Knepley   ierr = PetscLogEventEnd(DMPLEX_Interpolate,dm,0,0,0);CHKERRQ(ierr);
13179f074e33SMatthew G Knepley   PetscFunctionReturn(0);
13189f074e33SMatthew G Knepley }
131907b0a1fcSMatthew G Knepley 
132080330477SMatthew G. Knepley /*@
132180330477SMatthew G. Knepley   DMPlexCopyCoordinates - Copy coordinates from one mesh to another with the same vertices
132280330477SMatthew G. Knepley 
1323d083f849SBarry Smith   Collective on dmA
132480330477SMatthew G. Knepley 
132580330477SMatthew G. Knepley   Input Parameter:
132680330477SMatthew G. Knepley . dmA - The DMPlex object with initial coordinates
132780330477SMatthew G. Knepley 
132880330477SMatthew G. Knepley   Output Parameter:
132980330477SMatthew G. Knepley . dmB - The DMPlex object with copied coordinates
133080330477SMatthew G. Knepley 
133180330477SMatthew G. Knepley   Level: intermediate
133280330477SMatthew G. Knepley 
133380330477SMatthew G. Knepley   Note: This is typically used when adding pieces other than vertices to a mesh
133480330477SMatthew G. Knepley 
133565f90189SJed Brown .seealso: DMCopyLabels(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
133680330477SMatthew G. Knepley @*/
133707b0a1fcSMatthew G Knepley PetscErrorCode DMPlexCopyCoordinates(DM dmA, DM dmB)
133807b0a1fcSMatthew G Knepley {
133907b0a1fcSMatthew G Knepley   Vec            coordinatesA, coordinatesB;
134043eeeb2dSStefano Zampini   VecType        vtype;
134107b0a1fcSMatthew G Knepley   PetscSection   coordSectionA, coordSectionB;
134207b0a1fcSMatthew G Knepley   PetscScalar   *coordsA, *coordsB;
13430bedd6beSMatthew G. Knepley   PetscInt       spaceDim, Nf, vStartA, vStartB, vEndA, vEndB, coordSizeB, v, d;
134443eeeb2dSStefano Zampini   PetscInt       cStartA, cEndA, cStartB, cEndB, cS, cE;
134543eeeb2dSStefano Zampini   PetscBool      lc = PETSC_FALSE;
134607b0a1fcSMatthew G Knepley   PetscErrorCode ierr;
134707b0a1fcSMatthew G Knepley 
134807b0a1fcSMatthew G Knepley   PetscFunctionBegin;
134943eeeb2dSStefano Zampini   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
135043eeeb2dSStefano Zampini   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
135176b791aaSMatthew G. Knepley   if (dmA == dmB) PetscFunctionReturn(0);
135207b0a1fcSMatthew G Knepley   ierr = DMPlexGetDepthStratum(dmA, 0, &vStartA, &vEndA);CHKERRQ(ierr);
135307b0a1fcSMatthew G Knepley   ierr = DMPlexGetDepthStratum(dmB, 0, &vStartB, &vEndB);CHKERRQ(ierr);
135407b0a1fcSMatthew G Knepley   if ((vEndA-vStartA) != (vEndB-vStartB)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of vertices in first DM %d != %d in the second DM", vEndA-vStartA, vEndB-vStartB);
135543eeeb2dSStefano Zampini   ierr = DMPlexGetHeightStratum(dmA, 0, &cStartA, &cEndA);CHKERRQ(ierr);
135643eeeb2dSStefano Zampini   ierr = DMPlexGetHeightStratum(dmB, 0, &cStartB, &cEndB);CHKERRQ(ierr);
135769d8a9ceSMatthew G. Knepley   ierr = DMGetCoordinateSection(dmA, &coordSectionA);CHKERRQ(ierr);
135869d8a9ceSMatthew G. Knepley   ierr = DMGetCoordinateSection(dmB, &coordSectionB);CHKERRQ(ierr);
1359972bc18aSToby Isaac   if (coordSectionA == coordSectionB) PetscFunctionReturn(0);
13600bedd6beSMatthew G. Knepley   ierr = PetscSectionGetNumFields(coordSectionA, &Nf);CHKERRQ(ierr);
13610bedd6beSMatthew G. Knepley   if (!Nf) PetscFunctionReturn(0);
13620bedd6beSMatthew G. Knepley   if (Nf > 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of coordinate fields must be 1, not %D", Nf);
1363df26b574SMatthew G. Knepley   if (!coordSectionB) {
1364df26b574SMatthew G. Knepley     PetscInt dim;
1365df26b574SMatthew G. Knepley 
1366df26b574SMatthew G. Knepley     ierr = PetscSectionCreate(PetscObjectComm((PetscObject) coordSectionA), &coordSectionB);CHKERRQ(ierr);
1367df26b574SMatthew G. Knepley     ierr = DMGetCoordinateDim(dmA, &dim);CHKERRQ(ierr);
1368df26b574SMatthew G. Knepley     ierr = DMSetCoordinateSection(dmB, dim, coordSectionB);CHKERRQ(ierr);
1369df26b574SMatthew G. Knepley     ierr = PetscObjectDereference((PetscObject) coordSectionB);CHKERRQ(ierr);
1370df26b574SMatthew G. Knepley   }
137107b0a1fcSMatthew G Knepley   ierr = PetscSectionSetNumFields(coordSectionB, 1);CHKERRQ(ierr);
137207b0a1fcSMatthew G Knepley   ierr = PetscSectionGetFieldComponents(coordSectionA, 0, &spaceDim);CHKERRQ(ierr);
137307b0a1fcSMatthew G Knepley   ierr = PetscSectionSetFieldComponents(coordSectionB, 0, spaceDim);CHKERRQ(ierr);
137443eeeb2dSStefano Zampini   ierr = PetscSectionGetChart(coordSectionA, &cS, &cE);CHKERRQ(ierr);
137543eeeb2dSStefano Zampini   if (cStartA <= cS && cS < cEndA) { /* localized coordinates */
1376367003a6SStefano Zampini     if ((cEndA-cStartA) != (cEndB-cStartB)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cells in first DM %D != %D in the second DM", cEndA-cStartA, cEndB-cStartB);
137743eeeb2dSStefano Zampini     cS = cS - cStartA + cStartB;
137843eeeb2dSStefano Zampini     cE = vEndB;
137943eeeb2dSStefano Zampini     lc = PETSC_TRUE;
138043eeeb2dSStefano Zampini   } else {
138143eeeb2dSStefano Zampini     cS = vStartB;
138243eeeb2dSStefano Zampini     cE = vEndB;
138343eeeb2dSStefano Zampini   }
138443eeeb2dSStefano Zampini   ierr = PetscSectionSetChart(coordSectionB, cS, cE);CHKERRQ(ierr);
138507b0a1fcSMatthew G Knepley   for (v = vStartB; v < vEndB; ++v) {
138607b0a1fcSMatthew G Knepley     ierr = PetscSectionSetDof(coordSectionB, v, spaceDim);CHKERRQ(ierr);
138707b0a1fcSMatthew G Knepley     ierr = PetscSectionSetFieldDof(coordSectionB, v, 0, spaceDim);CHKERRQ(ierr);
138807b0a1fcSMatthew G Knepley   }
138943eeeb2dSStefano Zampini   if (lc) { /* localized coordinates */
139043eeeb2dSStefano Zampini     PetscInt c;
139143eeeb2dSStefano Zampini 
139243eeeb2dSStefano Zampini     for (c = cS-cStartB; c < cEndB-cStartB; c++) {
139343eeeb2dSStefano Zampini       PetscInt dof;
139443eeeb2dSStefano Zampini 
139543eeeb2dSStefano Zampini       ierr = PetscSectionGetDof(coordSectionA, c + cStartA, &dof);CHKERRQ(ierr);
139643eeeb2dSStefano Zampini       ierr = PetscSectionSetDof(coordSectionB, c + cStartB, dof);CHKERRQ(ierr);
139743eeeb2dSStefano Zampini       ierr = PetscSectionSetFieldDof(coordSectionB, c + cStartB, 0, dof);CHKERRQ(ierr);
139843eeeb2dSStefano Zampini     }
139943eeeb2dSStefano Zampini   }
140007b0a1fcSMatthew G Knepley   ierr = PetscSectionSetUp(coordSectionB);CHKERRQ(ierr);
140107b0a1fcSMatthew G Knepley   ierr = PetscSectionGetStorageSize(coordSectionB, &coordSizeB);CHKERRQ(ierr);
140207b0a1fcSMatthew G Knepley   ierr = DMGetCoordinatesLocal(dmA, &coordinatesA);CHKERRQ(ierr);
14038b9ced59SLisandro Dalcin   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesB);CHKERRQ(ierr);
140407b0a1fcSMatthew G Knepley   ierr = PetscObjectSetName((PetscObject) coordinatesB, "coordinates");CHKERRQ(ierr);
140507b0a1fcSMatthew G Knepley   ierr = VecSetSizes(coordinatesB, coordSizeB, PETSC_DETERMINE);CHKERRQ(ierr);
140643eeeb2dSStefano Zampini   ierr = VecGetBlockSize(coordinatesA, &d);CHKERRQ(ierr);
140743eeeb2dSStefano Zampini   ierr = VecSetBlockSize(coordinatesB, d);CHKERRQ(ierr);
140843eeeb2dSStefano Zampini   ierr = VecGetType(coordinatesA, &vtype);CHKERRQ(ierr);
140943eeeb2dSStefano Zampini   ierr = VecSetType(coordinatesB, vtype);CHKERRQ(ierr);
141007b0a1fcSMatthew G Knepley   ierr = VecGetArray(coordinatesA, &coordsA);CHKERRQ(ierr);
141107b0a1fcSMatthew G Knepley   ierr = VecGetArray(coordinatesB, &coordsB);CHKERRQ(ierr);
141207b0a1fcSMatthew G Knepley   for (v = 0; v < vEndB-vStartB; ++v) {
141343eeeb2dSStefano Zampini     PetscInt offA, offB;
141443eeeb2dSStefano Zampini 
141543eeeb2dSStefano Zampini     ierr = PetscSectionGetOffset(coordSectionA, v + vStartA, &offA);CHKERRQ(ierr);
141643eeeb2dSStefano Zampini     ierr = PetscSectionGetOffset(coordSectionB, v + vStartB, &offB);CHKERRQ(ierr);
141707b0a1fcSMatthew G Knepley     for (d = 0; d < spaceDim; ++d) {
141843eeeb2dSStefano Zampini       coordsB[offB+d] = coordsA[offA+d];
141943eeeb2dSStefano Zampini     }
142043eeeb2dSStefano Zampini   }
142143eeeb2dSStefano Zampini   if (lc) { /* localized coordinates */
142243eeeb2dSStefano Zampini     PetscInt c;
142343eeeb2dSStefano Zampini 
142443eeeb2dSStefano Zampini     for (c = cS-cStartB; c < cEndB-cStartB; c++) {
142543eeeb2dSStefano Zampini       PetscInt dof, offA, offB;
142643eeeb2dSStefano Zampini 
142743eeeb2dSStefano Zampini       ierr = PetscSectionGetOffset(coordSectionA, c + cStartA, &offA);CHKERRQ(ierr);
142843eeeb2dSStefano Zampini       ierr = PetscSectionGetOffset(coordSectionB, c + cStartB, &offB);CHKERRQ(ierr);
142943eeeb2dSStefano Zampini       ierr = PetscSectionGetDof(coordSectionA, c + cStartA, &dof);CHKERRQ(ierr);
1430580bdb30SBarry Smith       ierr = PetscArraycpy(coordsB + offB,coordsA + offA,dof);CHKERRQ(ierr);
143107b0a1fcSMatthew G Knepley     }
143207b0a1fcSMatthew G Knepley   }
143307b0a1fcSMatthew G Knepley   ierr = VecRestoreArray(coordinatesA, &coordsA);CHKERRQ(ierr);
143407b0a1fcSMatthew G Knepley   ierr = VecRestoreArray(coordinatesB, &coordsB);CHKERRQ(ierr);
143507b0a1fcSMatthew G Knepley   ierr = DMSetCoordinatesLocal(dmB, coordinatesB);CHKERRQ(ierr);
143607b0a1fcSMatthew G Knepley   ierr = VecDestroy(&coordinatesB);CHKERRQ(ierr);
143707b0a1fcSMatthew G Knepley   PetscFunctionReturn(0);
143807b0a1fcSMatthew G Knepley }
14395c386225SMatthew G. Knepley 
14404e3744c5SMatthew G. Knepley /*@
14414e3744c5SMatthew G. Knepley   DMPlexUninterpolate - Take in a mesh with all intermediate faces, edges, etc. and return a cell-vertex mesh
14424e3744c5SMatthew G. Knepley 
1443d083f849SBarry Smith   Collective on dm
14444e3744c5SMatthew G. Knepley 
14454e3744c5SMatthew G. Knepley   Input Parameter:
14464e3744c5SMatthew G. Knepley . dm - The complete DMPlex object
14474e3744c5SMatthew G. Knepley 
14484e3744c5SMatthew G. Knepley   Output Parameter:
14494e3744c5SMatthew G. Knepley . dmUnint - The DMPlex object with only cells and vertices
14504e3744c5SMatthew G. Knepley 
14514e3744c5SMatthew G. Knepley   Level: intermediate
14524e3744c5SMatthew G. Knepley 
145395452b02SPatrick Sanan   Notes:
145495452b02SPatrick Sanan     It does not copy over the coordinates.
145543eeeb2dSStefano Zampini 
145643eeeb2dSStefano Zampini .seealso: DMPlexInterpolate(), DMPlexCreateFromCellList(), DMPlexCopyCoordinates()
14574e3744c5SMatthew G. Knepley @*/
14584e3744c5SMatthew G. Knepley PetscErrorCode DMPlexUninterpolate(DM dm, DM *dmUnint)
14594e3744c5SMatthew G. Knepley {
1460827c4036SVaclav Hapla   DMPlexInterpolatedFlag interpolated;
14614e3744c5SMatthew G. Knepley   DM             udm;
1462c9f63434SStefano Zampini   PetscInt       dim, vStart, vEnd, cStart, cEnd, cMax, c, maxConeSize = 0, *cone;
14634e3744c5SMatthew G. Knepley   PetscErrorCode ierr;
14644e3744c5SMatthew G. Knepley 
14654e3744c5SMatthew G. Knepley   PetscFunctionBegin;
146643eeeb2dSStefano Zampini   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
146743eeeb2dSStefano Zampini   PetscValidPointer(dmUnint, 2);
1468c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1469827c4036SVaclav Hapla   ierr = DMPlexIsInterpolated(dm, &interpolated);CHKERRQ(ierr);
1470827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_PARTIAL) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes");
1471827c4036SVaclav Hapla   if (interpolated == DMPLEX_INTERPOLATED_NONE || dim <= 1) {
1472827c4036SVaclav Hapla     /* in case dim <= 1 just keep the DMPLEX_INTERPOLATED_FULL flag */
14734e3744c5SMatthew G. Knepley     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
1474595d4abbSMatthew G. Knepley     *dmUnint = dm;
1475595d4abbSMatthew G. Knepley     PetscFunctionReturn(0);
14764e3744c5SMatthew G. Knepley   }
1477595d4abbSMatthew G. Knepley   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1478595d4abbSMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1479c9f63434SStefano Zampini   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
14804e3744c5SMatthew G. Knepley   ierr = DMCreate(PetscObjectComm((PetscObject) dm), &udm);CHKERRQ(ierr);
14814e3744c5SMatthew G. Knepley   ierr = DMSetType(udm, DMPLEX);CHKERRQ(ierr);
1482c73cfb54SMatthew G. Knepley   ierr = DMSetDimension(udm, dim);CHKERRQ(ierr);
14834e3744c5SMatthew G. Knepley   ierr = DMPlexSetChart(udm, cStart, vEnd);CHKERRQ(ierr);
14844e3744c5SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1485595d4abbSMatthew G. Knepley     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
14864e3744c5SMatthew G. Knepley 
14874e3744c5SMatthew G. Knepley     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
14884e3744c5SMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
14894e3744c5SMatthew G. Knepley       const PetscInt p = closure[cl];
14904e3744c5SMatthew G. Knepley 
14914e3744c5SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) ++coneSize;
14924e3744c5SMatthew G. Knepley     }
14934e3744c5SMatthew G. Knepley     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
14944e3744c5SMatthew G. Knepley     ierr = DMPlexSetConeSize(udm, c, coneSize);CHKERRQ(ierr);
1495595d4abbSMatthew G. Knepley     maxConeSize = PetscMax(maxConeSize, coneSize);
14964e3744c5SMatthew G. Knepley   }
14974e3744c5SMatthew G. Knepley   ierr = DMSetUp(udm);CHKERRQ(ierr);
1498785e854fSJed Brown   ierr = PetscMalloc1(maxConeSize, &cone);CHKERRQ(ierr);
14994e3744c5SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1500595d4abbSMatthew G. Knepley     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;
15014e3744c5SMatthew G. Knepley 
15024e3744c5SMatthew G. Knepley     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
15034e3744c5SMatthew G. Knepley     for (cl = 0; cl < closureSize*2; cl += 2) {
15044e3744c5SMatthew G. Knepley       const PetscInt p = closure[cl];
15054e3744c5SMatthew G. Knepley 
15064e3744c5SMatthew G. Knepley       if ((p >= vStart) && (p < vEnd)) cone[coneSize++] = p;
15074e3744c5SMatthew G. Knepley     }
15084e3744c5SMatthew G. Knepley     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
15094e3744c5SMatthew G. Knepley     ierr = DMPlexSetCone(udm, c, cone);CHKERRQ(ierr);
15104e3744c5SMatthew G. Knepley   }
15114e3744c5SMatthew G. Knepley   ierr = PetscFree(cone);CHKERRQ(ierr);
1512c9f63434SStefano Zampini   ierr = DMPlexSetHybridBounds(udm, cMax, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
15134e3744c5SMatthew G. Knepley   ierr = DMPlexSymmetrize(udm);CHKERRQ(ierr);
15144e3744c5SMatthew G. Knepley   ierr = DMPlexStratify(udm);CHKERRQ(ierr);
15155c7de58aSMatthew G. Knepley   /* Reduce SF */
15165c7de58aSMatthew G. Knepley   {
15175c7de58aSMatthew G. Knepley     PetscSF            sfPoint, sfPointUn;
15185c7de58aSMatthew G. Knepley     const PetscSFNode *remotePoints;
15195c7de58aSMatthew G. Knepley     const PetscInt    *localPoints;
15205c7de58aSMatthew G. Knepley     PetscSFNode       *remotePointsUn;
15215c7de58aSMatthew G. Knepley     PetscInt          *localPointsUn;
15225c7de58aSMatthew G. Knepley     PetscInt           vEnd, numRoots, numLeaves, l;
15235c7de58aSMatthew G. Knepley     PetscInt           numLeavesUn = 0, n = 0;
15245c7de58aSMatthew G. Knepley     PetscErrorCode     ierr;
15255c7de58aSMatthew G. Knepley 
15265c7de58aSMatthew G. Knepley     /* Get original SF information */
15275c7de58aSMatthew G. Knepley     ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
15285c7de58aSMatthew G. Knepley     ierr = DMGetPointSF(udm, &sfPointUn);CHKERRQ(ierr);
15295c7de58aSMatthew G. Knepley     ierr = DMPlexGetDepthStratum(dm, 0, NULL, &vEnd);CHKERRQ(ierr);
15305c7de58aSMatthew G. Knepley     ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
15315c7de58aSMatthew G. Knepley     /* Allocate space for cells and vertices */
15325c7de58aSMatthew G. Knepley     for (l = 0; l < numLeaves; ++l) if (localPoints[l] < vEnd) numLeavesUn++;
15335c7de58aSMatthew G. Knepley     /* Fill in leaves */
15345c7de58aSMatthew G. Knepley     if (vEnd >= 0) {
15355c7de58aSMatthew G. Knepley       ierr = PetscMalloc1(numLeavesUn, &remotePointsUn);CHKERRQ(ierr);
15365c7de58aSMatthew G. Knepley       ierr = PetscMalloc1(numLeavesUn, &localPointsUn);CHKERRQ(ierr);
15375c7de58aSMatthew G. Knepley       for (l = 0; l < numLeaves; l++) {
15385c7de58aSMatthew G. Knepley         if (localPoints[l] < vEnd) {
15395c7de58aSMatthew G. Knepley           localPointsUn[n]        = localPoints[l];
15405c7de58aSMatthew G. Knepley           remotePointsUn[n].rank  = remotePoints[l].rank;
15415c7de58aSMatthew G. Knepley           remotePointsUn[n].index = remotePoints[l].index;
15425c7de58aSMatthew G. Knepley           ++n;
15435c7de58aSMatthew G. Knepley         }
15445c7de58aSMatthew G. Knepley       }
15455c7de58aSMatthew G. Knepley       if (n != numLeavesUn) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistent number of leaves %d != %d", n, numLeavesUn);
15465c7de58aSMatthew G. Knepley       ierr = PetscSFSetGraph(sfPointUn, vEnd, numLeavesUn, localPointsUn, PETSC_OWN_POINTER, remotePointsUn, PETSC_OWN_POINTER);CHKERRQ(ierr);
15475c7de58aSMatthew G. Knepley     }
15485c7de58aSMatthew G. Knepley   }
154943eeeb2dSStefano Zampini   {
155043eeeb2dSStefano Zampini     PetscBool            isper;
155143eeeb2dSStefano Zampini     const PetscReal      *maxCell, *L;
155243eeeb2dSStefano Zampini     const DMBoundaryType *bd;
155343eeeb2dSStefano Zampini 
155443eeeb2dSStefano Zampini     ierr = DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd);CHKERRQ(ierr);
155543eeeb2dSStefano Zampini     ierr = DMSetPeriodicity(udm,isper,maxCell,L,bd);CHKERRQ(ierr);
155643eeeb2dSStefano Zampini   }
1557827c4036SVaclav Hapla   /* This function makes the mesh fully uninterpolated on all ranks */
1558827c4036SVaclav Hapla   {
1559827c4036SVaclav Hapla     DM_Plex *plex = (DM_Plex *) dm->data;
1560827c4036SVaclav Hapla     plex->interpolated = plex->interpolatedCollective = DMPLEX_INTERPOLATED_NONE;
1561827c4036SVaclav Hapla   }
15624e3744c5SMatthew G. Knepley   *dmUnint = udm;
15634e3744c5SMatthew G. Knepley   PetscFunctionReturn(0);
15644e3744c5SMatthew G. Knepley }
1565a7748839SVaclav Hapla 
1566a7748839SVaclav Hapla static PetscErrorCode DMPlexIsInterpolated_Internal(DM dm, DMPlexInterpolatedFlag *interpolated)
1567a7748839SVaclav Hapla {
1568a7748839SVaclav Hapla   PetscInt       coneSize, depth, dim, h, p, pStart, pEnd;
1569a7748839SVaclav Hapla   MPI_Comm       comm;
1570a7748839SVaclav Hapla   PetscErrorCode ierr;
1571a7748839SVaclav Hapla 
1572a7748839SVaclav Hapla   PetscFunctionBegin;
1573a7748839SVaclav Hapla   ierr = PetscObjectGetComm((PetscObject)dm, &comm);CHKERRQ(ierr);
1574a7748839SVaclav Hapla   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1575a7748839SVaclav Hapla   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1576a7748839SVaclav Hapla 
1577a7748839SVaclav Hapla   if (depth == dim) {
1578a7748839SVaclav Hapla     *interpolated = DMPLEX_INTERPOLATED_FULL;
1579a7748839SVaclav Hapla     if (!dim) goto finish;
1580a7748839SVaclav Hapla 
1581a7748839SVaclav Hapla     /* Check points at height = dim are vertices (have no cones) */
1582a7748839SVaclav Hapla     ierr = DMPlexGetHeightStratum(dm, dim, &pStart, &pEnd);CHKERRQ(ierr);
1583a7748839SVaclav Hapla     for (p=pStart; p<pEnd; p++) {
1584a7748839SVaclav Hapla       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1585a7748839SVaclav Hapla       if (coneSize) {
1586a7748839SVaclav Hapla         *interpolated = DMPLEX_INTERPOLATED_PARTIAL;
1587a7748839SVaclav Hapla         goto finish;
1588a7748839SVaclav Hapla       }
1589a7748839SVaclav Hapla     }
1590a7748839SVaclav Hapla 
1591a7748839SVaclav Hapla     /* Check points at height < dim have cones */
1592a7748839SVaclav Hapla     for (h=0; h<dim; h++) {
1593a7748839SVaclav Hapla       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1594a7748839SVaclav Hapla       for (p=pStart; p<pEnd; p++) {
1595a7748839SVaclav Hapla         ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1596a7748839SVaclav Hapla         if (!coneSize) {
1597a7748839SVaclav Hapla           *interpolated = DMPLEX_INTERPOLATED_PARTIAL;
1598a7748839SVaclav Hapla           goto finish;
1599a7748839SVaclav Hapla         }
1600a7748839SVaclav Hapla       }
1601a7748839SVaclav Hapla     }
1602a7748839SVaclav Hapla   } else if (depth == 1) {
1603a7748839SVaclav Hapla     *interpolated = DMPLEX_INTERPOLATED_NONE;
1604a7748839SVaclav Hapla   } else {
1605a7748839SVaclav Hapla     *interpolated = DMPLEX_INTERPOLATED_PARTIAL;
1606a7748839SVaclav Hapla   }
1607a7748839SVaclav Hapla finish:
1608a7748839SVaclav Hapla   PetscFunctionReturn(0);
1609a7748839SVaclav Hapla }
1610a7748839SVaclav Hapla 
1611a7748839SVaclav Hapla /*@
1612a7748839SVaclav Hapla   DMPlexIsInterpolated - Find out whether this DM is interpolated, i.e. number of strata is equal to dimension.
1613a7748839SVaclav Hapla 
1614a7748839SVaclav Hapla   Not Collective
1615a7748839SVaclav Hapla 
1616a7748839SVaclav Hapla   Input Parameter:
1617a7748839SVaclav Hapla . dm      - The DM object
1618a7748839SVaclav Hapla 
1619a7748839SVaclav Hapla   Output Parameter:
1620a7748839SVaclav Hapla . interpolated - Flag whether the DM is interpolated
1621a7748839SVaclav Hapla 
1622a7748839SVaclav Hapla   Level: intermediate
1623a7748839SVaclav Hapla 
1624a7748839SVaclav Hapla   Notes:
1625a7748839SVaclav Hapla   This is NOT collective so the results can be different on different ranks in special cases.
1626a7748839SVaclav Hapla   However, DMPlexInterpolate() guarantees the result is the same on all.
1627a7748839SVaclav Hapla   Unlike DMPlexIsInterpolatedCollective(), this cannot return DMPLEX_INTERPOLATED_MIXED.
1628a7748839SVaclav Hapla 
1629a7748839SVaclav Hapla .seealso: DMPlexInterpolate(), DMPlexIsInterpolatedCollective()
1630a7748839SVaclav Hapla @*/
1631a7748839SVaclav Hapla PetscErrorCode DMPlexIsInterpolated(DM dm, DMPlexInterpolatedFlag *interpolated)
1632a7748839SVaclav Hapla {
1633a7748839SVaclav Hapla   DM_Plex        *plex = (DM_Plex *) dm->data;
1634a7748839SVaclav Hapla   PetscErrorCode  ierr;
1635a7748839SVaclav Hapla 
1636a7748839SVaclav Hapla   PetscFunctionBegin;
1637a7748839SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1638a7748839SVaclav Hapla   PetscValidPointer(interpolated,2);
1639a7748839SVaclav Hapla   if (plex->interpolated < 0) {
1640a7748839SVaclav Hapla     ierr = DMPlexIsInterpolated_Internal(dm, &plex->interpolated);CHKERRQ(ierr);
1641a7748839SVaclav Hapla   } else {
1642a7748839SVaclav Hapla #if defined (PETSC_USE_DEBUG)
1643a7748839SVaclav Hapla     DMPlexInterpolatedFlag flg;
1644a7748839SVaclav Hapla 
1645a7748839SVaclav Hapla     ierr = DMPlexIsInterpolated_Internal(dm, &flg);CHKERRQ(ierr);
1646a7748839SVaclav Hapla     if (flg != plex->interpolated) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "stashed DMPlexInterpolatedFlag is inconsistent");
1647a7748839SVaclav Hapla #endif
1648a7748839SVaclav Hapla   }
1649a7748839SVaclav Hapla   *interpolated = plex->interpolated;
1650a7748839SVaclav Hapla   PetscFunctionReturn(0);
1651a7748839SVaclav Hapla }
1652a7748839SVaclav Hapla 
1653a7748839SVaclav Hapla /*@
1654a7748839SVaclav Hapla   DMPlexIsInterpolatedCollective - Find out whether this DM is interpolated, i.e. number of strata is equal to dimension.
1655a7748839SVaclav Hapla 
16562666ff3cSVaclav Hapla   Collective
1657a7748839SVaclav Hapla 
1658a7748839SVaclav Hapla   Input Parameter:
1659a7748839SVaclav Hapla . dm      - The DM object
1660a7748839SVaclav Hapla 
1661a7748839SVaclav Hapla   Output Parameter:
1662a7748839SVaclav Hapla . interpolated - Flag whether the DM is interpolated
1663a7748839SVaclav Hapla 
1664a7748839SVaclav Hapla   Level: intermediate
1665a7748839SVaclav Hapla 
1666a7748839SVaclav Hapla   Notes:
1667a7748839SVaclav Hapla   This is collective so the results are always guaranteed to be the same on all ranks.
1668a7748839SVaclav Hapla   Unlike DMPlexIsInterpolated(), this will return DMPLEX_INTERPOLATED_MIXED if the results of DMPlexIsInterpolated() are different on different ranks.
1669a7748839SVaclav Hapla 
1670a7748839SVaclav Hapla .seealso: DMPlexInterpolate(), DMPlexIsInterpolated()
1671a7748839SVaclav Hapla @*/
1672a7748839SVaclav Hapla PetscErrorCode DMPlexIsInterpolatedCollective(DM dm, DMPlexInterpolatedFlag *interpolated)
1673a7748839SVaclav Hapla {
1674a7748839SVaclav Hapla   DM_Plex        *plex = (DM_Plex *) dm->data;
1675a7748839SVaclav Hapla   PetscBool       debug=PETSC_FALSE;
1676a7748839SVaclav Hapla   PetscErrorCode  ierr;
1677a7748839SVaclav Hapla 
1678a7748839SVaclav Hapla   PetscFunctionBegin;
1679a7748839SVaclav Hapla   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1680a7748839SVaclav Hapla   PetscValidPointer(interpolated,2);
1681a7748839SVaclav Hapla   ierr = PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_is_interpolated_collective_debug", &debug, NULL);CHKERRQ(ierr);
1682a7748839SVaclav Hapla   if (plex->interpolatedCollective < 0) {
1683a7748839SVaclav Hapla     DMPlexInterpolatedFlag  min, max;
1684a7748839SVaclav Hapla     MPI_Comm                comm;
1685a7748839SVaclav Hapla 
1686a7748839SVaclav Hapla     ierr = PetscObjectGetComm((PetscObject)dm, &comm);CHKERRQ(ierr);
1687a7748839SVaclav Hapla     ierr = DMPlexIsInterpolated(dm, &plex->interpolatedCollective);CHKERRQ(ierr);
1688a7748839SVaclav Hapla     ierr = MPI_Allreduce(&plex->interpolatedCollective, &min, 1, MPIU_ENUM, MPI_MIN, comm);CHKERRQ(ierr);
1689a7748839SVaclav Hapla     ierr = MPI_Allreduce(&plex->interpolatedCollective, &max, 1, MPIU_ENUM, MPI_MAX, comm);CHKERRQ(ierr);
1690a7748839SVaclav Hapla     if (min != max) plex->interpolatedCollective = DMPLEX_INTERPOLATED_MIXED;
1691a7748839SVaclav Hapla     if (debug) {
1692a7748839SVaclav Hapla       PetscMPIInt rank;
1693a7748839SVaclav Hapla 
1694a7748839SVaclav Hapla       ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1695a7748839SVaclav Hapla       ierr = PetscSynchronizedPrintf(comm, "[%d] interpolated=%s interpolatedCollective=%s\n", rank, DMPlexInterpolatedFlags[plex->interpolated], DMPlexInterpolatedFlags[plex->interpolatedCollective]);CHKERRQ(ierr);
1696a7748839SVaclav Hapla       ierr = PetscSynchronizedFlush(comm, PETSC_STDOUT);CHKERRQ(ierr);
1697a7748839SVaclav Hapla     }
1698a7748839SVaclav Hapla   }
1699a7748839SVaclav Hapla   *interpolated = plex->interpolatedCollective;
1700a7748839SVaclav Hapla   PetscFunctionReturn(0);
1701a7748839SVaclav Hapla }
1702