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