/*@C PetscSFGetGroups - gets incoming and outgoing process groups Collective Input Argument: . sf - star forest Output Arguments: + incoming - group of origin processes for incoming edges (leaves that reference my roots) - outgoing - group of destination processes for outgoing edges (roots that I reference) Level: developer .seealso: PetscSFGetWindow(), PetscSFRestoreWindow() @*/ PetscErrorCode PetscSFGetGroups(PetscSF sf,MPI_Group *incoming,MPI_Group *outgoing) { PetscErrorCode ierr; MPI_Group group; PetscFunctionBegin; if (sf->ingroup == MPI_GROUP_NULL) { PetscInt i; const PetscInt *indegree; PetscMPIInt rank,*outranks,*inranks; PetscSFNode *remote; PetscSF bgcount; /* Compute the number of incoming ranks */ ierr = PetscMalloc1(sf->nranks,&remote);CHKERRQ(ierr); for (i=0; i<sf->nranks; i++) { remote[i].rank = sf->ranks[i]; remote[i].index = 0; } ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_CONFONLY,&bgcount);CHKERRQ(ierr); ierr = PetscSFSetGraph(bgcount,1,sf->nranks,NULL,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(bgcount,&indegree);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(bgcount,&indegree);CHKERRQ(ierr); /* Enumerate the incoming ranks */ ierr = PetscMalloc2(indegree[0],&inranks,sf->nranks,&outranks);CHKERRQ(ierr); ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); for (i=0; i<sf->nranks; i++) outranks[i] = rank; ierr = PetscSFGatherBegin(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr); ierr = PetscSFGatherEnd(bgcount,MPI_INT,outranks,inranks);CHKERRQ(ierr); ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); ierr = MPI_Group_incl(group,indegree[0],inranks,&sf->ingroup);CHKERRQ(ierr); ierr = MPI_Group_free(&group);CHKERRQ(ierr); ierr = PetscFree2(inranks,outranks);CHKERRQ(ierr); ierr = PetscSFDestroy(&bgcount);CHKERRQ(ierr); } *incoming = sf->ingroup; if (sf->outgroup == MPI_GROUP_NULL) { ierr = MPI_Comm_group(PetscObjectComm((PetscObject)sf),&group);CHKERRQ(ierr); ierr = MPI_Group_incl(group,sf->nranks,sf->ranks,&sf->outgroup);CHKERRQ(ierr); ierr = MPI_Group_free(&group);CHKERRQ(ierr); } *outgoing = sf->outgroup; PetscFunctionReturn(0); }
/*@ DMLabelGather - Gather all label values from leafs into roots Input Parameters: + label - the DMLabel . point - the Star Forest point communication map Input Parameters: + label - the new DMLabel with localised leaf values Level: developer Note: This is the inverse operation to DMLabelDistribute. .seealso: DMLabelDistribute() @*/ PetscErrorCode DMLabelGather(DMLabel label, PetscSF sf, DMLabel *labelNew) { MPI_Comm comm; PetscSection rootSection; PetscSF sfLabel; PetscSFNode *rootPoints, *leafPoints; PetscInt p, s, d, nroots, nleaves, nmultiroots, idx, dof, offset; const PetscInt *rootDegree, *ilocal; PetscInt *rootStrata; char *name; PetscInt nameSize; size_t len = 0; PetscMPIInt rank, numProcs; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject)sf, &comm);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr); /* Bcast name */ if (!rank) {ierr = PetscStrlen(label->name, &len);CHKERRQ(ierr);} nameSize = len; ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); ierr = PetscMalloc1(nameSize+1, &name);CHKERRQ(ierr); if (!rank) {ierr = PetscMemcpy(name, label->name, nameSize+1);CHKERRQ(ierr);} ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr); ierr = DMLabelCreate(name, labelNew);CHKERRQ(ierr); ierr = PetscFree(name);CHKERRQ(ierr); /* Gather rank/index pairs of leaves into local roots to build an inverse, multi-rooted SF. Note that this ignores local leaf indexing due to the use of the multiSF in PetscSFGather. */ ierr = PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, NULL);CHKERRQ(ierr); ierr = PetscMalloc1(nleaves, &leafPoints);CHKERRQ(ierr); for (p = 0; p < nleaves; p++) { leafPoints[p].index = ilocal[p]; leafPoints[p].rank = rank; } ierr = PetscSFComputeDegreeBegin(sf, &rootDegree);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(sf, &rootDegree);CHKERRQ(ierr); for (p = 0, nmultiroots = 0; p < nroots; ++p) nmultiroots += rootDegree[p]; ierr = PetscMalloc1(nmultiroots, &rootPoints);CHKERRQ(ierr); ierr = PetscSFGatherBegin(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr); ierr = PetscSFGatherEnd(sf, MPIU_2INT, leafPoints, rootPoints);CHKERRQ(ierr); ierr = PetscSFCreate(comm,& sfLabel);CHKERRQ(ierr); ierr = PetscSFSetGraph(sfLabel, nroots, nmultiroots, NULL, PETSC_OWN_POINTER, rootPoints, PETSC_OWN_POINTER);CHKERRQ(ierr); /* Migrate label over inverted SF to pull stratum values at leaves into roots. */ ierr = DMLabelDistribute_Internal(label, sfLabel, &rootSection, &rootStrata);CHKERRQ(ierr); /* Rebuild the point strata on the receiver */ for (p = 0, idx = 0; p < nroots; p++) { for (d = 0; d < rootDegree[p]; d++) { ierr = PetscSectionGetDof(rootSection, idx+d, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootSection, idx+d, &offset);CHKERRQ(ierr); for (s = 0; s < dof; s++) {ierr = DMLabelSetValue(*labelNew, p, rootStrata[offset+s]);CHKERRQ(ierr);} } idx += rootDegree[p]; } ierr = PetscFree(leafPoints);CHKERRQ(ierr); ierr = PetscFree(rootStrata);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfLabel);CHKERRQ(ierr); PetscFunctionReturn(0); }
PETSC_EXTERN PetscErrorCode MatColoringLocalColor(MatColoring mc,PetscSF etoc,PetscSF etor,PetscReal *wts,ISColoringValue *color, ISColoringValue *maxcolor) { PetscInt nrows,ncols,ncolentries,nrowentries,idx,neighoffset; PetscInt i,j,k; PetscInt dist = mc->dist; PetscInt totalcolors; PetscBool *colormask; PetscErrorCode ierr; PetscBool *rowseen,*colseen; const PetscInt *rowdegrees; PetscInt *rowoffsets; const PetscInt *coldegrees; PetscInt *coloffsets; PetscInt offset; PetscInt *ll_ptr; PetscInt *ll_idx; PetscReal *swts; PetscInt *sidx; PetscInt unused; PetscInt rowlist,collist; PetscInt swp; PetscMPIInt rank; const PetscSFNode *colentries,*rowentries; PetscFunctionBegin; ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)mc),&rank);CHKERRQ(ierr); ierr = PetscSFGetGraph(etoc,&ncols,&ncolentries,NULL,&colentries);CHKERRQ(ierr); ierr = PetscSFGetGraph(etor,&nrows,&nrowentries,NULL,&rowentries);CHKERRQ(ierr); ierr = PetscMalloc6(nrows,&rowseen,ncols,&colseen,ncols,&coloffsets,nrows,&rowoffsets,2*ncols,&ll_ptr,2*ncols,&ll_idx);CHKERRQ(ierr); ierr = PetscMalloc2(ncols,&sidx,ncols,&swts);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(etoc,&rowdegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(etoc,&rowdegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(etor,&coldegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(etor,&coldegrees);CHKERRQ(ierr); /* sort by weight */ for (i=0;i<ncols;i++) { sidx[i] = i; swts[i] = wts[i]; } ierr = PetscSortRealWithPermutation(ncols,swts,sidx);CHKERRQ(ierr); for (i=0;i<ncols/2;i++) { swp = sidx[i]; sidx[i] = sidx[ncols-1-i]; sidx[ncols-1-i] = swp; } /* set up the "unused" linked list */ unused = 0; ll_ptr[2*ncols-1] = -1; for (i=0;i<2*ncols-1;i++) { ll_ptr[i] = i+1; } /* initialize the offsets */ offset=0; for (i=0;i<ncols;i++) { coloffsets[i] = offset; offset+=coldegrees[i]; colseen[i] = PETSC_FALSE; } offset=0; for (i=0;i<nrows;i++) { rowoffsets[i] = offset; offset+=rowdegrees[i]; rowseen[i] = PETSC_FALSE; } /* discover the maximum current color */ totalcolors = 1; for (i=0;i<ncols;i++) { if (color[i] > totalcolors-1 && color[i] != IS_COLORING_MAX) totalcolors = color[i]+1; } if (totalcolors < 10) totalcolors=10; ierr = PetscMalloc(sizeof(PetscBool)*totalcolors,&colormask);CHKERRQ(ierr); /* alternate between rows and columns to get the distance k minimum coloring */ for (i=0;i<ncols;i++) { collist = -1; rowlist = -1; if (color[sidx[i]] == IS_COLORING_MAX) { for (j=0;j<totalcolors;j++) colormask[j] = PETSC_FALSE; swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = collist; ll_idx[swp] = sidx[i]; collist = swp; colseen[sidx[i]] = PETSC_TRUE; for (k=0;k<=dist;k++) { if (k % 2 == 0) { while (collist >= 0) { if (k != dist) { for (j=0;j<coldegrees[ll_idx[collist]];j++) { neighoffset = coloffsets[ll_idx[collist]]+j; idx = colentries[neighoffset].index; if (colentries[neighoffset].rank == rank && !rowseen[idx]) { swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = rowlist; ll_idx[swp] = idx; rowlist = swp; rowseen[idx] = PETSC_TRUE; } } } if (color[ll_idx[collist]] != IS_COLORING_MAX) colormask[color[ll_idx[collist]]] = PETSC_TRUE; colseen[ll_idx[collist]] = PETSC_FALSE; swp = collist; collist = ll_ptr[collist]; ll_ptr[swp] = unused; unused = swp; } } else { while (rowlist >= 0) { if (k != dist) { for (j=0;j<rowdegrees[ll_idx[rowlist]];j++) { neighoffset = rowoffsets[ll_idx[rowlist]]+j; idx = rowentries[neighoffset].index; if (rowentries[neighoffset].rank == rank && !colseen[idx]) { swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = collist; ll_idx[swp] = idx; collist = swp; colseen[idx] = PETSC_TRUE; } } } if (color[ll_idx[rowlist]] != IS_COLORING_MAX) colormask[color[ll_idx[rowlist]]] = PETSC_TRUE; rowseen[ll_idx[rowlist]] = PETSC_FALSE; swp = rowlist; rowlist = ll_ptr[rowlist]; ll_ptr[swp] = unused; unused = swp; } } } color[sidx[i]] = totalcolors; for (k=0;k<totalcolors;k++) { if (!colormask[k]) {color[sidx[i]] = k; break;} } if (color[sidx[i]] >= mc->maxcolors && mc->maxcolors > 0) color[sidx[i]] = mc->maxcolors; if (color[sidx[i]] > *maxcolor) *maxcolor = color[sidx[i]]; if (color[sidx[i]] > totalcolors-1) { totalcolors *= 2; ierr = PetscFree(colormask);CHKERRQ(ierr); ierr = PetscMalloc(sizeof(PetscBool)*totalcolors,&colormask);CHKERRQ(ierr); } } if (collist != -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in local coloring BFS -- column queue still has %d\n",collist); if (rowlist != -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in local coloring BFS -- row queue still has %d\n",rowlist); } for (i=0;i<ncols;i++) { if (colseen[i]) {SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in local coloring BFS -- column %d still seen\n",i);} } for (i=0;i<nrows;i++) { if (rowseen[i]) {SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in local coloring BFS -- row %d still seen\n",i);} } ierr = PetscFree6(rowseen,colseen,coloffsets,rowoffsets,ll_ptr,ll_idx);CHKERRQ(ierr); ierr = PetscFree2(sidx,swts);CHKERRQ(ierr); ierr = PetscFree(colormask);CHKERRQ(ierr); PetscFunctionReturn(0); }
PETSC_EXTERN PetscErrorCode MatColoringDiscoverBoundary(MatColoring mc,PetscSF etoc,PetscSF etor,PetscInt *nboundary,PetscInt **boundary) { PetscInt nrows,ncols,ncolentries,nrowentries,idx,bidx,neighoffset; PetscInt i,j,k; PetscInt dist = mc->dist; PetscBool onBoundary; PetscErrorCode ierr; PetscBool *rowseen,*colseen; const PetscInt *rowdegrees; PetscInt *rowoffsets; const PetscInt *coldegrees; PetscInt *coloffsets; PetscInt offset; PetscInt *ll_ptr; PetscInt *ll_idx; PetscInt unused; PetscInt rowlist,collist; PetscInt swp; PetscMPIInt rank; const PetscSFNode *colentries,*rowentries; PetscFunctionBegin; *nboundary = 0; ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)mc),&rank);CHKERRQ(ierr); ierr = PetscSFGetGraph(etoc,&ncols,&ncolentries,NULL,&colentries);CHKERRQ(ierr); ierr = PetscSFGetGraph(etor,&nrows,&nrowentries,NULL,&rowentries);CHKERRQ(ierr); ierr = PetscMalloc6(nrows,&rowseen, ncols,&colseen, ncols,&coloffsets, nrows,&rowoffsets, 2*ncols,&ll_ptr, 2*ncols,&ll_idx);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(etoc,&rowdegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(etoc,&rowdegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(etor,&coldegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(etor,&coldegrees);CHKERRQ(ierr); /* set up the "unused" linked list -- double the size of the number of items as in tiny or large distance cases we may have a clique */ unused = 0; ll_ptr[2*ncols-1] = -1; for (i=0;i<2*ncols-1;i++) { ll_ptr[i] = i+1; } /* initialize the offsets */ offset=0; for (i=0;i<ncols;i++) { coloffsets[i] = offset; offset+=coldegrees[i]; colseen[i] = PETSC_FALSE; } offset=0; for (i=0;i<nrows;i++) { rowoffsets[i] = offset; offset+=rowdegrees[i]; rowseen[i] = PETSC_FALSE; } /* count the number of boundary nodes */ for (i=0;i<ncols;i++) { onBoundary = PETSC_FALSE; collist = -1; rowlist = -1; swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = collist; ll_idx[swp] = i; collist = swp; colseen[i] = PETSC_TRUE; for (k=0;k<=dist;k++) { if (k % 2 == 0) { while (collist >= 0) { if (k != dist) { for (j=0;j<coldegrees[ll_idx[collist]];j++) { neighoffset = coloffsets[ll_idx[collist]]+j; idx = colentries[neighoffset].index; if (colentries[neighoffset].rank == rank) { if (!rowseen[idx] && !onBoundary) { swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = rowlist; rowlist = swp; ll_idx[swp] = idx; rowseen[idx] = PETSC_TRUE; } } else { onBoundary = PETSC_TRUE; } } } colseen[ll_idx[collist]] = PETSC_FALSE; swp = collist; collist = ll_ptr[collist]; ll_ptr[swp] = unused; unused = swp; } } else { while (rowlist >= 0) { if (k != dist) { for (j=0;j<rowdegrees[ll_idx[rowlist]];j++) { neighoffset = rowoffsets[ll_idx[rowlist]]+j; if (rowentries[neighoffset].rank == rank) { idx = rowentries[neighoffset].index; if (!colseen[idx] && !onBoundary) { swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = collist; ll_idx[swp] = idx; colseen[idx] = PETSC_TRUE; collist = swp; } } else { onBoundary = PETSC_TRUE; } } } rowseen[ll_idx[rowlist]] = PETSC_FALSE; swp = rowlist; rowlist = ll_ptr[rowlist]; ll_ptr[swp] = unused; unused = swp; } } } if (onBoundary) {(*nboundary)++;} if (collist != -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in boundary count BFS -- column queue still has %d\n",collist); if (rowlist != -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in boundary count BFS -- row queue still has %d\n",collist); } for (i=0;i<ncols;i++) { if (colseen[i]) {SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in boundary count BFS -- column %d still seen\n",i);} } for (i=0;i<nrows;i++) { if (rowseen[i]) {SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in boundary count BFS -- row %d still seen\n",i);} } ierr = PetscMalloc(sizeof(PetscInt)*(*nboundary),boundary);CHKERRQ(ierr); /* set the boundary nodes */ bidx=0; for (i=0;i<ncols;i++) { onBoundary = PETSC_FALSE; collist = -1; rowlist = -1; swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = collist; ll_idx[swp] = i; collist = swp; colseen[i] = PETSC_TRUE; for (k=0;k<=dist;k++) { if (k % 2 == 0) { while (collist >= 0) { if (k != dist) { for (j=0;j<coldegrees[ll_idx[collist]];j++) { neighoffset = coloffsets[ll_idx[collist]]+j; idx = colentries[neighoffset].index; if (colentries[neighoffset].rank == rank) { if (!rowseen[idx] && !onBoundary) { swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = rowlist; rowlist = swp; ll_idx[swp] = idx; rowseen[idx] = PETSC_TRUE; } } else { onBoundary = PETSC_TRUE; } } } colseen[ll_idx[collist]] = PETSC_FALSE; swp = collist; collist = ll_ptr[collist]; ll_ptr[swp] = unused; unused = swp; } } else { while (rowlist >= 0) { if (k != dist) { for (j=0;j<rowdegrees[ll_idx[rowlist]];j++) { neighoffset = rowoffsets[ll_idx[rowlist]]+j; if (rowentries[neighoffset].rank == rank) { idx = rowentries[neighoffset].index; if (!colseen[idx] && !onBoundary) { swp = unused; unused = ll_ptr[unused]; ll_ptr[swp] = collist; ll_idx[swp] = idx; colseen[idx] = PETSC_TRUE; collist = swp; } } else { onBoundary = PETSC_TRUE; } } } rowseen[ll_idx[rowlist]] = PETSC_FALSE; swp = rowlist; rowlist = ll_ptr[rowlist]; ll_ptr[swp] = unused; unused = swp; } } } if (onBoundary) {(*boundary)[bidx] = i; bidx++;} } for (i=0;i<ncols;i++) { if (colseen[i]) {SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in boundary set BFS -- column %d still seen\n",i);} } for (i=0;i<nrows;i++) { if (rowseen[i]) {SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"Likely error in boundary set BFS -- row %d still seen\n",i);} } if (bidx != *nboundary) {SETERRQ(PetscObjectComm((PetscObject)mc),PETSC_ERR_NOT_CONVERGED,"Number of boundary nodes not matched");} ierr = PetscFree6(rowseen,colseen,coloffsets,rowoffsets,ll_ptr,ll_idx);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@C PetscSFGetMultiSF - gets the inner SF implemeting gathers and scatters Collective Input Argument: . sf - star forest that may contain roots with 0 or with more than 1 vertex Output Arguments: . multi - star forest with split roots, such that each root has degree exactly 1 Level: developer Notes: In most cases, users should use PetscSFGatherBegin() and PetscSFScatterBegin() instead of manipulating multi directly. Since multi satisfies the stronger condition that each entry in the global space has exactly one incoming edge, it is a candidate for future optimization that might involve its removal. .seealso: PetscSFSetGraph(), PetscSFGatherBegin(), PetscSFScatterBegin() @*/ PetscErrorCode PetscSFGetMultiSF(PetscSF sf,PetscSF *multi) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sf,PETSCSF_CLASSID,1); PetscValidPointer(multi,2); if (sf->nroots < 0) { /* Graph has not been set yet; why do we need this? */ ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr); *multi = sf->multi; PetscFunctionReturn(0); } if (!sf->multi) { const PetscInt *indegree; PetscInt i,*inoffset,*outones,*outoffset,maxlocal; PetscSFNode *remote; ierr = PetscSFComputeDegreeBegin(sf,&indegree);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(sf,&indegree);CHKERRQ(ierr); for (i=0,maxlocal=0; i<sf->nleaves; i++) maxlocal = PetscMax(maxlocal,(sf->mine ? sf->mine[i] : i)+1); ierr = PetscMalloc3(sf->nroots+1,&inoffset,maxlocal,&outones,maxlocal,&outoffset);CHKERRQ(ierr); inoffset[0] = 0; for (i=0; i<sf->nroots; i++) inoffset[i+1] = inoffset[i] + indegree[i]; for (i=0; i<maxlocal; i++) outones[i] = 1; ierr = PetscSFFetchAndOpBegin(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFFetchAndOpEnd(sf,MPIU_INT,inoffset,outones,outoffset,MPI_SUM);CHKERRQ(ierr); for (i=0; i<sf->nroots; i++) inoffset[i] -= indegree[i]; /* Undo the increment */ #if 0 #if defined(PETSC_USE_DEBUG) /* Check that the expected number of increments occurred */ for (i=0; i<sf->nroots; i++) { if (inoffset[i] + indegree[i] != inoffset[i+1]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Incorrect result after PetscSFFetchAndOp"); } #endif #endif ierr = PetscMalloc1(sf->nleaves,&remote);CHKERRQ(ierr); for (i=0; i<sf->nleaves; i++) { remote[i].rank = sf->remote[i].rank; remote[i].index = outoffset[sf->mine ? sf->mine[i] : i]; } ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_RANKS,&sf->multi);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,remote,PETSC_OWN_POINTER);CHKERRQ(ierr); if (sf->rankorder) { /* Sort the ranks */ PetscMPIInt rank; PetscInt *inranks,*newoffset,*outranks,*newoutoffset,*tmpoffset,maxdegree; PetscSFNode *newremote; ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)sf),&rank);CHKERRQ(ierr); for (i=0,maxdegree=0; i<sf->nroots; i++) maxdegree = PetscMax(maxdegree,indegree[i]); ierr = PetscMalloc5(sf->multi->nroots,&inranks,sf->multi->nroots,&newoffset,maxlocal,&outranks,maxlocal,&newoutoffset,maxdegree,&tmpoffset);CHKERRQ(ierr); for (i=0; i<maxlocal; i++) outranks[i] = rank; ierr = PetscSFReduceBegin(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr); ierr = PetscSFReduceEnd(sf->multi,MPIU_INT,outranks,inranks,MPIU_REPLACE);CHKERRQ(ierr); /* Sort the incoming ranks at each vertex, build the inverse map */ for (i=0; i<sf->nroots; i++) { PetscInt j; for (j=0; j<indegree[i]; j++) tmpoffset[j] = j; ierr = PetscSortIntWithArray(indegree[i],inranks+inoffset[i],tmpoffset);CHKERRQ(ierr); for (j=0; j<indegree[i]; j++) newoffset[inoffset[i] + tmpoffset[j]] = inoffset[i] + j; } ierr = PetscSFBcastBegin(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr); ierr = PetscSFBcastEnd(sf->multi,MPIU_INT,newoffset,newoutoffset);CHKERRQ(ierr); ierr = PetscMalloc1(sf->nleaves,&newremote);CHKERRQ(ierr); for (i=0; i<sf->nleaves; i++) { newremote[i].rank = sf->remote[i].rank; newremote[i].index = newoutoffset[sf->mine ? sf->mine[i] : i]; } ierr = PetscSFSetGraph(sf->multi,inoffset[sf->nroots],sf->nleaves,sf->mine,PETSC_COPY_VALUES,newremote,PETSC_OWN_POINTER);CHKERRQ(ierr); ierr = PetscFree5(inranks,newoffset,outranks,newoutoffset,tmpoffset);CHKERRQ(ierr); } ierr = PetscFree3(inoffset,outones,outoffset);CHKERRQ(ierr); } *multi = sf->multi; PetscFunctionReturn(0); }
int main(int argc,char **argv) { PetscSF sf,sfDup,sfInv,sfEmbed,sfA,sfB,sfBA; const PetscInt *degree; PetscErrorCode ierr; ierr = PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr; ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFReset(sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFReset(sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = CheckGraphEmpty(sf);CHKERRQ(ierr); ierr = PetscSFReset(sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = CheckGraphEmpty(sf);CHKERRQ(ierr); ierr = PetscSFReset(sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test setup */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = CheckRanksNotSet(sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = CheckRanksNotSet(sf);CHKERRQ(ierr); ierr = PetscSFSetUp(sf);CHKERRQ(ierr); ierr = CheckRanksEmpty(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test setup then reset */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFSetUp(sf);CHKERRQ(ierr); ierr = PetscSFReset(sf);CHKERRQ(ierr); ierr = CheckRanksNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test view (no graph set, no type set) */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFView(sf,NULL);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test set graph then view (no type set) */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFView(sf,NULL);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test set type then view (no graph set) */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr); ierr = PetscSFView(sf,NULL);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test set type then graph then view */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFView(sf,NULL);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test set graph then type */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr); ierr = CheckGraphEmpty(sf);CHKERRQ(ierr); ierr = PetscSFReset(sf);CHKERRQ(ierr); ierr = CheckGraphNotSet(sf);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test Bcast */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFBcastBegin(sf,MPI_INT,NULL,NULL);CHKERRQ(ierr); ierr = PetscSFBcastEnd (sf,MPI_INT,NULL,NULL);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test Reduce */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFReduceBegin(sf,MPI_INT,NULL,NULL,MPIU_REPLACE);CHKERRQ(ierr); ierr = PetscSFReduceEnd (sf,MPI_INT,NULL,NULL,MPIU_REPLACE);CHKERRQ(ierr); ierr = PetscSFReduceBegin(sf,MPI_INT,NULL,NULL,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFReduceEnd (sf,MPI_INT,NULL,NULL,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test FetchAndOp */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFFetchAndOpBegin(sf,MPI_INT,NULL,NULL,NULL,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFFetchAndOpEnd (sf,MPI_INT,NULL,NULL,NULL,MPI_SUM);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test ComputeDegree */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_COPY_VALUES,NULL,PETSC_COPY_VALUES);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(sf,°ree);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(sf,°ree);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test PetscSFDuplicate() */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_USE_POINTER,NULL,PETSC_USE_POINTER);CHKERRQ(ierr); ierr = PetscSFDuplicate(sf,PETSCSF_DUPLICATE_GRAPH,&sfDup);CHKERRQ(ierr); ierr = CheckGraphEmpty(sfDup);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfDup);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test PetscSFCreateInverseSF() */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_USE_POINTER,NULL,PETSC_USE_POINTER);CHKERRQ(ierr); ierr = PetscSFCreateInverseSF(sf,&sfInv);CHKERRQ(ierr); ierr = CheckGraphEmpty(sfInv);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfInv);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test PetscSFCreateEmbeddedSF() */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_USE_POINTER,NULL,PETSC_USE_POINTER);CHKERRQ(ierr); ierr = PetscSFCreateEmbeddedSF(sf,0,NULL,&sfEmbed);CHKERRQ(ierr); ierr = CheckGraphEmpty(sfEmbed);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfEmbed);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test PetscSFCreateEmbeddedLeafSF() */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sf);CHKERRQ(ierr); ierr = PetscSFSetGraph(sf,0,0,NULL,PETSC_USE_POINTER,NULL,PETSC_USE_POINTER);CHKERRQ(ierr); ierr = PetscSFCreateEmbeddedLeafSF(sf,0,NULL,&sfEmbed);CHKERRQ(ierr); ierr = CheckGraphEmpty(sfEmbed);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfEmbed);CHKERRQ(ierr); ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); /* Test PetscSFCompose() */ ierr = PetscSFCreate(PETSC_COMM_WORLD,&sfA);CHKERRQ(ierr); ierr = PetscSFSetGraph(sfA,0,0,NULL,PETSC_USE_POINTER,NULL,PETSC_USE_POINTER);CHKERRQ(ierr); ierr = PetscSFCreate(PETSC_COMM_WORLD,&sfB);CHKERRQ(ierr); ierr = PetscSFSetGraph(sfB,0,0,NULL,PETSC_USE_POINTER,NULL,PETSC_USE_POINTER);CHKERRQ(ierr); ierr = PetscSFCompose(sfA,sfB,&sfBA);CHKERRQ(ierr); ierr = CheckGraphEmpty(sfBA);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfBA);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfA);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfB);CHKERRQ(ierr); ierr = PetscFinalize(); return ierr; }
PETSC_EXTERN PetscErrorCode MatColoringCreateBipartiteGraph(MatColoring mc,PetscSF *etoc,PetscSF *etor) { PetscErrorCode ierr; PetscInt nentries,ncolentries,idx; PetscInt i,j,rs,re,cs,ce,cn; PetscInt *rowleaf,*colleaf,*rowdata; PetscInt ncol; const PetscScalar *vcol; const PetscInt *icol; const PetscInt *coldegrees,*rowdegrees; Mat m = mc->mat; PetscFunctionBegin; ierr = MatGetOwnershipRange(m,&rs,&re);CHKERRQ(ierr); ierr = MatGetOwnershipRangeColumn(m,&cs,&ce);CHKERRQ(ierr); cn = ce-cs; nentries=0; for (i=rs;i<re;i++) { ierr = MatGetRow(m,i,&ncol,NULL,&vcol);CHKERRQ(ierr); for (j=0;j<ncol;j++) { nentries++; } ierr = MatRestoreRow(m,i,&ncol,NULL,&vcol);CHKERRQ(ierr); } ierr = PetscMalloc(sizeof(PetscInt)*nentries,&rowleaf);CHKERRQ(ierr); ierr = PetscMalloc(sizeof(PetscInt)*nentries,&rowdata);CHKERRQ(ierr); idx=0; for (i=rs;i<re;i++) { ierr = MatGetRow(m,i,&ncol,&icol,&vcol);CHKERRQ(ierr); for (j=0;j<ncol;j++) { rowleaf[idx] = icol[j]; rowdata[idx] = i; idx++; } ierr = MatRestoreRow(m,i,&ncol,&icol,&vcol);CHKERRQ(ierr); } if (idx != nentries) SETERRQ2(PetscObjectComm((PetscObject)m),PETSC_ERR_NOT_CONVERGED,"Bad number of entries %d vs %d",idx,nentries); ierr = PetscSFCreate(PetscObjectComm((PetscObject)m),etoc);CHKERRQ(ierr); ierr = PetscSFCreate(PetscObjectComm((PetscObject)m),etor);CHKERRQ(ierr); ierr = PetscSFSetGraphLayout(*etoc,m->cmap,nentries,NULL,PETSC_COPY_VALUES,rowleaf);CHKERRQ(ierr); ierr = PetscSFSetFromOptions(*etoc);CHKERRQ(ierr); /* determine the number of entries in the column matrix */ ierr = PetscLogEventBegin(Mat_Coloring_Comm,*etoc,0,0,0);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(*etoc,&coldegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(*etoc,&coldegrees);CHKERRQ(ierr); ierr = PetscLogEventEnd(Mat_Coloring_Comm,*etoc,0,0,0);CHKERRQ(ierr); ncolentries=0; for (i=0;i<cn;i++) { ncolentries += coldegrees[i]; } ierr = PetscMalloc(sizeof(PetscInt)*ncolentries,&colleaf);CHKERRQ(ierr); /* create the one going the other way by building the leaf set */ ierr = PetscLogEventBegin(Mat_Coloring_Comm,*etoc,0,0,0);CHKERRQ(ierr); ierr = PetscSFGatherBegin(*etoc,MPIU_INT,rowdata,colleaf);CHKERRQ(ierr); ierr = PetscSFGatherEnd(*etoc,MPIU_INT,rowdata,colleaf);CHKERRQ(ierr); ierr = PetscLogEventEnd(Mat_Coloring_Comm,*etoc,0,0,0);CHKERRQ(ierr); /* this one takes mat entries in *columns* to rows -- you never have to actually be able to order the leaf entries. */ ierr = PetscSFSetGraphLayout(*etor,m->rmap,ncolentries,NULL,PETSC_COPY_VALUES,colleaf);CHKERRQ(ierr); ierr = PetscSFSetFromOptions(*etor);CHKERRQ(ierr); ierr = PetscLogEventBegin(Mat_Coloring_Comm,*etor,0,0,0);CHKERRQ(ierr); ierr = PetscSFComputeDegreeBegin(*etor,&rowdegrees);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(*etor,&rowdegrees);CHKERRQ(ierr); ierr = PetscLogEventEnd(Mat_Coloring_Comm,*etor,0,0,0);CHKERRQ(ierr); ierr = PetscFree(rowdata);CHKERRQ(ierr); ierr = PetscFree(rowleaf);CHKERRQ(ierr); ierr = PetscFree(colleaf);CHKERRQ(ierr); PetscFunctionReturn(0); }
/* This interpolates the PointSF in parallel following local interpolation */ static PetscErrorCode DMPlexInterpolatePointSF(DM dm, PetscSF pointSF, PetscInt depth) { PetscMPIInt numProcs, rank; PetscInt p, c, d, dof, offset; PetscInt numLeaves, numRoots, candidatesSize, candidatesRemoteSize; const PetscInt *localPoints; const PetscSFNode *remotePoints; PetscSFNode *candidates, *candidatesRemote, *claims; PetscSection candidateSection, candidateSectionRemote, claimSection; PetscHashI leafhash; PetscHashIJ roothash; PetscHashIJKey key; PetscErrorCode ierr; PetscFunctionBegin; ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr); ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr); if (numProcs < 2 || numRoots < 0) PetscFunctionReturn(0); /* Build hashes of points in the SF for efficient lookup */ PetscHashICreate(leafhash); PetscHashIJCreate(&roothash); ierr = PetscHashIJSetMultivalued(roothash, PETSC_FALSE);CHKERRQ(ierr); for (p = 0; p < numLeaves; ++p) { PetscHashIAdd(leafhash, localPoints[p], p); key.i = remotePoints[p].index; key.j = remotePoints[p].rank; PetscHashIJAdd(roothash, key, p); } /* Build a section / SFNode array of candidate points in the single-level adjacency of leaves, where each candidate is defined by the root entry for the other vertex that defines the edge. */ ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &candidateSection);CHKERRQ(ierr); ierr = PetscSectionSetChart(candidateSection, 0, numRoots);CHKERRQ(ierr); { PetscInt leaf, root, idx, a, *adj = NULL; for (p = 0; p < numLeaves; ++p) { PetscInt adjSize = PETSC_DETERMINE; ierr = DMPlexGetAdjacency_Internal(dm, localPoints[p], PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr); for (a = 0; a < adjSize; ++a) { PetscHashIMap(leafhash, adj[a], leaf); if (leaf >= 0) {ierr = PetscSectionAddDof(candidateSection, localPoints[p], 1);CHKERRQ(ierr);} } } ierr = PetscSectionSetUp(candidateSection);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(candidateSection, &candidatesSize);CHKERRQ(ierr); ierr = PetscMalloc1(candidatesSize, &candidates);CHKERRQ(ierr); for (p = 0; p < numLeaves; ++p) { PetscInt adjSize = PETSC_DETERMINE; ierr = PetscSectionGetOffset(candidateSection, localPoints[p], &offset);CHKERRQ(ierr); ierr = DMPlexGetAdjacency_Internal(dm, localPoints[p], PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr); for (idx = 0, a = 0; a < adjSize; ++a) { PetscHashIMap(leafhash, adj[a], root); if (root >= 0) candidates[offset+idx++] = remotePoints[root]; } } ierr = PetscFree(adj);CHKERRQ(ierr); } /* Gather candidate section / array pair into the root partition via inverse(multi(pointSF)). */ { PetscSF sfMulti, sfInverse, sfCandidates; PetscInt *remoteOffsets; ierr = PetscSFGetMultiSF(pointSF, &sfMulti);CHKERRQ(ierr); ierr = PetscSFCreateInverseSF(sfMulti, &sfInverse);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &candidateSectionRemote);CHKERRQ(ierr); ierr = PetscSFDistributeSection(sfInverse, candidateSection, &remoteOffsets, candidateSectionRemote);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(sfInverse, candidateSection, remoteOffsets, candidateSectionRemote, &sfCandidates);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(candidateSectionRemote, &candidatesRemoteSize);CHKERRQ(ierr); ierr = PetscMalloc1(candidatesRemoteSize, &candidatesRemote);CHKERRQ(ierr); ierr = PetscSFBcastBegin(sfCandidates, MPIU_2INT, candidates, candidatesRemote);CHKERRQ(ierr); ierr = PetscSFBcastEnd(sfCandidates, MPIU_2INT, candidates, candidatesRemote);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfInverse);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfCandidates);CHKERRQ(ierr); ierr = PetscFree(remoteOffsets);CHKERRQ(ierr); } /* Walk local roots and check for each remote candidate whether we know all required points, either from owning it or having a root entry in the point SF. If we do we place a claim by replacing the vertex number with our edge ID. */ { PetscInt idx, root, joinSize, vertices[2]; const PetscInt *rootdegree, *join = NULL; ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr); /* Loop remote edge connections and put in a claim if both vertices are known */ for (idx = 0, p = 0; p < numRoots; ++p) { for (d = 0; d < rootdegree[p]; ++d) { ierr = PetscSectionGetDof(candidateSectionRemote, idx, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(candidateSectionRemote, idx, &offset);CHKERRQ(ierr); for (c = 0; c < dof; ++c) { /* We own both vertices, so we claim the edge by replacing vertex with edge */ if (candidatesRemote[offset+c].rank == rank) { vertices[0] = p; vertices[1] = candidatesRemote[offset+c].index; ierr = DMPlexGetJoin(dm, 2, vertices, &joinSize, &join);CHKERRQ(ierr); if (joinSize == 1) candidatesRemote[offset+c].index = join[0]; ierr = DMPlexRestoreJoin(dm, 2, vertices, &joinSize, &join);CHKERRQ(ierr); continue; } /* If we own one vertex and share a root with the other, we claim it */ key.i = candidatesRemote[offset+c].index; key.j = candidatesRemote[offset+c].rank; PetscHashIJGet(roothash, key, &root); if (root >= 0) { vertices[0] = p; vertices[1] = localPoints[root]; ierr = DMPlexGetJoin(dm, 2, vertices, &joinSize, &join);CHKERRQ(ierr); if (joinSize == 1) { candidatesRemote[offset+c].index = join[0]; candidatesRemote[offset+c].rank = rank; } ierr = DMPlexRestoreJoin(dm, 2, vertices, &joinSize, &join);CHKERRQ(ierr); } } idx++; } } } /* Push claims back to receiver via the MultiSF and derive new pointSF mapping on receiver */ { PetscSF sfMulti, sfClaims, sfPointNew; PetscHashI claimshash; PetscInt size, pStart, pEnd, root, joinSize, numLocalNew; PetscInt *remoteOffsets, *localPointsNew, vertices[2]; const PetscInt *join = NULL; PetscSFNode *remotePointsNew; ierr = PetscSFGetMultiSF(pointSF, &sfMulti);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &claimSection);CHKERRQ(ierr); ierr = PetscSFDistributeSection(sfMulti, candidateSectionRemote, &remoteOffsets, claimSection);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(sfMulti, candidateSectionRemote, remoteOffsets, claimSection, &sfClaims);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(claimSection, &size);CHKERRQ(ierr); ierr = PetscMalloc1(size, &claims);CHKERRQ(ierr); ierr = PetscSFBcastBegin(sfClaims, MPIU_2INT, candidatesRemote, claims);CHKERRQ(ierr); ierr = PetscSFBcastEnd(sfClaims, MPIU_2INT, candidatesRemote, claims);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfClaims);CHKERRQ(ierr); ierr = PetscFree(remoteOffsets);CHKERRQ(ierr); /* Walk the original section of local supports and add an SF entry for each updated item */ PetscHashICreate(claimshash); for (p = 0; p < numRoots; ++p) { ierr = PetscSectionGetDof(candidateSection, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(candidateSection, p, &offset);CHKERRQ(ierr); for (d = 0; d < dof; ++d) { if (candidates[offset+d].index != claims[offset+d].index) { key.i = candidates[offset+d].index; key.j = candidates[offset+d].rank; PetscHashIJGet(roothash, key, &root); if (root >= 0) { vertices[0] = p; vertices[1] = localPoints[root]; ierr = DMPlexGetJoin(dm, 2, vertices, &joinSize, &join);CHKERRQ(ierr); if (joinSize == 1) PetscHashIAdd(claimshash, join[0], offset+d); ierr = DMPlexRestoreJoin(dm, 2, vertices, &joinSize, &join);CHKERRQ(ierr); } } } } /* Create new pointSF from hashed claims */ PetscHashISize(claimshash, numLocalNew); ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscMalloc1(numLeaves + numLocalNew, &localPointsNew);CHKERRQ(ierr); ierr = PetscMalloc1(numLeaves + numLocalNew, &remotePointsNew);CHKERRQ(ierr); for (p = 0; p < numLeaves; ++p) { localPointsNew[p] = localPoints[p]; remotePointsNew[p].index = remotePoints[p].index; remotePointsNew[p].rank = remotePoints[p].rank; } p = numLeaves; ierr = PetscHashIGetKeys(claimshash, &p, localPointsNew);CHKERRQ(ierr); for (p = numLeaves; p < numLeaves + numLocalNew; ++p) { PetscHashIMap(claimshash, localPointsNew[p], offset); remotePointsNew[p] = claims[offset]; } ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), &sfPointNew);CHKERRQ(ierr); ierr = PetscSFSetGraph(sfPointNew, pEnd-pStart, numLeaves+numLocalNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr); ierr = DMSetPointSF(dm, sfPointNew);CHKERRQ(ierr); ierr = PetscSFDestroy(&sfPointNew);CHKERRQ(ierr); PetscHashIDestroy(claimshash); } PetscHashIDestroy(leafhash); ierr = PetscHashIJDestroy(&roothash);CHKERRQ(ierr); ierr = PetscSectionDestroy(&candidateSection);CHKERRQ(ierr); ierr = PetscSectionDestroy(&candidateSectionRemote);CHKERRQ(ierr); ierr = PetscSectionDestroy(&claimSection);CHKERRQ(ierr); ierr = PetscFree(candidates);CHKERRQ(ierr); ierr = PetscFree(candidatesRemote);CHKERRQ(ierr); ierr = PetscFree(claims);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix) { MPI_Comm comm; MatType mtype; PetscSF sf, sfDof, sfAdj; PetscSection leafSectionAdj, rootSectionAdj, sectionAdj, anchorSectionAdj; PetscInt nroots, nleaves, l, p; const PetscInt *leaves; const PetscSFNode *remotes; PetscInt dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols; PetscInt *tmpAdj = NULL, *adj, *rootAdj, *anchorAdj = NULL, *cols, *remoteOffsets; PetscInt adjSize; PetscLayout rLayout; PetscInt locRows, rStart, rEnd, r; PetscMPIInt size; PetscBool doCommLocal, doComm, debug = PETSC_FALSE, isSymBlock, isSymSeqBlock, isSymMPIBlock; PetscBool useAnchors; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 3); PetscValidHeaderSpecific(sectionGlobal, PETSC_SECTION_CLASSID, 4); PetscValidHeaderSpecific(A, MAT_CLASSID, 9); if (dnz) PetscValidPointer(dnz,5); if (onz) PetscValidPointer(onz,6); if (dnzu) PetscValidPointer(dnzu,7); if (onzu) PetscValidPointer(onzu,8); ierr = PetscLogEventBegin(DMPLEX_Preallocate,dm,0,0,0);CHKERRQ(ierr); ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr); ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); doCommLocal = (size > 1) && (nroots >= 0) ? PETSC_TRUE : PETSC_FALSE; ierr = MPI_Allreduce(&doCommLocal, &doComm, 1, MPIU_BOOL, MPI_LAND, comm);CHKERRQ(ierr); /* Create dof SF based on point SF */ if (debug) { ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSFView(sf, NULL);CHKERRQ(ierr); } ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr); } /* Create section for dof adjacency (dof ==> # adj dof) */ ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr); ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr); ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr); ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr); ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr); /* Fill in the ghost dofs on the interface */ ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr); /* use constraints in finding adjacency in this routine */ ierr = DMPlexGetAdjacencyUseAnchors(dm,&useAnchors);CHKERRQ(ierr); ierr = DMPlexSetAdjacencyUseAnchors(dm,PETSC_TRUE);CHKERRQ(ierr); /* section - maps points to (# dofs, local dofs) sectionGlobal - maps points to (# dofs, global dofs) leafSectionAdj - maps unowned local dofs to # adj dofs rootSectionAdj - maps owned local dofs to # adj dofs adj - adj global dofs indexed by leafSectionAdj rootAdj - adj global dofs indexed by rootSectionAdj sf - describes shared points across procs sfDof - describes shared dofs across procs sfAdj - describes shared adjacent dofs across procs ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point. (0). If there are point-to-point constraints, add the adjacencies of constrained points to anchors in anchorAdj (This is done in DMPlexComputeAnchorAdjacencies()) 1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj Reduce those counts to rootSectionAdj (now redundantly counting some interface points) 2. Visit owned points on interface, count adjacencies placing in rootSectionAdj Create sfAdj connecting rootSectionAdj and leafSectionAdj 3. Visit unowned points on interface, write adjacencies to adj Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies) 4. Visit owned points on interface, write adjacencies to rootAdj Remove redundancy in rootAdj ** The last two traversals use transitive closure 5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj) Allocate memory addressed by sectionAdj (cols) 6. Visit all owned points in the subdomain, insert dof adjacencies into cols ** Knowing all the column adjacencies, check ownership and sum into dnz and onz */ ierr = DMPlexComputeAnchorAdjacencies(dm,section,sectionGlobal,&anchorSectionAdj,&anchorAdj);CHKERRQ(ierr); for (l = 0; l < nleaves; ++l) { PetscInt dof, off, d, q, anDof; PetscInt p = leaves[l], numAdj = PETSC_DETERMINE; if ((p < pStart) || (p >= pEnd)) continue; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr); } } ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); if (anDof) { for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(leafSectionAdj, d, anDof);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr); ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */ if (doComm) { ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr); ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr); } if (debug) { ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr); ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Add in local adjacency sizes for owned dofs on interface (roots) */ for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); if (!dof) continue; ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); if (adof <= 0) continue; ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr); } } ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); if (anDof) { for (d = off; d < off+dof; ++d) { ierr = PetscSectionAddDof(rootSectionAdj, d, anDof);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr); ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Create adj SF based on dof SF */ ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr); ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr); } ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr); /* Create leaf adjacency */ ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr); ierr = PetscCalloc1(adjSize, &adj);CHKERRQ(ierr); for (l = 0; l < nleaves; ++l) { PetscInt dof, off, d, q, anDof, anOff; PetscInt p = leaves[l], numAdj = PETSC_DETERMINE; if ((p < pStart) || (p >= pEnd)) continue; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(anchorSectionAdj, p, &anOff);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { PetscInt aoff, i = 0; ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, ngoff, nd; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); for (nd = 0; nd < ndof-ncdof; ++nd) { adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd; ++i; } } for (q = 0; q < anDof; q++) { adj[aoff+i] = anchorAdj[anOff+q]; ++i; } } } /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Gather adjacent indices to root */ ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr); ierr = PetscMalloc1(adjSize, &rootAdj);CHKERRQ(ierr); for (r = 0; r < adjSize; ++r) rootAdj[r] = -1; if (doComm) { const PetscInt *indegree; PetscInt *remoteadj, radjsize = 0; ierr = PetscSFComputeDegreeBegin(sfAdj, &indegree);CHKERRQ(ierr); ierr = PetscSFComputeDegreeEnd(sfAdj, &indegree);CHKERRQ(ierr); for (p = 0; p < adjSize; ++p) radjsize += indegree[p]; ierr = PetscMalloc1(radjsize, &remoteadj);CHKERRQ(ierr); ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, remoteadj);CHKERRQ(ierr); ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, remoteadj);CHKERRQ(ierr); for (p = 0, l = 0, r = 0; p < adjSize; ++p, l = PetscMax(p, l + indegree[p-1])) { PetscInt s; for (s = 0; s < indegree[p]; ++s, ++r) rootAdj[l+s] = remoteadj[r]; } if (r != radjsize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistency in communication %d != %d", r, radjsize); if (l != adjSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Inconsistency in communication %d != %d", l, adjSize); ierr = PetscFree(remoteadj);CHKERRQ(ierr); } ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr); ierr = PetscFree(adj);CHKERRQ(ierr); /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Add in local adjacency indices for owned dofs on interface (roots) */ for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, adof, dof, off, d, q, anDof, anOff; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); if (!dof) continue; ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); if (adof <= 0) continue; ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(anchorSectionAdj, p, &anOff);CHKERRQ(ierr); for (d = off; d < off+dof; ++d) { PetscInt adof, aoff, i; ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr); i = adof-1; for (q = 0; q < anDof; q++) { rootAdj[aoff+i] = anchorAdj[anOff+q]; --i; } for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, ngoff, nd; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); for (nd = 0; nd < ndof-ncdof; ++nd) { rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd; --i; } } } } /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Compress indices */ ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt dof, cdof, off, d; PetscInt adof, aoff; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); if (!dof) continue; ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr); if (adof <= 0) continue; for (d = off; d < off+dof-cdof; ++d) { ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr); ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr); ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr); } } /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr); ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Build adjacency section: Maps global indices to sets of adjacent global indices */ ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr); ierr = PetscSectionCreate(comm, §ionAdj);CHKERRQ(ierr); ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof; PetscBool found = PETSC_TRUE; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); for (d = 0; d < dof-cdof; ++d) { PetscInt ldof, rdof; ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr); ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr); if (ldof > 0) { /* We do not own this point */ } else if (rdof > 0) { ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr); } else { found = PETSC_FALSE; } } if (found) continue; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, noff; if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, padj, &noff);CHKERRQ(ierr); for (d = goff; d < goff+dof-cdof; ++d) { ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr); } } ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); if (anDof) { for (d = goff; d < goff+dof-cdof; ++d) { ierr = PetscSectionAddDof(sectionAdj, d, anDof);CHKERRQ(ierr); } } } ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr); if (debug) { ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr); ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); } /* Get adjacent indices */ ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr); ierr = PetscMalloc1(numCols, &cols);CHKERRQ(ierr); for (p = pStart; p < pEnd; ++p) { PetscInt numAdj = PETSC_DETERMINE, dof, cdof, off, goff, d, q, anDof, anOff; PetscBool found = PETSC_TRUE; ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr); for (d = 0; d < dof-cdof; ++d) { PetscInt ldof, rdof; ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr); ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr); if (ldof > 0) { /* We do not own this point */ } else if (rdof > 0) { PetscInt aoff, roff; ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr); ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr); ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr); } else { found = PETSC_FALSE; } } if (found) continue; ierr = DMPlexGetAdjacency(dm, p, &numAdj, &tmpAdj);CHKERRQ(ierr); ierr = PetscSectionGetDof(anchorSectionAdj, p, &anDof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(anchorSectionAdj, p, &anOff);CHKERRQ(ierr); for (d = goff; d < goff+dof-cdof; ++d) { PetscInt adof, aoff, i = 0; ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr); for (q = 0; q < numAdj; ++q) { const PetscInt padj = tmpAdj[q]; PetscInt ndof, ncdof, ngoff, nd; const PetscInt *ncind; /* Adjacent points may not be in the section chart */ if ((padj < pStart) || (padj >= pEnd)) continue; ierr = PetscSectionGetDof(section, padj, &ndof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintDof(section, padj, &ncdof);CHKERRQ(ierr); ierr = PetscSectionGetConstraintIndices(section, padj, &ncind);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionGlobal, padj, &ngoff);CHKERRQ(ierr); for (nd = 0; nd < ndof-ncdof; ++nd, ++i) { cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd; } } for (q = 0; q < anDof; q++, i++) { cols[aoff+i] = anchorAdj[anOff + q]; } 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); } } ierr = PetscSectionDestroy(&anchorSectionAdj);CHKERRQ(ierr); ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr); ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr); ierr = PetscFree(anchorAdj);CHKERRQ(ierr); ierr = PetscFree(rootAdj);CHKERRQ(ierr); ierr = PetscFree(tmpAdj);CHKERRQ(ierr); /* Debugging */ if (debug) { IS tmp; ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr); ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr); ierr = ISView(tmp, NULL);CHKERRQ(ierr); ierr = ISDestroy(&tmp);CHKERRQ(ierr); } /* Create allocation vectors from adjacency graph */ ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr); ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr); ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); /* Only loop over blocks of rows */ 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); for (r = rStart/bs; r < rEnd/bs; ++r) { const PetscInt row = r*bs; PetscInt numCols, cStart, c; ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr); for (c = cStart; c < cStart+numCols; ++c) { if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) { ++dnz[r-rStart]; if (cols[c] >= row) ++dnzu[r-rStart]; } else { ++onz[r-rStart]; if (cols[c] >= row) ++onzu[r-rStart]; } } } if (bs > 1) { for (r = 0; r < locRows/bs; ++r) { dnz[r] /= bs; onz[r] /= bs; dnzu[r] /= bs; onzu[r] /= bs; } } /* Set matrix pattern */ ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr); ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); /* Check for symmetric storage */ ierr = MatGetType(A, &mtype);CHKERRQ(ierr); ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); if (isSymBlock || isSymSeqBlock || isSymMPIBlock) {ierr = MatSetOption(A, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);} /* Fill matrix with zeros */ if (fillMatrix) { PetscScalar *values; PetscInt maxRowLen = 0; for (r = rStart; r < rEnd; ++r) { PetscInt len; ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr); maxRowLen = PetscMax(maxRowLen, len); } ierr = PetscCalloc1(maxRowLen, &values);CHKERRQ(ierr); for (r = rStart; r < rEnd; ++r) { PetscInt numCols, cStart; ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr); ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr); ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr); } ierr = PetscFree(values);CHKERRQ(ierr); ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); } /* restore original useAnchors */ ierr = DMPlexSetAdjacencyUseAnchors(dm,useAnchors);CHKERRQ(ierr); ierr = PetscSectionDestroy(§ionAdj);CHKERRQ(ierr); ierr = PetscFree(cols);CHKERRQ(ierr); ierr = PetscLogEventEnd(DMPLEX_Preallocate,dm,0,0,0);CHKERRQ(ierr); PetscFunctionReturn(0); }