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