xref: /petsc/src/ksp/pc/impls/bddc/bddcgraph.c (revision 1690c2ae071c7584458d4e437df7b47bc4686b3c)
1af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
25e5bbd0aSStefano Zampini #include <petsc/private/pcbddcprivateimpl.h>
35e5bbd0aSStefano Zampini #include <petsc/private/pcbddcstructsimpl.h>
49de2952eSStefano Zampini #include <petsc/private/hashmapi.h>
59de2952eSStefano Zampini #include <petscsf.h>
6674ae819SStefano Zampini 
7d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCDestroyGraphCandidatesIS(void *ctx)
8d71ae5a4SJacob Faibussowitsch {
932fe681dSStefano Zampini   PCBDDCGraphCandidates cand = (PCBDDCGraphCandidates)ctx;
1032fe681dSStefano Zampini 
1132fe681dSStefano Zampini   PetscFunctionBegin;
1232fe681dSStefano Zampini   for (PetscInt i = 0; i < cand->nfc; i++) PetscCall(ISDestroy(&cand->Faces[i]));
1332fe681dSStefano Zampini   for (PetscInt i = 0; i < cand->nec; i++) PetscCall(ISDestroy(&cand->Edges[i]));
1432fe681dSStefano Zampini   PetscCall(PetscFree(cand->Faces));
1532fe681dSStefano Zampini   PetscCall(PetscFree(cand->Edges));
1632fe681dSStefano Zampini   PetscCall(ISDestroy(&cand->Vertices));
1732fe681dSStefano Zampini   PetscCall(PetscFree(cand));
183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1932fe681dSStefano Zampini }
2032fe681dSStefano Zampini 
21d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphGetDirichletDofsB(PCBDDCGraph graph, IS *dirdofs)
22d71ae5a4SJacob Faibussowitsch {
23d62866d3SStefano Zampini   PetscFunctionBegin;
24d62866d3SStefano Zampini   if (graph->dirdofsB) {
259566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofsB));
26d62866d3SStefano Zampini   } else if (graph->has_dirichlet) {
27d62866d3SStefano Zampini     PetscInt  i, size;
28d62866d3SStefano Zampini     PetscInt *dirdofs_idxs;
29d62866d3SStefano Zampini 
30d62866d3SStefano Zampini     size = 0;
31d62866d3SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
329de2952eSStefano Zampini       if (graph->nodes[i].count > 1 && graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) size++;
33d62866d3SStefano Zampini     }
34d62866d3SStefano Zampini 
359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &dirdofs_idxs));
36d62866d3SStefano Zampini     size = 0;
37d62866d3SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
389de2952eSStefano Zampini       if (graph->nodes[i].count > 1 && graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) dirdofs_idxs[size++] = i;
39d62866d3SStefano Zampini     }
409566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, dirdofs_idxs, PETSC_OWN_POINTER, &graph->dirdofsB));
419566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofsB));
42d62866d3SStefano Zampini   }
43d62866d3SStefano Zampini   *dirdofs = graph->dirdofsB;
443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
45d62866d3SStefano Zampini }
46d62866d3SStefano Zampini 
47d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphGetDirichletDofs(PCBDDCGraph graph, IS *dirdofs)
48d71ae5a4SJacob Faibussowitsch {
491b968477SStefano Zampini   PetscFunctionBegin;
50a07ea27aSStefano Zampini   if (graph->dirdofs) {
519566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofs));
52a07ea27aSStefano Zampini   } else if (graph->has_dirichlet) {
53a07ea27aSStefano Zampini     PetscInt  i, size;
54a07ea27aSStefano Zampini     PetscInt *dirdofs_idxs;
55a07ea27aSStefano Zampini 
561b968477SStefano Zampini     size = 0;
571b968477SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
589de2952eSStefano Zampini       if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) size++;
591b968477SStefano Zampini     }
601b968477SStefano Zampini 
619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &dirdofs_idxs));
621b968477SStefano Zampini     size = 0;
631b968477SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
649de2952eSStefano Zampini       if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) dirdofs_idxs[size++] = i;
651b968477SStefano Zampini     }
669566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)graph->l2gmap), size, dirdofs_idxs, PETSC_OWN_POINTER, &graph->dirdofs));
679566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofs));
681b968477SStefano Zampini   }
69a07ea27aSStefano Zampini   *dirdofs = graph->dirdofs;
703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
711b968477SStefano Zampini }
721b968477SStefano Zampini 
73d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphASCIIView(PCBDDCGraph graph, PetscInt verbosity_level, PetscViewer viewer)
74d71ae5a4SJacob Faibussowitsch {
752b510759SStefano Zampini   PetscInt  i, j, tabs;
7693fb5fd3SStefano Zampini   PetscInt *queue_in_global_numbering;
77674ae819SStefano Zampini 
78674ae819SStefano Zampini   PetscFunctionBegin;
7994d400adSStefano Zampini   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(graph->seq_graph ? PETSC_COMM_SELF : PetscObjectComm((PetscObject)graph->l2gmap), &viewer));
809566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
819566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
829566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "--------------------------------------------------\n"));
839566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
849de2952eSStefano Zampini   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Local BDDC graph for subdomain %04d (seq %d)\n", PetscGlobalRank, graph->seq_graph));
8563a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of vertices %" PetscInt_FMT "\n", graph->nvtxs));
8663a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of local subdomains %" PetscInt_FMT "\n", graph->n_local_subs ? graph->n_local_subs : 1));
8763a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Custom minimal size %" PetscInt_FMT "\n", graph->custom_minimal_size));
88*1690c2aeSBarry Smith   if (graph->maxcount != PETSC_INT_MAX) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Max count %" PetscInt_FMT "\n", graph->maxcount));
8963a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Topological two dim? %s (set %s)\n", PetscBools[graph->twodim], PetscBools[graph->twodimset]));
90d4890cceSStefano Zampini   if (verbosity_level > 2) {
91674ae819SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
9263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":\n", i));
939de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   which_dof: %" PetscInt_FMT "\n", graph->nodes[i].which_dof));
949de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   special_dof: %" PetscInt_FMT "\n", graph->nodes[i].special_dof));
959de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   shared by: %" PetscInt_FMT "\n", graph->nodes[i].count));
969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
979de2952eSStefano Zampini       if (graph->nodes[i].count) {
989566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     set of neighbours:"));
999de2952eSStefano Zampini         for (j = 0; j < graph->nodes[i].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].neighbours_set[j]));
1009566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
101674ae819SStefano Zampini       }
1029566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1039566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1049de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   number of local groups: %" PetscInt_FMT "\n", graph->nodes[i].local_groups_count));
1059566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1069de2952eSStefano Zampini       if (graph->nodes[i].local_groups_count) {
1079de2952eSStefano Zampini         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     groups:"));
1089de2952eSStefano Zampini         for (j = 0; j < graph->nodes[i].local_groups_count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].local_groups[j]));
1099566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1109de2952eSStefano Zampini       }
1119566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1129566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1139de2952eSStefano Zampini 
114d4890cceSStefano Zampini       if (verbosity_level > 3) {
1151633d1f0SStefano Zampini         if (graph->xadj) {
1169566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   local adj list:"));
1179566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
11848a46eb9SPierre Jolivet           for (j = graph->xadj[i]; j < graph->xadj[i + 1]; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->adjncy[j]));
1199566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1209566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1219566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
122ec1c413dSStefano Zampini         } else {
1239566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   no adj info\n"));
124674ae819SStefano Zampini         }
125e49050b4SStefano Zampini       }
12648a46eb9SPierre Jolivet       if (graph->n_local_subs) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   local sub id: %" PetscInt_FMT "\n", graph->local_subs[i]));
1279de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   interface subset id: %" PetscInt_FMT "\n", graph->nodes[i].subset));
1289de2952eSStefano Zampini       if (graph->nodes[i].subset && graph->subset_ncc) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   ncc for subset: %" PetscInt_FMT "\n", graph->subset_ncc[graph->nodes[i].subset - 1]));
129674ae819SStefano Zampini     }
130e49050b4SStefano Zampini   }
13163a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Total number of connected components %" PetscInt_FMT "\n", graph->ncc));
1329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_in_global_numbering));
1339566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_in_global_numbering));
134674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
1351ce3d396SStefano Zampini     PetscInt  node_num = graph->queue[graph->cptr[i]];
1361ce3d396SStefano Zampini     PetscBool printcc  = PETSC_FALSE;
1379de2952eSStefano Zampini     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  cc %" PetscInt_FMT " (size %" PetscInt_FMT ", fid %" PetscInt_FMT ", neighs:", i, graph->cptr[i + 1] - graph->cptr[i], graph->nodes[node_num].which_dof));
1389566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1399de2952eSStefano Zampini     for (j = 0; j < graph->nodes[node_num].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[node_num].neighbours_set[j]));
140d4890cceSStefano Zampini     if (verbosity_level > 1) {
1419566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "):"));
1429de2952eSStefano Zampini       if (verbosity_level > 2 || graph->twodim || graph->nodes[node_num].count > 2 || (graph->nodes[node_num].count == 2 && graph->nodes[node_num].special_dof == PCBDDCGRAPH_NEUMANN_MARK)) { printcc = PETSC_TRUE; }
1431ce3d396SStefano Zampini       if (printcc) {
14448a46eb9SPierre Jolivet         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT " (%" PetscInt_FMT ")", graph->queue[j], queue_in_global_numbering[j]));
1451ce3d396SStefano Zampini       }
146d4890cceSStefano Zampini     } else {
1479566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ")"));
148d4890cceSStefano Zampini     }
1499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1519566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
152674ae819SStefano Zampini   }
1539566063dSJacob Faibussowitsch   PetscCall(PetscFree(queue_in_global_numbering));
1549566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
1553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
156674ae819SStefano Zampini }
157674ae819SStefano Zampini 
158d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphRestoreCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS)
159d71ae5a4SJacob Faibussowitsch {
160c8272957SStefano Zampini   PetscInt       i;
16132fe681dSStefano Zampini   PetscContainer gcand;
162c8272957SStefano Zampini 
163c8272957SStefano Zampini   PetscFunctionBegin;
16432fe681dSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand));
16532fe681dSStefano Zampini   if (gcand) {
16632fe681dSStefano Zampini     if (n_faces) *n_faces = 0;
16732fe681dSStefano Zampini     if (n_edges) *n_edges = 0;
16832fe681dSStefano Zampini     if (FacesIS) *FacesIS = NULL;
16932fe681dSStefano Zampini     if (EdgesIS) *EdgesIS = NULL;
17032fe681dSStefano Zampini     if (VerticesIS) *VerticesIS = NULL;
17132fe681dSStefano Zampini   }
172c8272957SStefano Zampini   if (n_faces) {
173c8272957SStefano Zampini     if (FacesIS) {
17448a46eb9SPierre Jolivet       for (i = 0; i < *n_faces; i++) PetscCall(ISDestroy(&((*FacesIS)[i])));
1759566063dSJacob Faibussowitsch       PetscCall(PetscFree(*FacesIS));
176c8272957SStefano Zampini     }
177c8272957SStefano Zampini     *n_faces = 0;
178c8272957SStefano Zampini   }
179c8272957SStefano Zampini   if (n_edges) {
180c8272957SStefano Zampini     if (EdgesIS) {
18148a46eb9SPierre Jolivet       for (i = 0; i < *n_edges; i++) PetscCall(ISDestroy(&((*EdgesIS)[i])));
1829566063dSJacob Faibussowitsch       PetscCall(PetscFree(*EdgesIS));
183c8272957SStefano Zampini     }
184c8272957SStefano Zampini     *n_edges = 0;
185c8272957SStefano Zampini   }
1861baa6e33SBarry Smith   if (VerticesIS) PetscCall(ISDestroy(VerticesIS));
1873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
188c8272957SStefano Zampini }
189c8272957SStefano Zampini 
190d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphGetCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS)
191d71ae5a4SJacob Faibussowitsch {
192674ae819SStefano Zampini   IS            *ISForFaces, *ISForEdges, ISForVertices;
193be12c134Sstefano_zampini   PetscInt       i, nfc, nec, nvc, *idx, *mark;
19432fe681dSStefano Zampini   PetscContainer gcand;
195674ae819SStefano Zampini 
196674ae819SStefano Zampini   PetscFunctionBegin;
19732fe681dSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand));
19832fe681dSStefano Zampini   if (gcand) {
19932fe681dSStefano Zampini     PCBDDCGraphCandidates cand;
20032fe681dSStefano Zampini 
20132fe681dSStefano Zampini     PetscCall(PetscContainerGetPointer(gcand, (void **)&cand));
20232fe681dSStefano Zampini     if (n_faces) *n_faces = cand->nfc;
20332fe681dSStefano Zampini     if (FacesIS) *FacesIS = cand->Faces;
20432fe681dSStefano Zampini     if (n_edges) *n_edges = cand->nec;
20532fe681dSStefano Zampini     if (EdgesIS) *EdgesIS = cand->Edges;
20632fe681dSStefano Zampini     if (VerticesIS) *VerticesIS = cand->Vertices;
2073ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20832fe681dSStefano Zampini   }
2099566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(graph->ncc, &mark));
210da81f932SPierre Jolivet   /* loop on ccs to evaluate number of faces, edges and vertices */
211674ae819SStefano Zampini   nfc = 0;
212674ae819SStefano Zampini   nec = 0;
213674ae819SStefano Zampini   nvc = 0;
214674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
2151e1f2d93SStefano Zampini     PetscInt repdof = graph->queue[graph->cptr[i]];
2169de2952eSStefano Zampini     if (graph->cptr[i + 1] - graph->cptr[i] > graph->custom_minimal_size && graph->nodes[repdof].count <= graph->maxcount) {
2179de2952eSStefano Zampini       if (!graph->twodim && graph->nodes[repdof].count == 2 && graph->nodes[repdof].special_dof != PCBDDCGRAPH_NEUMANN_MARK) {
218674ae819SStefano Zampini         nfc++;
219be12c134Sstefano_zampini         mark[i] = 2;
220be12c134Sstefano_zampini       } else {
221674ae819SStefano Zampini         nec++;
222be12c134Sstefano_zampini         mark[i] = 1;
223674ae819SStefano Zampini       }
224674ae819SStefano Zampini     } else {
225674ae819SStefano Zampini       nvc += graph->cptr[i + 1] - graph->cptr[i];
226674ae819SStefano Zampini     }
227674ae819SStefano Zampini   }
228adfc4fb2SStefano Zampini 
229674ae819SStefano Zampini   /* allocate IS arrays for faces, edges. Vertices need a single index set. */
23048a46eb9SPierre Jolivet   if (FacesIS) PetscCall(PetscMalloc1(nfc, &ISForFaces));
23148a46eb9SPierre Jolivet   if (EdgesIS) PetscCall(PetscMalloc1(nec, &ISForEdges));
23248a46eb9SPierre Jolivet   if (VerticesIS) PetscCall(PetscMalloc1(nvc, &idx));
233cf5a6209SStefano Zampini 
234674ae819SStefano Zampini   /* loop on ccs to compute index sets for faces and edges */
235acc113dbSStefano Zampini   if (!graph->queue_sorted) {
236acc113dbSStefano Zampini     PetscInt *queue_global;
237acc113dbSStefano Zampini 
2389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global));
2399566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global));
24048a46eb9SPierre Jolivet     for (i = 0; i < graph->ncc; i++) PetscCall(PetscSortIntWithArray(graph->cptr[i + 1] - graph->cptr[i], &queue_global[graph->cptr[i]], &graph->queue[graph->cptr[i]]));
2419566063dSJacob Faibussowitsch     PetscCall(PetscFree(queue_global));
242acc113dbSStefano Zampini     graph->queue_sorted = PETSC_TRUE;
243acc113dbSStefano Zampini   }
244674ae819SStefano Zampini   nfc = 0;
245674ae819SStefano Zampini   nec = 0;
246674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
247be12c134Sstefano_zampini     if (mark[i] == 2) {
24848a46eb9SPierre Jolivet       if (FacesIS) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, graph->cptr[i + 1] - graph->cptr[i], &graph->queue[graph->cptr[i]], PETSC_USE_POINTER, &ISForFaces[nfc]));
249674ae819SStefano Zampini       nfc++;
250be12c134Sstefano_zampini     } else if (mark[i] == 1) {
25148a46eb9SPierre Jolivet       if (EdgesIS) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, graph->cptr[i + 1] - graph->cptr[i], &graph->queue[graph->cptr[i]], PETSC_USE_POINTER, &ISForEdges[nec]));
252674ae819SStefano Zampini       nec++;
253674ae819SStefano Zampini     }
254674ae819SStefano Zampini   }
255be12c134Sstefano_zampini 
256674ae819SStefano Zampini   /* index set for vertices */
257cf5a6209SStefano Zampini   if (VerticesIS) {
258b8ffe317SStefano Zampini     nvc = 0;
259674ae819SStefano Zampini     for (i = 0; i < graph->ncc; i++) {
260be12c134Sstefano_zampini       if (!mark[i]) {
261adfc4fb2SStefano Zampini         PetscInt j;
262adfc4fb2SStefano Zampini 
263674ae819SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
264674ae819SStefano Zampini           idx[nvc] = graph->queue[j];
265674ae819SStefano Zampini           nvc++;
266674ae819SStefano Zampini         }
267674ae819SStefano Zampini       }
268674ae819SStefano Zampini     }
269674ae819SStefano Zampini     /* sort vertex set (by local ordering) */
2709566063dSJacob Faibussowitsch     PetscCall(PetscSortInt(nvc, idx));
2719566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nvc, idx, PETSC_OWN_POINTER, &ISForVertices));
272674ae819SStefano Zampini   }
2739566063dSJacob Faibussowitsch   PetscCall(PetscFree(mark));
274be12c134Sstefano_zampini 
275674ae819SStefano Zampini   /* get back info */
276a873d5d0SStefano Zampini   if (n_faces) *n_faces = nfc;
277c8272957SStefano Zampini   if (FacesIS) *FacesIS = ISForFaces;
278a873d5d0SStefano Zampini   if (n_edges) *n_edges = nec;
279c8272957SStefano Zampini   if (EdgesIS) *EdgesIS = ISForEdges;
280c8272957SStefano Zampini   if (VerticesIS) *VerticesIS = ISForVertices;
2813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
282674ae819SStefano Zampini }
283674ae819SStefano Zampini 
284d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphComputeConnectedComponents(PCBDDCGraph graph)
285d71ae5a4SJacob Faibussowitsch {
2869de2952eSStefano Zampini   PetscBool adapt_interface;
287674ae819SStefano Zampini   MPI_Comm  interface_comm;
2889de2952eSStefano Zampini   PetscBT   cornerp = NULL;
289674ae819SStefano Zampini 
290674ae819SStefano Zampini   PetscFunctionBegin;
291f4f49eeaSPierre Jolivet   PetscCall(PetscObjectGetComm((PetscObject)graph->l2gmap, &interface_comm));
2929de2952eSStefano Zampini   /* compute connected components locally */
2939566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponentsLocal(graph));
2949de2952eSStefano Zampini   if (graph->seq_graph) PetscFunctionReturn(PETSC_SUCCESS);
2951c7a958bSStefano Zampini 
2969de2952eSStefano Zampini   if (graph->active_coords && !graph->multi_element) { /* face based corner selection XXX multi_element */
2974f819b78SStefano Zampini     PetscBT    excluded;
2981c7a958bSStefano Zampini     PetscReal *wdist;
2991c7a958bSStefano Zampini     PetscInt   n_neigh, *neigh, *n_shared, **shared;
3001c7a958bSStefano Zampini     PetscInt   maxc, ns;
3011c7a958bSStefano Zampini 
3029566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(graph->nvtxs, &cornerp));
3039566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
3041c7a958bSStefano Zampini     for (ns = 1, maxc = 0; ns < n_neigh; ns++) maxc = PetscMax(maxc, n_shared[ns]);
3059566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxc * graph->cdim, &wdist));
3069566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(maxc, &excluded));
3071c7a958bSStefano Zampini 
3081c7a958bSStefano Zampini     for (ns = 1; ns < n_neigh; ns++) { /* first proc is self */
3091c7a958bSStefano Zampini       PetscReal *anchor, mdist;
3104f819b78SStefano Zampini       PetscInt   fst, j, k, d, cdim = graph->cdim, n = n_shared[ns];
31151ab8ad6SStefano Zampini       PetscInt   point1, point2, point3, point4;
3121c7a958bSStefano Zampini 
3131c7a958bSStefano Zampini       /* import coordinates on shared interface */
3149566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(n, excluded));
3154f819b78SStefano Zampini       for (j = 0, fst = -1, k = 0; j < n; j++) {
3164f819b78SStefano Zampini         PetscBool skip = PETSC_FALSE;
3174f819b78SStefano Zampini         for (d = 0; d < cdim; d++) {
3184f819b78SStefano Zampini           PetscReal c = graph->coords[shared[ns][j] * cdim + d];
3194f819b78SStefano Zampini           skip        = (PetscBool)(skip || c == PETSC_MAX_REAL);
3204f819b78SStefano Zampini           wdist[k++]  = c;
3214f819b78SStefano Zampini         }
3224f819b78SStefano Zampini         if (skip) {
3239566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(excluded, j));
3244f819b78SStefano Zampini         } else if (fst == -1) fst = j;
3254f819b78SStefano Zampini       }
3264f819b78SStefano Zampini       if (fst == -1) continue;
3271c7a958bSStefano Zampini 
32851ab8ad6SStefano Zampini       /* the dofs are sorted by global numbering, so each rank starts from the same id
32951ab8ad6SStefano Zampini          and it will detect the same corners from the given set */
3301c7a958bSStefano Zampini 
3311c7a958bSStefano Zampini       /* find the farthest point from the starting one */
33251ab8ad6SStefano Zampini       anchor = wdist + fst * cdim;
3331c7a958bSStefano Zampini       mdist  = -1.0;
3344f819b78SStefano Zampini       point1 = fst;
3354f819b78SStefano Zampini       for (j = fst; j < n; j++) {
3361c7a958bSStefano Zampini         PetscReal dist = 0.0;
3371c7a958bSStefano Zampini 
3384f819b78SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
3391c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]);
3409371c9d4SSatish Balay         if (dist > mdist) {
3419371c9d4SSatish Balay           mdist  = dist;
3429371c9d4SSatish Balay           point1 = j;
3439371c9d4SSatish Balay         }
3441c7a958bSStefano Zampini       }
3451c7a958bSStefano Zampini 
3461c7a958bSStefano Zampini       /* find the farthest point from point1 */
3471c7a958bSStefano Zampini       anchor = wdist + point1 * cdim;
3481c7a958bSStefano Zampini       mdist  = -1.0;
3494f819b78SStefano Zampini       point2 = point1;
3504f819b78SStefano Zampini       for (j = fst; j < n; j++) {
3511c7a958bSStefano Zampini         PetscReal dist = 0.0;
3521c7a958bSStefano Zampini 
3534f819b78SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
3541c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]);
3559371c9d4SSatish Balay         if (dist > mdist) {
3569371c9d4SSatish Balay           mdist  = dist;
3579371c9d4SSatish Balay           point2 = j;
3589371c9d4SSatish Balay         }
3591c7a958bSStefano Zampini       }
3601c7a958bSStefano Zampini 
3611c7a958bSStefano Zampini       /* find the third point maximizing the triangle area */
3621c7a958bSStefano Zampini       point3 = point2;
3631c7a958bSStefano Zampini       if (cdim > 2) {
3641c7a958bSStefano Zampini         PetscReal a = 0.0;
3651c7a958bSStefano Zampini 
3661c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) a += (wdist[point1 * cdim + d] - wdist[point2 * cdim + d]) * (wdist[point1 * cdim + d] - wdist[point2 * cdim + d]);
367fff73eb4SStefano Zampini         a     = PetscSqrtReal(a);
3681c7a958bSStefano Zampini         mdist = -1.0;
3694f819b78SStefano Zampini         for (j = fst; j < n; j++) {
370fff73eb4SStefano Zampini           PetscReal area, b = 0.0, c = 0.0, s;
3711c7a958bSStefano Zampini 
3724f819b78SStefano Zampini           if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
3731c7a958bSStefano Zampini           for (d = 0; d < cdim; d++) {
3741c7a958bSStefano Zampini             b += (wdist[point1 * cdim + d] - wdist[j * cdim + d]) * (wdist[point1 * cdim + d] - wdist[j * cdim + d]);
3751c7a958bSStefano Zampini             c += (wdist[point2 * cdim + d] - wdist[j * cdim + d]) * (wdist[point2 * cdim + d] - wdist[j * cdim + d]);
3761c7a958bSStefano Zampini           }
377fff73eb4SStefano Zampini           b = PetscSqrtReal(b);
378fff73eb4SStefano Zampini           c = PetscSqrtReal(c);
379fff73eb4SStefano Zampini           s = 0.5 * (a + b + c);
3804f819b78SStefano Zampini 
3814f819b78SStefano Zampini           /* Heron's formula, area squared */
3824f819b78SStefano Zampini           area = s * (s - a) * (s - b) * (s - c);
3839371c9d4SSatish Balay           if (area > mdist) {
3849371c9d4SSatish Balay             mdist  = area;
3859371c9d4SSatish Balay             point3 = j;
3869371c9d4SSatish Balay           }
3871c7a958bSStefano Zampini         }
3881c7a958bSStefano Zampini       }
3891c7a958bSStefano Zampini 
39051ab8ad6SStefano Zampini       /* find the farthest point from point3 different from point1 and point2 */
39151ab8ad6SStefano Zampini       anchor = wdist + point3 * cdim;
39251ab8ad6SStefano Zampini       mdist  = -1.0;
39351ab8ad6SStefano Zampini       point4 = point3;
39451ab8ad6SStefano Zampini       for (j = fst; j < n; j++) {
39551ab8ad6SStefano Zampini         PetscReal dist = 0.0;
39651ab8ad6SStefano Zampini 
39751ab8ad6SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j)) || j == point1 || j == point2 || j == point3) continue;
39851ab8ad6SStefano Zampini         for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]);
3999371c9d4SSatish Balay         if (dist > mdist) {
4009371c9d4SSatish Balay           mdist  = dist;
4019371c9d4SSatish Balay           point4 = j;
4029371c9d4SSatish Balay         }
40351ab8ad6SStefano Zampini       }
40451ab8ad6SStefano Zampini 
4059566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(cornerp, shared[ns][point1]));
4069566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(cornerp, shared[ns][point2]));
4079566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(cornerp, shared[ns][point3]));
40851ab8ad6SStefano Zampini       PetscCall(PetscBTSet(cornerp, shared[ns][point4]));
4094f819b78SStefano Zampini 
4101c7a958bSStefano Zampini       /* all dofs having the same coordinates will be primal */
4114f819b78SStefano Zampini       for (j = fst; j < n; j++) {
41251ab8ad6SStefano Zampini         PetscBool same[] = {PETSC_TRUE, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE};
4131c7a958bSStefano Zampini 
4144f819b78SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
4151c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) {
4161c7a958bSStefano Zampini           same[0] = (PetscBool)(same[0] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point1 * cdim + d]) < PETSC_SMALL));
4171c7a958bSStefano Zampini           same[1] = (PetscBool)(same[1] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point2 * cdim + d]) < PETSC_SMALL));
4181c7a958bSStefano Zampini           same[2] = (PetscBool)(same[2] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point3 * cdim + d]) < PETSC_SMALL));
41951ab8ad6SStefano Zampini           same[3] = (PetscBool)(same[3] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point4 * cdim + d]) < PETSC_SMALL));
4201c7a958bSStefano Zampini         }
42148a46eb9SPierre Jolivet         if (same[0] || same[1] || same[2] || same[3]) PetscCall(PetscBTSet(cornerp, shared[ns][j]));
4221c7a958bSStefano Zampini       }
4231c7a958bSStefano Zampini     }
4249566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&excluded));
4259566063dSJacob Faibussowitsch     PetscCall(PetscFree(wdist));
4269566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
4271c7a958bSStefano Zampini   }
4281c7a958bSStefano Zampini 
4299de2952eSStefano Zampini   /* Adapt connected components if needed */
4309de2952eSStefano Zampini   adapt_interface = (cornerp || graph->multi_element) ? PETSC_TRUE : PETSC_FALSE;
4319de2952eSStefano Zampini   for (PetscInt i = 0; i < graph->n_subsets && !adapt_interface; i++) {
4321c7a958bSStefano Zampini     if (graph->subset_ncc[i] > 1) adapt_interface = PETSC_TRUE;
433674ae819SStefano Zampini   }
4349de2952eSStefano Zampini   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &adapt_interface, 1, MPIU_BOOL, MPI_LOR, interface_comm));
4359de2952eSStefano Zampini   if (adapt_interface) {
4369de2952eSStefano Zampini     PetscSF         msf;
4379de2952eSStefano Zampini     const PetscInt *n_ref_sharing;
4389de2952eSStefano Zampini     PetscInt       *labels, *rootlabels, *mrlabels;
4399de2952eSStefano Zampini     PetscInt        nr, nmr, nrs, ncc, cum_queue;
440674ae819SStefano Zampini 
4419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->nvtxs, &labels));
4429566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(labels, graph->nvtxs));
4439de2952eSStefano Zampini     for (PetscInt i = 0, k = 0; i < graph->ncc; i++) {
4441c7a958bSStefano Zampini       PetscInt s = 1;
4459de2952eSStefano Zampini       for (PetscInt j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
4461c7a958bSStefano Zampini         if (cornerp && PetscBTLookup(cornerp, graph->queue[j])) {
4479de2952eSStefano Zampini           labels[graph->queue[j]] = -(k + s + 1);
4481c7a958bSStefano Zampini           s += 1;
4491c7a958bSStefano Zampini         } else {
4509de2952eSStefano Zampini           labels[graph->queue[j]] = -(k + 1);
4511c7a958bSStefano Zampini         }
4521c7a958bSStefano Zampini       }
4531c7a958bSStefano Zampini       k += s;
4541c7a958bSStefano Zampini     }
4559de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, &nr, NULL, NULL, NULL));
4569de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_subset_sf, &nrs, NULL, NULL, NULL));
4579de2952eSStefano Zampini     PetscCall(PetscSFGetMultiSF(graph->interface_subset_sf, &msf));
4589de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
4599de2952eSStefano Zampini     PetscCall(PetscCalloc2(nmr, &mrlabels, nrs, &rootlabels));
460b3cdcd63SStefano Zampini 
4619de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeBegin(graph->interface_subset_sf, &n_ref_sharing));
4629de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeEnd(graph->interface_subset_sf, &n_ref_sharing));
4639de2952eSStefano Zampini     PetscCall(PetscSFGatherBegin(graph->interface_subset_sf, MPIU_INT, labels, mrlabels));
4649de2952eSStefano Zampini     PetscCall(PetscSFGatherEnd(graph->interface_subset_sf, MPIU_INT, labels, mrlabels));
465b3cdcd63SStefano Zampini 
4669de2952eSStefano Zampini     /* analyze contributions from processes
4679de2952eSStefano Zampini        The structure of mrlabels is suitable to find intersections of ccs.
4689de2952eSStefano Zampini        supposing the root subset has dimension 5 and leaves with labels:
4699de2952eSStefano Zampini          0: [4 4 7 4 7], (2 connected components)
4709de2952eSStefano Zampini          1: [3 2 2 3 2], (2 connected components)
4719de2952eSStefano Zampini          2: [1 1 6 5 6], (3 connected components)
4729de2952eSStefano Zampini        the multiroot data and the new labels corresponding to intersected connected components will be (column major)
473b3cdcd63SStefano Zampini 
4749de2952eSStefano Zampini                   4 4 7 4 7
4759de2952eSStefano Zampini        mrlabels   3 2 2 3 2
4769de2952eSStefano Zampini                   1 1 6 5 6
4779de2952eSStefano Zampini                   ---------
4789de2952eSStefano Zampini        rootlabels 0 1 2 3 2
4799de2952eSStefano Zampini     */
4809de2952eSStefano Zampini     for (PetscInt i = 0, rcumlabels = 0, mcumlabels = 0; i < nr; i++) {
4819de2952eSStefano Zampini       const PetscInt  subset_size    = graph->interface_ref_rsize[i];
4829de2952eSStefano Zampini       const PetscInt *n_sharing      = n_ref_sharing + rcumlabels;
4839de2952eSStefano Zampini       const PetscInt *mrbuffer       = mrlabels + mcumlabels;
4849de2952eSStefano Zampini       PetscInt       *rbuffer        = rootlabels + rcumlabels;
485b3cdcd63SStefano Zampini       PetscInt        subset_counter = 0;
486ec1c413dSStefano Zampini 
4879de2952eSStefano Zampini       for (PetscInt j = 0; j < subset_size; j++) {
4889de2952eSStefano Zampini         if (!rbuffer[j]) { /* found a new cc  */
4899de2952eSStefano Zampini           const PetscInt *jlabels = mrbuffer + j * n_sharing[0];
4909de2952eSStefano Zampini           rbuffer[j]              = ++subset_counter;
491ec1c413dSStefano Zampini 
4929de2952eSStefano Zampini           for (PetscInt k = j + 1; k < subset_size; k++) { /* check for other nodes in new cc */
4939de2952eSStefano Zampini             PetscBool       same_set = PETSC_TRUE;
4949de2952eSStefano Zampini             const PetscInt *klabels  = mrbuffer + k * n_sharing[0];
4959de2952eSStefano Zampini 
4969de2952eSStefano Zampini             for (PetscInt s = 0; s < n_sharing[0]; s++) {
4979de2952eSStefano Zampini               if (jlabels[s] != klabels[s]) {
498674ae819SStefano Zampini                 same_set = PETSC_FALSE;
499674ae819SStefano Zampini                 break;
500674ae819SStefano Zampini               }
501674ae819SStefano Zampini             }
5029de2952eSStefano Zampini             if (same_set) rbuffer[k] = subset_counter;
503674ae819SStefano Zampini           }
504674ae819SStefano Zampini         }
505674ae819SStefano Zampini       }
5069de2952eSStefano Zampini       if (subset_size) {
5079de2952eSStefano Zampini         rcumlabels += subset_size;
5089de2952eSStefano Zampini         mcumlabels += n_sharing[0] * subset_size;
509674ae819SStefano Zampini       }
5109de2952eSStefano Zampini     }
5119de2952eSStefano Zampini 
5129de2952eSStefano Zampini     /* Now communicate the intersected labels */
5139de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(graph->interface_subset_sf, MPIU_INT, rootlabels, labels, MPI_REPLACE));
5149de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(graph->interface_subset_sf, MPIU_INT, rootlabels, labels, MPI_REPLACE));
5159de2952eSStefano Zampini     PetscCall(PetscFree2(mrlabels, rootlabels));
5169de2952eSStefano Zampini 
5179de2952eSStefano Zampini     /* and adapt local connected components */
5189de2952eSStefano Zampini     PetscInt  *ocptr, *oqueue;
5199de2952eSStefano Zampini     PetscBool *touched;
5209de2952eSStefano Zampini 
5219de2952eSStefano Zampini     PetscCall(PetscMalloc3(graph->ncc + 1, &ocptr, graph->cptr[graph->ncc], &oqueue, graph->cptr[graph->ncc], &touched));
5229de2952eSStefano Zampini     PetscCall(PetscArraycpy(ocptr, graph->cptr, graph->ncc + 1));
5239de2952eSStefano Zampini     PetscCall(PetscArraycpy(oqueue, graph->queue, graph->cptr[graph->ncc]));
5249de2952eSStefano Zampini     PetscCall(PetscArrayzero(touched, graph->cptr[graph->ncc]));
5259de2952eSStefano Zampini 
5269de2952eSStefano Zampini     ncc       = 0;
5279de2952eSStefano Zampini     cum_queue = 0;
5289de2952eSStefano Zampini     for (PetscInt i = 0; i < graph->ncc; i++) {
5299de2952eSStefano Zampini       for (PetscInt j = ocptr[i]; j < ocptr[i + 1]; j++) {
5309de2952eSStefano Zampini         const PetscInt jlabel = labels[oqueue[j]];
5319de2952eSStefano Zampini 
5329de2952eSStefano Zampini         if (jlabel) {
533b3cdcd63SStefano Zampini           graph->cptr[ncc] = cum_queue;
534b3cdcd63SStefano Zampini           ncc++;
5359de2952eSStefano Zampini           for (PetscInt k = j; k < ocptr[i + 1]; k++) { /* check for other nodes in new cc */
5369de2952eSStefano Zampini             if (labels[oqueue[k]] == jlabel) {
5379de2952eSStefano Zampini               graph->queue[cum_queue++] = oqueue[k];
5389de2952eSStefano Zampini               labels[oqueue[k]]         = 0;
539674ae819SStefano Zampini             }
540674ae819SStefano Zampini           }
541b3cdcd63SStefano Zampini         }
5429de2952eSStefano Zampini       }
5439de2952eSStefano Zampini     }
5449de2952eSStefano Zampini     PetscCall(PetscFree3(ocptr, oqueue, touched));
5459566063dSJacob Faibussowitsch     PetscCall(PetscFree(labels));
5469de2952eSStefano Zampini     graph->cptr[ncc]    = cum_queue;
5479de2952eSStefano Zampini     graph->queue_sorted = PETSC_FALSE;
5489de2952eSStefano Zampini     graph->ncc          = ncc;
549674ae819SStefano Zampini   }
5509566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&cornerp));
5518e4af1ccSStefano Zampini 
552cc0a5675Sstefano_zampini   /* Determine if we are in 2D or 3D */
553cc0a5675Sstefano_zampini   if (!graph->twodimset) {
554cc0a5675Sstefano_zampini     PetscBool twodim = PETSC_TRUE;
5559de2952eSStefano Zampini     for (PetscInt i = 0; i < graph->ncc; i++) {
556cc0a5675Sstefano_zampini       PetscInt repdof = graph->queue[graph->cptr[i]];
557cc0a5675Sstefano_zampini       PetscInt ccsize = graph->cptr[i + 1] - graph->cptr[i];
5589de2952eSStefano Zampini       if (graph->nodes[repdof].count > 2 && ccsize > graph->custom_minimal_size) {
559cc0a5675Sstefano_zampini         twodim = PETSC_FALSE;
560cc0a5675Sstefano_zampini         break;
561cc0a5675Sstefano_zampini       }
562cc0a5675Sstefano_zampini     }
5631c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&twodim, &graph->twodim, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)graph->l2gmap)));
564cc0a5675Sstefano_zampini     graph->twodimset = PETSC_TRUE;
565cc0a5675Sstefano_zampini   }
5663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
567674ae819SStefano Zampini }
568674ae819SStefano Zampini 
5699de2952eSStefano Zampini static inline PetscErrorCode PCBDDCGraphComputeCC_Private(PCBDDCGraph graph, PetscInt pid, PetscInt *PETSC_RESTRICT queue_tip, PetscInt n_prev, PetscInt *n_added)
570d71ae5a4SJacob Faibussowitsch {
5719de2952eSStefano Zampini   PetscInt i, j, n = 0;
5729de2952eSStefano Zampini 
5739de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT xadj        = graph->xadj;
5749de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT adjncy      = graph->adjncy;
5759de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT subset_idxs = graph->subset_idxs[pid - 1];
5769de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT local_subs  = graph->local_subs;
5779de2952eSStefano Zampini   const PetscInt                 subset_size = graph->subset_size[pid - 1];
5789de2952eSStefano Zampini 
5799de2952eSStefano Zampini   PCBDDCGraphNode *PETSC_RESTRICT nodes = graph->nodes;
5809de2952eSStefano Zampini 
5819de2952eSStefano Zampini   const PetscBool havecsr  = (PetscBool)(!!xadj);
5829de2952eSStefano Zampini   const PetscBool havesubs = (PetscBool)(!!graph->n_local_subs);
583b3cdcd63SStefano Zampini 
584b3cdcd63SStefano Zampini   PetscFunctionBegin;
585b3cdcd63SStefano Zampini   if (havecsr && !havesubs) {
586b3cdcd63SStefano Zampini     for (i = -n_prev; i < 0; i++) {
5879de2952eSStefano Zampini       const PetscInt start_dof = queue_tip[i];
5889de2952eSStefano Zampini 
58954fffbccSStefano Zampini       /* we assume that if a dof has a size 1 adjacency list and the corresponding entry is negative, it is connected to all dofs */
59054fffbccSStefano Zampini       if (xadj[start_dof + 1] - xadj[start_dof] == 1 && adjncy[xadj[start_dof]] < 0) {
5919de2952eSStefano Zampini         for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
5929de2952eSStefano Zampini           const PetscInt dof = subset_idxs[j];
5939de2952eSStefano Zampini 
5949de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid) {
5959de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
59654fffbccSStefano Zampini             queue_tip[n]       = dof;
59754fffbccSStefano Zampini             n++;
59854fffbccSStefano Zampini           }
59954fffbccSStefano Zampini         }
60054fffbccSStefano Zampini       } else {
601b3cdcd63SStefano Zampini         for (j = xadj[start_dof]; j < xadj[start_dof + 1]; j++) {
6029de2952eSStefano Zampini           const PetscInt dof = adjncy[j];
6039de2952eSStefano Zampini 
6049de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid) {
6059de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
606b3cdcd63SStefano Zampini             queue_tip[n]       = dof;
607b3cdcd63SStefano Zampini             n++;
608b3cdcd63SStefano Zampini           }
609b3cdcd63SStefano Zampini         }
610b3cdcd63SStefano Zampini       }
61154fffbccSStefano Zampini     }
612b3cdcd63SStefano Zampini   } else if (havecsr && havesubs) {
6139de2952eSStefano Zampini     const PetscInt sid = local_subs[queue_tip[-n_prev]];
6149de2952eSStefano Zampini 
615b3cdcd63SStefano Zampini     for (i = -n_prev; i < 0; i++) {
6169de2952eSStefano Zampini       const PetscInt start_dof = queue_tip[i];
6179de2952eSStefano Zampini 
61854fffbccSStefano Zampini       /* we assume that if a dof has a size 1 adjacency list and the corresponding entry is negative, it is connected to all dofs belonging to the local sub */
61954fffbccSStefano Zampini       if (xadj[start_dof + 1] - xadj[start_dof] == 1 && adjncy[xadj[start_dof]] < 0) {
6209de2952eSStefano Zampini         for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
6219de2952eSStefano Zampini           const PetscInt dof = subset_idxs[j];
6229de2952eSStefano Zampini 
6239de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) {
6249de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
62554fffbccSStefano Zampini             queue_tip[n]       = dof;
62654fffbccSStefano Zampini             n++;
62754fffbccSStefano Zampini           }
62854fffbccSStefano Zampini         }
62954fffbccSStefano Zampini       } else {
630b3cdcd63SStefano Zampini         for (j = xadj[start_dof]; j < xadj[start_dof + 1]; j++) {
6319de2952eSStefano Zampini           const PetscInt dof = adjncy[j];
6329de2952eSStefano Zampini 
6339de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) {
6349de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
635b3cdcd63SStefano Zampini             queue_tip[n]       = dof;
636b3cdcd63SStefano Zampini             n++;
637b3cdcd63SStefano Zampini           }
638b3cdcd63SStefano Zampini         }
639b3cdcd63SStefano Zampini       }
64054fffbccSStefano Zampini     }
6411c7a958bSStefano Zampini   } else if (havesubs) { /* sub info only */
6429de2952eSStefano Zampini     const PetscInt sid = local_subs[queue_tip[-n_prev]];
6439de2952eSStefano Zampini 
6449de2952eSStefano Zampini     for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
6459de2952eSStefano Zampini       const PetscInt dof = subset_idxs[j];
6469de2952eSStefano Zampini 
6479de2952eSStefano Zampini       if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) {
6489de2952eSStefano Zampini         nodes[dof].touched = PETSC_TRUE;
649b3cdcd63SStefano Zampini         queue_tip[n]       = dof;
650b3cdcd63SStefano Zampini         n++;
651b3cdcd63SStefano Zampini       }
652b3cdcd63SStefano Zampini     }
6531c7a958bSStefano Zampini   } else {
6549de2952eSStefano Zampini     for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
6559de2952eSStefano Zampini       const PetscInt dof = subset_idxs[j];
6569de2952eSStefano Zampini 
6579de2952eSStefano Zampini       if (!nodes[dof].touched && nodes[dof].subset == pid) {
6589de2952eSStefano Zampini         nodes[dof].touched = PETSC_TRUE;
6591c7a958bSStefano Zampini         queue_tip[n]       = dof;
6601c7a958bSStefano Zampini         n++;
6611c7a958bSStefano Zampini       }
6621c7a958bSStefano Zampini     }
663b3cdcd63SStefano Zampini   }
664b3cdcd63SStefano Zampini   *n_added = n;
6653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
666b3cdcd63SStefano Zampini }
667b3cdcd63SStefano Zampini 
668d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphComputeConnectedComponentsLocal(PCBDDCGraph graph)
669d71ae5a4SJacob Faibussowitsch {
6709de2952eSStefano Zampini   PetscInt ncc, cum_queue;
671674ae819SStefano Zampini 
672674ae819SStefano Zampini   PetscFunctionBegin;
67328b400f6SJacob Faibussowitsch   PetscCheck(graph->setupcalled, PetscObjectComm((PetscObject)graph->l2gmap), PETSC_ERR_ORDER, "PCBDDCGraphSetUp should be called first");
674b3cdcd63SStefano Zampini   /* quiet return if there isn't any local info */
6753ba16761SJacob Faibussowitsch   if (!graph->xadj && !graph->n_local_subs) PetscFunctionReturn(PETSC_SUCCESS);
676674ae819SStefano Zampini 
677674ae819SStefano Zampini   /* reset any previous search of connected components */
6789de2952eSStefano Zampini   for (PetscInt i = 0; i < graph->nvtxs; i++) graph->nodes[i].touched = PETSC_FALSE;
6799de2952eSStefano Zampini   if (!graph->seq_graph) {
6809de2952eSStefano Zampini     for (PetscInt i = 0; i < graph->nvtxs; i++) {
6819de2952eSStefano Zampini       if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK || graph->nodes[i].count < 2) graph->nodes[i].touched = PETSC_TRUE;
6824a060362SStefano Zampini     }
683b3cdcd63SStefano Zampini   }
684674ae819SStefano Zampini 
685674ae819SStefano Zampini   /* begin search for connected components */
686674ae819SStefano Zampini   cum_queue = 0;
687674ae819SStefano Zampini   ncc       = 0;
6889de2952eSStefano Zampini   for (PetscInt n = 0; n < graph->n_subsets; n++) {
6899de2952eSStefano Zampini     const PetscInt *subset_idxs = graph->subset_idxs[n];
6909de2952eSStefano Zampini     const PetscInt  pid         = n + 1; /* partition labeled by 0 is discarded */
6919de2952eSStefano Zampini 
692b3cdcd63SStefano Zampini     PetscInt found = 0, prev = 0, first = 0, ncc_pid = 0;
6939de2952eSStefano Zampini 
694b3cdcd63SStefano Zampini     while (found != graph->subset_size[n]) {
695b3cdcd63SStefano Zampini       PetscInt added = 0;
6969de2952eSStefano Zampini 
697b3cdcd63SStefano Zampini       if (!prev) { /* search for new starting dof */
6989de2952eSStefano Zampini         while (graph->nodes[subset_idxs[first]].touched) first++;
6999de2952eSStefano Zampini         graph->nodes[subset_idxs[first]].touched = PETSC_TRUE;
7009de2952eSStefano Zampini         graph->queue[cum_queue]                  = subset_idxs[first];
701674ae819SStefano Zampini         graph->cptr[ncc]                         = cum_queue;
702b3cdcd63SStefano Zampini         prev                                     = 1;
703b3cdcd63SStefano Zampini         cum_queue++;
704b3cdcd63SStefano Zampini         found++;
705674ae819SStefano Zampini         ncc_pid++;
706b3cdcd63SStefano Zampini         ncc++;
707674ae819SStefano Zampini       }
7089566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphComputeCC_Private(graph, pid, graph->queue + cum_queue, prev, &added));
709b3cdcd63SStefano Zampini       if (!added) {
710674ae819SStefano Zampini         graph->subset_ncc[n] = ncc_pid;
711b3cdcd63SStefano Zampini         graph->cptr[ncc]     = cum_queue;
712b3cdcd63SStefano Zampini       }
713b3cdcd63SStefano Zampini       prev = added;
714b3cdcd63SStefano Zampini       found += added;
715b3cdcd63SStefano Zampini       cum_queue += added;
716b3cdcd63SStefano Zampini       if (added && found == graph->subset_size[n]) {
717b3cdcd63SStefano Zampini         graph->subset_ncc[n] = ncc_pid;
718b3cdcd63SStefano Zampini         graph->cptr[ncc]     = cum_queue;
719b3cdcd63SStefano Zampini       }
720b3cdcd63SStefano Zampini     }
721674ae819SStefano Zampini   }
722674ae819SStefano Zampini   graph->ncc          = ncc;
723acc113dbSStefano Zampini   graph->queue_sorted = PETSC_FALSE;
7243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
725674ae819SStefano Zampini }
726674ae819SStefano Zampini 
727d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphSetUp(PCBDDCGraph graph, PetscInt custom_minimal_size, IS neumann_is, IS dirichlet_is, PetscInt n_ISForDofs, IS ISForDofs[], IS custom_primal_vertices)
728d71ae5a4SJacob Faibussowitsch {
7299de2952eSStefano Zampini   IS              subset;
730674ae819SStefano Zampini   MPI_Comm        comm;
731674ae819SStefano Zampini   const PetscInt *is_indices;
7329de2952eSStefano Zampini   PetscInt       *queue_global, *nodecount, **nodeneighs;
7339de2952eSStefano Zampini   PetscInt        i, j, k, total_counts, nodes_touched, is_size, nvtxs = graph->nvtxs;
7349de2952eSStefano Zampini   PetscMPIInt     size, rank;
7359de2952eSStefano Zampini   PetscBool       same_set;
736674ae819SStefano Zampini 
737674ae819SStefano Zampini   PetscFunctionBegin;
7387a0e7b2cSstefano_zampini   PetscValidLogicalCollectiveInt(graph->l2gmap, custom_minimal_size, 2);
7397a0e7b2cSstefano_zampini   if (neumann_is) {
7407a0e7b2cSstefano_zampini     PetscValidHeaderSpecific(neumann_is, IS_CLASSID, 3);
7417a0e7b2cSstefano_zampini     PetscCheckSameComm(graph->l2gmap, 1, neumann_is, 3);
7427a0e7b2cSstefano_zampini   }
743a07ea27aSStefano Zampini   graph->has_dirichlet = PETSC_FALSE;
744a07ea27aSStefano Zampini   if (dirichlet_is) {
7457a0e7b2cSstefano_zampini     PetscValidHeaderSpecific(dirichlet_is, IS_CLASSID, 4);
746a07ea27aSStefano Zampini     PetscCheckSameComm(graph->l2gmap, 1, dirichlet_is, 4);
747a07ea27aSStefano Zampini     graph->has_dirichlet = PETSC_TRUE;
748a07ea27aSStefano Zampini   }
7497a0e7b2cSstefano_zampini   PetscValidLogicalCollectiveInt(graph->l2gmap, n_ISForDofs, 5);
7507a0e7b2cSstefano_zampini   for (i = 0; i < n_ISForDofs; i++) {
7517a0e7b2cSstefano_zampini     PetscValidHeaderSpecific(ISForDofs[i], IS_CLASSID, 6);
7527a0e7b2cSstefano_zampini     PetscCheckSameComm(graph->l2gmap, 1, ISForDofs[i], 6);
7537a0e7b2cSstefano_zampini   }
7547a0e7b2cSstefano_zampini   if (custom_primal_vertices) {
755ab8c8b98SStefano Zampini     PetscValidHeaderSpecific(custom_primal_vertices, IS_CLASSID, 7);
7567a0e7b2cSstefano_zampini     PetscCheckSameComm(graph->l2gmap, 1, custom_primal_vertices, 7);
7577a0e7b2cSstefano_zampini   }
7589de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++) graph->nodes[i].touched = PETSC_FALSE;
7599de2952eSStefano Zampini 
760f4f49eeaSPierre Jolivet   PetscCall(PetscObjectGetComm((PetscObject)graph->l2gmap, &comm));
7619de2952eSStefano Zampini   PetscCallMPI(MPI_Comm_size(comm, &size));
7629de2952eSStefano Zampini   PetscCallMPI(MPI_Comm_rank(comm, &rank));
763b3cdcd63SStefano Zampini 
764674ae819SStefano Zampini   /* custom_minimal_size */
76514f95afaSStefano Zampini   graph->custom_minimal_size = custom_minimal_size;
7667a0e7b2cSstefano_zampini 
7679de2952eSStefano Zampini   /* get node info from l2gmap */
7689de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingGetNodeInfo(graph->l2gmap, NULL, &nodecount, &nodeneighs));
76951b0f6cfSStefano Zampini 
770674ae819SStefano Zampini   /* Allocate space for storing the set of neighbours for each node */
7719de2952eSStefano Zampini   graph->multi_element = PETSC_FALSE;
7729de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++) {
7739de2952eSStefano Zampini     graph->nodes[i].count = nodecount[i];
7749de2952eSStefano Zampini     if (!graph->seq_graph) {
7759de2952eSStefano Zampini       PetscCall(PetscMalloc1(nodecount[i], &graph->nodes[i].neighbours_set));
7769de2952eSStefano Zampini       PetscCall(PetscArraycpy(graph->nodes[i].neighbours_set, nodeneighs[i], nodecount[i]));
7779de2952eSStefano Zampini 
7789de2952eSStefano Zampini       if (!graph->multi_element) {
7799de2952eSStefano Zampini         PetscInt nself;
7809de2952eSStefano Zampini         for (j = 0, nself = 0; j < graph->nodes[i].count; j++)
7819de2952eSStefano Zampini           if (graph->nodes[i].neighbours_set[j] == rank) nself++;
7829de2952eSStefano Zampini         if (nself > 1) graph->multi_element = PETSC_TRUE;
783674ae819SStefano Zampini       }
7849de2952eSStefano Zampini     } else {
7859de2952eSStefano Zampini       PetscCall(PetscCalloc1(nodecount[i], &graph->nodes[i].neighbours_set));
786674ae819SStefano Zampini     }
787674ae819SStefano Zampini   }
7889de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(graph->l2gmap, NULL, &nodecount, &nodeneighs));
7899de2952eSStefano Zampini   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &graph->multi_element, 1, MPIU_BOOL, MPI_LOR, comm));
7909de2952eSStefano Zampini 
7919de2952eSStefano Zampini   /* compute local groups */
7929de2952eSStefano Zampini   if (graph->multi_element) {
7939de2952eSStefano Zampini     const PetscInt *idxs, *indegree;
7949de2952eSStefano Zampini     IS              is, lis;
7959de2952eSStefano Zampini     PetscLayout     layout;
7969de2952eSStefano Zampini     PetscSF         sf, multisf;
7979de2952eSStefano Zampini     PetscInt        n, nmulti, c, *multi_root_subs, *start;
7989de2952eSStefano Zampini 
7990b61a303SStefano Zampini     PetscCheck(!nvtxs || graph->local_subs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local subdomain information");
8009de2952eSStefano Zampini 
8019de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetIndices(graph->l2gmap, &idxs));
8029de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nvtxs, idxs, PETSC_USE_POINTER, &is));
8039de2952eSStefano Zampini     PetscCall(ISRenumber(is, NULL, &n, &lis));
8049de2952eSStefano Zampini     PetscCall(ISDestroy(&is));
8059de2952eSStefano Zampini 
8069de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingRestoreIndices(graph->l2gmap, &idxs));
8079de2952eSStefano Zampini     PetscCall(ISGetIndices(lis, &idxs));
8089de2952eSStefano Zampini     PetscCall(PetscLayoutCreate(PETSC_COMM_SELF, &layout));
8099de2952eSStefano Zampini     PetscCall(PetscLayoutSetSize(layout, n));
8109de2952eSStefano Zampini     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
8119de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(sf, layout, nvtxs, NULL, PETSC_OWN_POINTER, idxs));
8129de2952eSStefano Zampini     PetscCall(PetscLayoutDestroy(&layout));
8139de2952eSStefano Zampini     PetscCall(PetscSFGetMultiSF(sf, &multisf));
8149de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeBegin(sf, &indegree));
8159de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeEnd(sf, &indegree));
8169de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(multisf, &nmulti, NULL, NULL, NULL));
8179de2952eSStefano Zampini     PetscCall(PetscMalloc2(nmulti, &multi_root_subs, n + 1, &start));
8189de2952eSStefano Zampini     start[0] = 0;
8199de2952eSStefano Zampini     for (i = 0; i < n; i++) start[i + 1] = start[i] + indegree[i];
8209de2952eSStefano Zampini     PetscCall(PetscSFGatherBegin(sf, MPIU_INT, graph->local_subs, multi_root_subs));
8219de2952eSStefano Zampini     PetscCall(PetscSFGatherEnd(sf, MPIU_INT, graph->local_subs, multi_root_subs));
8229de2952eSStefano Zampini     for (i = 0; i < nvtxs; i++) {
8239de2952eSStefano Zampini       PetscInt gid = idxs[i];
8249de2952eSStefano Zampini 
8259de2952eSStefano Zampini       graph->nodes[i].local_sub = graph->local_subs[i];
8269de2952eSStefano Zampini       for (j = 0, c = 0; j < graph->nodes[i].count; j++) {
8279de2952eSStefano Zampini         if (graph->nodes[i].neighbours_set[j] == rank) c++;
8289de2952eSStefano Zampini       }
8299de2952eSStefano Zampini       PetscCheck(c == indegree[idxs[i]], PETSC_COMM_SELF, PETSC_ERR_PLIB, "%" PetscInt_FMT " != %" PetscInt_FMT, c, indegree[idxs[i]]);
8309de2952eSStefano Zampini       PetscCall(PetscMalloc1(c, &graph->nodes[i].local_groups));
8319de2952eSStefano Zampini       for (j = 0; j < c; j++) graph->nodes[i].local_groups[j] = multi_root_subs[start[gid] + j];
8329de2952eSStefano Zampini       PetscCall(PetscSortInt(c, graph->nodes[i].local_groups));
8339de2952eSStefano Zampini       graph->nodes[i].local_groups_count = c;
8349de2952eSStefano Zampini     }
8359de2952eSStefano Zampini     PetscCall(PetscFree2(multi_root_subs, start));
8369de2952eSStefano Zampini     PetscCall(ISRestoreIndices(lis, &idxs));
8379de2952eSStefano Zampini     PetscCall(ISDestroy(&lis));
8389de2952eSStefano Zampini     PetscCall(PetscSFDestroy(&sf));
8399de2952eSStefano Zampini   }
8407fb0e2dbSStefano Zampini 
84167c9da69SStefano Zampini   /*
84267c9da69SStefano Zampini      Get info for dofs splitting
8435777c63cSStefano Zampini      User can specify just a subset; an additional field is considered as a complementary field
84467c9da69SStefano Zampini   */
8450c85b387SStefano Zampini   for (i = 0, k = 0; i < n_ISForDofs; i++) {
8460c85b387SStefano Zampini     PetscInt bs;
8470c85b387SStefano Zampini 
8489566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(ISForDofs[i], &bs));
8490c85b387SStefano Zampini     k += bs;
8500c85b387SStefano Zampini   }
8519de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++) graph->nodes[i].which_dof = k; /* by default a dof belongs to the complement set */
8520c85b387SStefano Zampini   for (i = 0, k = 0; i < n_ISForDofs; i++) {
8530c85b387SStefano Zampini     PetscInt bs;
8540c85b387SStefano Zampini 
8559566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(ISForDofs[i], &is_size));
8569566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(ISForDofs[i], &bs));
8579566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(ISForDofs[i], (const PetscInt **)&is_indices));
8580c85b387SStefano Zampini     for (j = 0; j < is_size / bs; j++) {
8590c85b387SStefano Zampini       PetscInt b;
8600c85b387SStefano Zampini 
8610c85b387SStefano Zampini       for (b = 0; b < bs; b++) {
8620c85b387SStefano Zampini         PetscInt jj = bs * j + b;
8630c85b387SStefano Zampini 
8649de2952eSStefano Zampini         if (is_indices[jj] > -1 && is_indices[jj] < nvtxs) { /* out of bounds indices (if any) are skipped */
8659de2952eSStefano Zampini           graph->nodes[is_indices[jj]].which_dof = k + b;
8660c85b387SStefano Zampini         }
867674ae819SStefano Zampini       }
86867c9da69SStefano Zampini     }
8699566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(ISForDofs[i], (const PetscInt **)&is_indices));
8700c85b387SStefano Zampini     k += bs;
8715777c63cSStefano Zampini   }
8725777c63cSStefano Zampini 
873674ae819SStefano Zampini   /* Take into account Neumann nodes */
874674ae819SStefano Zampini   if (neumann_is) {
8759566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(neumann_is, &is_size));
8769566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(neumann_is, (const PetscInt **)&is_indices));
877674ae819SStefano Zampini     for (i = 0; i < is_size; i++) {
8789de2952eSStefano Zampini       if (is_indices[i] > -1 && is_indices[i] < nvtxs) { /* out of bounds indices (if any) are skipped */
8799de2952eSStefano Zampini         graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_NEUMANN_MARK;
880674ae819SStefano Zampini       }
8813c629590SStefano Zampini     }
8829566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(neumann_is, (const PetscInt **)&is_indices));
883674ae819SStefano Zampini   }
8849de2952eSStefano Zampini 
8859de2952eSStefano Zampini   /* Take into account Dirichlet nodes (they overwrite any mark previously set) */
886674ae819SStefano Zampini   if (dirichlet_is) {
8879566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(dirichlet_is, &is_size));
8889566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(dirichlet_is, (const PetscInt **)&is_indices));
889674ae819SStefano Zampini     for (i = 0; i < is_size; i++) {
8909de2952eSStefano Zampini       if (is_indices[i] > -1 && is_indices[i] < nvtxs) { /* out of bounds indices (if any) are skipped */
8919de2952eSStefano Zampini         if (!graph->seq_graph) {                         /* dirichlet nodes treated as internal */
8929de2952eSStefano Zampini           graph->nodes[is_indices[i]].touched = PETSC_TRUE;
8939de2952eSStefano Zampini           graph->nodes[is_indices[i]].subset  = 0;
8947a0e7b2cSstefano_zampini         }
8959de2952eSStefano Zampini         graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_DIRICHLET_MARK;
896674ae819SStefano Zampini       }
8973c629590SStefano Zampini     }
8989566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(dirichlet_is, (const PetscInt **)&is_indices));
8997fb0e2dbSStefano Zampini   }
90051b0f6cfSStefano Zampini 
9019de2952eSStefano Zampini   /* mark special nodes (if any) -> each will become a single dof equivalence class (i.e. point constraint for BDDC) */
902674ae819SStefano Zampini   if (custom_primal_vertices) {
9039566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(custom_primal_vertices, &is_size));
9049566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(custom_primal_vertices, (const PetscInt **)&is_indices));
9057a0e7b2cSstefano_zampini     for (i = 0, j = 0; i < is_size; i++) {
9069de2952eSStefano Zampini       if (is_indices[i] > -1 && is_indices[i] < nvtxs && graph->nodes[is_indices[i]].special_dof != PCBDDCGRAPH_DIRICHLET_MARK) { /* out of bounds indices (if any) are skipped */
9079de2952eSStefano Zampini         graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_SPECIAL_MARK - j;
9089b70a373SStefano Zampini         j++;
9099b70a373SStefano Zampini       }
9109b70a373SStefano Zampini     }
9119566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(custom_primal_vertices, (const PetscInt **)&is_indices));
91217eb1463SStefano Zampini   }
9139b70a373SStefano Zampini 
9149de2952eSStefano Zampini   /* mark interior nodes as touched and belonging to partition number 0 */
9159de2952eSStefano Zampini   if (!graph->seq_graph) {
9169de2952eSStefano Zampini     for (i = 0; i < nvtxs; i++) {
9179de2952eSStefano Zampini       if (graph->nodes[i].count < 2) {
9189de2952eSStefano Zampini         graph->nodes[i].touched = PETSC_TRUE;
9199de2952eSStefano Zampini         graph->nodes[i].subset  = 0;
920674ae819SStefano Zampini       }
921674ae819SStefano Zampini     }
922b3cdcd63SStefano Zampini   }
923b3cdcd63SStefano Zampini 
924674ae819SStefano Zampini   /* init graph structure and compute default subsets */
925674ae819SStefano Zampini   nodes_touched = 0;
9269de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++)
9279de2952eSStefano Zampini     if (graph->nodes[i].touched) nodes_touched++;
9289de2952eSStefano Zampini 
929674ae819SStefano Zampini   i            = 0;
930674ae819SStefano Zampini   graph->ncc   = 0;
931674ae819SStefano Zampini   total_counts = 0;
9327babac9bSStefano Zampini 
9337babac9bSStefano Zampini   /* allocated space for queues */
9349de2952eSStefano Zampini   if (graph->seq_graph) {
9359de2952eSStefano Zampini     PetscCall(PetscMalloc2(nvtxs + 1, &graph->cptr, nvtxs, &graph->queue));
9367babac9bSStefano Zampini   } else {
9379de2952eSStefano Zampini     PetscInt nused = nvtxs - nodes_touched;
9389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nused + 1, &graph->cptr, nused, &graph->queue));
9397babac9bSStefano Zampini   }
9407babac9bSStefano Zampini 
9419de2952eSStefano Zampini   while (nodes_touched < nvtxs) {
942674ae819SStefano Zampini     /*  find first untouched node in local ordering */
9439de2952eSStefano Zampini     while (graph->nodes[i].touched) i++;
9449de2952eSStefano Zampini     graph->nodes[i].touched    = PETSC_TRUE;
9459de2952eSStefano Zampini     graph->nodes[i].subset     = graph->ncc + 1;
946674ae819SStefano Zampini     graph->cptr[graph->ncc]    = total_counts;
947674ae819SStefano Zampini     graph->queue[total_counts] = i;
948674ae819SStefano Zampini     total_counts++;
949674ae819SStefano Zampini     nodes_touched++;
9509de2952eSStefano Zampini 
951674ae819SStefano Zampini     /* now find all other nodes having the same set of sharing subdomains */
9529de2952eSStefano Zampini     const PCBDDCGraphNode         *nodei               = &graph->nodes[i];
9539de2952eSStefano Zampini     const PetscInt                 icount              = nodei->count;
9549de2952eSStefano Zampini     const PetscInt                 iwhich_dof          = nodei->which_dof;
9559de2952eSStefano Zampini     const PetscInt                 ispecial_dof        = nodei->special_dof;
9569de2952eSStefano Zampini     const PetscInt                 ilocal_groups_count = nodei->local_groups_count;
9579de2952eSStefano Zampini     const PetscInt *PETSC_RESTRICT ineighbours_set     = nodei->neighbours_set;
9589de2952eSStefano Zampini     const PetscInt *PETSC_RESTRICT ilocal_groups       = nodei->local_groups;
9599de2952eSStefano Zampini     for (j = i + 1; j < nvtxs; j++) {
9609de2952eSStefano Zampini       PCBDDCGraphNode *PETSC_RESTRICT nodej = &graph->nodes[j];
9619de2952eSStefano Zampini 
9629de2952eSStefano Zampini       if (nodej->touched) continue;
96374e413f5SStefano Zampini       /* check for same number of sharing subdomains, dof number and same special mark */
9649de2952eSStefano Zampini       if (icount == nodej->count && iwhich_dof == nodej->which_dof && ispecial_dof == nodej->special_dof) {
9659de2952eSStefano Zampini         PetscBool mpi_shared = PETSC_TRUE;
9669de2952eSStefano Zampini 
967674ae819SStefano Zampini         /* check for same set of sharing subdomains */
968674ae819SStefano Zampini         same_set = PETSC_TRUE;
9699de2952eSStefano Zampini         for (k = 0; k < icount; k++) {
9709de2952eSStefano Zampini           if (ineighbours_set[k] != nodej->neighbours_set[k]) {
9719de2952eSStefano Zampini             same_set = PETSC_FALSE;
9729de2952eSStefano Zampini             break;
973674ae819SStefano Zampini           }
9749de2952eSStefano Zampini         }
9759de2952eSStefano Zampini 
9769de2952eSStefano Zampini         if (graph->multi_element) {
9779de2952eSStefano Zampini           mpi_shared = PETSC_FALSE;
9789de2952eSStefano Zampini           for (k = 0; k < icount; k++)
9799de2952eSStefano Zampini             if (ineighbours_set[k] != rank) {
9809de2952eSStefano Zampini               mpi_shared = PETSC_TRUE;
9819de2952eSStefano Zampini               break;
9829de2952eSStefano Zampini             }
9839de2952eSStefano Zampini         }
9849de2952eSStefano Zampini 
9859de2952eSStefano Zampini         /* check for same local groups
9869de2952eSStefano Zampini            shared dofs at the process boundaries will be handled differently */
9879de2952eSStefano Zampini         if (same_set && !mpi_shared) {
9889de2952eSStefano Zampini           if (ilocal_groups_count != nodej->local_groups_count) same_set = PETSC_FALSE;
9899de2952eSStefano Zampini           else {
9909de2952eSStefano Zampini             for (k = 0; k < ilocal_groups_count; k++) {
9919de2952eSStefano Zampini               if (ilocal_groups[k] != nodej->local_groups[k]) {
9929de2952eSStefano Zampini                 same_set = PETSC_FALSE;
9939de2952eSStefano Zampini                 break;
9949de2952eSStefano Zampini               }
9959de2952eSStefano Zampini             }
9969de2952eSStefano Zampini           }
9979de2952eSStefano Zampini         }
9989de2952eSStefano Zampini 
9999de2952eSStefano Zampini         /* Add to subset */
1000674ae819SStefano Zampini         if (same_set) {
10019de2952eSStefano Zampini           nodej->touched = PETSC_TRUE;
10029de2952eSStefano Zampini           nodej->subset  = graph->ncc + 1;
1003674ae819SStefano Zampini           nodes_touched++;
1004674ae819SStefano Zampini           graph->queue[total_counts] = j;
1005674ae819SStefano Zampini           total_counts++;
1006674ae819SStefano Zampini         }
1007674ae819SStefano Zampini       }
1008674ae819SStefano Zampini     }
1009674ae819SStefano Zampini     graph->ncc++;
1010674ae819SStefano Zampini   }
10119de2952eSStefano Zampini   graph->cptr[graph->ncc] = total_counts;
10129de2952eSStefano Zampini 
10139de2952eSStefano Zampini   /* set default number of subsets */
1014674ae819SStefano Zampini   graph->n_subsets = graph->ncc;
10159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->n_subsets, &graph->subset_ncc));
1016ad540459SPierre Jolivet   for (i = 0; i < graph->n_subsets; i++) graph->subset_ncc[i] = 1;
1017ec1c413dSStefano Zampini 
10189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->ncc, &graph->subset_ref_node));
10199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global));
10209de2952eSStefano Zampini   PetscCall(PetscMalloc2(graph->ncc, &graph->subset_size, graph->ncc, &graph->subset_idxs));
10219de2952eSStefano Zampini   if (graph->multi_element) PetscCall(PetscMalloc1(graph->ncc, &graph->gsubset_size));
10229de2952eSStefano Zampini   else graph->gsubset_size = graph->subset_size;
10239566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global));
10249de2952eSStefano Zampini 
10259de2952eSStefano Zampini   PetscHMapI cnt_unique;
10269de2952eSStefano Zampini 
10279de2952eSStefano Zampini   PetscCall(PetscHMapICreate(&cnt_unique));
1028ec1c413dSStefano Zampini   for (j = 0; j < graph->ncc; j++) {
1029*1690c2aeSBarry Smith     PetscInt c = 0, ref_node = PETSC_INT_MAX;
10309de2952eSStefano Zampini 
10319de2952eSStefano Zampini     for (k = graph->cptr[j]; k < graph->cptr[j + 1]; k++) {
10329de2952eSStefano Zampini       ref_node = PetscMin(ref_node, queue_global[k]);
10339de2952eSStefano Zampini       if (graph->multi_element) {
10349de2952eSStefano Zampini         PetscBool     missing;
10359de2952eSStefano Zampini         PetscHashIter iter;
10369de2952eSStefano Zampini 
10379de2952eSStefano Zampini         PetscCall(PetscHMapIPut(cnt_unique, queue_global[k], &iter, &missing));
10389de2952eSStefano Zampini         if (missing) c++;
1039f0321c90SStefano Zampini       }
10409de2952eSStefano Zampini     }
10419de2952eSStefano Zampini     graph->gsubset_size[j]    = c;
10429de2952eSStefano Zampini     graph->subset_size[j]     = graph->cptr[j + 1] - graph->cptr[j];
10439de2952eSStefano Zampini     graph->subset_ref_node[j] = ref_node;
10449de2952eSStefano Zampini     if (graph->multi_element) PetscCall(PetscHMapIClear(cnt_unique));
10459de2952eSStefano Zampini   }
10469de2952eSStefano Zampini   PetscCall(PetscHMapIDestroy(&cnt_unique));
104748bebe3cSStefano Zampini 
1048b3cdcd63SStefano Zampini   /* save information on subsets (needed when analyzing the connected components) */
10492f566a09SStefano Zampini   if (graph->ncc) {
10509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &graph->subset_idxs[0]));
10519566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(graph->subset_idxs[0], graph->cptr[graph->ncc]));
10529de2952eSStefano Zampini     for (j = 1; j < graph->ncc; j++) { graph->subset_idxs[j] = graph->subset_idxs[j - 1] + graph->subset_size[j - 1]; }
10539566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(graph->subset_idxs[0], graph->queue, graph->cptr[graph->ncc]));
1054ec1c413dSStefano Zampini   }
1055b3cdcd63SStefano Zampini 
10569de2952eSStefano Zampini   /* check consistency and create SF to analyze components on the interface between subdomains */
10579de2952eSStefano Zampini   if (!graph->seq_graph) {
10589de2952eSStefano Zampini     PetscSF         msf;
10599de2952eSStefano Zampini     PetscLayout     map;
10609de2952eSStefano Zampini     const PetscInt *degree;
10619de2952eSStefano Zampini     PetscInt        nr, nmr, *rdata;
10629de2952eSStefano Zampini     PetscBool       valid = PETSC_TRUE;
10639de2952eSStefano Zampini     PetscInt        subset_N;
10649de2952eSStefano Zampini     IS              subset_n;
10659de2952eSStefano Zampini     const PetscInt *idxs;
10669de2952eSStefano Zampini 
10679de2952eSStefano Zampini     PetscCall(ISCreateGeneral(comm, graph->n_subsets, graph->subset_ref_node, PETSC_USE_POINTER, &subset));
10689de2952eSStefano Zampini     PetscCall(ISRenumber(subset, NULL, &subset_N, &subset_n));
10699566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&subset));
10709de2952eSStefano Zampini 
10719de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &graph->interface_ref_sf));
10729de2952eSStefano Zampini     PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, subset_N, 1, &map));
10739de2952eSStefano Zampini     PetscCall(ISGetIndices(subset_n, &idxs));
10749de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(graph->interface_ref_sf, map, graph->n_subsets, NULL, PETSC_OWN_POINTER, idxs));
10759de2952eSStefano Zampini     PetscCall(ISRestoreIndices(subset_n, &idxs));
10769566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&subset_n));
10779de2952eSStefano Zampini     PetscCall(PetscLayoutDestroy(&map));
10789de2952eSStefano Zampini 
10799de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeBegin(graph->interface_ref_sf, &degree));
10809de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeEnd(graph->interface_ref_sf, &degree));
10819de2952eSStefano Zampini     PetscCall(PetscSFGetMultiSF(graph->interface_ref_sf, &msf));
10829de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, &nr, NULL, NULL, NULL));
10839de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
10849de2952eSStefano Zampini     PetscCall(PetscCalloc1(nmr, &rdata));
10859de2952eSStefano Zampini     PetscCall(PetscSFGatherBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata));
10869de2952eSStefano Zampini     PetscCall(PetscSFGatherEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata));
10879de2952eSStefano Zampini     for (PetscInt i = 0, c = 0; i < nr && valid; i++) {
10889de2952eSStefano Zampini       for (PetscInt j = 0; j < degree[i]; j++) {
10899de2952eSStefano Zampini         if (rdata[j + c] != rdata[c]) valid = PETSC_FALSE;
10909de2952eSStefano Zampini       }
10919de2952eSStefano Zampini       c += degree[i];
10929de2952eSStefano Zampini     }
10939de2952eSStefano Zampini     PetscCall(PetscFree(rdata));
10949de2952eSStefano Zampini     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &valid, 1, MPIU_BOOL, MPI_LAND, comm));
10959de2952eSStefano Zampini     PetscCheck(valid, comm, PETSC_ERR_PLIB, "Initial local subsets are not consistent");
10969de2952eSStefano Zampini 
10979de2952eSStefano Zampini     /* Now create SF with each root extended to gsubset_size roots */
1098e4ebd542SJose E. Roman     PetscInt           mss = 0;
10999de2952eSStefano Zampini     const PetscSFNode *subs_remote;
11009de2952eSStefano Zampini 
11019de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, NULL, NULL, NULL, &subs_remote));
1102e4ebd542SJose E. Roman     for (PetscInt i = 0; i < graph->n_subsets; i++) mss = PetscMax(graph->subset_size[i], mss);
11039de2952eSStefano Zampini 
11049de2952eSStefano Zampini     PetscInt nri, nli, *start_rsize, *cum_rsize;
11059de2952eSStefano Zampini     PetscCall(PetscCalloc1(graph->n_subsets + 1, &start_rsize));
11069de2952eSStefano Zampini     PetscCall(PetscCalloc1(nr, &graph->interface_ref_rsize));
11079de2952eSStefano Zampini     PetscCall(PetscMalloc1(nr + 1, &cum_rsize));
11089de2952eSStefano Zampini     PetscCall(PetscSFReduceBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE));
11099de2952eSStefano Zampini     PetscCall(PetscSFReduceEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE));
11109de2952eSStefano Zampini 
11119de2952eSStefano Zampini     nri          = 0;
11129de2952eSStefano Zampini     cum_rsize[0] = 0;
1113e4ebd542SJose E. Roman     for (PetscInt i = 0; i < nr; i++) {
11149de2952eSStefano Zampini       nri += graph->interface_ref_rsize[i];
11159de2952eSStefano Zampini       cum_rsize[i + 1] = cum_rsize[i] + graph->interface_ref_rsize[i];
11169de2952eSStefano Zampini     }
11179de2952eSStefano Zampini     nli = graph->cptr[graph->ncc];
11189de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE));
11199de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE));
11209de2952eSStefano Zampini     PetscCall(PetscFree(cum_rsize));
11219de2952eSStefano Zampini 
11229de2952eSStefano Zampini     PetscInt    *ilocal, *queue_global_uniq;
11239de2952eSStefano Zampini     PetscSFNode *iremote;
11249de2952eSStefano Zampini     PetscBool   *touched;
11259de2952eSStefano Zampini 
11269de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &graph->interface_subset_sf));
11279de2952eSStefano Zampini     PetscCall(PetscMalloc1(nli, &ilocal));
11289de2952eSStefano Zampini     PetscCall(PetscMalloc1(nli, &iremote));
11299de2952eSStefano Zampini     PetscCall(PetscMalloc2(mss, &queue_global_uniq, mss, &touched));
1130e4ebd542SJose E. Roman     for (PetscInt i = 0, nli = 0; i < graph->n_subsets; i++) {
11316497c311SBarry Smith       const PetscMPIInt rr                = (PetscMPIInt)subs_remote[i].rank;
11329de2952eSStefano Zampini       const PetscInt    start             = start_rsize[i];
11339de2952eSStefano Zampini       const PetscInt    subset_size       = graph->subset_size[i];
11349de2952eSStefano Zampini       const PetscInt    gsubset_size      = graph->gsubset_size[i];
11359de2952eSStefano Zampini       const PetscInt   *subset_idxs       = graph->subset_idxs[i];
11369de2952eSStefano Zampini       const PetscInt   *lsub_queue_global = queue_global + graph->cptr[i];
11379de2952eSStefano Zampini 
11389de2952eSStefano Zampini       k = subset_size;
11399de2952eSStefano Zampini       PetscCall(PetscArrayzero(touched, subset_size));
11409de2952eSStefano Zampini       PetscCall(PetscArraycpy(queue_global_uniq, lsub_queue_global, subset_size));
11419de2952eSStefano Zampini       PetscCall(PetscSortRemoveDupsInt(&k, queue_global_uniq));
11429de2952eSStefano Zampini       PetscCheck(k == gsubset_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid local subset %" PetscInt_FMT " size %" PetscInt_FMT " != %" PetscInt_FMT, i, k, gsubset_size);
11439de2952eSStefano Zampini 
11449de2952eSStefano Zampini       PetscInt t = 0, j = 0;
11459de2952eSStefano Zampini       while (t < subset_size) {
11469de2952eSStefano Zampini         while (j < subset_size && touched[j]) j++;
11479de2952eSStefano Zampini         PetscCheck(j < subset_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " >= %" PetscInt_FMT, j, subset_size);
11489de2952eSStefano Zampini         const PetscInt ls = graph->nodes[subset_idxs[j]].local_sub;
11499de2952eSStefano Zampini 
11509de2952eSStefano Zampini         for (k = j; k < subset_size; k++) {
11519de2952eSStefano Zampini           if (graph->nodes[subset_idxs[k]].local_sub == ls) {
11529de2952eSStefano Zampini             PetscInt ig;
11539de2952eSStefano Zampini 
11549de2952eSStefano Zampini             PetscCall(PetscFindInt(lsub_queue_global[k], gsubset_size, queue_global_uniq, &ig));
11559de2952eSStefano Zampini             ilocal[nli]        = subset_idxs[k];
11569de2952eSStefano Zampini             iremote[nli].rank  = rr;
11579de2952eSStefano Zampini             iremote[nli].index = start + ig;
11589de2952eSStefano Zampini             touched[k]         = PETSC_TRUE;
11599de2952eSStefano Zampini             nli++;
11609de2952eSStefano Zampini             t++;
11619de2952eSStefano Zampini           }
11629de2952eSStefano Zampini         }
11639de2952eSStefano Zampini       }
11649de2952eSStefano Zampini     }
11659de2952eSStefano Zampini     PetscCheck(nli == graph->cptr[graph->ncc], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid ilocal size %" PetscInt_FMT " != %" PetscInt_FMT, nli, graph->cptr[graph->ncc]);
11669de2952eSStefano Zampini     PetscCall(PetscSFSetGraph(graph->interface_subset_sf, nri, nli, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
11679de2952eSStefano Zampini     PetscCall(PetscFree(start_rsize));
11689de2952eSStefano Zampini     PetscCall(PetscFree2(queue_global_uniq, touched));
11699de2952eSStefano Zampini   }
11709de2952eSStefano Zampini   PetscCall(PetscFree(queue_global));
1171ec1c413dSStefano Zampini 
1172ec1c413dSStefano Zampini   /* free workspace */
1173b3cdcd63SStefano Zampini   graph->setupcalled = PETSC_TRUE;
11743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1175674ae819SStefano Zampini }
1176674ae819SStefano Zampini 
1177d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphResetCoords(PCBDDCGraph graph)
1178d71ae5a4SJacob Faibussowitsch {
1179ab8c8b98SStefano Zampini   PetscFunctionBegin;
11803ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
11819566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->coords));
1182ab8c8b98SStefano Zampini   graph->cdim  = 0;
1183ab8c8b98SStefano Zampini   graph->cnloc = 0;
1184ab8c8b98SStefano Zampini   graph->cloc  = PETSC_FALSE;
11853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1186ab8c8b98SStefano Zampini }
1187ab8c8b98SStefano Zampini 
1188d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphResetCSR(PCBDDCGraph graph)
1189d71ae5a4SJacob Faibussowitsch {
1190674ae819SStefano Zampini   PetscFunctionBegin;
11913ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
1192a1dbd327SStefano Zampini   if (graph->freecsr) {
11939566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph->xadj));
11949566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph->adjncy));
1195a1dbd327SStefano Zampini   } else {
1196a1dbd327SStefano Zampini     graph->xadj   = NULL;
1197a1dbd327SStefano Zampini     graph->adjncy = NULL;
1198a1dbd327SStefano Zampini   }
1199c8272957SStefano Zampini   graph->freecsr   = PETSC_FALSE;
1200575ad6abSStefano Zampini   graph->nvtxs_csr = 0;
12013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1202674ae819SStefano Zampini }
1203674ae819SStefano Zampini 
1204d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphReset(PCBDDCGraph graph)
1205d71ae5a4SJacob Faibussowitsch {
1206674ae819SStefano Zampini   PetscFunctionBegin;
12073ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
12089566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&graph->l2gmap));
12099566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->subset_ncc));
12109566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->subset_ref_node));
12119de2952eSStefano Zampini   for (PetscInt i = 0; i < graph->nvtxs; i++) {
12129de2952eSStefano Zampini     PetscCall(PetscFree(graph->nodes[i].neighbours_set));
12139de2952eSStefano Zampini     PetscCall(PetscFree(graph->nodes[i].local_groups));
12149de2952eSStefano Zampini   }
12159de2952eSStefano Zampini   PetscCall(PetscFree(graph->nodes));
12169566063dSJacob Faibussowitsch   PetscCall(PetscFree2(graph->cptr, graph->queue));
121748a46eb9SPierre Jolivet   if (graph->subset_idxs) PetscCall(PetscFree(graph->subset_idxs[0]));
12189566063dSJacob Faibussowitsch   PetscCall(PetscFree2(graph->subset_size, graph->subset_idxs));
12199de2952eSStefano Zampini   if (graph->multi_element) PetscCall(PetscFree(graph->gsubset_size));
12209de2952eSStefano Zampini   PetscCall(PetscFree(graph->interface_ref_rsize));
12219de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&graph->interface_subset_sf));
12229de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&graph->interface_ref_sf));
12239566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&graph->dirdofs));
12249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&graph->dirdofsB));
12251baa6e33SBarry Smith   if (graph->n_local_subs) PetscCall(PetscFree(graph->local_subs));
12269de2952eSStefano Zampini   graph->multi_element       = PETSC_FALSE;
1227a07ea27aSStefano Zampini   graph->has_dirichlet       = PETSC_FALSE;
1228cc0a5675Sstefano_zampini   graph->twodimset           = PETSC_FALSE;
1229cc0a5675Sstefano_zampini   graph->twodim              = PETSC_FALSE;
1230674ae819SStefano Zampini   graph->nvtxs               = 0;
12317babac9bSStefano Zampini   graph->nvtxs_global        = 0;
1232674ae819SStefano Zampini   graph->n_subsets           = 0;
1233674ae819SStefano Zampini   graph->custom_minimal_size = 1;
12344f1b2e48SStefano Zampini   graph->n_local_subs        = 0;
1235*1690c2aeSBarry Smith   graph->maxcount            = PETSC_INT_MAX;
12369de2952eSStefano Zampini   graph->seq_graph           = PETSC_FALSE;
1237fb597685SStefano Zampini   graph->setupcalled         = PETSC_FALSE;
12383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1239674ae819SStefano Zampini }
1240674ae819SStefano Zampini 
1241d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphInit(PCBDDCGraph graph, ISLocalToGlobalMapping l2gmap, PetscInt N, PetscInt maxcount)
1242d71ae5a4SJacob Faibussowitsch {
1243674ae819SStefano Zampini   PetscInt n;
1244674ae819SStefano Zampini 
1245674ae819SStefano Zampini   PetscFunctionBegin;
12464f572ea9SToby Isaac   PetscAssertPointer(graph, 1);
1247674ae819SStefano Zampini   PetscValidHeaderSpecific(l2gmap, IS_LTOGM_CLASSID, 2);
12487babac9bSStefano Zampini   PetscValidLogicalCollectiveInt(l2gmap, N, 3);
1249be12c134Sstefano_zampini   PetscValidLogicalCollectiveInt(l2gmap, maxcount, 4);
12508e61c736SStefano Zampini   /* raise an error if already allocated */
125128b400f6SJacob Faibussowitsch   PetscCheck(!graph->nvtxs_global, PetscObjectComm((PetscObject)l2gmap), PETSC_ERR_PLIB, "BDDCGraph already initialized");
1252674ae819SStefano Zampini   /* set number of vertices */
12539566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)l2gmap));
1254674ae819SStefano Zampini   graph->l2gmap = l2gmap;
12559566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
1256674ae819SStefano Zampini   graph->nvtxs        = n;
12577fb0e2dbSStefano Zampini   graph->nvtxs_global = N;
1258674ae819SStefano Zampini   /* allocate used space */
12599de2952eSStefano Zampini   PetscCall(PetscCalloc1(graph->nvtxs, &graph->nodes));
126063602bcaSStefano Zampini   /* use -1 as a default value for which_dof array */
12619de2952eSStefano Zampini   for (n = 0; n < graph->nvtxs; n++) graph->nodes[n].which_dof = -1;
12629de2952eSStefano Zampini 
1263674ae819SStefano Zampini   /* zeroes workspace for values of ncc */
12640a545947SLisandro Dalcin   graph->subset_ncc      = NULL;
12650a545947SLisandro Dalcin   graph->subset_ref_node = NULL;
1266be12c134Sstefano_zampini   /* maxcount for cc */
1267be12c134Sstefano_zampini   graph->maxcount = maxcount;
12683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1269674ae819SStefano Zampini }
1270674ae819SStefano Zampini 
1271d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphDestroy(PCBDDCGraph *graph)
1272d71ae5a4SJacob Faibussowitsch {
1273674ae819SStefano Zampini   PetscFunctionBegin;
12749566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(*graph));
12759566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCoords(*graph));
12769566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphReset(*graph));
12779566063dSJacob Faibussowitsch   PetscCall(PetscFree(*graph));
12783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1279674ae819SStefano Zampini }
1280674ae819SStefano Zampini 
1281d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphCreate(PCBDDCGraph *graph)
1282d71ae5a4SJacob Faibussowitsch {
1283674ae819SStefano Zampini   PCBDDCGraph new_graph;
1284674ae819SStefano Zampini 
1285674ae819SStefano Zampini   PetscFunctionBegin;
12869566063dSJacob Faibussowitsch   PetscCall(PetscNew(&new_graph));
1287674ae819SStefano Zampini   new_graph->custom_minimal_size = 1;
1288674ae819SStefano Zampini   *graph                         = new_graph;
12893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1290674ae819SStefano Zampini }
1291