1 #include <petsc/private/petscimpl.h> 2 #include <petsc/private/pcbddcprivateimpl.h> 3 #include <petsc/private/pcbddcstructsimpl.h> 4 #include <petsc/private/hashmapi.h> 5 #include <petscsf.h> 6 7 PetscErrorCode PCBDDCDestroyGraphCandidatesIS(void *ctx) 8 { 9 PCBDDCGraphCandidates cand = (PCBDDCGraphCandidates)ctx; 10 11 PetscFunctionBegin; 12 for (PetscInt i = 0; i < cand->nfc; i++) PetscCall(ISDestroy(&cand->Faces[i])); 13 for (PetscInt i = 0; i < cand->nec; i++) PetscCall(ISDestroy(&cand->Edges[i])); 14 PetscCall(PetscFree(cand->Faces)); 15 PetscCall(PetscFree(cand->Edges)); 16 PetscCall(ISDestroy(&cand->Vertices)); 17 PetscCall(PetscFree(cand)); 18 PetscFunctionReturn(PETSC_SUCCESS); 19 } 20 21 PetscErrorCode PCBDDCGraphGetDirichletDofsB(PCBDDCGraph graph, IS *dirdofs) 22 { 23 PetscFunctionBegin; 24 if (graph->dirdofsB) { 25 PetscCall(PetscObjectReference((PetscObject)graph->dirdofsB)); 26 } else if (graph->has_dirichlet) { 27 PetscInt i, size; 28 PetscInt *dirdofs_idxs; 29 30 size = 0; 31 for (i = 0; i < graph->nvtxs; i++) { 32 if (graph->nodes[i].count > 1 && graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) size++; 33 } 34 35 PetscCall(PetscMalloc1(size, &dirdofs_idxs)); 36 size = 0; 37 for (i = 0; i < graph->nvtxs; i++) { 38 if (graph->nodes[i].count > 1 && graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) dirdofs_idxs[size++] = i; 39 } 40 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, size, dirdofs_idxs, PETSC_OWN_POINTER, &graph->dirdofsB)); 41 PetscCall(PetscObjectReference((PetscObject)graph->dirdofsB)); 42 } 43 *dirdofs = graph->dirdofsB; 44 PetscFunctionReturn(PETSC_SUCCESS); 45 } 46 47 PetscErrorCode PCBDDCGraphGetDirichletDofs(PCBDDCGraph graph, IS *dirdofs) 48 { 49 PetscFunctionBegin; 50 if (graph->dirdofs) { 51 PetscCall(PetscObjectReference((PetscObject)graph->dirdofs)); 52 } else if (graph->has_dirichlet) { 53 PetscInt i, size; 54 PetscInt *dirdofs_idxs; 55 56 size = 0; 57 for (i = 0; i < graph->nvtxs; i++) { 58 if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) size++; 59 } 60 61 PetscCall(PetscMalloc1(size, &dirdofs_idxs)); 62 size = 0; 63 for (i = 0; i < graph->nvtxs; i++) { 64 if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK) dirdofs_idxs[size++] = i; 65 } 66 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)graph->l2gmap), size, dirdofs_idxs, PETSC_OWN_POINTER, &graph->dirdofs)); 67 PetscCall(PetscObjectReference((PetscObject)graph->dirdofs)); 68 } 69 *dirdofs = graph->dirdofs; 70 PetscFunctionReturn(PETSC_SUCCESS); 71 } 72 73 PetscErrorCode PCBDDCGraphASCIIView(PCBDDCGraph graph, PetscInt verbosity_level, PetscViewer viewer) 74 { 75 PetscInt i, j, tabs; 76 PetscInt *queue_in_global_numbering; 77 78 PetscFunctionBegin; 79 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(graph->seq_graph ? PETSC_COMM_SELF : PetscObjectComm((PetscObject)graph->l2gmap), &viewer)); 80 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 81 PetscCall(PetscViewerASCIIGetTab(viewer, &tabs)); 82 PetscCall(PetscViewerASCIIPrintf(viewer, "--------------------------------------------------\n")); 83 PetscCall(PetscViewerFlush(viewer)); 84 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Local BDDC graph for subdomain %04d (seq %d)\n", PetscGlobalRank, graph->seq_graph)); 85 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of vertices %" PetscInt_FMT "\n", graph->nvtxs)); 86 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Number of local subdomains %" PetscInt_FMT "\n", graph->n_local_subs ? graph->n_local_subs : 1)); 87 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Custom minimal size %" PetscInt_FMT "\n", graph->custom_minimal_size)); 88 if (graph->maxcount != PETSC_MAX_INT) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Max count %" PetscInt_FMT "\n", graph->maxcount)); 89 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Topological two dim? %s (set %s)\n", PetscBools[graph->twodim], PetscBools[graph->twodimset])); 90 if (verbosity_level > 2) { 91 for (i = 0; i < graph->nvtxs; i++) { 92 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT ":\n", i)); 93 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " which_dof: %" PetscInt_FMT "\n", graph->nodes[i].which_dof)); 94 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " special_dof: %" PetscInt_FMT "\n", graph->nodes[i].special_dof)); 95 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " shared by: %" PetscInt_FMT "\n", graph->nodes[i].count)); 96 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 97 if (graph->nodes[i].count) { 98 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " set of neighbours:")); 99 for (j = 0; j < graph->nodes[i].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].neighbours_set[j])); 100 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 101 } 102 PetscCall(PetscViewerASCIISetTab(viewer, tabs)); 103 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 104 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " number of local groups: %" PetscInt_FMT "\n", graph->nodes[i].local_groups_count)); 105 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 106 if (graph->nodes[i].local_groups_count) { 107 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " groups:")); 108 for (j = 0; j < graph->nodes[i].local_groups_count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[i].local_groups[j])); 109 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 110 } 111 PetscCall(PetscViewerASCIISetTab(viewer, tabs)); 112 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 113 114 if (verbosity_level > 3) { 115 if (graph->xadj) { 116 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " local adj list:")); 117 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 118 for (j = graph->xadj[i]; j < graph->xadj[i + 1]; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->adjncy[j])); 119 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 120 PetscCall(PetscViewerASCIISetTab(viewer, tabs)); 121 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 122 } else { 123 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " no adj info\n")); 124 } 125 } 126 if (graph->n_local_subs) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " local sub id: %" PetscInt_FMT "\n", graph->local_subs[i])); 127 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " interface subset id: %" PetscInt_FMT "\n", graph->nodes[i].subset)); 128 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])); 129 } 130 } 131 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Total number of connected components %" PetscInt_FMT "\n", graph->ncc)); 132 PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_in_global_numbering)); 133 PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_in_global_numbering)); 134 for (i = 0; i < graph->ncc; i++) { 135 PetscInt node_num = graph->queue[graph->cptr[i]]; 136 PetscBool printcc = PETSC_FALSE; 137 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)); 138 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 139 for (j = 0; j < graph->nodes[node_num].count; j++) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, graph->nodes[node_num].neighbours_set[j])); 140 if (verbosity_level > 1) { 141 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "):")); 142 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; } 143 if (printcc) { 144 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])); 145 } 146 } else { 147 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ")")); 148 } 149 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 150 PetscCall(PetscViewerASCIISetTab(viewer, tabs)); 151 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 152 } 153 PetscCall(PetscFree(queue_in_global_numbering)); 154 PetscCall(PetscViewerFlush(viewer)); 155 PetscFunctionReturn(PETSC_SUCCESS); 156 } 157 158 PetscErrorCode PCBDDCGraphRestoreCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS) 159 { 160 PetscInt i; 161 PetscContainer gcand; 162 163 PetscFunctionBegin; 164 PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand)); 165 if (gcand) { 166 if (n_faces) *n_faces = 0; 167 if (n_edges) *n_edges = 0; 168 if (FacesIS) *FacesIS = NULL; 169 if (EdgesIS) *EdgesIS = NULL; 170 if (VerticesIS) *VerticesIS = NULL; 171 } 172 if (n_faces) { 173 if (FacesIS) { 174 for (i = 0; i < *n_faces; i++) PetscCall(ISDestroy(&((*FacesIS)[i]))); 175 PetscCall(PetscFree(*FacesIS)); 176 } 177 *n_faces = 0; 178 } 179 if (n_edges) { 180 if (EdgesIS) { 181 for (i = 0; i < *n_edges; i++) PetscCall(ISDestroy(&((*EdgesIS)[i]))); 182 PetscCall(PetscFree(*EdgesIS)); 183 } 184 *n_edges = 0; 185 } 186 if (VerticesIS) PetscCall(ISDestroy(VerticesIS)); 187 PetscFunctionReturn(PETSC_SUCCESS); 188 } 189 190 PetscErrorCode PCBDDCGraphGetCandidatesIS(PCBDDCGraph graph, PetscInt *n_faces, IS *FacesIS[], PetscInt *n_edges, IS *EdgesIS[], IS *VerticesIS) 191 { 192 IS *ISForFaces, *ISForEdges, ISForVertices; 193 PetscInt i, nfc, nec, nvc, *idx, *mark; 194 PetscContainer gcand; 195 196 PetscFunctionBegin; 197 PetscCall(PetscObjectQuery((PetscObject)graph->l2gmap, "_PCBDDCGraphCandidatesIS", (PetscObject *)&gcand)); 198 if (gcand) { 199 PCBDDCGraphCandidates cand; 200 201 PetscCall(PetscContainerGetPointer(gcand, (void **)&cand)); 202 if (n_faces) *n_faces = cand->nfc; 203 if (FacesIS) *FacesIS = cand->Faces; 204 if (n_edges) *n_edges = cand->nec; 205 if (EdgesIS) *EdgesIS = cand->Edges; 206 if (VerticesIS) *VerticesIS = cand->Vertices; 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 PetscCall(PetscCalloc1(graph->ncc, &mark)); 210 /* loop on ccs to evaluate number of faces, edges and vertices */ 211 nfc = 0; 212 nec = 0; 213 nvc = 0; 214 for (i = 0; i < graph->ncc; i++) { 215 PetscInt repdof = graph->queue[graph->cptr[i]]; 216 if (graph->cptr[i + 1] - graph->cptr[i] > graph->custom_minimal_size && graph->nodes[repdof].count <= graph->maxcount) { 217 if (!graph->twodim && graph->nodes[repdof].count == 2 && graph->nodes[repdof].special_dof != PCBDDCGRAPH_NEUMANN_MARK) { 218 nfc++; 219 mark[i] = 2; 220 } else { 221 nec++; 222 mark[i] = 1; 223 } 224 } else { 225 nvc += graph->cptr[i + 1] - graph->cptr[i]; 226 } 227 } 228 229 /* allocate IS arrays for faces, edges. Vertices need a single index set. */ 230 if (FacesIS) PetscCall(PetscMalloc1(nfc, &ISForFaces)); 231 if (EdgesIS) PetscCall(PetscMalloc1(nec, &ISForEdges)); 232 if (VerticesIS) PetscCall(PetscMalloc1(nvc, &idx)); 233 234 /* loop on ccs to compute index sets for faces and edges */ 235 if (!graph->queue_sorted) { 236 PetscInt *queue_global; 237 238 PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global)); 239 PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global)); 240 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]])); 241 PetscCall(PetscFree(queue_global)); 242 graph->queue_sorted = PETSC_TRUE; 243 } 244 nfc = 0; 245 nec = 0; 246 for (i = 0; i < graph->ncc; i++) { 247 if (mark[i] == 2) { 248 if (FacesIS) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, graph->cptr[i + 1] - graph->cptr[i], &graph->queue[graph->cptr[i]], PETSC_USE_POINTER, &ISForFaces[nfc])); 249 nfc++; 250 } else if (mark[i] == 1) { 251 if (EdgesIS) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, graph->cptr[i + 1] - graph->cptr[i], &graph->queue[graph->cptr[i]], PETSC_USE_POINTER, &ISForEdges[nec])); 252 nec++; 253 } 254 } 255 256 /* index set for vertices */ 257 if (VerticesIS) { 258 nvc = 0; 259 for (i = 0; i < graph->ncc; i++) { 260 if (!mark[i]) { 261 PetscInt j; 262 263 for (j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) { 264 idx[nvc] = graph->queue[j]; 265 nvc++; 266 } 267 } 268 } 269 /* sort vertex set (by local ordering) */ 270 PetscCall(PetscSortInt(nvc, idx)); 271 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nvc, idx, PETSC_OWN_POINTER, &ISForVertices)); 272 } 273 PetscCall(PetscFree(mark)); 274 275 /* get back info */ 276 if (n_faces) *n_faces = nfc; 277 if (FacesIS) *FacesIS = ISForFaces; 278 if (n_edges) *n_edges = nec; 279 if (EdgesIS) *EdgesIS = ISForEdges; 280 if (VerticesIS) *VerticesIS = ISForVertices; 281 PetscFunctionReturn(PETSC_SUCCESS); 282 } 283 284 PetscErrorCode PCBDDCGraphComputeConnectedComponents(PCBDDCGraph graph) 285 { 286 PetscBool adapt_interface; 287 MPI_Comm interface_comm; 288 PetscBT cornerp = NULL; 289 290 PetscFunctionBegin; 291 PetscCall(PetscObjectGetComm((PetscObject)graph->l2gmap, &interface_comm)); 292 /* compute connected components locally */ 293 PetscCall(PCBDDCGraphComputeConnectedComponentsLocal(graph)); 294 if (graph->seq_graph) PetscFunctionReturn(PETSC_SUCCESS); 295 296 if (graph->active_coords && !graph->multi_element) { /* face based corner selection XXX multi_element */ 297 PetscBT excluded; 298 PetscReal *wdist; 299 PetscInt n_neigh, *neigh, *n_shared, **shared; 300 PetscInt maxc, ns; 301 302 PetscCall(PetscBTCreate(graph->nvtxs, &cornerp)); 303 PetscCall(ISLocalToGlobalMappingGetInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared)); 304 for (ns = 1, maxc = 0; ns < n_neigh; ns++) maxc = PetscMax(maxc, n_shared[ns]); 305 PetscCall(PetscMalloc1(maxc * graph->cdim, &wdist)); 306 PetscCall(PetscBTCreate(maxc, &excluded)); 307 308 for (ns = 1; ns < n_neigh; ns++) { /* first proc is self */ 309 PetscReal *anchor, mdist; 310 PetscInt fst, j, k, d, cdim = graph->cdim, n = n_shared[ns]; 311 PetscInt point1, point2, point3, point4; 312 313 /* import coordinates on shared interface */ 314 PetscCall(PetscBTMemzero(n, excluded)); 315 for (j = 0, fst = -1, k = 0; j < n; j++) { 316 PetscBool skip = PETSC_FALSE; 317 for (d = 0; d < cdim; d++) { 318 PetscReal c = graph->coords[shared[ns][j] * cdim + d]; 319 skip = (PetscBool)(skip || c == PETSC_MAX_REAL); 320 wdist[k++] = c; 321 } 322 if (skip) { 323 PetscCall(PetscBTSet(excluded, j)); 324 } else if (fst == -1) fst = j; 325 } 326 if (fst == -1) continue; 327 328 /* the dofs are sorted by global numbering, so each rank starts from the same id 329 and it will detect the same corners from the given set */ 330 331 /* find the farthest point from the starting one */ 332 anchor = wdist + fst * cdim; 333 mdist = -1.0; 334 point1 = fst; 335 for (j = fst; j < n; j++) { 336 PetscReal dist = 0.0; 337 338 if (PetscUnlikely(PetscBTLookup(excluded, j))) continue; 339 for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]); 340 if (dist > mdist) { 341 mdist = dist; 342 point1 = j; 343 } 344 } 345 346 /* find the farthest point from point1 */ 347 anchor = wdist + point1 * cdim; 348 mdist = -1.0; 349 point2 = point1; 350 for (j = fst; j < n; j++) { 351 PetscReal dist = 0.0; 352 353 if (PetscUnlikely(PetscBTLookup(excluded, j))) continue; 354 for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]); 355 if (dist > mdist) { 356 mdist = dist; 357 point2 = j; 358 } 359 } 360 361 /* find the third point maximizing the triangle area */ 362 point3 = point2; 363 if (cdim > 2) { 364 PetscReal a = 0.0; 365 366 for (d = 0; d < cdim; d++) a += (wdist[point1 * cdim + d] - wdist[point2 * cdim + d]) * (wdist[point1 * cdim + d] - wdist[point2 * cdim + d]); 367 a = PetscSqrtReal(a); 368 mdist = -1.0; 369 for (j = fst; j < n; j++) { 370 PetscReal area, b = 0.0, c = 0.0, s; 371 372 if (PetscUnlikely(PetscBTLookup(excluded, j))) continue; 373 for (d = 0; d < cdim; d++) { 374 b += (wdist[point1 * cdim + d] - wdist[j * cdim + d]) * (wdist[point1 * cdim + d] - wdist[j * cdim + d]); 375 c += (wdist[point2 * cdim + d] - wdist[j * cdim + d]) * (wdist[point2 * cdim + d] - wdist[j * cdim + d]); 376 } 377 b = PetscSqrtReal(b); 378 c = PetscSqrtReal(c); 379 s = 0.5 * (a + b + c); 380 381 /* Heron's formula, area squared */ 382 area = s * (s - a) * (s - b) * (s - c); 383 if (area > mdist) { 384 mdist = area; 385 point3 = j; 386 } 387 } 388 } 389 390 /* find the farthest point from point3 different from point1 and point2 */ 391 anchor = wdist + point3 * cdim; 392 mdist = -1.0; 393 point4 = point3; 394 for (j = fst; j < n; j++) { 395 PetscReal dist = 0.0; 396 397 if (PetscUnlikely(PetscBTLookup(excluded, j)) || j == point1 || j == point2 || j == point3) continue; 398 for (d = 0; d < cdim; d++) dist += (wdist[j * cdim + d] - anchor[d]) * (wdist[j * cdim + d] - anchor[d]); 399 if (dist > mdist) { 400 mdist = dist; 401 point4 = j; 402 } 403 } 404 405 PetscCall(PetscBTSet(cornerp, shared[ns][point1])); 406 PetscCall(PetscBTSet(cornerp, shared[ns][point2])); 407 PetscCall(PetscBTSet(cornerp, shared[ns][point3])); 408 PetscCall(PetscBTSet(cornerp, shared[ns][point4])); 409 410 /* all dofs having the same coordinates will be primal */ 411 for (j = fst; j < n; j++) { 412 PetscBool same[] = {PETSC_TRUE, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE}; 413 414 if (PetscUnlikely(PetscBTLookup(excluded, j))) continue; 415 for (d = 0; d < cdim; d++) { 416 same[0] = (PetscBool)(same[0] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point1 * cdim + d]) < PETSC_SMALL)); 417 same[1] = (PetscBool)(same[1] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point2 * cdim + d]) < PETSC_SMALL)); 418 same[2] = (PetscBool)(same[2] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point3 * cdim + d]) < PETSC_SMALL)); 419 same[3] = (PetscBool)(same[3] && (PetscAbsReal(wdist[j * cdim + d] - wdist[point4 * cdim + d]) < PETSC_SMALL)); 420 } 421 if (same[0] || same[1] || same[2] || same[3]) PetscCall(PetscBTSet(cornerp, shared[ns][j])); 422 } 423 } 424 PetscCall(PetscBTDestroy(&excluded)); 425 PetscCall(PetscFree(wdist)); 426 PetscCall(ISLocalToGlobalMappingRestoreInfo(graph->l2gmap, &n_neigh, &neigh, &n_shared, &shared)); 427 } 428 429 /* Adapt connected components if needed */ 430 adapt_interface = (cornerp || graph->multi_element) ? PETSC_TRUE : PETSC_FALSE; 431 for (PetscInt i = 0; i < graph->n_subsets && !adapt_interface; i++) { 432 if (graph->subset_ncc[i] > 1) adapt_interface = PETSC_TRUE; 433 } 434 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &adapt_interface, 1, MPIU_BOOL, MPI_LOR, interface_comm)); 435 if (adapt_interface) { 436 PetscSF msf; 437 const PetscInt *n_ref_sharing; 438 PetscInt *labels, *rootlabels, *mrlabels; 439 PetscInt nr, nmr, nrs, ncc, cum_queue; 440 441 PetscCall(PetscMalloc1(graph->nvtxs, &labels)); 442 PetscCall(PetscArrayzero(labels, graph->nvtxs)); 443 for (PetscInt i = 0, k = 0; i < graph->ncc; i++) { 444 PetscInt s = 1; 445 for (PetscInt j = graph->cptr[i]; j < graph->cptr[i + 1]; j++) { 446 if (cornerp && PetscBTLookup(cornerp, graph->queue[j])) { 447 labels[graph->queue[j]] = -(k + s + 1); 448 s += 1; 449 } else { 450 labels[graph->queue[j]] = -(k + 1); 451 } 452 } 453 k += s; 454 } 455 PetscCall(PetscSFGetGraph(graph->interface_ref_sf, &nr, NULL, NULL, NULL)); 456 PetscCall(PetscSFGetGraph(graph->interface_subset_sf, &nrs, NULL, NULL, NULL)); 457 PetscCall(PetscSFGetMultiSF(graph->interface_subset_sf, &msf)); 458 PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL)); 459 PetscCall(PetscCalloc2(nmr, &mrlabels, nrs, &rootlabels)); 460 461 PetscCall(PetscSFComputeDegreeBegin(graph->interface_subset_sf, &n_ref_sharing)); 462 PetscCall(PetscSFComputeDegreeEnd(graph->interface_subset_sf, &n_ref_sharing)); 463 PetscCall(PetscSFGatherBegin(graph->interface_subset_sf, MPIU_INT, labels, mrlabels)); 464 PetscCall(PetscSFGatherEnd(graph->interface_subset_sf, MPIU_INT, labels, mrlabels)); 465 466 /* analyze contributions from processes 467 The structure of mrlabels is suitable to find intersections of ccs. 468 supposing the root subset has dimension 5 and leaves with labels: 469 0: [4 4 7 4 7], (2 connected components) 470 1: [3 2 2 3 2], (2 connected components) 471 2: [1 1 6 5 6], (3 connected components) 472 the multiroot data and the new labels corresponding to intersected connected components will be (column major) 473 474 4 4 7 4 7 475 mrlabels 3 2 2 3 2 476 1 1 6 5 6 477 --------- 478 rootlabels 0 1 2 3 2 479 */ 480 for (PetscInt i = 0, rcumlabels = 0, mcumlabels = 0; i < nr; i++) { 481 const PetscInt subset_size = graph->interface_ref_rsize[i]; 482 const PetscInt *n_sharing = n_ref_sharing + rcumlabels; 483 const PetscInt *mrbuffer = mrlabels + mcumlabels; 484 PetscInt *rbuffer = rootlabels + rcumlabels; 485 PetscInt subset_counter = 0; 486 487 for (PetscInt j = 0; j < subset_size; j++) { 488 if (!rbuffer[j]) { /* found a new cc */ 489 const PetscInt *jlabels = mrbuffer + j * n_sharing[0]; 490 rbuffer[j] = ++subset_counter; 491 492 for (PetscInt k = j + 1; k < subset_size; k++) { /* check for other nodes in new cc */ 493 PetscBool same_set = PETSC_TRUE; 494 const PetscInt *klabels = mrbuffer + k * n_sharing[0]; 495 496 for (PetscInt s = 0; s < n_sharing[0]; s++) { 497 if (jlabels[s] != klabels[s]) { 498 same_set = PETSC_FALSE; 499 break; 500 } 501 } 502 if (same_set) rbuffer[k] = subset_counter; 503 } 504 } 505 } 506 if (subset_size) { 507 rcumlabels += subset_size; 508 mcumlabels += n_sharing[0] * subset_size; 509 } 510 } 511 512 /* Now communicate the intersected labels */ 513 PetscCall(PetscSFBcastBegin(graph->interface_subset_sf, MPIU_INT, rootlabels, labels, MPI_REPLACE)); 514 PetscCall(PetscSFBcastEnd(graph->interface_subset_sf, MPIU_INT, rootlabels, labels, MPI_REPLACE)); 515 PetscCall(PetscFree2(mrlabels, rootlabels)); 516 517 /* and adapt local connected components */ 518 PetscInt *ocptr, *oqueue; 519 PetscBool *touched; 520 521 PetscCall(PetscMalloc3(graph->ncc + 1, &ocptr, graph->cptr[graph->ncc], &oqueue, graph->cptr[graph->ncc], &touched)); 522 PetscCall(PetscArraycpy(ocptr, graph->cptr, graph->ncc + 1)); 523 PetscCall(PetscArraycpy(oqueue, graph->queue, graph->cptr[graph->ncc])); 524 PetscCall(PetscArrayzero(touched, graph->cptr[graph->ncc])); 525 526 ncc = 0; 527 cum_queue = 0; 528 for (PetscInt i = 0; i < graph->ncc; i++) { 529 for (PetscInt j = ocptr[i]; j < ocptr[i + 1]; j++) { 530 const PetscInt jlabel = labels[oqueue[j]]; 531 532 if (jlabel) { 533 graph->cptr[ncc] = cum_queue; 534 ncc++; 535 for (PetscInt k = j; k < ocptr[i + 1]; k++) { /* check for other nodes in new cc */ 536 if (labels[oqueue[k]] == jlabel) { 537 graph->queue[cum_queue++] = oqueue[k]; 538 labels[oqueue[k]] = 0; 539 } 540 } 541 } 542 } 543 } 544 PetscCall(PetscFree3(ocptr, oqueue, touched)); 545 PetscCall(PetscFree(labels)); 546 graph->cptr[ncc] = cum_queue; 547 graph->queue_sorted = PETSC_FALSE; 548 graph->ncc = ncc; 549 } 550 PetscCall(PetscBTDestroy(&cornerp)); 551 552 /* Determine if we are in 2D or 3D */ 553 if (!graph->twodimset) { 554 PetscBool twodim = PETSC_TRUE; 555 for (PetscInt i = 0; i < graph->ncc; i++) { 556 PetscInt repdof = graph->queue[graph->cptr[i]]; 557 PetscInt ccsize = graph->cptr[i + 1] - graph->cptr[i]; 558 if (graph->nodes[repdof].count > 2 && ccsize > graph->custom_minimal_size) { 559 twodim = PETSC_FALSE; 560 break; 561 } 562 } 563 PetscCall(MPIU_Allreduce(&twodim, &graph->twodim, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)graph->l2gmap))); 564 graph->twodimset = PETSC_TRUE; 565 } 566 PetscFunctionReturn(PETSC_SUCCESS); 567 } 568 569 static inline PetscErrorCode PCBDDCGraphComputeCC_Private(PCBDDCGraph graph, PetscInt pid, PetscInt *PETSC_RESTRICT queue_tip, PetscInt n_prev, PetscInt *n_added) 570 { 571 PetscInt i, j, n = 0; 572 573 const PetscInt *PETSC_RESTRICT xadj = graph->xadj; 574 const PetscInt *PETSC_RESTRICT adjncy = graph->adjncy; 575 const PetscInt *PETSC_RESTRICT subset_idxs = graph->subset_idxs[pid - 1]; 576 const PetscInt *PETSC_RESTRICT local_subs = graph->local_subs; 577 const PetscInt subset_size = graph->subset_size[pid - 1]; 578 579 PCBDDCGraphNode *PETSC_RESTRICT nodes = graph->nodes; 580 581 const PetscBool havecsr = (PetscBool)(!!xadj); 582 const PetscBool havesubs = (PetscBool)(!!graph->n_local_subs); 583 584 PetscFunctionBegin; 585 if (havecsr && !havesubs) { 586 for (i = -n_prev; i < 0; i++) { 587 const PetscInt start_dof = queue_tip[i]; 588 589 /* we assume that if a dof has a size 1 adjacency list and the corresponding entry is negative, it is connected to all dofs */ 590 if (xadj[start_dof + 1] - xadj[start_dof] == 1 && adjncy[xadj[start_dof]] < 0) { 591 for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */ 592 const PetscInt dof = subset_idxs[j]; 593 594 if (!nodes[dof].touched && nodes[dof].subset == pid) { 595 nodes[dof].touched = PETSC_TRUE; 596 queue_tip[n] = dof; 597 n++; 598 } 599 } 600 } else { 601 for (j = xadj[start_dof]; j < xadj[start_dof + 1]; j++) { 602 const PetscInt dof = adjncy[j]; 603 604 if (!nodes[dof].touched && nodes[dof].subset == pid) { 605 nodes[dof].touched = PETSC_TRUE; 606 queue_tip[n] = dof; 607 n++; 608 } 609 } 610 } 611 } 612 } else if (havecsr && havesubs) { 613 const PetscInt sid = local_subs[queue_tip[-n_prev]]; 614 615 for (i = -n_prev; i < 0; i++) { 616 const PetscInt start_dof = queue_tip[i]; 617 618 /* 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 */ 619 if (xadj[start_dof + 1] - xadj[start_dof] == 1 && adjncy[xadj[start_dof]] < 0) { 620 for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */ 621 const PetscInt dof = subset_idxs[j]; 622 623 if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) { 624 nodes[dof].touched = PETSC_TRUE; 625 queue_tip[n] = dof; 626 n++; 627 } 628 } 629 } else { 630 for (j = xadj[start_dof]; j < xadj[start_dof + 1]; j++) { 631 const PetscInt dof = adjncy[j]; 632 633 if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) { 634 nodes[dof].touched = PETSC_TRUE; 635 queue_tip[n] = dof; 636 n++; 637 } 638 } 639 } 640 } 641 } else if (havesubs) { /* sub info only */ 642 const PetscInt sid = local_subs[queue_tip[-n_prev]]; 643 644 for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */ 645 const PetscInt dof = subset_idxs[j]; 646 647 if (!nodes[dof].touched && nodes[dof].subset == pid && local_subs[dof] == sid) { 648 nodes[dof].touched = PETSC_TRUE; 649 queue_tip[n] = dof; 650 n++; 651 } 652 } 653 } else { 654 for (j = 0; j < subset_size; j++) { /* pid \in [1,graph->n_subsets] */ 655 const PetscInt dof = subset_idxs[j]; 656 657 if (!nodes[dof].touched && nodes[dof].subset == pid) { 658 nodes[dof].touched = PETSC_TRUE; 659 queue_tip[n] = dof; 660 n++; 661 } 662 } 663 } 664 *n_added = n; 665 PetscFunctionReturn(PETSC_SUCCESS); 666 } 667 668 PetscErrorCode PCBDDCGraphComputeConnectedComponentsLocal(PCBDDCGraph graph) 669 { 670 PetscInt ncc, cum_queue; 671 672 PetscFunctionBegin; 673 PetscCheck(graph->setupcalled, PetscObjectComm((PetscObject)graph->l2gmap), PETSC_ERR_ORDER, "PCBDDCGraphSetUp should be called first"); 674 /* quiet return if there isn't any local info */ 675 if (!graph->xadj && !graph->n_local_subs) PetscFunctionReturn(PETSC_SUCCESS); 676 677 /* reset any previous search of connected components */ 678 for (PetscInt i = 0; i < graph->nvtxs; i++) graph->nodes[i].touched = PETSC_FALSE; 679 if (!graph->seq_graph) { 680 for (PetscInt i = 0; i < graph->nvtxs; i++) { 681 if (graph->nodes[i].special_dof == PCBDDCGRAPH_DIRICHLET_MARK || graph->nodes[i].count < 2) graph->nodes[i].touched = PETSC_TRUE; 682 } 683 } 684 685 /* begin search for connected components */ 686 cum_queue = 0; 687 ncc = 0; 688 for (PetscInt n = 0; n < graph->n_subsets; n++) { 689 const PetscInt *subset_idxs = graph->subset_idxs[n]; 690 const PetscInt pid = n + 1; /* partition labeled by 0 is discarded */ 691 692 PetscInt found = 0, prev = 0, first = 0, ncc_pid = 0; 693 694 while (found != graph->subset_size[n]) { 695 PetscInt added = 0; 696 697 if (!prev) { /* search for new starting dof */ 698 while (graph->nodes[subset_idxs[first]].touched) first++; 699 graph->nodes[subset_idxs[first]].touched = PETSC_TRUE; 700 graph->queue[cum_queue] = subset_idxs[first]; 701 graph->cptr[ncc] = cum_queue; 702 prev = 1; 703 cum_queue++; 704 found++; 705 ncc_pid++; 706 ncc++; 707 } 708 PetscCall(PCBDDCGraphComputeCC_Private(graph, pid, graph->queue + cum_queue, prev, &added)); 709 if (!added) { 710 graph->subset_ncc[n] = ncc_pid; 711 graph->cptr[ncc] = cum_queue; 712 } 713 prev = added; 714 found += added; 715 cum_queue += added; 716 if (added && found == graph->subset_size[n]) { 717 graph->subset_ncc[n] = ncc_pid; 718 graph->cptr[ncc] = cum_queue; 719 } 720 } 721 } 722 graph->ncc = ncc; 723 graph->queue_sorted = PETSC_FALSE; 724 PetscFunctionReturn(PETSC_SUCCESS); 725 } 726 727 PetscErrorCode PCBDDCGraphSetUp(PCBDDCGraph graph, PetscInt custom_minimal_size, IS neumann_is, IS dirichlet_is, PetscInt n_ISForDofs, IS ISForDofs[], IS custom_primal_vertices) 728 { 729 IS subset; 730 MPI_Comm comm; 731 const PetscInt *is_indices; 732 PetscInt *queue_global, *nodecount, **nodeneighs; 733 PetscInt i, j, k, total_counts, nodes_touched, is_size, nvtxs = graph->nvtxs; 734 PetscMPIInt size, rank; 735 PetscBool same_set; 736 737 PetscFunctionBegin; 738 PetscValidLogicalCollectiveInt(graph->l2gmap, custom_minimal_size, 2); 739 if (neumann_is) { 740 PetscValidHeaderSpecific(neumann_is, IS_CLASSID, 3); 741 PetscCheckSameComm(graph->l2gmap, 1, neumann_is, 3); 742 } 743 graph->has_dirichlet = PETSC_FALSE; 744 if (dirichlet_is) { 745 PetscValidHeaderSpecific(dirichlet_is, IS_CLASSID, 4); 746 PetscCheckSameComm(graph->l2gmap, 1, dirichlet_is, 4); 747 graph->has_dirichlet = PETSC_TRUE; 748 } 749 PetscValidLogicalCollectiveInt(graph->l2gmap, n_ISForDofs, 5); 750 for (i = 0; i < n_ISForDofs; i++) { 751 PetscValidHeaderSpecific(ISForDofs[i], IS_CLASSID, 6); 752 PetscCheckSameComm(graph->l2gmap, 1, ISForDofs[i], 6); 753 } 754 if (custom_primal_vertices) { 755 PetscValidHeaderSpecific(custom_primal_vertices, IS_CLASSID, 7); 756 PetscCheckSameComm(graph->l2gmap, 1, custom_primal_vertices, 7); 757 } 758 for (i = 0; i < nvtxs; i++) graph->nodes[i].touched = PETSC_FALSE; 759 760 PetscCall(PetscObjectGetComm((PetscObject)graph->l2gmap, &comm)); 761 PetscCallMPI(MPI_Comm_size(comm, &size)); 762 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 763 764 /* custom_minimal_size */ 765 graph->custom_minimal_size = custom_minimal_size; 766 767 /* get node info from l2gmap */ 768 PetscCall(ISLocalToGlobalMappingGetNodeInfo(graph->l2gmap, NULL, &nodecount, &nodeneighs)); 769 770 /* Allocate space for storing the set of neighbours for each node */ 771 graph->multi_element = PETSC_FALSE; 772 for (i = 0; i < nvtxs; i++) { 773 graph->nodes[i].count = nodecount[i]; 774 if (!graph->seq_graph) { 775 PetscCall(PetscMalloc1(nodecount[i], &graph->nodes[i].neighbours_set)); 776 PetscCall(PetscArraycpy(graph->nodes[i].neighbours_set, nodeneighs[i], nodecount[i])); 777 778 if (!graph->multi_element) { 779 PetscInt nself; 780 for (j = 0, nself = 0; j < graph->nodes[i].count; j++) 781 if (graph->nodes[i].neighbours_set[j] == rank) nself++; 782 if (nself > 1) graph->multi_element = PETSC_TRUE; 783 } 784 } else { 785 PetscCall(PetscCalloc1(nodecount[i], &graph->nodes[i].neighbours_set)); 786 } 787 } 788 PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(graph->l2gmap, NULL, &nodecount, &nodeneighs)); 789 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &graph->multi_element, 1, MPIU_BOOL, MPI_LOR, comm)); 790 791 /* compute local groups */ 792 if (graph->multi_element) { 793 const PetscInt *idxs, *indegree; 794 IS is, lis; 795 PetscLayout layout; 796 PetscSF sf, multisf; 797 PetscInt n, nmulti, c, *multi_root_subs, *start; 798 799 PetscCheck(!nvtxs || graph->local_subs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing local subdomain information"); 800 801 PetscCall(ISLocalToGlobalMappingGetIndices(graph->l2gmap, &idxs)); 802 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nvtxs, idxs, PETSC_USE_POINTER, &is)); 803 PetscCall(ISRenumber(is, NULL, &n, &lis)); 804 PetscCall(ISDestroy(&is)); 805 806 PetscCall(ISLocalToGlobalMappingRestoreIndices(graph->l2gmap, &idxs)); 807 PetscCall(ISGetIndices(lis, &idxs)); 808 PetscCall(PetscLayoutCreate(PETSC_COMM_SELF, &layout)); 809 PetscCall(PetscLayoutSetSize(layout, n)); 810 PetscCall(PetscSFCreate(PETSC_COMM_SELF, &sf)); 811 PetscCall(PetscSFSetGraphLayout(sf, layout, nvtxs, NULL, PETSC_OWN_POINTER, idxs)); 812 PetscCall(PetscLayoutDestroy(&layout)); 813 PetscCall(PetscSFGetMultiSF(sf, &multisf)); 814 PetscCall(PetscSFComputeDegreeBegin(sf, &indegree)); 815 PetscCall(PetscSFComputeDegreeEnd(sf, &indegree)); 816 PetscCall(PetscSFGetGraph(multisf, &nmulti, NULL, NULL, NULL)); 817 PetscCall(PetscMalloc2(nmulti, &multi_root_subs, n + 1, &start)); 818 start[0] = 0; 819 for (i = 0; i < n; i++) start[i + 1] = start[i] + indegree[i]; 820 PetscCall(PetscSFGatherBegin(sf, MPIU_INT, graph->local_subs, multi_root_subs)); 821 PetscCall(PetscSFGatherEnd(sf, MPIU_INT, graph->local_subs, multi_root_subs)); 822 for (i = 0; i < nvtxs; i++) { 823 PetscInt gid = idxs[i]; 824 825 graph->nodes[i].local_sub = graph->local_subs[i]; 826 for (j = 0, c = 0; j < graph->nodes[i].count; j++) { 827 if (graph->nodes[i].neighbours_set[j] == rank) c++; 828 } 829 PetscCheck(c == indegree[idxs[i]], PETSC_COMM_SELF, PETSC_ERR_PLIB, "%" PetscInt_FMT " != %" PetscInt_FMT, c, indegree[idxs[i]]); 830 PetscCall(PetscMalloc1(c, &graph->nodes[i].local_groups)); 831 for (j = 0; j < c; j++) graph->nodes[i].local_groups[j] = multi_root_subs[start[gid] + j]; 832 PetscCall(PetscSortInt(c, graph->nodes[i].local_groups)); 833 graph->nodes[i].local_groups_count = c; 834 } 835 PetscCall(PetscFree2(multi_root_subs, start)); 836 PetscCall(ISRestoreIndices(lis, &idxs)); 837 PetscCall(ISDestroy(&lis)); 838 PetscCall(PetscSFDestroy(&sf)); 839 } 840 841 /* 842 Get info for dofs splitting 843 User can specify just a subset; an additional field is considered as a complementary field 844 */ 845 for (i = 0, k = 0; i < n_ISForDofs; i++) { 846 PetscInt bs; 847 848 PetscCall(ISGetBlockSize(ISForDofs[i], &bs)); 849 k += bs; 850 } 851 for (i = 0; i < nvtxs; i++) graph->nodes[i].which_dof = k; /* by default a dof belongs to the complement set */ 852 for (i = 0, k = 0; i < n_ISForDofs; i++) { 853 PetscInt bs; 854 855 PetscCall(ISGetLocalSize(ISForDofs[i], &is_size)); 856 PetscCall(ISGetBlockSize(ISForDofs[i], &bs)); 857 PetscCall(ISGetIndices(ISForDofs[i], (const PetscInt **)&is_indices)); 858 for (j = 0; j < is_size / bs; j++) { 859 PetscInt b; 860 861 for (b = 0; b < bs; b++) { 862 PetscInt jj = bs * j + b; 863 864 if (is_indices[jj] > -1 && is_indices[jj] < nvtxs) { /* out of bounds indices (if any) are skipped */ 865 graph->nodes[is_indices[jj]].which_dof = k + b; 866 } 867 } 868 } 869 PetscCall(ISRestoreIndices(ISForDofs[i], (const PetscInt **)&is_indices)); 870 k += bs; 871 } 872 873 /* Take into account Neumann nodes */ 874 if (neumann_is) { 875 PetscCall(ISGetLocalSize(neumann_is, &is_size)); 876 PetscCall(ISGetIndices(neumann_is, (const PetscInt **)&is_indices)); 877 for (i = 0; i < is_size; i++) { 878 if (is_indices[i] > -1 && is_indices[i] < nvtxs) { /* out of bounds indices (if any) are skipped */ 879 graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_NEUMANN_MARK; 880 } 881 } 882 PetscCall(ISRestoreIndices(neumann_is, (const PetscInt **)&is_indices)); 883 } 884 885 /* Take into account Dirichlet nodes (they overwrite any mark previously set) */ 886 if (dirichlet_is) { 887 PetscCall(ISGetLocalSize(dirichlet_is, &is_size)); 888 PetscCall(ISGetIndices(dirichlet_is, (const PetscInt **)&is_indices)); 889 for (i = 0; i < is_size; i++) { 890 if (is_indices[i] > -1 && is_indices[i] < nvtxs) { /* out of bounds indices (if any) are skipped */ 891 if (!graph->seq_graph) { /* dirichlet nodes treated as internal */ 892 graph->nodes[is_indices[i]].touched = PETSC_TRUE; 893 graph->nodes[is_indices[i]].subset = 0; 894 } 895 graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_DIRICHLET_MARK; 896 } 897 } 898 PetscCall(ISRestoreIndices(dirichlet_is, (const PetscInt **)&is_indices)); 899 } 900 901 /* mark special nodes (if any) -> each will become a single dof equivalence class (i.e. point constraint for BDDC) */ 902 if (custom_primal_vertices) { 903 PetscCall(ISGetLocalSize(custom_primal_vertices, &is_size)); 904 PetscCall(ISGetIndices(custom_primal_vertices, (const PetscInt **)&is_indices)); 905 for (i = 0, j = 0; i < is_size; i++) { 906 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 */ 907 graph->nodes[is_indices[i]].special_dof = PCBDDCGRAPH_SPECIAL_MARK - j; 908 j++; 909 } 910 } 911 PetscCall(ISRestoreIndices(custom_primal_vertices, (const PetscInt **)&is_indices)); 912 } 913 914 /* mark interior nodes as touched and belonging to partition number 0 */ 915 if (!graph->seq_graph) { 916 for (i = 0; i < nvtxs; i++) { 917 if (graph->nodes[i].count < 2) { 918 graph->nodes[i].touched = PETSC_TRUE; 919 graph->nodes[i].subset = 0; 920 } 921 } 922 } 923 924 /* init graph structure and compute default subsets */ 925 nodes_touched = 0; 926 for (i = 0; i < nvtxs; i++) 927 if (graph->nodes[i].touched) nodes_touched++; 928 929 i = 0; 930 graph->ncc = 0; 931 total_counts = 0; 932 933 /* allocated space for queues */ 934 if (graph->seq_graph) { 935 PetscCall(PetscMalloc2(nvtxs + 1, &graph->cptr, nvtxs, &graph->queue)); 936 } else { 937 PetscInt nused = nvtxs - nodes_touched; 938 PetscCall(PetscMalloc2(nused + 1, &graph->cptr, nused, &graph->queue)); 939 } 940 941 while (nodes_touched < nvtxs) { 942 /* find first untouched node in local ordering */ 943 while (graph->nodes[i].touched) i++; 944 graph->nodes[i].touched = PETSC_TRUE; 945 graph->nodes[i].subset = graph->ncc + 1; 946 graph->cptr[graph->ncc] = total_counts; 947 graph->queue[total_counts] = i; 948 total_counts++; 949 nodes_touched++; 950 951 /* now find all other nodes having the same set of sharing subdomains */ 952 const PCBDDCGraphNode *nodei = &graph->nodes[i]; 953 const PetscInt icount = nodei->count; 954 const PetscInt iwhich_dof = nodei->which_dof; 955 const PetscInt ispecial_dof = nodei->special_dof; 956 const PetscInt ilocal_groups_count = nodei->local_groups_count; 957 const PetscInt *PETSC_RESTRICT ineighbours_set = nodei->neighbours_set; 958 const PetscInt *PETSC_RESTRICT ilocal_groups = nodei->local_groups; 959 for (j = i + 1; j < nvtxs; j++) { 960 PCBDDCGraphNode *PETSC_RESTRICT nodej = &graph->nodes[j]; 961 962 if (nodej->touched) continue; 963 /* check for same number of sharing subdomains, dof number and same special mark */ 964 if (icount == nodej->count && iwhich_dof == nodej->which_dof && ispecial_dof == nodej->special_dof) { 965 PetscBool mpi_shared = PETSC_TRUE; 966 967 /* check for same set of sharing subdomains */ 968 same_set = PETSC_TRUE; 969 for (k = 0; k < icount; k++) { 970 if (ineighbours_set[k] != nodej->neighbours_set[k]) { 971 same_set = PETSC_FALSE; 972 break; 973 } 974 } 975 976 if (graph->multi_element) { 977 mpi_shared = PETSC_FALSE; 978 for (k = 0; k < icount; k++) 979 if (ineighbours_set[k] != rank) { 980 mpi_shared = PETSC_TRUE; 981 break; 982 } 983 } 984 985 /* check for same local groups 986 shared dofs at the process boundaries will be handled differently */ 987 if (same_set && !mpi_shared) { 988 if (ilocal_groups_count != nodej->local_groups_count) same_set = PETSC_FALSE; 989 else { 990 for (k = 0; k < ilocal_groups_count; k++) { 991 if (ilocal_groups[k] != nodej->local_groups[k]) { 992 same_set = PETSC_FALSE; 993 break; 994 } 995 } 996 } 997 } 998 999 /* Add to subset */ 1000 if (same_set) { 1001 nodej->touched = PETSC_TRUE; 1002 nodej->subset = graph->ncc + 1; 1003 nodes_touched++; 1004 graph->queue[total_counts] = j; 1005 total_counts++; 1006 } 1007 } 1008 } 1009 graph->ncc++; 1010 } 1011 graph->cptr[graph->ncc] = total_counts; 1012 1013 /* set default number of subsets */ 1014 graph->n_subsets = graph->ncc; 1015 PetscCall(PetscMalloc1(graph->n_subsets, &graph->subset_ncc)); 1016 for (i = 0; i < graph->n_subsets; i++) graph->subset_ncc[i] = 1; 1017 1018 PetscCall(PetscMalloc1(graph->ncc, &graph->subset_ref_node)); 1019 PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &queue_global)); 1020 PetscCall(PetscMalloc2(graph->ncc, &graph->subset_size, graph->ncc, &graph->subset_idxs)); 1021 if (graph->multi_element) PetscCall(PetscMalloc1(graph->ncc, &graph->gsubset_size)); 1022 else graph->gsubset_size = graph->subset_size; 1023 PetscCall(ISLocalToGlobalMappingApply(graph->l2gmap, graph->cptr[graph->ncc], graph->queue, queue_global)); 1024 1025 PetscHMapI cnt_unique; 1026 1027 PetscCall(PetscHMapICreate(&cnt_unique)); 1028 for (j = 0; j < graph->ncc; j++) { 1029 PetscInt c = 0, ref_node = PETSC_MAX_INT; 1030 1031 for (k = graph->cptr[j]; k < graph->cptr[j + 1]; k++) { 1032 ref_node = PetscMin(ref_node, queue_global[k]); 1033 if (graph->multi_element) { 1034 PetscBool missing; 1035 PetscHashIter iter; 1036 1037 PetscCall(PetscHMapIPut(cnt_unique, queue_global[k], &iter, &missing)); 1038 if (missing) c++; 1039 } 1040 } 1041 graph->gsubset_size[j] = c; 1042 graph->subset_size[j] = graph->cptr[j + 1] - graph->cptr[j]; 1043 graph->subset_ref_node[j] = ref_node; 1044 if (graph->multi_element) PetscCall(PetscHMapIClear(cnt_unique)); 1045 } 1046 PetscCall(PetscHMapIDestroy(&cnt_unique)); 1047 1048 /* save information on subsets (needed when analyzing the connected components) */ 1049 if (graph->ncc) { 1050 PetscCall(PetscMalloc1(graph->cptr[graph->ncc], &graph->subset_idxs[0])); 1051 PetscCall(PetscArrayzero(graph->subset_idxs[0], graph->cptr[graph->ncc])); 1052 for (j = 1; j < graph->ncc; j++) { graph->subset_idxs[j] = graph->subset_idxs[j - 1] + graph->subset_size[j - 1]; } 1053 PetscCall(PetscArraycpy(graph->subset_idxs[0], graph->queue, graph->cptr[graph->ncc])); 1054 } 1055 1056 /* check consistency and create SF to analyze components on the interface between subdomains */ 1057 if (!graph->seq_graph) { 1058 PetscSF msf; 1059 PetscLayout map; 1060 const PetscInt *degree; 1061 PetscInt nr, nmr, *rdata; 1062 PetscBool valid = PETSC_TRUE; 1063 PetscInt subset_N; 1064 IS subset_n; 1065 const PetscInt *idxs; 1066 1067 PetscCall(ISCreateGeneral(comm, graph->n_subsets, graph->subset_ref_node, PETSC_USE_POINTER, &subset)); 1068 PetscCall(ISRenumber(subset, NULL, &subset_N, &subset_n)); 1069 PetscCall(ISDestroy(&subset)); 1070 1071 PetscCall(PetscSFCreate(comm, &graph->interface_ref_sf)); 1072 PetscCall(PetscLayoutCreateFromSizes(comm, PETSC_DECIDE, subset_N, 1, &map)); 1073 PetscCall(ISGetIndices(subset_n, &idxs)); 1074 PetscCall(PetscSFSetGraphLayout(graph->interface_ref_sf, map, graph->n_subsets, NULL, PETSC_OWN_POINTER, idxs)); 1075 PetscCall(ISRestoreIndices(subset_n, &idxs)); 1076 PetscCall(ISDestroy(&subset_n)); 1077 PetscCall(PetscLayoutDestroy(&map)); 1078 1079 PetscCall(PetscSFComputeDegreeBegin(graph->interface_ref_sf, °ree)); 1080 PetscCall(PetscSFComputeDegreeEnd(graph->interface_ref_sf, °ree)); 1081 PetscCall(PetscSFGetMultiSF(graph->interface_ref_sf, &msf)); 1082 PetscCall(PetscSFGetGraph(graph->interface_ref_sf, &nr, NULL, NULL, NULL)); 1083 PetscCall(PetscSFGetGraph(msf, &nmr, NULL, NULL, NULL)); 1084 PetscCall(PetscCalloc1(nmr, &rdata)); 1085 PetscCall(PetscSFGatherBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata)); 1086 PetscCall(PetscSFGatherEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, rdata)); 1087 for (PetscInt i = 0, c = 0; i < nr && valid; i++) { 1088 for (PetscInt j = 0; j < degree[i]; j++) { 1089 if (rdata[j + c] != rdata[c]) valid = PETSC_FALSE; 1090 } 1091 c += degree[i]; 1092 } 1093 PetscCall(PetscFree(rdata)); 1094 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &valid, 1, MPIU_BOOL, MPI_LAND, comm)); 1095 PetscCheck(valid, comm, PETSC_ERR_PLIB, "Initial local subsets are not consistent"); 1096 1097 /* Now create SF with each root extended to gsubset_size roots */ 1098 PetscInt mss = 0; 1099 const PetscSFNode *subs_remote; 1100 1101 PetscCall(PetscSFGetGraph(graph->interface_ref_sf, NULL, NULL, NULL, &subs_remote)); 1102 for (PetscInt i = 0; i < graph->n_subsets; i++) mss = PetscMax(graph->subset_size[i], mss); 1103 1104 PetscInt nri, nli, *start_rsize, *cum_rsize; 1105 PetscCall(PetscCalloc1(graph->n_subsets + 1, &start_rsize)); 1106 PetscCall(PetscCalloc1(nr, &graph->interface_ref_rsize)); 1107 PetscCall(PetscMalloc1(nr + 1, &cum_rsize)); 1108 PetscCall(PetscSFReduceBegin(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE)); 1109 PetscCall(PetscSFReduceEnd(graph->interface_ref_sf, MPIU_INT, graph->gsubset_size, graph->interface_ref_rsize, MPI_REPLACE)); 1110 1111 nri = 0; 1112 cum_rsize[0] = 0; 1113 for (PetscInt i = 0; i < nr; i++) { 1114 nri += graph->interface_ref_rsize[i]; 1115 cum_rsize[i + 1] = cum_rsize[i] + graph->interface_ref_rsize[i]; 1116 } 1117 nli = graph->cptr[graph->ncc]; 1118 PetscCall(PetscSFBcastBegin(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE)); 1119 PetscCall(PetscSFBcastEnd(graph->interface_ref_sf, MPIU_INT, cum_rsize, start_rsize, MPI_REPLACE)); 1120 PetscCall(PetscFree(cum_rsize)); 1121 1122 PetscInt *ilocal, *queue_global_uniq; 1123 PetscSFNode *iremote; 1124 PetscBool *touched; 1125 1126 PetscCall(PetscSFCreate(comm, &graph->interface_subset_sf)); 1127 PetscCall(PetscMalloc1(nli, &ilocal)); 1128 PetscCall(PetscMalloc1(nli, &iremote)); 1129 PetscCall(PetscMalloc2(mss, &queue_global_uniq, mss, &touched)); 1130 for (PetscInt i = 0, nli = 0; i < graph->n_subsets; i++) { 1131 const PetscMPIInt rr = subs_remote[i].rank; 1132 const PetscInt start = start_rsize[i]; 1133 const PetscInt subset_size = graph->subset_size[i]; 1134 const PetscInt gsubset_size = graph->gsubset_size[i]; 1135 const PetscInt *subset_idxs = graph->subset_idxs[i]; 1136 const PetscInt *lsub_queue_global = queue_global + graph->cptr[i]; 1137 1138 k = subset_size; 1139 PetscCall(PetscArrayzero(touched, subset_size)); 1140 PetscCall(PetscArraycpy(queue_global_uniq, lsub_queue_global, subset_size)); 1141 PetscCall(PetscSortRemoveDupsInt(&k, queue_global_uniq)); 1142 PetscCheck(k == gsubset_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid local subset %" PetscInt_FMT " size %" PetscInt_FMT " != %" PetscInt_FMT, i, k, gsubset_size); 1143 1144 PetscInt t = 0, j = 0; 1145 while (t < subset_size) { 1146 while (j < subset_size && touched[j]) j++; 1147 PetscCheck(j < subset_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " >= %" PetscInt_FMT, j, subset_size); 1148 const PetscInt ls = graph->nodes[subset_idxs[j]].local_sub; 1149 1150 for (k = j; k < subset_size; k++) { 1151 if (graph->nodes[subset_idxs[k]].local_sub == ls) { 1152 PetscInt ig; 1153 1154 PetscCall(PetscFindInt(lsub_queue_global[k], gsubset_size, queue_global_uniq, &ig)); 1155 ilocal[nli] = subset_idxs[k]; 1156 iremote[nli].rank = rr; 1157 iremote[nli].index = start + ig; 1158 touched[k] = PETSC_TRUE; 1159 nli++; 1160 t++; 1161 } 1162 } 1163 } 1164 } 1165 PetscCheck(nli == graph->cptr[graph->ncc], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid ilocal size %" PetscInt_FMT " != %" PetscInt_FMT, nli, graph->cptr[graph->ncc]); 1166 PetscCall(PetscSFSetGraph(graph->interface_subset_sf, nri, nli, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 1167 PetscCall(PetscFree(start_rsize)); 1168 PetscCall(PetscFree2(queue_global_uniq, touched)); 1169 } 1170 PetscCall(PetscFree(queue_global)); 1171 1172 /* free workspace */ 1173 graph->setupcalled = PETSC_TRUE; 1174 PetscFunctionReturn(PETSC_SUCCESS); 1175 } 1176 1177 PetscErrorCode PCBDDCGraphResetCoords(PCBDDCGraph graph) 1178 { 1179 PetscFunctionBegin; 1180 if (!graph) PetscFunctionReturn(PETSC_SUCCESS); 1181 PetscCall(PetscFree(graph->coords)); 1182 graph->cdim = 0; 1183 graph->cnloc = 0; 1184 graph->cloc = PETSC_FALSE; 1185 PetscFunctionReturn(PETSC_SUCCESS); 1186 } 1187 1188 PetscErrorCode PCBDDCGraphResetCSR(PCBDDCGraph graph) 1189 { 1190 PetscFunctionBegin; 1191 if (!graph) PetscFunctionReturn(PETSC_SUCCESS); 1192 if (graph->freecsr) { 1193 PetscCall(PetscFree(graph->xadj)); 1194 PetscCall(PetscFree(graph->adjncy)); 1195 } else { 1196 graph->xadj = NULL; 1197 graph->adjncy = NULL; 1198 } 1199 graph->freecsr = PETSC_FALSE; 1200 graph->nvtxs_csr = 0; 1201 PetscFunctionReturn(PETSC_SUCCESS); 1202 } 1203 1204 PetscErrorCode PCBDDCGraphReset(PCBDDCGraph graph) 1205 { 1206 PetscFunctionBegin; 1207 if (!graph) PetscFunctionReturn(PETSC_SUCCESS); 1208 PetscCall(ISLocalToGlobalMappingDestroy(&graph->l2gmap)); 1209 PetscCall(PetscFree(graph->subset_ncc)); 1210 PetscCall(PetscFree(graph->subset_ref_node)); 1211 for (PetscInt i = 0; i < graph->nvtxs; i++) { 1212 PetscCall(PetscFree(graph->nodes[i].neighbours_set)); 1213 PetscCall(PetscFree(graph->nodes[i].local_groups)); 1214 } 1215 PetscCall(PetscFree(graph->nodes)); 1216 PetscCall(PetscFree2(graph->cptr, graph->queue)); 1217 if (graph->subset_idxs) PetscCall(PetscFree(graph->subset_idxs[0])); 1218 PetscCall(PetscFree2(graph->subset_size, graph->subset_idxs)); 1219 if (graph->multi_element) PetscCall(PetscFree(graph->gsubset_size)); 1220 PetscCall(PetscFree(graph->interface_ref_rsize)); 1221 PetscCall(PetscSFDestroy(&graph->interface_subset_sf)); 1222 PetscCall(PetscSFDestroy(&graph->interface_ref_sf)); 1223 PetscCall(ISDestroy(&graph->dirdofs)); 1224 PetscCall(ISDestroy(&graph->dirdofsB)); 1225 if (graph->n_local_subs) PetscCall(PetscFree(graph->local_subs)); 1226 graph->multi_element = PETSC_FALSE; 1227 graph->has_dirichlet = PETSC_FALSE; 1228 graph->twodimset = PETSC_FALSE; 1229 graph->twodim = PETSC_FALSE; 1230 graph->nvtxs = 0; 1231 graph->nvtxs_global = 0; 1232 graph->n_subsets = 0; 1233 graph->custom_minimal_size = 1; 1234 graph->n_local_subs = 0; 1235 graph->maxcount = PETSC_MAX_INT; 1236 graph->seq_graph = PETSC_FALSE; 1237 graph->setupcalled = PETSC_FALSE; 1238 PetscFunctionReturn(PETSC_SUCCESS); 1239 } 1240 1241 PetscErrorCode PCBDDCGraphInit(PCBDDCGraph graph, ISLocalToGlobalMapping l2gmap, PetscInt N, PetscInt maxcount) 1242 { 1243 PetscInt n; 1244 1245 PetscFunctionBegin; 1246 PetscAssertPointer(graph, 1); 1247 PetscValidHeaderSpecific(l2gmap, IS_LTOGM_CLASSID, 2); 1248 PetscValidLogicalCollectiveInt(l2gmap, N, 3); 1249 PetscValidLogicalCollectiveInt(l2gmap, maxcount, 4); 1250 /* raise an error if already allocated */ 1251 PetscCheck(!graph->nvtxs_global, PetscObjectComm((PetscObject)l2gmap), PETSC_ERR_PLIB, "BDDCGraph already initialized"); 1252 /* set number of vertices */ 1253 PetscCall(PetscObjectReference((PetscObject)l2gmap)); 1254 graph->l2gmap = l2gmap; 1255 PetscCall(ISLocalToGlobalMappingGetSize(l2gmap, &n)); 1256 graph->nvtxs = n; 1257 graph->nvtxs_global = N; 1258 /* allocate used space */ 1259 PetscCall(PetscCalloc1(graph->nvtxs, &graph->nodes)); 1260 /* use -1 as a default value for which_dof array */ 1261 for (n = 0; n < graph->nvtxs; n++) graph->nodes[n].which_dof = -1; 1262 1263 /* zeroes workspace for values of ncc */ 1264 graph->subset_ncc = NULL; 1265 graph->subset_ref_node = NULL; 1266 /* maxcount for cc */ 1267 graph->maxcount = maxcount; 1268 PetscFunctionReturn(PETSC_SUCCESS); 1269 } 1270 1271 PetscErrorCode PCBDDCGraphDestroy(PCBDDCGraph *graph) 1272 { 1273 PetscFunctionBegin; 1274 PetscCall(PCBDDCGraphResetCSR(*graph)); 1275 PetscCall(PCBDDCGraphResetCoords(*graph)); 1276 PetscCall(PCBDDCGraphReset(*graph)); 1277 PetscCall(PetscFree(*graph)); 1278 PetscFunctionReturn(PETSC_SUCCESS); 1279 } 1280 1281 PetscErrorCode PCBDDCGraphCreate(PCBDDCGraph *graph) 1282 { 1283 PCBDDCGraph new_graph; 1284 1285 PetscFunctionBegin; 1286 PetscCall(PetscNew(&new_graph)); 1287 new_graph->custom_minimal_size = 1; 1288 *graph = new_graph; 1289 PetscFunctionReturn(PETSC_SUCCESS); 1290 } 1291