xref: /petsc/src/ksp/pc/impls/bddc/bddcgraph.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
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>
52daa06b4SStefano Zampini #include <petsc/private/pcbddcgraphhashmap.h>
69de2952eSStefano Zampini #include <petscsf.h>
7674ae819SStefano Zampini 
PCBDDCDestroyGraphCandidatesIS(PetscCtxRt ctx)8*2a8381b2SBarry Smith PetscErrorCode PCBDDCDestroyGraphCandidatesIS(PetscCtxRt ctx)
9d71ae5a4SJacob Faibussowitsch {
10*2a8381b2SBarry Smith   PCBDDCGraphCandidates cand = *(PCBDDCGraphCandidates *)ctx;
1132fe681dSStefano Zampini 
1232fe681dSStefano Zampini   PetscFunctionBegin;
1332fe681dSStefano Zampini   for (PetscInt i = 0; i < cand->nfc; i++) PetscCall(ISDestroy(&cand->Faces[i]));
1432fe681dSStefano Zampini   for (PetscInt i = 0; i < cand->nec; i++) PetscCall(ISDestroy(&cand->Edges[i]));
1532fe681dSStefano Zampini   PetscCall(PetscFree(cand->Faces));
1632fe681dSStefano Zampini   PetscCall(PetscFree(cand->Edges));
1732fe681dSStefano Zampini   PetscCall(ISDestroy(&cand->Vertices));
1832fe681dSStefano Zampini   PetscCall(PetscFree(cand));
193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2032fe681dSStefano Zampini }
2132fe681dSStefano Zampini 
PCBDDCGraphGetDirichletDofsB(PCBDDCGraph graph,IS * dirdofs)22d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphGetDirichletDofsB(PCBDDCGraph graph, IS *dirdofs)
23d71ae5a4SJacob Faibussowitsch {
24d62866d3SStefano Zampini   PetscFunctionBegin;
25d62866d3SStefano Zampini   if (graph->dirdofsB) {
269566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofsB));
27d62866d3SStefano Zampini   } else if (graph->has_dirichlet) {
28d62866d3SStefano Zampini     PetscInt  i, size;
29d62866d3SStefano Zampini     PetscInt *dirdofs_idxs;
30d62866d3SStefano Zampini 
31d62866d3SStefano Zampini     size = 0;
32d62866d3SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
339de2952eSStefano Zampini       if (graph->nodes[i].count > 1 && graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) size++;
34d62866d3SStefano Zampini     }
35d62866d3SStefano Zampini 
369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &dirdofs_idxs));
37d62866d3SStefano Zampini     size = 0;
38d62866d3SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
399de2952eSStefano Zampini       if (graph->nodes[i].count > 1 && graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) dirdofs_idxs[size++] = i;
40d62866d3SStefano Zampini     }
419566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, dirdofs_idxs, PETSC_OWN_POINTER, &graph->dirdofsB));
429566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofsB));
43d62866d3SStefano Zampini   }
44d62866d3SStefano Zampini   *dirdofs = graph->dirdofsB;
453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46d62866d3SStefano Zampini }
47d62866d3SStefano Zampini 
PCBDDCGraphGetDirichletDofs(PCBDDCGraph graph,IS * dirdofs)48d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphGetDirichletDofs(PCBDDCGraph graph, IS *dirdofs)
49d71ae5a4SJacob Faibussowitsch {
501b968477SStefano Zampini   PetscFunctionBegin;
51a07ea27aSStefano Zampini   if (graph->dirdofs) {
529566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofs));
53a07ea27aSStefano Zampini   } else if (graph->has_dirichlet) {
54a07ea27aSStefano Zampini     PetscInt  i, size;
55a07ea27aSStefano Zampini     PetscInt *dirdofs_idxs;
56a07ea27aSStefano Zampini 
571b968477SStefano Zampini     size = 0;
581b968477SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
599de2952eSStefano Zampini       if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) size++;
601b968477SStefano Zampini     }
611b968477SStefano Zampini 
629566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(size, &dirdofs_idxs));
631b968477SStefano Zampini     size = 0;
641b968477SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
659de2952eSStefano Zampini       if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) dirdofs_idxs[size++] = i;
661b968477SStefano Zampini     }
679566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)graph->l2gmap), size, dirdofs_idxs, PETSC_OWN_POINTER, &graph->dirdofs));
689566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)graph->dirdofs));
691b968477SStefano Zampini   }
70a07ea27aSStefano Zampini   *dirdofs = graph->dirdofs;
713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
721b968477SStefano Zampini }
731b968477SStefano Zampini 
PCBDDCGraphASCIIView(PCBDDCGraph graph,PetscInt verbosity_level,PetscViewer viewer)74d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphASCIIView(PCBDDCGraph graph, PetscInt verbosity_level, PetscViewer viewer)
75d71ae5a4SJacob Faibussowitsch {
762b510759SStefano Zampini   PetscInt  i, j, tabs;
7793fb5fd3SStefano Zampini   PetscInt *queue_in_global_numbering;
78674ae819SStefano Zampini 
79674ae819SStefano Zampini   PetscFunctionBegin;
8094d400adSStefano Zampini   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(graph->seq_graph ? PETSC_COMM_SELF : PetscObjectComm((PetscObject)graph->l2gmap), &viewer));
819566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
829566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIGetTab(viewer, &tabs));
839566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "--------------------------------------------------\n"));
849566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
859de2952eSStefano Zampini   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Local BDDC graph for subdomain %04d (seq %d)\n", PetscGlobalRank, graph->seq_graph));
8663a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of vertices %" PetscInt_FMT "\n", graph->nvtxs));
8763a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of local subdomains %" PetscInt_FMT "\n", graph->n_local_subs ? graph->n_local_subs : 1));
8863a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Custom minimal size %" PetscInt_FMT "\n", graph->custom_minimal_size));
891690c2aeSBarry Smith   if (graph->maxcount != PETSC_INT_MAX) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Max count %" PetscInt_FMT "\n", graph->maxcount));
9063a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Topological two dim? %s (set %s)\n", PetscBools[graph->twodim], PetscBools[graph->twodimset]));
91d4890cceSStefano Zampini   if (verbosity_level > 2) {
92674ae819SStefano Zampini     for (i = 0; i < graph->nvtxs; i++) {
9363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":\n", i));
949de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   which_dof: %" PetscInt_FMT "\n", graph->nodes[i].which_dof));
959de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   special_dof: %" PetscInt_FMT "\n", graph->nodes[i].special_dof));
969de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   shared by: %" PetscInt_FMT "\n", graph->nodes[i].count));
979566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
989de2952eSStefano Zampini       if (graph->nodes[i].count) {
999566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     set of neighbours:"));
1009de2952eSStefano Zampini         for (j = 0; j < graph->nodes[i].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].neighbours_set[j]));
1019566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
102674ae819SStefano Zampini       }
1039566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1049566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1059de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   number of local groups: %" PetscInt_FMT "\n", graph->nodes[i].local_groups_count));
1069566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1079de2952eSStefano Zampini       if (graph->nodes[i].local_groups_count) {
1089de2952eSStefano Zampini         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     groups:"));
1099de2952eSStefano Zampini         for (j = 0; j < graph->nodes[i].local_groups_count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].local_groups[j]));
1109566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1119de2952eSStefano Zampini       }
1129566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1139566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1149de2952eSStefano Zampini 
115d4890cceSStefano Zampini       if (verbosity_level > 3) {
1161633d1f0SStefano Zampini         if (graph->xadj) {
1179566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   local adj list:"));
1189566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
11948a46eb9SPierre Jolivet           for (j = graph->xadj[i]; j < graph->xadj[i + 1]; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->adjncy[j]));
1209566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1219566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1229566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
123ec1c413dSStefano Zampini         } else {
1249566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   no adj info\n"));
125674ae819SStefano Zampini         }
126e49050b4SStefano Zampini       }
12748a46eb9SPierre Jolivet       if (graph->n_local_subs) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   local sub id: %" PetscInt_FMT "\n", graph->local_subs[i]));
1289de2952eSStefano Zampini       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "   interface subset id: %" PetscInt_FMT "\n", graph->nodes[i].subset));
1299de2952eSStefano 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]));
130674ae819SStefano Zampini     }
131e49050b4SStefano Zampini   }
13263a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Total number of connected components %" PetscInt_FMT "\n", graph->ncc));
1339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_in_global_numbering));
1349566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_in_global_numbering));
135674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
1361ce3d396SStefano Zampini     PetscInt  node_num = graph->queue[graph->cptr[i]];
1371ce3d396SStefano Zampini     PetscBool printcc  = PETSC_FALSE;
1389de2952eSStefano 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));
1399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1409de2952eSStefano Zampini     for (j = 0; j < graph->nodes[node_num].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[node_num].neighbours_set[j]));
141d4890cceSStefano Zampini     if (verbosity_level > 1) {
1429566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "):"));
143ac530a7eSPierre Jolivet       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;
1441ce3d396SStefano Zampini       if (printcc) {
14548a46eb9SPierre 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]));
1461ce3d396SStefano Zampini       }
147d4890cceSStefano Zampini     } else {
1489566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ")"));
149d4890cceSStefano Zampini     }
1509566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n"));
1519566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIISetTab(viewer, tabs));
1529566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
153674ae819SStefano Zampini   }
1549566063dSJacob Faibussowitsch   PetscCall(PetscFree(queue_in_global_numbering));
1559566063dSJacob Faibussowitsch   PetscCall(PetscViewerFlush(viewer));
1563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
157674ae819SStefano Zampini }
158674ae819SStefano Zampini 
PCBDDCGraphRestoreCandidatesIS(PCBDDCGraph graph,PetscInt * n_faces,IS * FacesIS[],PetscInt * n_edges,IS * EdgesIS[],IS * VerticesIS)159d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphRestoreCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS)
160d71ae5a4SJacob Faibussowitsch {
161c8272957SStefano Zampini   PetscInt       i;
16232fe681dSStefano Zampini   PetscContainer gcand;
163c8272957SStefano Zampini 
164c8272957SStefano Zampini   PetscFunctionBegin;
16532fe681dSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand));
16632fe681dSStefano Zampini   if (gcand) {
16732fe681dSStefano Zampini     if (n_faces) *n_faces = 0;
16832fe681dSStefano Zampini     if (n_edges) *n_edges = 0;
16932fe681dSStefano Zampini     if (FacesIS) *FacesIS = NULL;
17032fe681dSStefano Zampini     if (EdgesIS) *EdgesIS = NULL;
17132fe681dSStefano Zampini     if (VerticesIS) *VerticesIS = NULL;
17232fe681dSStefano Zampini   }
173c8272957SStefano Zampini   if (n_faces) {
174c8272957SStefano Zampini     if (FacesIS) {
17557508eceSPierre Jolivet       for (i = 0; i < *n_faces; i++) PetscCall(ISDestroy(&(*FacesIS)[i]));
1769566063dSJacob Faibussowitsch       PetscCall(PetscFree(*FacesIS));
177c8272957SStefano Zampini     }
178c8272957SStefano Zampini     *n_faces = 0;
179c8272957SStefano Zampini   }
180c8272957SStefano Zampini   if (n_edges) {
181c8272957SStefano Zampini     if (EdgesIS) {
18257508eceSPierre Jolivet       for (i = 0; i < *n_edges; i++) PetscCall(ISDestroy(&(*EdgesIS)[i]));
1839566063dSJacob Faibussowitsch       PetscCall(PetscFree(*EdgesIS));
184c8272957SStefano Zampini     }
185c8272957SStefano Zampini     *n_edges = 0;
186c8272957SStefano Zampini   }
1871baa6e33SBarry Smith   if (VerticesIS) PetscCall(ISDestroy(VerticesIS));
1883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
189c8272957SStefano Zampini }
190c8272957SStefano Zampini 
PCBDDCGraphGetCandidatesIS(PCBDDCGraph graph,PetscInt * n_faces,IS * FacesIS[],PetscInt * n_edges,IS * EdgesIS[],IS * VerticesIS)191d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphGetCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS)
192d71ae5a4SJacob Faibussowitsch {
193674ae819SStefano Zampini   IS            *ISForFaces, *ISForEdges, ISForVertices;
194be12c134Sstefano_zampini   PetscInt       i, nfc, nec, nvc, *idx, *mark;
19532fe681dSStefano Zampini   PetscContainer gcand;
196674ae819SStefano Zampini 
197674ae819SStefano Zampini   PetscFunctionBegin;
19832fe681dSStefano Zampini   PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand));
19932fe681dSStefano Zampini   if (gcand) {
20032fe681dSStefano Zampini     PCBDDCGraphCandidates cand;
20132fe681dSStefano Zampini 
202*2a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(gcand, &cand));
20332fe681dSStefano Zampini     if (n_faces) *n_faces = cand->nfc;
20432fe681dSStefano Zampini     if (FacesIS) *FacesIS = cand->Faces;
20532fe681dSStefano Zampini     if (n_edges) *n_edges = cand->nec;
20632fe681dSStefano Zampini     if (EdgesIS) *EdgesIS = cand->Edges;
20732fe681dSStefano Zampini     if (VerticesIS) *VerticesIS = cand->Vertices;
2083ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20932fe681dSStefano Zampini   }
2109566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(graph->ncc, &mark));
211da81f932SPierre Jolivet   /* loop on ccs to evaluate number of faces, edges and vertices */
212674ae819SStefano Zampini   nfc = 0;
213674ae819SStefano Zampini   nec = 0;
214674ae819SStefano Zampini   nvc = 0;
215674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
2161e1f2d93SStefano Zampini     PetscInt repdof = graph->queue[graph->cptr[i]];
2179de2952eSStefano Zampini     if (graph->cptr[i + 1] - graph->cptr[i] > graph->custom_minimal_size && graph->nodes[repdof].count <= graph->maxcount) {
2189de2952eSStefano Zampini       if (!graph->twodim && graph->nodes[repdof].count == 2 && graph->nodes[repdof].special_dof != PCBDDCGRAPH_NEUMANN_MARK) {
219674ae819SStefano Zampini         nfc++;
220be12c134Sstefano_zampini         mark[i] = 2;
221be12c134Sstefano_zampini       } else {
222674ae819SStefano Zampini         nec++;
223be12c134Sstefano_zampini         mark[i] = 1;
224674ae819SStefano Zampini       }
225674ae819SStefano Zampini     } else {
226674ae819SStefano Zampini       nvc += graph->cptr[i + 1] - graph->cptr[i];
227674ae819SStefano Zampini     }
228674ae819SStefano Zampini   }
229adfc4fb2SStefano Zampini 
230674ae819SStefano Zampini   /* allocate IS arrays for faces, edges. Vertices need a single index set. */
23148a46eb9SPierre Jolivet   if (FacesIS) PetscCall(PetscMalloc1(nfc, &ISForFaces));
23248a46eb9SPierre Jolivet   if (EdgesIS) PetscCall(PetscMalloc1(nec, &ISForEdges));
23348a46eb9SPierre Jolivet   if (VerticesIS) PetscCall(PetscMalloc1(nvc, &idx));
234cf5a6209SStefano Zampini 
235674ae819SStefano Zampini   /* loop on ccs to compute index sets for faces and edges */
236acc113dbSStefano Zampini   if (!graph->queue_sorted) {
237acc113dbSStefano Zampini     PetscInt *queue_global;
238acc113dbSStefano Zampini 
2399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global));
2409566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global));
24148a46eb9SPierre 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]]));
2429566063dSJacob Faibussowitsch     PetscCall(PetscFree(queue_global));
243acc113dbSStefano Zampini     graph->queue_sorted = PETSC_TRUE;
244acc113dbSStefano Zampini   }
245674ae819SStefano Zampini   nfc = 0;
246674ae819SStefano Zampini   nec = 0;
247674ae819SStefano Zampini   for (i = 0; i < graph->ncc; i++) {
248be12c134Sstefano_zampini     if (mark[i] == 2) {
24948a46eb9SPierre 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]));
250674ae819SStefano Zampini       nfc++;
251be12c134Sstefano_zampini     } else if (mark[i] == 1) {
25248a46eb9SPierre 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]));
253674ae819SStefano Zampini       nec++;
254674ae819SStefano Zampini     }
255674ae819SStefano Zampini   }
256be12c134Sstefano_zampini 
257674ae819SStefano Zampini   /* index set for vertices */
258cf5a6209SStefano Zampini   if (VerticesIS) {
259b8ffe317SStefano Zampini     nvc = 0;
260674ae819SStefano Zampini     for (i = 0; i < graph->ncc; i++) {
261be12c134Sstefano_zampini       if (!mark[i]) {
262adfc4fb2SStefano Zampini         PetscInt j;
263adfc4fb2SStefano Zampini 
264674ae819SStefano Zampini         for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) {
265674ae819SStefano Zampini           idx[nvc] = graph->queue[j];
266674ae819SStefano Zampini           nvc++;
267674ae819SStefano Zampini         }
268674ae819SStefano Zampini       }
269674ae819SStefano Zampini     }
270674ae819SStefano Zampini     /* sort vertex set (by local ordering) */
2719566063dSJacob Faibussowitsch     PetscCall(PetscSortInt(nvc, idx));
2729566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nvc, idx, PETSC_OWN_POINTER, &ISForVertices));
273674ae819SStefano Zampini   }
2749566063dSJacob Faibussowitsch   PetscCall(PetscFree(mark));
275be12c134Sstefano_zampini 
276674ae819SStefano Zampini   /* get back info */
277a873d5d0SStefano Zampini   if (n_faces) *n_faces = nfc;
278c8272957SStefano Zampini   if (FacesIS) *FacesIS = ISForFaces;
279a873d5d0SStefano Zampini   if (n_edges) *n_edges = nec;
280c8272957SStefano Zampini   if (EdgesIS) *EdgesIS = ISForEdges;
281c8272957SStefano Zampini   if (VerticesIS) *VerticesIS = ISForVertices;
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
283674ae819SStefano Zampini }
284674ae819SStefano Zampini 
PCBDDCGraphComputeConnectedComponents(PCBDDCGraph graph)285d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphComputeConnectedComponents(PCBDDCGraph graph)
286d71ae5a4SJacob Faibussowitsch {
2879de2952eSStefano Zampini   PetscBool adapt_interface;
288674ae819SStefano Zampini   MPI_Comm  interface_comm;
2899de2952eSStefano Zampini   PetscBT   cornerp = NULL;
290674ae819SStefano Zampini 
291674ae819SStefano Zampini   PetscFunctionBegin;
292f4f49eeaSPierre Jolivet   PetscCall(PetscObjectGetComm((PetscObject)graph->l2gmap, &interface_comm));
2939de2952eSStefano Zampini   /* compute connected components locally */
2949566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphComputeConnectedComponentsLocal(graph));
2959de2952eSStefano Zampini   if (graph->seq_graph) PetscFunctionReturn(PETSC_SUCCESS);
2961c7a958bSStefano Zampini 
2979de2952eSStefano Zampini   if (graph->active_coords && !graph->multi_element) { /* face based corner selection XXX multi_element */
2984f819b78SStefano Zampini     PetscBT    excluded;
2991c7a958bSStefano Zampini     PetscReal *wdist;
3001c7a958bSStefano Zampini     PetscInt   n_neigh, *neigh, *n_shared, **shared;
3011c7a958bSStefano Zampini     PetscInt   maxc, ns;
3021c7a958bSStefano Zampini 
3039566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(graph->nvtxs, &cornerp));
3049566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingGetInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared));
3051c7a958bSStefano Zampini     for (ns = 1, maxc = 0; ns < n_neigh; ns++) maxc = PetscMax(maxc, n_shared[ns]);
3069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxc * graph->cdim, &wdist));
3079566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(maxc, &excluded));
3081c7a958bSStefano Zampini 
3091c7a958bSStefano Zampini     for (ns = 1; ns < n_neigh; ns++) { /* first proc is self */
3101c7a958bSStefano Zampini       PetscReal *anchor, mdist;
3114f819b78SStefano Zampini       PetscInt   fst, j, k, d, cdim = graph->cdim, n = n_shared[ns];
31251ab8ad6SStefano Zampini       PetscInt   point1, point2, point3, point4;
3131c7a958bSStefano Zampini 
3141c7a958bSStefano Zampini       /* import coordinates on shared interface */
3159566063dSJacob Faibussowitsch       PetscCall(PetscBTMemzero(n, excluded));
3164f819b78SStefano Zampini       for (j = 0, fst = -1, k = 0; j < n; j++) {
3174f819b78SStefano Zampini         PetscBool skip = PETSC_FALSE;
3184f819b78SStefano Zampini         for (d = 0; d < cdim; d++) {
3194f819b78SStefano Zampini           PetscReal c = graph->coords[shared[ns][j] * cdim + d];
3204f819b78SStefano Zampini           skip        = (PetscBool)(skip || c == PETSC_MAX_REAL);
3214f819b78SStefano Zampini           wdist[k++]  = c;
3224f819b78SStefano Zampini         }
323ac530a7eSPierre Jolivet         if (skip) PetscCall(PetscBTSet(excluded, j));
324ac530a7eSPierre Jolivet         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   }
4345440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &adapt_interface, 1, MPI_C_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     }
5635440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(&twodim, &graph->twodim, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)graph->l2gmap)));
564cc0a5675Sstefano_zampini     graph->twodimset = PETSC_TRUE;
565cc0a5675Sstefano_zampini   }
5663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
567674ae819SStefano Zampini }
568674ae819SStefano Zampini 
PCBDDCGraphComputeCC_Private(PCBDDCGraph graph,PetscInt pid,PetscInt * PETSC_RESTRICT queue_tip,PetscInt n_prev,PetscInt * n_added)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 
PCBDDCGraphComputeConnectedComponentsLocal(PCBDDCGraph graph)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 
PCBDDCGraphSetUp(PCBDDCGraph graph,PetscInt custom_minimal_size,IS neumann_is,IS dirichlet_is,PetscInt n_ISForDofs,IS ISForDofs[],IS custom_primal_vertices)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;
7312daa06b4SStefano Zampini   PetscHMapPCBDDCGraphNode subsetmaps;
732674ae819SStefano Zampini   const PetscInt          *is_indices;
7332daa06b4SStefano Zampini   PetscInt                *queue_global, *nodecount, **nodeneighs, *subset_sizes;
7342daa06b4SStefano Zampini   PetscInt                 i, j, k, nodes_touched, is_size, nvtxs = graph->nvtxs;
7359de2952eSStefano Zampini   PetscMPIInt              size, rank;
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));
7895440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &graph->multi_element, 1, MPI_C_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));
857835f2295SStefano Zampini     PetscCall(ISGetIndices(ISForDofs[i], &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     }
869835f2295SStefano Zampini     PetscCall(ISRestoreIndices(ISForDofs[i], &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));
876835f2295SStefano Zampini     PetscCall(ISGetIndices(neumann_is, &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     }
882835f2295SStefano Zampini     PetscCall(ISRestoreIndices(neumann_is, &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));
888835f2295SStefano Zampini     PetscCall(ISGetIndices(dirichlet_is, &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     }
898835f2295SStefano Zampini     PetscCall(ISRestoreIndices(dirichlet_is, &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));
904835f2295SStefano Zampini     PetscCall(ISGetIndices(custom_primal_vertices, &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     }
911835f2295SStefano Zampini     PetscCall(ISRestoreIndices(custom_primal_vertices, &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++) {
9172daa06b4SStefano Zampini       const PetscInt icount = graph->nodes[i].count;
9189de2952eSStefano Zampini       if (graph->nodes[i].count < 2) {
9199de2952eSStefano Zampini         graph->nodes[i].touched = PETSC_TRUE;
9209de2952eSStefano Zampini         graph->nodes[i].subset  = 0;
9212daa06b4SStefano Zampini       } else {
9222daa06b4SStefano Zampini         if (graph->multi_element) {
9232daa06b4SStefano Zampini           graph->nodes[i].shared = PETSC_FALSE;
9242daa06b4SStefano Zampini           for (k = 0; k < icount; k++)
9252daa06b4SStefano Zampini             if (graph->nodes[i].neighbours_set[k] != rank) {
9262daa06b4SStefano Zampini               graph->nodes[i].shared = PETSC_TRUE;
9272daa06b4SStefano Zampini               break;
9282daa06b4SStefano Zampini             }
9292daa06b4SStefano Zampini         } else {
9302daa06b4SStefano Zampini           graph->nodes[i].shared = PETSC_TRUE;
931674ae819SStefano Zampini         }
932674ae819SStefano Zampini       }
933b3cdcd63SStefano Zampini     }
9342daa06b4SStefano Zampini   } else {
9352daa06b4SStefano Zampini     for (i = 0; i < nvtxs; i++) graph->nodes[i].shared = PETSC_TRUE;
9362daa06b4SStefano Zampini   }
937b3cdcd63SStefano Zampini 
938674ae819SStefano Zampini   /* init graph structure and compute default subsets */
939674ae819SStefano Zampini   nodes_touched = 0;
9409de2952eSStefano Zampini   for (i = 0; i < nvtxs; i++)
9419de2952eSStefano Zampini     if (graph->nodes[i].touched) nodes_touched++;
9429de2952eSStefano Zampini 
9437babac9bSStefano Zampini   /* allocated space for queues */
9449de2952eSStefano Zampini   if (graph->seq_graph) {
9459de2952eSStefano Zampini     PetscCall(PetscMalloc2(nvtxs + 1, &graph->cptr, nvtxs, &graph->queue));
9467babac9bSStefano Zampini   } else {
9479de2952eSStefano Zampini     PetscInt nused = nvtxs - nodes_touched;
9489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nused + 1, &graph->cptr, nused, &graph->queue));
9497babac9bSStefano Zampini   }
9507babac9bSStefano Zampini 
9512daa06b4SStefano Zampini   graph->ncc = 0;
9522daa06b4SStefano Zampini   PetscCall(PetscHMapPCBDDCGraphNodeCreate(&subsetmaps));
9532daa06b4SStefano Zampini   PetscCall(PetscCalloc1(nvtxs, &subset_sizes));
9542daa06b4SStefano Zampini   for (i = 0; i < nvtxs; i++) {
9552daa06b4SStefano Zampini     PetscHashIter iter;
9562daa06b4SStefano Zampini     PetscBool     missing;
9572daa06b4SStefano Zampini     PetscInt      subset;
9582daa06b4SStefano Zampini 
9592daa06b4SStefano Zampini     if (graph->nodes[i].touched) continue;
9609de2952eSStefano Zampini     graph->nodes[i].touched = PETSC_TRUE;
9612daa06b4SStefano Zampini     PetscCall(PetscHMapPCBDDCGraphNodePut(subsetmaps, &graph->nodes[i], &iter, &missing));
9622daa06b4SStefano Zampini     if (missing) {
963674ae819SStefano Zampini       graph->ncc++;
9642daa06b4SStefano Zampini       PetscCall(PetscHMapPCBDDCGraphNodeIterSet(subsetmaps, iter, graph->ncc));
9652daa06b4SStefano Zampini       subset = graph->ncc;
9662daa06b4SStefano Zampini     } else PetscCall(PetscHMapPCBDDCGraphNodeIterGet(subsetmaps, iter, &subset));
9672daa06b4SStefano Zampini     subset_sizes[subset - 1] += 1;
9682daa06b4SStefano Zampini     graph->nodes[i].subset = subset;
969674ae819SStefano Zampini   }
9702daa06b4SStefano Zampini 
9712daa06b4SStefano Zampini   graph->cptr[0] = 0;
9722daa06b4SStefano Zampini   for (i = 0; i < graph->ncc; i++) graph->cptr[i + 1] = graph->cptr[i] + subset_sizes[i];
9732daa06b4SStefano Zampini   for (i = 0; i < graph->ncc; i++) subset_sizes[i] = 0;
9742daa06b4SStefano Zampini 
9752daa06b4SStefano Zampini   for (i = 0; i < nvtxs; i++) {
9762daa06b4SStefano Zampini     const PetscInt subset = graph->nodes[i].subset - 1;
9772daa06b4SStefano Zampini     if (subset < 0) continue;
9782daa06b4SStefano Zampini     PetscCheck(subset_sizes[subset] + graph->cptr[subset] < graph->cptr[subset + 1], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error for subset %" PetscInt_FMT, subset);
9792daa06b4SStefano Zampini     graph->queue[subset_sizes[subset] + graph->cptr[subset]] = i;
9802daa06b4SStefano Zampini     subset_sizes[subset] += 1;
9812daa06b4SStefano Zampini   }
9822daa06b4SStefano Zampini   for (i = 0; i < graph->ncc; i++) PetscCheck(subset_sizes[i] + graph->cptr[i] == graph->cptr[i + 1], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error for subset %" PetscInt_FMT, i);
9832daa06b4SStefano Zampini 
9842daa06b4SStefano Zampini   PetscCall(PetscHMapPCBDDCGraphNodeDestroy(&subsetmaps));
9852daa06b4SStefano Zampini   PetscCall(PetscFree(subset_sizes));
9869de2952eSStefano Zampini 
9879de2952eSStefano Zampini   /* set default number of subsets */
988674ae819SStefano Zampini   graph->n_subsets = graph->ncc;
9899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->n_subsets, &graph->subset_ncc));
990ad540459SPierre Jolivet   for (i = 0; i < graph->n_subsets; i++) graph->subset_ncc[i] = 1;
991ec1c413dSStefano Zampini 
9929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->ncc, &graph->subset_ref_node));
9939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global));
9949de2952eSStefano Zampini   PetscCall(PetscMalloc2(graph->ncc, &graph->subset_size, graph->ncc, &graph->subset_idxs));
9959de2952eSStefano Zampini   if (graph->multi_element) PetscCall(PetscMalloc1(graph->ncc, &graph->gsubset_size));
9969de2952eSStefano Zampini   else graph->gsubset_size = graph->subset_size;
9979566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global));
9989de2952eSStefano Zampini 
9999de2952eSStefano Zampini   PetscHMapI cnt_unique;
10009de2952eSStefano Zampini 
10019de2952eSStefano Zampini   PetscCall(PetscHMapICreate(&cnt_unique));
1002ec1c413dSStefano Zampini   for (j = 0; j < graph->ncc; j++) {
10031690c2aeSBarry Smith     PetscInt c = 0, ref_node = PETSC_INT_MAX;
10049de2952eSStefano Zampini 
10059de2952eSStefano Zampini     for (k = graph->cptr[j]; k < graph->cptr[j + 1]; k++) {
10069de2952eSStefano Zampini       ref_node = PetscMin(ref_node, queue_global[k]);
10079de2952eSStefano Zampini       if (graph->multi_element) {
10089de2952eSStefano Zampini         PetscBool     missing;
10099de2952eSStefano Zampini         PetscHashIter iter;
10109de2952eSStefano Zampini 
10119de2952eSStefano Zampini         PetscCall(PetscHMapIPut(cnt_unique, queue_global[k], &iter, &missing));
10129de2952eSStefano Zampini         if (missing) c++;
1013f0321c90SStefano Zampini       }
10149de2952eSStefano Zampini     }
10159de2952eSStefano Zampini     graph->gsubset_size[j]    = c;
10169de2952eSStefano Zampini     graph->subset_size[j]     = graph->cptr[j + 1] - graph->cptr[j];
10179de2952eSStefano Zampini     graph->subset_ref_node[j] = ref_node;
10189de2952eSStefano Zampini     if (graph->multi_element) PetscCall(PetscHMapIClear(cnt_unique));
10199de2952eSStefano Zampini   }
10209de2952eSStefano Zampini   PetscCall(PetscHMapIDestroy(&cnt_unique));
102148bebe3cSStefano Zampini 
1022b3cdcd63SStefano Zampini   /* save information on subsets (needed when analyzing the connected components) */
10232f566a09SStefano Zampini   if (graph->ncc) {
10249566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &graph->subset_idxs[0]));
10259566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(graph->subset_idxs[0], graph->cptr[graph->ncc]));
1026ac530a7eSPierre Jolivet     for (j = 1; j < graph->ncc; j++) graph->subset_idxs[j] = graph->subset_idxs[j - 1] + graph->subset_size[j - 1];
10279566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(graph->subset_idxs[0], graph->queue, graph->cptr[graph->ncc]));
1028ec1c413dSStefano Zampini   }
1029b3cdcd63SStefano Zampini 
10309de2952eSStefano Zampini   /* check consistency and create SF to analyze components on the interface between subdomains */
10319de2952eSStefano Zampini   if (!graph->seq_graph) {
10329de2952eSStefano Zampini     PetscSF         msf;
10339de2952eSStefano Zampini     PetscLayout     map;
10349de2952eSStefano Zampini     const PetscInt *degree;
10359de2952eSStefano Zampini     PetscInt        nr, nmr, *rdata;
10369de2952eSStefano Zampini     PetscBool       valid = PETSC_TRUE;
10379de2952eSStefano Zampini     PetscInt        subset_N;
10389de2952eSStefano Zampini     IS              subset_n;
10399de2952eSStefano Zampini     const PetscInt *idxs;
10409de2952eSStefano Zampini 
10419de2952eSStefano Zampini     PetscCall(ISCreateGeneral(comm, graph->n_subsets, graph->subset_ref_node, PETSC_USE_POINTER, &subset));
10429de2952eSStefano Zampini     PetscCall(ISRenumber(subset, NULL, &subset_N, &subset_n));
10439566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&subset));
10449de2952eSStefano Zampini 
10459de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &graph->interface_ref_sf));
10469de2952eSStefano Zampini     PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, subset_N, 1, &map));
10479de2952eSStefano Zampini     PetscCall(ISGetIndices(subset_n, &idxs));
10489de2952eSStefano Zampini     PetscCall(PetscSFSetGraphLayout(graph->interface_ref_sf, map, graph->n_subsets, NULL, PETSC_OWN_POINTER, idxs));
10499de2952eSStefano Zampini     PetscCall(ISRestoreIndices(subset_n, &idxs));
10509566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&subset_n));
10519de2952eSStefano Zampini     PetscCall(PetscLayoutDestroy(&map));
10529de2952eSStefano Zampini 
10539de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeBegin(graph->interface_ref_sf, &degree));
10549de2952eSStefano Zampini     PetscCall(PetscSFComputeDegreeEnd(graph->interface_ref_sf, &degree));
10559de2952eSStefano Zampini     PetscCall(PetscSFGetMultiSF(graph->interface_ref_sf, &msf));
10569de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, &nr, NULL, NULL, NULL));
10579de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL));
10589de2952eSStefano Zampini     PetscCall(PetscCalloc1(nmr, &rdata));
10599de2952eSStefano Zampini     PetscCall(PetscSFGatherBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata));
10609de2952eSStefano Zampini     PetscCall(PetscSFGatherEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata));
10619de2952eSStefano Zampini     for (PetscInt i = 0, c = 0; i < nr && valid; i++) {
10629de2952eSStefano Zampini       for (PetscInt j = 0; j < degree[i]; j++) {
10639de2952eSStefano Zampini         if (rdata[j + c] != rdata[c]) valid = PETSC_FALSE;
10649de2952eSStefano Zampini       }
10659de2952eSStefano Zampini       c += degree[i];
10669de2952eSStefano Zampini     }
10679de2952eSStefano Zampini     PetscCall(PetscFree(rdata));
10685440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &valid, 1, MPI_C_BOOL, MPI_LAND, comm));
10699de2952eSStefano Zampini     PetscCheck(valid, comm, PETSC_ERR_PLIB, "Initial local subsets are not consistent");
10709de2952eSStefano Zampini 
10719de2952eSStefano Zampini     /* Now create SF with each root extended to gsubset_size roots */
1072e4ebd542SJose E. Roman     PetscInt           mss = 0;
10739de2952eSStefano Zampini     const PetscSFNode *subs_remote;
10749de2952eSStefano Zampini 
10759de2952eSStefano Zampini     PetscCall(PetscSFGetGraph(graph->interface_ref_sf, NULL, NULL, NULL, &subs_remote));
1076e4ebd542SJose E. Roman     for (PetscInt i = 0; i < graph->n_subsets; i++) mss = PetscMax(graph->subset_size[i], mss);
10779de2952eSStefano Zampini 
10789de2952eSStefano Zampini     PetscInt nri, nli, *start_rsize, *cum_rsize;
10799de2952eSStefano Zampini     PetscCall(PetscCalloc1(graph->n_subsets + 1, &start_rsize));
10809de2952eSStefano Zampini     PetscCall(PetscCalloc1(nr, &graph->interface_ref_rsize));
10819de2952eSStefano Zampini     PetscCall(PetscMalloc1(nr + 1, &cum_rsize));
10829de2952eSStefano Zampini     PetscCall(PetscSFReduceBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE));
10839de2952eSStefano Zampini     PetscCall(PetscSFReduceEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE));
10849de2952eSStefano Zampini 
10859de2952eSStefano Zampini     nri          = 0;
10869de2952eSStefano Zampini     cum_rsize[0] = 0;
1087e4ebd542SJose E. Roman     for (PetscInt i = 0; i < nr; i++) {
10889de2952eSStefano Zampini       nri += graph->interface_ref_rsize[i];
10899de2952eSStefano Zampini       cum_rsize[i + 1] = cum_rsize[i] + graph->interface_ref_rsize[i];
10909de2952eSStefano Zampini     }
10919de2952eSStefano Zampini     nli = graph->cptr[graph->ncc];
10929de2952eSStefano Zampini     PetscCall(PetscSFBcastBegin(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE));
10939de2952eSStefano Zampini     PetscCall(PetscSFBcastEnd(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE));
10949de2952eSStefano Zampini     PetscCall(PetscFree(cum_rsize));
10959de2952eSStefano Zampini 
10969de2952eSStefano Zampini     PetscInt    *ilocal, *queue_global_uniq;
10979de2952eSStefano Zampini     PetscSFNode *iremote;
10989de2952eSStefano Zampini     PetscBool   *touched;
10999de2952eSStefano Zampini 
11009de2952eSStefano Zampini     PetscCall(PetscSFCreate(comm, &graph->interface_subset_sf));
11019de2952eSStefano Zampini     PetscCall(PetscMalloc1(nli, &ilocal));
11029de2952eSStefano Zampini     PetscCall(PetscMalloc1(nli, &iremote));
11039de2952eSStefano Zampini     PetscCall(PetscMalloc2(mss, &queue_global_uniq, mss, &touched));
1104e4ebd542SJose E. Roman     for (PetscInt i = 0, nli = 0; i < graph->n_subsets; i++) {
11056497c311SBarry Smith       const PetscMPIInt rr                = (PetscMPIInt)subs_remote[i].rank;
11069de2952eSStefano Zampini       const PetscInt    start             = start_rsize[i];
11079de2952eSStefano Zampini       const PetscInt    subset_size       = graph->subset_size[i];
11089de2952eSStefano Zampini       const PetscInt    gsubset_size      = graph->gsubset_size[i];
11099de2952eSStefano Zampini       const PetscInt   *subset_idxs       = graph->subset_idxs[i];
11109de2952eSStefano Zampini       const PetscInt   *lsub_queue_global = queue_global + graph->cptr[i];
11119de2952eSStefano Zampini 
11129de2952eSStefano Zampini       k = subset_size;
11139de2952eSStefano Zampini       PetscCall(PetscArrayzero(touched, subset_size));
11149de2952eSStefano Zampini       PetscCall(PetscArraycpy(queue_global_uniq, lsub_queue_global, subset_size));
11159de2952eSStefano Zampini       PetscCall(PetscSortRemoveDupsInt(&k, queue_global_uniq));
11169de2952eSStefano 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);
11179de2952eSStefano Zampini 
11189de2952eSStefano Zampini       PetscInt t = 0, j = 0;
11199de2952eSStefano Zampini       while (t < subset_size) {
11209de2952eSStefano Zampini         while (j < subset_size && touched[j]) j++;
11219de2952eSStefano Zampini         PetscCheck(j < subset_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " >= %" PetscInt_FMT, j, subset_size);
11229de2952eSStefano Zampini         const PetscInt ls = graph->nodes[subset_idxs[j]].local_sub;
11239de2952eSStefano Zampini 
11249de2952eSStefano Zampini         for (k = j; k < subset_size; k++) {
11259de2952eSStefano Zampini           if (graph->nodes[subset_idxs[k]].local_sub == ls) {
11269de2952eSStefano Zampini             PetscInt ig;
11279de2952eSStefano Zampini 
11289de2952eSStefano Zampini             PetscCall(PetscFindInt(lsub_queue_global[k], gsubset_size, queue_global_uniq, &ig));
11299de2952eSStefano Zampini             ilocal[nli]        = subset_idxs[k];
11309de2952eSStefano Zampini             iremote[nli].rank  = rr;
11319de2952eSStefano Zampini             iremote[nli].index = start + ig;
11329de2952eSStefano Zampini             touched[k]         = PETSC_TRUE;
11339de2952eSStefano Zampini             nli++;
11349de2952eSStefano Zampini             t++;
11359de2952eSStefano Zampini           }
11369de2952eSStefano Zampini         }
11379de2952eSStefano Zampini       }
11389de2952eSStefano Zampini     }
11399de2952eSStefano 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]);
11409de2952eSStefano Zampini     PetscCall(PetscSFSetGraph(graph->interface_subset_sf, nri, nli, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
11419de2952eSStefano Zampini     PetscCall(PetscFree(start_rsize));
11429de2952eSStefano Zampini     PetscCall(PetscFree2(queue_global_uniq, touched));
11439de2952eSStefano Zampini   }
11449de2952eSStefano Zampini   PetscCall(PetscFree(queue_global));
1145ec1c413dSStefano Zampini 
1146ec1c413dSStefano Zampini   /* free workspace */
1147b3cdcd63SStefano Zampini   graph->setupcalled = PETSC_TRUE;
11483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1149674ae819SStefano Zampini }
1150674ae819SStefano Zampini 
PCBDDCGraphResetCoords(PCBDDCGraph graph)1151d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphResetCoords(PCBDDCGraph graph)
1152d71ae5a4SJacob Faibussowitsch {
1153ab8c8b98SStefano Zampini   PetscFunctionBegin;
11543ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
11559566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->coords));
1156ab8c8b98SStefano Zampini   graph->cdim  = 0;
1157ab8c8b98SStefano Zampini   graph->cnloc = 0;
1158ab8c8b98SStefano Zampini   graph->cloc  = PETSC_FALSE;
11593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1160ab8c8b98SStefano Zampini }
1161ab8c8b98SStefano Zampini 
PCBDDCGraphResetCSR(PCBDDCGraph graph)1162d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphResetCSR(PCBDDCGraph graph)
1163d71ae5a4SJacob Faibussowitsch {
1164674ae819SStefano Zampini   PetscFunctionBegin;
11653ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
1166a1dbd327SStefano Zampini   if (graph->freecsr) {
11679566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph->xadj));
11689566063dSJacob Faibussowitsch     PetscCall(PetscFree(graph->adjncy));
1169a1dbd327SStefano Zampini   } else {
1170a1dbd327SStefano Zampini     graph->xadj   = NULL;
1171a1dbd327SStefano Zampini     graph->adjncy = NULL;
1172a1dbd327SStefano Zampini   }
1173c8272957SStefano Zampini   graph->freecsr   = PETSC_FALSE;
1174575ad6abSStefano Zampini   graph->nvtxs_csr = 0;
11753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1176674ae819SStefano Zampini }
1177674ae819SStefano Zampini 
PCBDDCGraphReset(PCBDDCGraph graph)1178d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphReset(PCBDDCGraph graph)
1179d71ae5a4SJacob Faibussowitsch {
1180674ae819SStefano Zampini   PetscFunctionBegin;
11813ba16761SJacob Faibussowitsch   if (!graph) PetscFunctionReturn(PETSC_SUCCESS);
11829566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingDestroy(&graph->l2gmap));
11839566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->subset_ncc));
11849566063dSJacob Faibussowitsch   PetscCall(PetscFree(graph->subset_ref_node));
11859de2952eSStefano Zampini   for (PetscInt i = 0; i < graph->nvtxs; i++) {
11869de2952eSStefano Zampini     PetscCall(PetscFree(graph->nodes[i].neighbours_set));
11879de2952eSStefano Zampini     PetscCall(PetscFree(graph->nodes[i].local_groups));
11889de2952eSStefano Zampini   }
11899de2952eSStefano Zampini   PetscCall(PetscFree(graph->nodes));
11909566063dSJacob Faibussowitsch   PetscCall(PetscFree2(graph->cptr, graph->queue));
119148a46eb9SPierre Jolivet   if (graph->subset_idxs) PetscCall(PetscFree(graph->subset_idxs[0]));
11929566063dSJacob Faibussowitsch   PetscCall(PetscFree2(graph->subset_size, graph->subset_idxs));
11939de2952eSStefano Zampini   if (graph->multi_element) PetscCall(PetscFree(graph->gsubset_size));
11949de2952eSStefano Zampini   PetscCall(PetscFree(graph->interface_ref_rsize));
11959de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&graph->interface_subset_sf));
11969de2952eSStefano Zampini   PetscCall(PetscSFDestroy(&graph->interface_ref_sf));
11979566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&graph->dirdofs));
11989566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&graph->dirdofsB));
11991baa6e33SBarry Smith   if (graph->n_local_subs) PetscCall(PetscFree(graph->local_subs));
12009de2952eSStefano Zampini   graph->multi_element       = PETSC_FALSE;
1201a07ea27aSStefano Zampini   graph->has_dirichlet       = PETSC_FALSE;
1202cc0a5675Sstefano_zampini   graph->twodimset           = PETSC_FALSE;
1203cc0a5675Sstefano_zampini   graph->twodim              = PETSC_FALSE;
1204674ae819SStefano Zampini   graph->nvtxs               = 0;
12057babac9bSStefano Zampini   graph->nvtxs_global        = 0;
1206674ae819SStefano Zampini   graph->n_subsets           = 0;
1207674ae819SStefano Zampini   graph->custom_minimal_size = 1;
12084f1b2e48SStefano Zampini   graph->n_local_subs        = 0;
12091690c2aeSBarry Smith   graph->maxcount            = PETSC_INT_MAX;
12109de2952eSStefano Zampini   graph->seq_graph           = PETSC_FALSE;
1211fb597685SStefano Zampini   graph->setupcalled         = PETSC_FALSE;
12123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1213674ae819SStefano Zampini }
1214674ae819SStefano Zampini 
PCBDDCGraphInit(PCBDDCGraph graph,ISLocalToGlobalMapping l2gmap,PetscInt N,PetscInt maxcount)1215d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphInit(PCBDDCGraph graph, ISLocalToGlobalMapping l2gmap, PetscInt N, PetscInt maxcount)
1216d71ae5a4SJacob Faibussowitsch {
1217674ae819SStefano Zampini   PetscInt n;
1218674ae819SStefano Zampini 
1219674ae819SStefano Zampini   PetscFunctionBegin;
12204f572ea9SToby Isaac   PetscAssertPointer(graph, 1);
1221674ae819SStefano Zampini   PetscValidHeaderSpecific(l2gmap, IS_LTOGM_CLASSID, 2);
12227babac9bSStefano Zampini   PetscValidLogicalCollectiveInt(l2gmap, N, 3);
1223be12c134Sstefano_zampini   PetscValidLogicalCollectiveInt(l2gmap, maxcount, 4);
12248e61c736SStefano Zampini   /* raise an error if already allocated */
122528b400f6SJacob Faibussowitsch   PetscCheck(!graph->nvtxs_global, PetscObjectComm((PetscObject)l2gmap), PETSC_ERR_PLIB, "BDDCGraph already initialized");
1226674ae819SStefano Zampini   /* set number of vertices */
12279566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)l2gmap));
1228674ae819SStefano Zampini   graph->l2gmap = l2gmap;
12299566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n));
1230674ae819SStefano Zampini   graph->nvtxs        = n;
12317fb0e2dbSStefano Zampini   graph->nvtxs_global = N;
1232674ae819SStefano Zampini   /* allocate used space */
12339de2952eSStefano Zampini   PetscCall(PetscCalloc1(graph->nvtxs, &graph->nodes));
123463602bcaSStefano Zampini   /* use -1 as a default value for which_dof array */
12359de2952eSStefano Zampini   for (n = 0; n < graph->nvtxs; n++) graph->nodes[n].which_dof = -1;
12369de2952eSStefano Zampini 
1237674ae819SStefano Zampini   /* zeroes workspace for values of ncc */
12380a545947SLisandro Dalcin   graph->subset_ncc      = NULL;
12390a545947SLisandro Dalcin   graph->subset_ref_node = NULL;
1240be12c134Sstefano_zampini   /* maxcount for cc */
1241be12c134Sstefano_zampini   graph->maxcount = maxcount;
12423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1243674ae819SStefano Zampini }
1244674ae819SStefano Zampini 
PCBDDCGraphDestroy(PCBDDCGraph * graph)1245d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphDestroy(PCBDDCGraph *graph)
1246d71ae5a4SJacob Faibussowitsch {
1247674ae819SStefano Zampini   PetscFunctionBegin;
12489566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCSR(*graph));
12499566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphResetCoords(*graph));
12509566063dSJacob Faibussowitsch   PetscCall(PCBDDCGraphReset(*graph));
12519566063dSJacob Faibussowitsch   PetscCall(PetscFree(*graph));
12523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1253674ae819SStefano Zampini }
1254674ae819SStefano Zampini 
PCBDDCGraphCreate(PCBDDCGraph * graph)1255d71ae5a4SJacob Faibussowitsch PetscErrorCode PCBDDCGraphCreate(PCBDDCGraph *graph)
1256d71ae5a4SJacob Faibussowitsch {
1257674ae819SStefano Zampini   PCBDDCGraph new_graph;
1258674ae819SStefano Zampini 
1259674ae819SStefano Zampini   PetscFunctionBegin;
12609566063dSJacob Faibussowitsch   PetscCall(PetscNew(&new_graph));
1261674ae819SStefano Zampini   new_graph->custom_minimal_size = 1;
1262674ae819SStefano Zampini   *graph                         = new_graph;
12633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1264674ae819SStefano Zampini }
1265