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