/*@ PCMGSetCycleType - Sets the type cycles to use. Use PCMGSetCycleTypeOnLevel() for more complicated cycling. Logically Collective on PC Input Parameters: + pc - the multigrid context - PC_MG_CYCLE_V or PC_MG_CYCLE_W Options Database Key: $ -pc_mg_cycle_type v or w Level: advanced .keywords: MG, set, cycles, V-cycle, W-cycle, multigrid .seealso: PCMGSetCycleTypeOnLevel() @*/ PetscErrorCode PCMGSetCycleType(PC pc,PCMGCycleType n) { PC_MG *mg = (PC_MG*)pc->data; PC_MG_Levels **mglevels = mg->levels; PetscInt i,levels; PetscFunctionBegin; PetscValidHeaderSpecific(pc,PC_CLASSID,1); if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); PetscValidLogicalCollectiveInt(pc,n,2); levels = mglevels[0]->levels; for (i=0; i<levels; i++) mglevels[i]->cycles = n; PetscFunctionReturn(0); }
/*@ EPSSetDimensions - Sets the number of eigenvalues to compute and the dimension of the subspace. Logically Collective on EPS Input Parameters: + eps - the eigensolver context . nev - number of eigenvalues to compute . ncv - the maximum dimension of the subspace to be used by the solver - mpd - the maximum dimension allowed for the projected problem Options Database Keys: + -eps_nev <nev> - Sets the number of eigenvalues . -eps_ncv <ncv> - Sets the dimension of the subspace - -eps_mpd <mpd> - Sets the maximum projected dimension Notes: Use PETSC_DEFAULT for ncv and mpd to assign a reasonably good value, which is dependent on the solution method. The parameters ncv and mpd are intimately related, so that the user is advised to set one of them at most. Normal usage is that (a) in cases where nev is small, the user sets ncv (a reasonable default is 2*nev); and (b) in cases where nev is large, the user sets mpd. The value of ncv should always be between nev and (nev+mpd), typically ncv=nev+mpd. If nev is not too large, mpd=nev is a reasonable choice, otherwise a smaller value should be used. When computing all eigenvalues in an interval, see EPSSetInterval(), these parameters lose relevance, and tuning must be done with EPSKrylovSchurSetDimensions(). Level: intermediate .seealso: EPSGetDimensions(), EPSSetInterval(), EPSKrylovSchurSetDimensions() @*/ PetscErrorCode EPSSetDimensions(EPS eps,PetscInt nev,PetscInt ncv,PetscInt mpd) { PetscFunctionBegin; PetscValidHeaderSpecific(eps,EPS_CLASSID,1); PetscValidLogicalCollectiveInt(eps,nev,2); PetscValidLogicalCollectiveInt(eps,ncv,3); PetscValidLogicalCollectiveInt(eps,mpd,4); if (nev<1) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of nev. Must be > 0"); eps->nev = nev; if (ncv == PETSC_DECIDE || ncv == PETSC_DEFAULT) { eps->ncv = 0; } else { if (ncv<1) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of ncv. Must be > 0"); eps->ncv = ncv; } if (mpd == PETSC_DECIDE || mpd == PETSC_DEFAULT) { eps->mpd = 0; } else { if (mpd<1) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of mpd. Must be > 0"); eps->mpd = mpd; } eps->state = EPS_STATE_INITIAL; PetscFunctionReturn(0); }
/*@ SVDComputeResidualNorms - Computes the norms of the residual vectors associated with the i-th computed singular triplet. Collective on SVD Input Parameters: + svd - the singular value solver context - i - the solution index Output Parameters: + norm1 - the norm ||A*v-sigma*u||_2 where sigma is the singular value, u and v are the left and right singular vectors. - norm2 - the norm ||A^T*u-sigma*v||_2 with the same sigma, u and v Note: The index i should be a value between 0 and nconv-1 (see SVDGetConverged()). Both output parameters can be NULL on input if not needed. Level: beginner .seealso: SVDSolve(), SVDGetConverged(), SVDComputeRelativeError() @*/ PetscErrorCode SVDComputeResidualNorms(SVD svd,PetscInt i,PetscReal *norm1,PetscReal *norm2) { PetscErrorCode ierr; Vec u,v,x = NULL,y = NULL; PetscReal sigma; PetscInt M,N; PetscFunctionBegin; PetscValidHeaderSpecific(svd,SVD_CLASSID,1); PetscValidLogicalCollectiveInt(svd,i,2); if (svd->reason == SVD_CONVERGED_ITERATING) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_WRONGSTATE,"SVDSolve must be called first"); if (i<0 || i>=svd->nconv) SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range"); ierr = MatGetVecs(svd->OP,&v,&u);CHKERRQ(ierr); ierr = SVDGetSingularTriplet(svd,i,&sigma,u,v);CHKERRQ(ierr); if (norm1) { ierr = VecDuplicate(u,&x);CHKERRQ(ierr); ierr = MatMult(svd->OP,v,x);CHKERRQ(ierr); ierr = VecAXPY(x,-sigma,u);CHKERRQ(ierr); ierr = VecNorm(x,NORM_2,norm1);CHKERRQ(ierr); } if (norm2) { ierr = VecDuplicate(v,&y);CHKERRQ(ierr); if (svd->A && svd->AT) { ierr = MatGetSize(svd->OP,&M,&N);CHKERRQ(ierr); if (M<N) { ierr = MatMult(svd->A,u,y);CHKERRQ(ierr); } else { ierr = MatMult(svd->AT,u,y);CHKERRQ(ierr); } } else { #if defined(PETSC_USE_COMPLEX) ierr = MatMultHermitianTranspose(svd->OP,u,y);CHKERRQ(ierr); #else ierr = MatMultTranspose(svd->OP,u,y);CHKERRQ(ierr); #endif } ierr = VecAXPY(y,-sigma,v);CHKERRQ(ierr); ierr = VecNorm(y,NORM_2,norm2);CHKERRQ(ierr); } ierr = VecDestroy(&v);CHKERRQ(ierr); ierr = VecDestroy(&u);CHKERRQ(ierr); ierr = VecDestroy(&x);CHKERRQ(ierr); ierr = VecDestroy(&y);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ PEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by PEPSolve(). The solution consists in both the eigenvalue and the eigenvector. Logically Collective on EPS Input Parameters: + pep - polynomial eigensolver context - i - index of the solution Output Parameters: + eigr - real part of eigenvalue . eigi - imaginary part of eigenvalue . Vr - real part of eigenvector - Vi - imaginary part of eigenvector Notes: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is configured with complex scalars the eigenvalue is stored directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is set to zero). The index i should be a value between 0 and nconv-1 (see PEPGetConverged()). Eigenpairs are indexed according to the ordering criterion established with PEPSetWhichEigenpairs(). Level: beginner .seealso: PEPSolve(), PEPGetConverged(), PEPSetWhichEigenpairs() @*/ PetscErrorCode PEPGetEigenpair(PEP pep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi) { PetscInt k; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(pep,PEP_CLASSID,1); PetscValidLogicalCollectiveInt(pep,i,2); if (Vr) { PetscValidHeaderSpecific(Vr,VEC_CLASSID,5); PetscCheckSameComm(pep,1,Vr,5); } if (Vi) { PetscValidHeaderSpecific(Vi,VEC_CLASSID,6); PetscCheckSameComm(pep,1,Vi,6); } PEPCheckSolved(pep,1); if (i<0 || i>=pep->nconv) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range"); ierr = PEPComputeVectors(pep);CHKERRQ(ierr); if (!pep->perm) k = i; else k = pep->perm[i]; /* eigenvalue */ #if defined(PETSC_USE_COMPLEX) if (eigr) *eigr = pep->eigr[k]; if (eigi) *eigi = 0; #else if (eigr) *eigr = pep->eigr[k]; if (eigi) *eigi = pep->eigi[k]; #endif /* eigenvector */ #if defined(PETSC_USE_COMPLEX) if (Vr) { ierr = BVCopyVec(pep->V,k,Vr);CHKERRQ(ierr); } if (Vi) { ierr = VecSet(Vi,0.0);CHKERRQ(ierr); } #else if (pep->eigi[k]>0) { /* first value of conjugate pair */ if (Vr) { ierr = BVCopyVec(pep->V,k,Vr);CHKERRQ(ierr); } if (Vi) { ierr = BVCopyVec(pep->V,k+1,Vi);CHKERRQ(ierr); } } else if (pep->eigi[k]<0) { /* second value of conjugate pair */ if (Vr) { ierr = BVCopyVec(pep->V,k-1,Vr);CHKERRQ(ierr); } if (Vi) { ierr = BVCopyVec(pep->V,k,Vi);CHKERRQ(ierr); ierr = VecScale(Vi,-1.0);CHKERRQ(ierr); } } else { /* real eigenvalue */ if (Vr) { ierr = BVCopyVec(pep->V,k,Vr);CHKERRQ(ierr); } if (Vi) { ierr = VecSet(Vi,0.0);CHKERRQ(ierr); } } #endif PetscFunctionReturn(0); }
/*@C PetscViewerDrawBaseSet - sets the base integer that is added to the windownumber passed to PetscViewerDrawGetDraw() Logically Collective on PetscViewer Input Parameters: + viewer - the PetscViewer (created with PetscViewerDrawOpen()) - windownumber - value to set the base Level: developer Concepts: drawing^accessing PetscDraw context from PetscViewer Concepts: graphics .seealso: PetscViewerDrawGetLG(), PetscViewerDrawGetAxis(), PetscViewerDrawOpen(), PetscViewerDrawGetDraw(), PetscViewerDrawBaseAdd() @*/ PetscErrorCode PetscViewerDrawBaseSet(PetscViewer viewer,PetscInt windownumber) { PetscViewer_Draw *vdraw; PetscErrorCode ierr; PetscBool isdraw; PetscFunctionBegin; PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1); PetscValidLogicalCollectiveInt(viewer,windownumber,2); ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); if (!isdraw) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Must be draw type PetscViewer"); vdraw = (PetscViewer_Draw*)viewer->data; if (windownumber < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Resulting base %D cannot be negative",windownumber); vdraw->draw_base = windownumber; PetscFunctionReturn(0); }
/*@C PetscDrawHGCreate - Creates a histogram data structure. Collective over PetscDraw Input Parameters: + draw - The window where the graph will be made - bins - The number of bins to use Output Parameters: . hist - The histogram context Level: intermediate Concepts: histogram^creating .seealso: PetscDrawHGDestroy() @*/ PetscErrorCode PetscDrawHGCreate(PetscDraw draw, int bins, PetscDrawHG *hist) { PetscBool isnull; PetscDrawHG h; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID,1); PetscValidLogicalCollectiveInt(draw,bins,2); PetscValidPointer(hist,3); ierr = PetscDrawIsNull(draw,&isnull);CHKERRQ(ierr); if (isnull) {*hist = NULL; PetscFunctionReturn(0);} ierr = PetscHeaderCreate(h, PETSC_DRAWHG_CLASSID, "PetscDrawHG", "Histogram", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawHGDestroy, NULL);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)draw,(PetscObject)h);CHKERRQ(ierr); ierr = PetscObjectReference((PetscObject)draw);CHKERRQ(ierr); h->win = draw; h->view = NULL; h->destroy = NULL; h->color = PETSC_DRAW_GREEN; h->xmin = PETSC_MAX_REAL; h->xmax = PETSC_MIN_REAL; h->ymin = 0.; h->ymax = 1.; h->numBins = bins; h->maxBins = bins; ierr = PetscMalloc1(h->maxBins,&h->bins);CHKERRQ(ierr); h->numValues = 0; h->maxValues = CHUNKSIZE; h->calcStats = PETSC_FALSE; h->integerBins = PETSC_FALSE; ierr = PetscMalloc1(h->maxValues,&h->values);CHKERRQ(ierr); ierr = PetscLogObjectMemory((PetscObject)h,(h->maxBins + h->maxValues)*sizeof(PetscReal));CHKERRQ(ierr); ierr = PetscDrawAxisCreate(draw,&h->axis);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)h,(PetscObject)h->axis);CHKERRQ(ierr); *hist = h; PetscFunctionReturn(0); }
/*@ MatMFFDSetHHistory - Sets an array to collect a history of the differencing values (h) computed for the matrix-free product. Logically Collective on Mat Input Parameters: + J - the matrix-free matrix context . histroy - space to hold the history - nhistory - number of entries in history, if more entries are generated than nhistory, then the later ones are discarded Level: advanced Notes: Use MatMFFDResetHHistory() to reset the history counter and collect a new batch of differencing parameters, h. .keywords: SNES, matrix-free, h history, differencing history .seealso: MatMFFDGetH(), MatCreateSNESMF(), MatMFFDResetHHistory(), MatMFFDSetFunctionError() @*/ PetscErrorCode MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory) { MatMFFD ctx = (MatMFFD)J->data; PetscErrorCode ierr; PetscBool match; PetscFunctionBegin; PetscValidHeaderSpecific(J,MAT_CLASSID,1); if (history) PetscValidPointer(history,2); PetscValidLogicalCollectiveInt(J,nhistory,3); ierr = PetscObjectTypeCompare((PetscObject)J,MATMFFD,&match);CHKERRQ(ierr); if (!match) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_WRONG,"Not a MFFD matrix"); ctx->historyh = history; ctx->maxcurrenth = nhistory; ctx->currenth = 0.; PetscFunctionReturn(0); }
/*@ PetscDrawHGSetNumberBins - Change the number of bins that are to be drawn. Not Collective (ignored except on processor 0 of PetscDrawHG) Input Parameter: + hist - The histogram context. - bins - The number of bins. Level: intermediate Concepts: histogram^setting number of bins @*/ PetscErrorCode PetscDrawHGSetNumberBins(PetscDrawHG hist, int bins) { PetscErrorCode ierr; PetscFunctionBegin; if (!hist) PetscFunctionReturn(0); PetscValidHeaderSpecific(hist,PETSC_DRAWHG_CLASSID,1); PetscValidLogicalCollectiveInt(hist,bins,2); if (hist->maxBins < bins) { ierr = PetscFree(hist->bins);CHKERRQ(ierr); ierr = PetscMalloc1(bins, &hist->bins);CHKERRQ(ierr); ierr = PetscLogObjectMemory((PetscObject)hist, (bins - hist->maxBins) * sizeof(PetscReal));CHKERRQ(ierr); hist->maxBins = bins; } hist->numBins = bins; PetscFunctionReturn(0); }
/*@ PEPComputeRelativeError - Computes the relative error bound associated with the i-th computed eigenpair. Collective on PEP Input Parameter: + pep - the polynomial eigensolver context - i - the solution index Output Parameter: . error - the relative error bound, computed as ||P(l)x||_2/||lx||_2 where l is the eigenvalue and x is the eigenvector. Level: beginner .seealso: PEPSolve(), PEPComputeResidualNorm(), PEPGetErrorEstimate() @*/ PetscErrorCode PEPComputeRelativeError(PEP pep,PetscInt i,PetscReal *error) { PetscErrorCode ierr; Vec xr,xi; PetscScalar kr,ki; PetscFunctionBegin; PetscValidHeaderSpecific(pep,PEP_CLASSID,1); PetscValidLogicalCollectiveInt(pep,i,2); PetscValidPointer(error,3); PEPCheckSolved(pep,1); ierr = BVGetVec(pep->V,&xr);CHKERRQ(ierr); ierr = BVGetVec(pep->V,&xi);CHKERRQ(ierr); ierr = PEPGetEigenpair(pep,i,&kr,&ki,xr,xi);CHKERRQ(ierr); ierr = PEPComputeRelativeError_Private(pep,kr,ki,xr,xi,error);CHKERRQ(ierr); ierr = VecDestroy(&xr);CHKERRQ(ierr); ierr = VecDestroy(&xi);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ EPSComputeRelativeError - Computes the relative error bound associated with the i-th computed eigenpair. Collective on EPS Input Parameter: + eps - the eigensolver context - i - the solution index Output Parameter: . error - the relative error bound, computed as ||Ax-kBx||_2/||kx||_2 where k is the eigenvalue and x is the eigenvector. If k=0 the relative error is computed as ||Ax||_2/||x||_2. Level: beginner .seealso: EPSSolve(), EPSComputeResidualNorm(), EPSGetErrorEstimate() @*/ PetscErrorCode EPSComputeRelativeError(EPS eps,PetscInt i,PetscReal *error) { PetscErrorCode ierr; Vec xr,xi; PetscScalar kr,ki; PetscFunctionBegin; PetscValidHeaderSpecific(eps,EPS_CLASSID,1); PetscValidLogicalCollectiveInt(eps,i,2); PetscValidPointer(error,3); EPSCheckSolved(eps,1); ierr = BVGetVec(eps->V,&xr);CHKERRQ(ierr); ierr = BVGetVec(eps->V,&xi);CHKERRQ(ierr); ierr = EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);CHKERRQ(ierr); ierr = EPSComputeRelativeError_Private(eps,kr,ki,xr,xi,error);CHKERRQ(ierr); ierr = VecDestroy(&xr);CHKERRQ(ierr); ierr = VecDestroy(&xi);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ BVScaleColumn - Scale one column of a BV. Logically Collective on BV Input Parameters: + bv - basis vectors . j - column number to be scaled - alpha - scaling factor Level: intermediate .seealso: BVScale(), BVSetActiveColumns() @*/ PetscErrorCode BVScaleColumn(BV bv,PetscInt j,PetscScalar alpha) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(bv,BV_CLASSID,1); PetscValidLogicalCollectiveInt(bv,j,2); PetscValidLogicalCollectiveScalar(bv,alpha,3); PetscValidType(bv,1); BVCheckSizes(bv,1); if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m); if (!bv->n || alpha == (PetscScalar)1.0) PetscFunctionReturn(0); ierr = PetscLogEventBegin(BV_Scale,bv,0,0,0);CHKERRQ(ierr); ierr = (*bv->ops->scale)(bv,j,alpha);CHKERRQ(ierr); ierr = PetscLogEventEnd(BV_Scale,bv,0,0,0);CHKERRQ(ierr); ierr = PetscObjectStateIncrease((PetscObject)bv);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ KSPBCGSLSetEll - Sets the number of search directions in BiCGStab(L). Logically Collective on KSP Input Parameters: + ksp - iterative context obtained from KSPCreate - ell - number of search directions Options Database Keys: . -ksp_bcgsl_ell ell Level: intermediate Notes: For large ell it is common for the polynomial update problem to become singular (due to happy breakdown for smallish test problems, but also for larger problems). Consequently, by default, the system is solved by pseudoinverse, which allows the iteration to complete successfully. See KSPBCGSLSetUsePseudoinverse() to switch to a conventional solve. .keywords: KSP, BiCGStab(L), set, exact residuals, .seealso: KSPBCGSLSetUsePseudoinverse() @*/ PetscErrorCode KSPBCGSLSetEll(KSP ksp, PetscInt ell) { KSP_BCGSL *bcgsl = (KSP_BCGSL*)ksp->data; PetscErrorCode ierr; PetscFunctionBegin; if (ell < 1) SETERRQ(PetscObjectComm((PetscObject)ksp),PETSC_ERR_ARG_OUTOFRANGE, "KSPBCGSLSetEll: second argument must be positive"); PetscValidLogicalCollectiveInt(ksp,ell,2); if (!ksp->setupstage) bcgsl->ell = ell; else if (bcgsl->ell != ell) { /* free the data structures, then create them again */ ierr = VecDestroyVecs(ksp->nwork,&ksp->work);CHKERRQ(ierr); ierr = PetscFree5(AY0c,AYlc,AYtc,MZa,MZb);CHKERRQ(ierr); ierr = PetscFree4(bcgsl->work,bcgsl->s,bcgsl->u,bcgsl->v);CHKERRQ(ierr); bcgsl->ell = ell; ksp->setupstage = KSP_SETUP_NEW; } PetscFunctionReturn(0); }
/*@ EPSSetTolerances - Sets the tolerance and maximum iteration count used by the EPS convergence tests. Logically Collective on EPS Input Parameters: + eps - the eigensolver context . tol - the convergence tolerance - maxits - maximum number of iterations to use Options Database Keys: + -eps_tol <tol> - Sets the convergence tolerance - -eps_max_it <maxits> - Sets the maximum number of iterations allowed Notes: Use PETSC_DEFAULT for either argument to assign a reasonably good value. Level: intermediate .seealso: EPSGetTolerances() @*/ PetscErrorCode EPSSetTolerances(EPS eps,PetscReal tol,PetscInt maxits) { PetscFunctionBegin; PetscValidHeaderSpecific(eps,EPS_CLASSID,1); PetscValidLogicalCollectiveReal(eps,tol,2); PetscValidLogicalCollectiveInt(eps,maxits,3); if (tol == PETSC_DEFAULT) { eps->tol = PETSC_DEFAULT; eps->state = EPS_STATE_INITIAL; } else { if (tol <= 0.0) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of tol. Must be > 0"); eps->tol = tol; } if (maxits == PETSC_DEFAULT || maxits == PETSC_DECIDE) { eps->max_it = 0; eps->state = EPS_STATE_INITIAL; } else { if (maxits <= 0) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of maxits. Must be > 0"); eps->max_it = maxits; } PetscFunctionReturn(0); }
/*@ MFNSetTolerances - Sets the tolerance and maximum iteration count used by the MFN convergence tests. Logically Collective on MFN Input Parameters: + mfn - the matrix function context . tol - the convergence tolerance - maxits - maximum number of iterations to use Options Database Keys: + -mfn_tol <tol> - Sets the convergence tolerance - -mfn_max_it <maxits> - Sets the maximum number of iterations allowed Notes: Use PETSC_DEFAULT for either argument to assign a reasonably good value. Level: intermediate .seealso: MFNGetTolerances() @*/ PetscErrorCode MFNSetTolerances(MFN mfn,PetscReal tol,PetscInt maxits) { PetscFunctionBegin; PetscValidHeaderSpecific(mfn,MFN_CLASSID,1); PetscValidLogicalCollectiveReal(mfn,tol,2); PetscValidLogicalCollectiveInt(mfn,maxits,3); if (tol == PETSC_DEFAULT) { mfn->tol = PETSC_DEFAULT; mfn->setupcalled = 0; } else { if (tol <= 0.0) SETERRQ(PetscObjectComm((PetscObject)mfn),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of tol. Must be > 0"); mfn->tol = tol; } if (maxits == PETSC_DEFAULT || maxits == PETSC_DECIDE) { mfn->max_it = 0; mfn->setupcalled = 0; } else { if (maxits <= 0) SETERRQ(PetscObjectComm((PetscObject)mfn),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of maxits. Must be > 0"); mfn->max_it = maxits; } PetscFunctionReturn(0); }
/*@ PetscDrawLGCreate - Creates a line graph data structure. Collective on PetscDraw Input Parameters: + draw - the window where the graph will be made. - dim - the number of curves which will be drawn Output Parameters: . outlg - the line graph context Level: intermediate Notes: The MPI communicator that owns the PetscDraw owns this PetscDrawLG, but the calls to set options and add points are ignored on all processes except the zeroth MPI process in the communicator. All MPI processes in the communicator must call PetscDrawLGDraw() to display the updated graph. Concepts: line graph^creating .seealso: PetscDrawLGDestroy(), PetscDrawLGAddPoint(), PetscDrawLGAddCommonPoint(), PetscDrawLGAddPoints(), PetscDrawLGDraw(), PetscDrawLGSave(), PetscDrawLGView(), PetscDrawLGReset(), PetscDrawLGSetDimension(), PetscDrawLGGetDimension(), PetscDrawLGSetLegend(), PetscDrawLGGetAxis(), PetscDrawLGGetDraw(), PetscDrawLGSetUseMarkers(), PetscDrawLGSetLimits(), PetscDrawLGSetColors(), PetscDrawLGSetOptionsPrefix(), PetscDrawLGSetFromOptions() @*/ PetscErrorCode PetscDrawLGCreate(PetscDraw draw,PetscInt dim,PetscDrawLG *outlg) { PetscDrawLG lg; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1); PetscValidLogicalCollectiveInt(draw,dim,2); PetscValidPointer(outlg,3); ierr = PetscHeaderCreate(lg,PETSC_DRAWLG_CLASSID,"DrawLG","Line Graph","Draw",PetscObjectComm((PetscObject)draw),PetscDrawLGDestroy,NULL);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)draw,(PetscObject)lg);CHKERRQ(ierr); ierr = PetscDrawLGSetOptionsPrefix(lg,((PetscObject)draw)->prefix);CHKERRQ(ierr); ierr = PetscObjectReference((PetscObject)draw);CHKERRQ(ierr); lg->win = draw; lg->view = NULL; lg->destroy = NULL; lg->nopts = 0; lg->dim = dim; lg->xmin = 1.e20; lg->ymin = 1.e20; lg->xmax = -1.e20; lg->ymax = -1.e20; ierr = PetscMalloc2(dim*CHUNCKSIZE,&lg->x,dim*CHUNCKSIZE,&lg->y);CHKERRQ(ierr); ierr = PetscLogObjectMemory((PetscObject)lg,2*dim*CHUNCKSIZE*sizeof(PetscReal));CHKERRQ(ierr); lg->len = dim*CHUNCKSIZE; lg->loc = 0; lg->use_markers = PETSC_FALSE; ierr = PetscDrawAxisCreate(draw,&lg->axis);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)lg,(PetscObject)lg->axis);CHKERRQ(ierr); *outlg = lg; PetscFunctionReturn(0); }
/*@ PCMGSetNumberSmoothUp - Sets the number of post-smoothing steps to use on all levels. Use PCMGGetSmootherUp() to set different numbers of post-smoothing steps on different levels. Logically Collective on PC Input Parameters: + mg - the multigrid context - n - the number of smoothing steps Options Database Key: . -pc_mg_smoothup <n> - Sets number of post-smoothing steps Level: advanced Note: this does not set a value on the coarsest grid, since we assume that there is no separate smooth up on the coarsest grid. .keywords: MG, smooth, up, post-smoothing, steps, multigrid .seealso: PCMGSetNumberSmoothDown() @*/ PetscErrorCode PCMGSetNumberSmoothUp(PC pc,PetscInt n) { PC_MG *mg = (PC_MG*)pc->data; PC_MG_Levels **mglevels = mg->levels; PetscErrorCode ierr; PetscInt i,levels; PetscFunctionBegin; PetscValidHeaderSpecific(pc,PC_CLASSID,1); if (!mglevels) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must set MG levels before calling"); PetscValidLogicalCollectiveInt(pc,n,2); levels = mglevels[0]->levels; for (i=1; i<levels; i++) { /* make sure smoother up and down are different */ ierr = PCMGGetSmootherUp(pc,i,NULL);CHKERRQ(ierr); ierr = KSPSetTolerances(mglevels[i]->smoothu,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,n);CHKERRQ(ierr); mg->default_smoothu = n; } PetscFunctionReturn(0); }
/*@ EPSGetEigenvector - Gets the i-th right eigenvector as computed by EPSSolve(). Logically Collective on EPS Input Parameters: + eps - eigensolver context - i - index of the solution Output Parameters: + Vr - real part of eigenvector - Vi - imaginary part of eigenvector Notes: If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is configured with complex scalars the eigenvector is stored directly in Vr (Vi is set to zero). The index i should be a value between 0 and nconv-1 (see EPSGetConverged()). Eigenpairs are indexed according to the ordering criterion established with EPSSetWhichEigenpairs(). The 2-norm of the eigenvector is one unless the problem is generalized Hermitian. In this case the eigenvector is normalized with respect to the norm defined by the B matrix. Level: beginner .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair() @*/ PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi) { PetscErrorCode ierr; PetscInt k; PetscFunctionBegin; PetscValidHeaderSpecific(eps,EPS_CLASSID,1); PetscValidLogicalCollectiveInt(eps,i,2); PetscValidHeaderSpecific(Vr,VEC_CLASSID,3); PetscCheckSameComm(eps,1,Vr,3); if (Vi) { PetscValidHeaderSpecific(Vi,VEC_CLASSID,4); PetscCheckSameComm(eps,1,Vi,4); } EPSCheckSolved(eps,1); if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range"); ierr = EPSComputeVectors(eps);CHKERRQ(ierr); if (!eps->perm) k = i; else k = eps->perm[i]; #if defined(PETSC_USE_COMPLEX) ierr = BVCopyVec(eps->V,k,Vr);CHKERRQ(ierr); if (Vi) { ierr = VecSet(Vi,0.0);CHKERRQ(ierr); } #else if (eps->eigi[k] > 0) { /* first value of conjugate pair */ ierr = BVCopyVec(eps->V,k,Vr);CHKERRQ(ierr); if (Vi) { ierr = BVCopyVec(eps->V,k+1,Vi);CHKERRQ(ierr); } } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */ ierr = BVCopyVec(eps->V,k-1,Vr);CHKERRQ(ierr); if (Vi) { ierr = BVCopyVec(eps->V,k,Vi);CHKERRQ(ierr); ierr = VecScale(Vi,-1.0);CHKERRQ(ierr); } } else { /* real eigenvalue */ ierr = BVCopyVec(eps->V,k,Vr);CHKERRQ(ierr); if (Vi) { ierr = VecSet(Vi,0.0);CHKERRQ(ierr); } } #endif PetscFunctionReturn(0); }
/* EPSGetStartVector - Generate a suitable vector to be used as the starting vector for the recurrence that builds the right subspace. Collective on EPS and Vec Input Parameters: + eps - the eigensolver context - i - iteration number Output Parameters: . breakdown - flag indicating that a breakdown has occurred Notes: The start vector is computed from another vector: for the first step (i=0), the first initial vector is used (see EPSSetInitialSpace()); otherwise a random vector is created. Then this vector is forced to be in the range of OP (only for generalized definite problems) and orthonormalized with respect to all V-vectors up to i-1. The resulting vector is placed in V[i]. The flag breakdown is set to true if either i=0 and the vector belongs to the deflation space, or i>0 and the vector is linearly dependent with respect to the V-vectors. */ PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,PetscBool *breakdown) { PetscErrorCode ierr; PetscReal norm; PetscBool lindep; Vec w,z; PetscFunctionBegin; PetscValidHeaderSpecific(eps,EPS_CLASSID,1); PetscValidLogicalCollectiveInt(eps,i,2); /* For the first step, use the first initial vector, otherwise a random one */ if (i>0 || eps->nini==0) { ierr = BVSetRandomColumn(eps->V,i,eps->rand);CHKERRQ(ierr); } ierr = BVGetVec(eps->V,&w);CHKERRQ(ierr); ierr = BVCopyVec(eps->V,i,w);CHKERRQ(ierr); /* Force the vector to be in the range of OP for definite generalized problems */ ierr = BVGetColumn(eps->V,i,&z);CHKERRQ(ierr); if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) { ierr = STApply(eps->st,w,z);CHKERRQ(ierr); } else { ierr = VecCopy(w,z);CHKERRQ(ierr); } ierr = BVRestoreColumn(eps->V,i,&z);CHKERRQ(ierr); ierr = VecDestroy(&w);CHKERRQ(ierr); /* Orthonormalize the vector with respect to previous vectors */ ierr = BVOrthogonalizeColumn(eps->V,i,NULL,&norm,&lindep);CHKERRQ(ierr); if (breakdown) *breakdown = lindep; else if (lindep || norm == 0.0) { if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Initial vector is zero or belongs to the deflation space"); else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more start vectors"); } ierr = BVScaleColumn(eps->V,i,1.0/norm);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ DMPlexCreateBoxMesh - Creates a mesh on the tensor product of unit intervals (box). Collective on MPI_Comm Input Parameters: + comm - The communicator for the DM object . dim - The spatial dimension - interpolate - Flag to create intermediate mesh pieces (edges, faces) Output Parameter: . dm - The DM object Level: beginner .keywords: DM, create .seealso: DMSetType(), DMCreate() @*/ PetscErrorCode DMPlexCreateBoxMesh(MPI_Comm comm, PetscInt dim, PetscBool interpolate, DM *dm) { DM boundary; PetscErrorCode ierr; PetscFunctionBegin; PetscValidPointer(dm, 4); ierr = DMCreate(comm, &boundary);CHKERRQ(ierr); PetscValidLogicalCollectiveInt(boundary,dim,2); ierr = DMSetType(boundary, DMPLEX);CHKERRQ(ierr); ierr = DMPlexSetDimension(boundary, dim-1);CHKERRQ(ierr); switch (dim) { case 2: { PetscReal lower[2] = {0.0, 0.0}; PetscReal upper[2] = {1.0, 1.0}; PetscInt edges[2] = {2, 2}; ierr = DMPlexCreateSquareBoundary(boundary, lower, upper, edges);CHKERRQ(ierr); break; } case 3: { PetscReal lower[3] = {0.0, 0.0, 0.0}; PetscReal upper[3] = {1.0, 1.0, 1.0}; PetscInt faces[3] = {1, 1, 1}; ierr = DMPlexCreateCubeBoundary(boundary, lower, upper, faces);CHKERRQ(ierr); break; } default: SETERRQ1(comm, PETSC_ERR_SUP, "Dimension not supported: %d", dim); } ierr = DMPlexGenerate(boundary, NULL, interpolate, dm);CHKERRQ(ierr); ierr = DMDestroy(&boundary);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ BVSetRandomColumn - Set one column of a BV to random numbers. Logically Collective on BV Input Parameters: + bv - basis vectors . j - column number to be set - rctx - the random number context, formed by PetscRandomCreate(), or NULL and it will create one internally. Note: This operation is analogue to VecSetRandom - the difference is that the generated random vector is the same irrespective of the size of the communicator (if all processes pass a PetscRandom context initialized with the same seed). Level: advanced .seealso: BVSetRandom(), BVSetActiveColumns() @*/ PetscErrorCode BVSetRandomColumn(BV bv,PetscInt j,PetscRandom rctx) { PetscErrorCode ierr; PetscRandom rand=NULL; PetscInt i,low,high; PetscScalar *px,t; Vec x; PetscFunctionBegin; PetscValidHeaderSpecific(bv,BV_CLASSID,1); PetscValidLogicalCollectiveInt(bv,j,2); if (rctx) PetscValidHeaderSpecific(rctx,PETSC_RANDOM_CLASSID,3); else { ierr = PetscRandomCreate(PetscObjectComm((PetscObject)bv),&rand);CHKERRQ(ierr); ierr = PetscRandomSetSeed(rand,0x12345678);CHKERRQ(ierr); ierr = PetscRandomSetFromOptions(rand);CHKERRQ(ierr); rctx = rand; } PetscValidType(bv,1); BVCheckSizes(bv,1); if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m); ierr = PetscLogEventBegin(BV_SetRandom,bv,rctx,0,0);CHKERRQ(ierr); ierr = BVGetColumn(bv,j,&x);CHKERRQ(ierr); ierr = VecGetOwnershipRange(x,&low,&high);CHKERRQ(ierr); ierr = VecGetArray(x,&px);CHKERRQ(ierr); for (i=0;i<bv->N;i++) { ierr = PetscRandomGetValue(rctx,&t);CHKERRQ(ierr); if (i>=low && i<high) px[i-low] = t; } ierr = VecRestoreArray(x,&px);CHKERRQ(ierr); ierr = BVRestoreColumn(bv,j,&x);CHKERRQ(ierr); ierr = PetscLogEventEnd(BV_SetRandom,bv,rctx,0,0);CHKERRQ(ierr); ierr = PetscRandomDestroy(&rand);CHKERRQ(ierr); ierr = PetscObjectStateIncrease((PetscObject)bv);CHKERRQ(ierr); PetscFunctionReturn(0); }
/*@ PetscDrawLGSetDimension - Change the number of lines that are to be drawn. Logically Collective on PetscDrawLG Input Parameter: + lg - the line graph context. - dim - the number of curves. Level: intermediate Concepts: line graph^setting number of lines .seealso: PetscDrawLGCreate(), PetscDrawLGGetDimension() @*/ PetscErrorCode PetscDrawLGSetDimension(PetscDrawLG lg,PetscInt dim) { PetscErrorCode ierr; PetscInt i; PetscFunctionBegin; PetscValidHeaderSpecific(lg,PETSC_DRAWLG_CLASSID,1); PetscValidLogicalCollectiveInt(lg,dim,2); if (lg->dim == dim) PetscFunctionReturn(0); ierr = PetscFree2(lg->x,lg->y);CHKERRQ(ierr); if (lg->legend) { for (i=0; i<lg->dim; i++) { ierr = PetscFree(lg->legend[i]);CHKERRQ(ierr); } ierr = PetscFree(lg->legend);CHKERRQ(ierr); } ierr = PetscFree(lg->colors);CHKERRQ(ierr); lg->dim = dim; ierr = PetscMalloc2(dim*CHUNCKSIZE,&lg->x,dim*CHUNCKSIZE,&lg->y);CHKERRQ(ierr); ierr = PetscLogObjectMemory((PetscObject)lg,2*dim*CHUNCKSIZE*sizeof(PetscReal));CHKERRQ(ierr); lg->len = dim*CHUNCKSIZE; PetscFunctionReturn(0); }
/*@ DMDASetNonOverlappingRegion - Sets the indices of the nonoverlapping region of a subdomain DM. Collective on DA Input Parameter: + da - The DMDA . xs - The start of the region in x . ys - The start of the region in y . zs - The start of the region in z . xs - The size of the region in x . ys - The size of the region in y . zs - The size of the region in z Level: intermediate .keywords: distributed array, degrees of freedom .seealso: DMDAGetOffset(), DMDAVecGetArray() @*/ PetscErrorCode DMDASetNonOverlappingRegion(DM da, PetscInt xs, PetscInt ys, PetscInt zs, PetscInt xm, PetscInt ym, PetscInt zm) { DM_DA *dd = (DM_DA*)da->data; PetscFunctionBegin; PetscValidHeaderSpecific(da,DM_CLASSID,1); PetscValidLogicalCollectiveInt(da,xs,2); PetscValidLogicalCollectiveInt(da,ys,3); PetscValidLogicalCollectiveInt(da,zs,4); PetscValidLogicalCollectiveInt(da,xm,5); PetscValidLogicalCollectiveInt(da,ym,6); PetscValidLogicalCollectiveInt(da,zm,7); dd->nonxs = xs; dd->nonys = ys; dd->nonzs = zs; dd->nonxm = xm; dd->nonym = ym; dd->nonzm = zm; PetscFunctionReturn(0); }
/*@C PCMGSetLevels - Sets the number of levels to use with MG. Must be called before any other MG routine. Logically Collective on PC Input Parameters: + pc - the preconditioner context . levels - the number of levels - comms - optional communicators for each level; this is to allow solving the coarser problems on smaller sets of processors. Use NULL_OBJECT for default in Fortran Level: intermediate Notes: If the number of levels is one then the multigrid uses the -mg_levels prefix for setting the level options rather than the -mg_coarse prefix. .keywords: MG, set, levels, multigrid .seealso: PCMGSetType(), PCMGGetLevels() @*/ PetscErrorCode PCMGSetLevels(PC pc,PetscInt levels,MPI_Comm *comms) { PetscErrorCode ierr; PC_MG *mg = (PC_MG*)pc->data; MPI_Comm comm; PC_MG_Levels **mglevels = mg->levels; PCMGType mgtype = mg->am; PetscInt mgctype = (PetscInt) PC_MG_CYCLE_V; PetscInt i; PetscMPIInt size; const char *prefix; PC ipc; PetscInt n; PetscFunctionBegin; PetscValidHeaderSpecific(pc,PC_CLASSID,1); PetscValidLogicalCollectiveInt(pc,levels,2); ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr); if (mg->nlevels == levels) PetscFunctionReturn(0); if (mglevels) { mgctype = mglevels[0]->cycles; /* changing the number of levels so free up the previous stuff */ ierr = PCReset_MG(pc);CHKERRQ(ierr); n = mglevels[0]->levels; for (i=0; i<n; i++) { if (mglevels[i]->smoothd != mglevels[i]->smoothu) { ierr = KSPDestroy(&mglevels[i]->smoothd);CHKERRQ(ierr); } ierr = KSPDestroy(&mglevels[i]->smoothu);CHKERRQ(ierr); ierr = PetscFree(mglevels[i]);CHKERRQ(ierr); } ierr = PetscFree(mg->levels);CHKERRQ(ierr); } mg->nlevels = levels; ierr = PetscMalloc1(levels,&mglevels);CHKERRQ(ierr); ierr = PetscLogObjectMemory((PetscObject)pc,levels*(sizeof(PC_MG*)));CHKERRQ(ierr); ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); mg->stageApply = 0; for (i=0; i<levels; i++) { ierr = PetscNewLog(pc,&mglevels[i]);CHKERRQ(ierr); mglevels[i]->level = i; mglevels[i]->levels = levels; mglevels[i]->cycles = mgctype; mg->default_smoothu = 2; mg->default_smoothd = 2; mglevels[i]->eventsmoothsetup = 0; mglevels[i]->eventsmoothsolve = 0; mglevels[i]->eventresidual = 0; mglevels[i]->eventinterprestrict = 0; if (comms) comm = comms[i]; ierr = KSPCreate(comm,&mglevels[i]->smoothd);CHKERRQ(ierr); ierr = KSPSetErrorIfNotConverged(mglevels[i]->smoothd,pc->erroriffailure);CHKERRQ(ierr); ierr = PetscObjectIncrementTabLevel((PetscObject)mglevels[i]->smoothd,(PetscObject)pc,levels-i);CHKERRQ(ierr); ierr = KSPSetOptionsPrefix(mglevels[i]->smoothd,prefix);CHKERRQ(ierr); ierr = PetscObjectComposedDataSetInt((PetscObject) mglevels[i]->smoothd, PetscMGLevelId, mglevels[i]->level);CHKERRQ(ierr); if (i || levels == 1) { char tprefix[128]; ierr = KSPSetType(mglevels[i]->smoothd,KSPCHEBYSHEV);CHKERRQ(ierr); ierr = KSPSetConvergenceTest(mglevels[i]->smoothd,KSPConvergedSkip,NULL,NULL);CHKERRQ(ierr); ierr = KSPSetNormType(mglevels[i]->smoothd,KSP_NORM_NONE);CHKERRQ(ierr); ierr = KSPGetPC(mglevels[i]->smoothd,&ipc);CHKERRQ(ierr); ierr = PCSetType(ipc,PCSOR);CHKERRQ(ierr); ierr = KSPSetTolerances(mglevels[i]->smoothd,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, mg->default_smoothd);CHKERRQ(ierr); sprintf(tprefix,"mg_levels_%d_",(int)i); ierr = KSPAppendOptionsPrefix(mglevels[i]->smoothd,tprefix);CHKERRQ(ierr); } else { ierr = KSPAppendOptionsPrefix(mglevels[0]->smoothd,"mg_coarse_");CHKERRQ(ierr); /* coarse solve is (redundant) LU by default; set shifttype NONZERO to avoid annoying zero-pivot in LU preconditioner */ ierr = KSPSetType(mglevels[0]->smoothd,KSPPREONLY);CHKERRQ(ierr); ierr = KSPGetPC(mglevels[0]->smoothd,&ipc);CHKERRQ(ierr); ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); if (size > 1) { ierr = PCSetType(ipc,PCREDUNDANT);CHKERRQ(ierr); } else { ierr = PCSetType(ipc,PCLU);CHKERRQ(ierr); } ierr = PCFactorSetShiftType(ipc,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr); } ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)mglevels[i]->smoothd);CHKERRQ(ierr); mglevels[i]->smoothu = mglevels[i]->smoothd; mg->rtol = 0.0; mg->abstol = 0.0; mg->dtol = 0.0; mg->ttol = 0.0; mg->cyclesperpcapply = 1; } mg->levels = mglevels; ierr = PCMGSetType(pc,mgtype);CHKERRQ(ierr); PetscFunctionReturn(0); }
PetscErrorCode PCBDDCGraphSetUp(PCBDDCGraph graph, PetscInt custom_minimal_size, IS neumann_is, IS dirichlet_is, PetscInt n_ISForDofs, IS ISForDofs[], IS custom_primal_vertices) { IS subset,subset_n; MPI_Comm comm; const PetscInt *is_indices; PetscInt n_neigh,*neigh,*n_shared,**shared,*queue_global; PetscInt i,j,k,s,total_counts,nodes_touched,is_size; PetscMPIInt commsize; PetscBool same_set,mirrors_found; PetscErrorCode ierr; PetscFunctionBegin; PetscValidLogicalCollectiveInt(graph->l2gmap,custom_minimal_size,2); if (neumann_is) { PetscValidHeaderSpecific(neumann_is,IS_CLASSID,3); PetscCheckSameComm(graph->l2gmap,1,neumann_is,3); } graph->has_dirichlet = PETSC_FALSE; if (dirichlet_is) { PetscValidHeaderSpecific(dirichlet_is,IS_CLASSID,4); PetscCheckSameComm(graph->l2gmap,1,dirichlet_is,4); graph->has_dirichlet = PETSC_TRUE; } PetscValidLogicalCollectiveInt(graph->l2gmap,n_ISForDofs,5); for (i=0;i<n_ISForDofs;i++) { PetscValidHeaderSpecific(ISForDofs[i],IS_CLASSID,6); PetscCheckSameComm(graph->l2gmap,1,ISForDofs[i],6); } if (custom_primal_vertices) { PetscValidHeaderSpecific(custom_primal_vertices,IS_CLASSID,6); PetscCheckSameComm(graph->l2gmap,1,custom_primal_vertices,7); } ierr = PetscObjectGetComm((PetscObject)(graph->l2gmap),&comm);CHKERRQ(ierr); ierr = MPI_Comm_size(comm,&commsize);CHKERRQ(ierr); /* custom_minimal_size */ graph->custom_minimal_size = custom_minimal_size; /* get info l2gmap and allocate work vectors */ ierr = ISLocalToGlobalMappingGetInfo(graph->l2gmap,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr); /* check if we have any local periodic nodes (periodic BCs) */ mirrors_found = PETSC_FALSE; if (graph->nvtxs && n_neigh) { for (i=0; i<n_shared[0]; i++) graph->count[shared[0][i]] += 1; for (i=0; i<n_shared[0]; i++) { if (graph->count[shared[0][i]] > 1) { mirrors_found = PETSC_TRUE; break; } } } /* compute local mirrors (if any) */ if (mirrors_found) { IS to,from; PetscInt *local_indices,*global_indices; ierr = ISCreateStride(PETSC_COMM_SELF,graph->nvtxs,0,1,&to);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingApplyIS(graph->l2gmap,to,&from);CHKERRQ(ierr); /* get arrays of local and global indices */ ierr = PetscMalloc1(graph->nvtxs,&local_indices);CHKERRQ(ierr); ierr = ISGetIndices(to,(const PetscInt**)&is_indices);CHKERRQ(ierr); ierr = PetscMemcpy(local_indices,is_indices,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr); ierr = ISRestoreIndices(to,(const PetscInt**)&is_indices);CHKERRQ(ierr); ierr = PetscMalloc1(graph->nvtxs,&global_indices);CHKERRQ(ierr); ierr = ISGetIndices(from,(const PetscInt**)&is_indices);CHKERRQ(ierr); ierr = PetscMemcpy(global_indices,is_indices,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr); ierr = ISRestoreIndices(from,(const PetscInt**)&is_indices);CHKERRQ(ierr); /* allocate space for mirrors */ ierr = PetscMalloc2(graph->nvtxs,&graph->mirrors,graph->nvtxs,&graph->mirrors_set);CHKERRQ(ierr); ierr = PetscMemzero(graph->mirrors,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr); graph->mirrors_set[0] = 0; k=0; for (i=0;i<n_shared[0];i++) { j=shared[0][i]; if (graph->count[j] > 1) { graph->mirrors[j]++; k++; } } /* allocate space for set of mirrors */ ierr = PetscMalloc1(k,&graph->mirrors_set[0]);CHKERRQ(ierr); for (i=1;i<graph->nvtxs;i++) graph->mirrors_set[i]=graph->mirrors_set[i-1]+graph->mirrors[i-1]; /* fill arrays */ ierr = PetscMemzero(graph->mirrors,graph->nvtxs*sizeof(PetscInt));CHKERRQ(ierr); for (j=0;j<n_shared[0];j++) { i=shared[0][j]; if (graph->count[i] > 1) graph->mirrors_set[i][graph->mirrors[i]++]=global_indices[i]; } ierr = PetscSortIntWithArray(graph->nvtxs,global_indices,local_indices);CHKERRQ(ierr); for (i=0;i<graph->nvtxs;i++) { if (graph->mirrors[i] > 0) { ierr = PetscFindInt(graph->mirrors_set[i][0],graph->nvtxs,global_indices,&k);CHKERRQ(ierr); j = global_indices[k]; while ( k > 0 && global_indices[k-1] == j) k--; for (j=0;j<graph->mirrors[i];j++) { graph->mirrors_set[i][j]=local_indices[k+j]; } ierr = PetscSortInt(graph->mirrors[i],graph->mirrors_set[i]);CHKERRQ(ierr); } } ierr = PetscFree(local_indices);CHKERRQ(ierr); ierr = PetscFree(global_indices);CHKERRQ(ierr); ierr = ISDestroy(&to);CHKERRQ(ierr); ierr = ISDestroy(&from);CHKERRQ(ierr); } ierr = PetscMemzero(graph->count,graph->nvtxs*sizeof(*graph->count));CHKERRQ(ierr); /* Count total number of neigh per node */ k = 0; for (i=1;i<n_neigh;i++) { k += n_shared[i]; for (j=0;j<n_shared[i];j++) { graph->count[shared[i][j]] += 1; } } /* Allocate space for storing the set of neighbours for each node */ if (graph->nvtxs) { ierr = PetscMalloc1(k,&graph->neighbours_set[0]);CHKERRQ(ierr); } for (i=1;i<graph->nvtxs;i++) { /* dont count myself */ graph->neighbours_set[i]=graph->neighbours_set[i-1]+graph->count[i-1]; } /* Get information for sharing subdomains */ ierr = PetscMemzero(graph->count,graph->nvtxs*sizeof(*graph->count));CHKERRQ(ierr); for (i=1;i<n_neigh;i++) { /* dont count myself */ s = n_shared[i]; for (j=0;j<s;j++) { k = shared[i][j]; graph->neighbours_set[k][graph->count[k]] = neigh[i]; graph->count[k] += 1; } } /* sort set of sharing subdomains */ for (i=0;i<graph->nvtxs;i++) { ierr = PetscSortRemoveDupsInt(&graph->count[i],graph->neighbours_set[i]);CHKERRQ(ierr); } /* free memory allocated by ISLocalToGlobalMappingGetInfo */ ierr = ISLocalToGlobalMappingRestoreInfo(graph->l2gmap,&n_neigh,&neigh,&n_shared,&shared);CHKERRQ(ierr); /* Get info for dofs splitting User can specify just a subset; an additional field is considered as a complementary field */ for (i=0;i<graph->nvtxs;i++) graph->which_dof[i] = n_ISForDofs; /* by default a dof belongs to the complement set */ for (i=0;i<n_ISForDofs;i++) { ierr = ISGetLocalSize(ISForDofs[i],&is_size);CHKERRQ(ierr); ierr = ISGetIndices(ISForDofs[i],(const PetscInt**)&is_indices);CHKERRQ(ierr); for (j=0;j<is_size;j++) { if (is_indices[j] > -1 && is_indices[j] < graph->nvtxs) { /* out of bounds indices (if any) are skipped */ graph->which_dof[is_indices[j]] = i; } } ierr = ISRestoreIndices(ISForDofs[i],(const PetscInt**)&is_indices);CHKERRQ(ierr); } /* Take into account Neumann nodes */ if (neumann_is) { ierr = ISGetLocalSize(neumann_is,&is_size);CHKERRQ(ierr); ierr = ISGetIndices(neumann_is,(const PetscInt**)&is_indices);CHKERRQ(ierr); for (i=0;i<is_size;i++) { if (is_indices[i] > -1 && is_indices[i] < graph->nvtxs) { /* out of bounds indices (if any) are skipped */ graph->special_dof[is_indices[i]] = PCBDDCGRAPH_NEUMANN_MARK; } } ierr = ISRestoreIndices(neumann_is,(const PetscInt**)&is_indices);CHKERRQ(ierr); } /* Take into account Dirichlet nodes (they overwrite any neumann boundary mark previously set) */ if (dirichlet_is) { ierr = ISGetLocalSize(dirichlet_is,&is_size);CHKERRQ(ierr); ierr = ISGetIndices(dirichlet_is,(const PetscInt**)&is_indices);CHKERRQ(ierr); for (i=0;i<is_size;i++){ if (is_indices[i] > -1 && is_indices[i] < graph->nvtxs) { /* out of bounds indices (if any) are skipped */ if (commsize > graph->commsizelimit) { /* dirichlet nodes treated as internal */ ierr = PetscBTSet(graph->touched,is_indices[i]);CHKERRQ(ierr); graph->subset[is_indices[i]] = 0; } graph->special_dof[is_indices[i]] = PCBDDCGRAPH_DIRICHLET_MARK; } } ierr = ISRestoreIndices(dirichlet_is,(const PetscInt**)&is_indices);CHKERRQ(ierr); } /* mark local periodic nodes (if any) and adapt CSR graph (if any) */ if (graph->mirrors) { for (i=0;i<graph->nvtxs;i++) if (graph->mirrors[i]) graph->special_dof[i] = PCBDDCGRAPH_LOCAL_PERIODIC_MARK; if (graph->xadj) { PetscInt *new_xadj,*new_adjncy; /* sort CSR graph */ for (i=0;i<graph->nvtxs;i++) ierr = PetscSortInt(graph->xadj[i+1]-graph->xadj[i],&graph->adjncy[graph->xadj[i]]);CHKERRQ(ierr); /* adapt local CSR graph in case of local periodicity */ k = 0; for (i=0;i<graph->nvtxs;i++) for (j=graph->xadj[i];j<graph->xadj[i+1];j++) k += graph->mirrors[graph->adjncy[j]]; ierr = PetscMalloc1(graph->nvtxs+1,&new_xadj);CHKERRQ(ierr); ierr = PetscMalloc1(k+graph->xadj[graph->nvtxs],&new_adjncy);CHKERRQ(ierr); new_xadj[0] = 0; for (i=0;i<graph->nvtxs;i++) { k = graph->xadj[i+1]-graph->xadj[i]; ierr = PetscMemcpy(&new_adjncy[new_xadj[i]],&graph->adjncy[graph->xadj[i]],k*sizeof(PetscInt));CHKERRQ(ierr); new_xadj[i+1] = new_xadj[i]+k; for (j=graph->xadj[i];j<graph->xadj[i+1];j++) { k = graph->mirrors[graph->adjncy[j]]; ierr = PetscMemcpy(&new_adjncy[new_xadj[i+1]],graph->mirrors_set[graph->adjncy[j]],k*sizeof(PetscInt));CHKERRQ(ierr); new_xadj[i+1] += k; } k = new_xadj[i+1]-new_xadj[i]; ierr = PetscSortRemoveDupsInt(&k,&new_adjncy[new_xadj[i]]);CHKERRQ(ierr); new_xadj[i+1] = new_xadj[i]+k; } /* set new CSR into graph */ ierr = PetscFree(graph->xadj);CHKERRQ(ierr); ierr = PetscFree(graph->adjncy);CHKERRQ(ierr); graph->xadj = new_xadj; graph->adjncy = new_adjncy; } } /* mark special nodes (if any) -> each will become a single node equivalence class */ if (custom_primal_vertices) { ierr = ISGetLocalSize(custom_primal_vertices,&is_size);CHKERRQ(ierr); ierr = ISGetIndices(custom_primal_vertices,(const PetscInt**)&is_indices);CHKERRQ(ierr); for (i=0,j=0;i<is_size;i++){ if (is_indices[i] > -1 && is_indices[i] < graph->nvtxs && graph->special_dof[is_indices[i]] != PCBDDCGRAPH_DIRICHLET_MARK) { /* out of bounds indices (if any) are skipped */ graph->special_dof[is_indices[i]] = PCBDDCGRAPH_SPECIAL_MARK-j; j++; } } ierr = ISRestoreIndices(custom_primal_vertices,(const PetscInt**)&is_indices);CHKERRQ(ierr); } /* mark interior nodes (if commsize > graph->commsizelimit) as touched and belonging to partition number 0 */ if (commsize > graph->commsizelimit) { for (i=0;i<graph->nvtxs;i++) { if (!graph->count[i]) { ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr); graph->subset[i] = 0; } } } /* init graph structure and compute default subsets */ nodes_touched = 0; for (i=0;i<graph->nvtxs;i++) { if (PetscBTLookup(graph->touched,i)) { nodes_touched++; } } i = 0; graph->ncc = 0; total_counts = 0; /* allocated space for queues */ if (commsize == graph->commsizelimit) { ierr = PetscMalloc2(graph->nvtxs+1,&graph->cptr,graph->nvtxs,&graph->queue);CHKERRQ(ierr); } else { PetscInt nused = graph->nvtxs - nodes_touched; ierr = PetscMalloc2(nused+1,&graph->cptr,nused,&graph->queue);CHKERRQ(ierr); } while (nodes_touched<graph->nvtxs) { /* find first untouched node in local ordering */ while (PetscBTLookup(graph->touched,i)) i++; ierr = PetscBTSet(graph->touched,i);CHKERRQ(ierr); graph->subset[i] = graph->ncc+1; graph->cptr[graph->ncc] = total_counts; graph->queue[total_counts] = i; total_counts++; nodes_touched++; /* now find all other nodes having the same set of sharing subdomains */ for (j=i+1;j<graph->nvtxs;j++) { /* check for same number of sharing subdomains, dof number and same special mark */ if (!PetscBTLookup(graph->touched,j) && graph->count[i] == graph->count[j] && graph->which_dof[i] == graph->which_dof[j] && graph->special_dof[i] == graph->special_dof[j]) { /* check for same set of sharing subdomains */ same_set = PETSC_TRUE; for (k=0;k<graph->count[j];k++){ if (graph->neighbours_set[i][k] != graph->neighbours_set[j][k]) { same_set = PETSC_FALSE; } } /* I found a friend of mine */ if (same_set) { ierr = PetscBTSet(graph->touched,j);CHKERRQ(ierr); graph->subset[j] = graph->ncc+1; nodes_touched++; graph->queue[total_counts] = j; total_counts++; } } } graph->ncc++; } /* set default number of subsets (at this point no info on csr and/or local_subs has been taken into account, so n_subsets = ncc */ graph->n_subsets = graph->ncc; ierr = PetscMalloc1(graph->n_subsets,&graph->subset_ncc);CHKERRQ(ierr); for (i=0;i<graph->n_subsets;i++) { graph->subset_ncc[i] = 1; } /* final pointer */ graph->cptr[graph->ncc] = total_counts; /* For consistency reasons (among neighbours), I need to sort (by global ordering) each connected component */ /* Get a reference node (min index in global ordering) for each subset for tagging messages */ ierr = PetscMalloc1(graph->ncc,&graph->subset_ref_node);CHKERRQ(ierr); ierr = PetscMalloc1(graph->cptr[graph->ncc],&queue_global);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingApply(graph->l2gmap,graph->cptr[graph->ncc],graph->queue,queue_global);CHKERRQ(ierr); for (j=0;j<graph->ncc;j++) { ierr = PetscSortIntWithArray(graph->cptr[j+1]-graph->cptr[j],&queue_global[graph->cptr[j]],&graph->queue[graph->cptr[j]]);CHKERRQ(ierr); graph->subset_ref_node[j] = graph->queue[graph->cptr[j]]; } ierr = PetscFree(queue_global);CHKERRQ(ierr); graph->queue_sorted = PETSC_TRUE; /* save information on subsets (needed when analyzing the connected components) */ if (graph->ncc) { ierr = PetscMalloc2(graph->ncc,&graph->subset_size,graph->ncc,&graph->subset_idxs);CHKERRQ(ierr); ierr = PetscMalloc1(graph->cptr[graph->ncc],&graph->subset_idxs[0]);CHKERRQ(ierr); ierr = PetscMemzero(graph->subset_idxs[0],graph->cptr[graph->ncc]*sizeof(PetscInt));CHKERRQ(ierr); for (j=1;j<graph->ncc;j++) { graph->subset_size[j-1] = graph->cptr[j] - graph->cptr[j-1]; graph->subset_idxs[j] = graph->subset_idxs[j-1] + graph->subset_size[j-1]; } graph->subset_size[graph->ncc-1] = graph->cptr[graph->ncc] - graph->cptr[graph->ncc-1]; ierr = PetscMemcpy(graph->subset_idxs[0],graph->queue,graph->cptr[graph->ncc]*sizeof(PetscInt));CHKERRQ(ierr); } /* renumber reference nodes */ ierr = ISCreateGeneral(PetscObjectComm((PetscObject)(graph->l2gmap)),graph->ncc,graph->subset_ref_node,PETSC_COPY_VALUES,&subset_n);CHKERRQ(ierr); ierr = ISLocalToGlobalMappingApplyIS(graph->l2gmap,subset_n,&subset);CHKERRQ(ierr); ierr = ISDestroy(&subset_n);CHKERRQ(ierr); ierr = ISRenumber(subset,NULL,NULL,&subset_n);CHKERRQ(ierr); ierr = ISDestroy(&subset);CHKERRQ(ierr); ierr = ISGetLocalSize(subset_n,&k);CHKERRQ(ierr); if (k != graph->ncc) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Invalid size of new subset! %D != %D",k,graph->ncc); ierr = ISGetIndices(subset_n,&is_indices);CHKERRQ(ierr); ierr = PetscMemcpy(graph->subset_ref_node,is_indices,graph->ncc*sizeof(PetscInt));CHKERRQ(ierr); ierr = ISRestoreIndices(subset_n,&is_indices);CHKERRQ(ierr); ierr = ISDestroy(&subset_n);CHKERRQ(ierr); /* free workspace */ graph->setupcalled = PETSC_TRUE; PetscFunctionReturn(0); }