xref: /petsc/src/ksp/pc/impls/bddc/bddcgraph.c (revision 9de2952e64edfa51c4ec5537730b8a834bdd3686)
1af0996ceSBarry Smith #include <petsc/private/petscimpl.h>
25e5bbd0aSStefano Zampini #include <petsc/private/pcbddcprivateimpl.h>
35e5bbd0aSStefano Zampini #include <petsc/private/pcbddcstructsimpl.h>
4*9de2952eSStefano Zampini #include <petsc/private/hashmapi.h>
5*9de2952eSStefano 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++) {
32*9de2952eSStefano 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++) {
38*9de2952eSStefano 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++) {
58*9de2952eSStefano 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++) {
64*9de2952eSStefano 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;
799566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
809566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
819566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "--------------------------------------------------\n"));
829566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
83*9de2952eSStefano Zampini   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Local BDDC graph for subdomain %04d (seq %d)\n", PetscGlobalRank, graph->seq_graph));
8463a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of vertices %" PetscInt_FMT "\n", graph->nvtxs));
8563a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of local subdomains %" PetscInt_FMT "\n", graph->n_local_subs ? graph->n_local_subs : 1));
8663a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Custom minimal size %" PetscInt_FMT "\n", graph->custom_minimal_size));
8748a46eb9SPierre Jolivet   if (graph->maxcount != PETSC_MAX_INT) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Max count %" PetscInt_FMT "\n", graph->maxcount));
8863a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Topological two dim? %s (set %s)\n", PetscBools[graph->twodim], PetscBools[graph->twodimset]));
89d4890cceSStefano Zampini   if (verbosity_level > 2) {
90674ae819SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
9163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":\n", i));
92*9de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   which_dof: %" PetscInt_FMT "\n", graph->nodes[i].which_dof));
93*9de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   special_dof: %" PetscInt_FMT "\n", graph->nodes[i].special_dof));
94*9de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   shared by: %" PetscInt_FMT "\n", graph->nodes[i].count));
959566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
96*9de2952eSStefano Zampini       if (graph->nodes[i].count) {
979566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     set of neighbours:"));
98*9de2952eSStefano Zampini         for (j = 0; j < graph->nodes[i].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].neighbours_set[j]));
999566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
100674ae819SStefano Zampini       }
1019566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1029566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
103*9de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   number of local groups: %" PetscInt_FMT "\n", graph->nodes[i].local_groups_count));
1049566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
105*9de2952eSStefano Zampini       if (graph->nodes[i].local_groups_count) {
106*9de2952eSStefano Zampini         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     groups:"));
107*9de2952eSStefano Zampini         for (j = 0; j < graph->nodes[i].local_groups_count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].local_groups[j]));
1089566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
109*9de2952eSStefano Zampini       }
1109566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1119566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
112*9de2952eSStefano Zampini 
113d4890cceSStefano Zampini       if (verbosity_level > 3) {
1141633d1f0SStefano Zampini         if (graph->xadj) {
1159566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   local adj list:"));
1169566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
11748a46eb9SPierre Jolivet           for (j = graph->xadj[i]; j < graph->xadj[i + 1]; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->adjncy[j]));
1189566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1199566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1209566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
121ec1c413dSStefano Zampini         } else {
1229566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   no adj info\n"));
123674ae819SStefano Zampini         }
124e49050b4SStefano Zampini       }
12548a46eb9SPierre Jolivet       if (graph->n_local_subs) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   local sub id: %" PetscInt_FMT "\n", graph->local_subs[i]));
126*9de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   interface subset id: %" PetscInt_FMT "\n", graph->nodes[i].subset));
127*9de2952eSStefano 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]));
128674ae819SStefano Zampini     }
129e49050b4SStefano Zampini   }
13063a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Total number of connected components %" PetscInt_FMT "\n", graph->ncc));
1319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_in_global_numbering));
1329566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_in_global_numbering));
133674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
1341ce3d396SStefano Zampini     PetscInt  node_num = graph->queue[graph->cptr[i]];
1351ce3d396SStefano Zampini     PetscBool printcc  = PETSC_FALSE;
136*9de2952eSStefano 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));
1379566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
138*9de2952eSStefano Zampini     for (j = 0; j < graph->nodes[node_num].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[node_num].neighbours_set[j]));
139d4890cceSStefano Zampini     if (verbosity_level > 1) {
1409566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "):"));
141*9de2952eSStefano 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; }
1421ce3d396SStefano Zampini       if (printcc) {
14348a46eb9SPierre 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]));
1441ce3d396SStefano Zampini       }
145d4890cceSStefano Zampini     } else {
1469566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ")"));
147d4890cceSStefano Zampini     }
1489566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1499566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
151674ae819SStefano Zampini   }
1529566063dSJacob Faibussowitsch   PetscCall(PetscFree(queue_in_global_numbering));
1539566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
1543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
155674ae819SStefano Zampini }
156674ae819SStefano Zampini 
157d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphRestoreCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS)
158d71ae5a4SJacob Faibussowitsch {
159c8272957SStefano Zampini   PetscInt       i;
16032fe681dSStefano Zampini   PetscContainer gcand;
161c8272957SStefano Zampini 
162c8272957SStefano Zampini   PetscFunctionBegin;
16332fe681dSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand));
16432fe681dSStefano Zampini   if (gcand) {
16532fe681dSStefano Zampini     if (n_faces) *n_faces = 0;
16632fe681dSStefano Zampini     if (n_edges) *n_edges = 0;
16732fe681dSStefano Zampini     if (FacesIS) *FacesIS = NULL;
16832fe681dSStefano Zampini     if (EdgesIS) *EdgesIS = NULL;
16932fe681dSStefano Zampini     if (VerticesIS) *VerticesIS = NULL;
17032fe681dSStefano Zampini   }
171c8272957SStefano Zampini   if (n_faces) {
172c8272957SStefano Zampini     if (FacesIS) {
17348a46eb9SPierre Jolivet       for (i = 0; i < *n_faces; i++) PetscCall(ISDestroy(&((*FacesIS)[i])));
1749566063dSJacob Faibussowitsch       PetscCall(PetscFree(*FacesIS));
175c8272957SStefano Zampini     }
176c8272957SStefano Zampini     *n_faces = 0;
177c8272957SStefano Zampini   }
178c8272957SStefano Zampini   if (n_edges) {
179c8272957SStefano Zampini     if (EdgesIS) {
18048a46eb9SPierre Jolivet       for (i = 0; i < *n_edges; i++) PetscCall(ISDestroy(&((*EdgesIS)[i])));
1819566063dSJacob Faibussowitsch       PetscCall(PetscFree(*EdgesIS));
182c8272957SStefano Zampini     }
183c8272957SStefano Zampini     *n_edges = 0;
184c8272957SStefano Zampini   }
1851baa6e33SBarry Smith   if (VerticesIS) PetscCall(ISDestroy(VerticesIS));
1863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
187c8272957SStefano Zampini }
188c8272957SStefano Zampini 
189d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphGetCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS)
190d71ae5a4SJacob Faibussowitsch {
191674ae819SStefano Zampini   IS            *ISForFaces, *ISForEdges, ISForVertices;
192be12c134Sstefano_zampini   PetscInt       i, nfc, nec, nvc, *idx, *mark;
19332fe681dSStefano Zampini   PetscContainer gcand;
194674ae819SStefano Zampini 
195674ae819SStefano Zampini   PetscFunctionBegin;
19632fe681dSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand));
19732fe681dSStefano Zampini   if (gcand) {
19832fe681dSStefano Zampini     PCBDDCGraphCandidates cand;
19932fe681dSStefano Zampini 
20032fe681dSStefano Zampini     PetscCall(PetscContainerGetPointer(gcand, (void **)&cand));
20132fe681dSStefano Zampini     if (n_faces) *n_faces = cand->nfc;
20232fe681dSStefano Zampini     if (FacesIS) *FacesIS = cand->Faces;
20332fe681dSStefano Zampini     if (n_edges) *n_edges = cand->nec;
20432fe681dSStefano Zampini     if (EdgesIS) *EdgesIS = cand->Edges;
20532fe681dSStefano Zampini     if (VerticesIS) *VerticesIS = cand->Vertices;
2063ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20732fe681dSStefano Zampini   }
2089566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(graph->ncc, &mark));
209da81f932SPierre Jolivet   /* loop on ccs to evaluate number of faces, edges and vertices */
210674ae819SStefano Zampini   nfc = 0;
211674ae819SStefano Zampini   nec = 0;
212674ae819SStefano Zampini   nvc = 0;
213674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
2141e1f2d93SStefano Zampini     PetscInt repdof = graph->queue[graph->cptr[i]];
215*9de2952eSStefano Zampini     if (graph->cptr[i + 1] - graph->cptr[i] > graph->custom_minimal_size && graph->nodes[repdof].count <= graph->maxcount) {
216*9de2952eSStefano Zampini       if (!graph->twodim && graph->nodes[repdof].count == 2 && graph->nodes[repdof].special_dof != PCBDDCGRAPH_NEUMANN_MARK) {
217674ae819SStefano Zampini         nfc++;
218be12c134Sstefano_zampini         mark[i] = 2;
219be12c134Sstefano_zampini       } else {
220674ae819SStefano Zampini         nec++;
221be12c134Sstefano_zampini         mark[i] = 1;
222674ae819SStefano Zampini       }
223674ae819SStefano Zampini     } else {
224674ae819SStefano Zampini       nvc += graph->cptr[i + 1] - graph->cptr[i];
225674ae819SStefano Zampini     }
226674ae819SStefano Zampini   }
227adfc4fb2SStefano Zampini 
228674ae819SStefano Zampini   /* allocate IS arrays for faces, edges. Vertices need a single index set. */
22948a46eb9SPierre Jolivet   if (FacesIS) PetscCall(PetscMalloc1(nfc, &ISForFaces));
23048a46eb9SPierre Jolivet   if (EdgesIS) PetscCall(PetscMalloc1(nec, &ISForEdges));
23148a46eb9SPierre Jolivet   if (VerticesIS) PetscCall(PetscMalloc1(nvc, &idx));
232cf5a6209SStefano Zampini 
233674ae819SStefano Zampini   /* loop on ccs to compute index sets for faces and edges */
234acc113dbSStefano Zampini   if (!graph->queue_sorted) {
235acc113dbSStefano Zampini     PetscInt *queue_global;
236acc113dbSStefano Zampini 
2379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global));
2389566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global));
23948a46eb9SPierre 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]]));
2409566063dSJacob Faibussowitsch     PetscCall(PetscFree(queue_global));
241acc113dbSStefano Zampini     graph->queue_sorted = PETSC_TRUE;
242acc113dbSStefano Zampini   }
243674ae819SStefano Zampini   nfc = 0;
244674ae819SStefano Zampini   nec = 0;
245674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
246be12c134Sstefano_zampini     if (mark[i] == 2) {
24748a46eb9SPierre 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]));
248674ae819SStefano Zampini       nfc++;
249be12c134Sstefano_zampini     } else if (mark[i] == 1) {
25048a46eb9SPierre 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]));
251674ae819SStefano Zampini       nec++;
252674ae819SStefano Zampini     }
253674ae819SStefano Zampini   }
254be12c134Sstefano_zampini 
255674ae819SStefano Zampini   /* index set for vertices */
256cf5a6209SStefano Zampini   if (VerticesIS) {
257b8ffe317SStefano Zampini     nvc = 0;
258674ae819SStefano Zampini     for (i = 0; i < graph->ncc; i++) {
259be12c134Sstefano_zampini       if (!mark[i]) {
260adfc4fb2SStefano Zampini         PetscInt j;
261adfc4fb2SStefano Zampini 
262674ae819SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
263674ae819SStefano Zampini           idx[nvc] = graph->queue[j];
264674ae819SStefano Zampini           nvc++;
265674ae819SStefano Zampini         }
266674ae819SStefano Zampini       }
267674ae819SStefano Zampini     }
268674ae819SStefano Zampini     /* sort vertex set (by local ordering) */
2699566063dSJacob Faibussowitsch     PetscCall(PetscSortInt(nvc, idx));
2709566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nvc, idx, PETSC_OWN_POINTER, &ISForVertices));
271674ae819SStefano Zampini   }
2729566063dSJacob Faibussowitsch   PetscCall(PetscFree(mark));
273be12c134Sstefano_zampini 
274674ae819SStefano Zampini   /* get back info */
275a873d5d0SStefano Zampini   if (n_faces) *n_faces = nfc;
276c8272957SStefano Zampini   if (FacesIS) *FacesIS = ISForFaces;
277a873d5d0SStefano Zampini   if (n_edges) *n_edges = nec;
278c8272957SStefano Zampini   if (EdgesIS) *EdgesIS = ISForEdges;
279c8272957SStefano Zampini   if (VerticesIS) *VerticesIS = ISForVertices;
2803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
281674ae819SStefano Zampini }
282674ae819SStefano Zampini 
283d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphComputeConnectedComponents(PCBDDCGraph graph)
284d71ae5a4SJacob Faibussowitsch {
285*9de2952eSStefano Zampini   PetscBool adapt_interface;
286674ae819SStefano Zampini   MPI_Comm  interface_comm;
287*9de2952eSStefano Zampini   PetscBT   cornerp = NULL;
288674ae819SStefano Zampini 
289674ae819SStefano Zampini   PetscFunctionBegin;
290f4f49eeaSPierre Jolivet   PetscCall(PetscObjectGetComm((PetscObject)graph->l2gmap, &interface_comm));
291*9de2952eSStefano Zampini   /* compute connected components locally */
2929566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponentsLocal(graph));
293*9de2952eSStefano Zampini   if (graph->seq_graph) PetscFunctionReturn(PETSC_SUCCESS);
2941c7a958bSStefano Zampini 
295*9de2952eSStefano Zampini   if (graph->active_coords && !graph->multi_element) { /* face based corner selection XXX multi_element */
2964f819b78SStefano Zampini     PetscBT    excluded;
2971c7a958bSStefano Zampini     PetscReal *wdist;
2981c7a958bSStefano Zampini     PetscInt   n_neigh, *neigh, *n_shared, **shared;
2991c7a958bSStefano Zampini     PetscInt   maxc, ns;
3001c7a958bSStefano Zampini 
3019566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(graph->nvtxs, &cornerp));
3029566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
3031c7a958bSStefano Zampini     for (ns = 1, maxc = 0; ns < n_neigh; ns++) maxc = PetscMax(maxc, n_shared[ns]);
3049566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxc * graph->cdim, &wdist));
3059566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(maxc, &excluded));
3061c7a958bSStefano Zampini 
3071c7a958bSStefano Zampini     for (ns = 1; ns < n_neigh; ns++) { /* first proc is self */
3081c7a958bSStefano Zampini       PetscReal *anchor, mdist;
3094f819b78SStefano Zampini       PetscInt   fst, j, k, d, cdim = graph->cdim, n = n_shared[ns];
31051ab8ad6SStefano Zampini       PetscInt   point1, point2, point3, point4;
3111c7a958bSStefano Zampini 
3121c7a958bSStefano Zampini       /* import coordinates on shared interface */
3139566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(n, excluded));
3144f819b78SStefano Zampini       for (j = 0, fst = -1, k = 0; j < n; j++) {
3154f819b78SStefano Zampini         PetscBool skip = PETSC_FALSE;
3164f819b78SStefano Zampini         for (d = 0; d < cdim; d++) {
3174f819b78SStefano Zampini           PetscReal c = graph->coords[shared[ns][j] * cdim + d];
3184f819b78SStefano Zampini           skip        = (PetscBool)(skip || c == PETSC_MAX_REAL);
3194f819b78SStefano Zampini           wdist[k++]  = c;
3204f819b78SStefano Zampini         }
3214f819b78SStefano Zampini         if (skip) {
3229566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(excluded, j));
3234f819b78SStefano Zampini         } else if (fst == -1) fst = j;
3244f819b78SStefano Zampini       }
3254f819b78SStefano Zampini       if (fst == -1) continue;
3261c7a958bSStefano Zampini 
32751ab8ad6SStefano Zampini       /* the dofs are sorted by global numbering, so each rank starts from the same id
32851ab8ad6SStefano Zampini          and it will detect the same corners from the given set */
3291c7a958bSStefano Zampini 
3301c7a958bSStefano Zampini       /* find the farthest point from the starting one */
33151ab8ad6SStefano Zampini       anchor = wdist + fst * cdim;
3321c7a958bSStefano Zampini       mdist  = -1.0;
3334f819b78SStefano Zampini       point1 = fst;
3344f819b78SStefano Zampini       for (j = fst; j < n; j++) {
3351c7a958bSStefano Zampini         PetscReal dist = 0.0;
3361c7a958bSStefano Zampini 
3374f819b78SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
3381c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]);
3399371c9d4SSatish Balay         if (dist > mdist) {
3409371c9d4SSatish Balay           mdist  = dist;
3419371c9d4SSatish Balay           point1 = j;
3429371c9d4SSatish Balay         }
3431c7a958bSStefano Zampini       }
3441c7a958bSStefano Zampini 
3451c7a958bSStefano Zampini       /* find the farthest point from point1 */
3461c7a958bSStefano Zampini       anchor = wdist + point1 * cdim;
3471c7a958bSStefano Zampini       mdist  = -1.0;
3484f819b78SStefano Zampini       point2 = point1;
3494f819b78SStefano Zampini       for (j = fst; j < n; j++) {
3501c7a958bSStefano Zampini         PetscReal dist = 0.0;
3511c7a958bSStefano Zampini 
3524f819b78SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
3531c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]);
3549371c9d4SSatish Balay         if (dist > mdist) {
3559371c9d4SSatish Balay           mdist  = dist;
3569371c9d4SSatish Balay           point2 = j;
3579371c9d4SSatish Balay         }
3581c7a958bSStefano Zampini       }
3591c7a958bSStefano Zampini 
3601c7a958bSStefano Zampini       /* find the third point maximizing the triangle area */
3611c7a958bSStefano Zampini       point3 = point2;
3621c7a958bSStefano Zampini       if (cdim > 2) {
3631c7a958bSStefano Zampini         PetscReal a = 0.0;
3641c7a958bSStefano Zampini 
3651c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) a += (wdist[point1 * cdim + d] - wdist[point2 * cdim + d]) * (wdist[point1 * cdim + d] - wdist[point2 * cdim + d]);
366fff73eb4SStefano Zampini         a     = PetscSqrtReal(a);
3671c7a958bSStefano Zampini         mdist = -1.0;
3684f819b78SStefano Zampini         for (j = fst; j < n; j++) {
369fff73eb4SStefano Zampini           PetscReal area, b = 0.0, c = 0.0, s;
3701c7a958bSStefano Zampini 
3714f819b78SStefano Zampini           if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
3721c7a958bSStefano Zampini           for (d = 0; d < cdim; d++) {
3731c7a958bSStefano Zampini             b += (wdist[point1 * cdim + d] - wdist[j * cdim + d]) * (wdist[point1 * cdim + d] - wdist[j * cdim + d]);
3741c7a958bSStefano Zampini             c += (wdist[point2 * cdim + d] - wdist[j * cdim + d]) * (wdist[point2 * cdim + d] - wdist[j * cdim + d]);
3751c7a958bSStefano Zampini           }
376fff73eb4SStefano Zampini           b = PetscSqrtReal(b);
377fff73eb4SStefano Zampini           c = PetscSqrtReal(c);
378fff73eb4SStefano Zampini           s = 0.5 * (a + b + c);
3794f819b78SStefano Zampini 
3804f819b78SStefano Zampini           /* Heron's formula, area squared */
3814f819b78SStefano Zampini           area = s * (s - a) * (s - b) * (s - c);
3829371c9d4SSatish Balay           if (area > mdist) {
3839371c9d4SSatish Balay             mdist  = area;
3849371c9d4SSatish Balay             point3 = j;
3859371c9d4SSatish Balay           }
3861c7a958bSStefano Zampini         }
3871c7a958bSStefano Zampini       }
3881c7a958bSStefano Zampini 
38951ab8ad6SStefano Zampini       /* find the farthest point from point3 different from point1 and point2 */
39051ab8ad6SStefano Zampini       anchor = wdist + point3 * cdim;
39151ab8ad6SStefano Zampini       mdist  = -1.0;
39251ab8ad6SStefano Zampini       point4 = point3;
39351ab8ad6SStefano Zampini       for (j = fst; j < n; j++) {
39451ab8ad6SStefano Zampini         PetscReal dist = 0.0;
39551ab8ad6SStefano Zampini 
39651ab8ad6SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j)) || j == point1 || j == point2 || j == point3) continue;
39751ab8ad6SStefano Zampini         for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]);
3989371c9d4SSatish Balay         if (dist > mdist) {
3999371c9d4SSatish Balay           mdist  = dist;
4009371c9d4SSatish Balay           point4 = j;
4019371c9d4SSatish Balay         }
40251ab8ad6SStefano Zampini       }
40351ab8ad6SStefano Zampini 
4049566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(cornerp, shared[ns][point1]));
4059566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(cornerp, shared[ns][point2]));
4069566063dSJacob Faibussowitsch       PetscCall(PetscBTSet(cornerp, shared[ns][point3]));
40751ab8ad6SStefano Zampini       PetscCall(PetscBTSet(cornerp, shared[ns][point4]));
4084f819b78SStefano Zampini 
4091c7a958bSStefano Zampini       /* all dofs having the same coordinates will be primal */
4104f819b78SStefano Zampini       for (j = fst; j < n; j++) {
41151ab8ad6SStefano Zampini         PetscBool same[] = {PETSC_TRUE, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE};
4121c7a958bSStefano Zampini 
4134f819b78SStefano Zampini         if (PetscUnlikely(PetscBTLookup(excluded, j))) continue;
4141c7a958bSStefano Zampini         for (d = 0; d < cdim; d++) {
4151c7a958bSStefano Zampini           same[0] = (PetscBool)(same[0] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point1 * cdim + d]) < PETSC_SMALL));
4161c7a958bSStefano Zampini           same[1] = (PetscBool)(same[1] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point2 * cdim + d]) < PETSC_SMALL));
4171c7a958bSStefano Zampini           same[2] = (PetscBool)(same[2] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point3 * cdim + d]) < PETSC_SMALL));
41851ab8ad6SStefano Zampini           same[3] = (PetscBool)(same[3] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point4 * cdim + d]) < PETSC_SMALL));
4191c7a958bSStefano Zampini         }
42048a46eb9SPierre Jolivet         if (same[0] || same[1] || same[2] || same[3]) PetscCall(PetscBTSet(cornerp, shared[ns][j]));
4211c7a958bSStefano Zampini       }
4221c7a958bSStefano Zampini     }
4239566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&excluded));
4249566063dSJacob Faibussowitsch     PetscCall(PetscFree(wdist));
4259566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
4261c7a958bSStefano Zampini   }
4271c7a958bSStefano Zampini 
428*9de2952eSStefano Zampini   /* Adapt connected components if needed */
429*9de2952eSStefano Zampini   adapt_interface = (cornerp || graph->multi_element) ? PETSC_TRUE : PETSC_FALSE;
430*9de2952eSStefano Zampini   for (PetscInt i = 0; i < graph->n_subsets && !adapt_interface; i++) {
4311c7a958bSStefano Zampini     if (graph->subset_ncc[i] > 1) adapt_interface = PETSC_TRUE;
432674ae819SStefano Zampini   }
433*9de2952eSStefano Zampini   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &adapt_interface, 1, MPIU_BOOL, MPI_LOR, interface_comm));
434*9de2952eSStefano Zampini   if (adapt_interface) {
435*9de2952eSStefano Zampini     PetscSF         msf;
436*9de2952eSStefano Zampini     const PetscInt *n_ref_sharing;
437*9de2952eSStefano Zampini     PetscInt       *labels, *rootlabels, *mrlabels;
438*9de2952eSStefano Zampini     PetscInt        nr, nmr, nrs, ncc, cum_queue;
439674ae819SStefano Zampini 
4409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->nvtxs, &labels));
4419566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(labels, graph->nvtxs));
442*9de2952eSStefano Zampini     for (PetscInt i = 0, k = 0; i < graph->ncc; i++) {
4431c7a958bSStefano Zampini       PetscInt s = 1;
444*9de2952eSStefano Zampini       for (PetscInt j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
4451c7a958bSStefano Zampini         if (cornerp && PetscBTLookup(cornerp, graph->queue[j])) {
446*9de2952eSStefano Zampini           labels[graph->queue[j]] = -(k + s + 1);
4471c7a958bSStefano Zampini           s += 1;
4481c7a958bSStefano Zampini         } else {
449*9de2952eSStefano Zampini           labels[graph->queue[j]] = -(k + 1);
4501c7a958bSStefano Zampini         }
4511c7a958bSStefano Zampini       }
4521c7a958bSStefano Zampini       k += s;
4531c7a958bSStefano Zampini     }
454*9de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, &nr, NULL, NULL, NULL));
455*9de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_subset_sf, &nrs, NULL, NULL, NULL));
456*9de2952eSStefano Zampini     PetscCall(PetscSFGetMultiSF(graph->interface_subset_sf, &msf));
457*9de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
458*9de2952eSStefano Zampini     PetscCall(PetscCalloc2(nmr, &mrlabels, nrs, &rootlabels));
459b3cdcd63SStefano Zampini 
460*9de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeBegin(graph->interface_subset_sf, &n_ref_sharing));
461*9de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeEnd(graph->interface_subset_sf, &n_ref_sharing));
462*9de2952eSStefano Zampini     PetscCall(PetscSFGatherBegin(graph->interface_subset_sf, MPIU_INT, labels, mrlabels));
463*9de2952eSStefano Zampini     PetscCall(PetscSFGatherEnd(graph->interface_subset_sf, MPIU_INT, labels, mrlabels));
464b3cdcd63SStefano Zampini 
465*9de2952eSStefano Zampini     /* analyze contributions from processes
466*9de2952eSStefano Zampini        The structure of mrlabels is suitable to find intersections of ccs.
467*9de2952eSStefano Zampini        supposing the root subset has dimension 5 and leaves with labels:
468*9de2952eSStefano Zampini          0: [4 4 7 4 7], (2 connected components)
469*9de2952eSStefano Zampini          1: [3 2 2 3 2], (2 connected components)
470*9de2952eSStefano Zampini          2: [1 1 6 5 6], (3 connected components)
471*9de2952eSStefano Zampini        the multiroot data and the new labels corresponding to intersected connected components will be (column major)
472b3cdcd63SStefano Zampini 
473*9de2952eSStefano Zampini                   4 4 7 4 7
474*9de2952eSStefano Zampini        mrlabels   3 2 2 3 2
475*9de2952eSStefano Zampini                   1 1 6 5 6
476*9de2952eSStefano Zampini                   ---------
477*9de2952eSStefano Zampini        rootlabels 0 1 2 3 2
478*9de2952eSStefano Zampini     */
479*9de2952eSStefano Zampini     for (PetscInt i = 0, rcumlabels = 0, mcumlabels = 0; i < nr; i++) {
480*9de2952eSStefano Zampini       const PetscInt  subset_size    = graph->interface_ref_rsize[i];
481*9de2952eSStefano Zampini       const PetscInt *n_sharing      = n_ref_sharing + rcumlabels;
482*9de2952eSStefano Zampini       const PetscInt *mrbuffer       = mrlabels + mcumlabels;
483*9de2952eSStefano Zampini       PetscInt       *rbuffer        = rootlabels + rcumlabels;
484b3cdcd63SStefano Zampini       PetscInt        subset_counter = 0;
485ec1c413dSStefano Zampini 
486*9de2952eSStefano Zampini       for (PetscInt j = 0; j < subset_size; j++) {
487*9de2952eSStefano Zampini         if (!rbuffer[j]) { /* found a new cc  */
488*9de2952eSStefano Zampini           const PetscInt *jlabels = mrbuffer + j * n_sharing[0];
489*9de2952eSStefano Zampini           rbuffer[j]              = ++subset_counter;
490ec1c413dSStefano Zampini 
491*9de2952eSStefano Zampini           for (PetscInt k = j + 1; k < subset_size; k++) { /* check for other nodes in new cc */
492*9de2952eSStefano Zampini             PetscBool       same_set = PETSC_TRUE;
493*9de2952eSStefano Zampini             const PetscInt *klabels  = mrbuffer + k * n_sharing[0];
494*9de2952eSStefano Zampini 
495*9de2952eSStefano Zampini             for (PetscInt s = 0; s < n_sharing[0]; s++) {
496*9de2952eSStefano Zampini               if (jlabels[s] != klabels[s]) {
497674ae819SStefano Zampini                 same_set = PETSC_FALSE;
498674ae819SStefano Zampini                 break;
499674ae819SStefano Zampini               }
500674ae819SStefano Zampini             }
501*9de2952eSStefano Zampini             if (same_set) rbuffer[k] = subset_counter;
502674ae819SStefano Zampini           }
503674ae819SStefano Zampini         }
504674ae819SStefano Zampini       }
505*9de2952eSStefano Zampini       if (subset_size) {
506*9de2952eSStefano Zampini         rcumlabels += subset_size;
507*9de2952eSStefano Zampini         mcumlabels += n_sharing[0] * subset_size;
508674ae819SStefano Zampini       }
509*9de2952eSStefano Zampini     }
510*9de2952eSStefano Zampini 
511*9de2952eSStefano Zampini     /* Now communicate the intersected labels */
512*9de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(graph->interface_subset_sf, MPIU_INT, rootlabels, labels, MPI_REPLACE));
513*9de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(graph->interface_subset_sf, MPIU_INT, rootlabels, labels, MPI_REPLACE));
514*9de2952eSStefano Zampini     PetscCall(PetscFree2(mrlabels, rootlabels));
515*9de2952eSStefano Zampini 
516*9de2952eSStefano Zampini     /* and adapt local connected components */
517*9de2952eSStefano Zampini     PetscInt  *ocptr, *oqueue;
518*9de2952eSStefano Zampini     PetscBool *touched;
519*9de2952eSStefano Zampini 
520*9de2952eSStefano Zampini     PetscCall(PetscMalloc3(graph->ncc + 1, &ocptr, graph->cptr[graph->ncc], &oqueue, graph->cptr[graph->ncc], &touched));
521*9de2952eSStefano Zampini     PetscCall(PetscArraycpy(ocptr, graph->cptr, graph->ncc + 1));
522*9de2952eSStefano Zampini     PetscCall(PetscArraycpy(oqueue, graph->queue, graph->cptr[graph->ncc]));
523*9de2952eSStefano Zampini     PetscCall(PetscArrayzero(touched, graph->cptr[graph->ncc]));
524*9de2952eSStefano Zampini 
525*9de2952eSStefano Zampini     ncc       = 0;
526*9de2952eSStefano Zampini     cum_queue = 0;
527*9de2952eSStefano Zampini     for (PetscInt i = 0; i < graph->ncc; i++) {
528*9de2952eSStefano Zampini       for (PetscInt j = ocptr[i]; j < ocptr[i + 1]; j++) {
529*9de2952eSStefano Zampini         const PetscInt jlabel = labels[oqueue[j]];
530*9de2952eSStefano Zampini 
531*9de2952eSStefano Zampini         if (jlabel) {
532b3cdcd63SStefano Zampini           graph->cptr[ncc] = cum_queue;
533b3cdcd63SStefano Zampini           ncc++;
534*9de2952eSStefano Zampini           for (PetscInt k = j; k < ocptr[i + 1]; k++) { /* check for other nodes in new cc */
535*9de2952eSStefano Zampini             if (labels[oqueue[k]] == jlabel) {
536*9de2952eSStefano Zampini               graph->queue[cum_queue++] = oqueue[k];
537*9de2952eSStefano Zampini               labels[oqueue[k]]         = 0;
538674ae819SStefano Zampini             }
539674ae819SStefano Zampini           }
540b3cdcd63SStefano Zampini         }
541*9de2952eSStefano Zampini       }
542*9de2952eSStefano Zampini     }
543*9de2952eSStefano Zampini     PetscCall(PetscFree3(ocptr, oqueue, touched));
5449566063dSJacob Faibussowitsch     PetscCall(PetscFree(labels));
545*9de2952eSStefano Zampini     graph->cptr[ncc]    = cum_queue;
546*9de2952eSStefano Zampini     graph->queue_sorted = PETSC_FALSE;
547*9de2952eSStefano Zampini     graph->ncc          = ncc;
548674ae819SStefano Zampini   }
5499566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&cornerp));
5508e4af1ccSStefano Zampini 
551cc0a5675Sstefano_zampini   /* Determine if we are in 2D or 3D */
552cc0a5675Sstefano_zampini   if (!graph->twodimset) {
553cc0a5675Sstefano_zampini     PetscBool twodim = PETSC_TRUE;
554*9de2952eSStefano Zampini     for (PetscInt i = 0; i < graph->ncc; i++) {
555cc0a5675Sstefano_zampini       PetscInt repdof = graph->queue[graph->cptr[i]];
556cc0a5675Sstefano_zampini       PetscInt ccsize = graph->cptr[i + 1] - graph->cptr[i];
557*9de2952eSStefano Zampini       if (graph->nodes[repdof].count > 2 && ccsize > graph->custom_minimal_size) {
558cc0a5675Sstefano_zampini         twodim = PETSC_FALSE;
559cc0a5675Sstefano_zampini         break;
560cc0a5675Sstefano_zampini       }
561cc0a5675Sstefano_zampini     }
5621c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&twodim, &graph->twodim, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)graph->l2gmap)));
563cc0a5675Sstefano_zampini     graph->twodimset = PETSC_TRUE;
564cc0a5675Sstefano_zampini   }
5653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
566674ae819SStefano Zampini }
567674ae819SStefano Zampini 
568*9de2952eSStefano Zampini static inline PetscErrorCode PCBDDCGraphComputeCC_Private(PCBDDCGraph graph, PetscInt pid, PetscInt *PETSC_RESTRICT queue_tip, PetscInt n_prev, PetscInt *n_added)
569d71ae5a4SJacob Faibussowitsch {
570*9de2952eSStefano Zampini   PetscInt i, j, n = 0;
571*9de2952eSStefano Zampini 
572*9de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT xadj        = graph->xadj;
573*9de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT adjncy      = graph->adjncy;
574*9de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT subset_idxs = graph->subset_idxs[pid - 1];
575*9de2952eSStefano Zampini   const PetscInt *PETSC_RESTRICT local_subs  = graph->local_subs;
576*9de2952eSStefano Zampini   const PetscInt                 subset_size = graph->subset_size[pid - 1];
577*9de2952eSStefano Zampini 
578*9de2952eSStefano Zampini   PCBDDCGraphNode *PETSC_RESTRICT nodes = graph->nodes;
579*9de2952eSStefano Zampini 
580*9de2952eSStefano Zampini   const PetscBool havecsr  = (PetscBool)(!!xadj);
581*9de2952eSStefano Zampini   const PetscBool havesubs = (PetscBool)(!!graph->n_local_subs);
582b3cdcd63SStefano Zampini 
583b3cdcd63SStefano Zampini   PetscFunctionBegin;
584b3cdcd63SStefano Zampini   if (havecsr && !havesubs) {
585b3cdcd63SStefano Zampini     for (i = -n_prev; i < 0; i++) {
586*9de2952eSStefano Zampini       const PetscInt start_dof = queue_tip[i];
587*9de2952eSStefano Zampini 
58854fffbccSStefano 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 */
58954fffbccSStefano Zampini       if (xadj[start_dof + 1] - xadj[start_dof] == 1 && adjncy[xadj[start_dof]] < 0) {
590*9de2952eSStefano Zampini         for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
591*9de2952eSStefano Zampini           const PetscInt dof = subset_idxs[j];
592*9de2952eSStefano Zampini 
593*9de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid) {
594*9de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
59554fffbccSStefano Zampini             queue_tip[n]       = dof;
59654fffbccSStefano Zampini             n++;
59754fffbccSStefano Zampini           }
59854fffbccSStefano Zampini         }
59954fffbccSStefano Zampini       } else {
600b3cdcd63SStefano Zampini         for (j = xadj[start_dof]; j < xadj[start_dof + 1]; j++) {
601*9de2952eSStefano Zampini           const PetscInt dof = adjncy[j];
602*9de2952eSStefano Zampini 
603*9de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid) {
604*9de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
605b3cdcd63SStefano Zampini             queue_tip[n]       = dof;
606b3cdcd63SStefano Zampini             n++;
607b3cdcd63SStefano Zampini           }
608b3cdcd63SStefano Zampini         }
609b3cdcd63SStefano Zampini       }
61054fffbccSStefano Zampini     }
611b3cdcd63SStefano Zampini   } else if (havecsr && havesubs) {
612*9de2952eSStefano Zampini     const PetscInt sid = local_subs[queue_tip[-n_prev]];
613*9de2952eSStefano Zampini 
614b3cdcd63SStefano Zampini     for (i = -n_prev; i < 0; i++) {
615*9de2952eSStefano Zampini       const PetscInt start_dof = queue_tip[i];
616*9de2952eSStefano Zampini 
61754fffbccSStefano 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 */
61854fffbccSStefano Zampini       if (xadj[start_dof + 1] - xadj[start_dof] == 1 && adjncy[xadj[start_dof]] < 0) {
619*9de2952eSStefano Zampini         for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
620*9de2952eSStefano Zampini           const PetscInt dof = subset_idxs[j];
621*9de2952eSStefano Zampini 
622*9de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) {
623*9de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
62454fffbccSStefano Zampini             queue_tip[n]       = dof;
62554fffbccSStefano Zampini             n++;
62654fffbccSStefano Zampini           }
62754fffbccSStefano Zampini         }
62854fffbccSStefano Zampini       } else {
629b3cdcd63SStefano Zampini         for (j = xadj[start_dof]; j < xadj[start_dof + 1]; j++) {
630*9de2952eSStefano Zampini           const PetscInt dof = adjncy[j];
631*9de2952eSStefano Zampini 
632*9de2952eSStefano Zampini           if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) {
633*9de2952eSStefano Zampini             nodes[dof].touched = PETSC_TRUE;
634b3cdcd63SStefano Zampini             queue_tip[n]       = dof;
635b3cdcd63SStefano Zampini             n++;
636b3cdcd63SStefano Zampini           }
637b3cdcd63SStefano Zampini         }
638b3cdcd63SStefano Zampini       }
63954fffbccSStefano Zampini     }
6401c7a958bSStefano Zampini   } else if (havesubs) { /* sub info only */
641*9de2952eSStefano Zampini     const PetscInt sid = local_subs[queue_tip[-n_prev]];
642*9de2952eSStefano Zampini 
643*9de2952eSStefano Zampini     for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
644*9de2952eSStefano Zampini       const PetscInt dof = subset_idxs[j];
645*9de2952eSStefano Zampini 
646*9de2952eSStefano Zampini       if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) {
647*9de2952eSStefano Zampini         nodes[dof].touched = PETSC_TRUE;
648b3cdcd63SStefano Zampini         queue_tip[n]       = dof;
649b3cdcd63SStefano Zampini         n++;
650b3cdcd63SStefano Zampini       }
651b3cdcd63SStefano Zampini     }
6521c7a958bSStefano Zampini   } else {
653*9de2952eSStefano Zampini     for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */
654*9de2952eSStefano Zampini       const PetscInt dof = subset_idxs[j];
655*9de2952eSStefano Zampini 
656*9de2952eSStefano Zampini       if (!nodes[dof].touched && nodes[dof].subset == pid) {
657*9de2952eSStefano Zampini         nodes[dof].touched = PETSC_TRUE;
6581c7a958bSStefano Zampini         queue_tip[n]       = dof;
6591c7a958bSStefano Zampini         n++;
6601c7a958bSStefano Zampini       }
6611c7a958bSStefano Zampini     }
662b3cdcd63SStefano Zampini   }
663b3cdcd63SStefano Zampini   *n_added = n;
6643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
665b3cdcd63SStefano Zampini }
666b3cdcd63SStefano Zampini 
667d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphComputeConnectedComponentsLocal(PCBDDCGraph graph)
668d71ae5a4SJacob Faibussowitsch {
669*9de2952eSStefano Zampini   PetscInt ncc, cum_queue;
670674ae819SStefano Zampini 
671674ae819SStefano Zampini   PetscFunctionBegin;
67228b400f6SJacob Faibussowitsch   PetscCheck(graph->setupcalled, PetscObjectComm((PetscObject)graph->l2gmap), PETSC_ERR_ORDER, "PCBDDCGraphSetUp should be called first");
673b3cdcd63SStefano Zampini   /* quiet return if there isn't any local info */
6743ba16761SJacob Faibussowitsch   if (!graph->xadj && !graph->n_local_subs) PetscFunctionReturn(PETSC_SUCCESS);
675674ae819SStefano Zampini 
676674ae819SStefano Zampini   /* reset any previous search of connected components */
677*9de2952eSStefano Zampini   for (PetscInt i = 0; i < graph->nvtxs; i++) graph->nodes[i].touched = PETSC_FALSE;
678*9de2952eSStefano Zampini   if (!graph->seq_graph) {
679*9de2952eSStefano Zampini     for (PetscInt i = 0; i < graph->nvtxs; i++) {
680*9de2952eSStefano Zampini       if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK || graph->nodes[i].count < 2) graph->nodes[i].touched = PETSC_TRUE;
6814a060362SStefano Zampini     }
682b3cdcd63SStefano Zampini   }
683674ae819SStefano Zampini 
684674ae819SStefano Zampini   /* begin search for connected components */
685674ae819SStefano Zampini   cum_queue = 0;
686674ae819SStefano Zampini   ncc       = 0;
687*9de2952eSStefano Zampini   for (PetscInt n = 0; n < graph->n_subsets; n++) {
688*9de2952eSStefano Zampini     const PetscInt *subset_idxs = graph->subset_idxs[n];
689*9de2952eSStefano Zampini     const PetscInt  pid         = n + 1; /* partition labeled by 0 is discarded */
690*9de2952eSStefano Zampini 
691b3cdcd63SStefano Zampini     PetscInt found = 0, prev = 0, first = 0, ncc_pid = 0;
692*9de2952eSStefano Zampini 
693b3cdcd63SStefano Zampini     while (found != graph->subset_size[n]) {
694b3cdcd63SStefano Zampini       PetscInt added = 0;
695*9de2952eSStefano Zampini 
696b3cdcd63SStefano Zampini       if (!prev) { /* search for new starting dof */
697*9de2952eSStefano Zampini         while (graph->nodes[subset_idxs[first]].touched) first++;
698*9de2952eSStefano Zampini         graph->nodes[subset_idxs[first]].touched = PETSC_TRUE;
699*9de2952eSStefano Zampini         graph->queue[cum_queue]                  = subset_idxs[first];
700674ae819SStefano Zampini         graph->cptr[ncc]                         = cum_queue;
701b3cdcd63SStefano Zampini         prev                                     = 1;
702b3cdcd63SStefano Zampini         cum_queue++;
703b3cdcd63SStefano Zampini         found++;
704674ae819SStefano Zampini         ncc_pid++;
705b3cdcd63SStefano Zampini         ncc++;
706674ae819SStefano Zampini       }
7079566063dSJacob Faibussowitsch       PetscCall(PCBDDCGraphComputeCC_Private(graph, pid, graph->queue + cum_queue, prev, &added));
708b3cdcd63SStefano Zampini       if (!added) {
709674ae819SStefano Zampini         graph->subset_ncc[n] = ncc_pid;
710b3cdcd63SStefano Zampini         graph->cptr[ncc]     = cum_queue;
711b3cdcd63SStefano Zampini       }
712b3cdcd63SStefano Zampini       prev = added;
713b3cdcd63SStefano Zampini       found += added;
714b3cdcd63SStefano Zampini       cum_queue += added;
715b3cdcd63SStefano Zampini       if (added && found == graph->subset_size[n]) {
716b3cdcd63SStefano Zampini         graph->subset_ncc[n] = ncc_pid;
717b3cdcd63SStefano Zampini         graph->cptr[ncc]     = cum_queue;
718b3cdcd63SStefano Zampini       }
719b3cdcd63SStefano Zampini     }
720674ae819SStefano Zampini   }
721674ae819SStefano Zampini   graph->ncc          = ncc;
722acc113dbSStefano Zampini   graph->queue_sorted = PETSC_FALSE;
7233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
724674ae819SStefano Zampini }
725674ae819SStefano Zampini 
726d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphSetUp(PCBDDCGraph graph, PetscInt custom_minimal_size, IS neumann_is, IS dirichlet_is, PetscInt n_ISForDofs, IS ISForDofs[], IS custom_primal_vertices)
727d71ae5a4SJacob Faibussowitsch {
728*9de2952eSStefano Zampini   IS              subset;
729674ae819SStefano Zampini   MPI_Comm        comm;
730674ae819SStefano Zampini   const PetscInt *is_indices;
731*9de2952eSStefano Zampini   PetscInt       *queue_global, *nodecount, **nodeneighs;
732*9de2952eSStefano Zampini   PetscInt        i, j, k, total_counts, nodes_touched, is_size, nvtxs = graph->nvtxs;
733*9de2952eSStefano Zampini   PetscMPIInt     size, rank;
734*9de2952eSStefano Zampini   PetscBool       same_set;
735674ae819SStefano Zampini 
736674ae819SStefano Zampini   PetscFunctionBegin;
7377a0e7b2cSstefano_zampini   PetscValidLogicalCollectiveInt(graph->l2gmap, custom_minimal_size, 2);
7387a0e7b2cSstefano_zampini   if (neumann_is) {
7397a0e7b2cSstefano_zampini     PetscValidHeaderSpecific(neumann_is, IS_CLASSID, 3);
7407a0e7b2cSstefano_zampini     PetscCheckSameComm(graph->l2gmap, 1, neumann_is, 3);
7417a0e7b2cSstefano_zampini   }
742a07ea27aSStefano Zampini   graph->has_dirichlet = PETSC_FALSE;
743a07ea27aSStefano Zampini   if (dirichlet_is) {
7447a0e7b2cSstefano_zampini     PetscValidHeaderSpecific(dirichlet_is, IS_CLASSID, 4);
745a07ea27aSStefano Zampini     PetscCheckSameComm(graph->l2gmap, 1, dirichlet_is, 4);
746a07ea27aSStefano Zampini     graph->has_dirichlet = PETSC_TRUE;
747a07ea27aSStefano Zampini   }
7487a0e7b2cSstefano_zampini   PetscValidLogicalCollectiveInt(graph->l2gmap, n_ISForDofs, 5);
7497a0e7b2cSstefano_zampini   for (i = 0; i < n_ISForDofs; i++) {
7507a0e7b2cSstefano_zampini     PetscValidHeaderSpecific(ISForDofs[i], IS_CLASSID, 6);
7517a0e7b2cSstefano_zampini     PetscCheckSameComm(graph->l2gmap, 1, ISForDofs[i], 6);
7527a0e7b2cSstefano_zampini   }
7537a0e7b2cSstefano_zampini   if (custom_primal_vertices) {
754ab8c8b98SStefano Zampini     PetscValidHeaderSpecific(custom_primal_vertices, IS_CLASSID, 7);
7557a0e7b2cSstefano_zampini     PetscCheckSameComm(graph->l2gmap, 1, custom_primal_vertices, 7);
7567a0e7b2cSstefano_zampini   }
757*9de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++) graph->nodes[i].touched = PETSC_FALSE;
758*9de2952eSStefano Zampini 
759f4f49eeaSPierre Jolivet   PetscCall(PetscObjectGetComm((PetscObject)graph->l2gmap, &comm));
760*9de2952eSStefano Zampini   PetscCallMPI(MPI_Comm_size(comm, &size));
761*9de2952eSStefano Zampini   PetscCallMPI(MPI_Comm_rank(comm, &rank));
762b3cdcd63SStefano Zampini 
763674ae819SStefano Zampini   /* custom_minimal_size */
76414f95afaSStefano Zampini   graph->custom_minimal_size = custom_minimal_size;
7657a0e7b2cSstefano_zampini 
766*9de2952eSStefano Zampini   /* get node info from l2gmap */
767*9de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingGetNodeInfo(graph->l2gmap, NULL, &nodecount, &nodeneighs));
76851b0f6cfSStefano Zampini 
769674ae819SStefano Zampini   /* Allocate space for storing the set of neighbours for each node */
770*9de2952eSStefano Zampini   graph->multi_element = PETSC_FALSE;
771*9de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++) {
772*9de2952eSStefano Zampini     graph->nodes[i].count = nodecount[i];
773*9de2952eSStefano Zampini     if (!graph->seq_graph) {
774*9de2952eSStefano Zampini       PetscCall(PetscMalloc1(nodecount[i], &graph->nodes[i].neighbours_set));
775*9de2952eSStefano Zampini       PetscCall(PetscArraycpy(graph->nodes[i].neighbours_set, nodeneighs[i], nodecount[i]));
776*9de2952eSStefano Zampini 
777*9de2952eSStefano Zampini       if (!graph->multi_element) {
778*9de2952eSStefano Zampini         PetscInt nself;
779*9de2952eSStefano Zampini         for (j = 0, nself = 0; j < graph->nodes[i].count; j++)
780*9de2952eSStefano Zampini           if (graph->nodes[i].neighbours_set[j] == rank) nself++;
781*9de2952eSStefano Zampini         if (nself > 1) graph->multi_element = PETSC_TRUE;
782674ae819SStefano Zampini       }
783*9de2952eSStefano Zampini     } else {
784*9de2952eSStefano Zampini       PetscCall(PetscCalloc1(nodecount[i], &graph->nodes[i].neighbours_set));
785674ae819SStefano Zampini     }
786674ae819SStefano Zampini   }
787*9de2952eSStefano Zampini   PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(graph->l2gmap, NULL, &nodecount, &nodeneighs));
788*9de2952eSStefano Zampini   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &graph->multi_element, 1, MPIU_BOOL, MPI_LOR, comm));
789*9de2952eSStefano Zampini 
790*9de2952eSStefano Zampini   /* compute local groups */
791*9de2952eSStefano Zampini   if (graph->multi_element) {
792*9de2952eSStefano Zampini     const PetscInt *idxs, *indegree;
793*9de2952eSStefano Zampini     IS              is, lis;
794*9de2952eSStefano Zampini     PetscLayout     layout;
795*9de2952eSStefano Zampini     PetscSF         sf, multisf;
796*9de2952eSStefano Zampini     PetscInt        n, nmulti, c, *multi_root_subs, *start;
797*9de2952eSStefano Zampini 
798*9de2952eSStefano Zampini     PetscCheck(graph->local_subs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local subdomain information");
799*9de2952eSStefano Zampini 
800*9de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingGetIndices(graph->l2gmap, &idxs));
801*9de2952eSStefano Zampini     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nvtxs, idxs, PETSC_USE_POINTER, &is));
802*9de2952eSStefano Zampini     PetscCall(ISRenumber(is, NULL, &n, &lis));
803*9de2952eSStefano Zampini     PetscCall(ISDestroy(&is));
804*9de2952eSStefano Zampini 
805*9de2952eSStefano Zampini     PetscCall(ISLocalToGlobalMappingRestoreIndices(graph->l2gmap, &idxs));
806*9de2952eSStefano Zampini     PetscCall(ISGetIndices(lis, &idxs));
807*9de2952eSStefano Zampini     PetscCall(PetscLayoutCreate(PETSC_COMM_SELF, &layout));
808*9de2952eSStefano Zampini     PetscCall(PetscLayoutSetSize(layout, n));
809*9de2952eSStefano Zampini     PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf));
810*9de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(sf, layout, nvtxs, NULL, PETSC_OWN_POINTER, idxs));
811*9de2952eSStefano Zampini     PetscCall(PetscLayoutDestroy(&layout));
812*9de2952eSStefano Zampini     PetscCall(PetscSFGetMultiSF(sf, &multisf));
813*9de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeBegin(sf, &indegree));
814*9de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeEnd(sf, &indegree));
815*9de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(multisf, &nmulti, NULL, NULL, NULL));
816*9de2952eSStefano Zampini     PetscCall(PetscMalloc2(nmulti, &multi_root_subs, n + 1, &start));
817*9de2952eSStefano Zampini     start[0] = 0;
818*9de2952eSStefano Zampini     for (i = 0; i < n; i++) start[i + 1] = start[i] + indegree[i];
819*9de2952eSStefano Zampini     PetscCall(PetscSFGatherBegin(sf, MPIU_INT, graph->local_subs, multi_root_subs));
820*9de2952eSStefano Zampini     PetscCall(PetscSFGatherEnd(sf, MPIU_INT, graph->local_subs, multi_root_subs));
821*9de2952eSStefano Zampini     for (i = 0; i < nvtxs; i++) {
822*9de2952eSStefano Zampini       PetscInt gid = idxs[i];
823*9de2952eSStefano Zampini 
824*9de2952eSStefano Zampini       graph->nodes[i].local_sub = graph->local_subs[i];
825*9de2952eSStefano Zampini       for (j = 0, c = 0; j < graph->nodes[i].count; j++) {
826*9de2952eSStefano Zampini         if (graph->nodes[i].neighbours_set[j] == rank) c++;
827*9de2952eSStefano Zampini       }
828*9de2952eSStefano Zampini       PetscCheck(c == indegree[idxs[i]], PETSC_COMM_SELF, PETSC_ERR_PLIB, "%" PetscInt_FMT " != %" PetscInt_FMT, c, indegree[idxs[i]]);
829*9de2952eSStefano Zampini       PetscCall(PetscMalloc1(c, &graph->nodes[i].local_groups));
830*9de2952eSStefano Zampini       for (j = 0; j < c; j++) graph->nodes[i].local_groups[j] = multi_root_subs[start[gid] + j];
831*9de2952eSStefano Zampini       PetscCall(PetscSortInt(c, graph->nodes[i].local_groups));
832*9de2952eSStefano Zampini       graph->nodes[i].local_groups_count = c;
833*9de2952eSStefano Zampini     }
834*9de2952eSStefano Zampini     PetscCall(PetscFree2(multi_root_subs, start));
835*9de2952eSStefano Zampini     PetscCall(ISRestoreIndices(lis, &idxs));
836*9de2952eSStefano Zampini     PetscCall(ISDestroy(&lis));
837*9de2952eSStefano Zampini     PetscCall(PetscSFDestroy(&sf));
838*9de2952eSStefano Zampini   }
8397fb0e2dbSStefano Zampini 
84067c9da69SStefano Zampini   /*
84167c9da69SStefano Zampini      Get info for dofs splitting
8425777c63cSStefano Zampini      User can specify just a subset; an additional field is considered as a complementary field
84367c9da69SStefano Zampini   */
8440c85b387SStefano Zampini   for (i = 0, k = 0; i < n_ISForDofs; i++) {
8450c85b387SStefano Zampini     PetscInt bs;
8460c85b387SStefano Zampini 
8479566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(ISForDofs[i], &bs));
8480c85b387SStefano Zampini     k += bs;
8490c85b387SStefano Zampini   }
850*9de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++) graph->nodes[i].which_dof = k; /* by default a dof belongs to the complement set */
8510c85b387SStefano Zampini   for (i = 0, k = 0; i < n_ISForDofs; i++) {
8520c85b387SStefano Zampini     PetscInt bs;
8530c85b387SStefano Zampini 
8549566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(ISForDofs[i], &is_size));
8559566063dSJacob Faibussowitsch     PetscCall(ISGetBlockSize(ISForDofs[i], &bs));
8569566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(ISForDofs[i], (const PetscInt **)&is_indices));
8570c85b387SStefano Zampini     for (j = 0; j < is_size / bs; j++) {
8580c85b387SStefano Zampini       PetscInt b;
8590c85b387SStefano Zampini 
8600c85b387SStefano Zampini       for (b = 0; b < bs; b++) {
8610c85b387SStefano Zampini         PetscInt jj = bs * j + b;
8620c85b387SStefano Zampini 
863*9de2952eSStefano Zampini         if (is_indices[jj] > -1 && is_indices[jj] < nvtxs) { /* out of bounds indices (if any) are skipped */
864*9de2952eSStefano Zampini           graph->nodes[is_indices[jj]].which_dof = k + b;
8650c85b387SStefano Zampini         }
866674ae819SStefano Zampini       }
86767c9da69SStefano Zampini     }
8689566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(ISForDofs[i], (const PetscInt **)&is_indices));
8690c85b387SStefano Zampini     k += bs;
8705777c63cSStefano Zampini   }
8715777c63cSStefano Zampini 
872674ae819SStefano Zampini   /* Take into account Neumann nodes */
873674ae819SStefano Zampini   if (neumann_is) {
8749566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(neumann_is, &is_size));
8759566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(neumann_is, (const PetscInt **)&is_indices));
876674ae819SStefano Zampini     for (i = 0; i < is_size; i++) {
877*9de2952eSStefano Zampini       if (is_indices[i] > -1 && is_indices[i] < nvtxs) { /* out of bounds indices (if any) are skipped */
878*9de2952eSStefano Zampini         graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_NEUMANN_MARK;
879674ae819SStefano Zampini       }
8803c629590SStefano Zampini     }
8819566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(neumann_is, (const PetscInt **)&is_indices));
882674ae819SStefano Zampini   }
883*9de2952eSStefano Zampini 
884*9de2952eSStefano Zampini   /* Take into account Dirichlet nodes (they overwrite any mark previously set) */
885674ae819SStefano Zampini   if (dirichlet_is) {
8869566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(dirichlet_is, &is_size));
8879566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(dirichlet_is, (const PetscInt **)&is_indices));
888674ae819SStefano Zampini     for (i = 0; i < is_size; i++) {
889*9de2952eSStefano Zampini       if (is_indices[i] > -1 && is_indices[i] < nvtxs) { /* out of bounds indices (if any) are skipped */
890*9de2952eSStefano Zampini         if (!graph->seq_graph) {                         /* dirichlet nodes treated as internal */
891*9de2952eSStefano Zampini           graph->nodes[is_indices[i]].touched = PETSC_TRUE;
892*9de2952eSStefano Zampini           graph->nodes[is_indices[i]].subset  = 0;
8937a0e7b2cSstefano_zampini         }
894*9de2952eSStefano Zampini         graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_DIRICHLET_MARK;
895674ae819SStefano Zampini       }
8963c629590SStefano Zampini     }
8979566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(dirichlet_is, (const PetscInt **)&is_indices));
8987fb0e2dbSStefano Zampini   }
89951b0f6cfSStefano Zampini 
900*9de2952eSStefano Zampini   /* mark special nodes (if any) -> each will become a single dof equivalence class (i.e. point constraint for BDDC) */
901674ae819SStefano Zampini   if (custom_primal_vertices) {
9029566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(custom_primal_vertices, &is_size));
9039566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(custom_primal_vertices, (const PetscInt **)&is_indices));
9047a0e7b2cSstefano_zampini     for (i = 0, j = 0; i < is_size; i++) {
905*9de2952eSStefano 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 */
906*9de2952eSStefano Zampini         graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_SPECIAL_MARK - j;
9079b70a373SStefano Zampini         j++;
9089b70a373SStefano Zampini       }
9099b70a373SStefano Zampini     }
9109566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(custom_primal_vertices, (const PetscInt **)&is_indices));
91117eb1463SStefano Zampini   }
9129b70a373SStefano Zampini 
913*9de2952eSStefano Zampini   /* mark interior nodes as touched and belonging to partition number 0 */
914*9de2952eSStefano Zampini   if (!graph->seq_graph) {
915*9de2952eSStefano Zampini     for (i = 0; i < nvtxs; i++) {
916*9de2952eSStefano Zampini       if (graph->nodes[i].count < 2) {
917*9de2952eSStefano Zampini         graph->nodes[i].touched = PETSC_TRUE;
918*9de2952eSStefano Zampini         graph->nodes[i].subset  = 0;
919674ae819SStefano Zampini       }
920674ae819SStefano Zampini     }
921b3cdcd63SStefano Zampini   }
922b3cdcd63SStefano Zampini 
923674ae819SStefano Zampini   /* init graph structure and compute default subsets */
924674ae819SStefano Zampini   nodes_touched = 0;
925*9de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++)
926*9de2952eSStefano Zampini     if (graph->nodes[i].touched) nodes_touched++;
927*9de2952eSStefano Zampini 
928674ae819SStefano Zampini   i            = 0;
929674ae819SStefano Zampini   graph->ncc   = 0;
930674ae819SStefano Zampini   total_counts = 0;
9317babac9bSStefano Zampini 
9327babac9bSStefano Zampini   /* allocated space for queues */
933*9de2952eSStefano Zampini   if (graph->seq_graph) {
934*9de2952eSStefano Zampini     PetscCall(PetscMalloc2(nvtxs + 1, &graph->cptr, nvtxs, &graph->queue));
9357babac9bSStefano Zampini   } else {
936*9de2952eSStefano Zampini     PetscInt nused = nvtxs - nodes_touched;
9379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nused + 1, &graph->cptr, nused, &graph->queue));
9387babac9bSStefano Zampini   }
9397babac9bSStefano Zampini 
940*9de2952eSStefano Zampini   while (nodes_touched < nvtxs) {
941674ae819SStefano Zampini     /*  find first untouched node in local ordering */
942*9de2952eSStefano Zampini     while (graph->nodes[i].touched) i++;
943*9de2952eSStefano Zampini     graph->nodes[i].touched    = PETSC_TRUE;
944*9de2952eSStefano Zampini     graph->nodes[i].subset     = graph->ncc + 1;
945674ae819SStefano Zampini     graph->cptr[graph->ncc]    = total_counts;
946674ae819SStefano Zampini     graph->queue[total_counts] = i;
947674ae819SStefano Zampini     total_counts++;
948674ae819SStefano Zampini     nodes_touched++;
949*9de2952eSStefano Zampini 
950674ae819SStefano Zampini     /* now find all other nodes having the same set of sharing subdomains */
951*9de2952eSStefano Zampini     const PCBDDCGraphNode         *nodei               = &graph->nodes[i];
952*9de2952eSStefano Zampini     const PetscInt                 icount              = nodei->count;
953*9de2952eSStefano Zampini     const PetscInt                 iwhich_dof          = nodei->which_dof;
954*9de2952eSStefano Zampini     const PetscInt                 ispecial_dof        = nodei->special_dof;
955*9de2952eSStefano Zampini     const PetscInt                 ilocal_groups_count = nodei->local_groups_count;
956*9de2952eSStefano Zampini     const PetscInt *PETSC_RESTRICT ineighbours_set     = nodei->neighbours_set;
957*9de2952eSStefano Zampini     const PetscInt *PETSC_RESTRICT ilocal_groups       = nodei->local_groups;
958*9de2952eSStefano Zampini     for (j = i + 1; j < nvtxs; j++) {
959*9de2952eSStefano Zampini       PCBDDCGraphNode *PETSC_RESTRICT nodej = &graph->nodes[j];
960*9de2952eSStefano Zampini 
961*9de2952eSStefano Zampini       if (nodej->touched) continue;
96274e413f5SStefano Zampini       /* check for same number of sharing subdomains, dof number and same special mark */
963*9de2952eSStefano Zampini       if (icount == nodej->count && iwhich_dof == nodej->which_dof && ispecial_dof == nodej->special_dof) {
964*9de2952eSStefano Zampini         PetscBool mpi_shared = PETSC_TRUE;
965*9de2952eSStefano Zampini 
966674ae819SStefano Zampini         /* check for same set of sharing subdomains */
967674ae819SStefano Zampini         same_set = PETSC_TRUE;
968*9de2952eSStefano Zampini         for (k = 0; k < icount; k++) {
969*9de2952eSStefano Zampini           if (ineighbours_set[k] != nodej->neighbours_set[k]) {
970*9de2952eSStefano Zampini             same_set = PETSC_FALSE;
971*9de2952eSStefano Zampini             break;
972674ae819SStefano Zampini           }
973*9de2952eSStefano Zampini         }
974*9de2952eSStefano Zampini 
975*9de2952eSStefano Zampini         if (graph->multi_element) {
976*9de2952eSStefano Zampini           mpi_shared = PETSC_FALSE;
977*9de2952eSStefano Zampini           for (k = 0; k < icount; k++)
978*9de2952eSStefano Zampini             if (ineighbours_set[k] != rank) {
979*9de2952eSStefano Zampini               mpi_shared = PETSC_TRUE;
980*9de2952eSStefano Zampini               break;
981*9de2952eSStefano Zampini             }
982*9de2952eSStefano Zampini         }
983*9de2952eSStefano Zampini 
984*9de2952eSStefano Zampini         /* check for same local groups
985*9de2952eSStefano Zampini            shared dofs at the process boundaries will be handled differently */
986*9de2952eSStefano Zampini         if (same_set && !mpi_shared) {
987*9de2952eSStefano Zampini           if (ilocal_groups_count != nodej->local_groups_count) same_set = PETSC_FALSE;
988*9de2952eSStefano Zampini           else {
989*9de2952eSStefano Zampini             for (k = 0; k < ilocal_groups_count; k++) {
990*9de2952eSStefano Zampini               if (ilocal_groups[k] != nodej->local_groups[k]) {
991*9de2952eSStefano Zampini                 same_set = PETSC_FALSE;
992*9de2952eSStefano Zampini                 break;
993*9de2952eSStefano Zampini               }
994*9de2952eSStefano Zampini             }
995*9de2952eSStefano Zampini           }
996*9de2952eSStefano Zampini         }
997*9de2952eSStefano Zampini 
998*9de2952eSStefano Zampini         /* Add to subset */
999674ae819SStefano Zampini         if (same_set) {
1000*9de2952eSStefano Zampini           nodej->touched = PETSC_TRUE;
1001*9de2952eSStefano Zampini           nodej->subset  = graph->ncc + 1;
1002674ae819SStefano Zampini           nodes_touched++;
1003674ae819SStefano Zampini           graph->queue[total_counts] = j;
1004674ae819SStefano Zampini           total_counts++;
1005674ae819SStefano Zampini         }
1006674ae819SStefano Zampini       }
1007674ae819SStefano Zampini     }
1008674ae819SStefano Zampini     graph->ncc++;
1009674ae819SStefano Zampini   }
1010*9de2952eSStefano Zampini   graph->cptr[graph->ncc] = total_counts;
1011*9de2952eSStefano Zampini 
1012*9de2952eSStefano Zampini   /* set default number of subsets */
1013674ae819SStefano Zampini   graph->n_subsets = graph->ncc;
10149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->n_subsets, &graph->subset_ncc));
1015ad540459SPierre Jolivet   for (i = 0; i < graph->n_subsets; i++) graph->subset_ncc[i] = 1;
1016ec1c413dSStefano Zampini 
10179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->ncc, &graph->subset_ref_node));
10189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global));
1019*9de2952eSStefano Zampini   PetscCall(PetscMalloc2(graph->ncc, &graph->subset_size, graph->ncc, &graph->subset_idxs));
1020*9de2952eSStefano Zampini   if (graph->multi_element) PetscCall(PetscMalloc1(graph->ncc, &graph->gsubset_size));
1021*9de2952eSStefano Zampini   else graph->gsubset_size = graph->subset_size;
10229566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global));
1023*9de2952eSStefano Zampini 
1024*9de2952eSStefano Zampini   PetscHMapI cnt_unique;
1025*9de2952eSStefano Zampini 
1026*9de2952eSStefano Zampini   PetscCall(PetscHMapICreate(&cnt_unique));
1027ec1c413dSStefano Zampini   for (j = 0; j < graph->ncc; j++) {
1028*9de2952eSStefano Zampini     PetscInt c = 0, ref_node = PETSC_MAX_INT;
1029*9de2952eSStefano Zampini 
1030*9de2952eSStefano Zampini     for (k = graph->cptr[j]; k < graph->cptr[j + 1]; k++) {
1031*9de2952eSStefano Zampini       ref_node = PetscMin(ref_node, queue_global[k]);
1032*9de2952eSStefano Zampini       if (graph->multi_element) {
1033*9de2952eSStefano Zampini         PetscBool     missing;
1034*9de2952eSStefano Zampini         PetscHashIter iter;
1035*9de2952eSStefano Zampini 
1036*9de2952eSStefano Zampini         PetscCall(PetscHMapIPut(cnt_unique, queue_global[k], &iter, &missing));
1037*9de2952eSStefano Zampini         if (missing) c++;
1038f0321c90SStefano Zampini       }
1039*9de2952eSStefano Zampini     }
1040*9de2952eSStefano Zampini     graph->gsubset_size[j]    = c;
1041*9de2952eSStefano Zampini     graph->subset_size[j]     = graph->cptr[j + 1] - graph->cptr[j];
1042*9de2952eSStefano Zampini     graph->subset_ref_node[j] = ref_node;
1043*9de2952eSStefano Zampini     if (graph->multi_element) PetscCall(PetscHMapIClear(cnt_unique));
1044*9de2952eSStefano Zampini   }
1045*9de2952eSStefano Zampini   PetscCall(PetscHMapIDestroy(&cnt_unique));
104648bebe3cSStefano Zampini 
1047b3cdcd63SStefano Zampini   /* save information on subsets (needed when analyzing the connected components) */
10482f566a09SStefano Zampini   if (graph->ncc) {
10499566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &graph->subset_idxs[0]));
10509566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(graph->subset_idxs[0], graph->cptr[graph->ncc]));
1051*9de2952eSStefano Zampini     for (j = 1; j < graph->ncc; j++) { graph->subset_idxs[j] = graph->subset_idxs[j - 1] + graph->subset_size[j - 1]; }
10529566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(graph->subset_idxs[0], graph->queue, graph->cptr[graph->ncc]));
1053ec1c413dSStefano Zampini   }
1054b3cdcd63SStefano Zampini 
1055*9de2952eSStefano Zampini   /* check consistency and create SF to analyze components on the interface between subdomains */
1056*9de2952eSStefano Zampini   if (!graph->seq_graph) {
1057*9de2952eSStefano Zampini     PetscSF         msf;
1058*9de2952eSStefano Zampini     PetscLayout     map;
1059*9de2952eSStefano Zampini     const PetscInt *degree;
1060*9de2952eSStefano Zampini     PetscInt        nr, nmr, *rdata;
1061*9de2952eSStefano Zampini     PetscBool       valid = PETSC_TRUE;
1062*9de2952eSStefano Zampini     PetscInt        subset_N;
1063*9de2952eSStefano Zampini     IS              subset_n;
1064*9de2952eSStefano Zampini     const PetscInt *idxs;
1065*9de2952eSStefano Zampini 
1066*9de2952eSStefano Zampini     PetscCall(ISCreateGeneral(comm, graph->n_subsets, graph->subset_ref_node, PETSC_USE_POINTER, &subset));
1067*9de2952eSStefano Zampini     PetscCall(ISRenumber(subset, NULL, &subset_N, &subset_n));
10689566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&subset));
1069*9de2952eSStefano Zampini 
1070*9de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &graph->interface_ref_sf));
1071*9de2952eSStefano Zampini     PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, subset_N, 1, &map));
1072*9de2952eSStefano Zampini     PetscCall(ISGetIndices(subset_n, &idxs));
1073*9de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(graph->interface_ref_sf, map, graph->n_subsets, NULL, PETSC_OWN_POINTER, idxs));
1074*9de2952eSStefano Zampini     PetscCall(ISRestoreIndices(subset_n, &idxs));
10759566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&subset_n));
1076*9de2952eSStefano Zampini     PetscCall(PetscLayoutDestroy(&map));
1077*9de2952eSStefano Zampini 
1078*9de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeBegin(graph->interface_ref_sf, &degree));
1079*9de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeEnd(graph->interface_ref_sf, &degree));
1080*9de2952eSStefano Zampini     PetscCall(PetscSFGetMultiSF(graph->interface_ref_sf, &msf));
1081*9de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, &nr, NULL, NULL, NULL));
1082*9de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
1083*9de2952eSStefano Zampini     PetscCall(PetscCalloc1(nmr, &rdata));
1084*9de2952eSStefano Zampini     PetscCall(PetscSFGatherBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata));
1085*9de2952eSStefano Zampini     PetscCall(PetscSFGatherEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata));
1086*9de2952eSStefano Zampini     for (PetscInt i = 0, c = 0; i < nr && valid; i++) {
1087*9de2952eSStefano Zampini       for (PetscInt j = 0; j < degree[i]; j++) {
1088*9de2952eSStefano Zampini         if (rdata[j + c] != rdata[c]) valid = PETSC_FALSE;
1089*9de2952eSStefano Zampini       }
1090*9de2952eSStefano Zampini       c += degree[i];
1091*9de2952eSStefano Zampini     }
1092*9de2952eSStefano Zampini     PetscCall(PetscFree(rdata));
1093*9de2952eSStefano Zampini     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &valid, 1, MPIU_BOOL, MPI_LAND, comm));
1094*9de2952eSStefano Zampini     PetscCheck(valid, comm, PETSC_ERR_PLIB, "Initial local subsets are not consistent");
1095*9de2952eSStefano Zampini 
1096*9de2952eSStefano Zampini     /* Now create SF with each root extended to gsubset_size roots */
1097*9de2952eSStefano Zampini     PetscInt           mss;
1098*9de2952eSStefano Zampini     const PetscSFNode *subs_remote;
1099*9de2952eSStefano Zampini 
1100*9de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, NULL, NULL, NULL, &subs_remote));
1101*9de2952eSStefano Zampini     for (i = 0, mss = 0; i < graph->n_subsets; i++) mss = PetscMax(graph->subset_size[i], mss);
1102*9de2952eSStefano Zampini 
1103*9de2952eSStefano Zampini     PetscInt nri, nli, *start_rsize, *cum_rsize;
1104*9de2952eSStefano Zampini     PetscCall(PetscCalloc1(graph->n_subsets + 1, &start_rsize));
1105*9de2952eSStefano Zampini     PetscCall(PetscCalloc1(nr, &graph->interface_ref_rsize));
1106*9de2952eSStefano Zampini     PetscCall(PetscMalloc1(nr + 1, &cum_rsize));
1107*9de2952eSStefano Zampini     PetscCall(PetscSFReduceBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE));
1108*9de2952eSStefano Zampini     PetscCall(PetscSFReduceEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE));
1109*9de2952eSStefano Zampini 
1110*9de2952eSStefano Zampini     nri          = 0;
1111*9de2952eSStefano Zampini     cum_rsize[0] = 0;
1112*9de2952eSStefano Zampini     for (i = 0; i < nr; i++) {
1113*9de2952eSStefano Zampini       nri += graph->interface_ref_rsize[i];
1114*9de2952eSStefano Zampini       cum_rsize[i + 1] = cum_rsize[i] + graph->interface_ref_rsize[i];
1115*9de2952eSStefano Zampini     }
1116*9de2952eSStefano Zampini     nli = graph->cptr[graph->ncc];
1117*9de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE));
1118*9de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE));
1119*9de2952eSStefano Zampini     PetscCall(PetscFree(cum_rsize));
1120*9de2952eSStefano Zampini 
1121*9de2952eSStefano Zampini     PetscInt    *ilocal, *queue_global_uniq;
1122*9de2952eSStefano Zampini     PetscSFNode *iremote;
1123*9de2952eSStefano Zampini     PetscBool   *touched;
1124*9de2952eSStefano Zampini 
1125*9de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &graph->interface_subset_sf));
1126*9de2952eSStefano Zampini     PetscCall(PetscMalloc1(nli, &ilocal));
1127*9de2952eSStefano Zampini     PetscCall(PetscMalloc1(nli, &iremote));
1128*9de2952eSStefano Zampini     PetscCall(PetscMalloc2(mss, &queue_global_uniq, mss, &touched));
1129*9de2952eSStefano Zampini     for (i = 0, nli = 0; i < graph->n_subsets; i++) {
1130*9de2952eSStefano Zampini       const PetscMPIInt rr                = subs_remote[i].rank;
1131*9de2952eSStefano Zampini       const PetscInt    start             = start_rsize[i];
1132*9de2952eSStefano Zampini       const PetscInt    subset_size       = graph->subset_size[i];
1133*9de2952eSStefano Zampini       const PetscInt    gsubset_size      = graph->gsubset_size[i];
1134*9de2952eSStefano Zampini       const PetscInt   *subset_idxs       = graph->subset_idxs[i];
1135*9de2952eSStefano Zampini       const PetscInt   *lsub_queue_global = queue_global + graph->cptr[i];
1136*9de2952eSStefano Zampini 
1137*9de2952eSStefano Zampini       k = subset_size;
1138*9de2952eSStefano Zampini       PetscCall(PetscArrayzero(touched, subset_size));
1139*9de2952eSStefano Zampini       PetscCall(PetscArraycpy(queue_global_uniq, lsub_queue_global, subset_size));
1140*9de2952eSStefano Zampini       PetscCall(PetscSortRemoveDupsInt(&k, queue_global_uniq));
1141*9de2952eSStefano 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);
1142*9de2952eSStefano Zampini 
1143*9de2952eSStefano Zampini       PetscInt t = 0, j = 0;
1144*9de2952eSStefano Zampini       while (t < subset_size) {
1145*9de2952eSStefano Zampini         while (j < subset_size && touched[j]) j++;
1146*9de2952eSStefano Zampini         PetscCheck(j < subset_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " >= %" PetscInt_FMT, j, subset_size);
1147*9de2952eSStefano Zampini         const PetscInt ls = graph->nodes[subset_idxs[j]].local_sub;
1148*9de2952eSStefano Zampini 
1149*9de2952eSStefano Zampini         for (k = j; k < subset_size; k++) {
1150*9de2952eSStefano Zampini           if (graph->nodes[subset_idxs[k]].local_sub == ls) {
1151*9de2952eSStefano Zampini             PetscInt ig;
1152*9de2952eSStefano Zampini 
1153*9de2952eSStefano Zampini             PetscCall(PetscFindInt(lsub_queue_global[k], gsubset_size, queue_global_uniq, &ig));
1154*9de2952eSStefano Zampini             ilocal[nli]        = subset_idxs[k];
1155*9de2952eSStefano Zampini             iremote[nli].rank  = rr;
1156*9de2952eSStefano Zampini             iremote[nli].index = start + ig;
1157*9de2952eSStefano Zampini             touched[k]         = PETSC_TRUE;
1158*9de2952eSStefano Zampini             nli++;
1159*9de2952eSStefano Zampini             t++;
1160*9de2952eSStefano Zampini           }
1161*9de2952eSStefano Zampini         }
1162*9de2952eSStefano Zampini       }
1163*9de2952eSStefano Zampini     }
1164*9de2952eSStefano 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]);
1165*9de2952eSStefano Zampini     PetscCall(PetscSFSetGraph(graph->interface_subset_sf, nri, nli, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
1166*9de2952eSStefano Zampini     PetscCall(PetscFree(start_rsize));
1167*9de2952eSStefano Zampini     PetscCall(PetscFree2(queue_global_uniq, touched));
1168*9de2952eSStefano Zampini   }
1169*9de2952eSStefano Zampini   PetscCall(PetscFree(queue_global));
1170ec1c413dSStefano Zampini 
1171ec1c413dSStefano Zampini   /* free workspace */
1172b3cdcd63SStefano Zampini   graph->setupcalled = PETSC_TRUE;
11733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1174674ae819SStefano Zampini }
1175674ae819SStefano Zampini 
1176d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphResetCoords(PCBDDCGraph graph)
1177d71ae5a4SJacob Faibussowitsch {
1178ab8c8b98SStefano Zampini   PetscFunctionBegin;
11793ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
11809566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->coords));
1181ab8c8b98SStefano Zampini   graph->cdim  = 0;
1182ab8c8b98SStefano Zampini   graph->cnloc = 0;
1183ab8c8b98SStefano Zampini   graph->cloc  = PETSC_FALSE;
11843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1185ab8c8b98SStefano Zampini }
1186ab8c8b98SStefano Zampini 
1187d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphResetCSR(PCBDDCGraph graph)
1188d71ae5a4SJacob Faibussowitsch {
1189674ae819SStefano Zampini   PetscFunctionBegin;
11903ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
1191a1dbd327SStefano Zampini   if (graph->freecsr) {
11929566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph->xadj));
11939566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph->adjncy));
1194a1dbd327SStefano Zampini   } else {
1195a1dbd327SStefano Zampini     graph->xadj   = NULL;
1196a1dbd327SStefano Zampini     graph->adjncy = NULL;
1197a1dbd327SStefano Zampini   }
1198c8272957SStefano Zampini   graph->freecsr   = PETSC_FALSE;
1199575ad6abSStefano Zampini   graph->nvtxs_csr = 0;
12003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1201674ae819SStefano Zampini }
1202674ae819SStefano Zampini 
1203d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphReset(PCBDDCGraph graph)
1204d71ae5a4SJacob Faibussowitsch {
1205674ae819SStefano Zampini   PetscFunctionBegin;
12063ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
12079566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&graph->l2gmap));
12089566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->subset_ncc));
12099566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->subset_ref_node));
1210*9de2952eSStefano Zampini   for (PetscInt i = 0; i < graph->nvtxs; i++) {
1211*9de2952eSStefano Zampini     PetscCall(PetscFree(graph->nodes[i].neighbours_set));
1212*9de2952eSStefano Zampini     PetscCall(PetscFree(graph->nodes[i].local_groups));
1213*9de2952eSStefano Zampini   }
1214*9de2952eSStefano Zampini   PetscCall(PetscFree(graph->nodes));
12159566063dSJacob Faibussowitsch   PetscCall(PetscFree2(graph->cptr, graph->queue));
121648a46eb9SPierre Jolivet   if (graph->subset_idxs) PetscCall(PetscFree(graph->subset_idxs[0]));
12179566063dSJacob Faibussowitsch   PetscCall(PetscFree2(graph->subset_size, graph->subset_idxs));
1218*9de2952eSStefano Zampini   if (graph->multi_element) PetscCall(PetscFree(graph->gsubset_size));
1219*9de2952eSStefano Zampini   PetscCall(PetscFree(graph->interface_ref_rsize));
1220*9de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&graph->interface_subset_sf));
1221*9de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&graph->interface_ref_sf));
12229566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&graph->dirdofs));
12239566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&graph->dirdofsB));
12241baa6e33SBarry Smith   if (graph->n_local_subs) PetscCall(PetscFree(graph->local_subs));
1225*9de2952eSStefano Zampini   graph->multi_element       = PETSC_FALSE;
1226a07ea27aSStefano Zampini   graph->has_dirichlet       = PETSC_FALSE;
1227cc0a5675Sstefano_zampini   graph->twodimset           = PETSC_FALSE;
1228cc0a5675Sstefano_zampini   graph->twodim              = PETSC_FALSE;
1229674ae819SStefano Zampini   graph->nvtxs               = 0;
12307babac9bSStefano Zampini   graph->nvtxs_global        = 0;
1231674ae819SStefano Zampini   graph->n_subsets           = 0;
1232674ae819SStefano Zampini   graph->custom_minimal_size = 1;
12334f1b2e48SStefano Zampini   graph->n_local_subs        = 0;
1234be12c134Sstefano_zampini   graph->maxcount            = PETSC_MAX_INT;
1235*9de2952eSStefano Zampini   graph->seq_graph           = PETSC_FALSE;
1236fb597685SStefano Zampini   graph->setupcalled         = PETSC_FALSE;
12373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1238674ae819SStefano Zampini }
1239674ae819SStefano Zampini 
1240d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphInit(PCBDDCGraph graph, ISLocalToGlobalMapping l2gmap, PetscInt N, PetscInt maxcount)
1241d71ae5a4SJacob Faibussowitsch {
1242674ae819SStefano Zampini   PetscInt n;
1243674ae819SStefano Zampini 
1244674ae819SStefano Zampini   PetscFunctionBegin;
12454f572ea9SToby Isaac   PetscAssertPointer(graph, 1);
1246674ae819SStefano Zampini   PetscValidHeaderSpecific(l2gmap, IS_LTOGM_CLASSID, 2);
12477babac9bSStefano Zampini   PetscValidLogicalCollectiveInt(l2gmap, N, 3);
1248be12c134Sstefano_zampini   PetscValidLogicalCollectiveInt(l2gmap, maxcount, 4);
12498e61c736SStefano Zampini   /* raise an error if already allocated */
125028b400f6SJacob Faibussowitsch   PetscCheck(!graph->nvtxs_global, PetscObjectComm((PetscObject)l2gmap), PETSC_ERR_PLIB, "BDDCGraph already initialized");
1251674ae819SStefano Zampini   /* set number of vertices */
12529566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)l2gmap));
1253674ae819SStefano Zampini   graph->l2gmap = l2gmap;
12549566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
1255674ae819SStefano Zampini   graph->nvtxs        = n;
12567fb0e2dbSStefano Zampini   graph->nvtxs_global = N;
1257674ae819SStefano Zampini   /* allocate used space */
1258*9de2952eSStefano Zampini   PetscCall(PetscCalloc1(graph->nvtxs, &graph->nodes));
125963602bcaSStefano Zampini   /* use -1 as a default value for which_dof array */
1260*9de2952eSStefano Zampini   for (n = 0; n < graph->nvtxs; n++) graph->nodes[n].which_dof = -1;
1261*9de2952eSStefano Zampini 
1262674ae819SStefano Zampini   /* zeroes workspace for values of ncc */
12630a545947SLisandro Dalcin   graph->subset_ncc      = NULL;
12640a545947SLisandro Dalcin   graph->subset_ref_node = NULL;
1265be12c134Sstefano_zampini   /* maxcount for cc */
1266be12c134Sstefano_zampini   graph->maxcount = maxcount;
12673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1268674ae819SStefano Zampini }
1269674ae819SStefano Zampini 
1270d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphDestroy(PCBDDCGraph *graph)
1271d71ae5a4SJacob Faibussowitsch {
1272674ae819SStefano Zampini   PetscFunctionBegin;
12739566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(*graph));
12749566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCoords(*graph));
12759566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphReset(*graph));
12769566063dSJacob Faibussowitsch   PetscCall(PetscFree(*graph));
12773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1278674ae819SStefano Zampini }
1279674ae819SStefano Zampini 
1280d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphCreate(PCBDDCGraph *graph)
1281d71ae5a4SJacob Faibussowitsch {
1282674ae819SStefano Zampini   PCBDDCGraph new_graph;
1283674ae819SStefano Zampini 
1284674ae819SStefano Zampini   PetscFunctionBegin;
12859566063dSJacob Faibussowitsch   PetscCall(PetscNew(&new_graph));
1286674ae819SStefano Zampini   new_graph->custom_minimal_size = 1;
1287674ae819SStefano Zampini   *graph                         = new_graph;
12883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1289674ae819SStefano Zampini }
1290