1 #include <petsc-private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc-private/isimpl.h> 3 #include <petscsf.h> 4 5 #undef __FUNCT__ 6 #define __FUNCT__ "DMPlexGetAdjacency_Internal" 7 static PetscErrorCode DMPlexGetAdjacency_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[]) 8 { 9 const PetscInt *star = tmpClosure; 10 PetscInt numAdj = 0, maxAdjSize = *adjSize, starSize, s; 11 PetscErrorCode ierr; 12 13 PetscFunctionBegin; 14 ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr); 15 for (s = 2; s < starSize*2; s += 2) { 16 const PetscInt *closure = NULL; 17 PetscInt closureSize, c, q; 18 19 ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr); 20 for (c = 0; c < closureSize*2; c += 2) { 21 for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) { 22 if (closure[c] == adj[q]) break; 23 } 24 if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize); 25 } 26 ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr); 27 } 28 *adjSize = numAdj; 29 PetscFunctionReturn(0); 30 } 31 32 #undef __FUNCT__ 33 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension" 34 /*@ 35 DMPlexSetPreallocationCenterDimension - Determine the topology used to determine adjacency 36 37 Input Parameters: 38 + dm - The DM object 39 - preallocCenterDim - The dimension of points which connect adjacent entries 40 41 Level: developer 42 43 Notes: 44 $ FEM: Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim 45 $ FVM: Two points p and q are adjacent if q \in star(cone(p)), preallocCenterDim = dim-1 46 $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0 47 48 .seealso: DMCreateMatrix(), DMPlexPreallocateOperator() 49 @*/ 50 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim) 51 { 52 DM_Plex *mesh = (DM_Plex*) dm->data; 53 54 PetscFunctionBegin; 55 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 56 mesh->preallocCenterDim = preallocCenterDim; 57 PetscFunctionReturn(0); 58 } 59 60 #undef __FUNCT__ 61 #define __FUNCT__ "DMPlexPreallocateOperator" 62 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix) 63 { 64 DM_Plex *mesh = (DM_Plex*) dm->data; 65 MPI_Comm comm; 66 MatType mtype; 67 PetscSF sf, sfDof, sfAdj; 68 PetscSection leafSectionAdj, rootSectionAdj, sectionAdj; 69 PetscInt nleaves, l, p; 70 const PetscInt *leaves; 71 const PetscSFNode *remotes; 72 PetscInt dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols; 73 PetscInt *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets; 74 PetscInt depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize; 75 PetscLayout rLayout; 76 PetscInt locRows, rStart, rEnd, r; 77 PetscMPIInt size; 78 PetscBool useClosure, debug = PETSC_FALSE, isSymBlock, isSymSeqBlock, isSymMPIBlock; 79 PetscErrorCode ierr; 80 81 PetscFunctionBegin; 82 ierr = PetscLogEventBegin(DMPLEX_Preallocate,dm,0,0,0);CHKERRQ(ierr); 83 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 84 ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr); 85 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 86 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 87 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 88 /* Create dof SF based on point SF */ 89 if (debug) { 90 ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr); 91 ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 92 ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr); 93 ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 94 ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr); 95 ierr = PetscSFView(sf, NULL);CHKERRQ(ierr); 96 } 97 ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr); 98 ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr); 99 if (debug) { 100 ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr); 101 ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr); 102 } 103 /* Create section for dof adjacency (dof ==> # adj dof) */ 104 /* FEM: Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim */ 105 /* FVM: Two points p and q are adjacent if q \in star(cone(p)), preallocCenterDim = dim-1 */ 106 /* FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0 */ 107 if (mesh->preallocCenterDim == dim) { 108 useClosure = PETSC_FALSE; 109 } else if (mesh->preallocCenterDim == 0) { 110 useClosure = PETSC_TRUE; 111 } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim); 112 113 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 114 ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr); 115 ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr); 116 ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr); 117 ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr); 118 ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr); 119 /* Fill in the ghost dofs on the interface */ 120 ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr); 121 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 122 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); 123 124 maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)); 125 maxAdjSize = PetscPowInt(mesh->maxConeSize,depth+1) * PetscPowInt(mesh->maxSupportSize,depth+1) + 1; 126 127 ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr); 128 129 /* 130 ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point. 131 1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj 132 Reduce those counts to rootSectionAdj (now redundantly counting some interface points) 133 2. Visit owned points on interface, count adjacencies placing in rootSectionAdj 134 Create sfAdj connecting rootSectionAdj and leafSectionAdj 135 3. Visit unowned points on interface, write adjacencies to adj 136 Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies) 137 4. Visit owned points on interface, write adjacencies to rootAdj 138 Remove redundancy in rootAdj 139 ** The last two traversals use transitive closure 140 5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj) 141 Allocate memory addressed by sectionAdj (cols) 142 6. Visit all owned points in the subdomain, insert dof adjacencies into cols 143 ** Knowing all the column adjacencies, check ownership and sum into dnz and onz 144 */ 145 146 for (l = 0; l < nleaves; ++l) { 147 PetscInt dof, off, d, q; 148 PetscInt p = leaves[l], numAdj = maxAdjSize; 149 150 if ((p < pStart) || (p >= pEnd)) continue; 151 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 152 ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 153 ierr = DMPlexGetAdjacency_Internal(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr); 154 for (q = 0; q < numAdj; ++q) { 155 const PetscInt padj = tmpAdj[q]; 156 PetscInt ndof, ncdof; 157 158 if ((padj < pStart) || (padj >= pEnd)) continue; 159 ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); 160 ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); 161 for (d = off; d < off+dof; ++d) { 162 ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr); 163 } 164 } 165 } 166 ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr); 167 if (debug) { 168 ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr); 169 ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 170 } 171 /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */ 172 if (size > 1) { 173 ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr); 174 ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr); 175 } 176 if (debug) { 177 ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr); 178 ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 179 } 180 /* Add in local adjacency sizes for owned dofs on interface (roots) */ 181 for (p = pStart; p < pEnd; ++p) { 182 PetscInt numAdj = maxAdjSize, adof, dof, off, d, q; 183 184 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 185 ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 186 if (!dof) continue; 187 ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); 188 if (adof <= 0) continue; 189 ierr = DMPlexGetAdjacency_Internal(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr); 190 for (q = 0; q < numAdj; ++q) { 191 const PetscInt padj = tmpAdj[q]; 192 PetscInt ndof, ncdof; 193 194 if ((padj < pStart) || (padj >= pEnd)) continue; 195 ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); 196 ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); 197 for (d = off; d < off+dof; ++d) { 198 ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr); 199 } 200 } 201 } 202 ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr); 203 if (debug) { 204 ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr); 205 ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 206 } 207 /* Create adj SF based on dof SF */ 208 ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr); 209 ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr); 210 if (debug) { 211 ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr); 212 ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr); 213 } 214 ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr); 215 /* Create leaf adjacency */ 216 ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr); 217 ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr); 218 ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr); 219 ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr); 220 for (l = 0; l < nleaves; ++l) { 221 PetscInt dof, off, d, q; 222 PetscInt p = leaves[l], numAdj = maxAdjSize; 223 224 if ((p < pStart) || (p >= pEnd)) continue; 225 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 226 ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 227 ierr = DMPlexGetAdjacency_Internal(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr); 228 for (d = off; d < off+dof; ++d) { 229 PetscInt aoff, i = 0; 230 231 ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr); 232 for (q = 0; q < numAdj; ++q) { 233 const PetscInt padj = tmpAdj[q]; 234 PetscInt ndof, ncdof, ngoff, nd; 235 236 if ((padj < pStart) || (padj >= pEnd)) continue; 237 ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); 238 ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); 239 ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); 240 for (nd = 0; nd < ndof-ncdof; ++nd) { 241 adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd; 242 ++i; 243 } 244 } 245 } 246 } 247 /* Debugging */ 248 if (debug) { 249 IS tmp; 250 ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr); 251 ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); 252 ierr = ISView(tmp, NULL);CHKERRQ(ierr); 253 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 254 } 255 /* Gather adjacenct indices to root */ 256 ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr); 257 ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr); 258 for (r = 0; r < adjSize; ++r) rootAdj[r] = -1; 259 if (size > 1) { 260 ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr); 261 ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr); 262 } 263 ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr); 264 ierr = PetscFree(adj);CHKERRQ(ierr); 265 /* Debugging */ 266 if (debug) { 267 IS tmp; 268 ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr); 269 ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); 270 ierr = ISView(tmp, NULL);CHKERRQ(ierr); 271 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 272 } 273 /* Add in local adjacency indices for owned dofs on interface (roots) */ 274 for (p = pStart; p < pEnd; ++p) { 275 PetscInt numAdj = maxAdjSize, adof, dof, off, d, q; 276 277 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 278 ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 279 if (!dof) continue; 280 ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); 281 if (adof <= 0) continue; 282 ierr = DMPlexGetAdjacency_Internal(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr); 283 for (d = off; d < off+dof; ++d) { 284 PetscInt adof, aoff, i; 285 286 ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr); 287 ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr); 288 i = adof-1; 289 for (q = 0; q < numAdj; ++q) { 290 const PetscInt padj = tmpAdj[q]; 291 PetscInt ndof, ncdof, ngoff, nd; 292 293 if ((padj < pStart) || (padj >= pEnd)) continue; 294 ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); 295 ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); 296 ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); 297 for (nd = 0; nd < ndof-ncdof; ++nd) { 298 rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd; 299 --i; 300 } 301 } 302 } 303 } 304 /* Debugging */ 305 if (debug) { 306 IS tmp; 307 ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr); 308 ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); 309 ierr = ISView(tmp, NULL);CHKERRQ(ierr); 310 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 311 } 312 /* Compress indices */ 313 ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr); 314 for (p = pStart; p < pEnd; ++p) { 315 PetscInt dof, cdof, off, d; 316 PetscInt adof, aoff; 317 318 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 319 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 320 ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 321 if (!dof) continue; 322 ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); 323 if (adof <= 0) continue; 324 for (d = off; d < off+dof-cdof; ++d) { 325 ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr); 326 ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr); 327 ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr); 328 ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr); 329 } 330 } 331 /* Debugging */ 332 if (debug) { 333 IS tmp; 334 ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr); 335 ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 336 ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr); 337 ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); 338 ierr = ISView(tmp, NULL);CHKERRQ(ierr); 339 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 340 } 341 /* Build adjacency section: Maps global indices to sets of adjacent global indices */ 342 ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr); 343 ierr = PetscSectionCreate(comm, §ionAdj);CHKERRQ(ierr); 344 ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr); 345 for (p = pStart; p < pEnd; ++p) { 346 PetscInt numAdj = maxAdjSize, dof, cdof, off, goff, d, q; 347 PetscBool found = PETSC_TRUE; 348 349 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 350 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 351 ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 352 ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); 353 for (d = 0; d < dof-cdof; ++d) { 354 PetscInt ldof, rdof; 355 356 ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr); 357 ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr); 358 if (ldof > 0) { 359 /* We do not own this point */ 360 } else if (rdof > 0) { 361 ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr); 362 } else { 363 found = PETSC_FALSE; 364 } 365 } 366 if (found) continue; 367 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 368 ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); 369 ierr = DMPlexGetAdjacency_Internal(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr); 370 for (q = 0; q < numAdj; ++q) { 371 const PetscInt padj = tmpAdj[q]; 372 PetscInt ndof, ncdof, noff; 373 374 if ((padj < pStart) || (padj >= pEnd)) continue; 375 ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); 376 ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); 377 ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr); 378 for (d = goff; d < goff+dof-cdof; ++d) { 379 ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr); 380 } 381 } 382 } 383 ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr); 384 if (debug) { 385 ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr); 386 ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 387 } 388 /* Get adjacent indices */ 389 ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr); 390 ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr); 391 for (p = pStart; p < pEnd; ++p) { 392 PetscInt numAdj = maxAdjSize, dof, cdof, off, goff, d, q; 393 PetscBool found = PETSC_TRUE; 394 395 ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); 396 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 397 ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); 398 ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); 399 for (d = 0; d < dof-cdof; ++d) { 400 PetscInt ldof, rdof; 401 402 ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr); 403 ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr); 404 if (ldof > 0) { 405 /* We do not own this point */ 406 } else if (rdof > 0) { 407 PetscInt aoff, roff; 408 409 ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr); 410 ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr); 411 ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr); 412 } else { 413 found = PETSC_FALSE; 414 } 415 } 416 if (found) continue; 417 ierr = DMPlexGetAdjacency_Internal(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr); 418 for (d = goff; d < goff+dof-cdof; ++d) { 419 PetscInt adof, aoff, i = 0; 420 421 ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr); 422 ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr); 423 for (q = 0; q < numAdj; ++q) { 424 const PetscInt padj = tmpAdj[q]; 425 PetscInt ndof, ncdof, ngoff, nd; 426 const PetscInt *ncind; 427 428 /* Adjacent points may not be in the section chart */ 429 if ((padj < pStart) || (padj >= pEnd)) continue; 430 ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); 431 ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); 432 ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr); 433 ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); 434 for (nd = 0; nd < ndof-ncdof; ++nd, ++i) { 435 cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd; 436 } 437 } 438 if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p); 439 } 440 } 441 ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr); 442 ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr); 443 ierr = PetscFree(rootAdj);CHKERRQ(ierr); 444 ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr); 445 /* Debugging */ 446 if (debug) { 447 IS tmp; 448 ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr); 449 ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); 450 ierr = ISView(tmp, NULL);CHKERRQ(ierr); 451 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 452 } 453 /* Create allocation vectors from adjacency graph */ 454 ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr); 455 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr); 456 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 457 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 458 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 459 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 460 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 461 /* Only loop over blocks of rows */ 462 if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs); 463 for (r = rStart/bs; r < rEnd/bs; ++r) { 464 const PetscInt row = r*bs; 465 PetscInt numCols, cStart, c; 466 467 ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr); 468 ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr); 469 for (c = cStart; c < cStart+numCols; ++c) { 470 if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) { 471 ++dnz[r-rStart]; 472 if (cols[c] >= row) ++dnzu[r-rStart]; 473 } else { 474 ++onz[r-rStart]; 475 if (cols[c] >= row) ++onzu[r-rStart]; 476 } 477 } 478 } 479 if (bs > 1) { 480 for (r = 0; r < locRows/bs; ++r) { 481 dnz[r] /= bs; 482 onz[r] /= bs; 483 dnzu[r] /= bs; 484 onzu[r] /= bs; 485 } 486 } 487 /* Set matrix pattern */ 488 ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr); 489 ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 490 /* Check for symmetric storage */ 491 ierr = MatGetType(A, &mtype);CHKERRQ(ierr); 492 ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); 493 ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); 494 ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); 495 if (isSymBlock || isSymSeqBlock || isSymMPIBlock) {ierr = MatSetOption(A, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);} 496 /* Fill matrix with zeros */ 497 if (fillMatrix) { 498 PetscScalar *values; 499 PetscInt maxRowLen = 0; 500 501 for (r = rStart; r < rEnd; ++r) { 502 PetscInt len; 503 504 ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr); 505 maxRowLen = PetscMax(maxRowLen, len); 506 } 507 ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr); 508 ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr); 509 for (r = rStart; r < rEnd; ++r) { 510 PetscInt numCols, cStart; 511 512 ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr); 513 ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr); 514 ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr); 515 } 516 ierr = PetscFree(values);CHKERRQ(ierr); 517 ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 518 ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 519 } 520 ierr = PetscSectionDestroy(§ionAdj);CHKERRQ(ierr); 521 ierr = PetscFree(cols);CHKERRQ(ierr); 522 ierr = PetscLogEventEnd(DMPLEX_Preallocate,dm,0,0,0);CHKERRQ(ierr); 523 PetscFunctionReturn(0); 524 } 525 526 #if 0 527 #undef __FUNCT__ 528 #define __FUNCT__ "DMPlexPreallocateOperator_2" 529 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix) 530 { 531 PetscInt *tmpClosure,*tmpAdj,*visits; 532 PetscInt c,cStart,cEnd,pStart,pEnd; 533 PetscErrorCode ierr; 534 535 PetscFunctionBegin; 536 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 537 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 538 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); 539 540 maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)); 541 542 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 543 npoints = pEnd - pStart; 544 545 ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr); 546 ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr); 547 ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr); 548 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 549 for (c=cStart; c<cEnd; c++) { 550 PetscInt *support = tmpClosure; 551 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr); 552 for (p=0; p<supportSize; p++) lvisits[support[p]]++; 553 } 554 ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr); 555 ierr = PetscSFReduceEnd (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr); 556 ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr); 557 ierr = PetscSFBcastEnd (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr); 558 559 ierr = PetscSFGetRanks();CHKERRQ(ierr); 560 561 562 ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr); 563 for (c=cStart; c<cEnd; c++) { 564 ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr); 565 /* 566 Depth-first walk of transitive closure. 567 At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat. 568 This contribution is added to dnz if owning ranks of p and q match, to onz otherwise. 569 */ 570 } 571 572 ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr); 573 ierr = PetscSFReduceEnd (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr); 574 PetscFunctionReturn(0); 575 } 576 #endif 577