/*@C SNESFASSetLevels - Sets the number of levels to use with FAS. Must be called before any other FAS routine. Input Parameters: + snes - the snes 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 -fas_levels prefix for setting the level options rather than the -fas_coarse prefix. .keywords: FAS, MG, set, levels, multigrid .seealso: SNESFASGetLevels() @*/ PetscErrorCode SNESFASSetLevels(SNES snes, PetscInt levels, MPI_Comm * comms) { PetscErrorCode ierr; PetscInt i; const char *optionsprefix; char tprefix[128]; SNES_FAS *fas = (SNES_FAS*)snes->data; SNES prevsnes; MPI_Comm comm; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr); if (levels == fas->levels) { if (!comms) PetscFunctionReturn(0); } /* user has changed the number of levels; reset */ ierr = SNESReset(snes);CHKERRQ(ierr); /* destroy any coarser levels if necessary */ if (fas->next) SNESDestroy(&fas->next);CHKERRQ(ierr); fas->next = NULL; fas->previous = NULL; prevsnes = snes; /* setup the finest level */ ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr); for (i = levels - 1; i >= 0; i--) { if (comms) comm = comms[i]; fas->level = i; fas->levels = levels; fas->fine = snes; fas->next = NULL; if (i > 0) { ierr = SNESCreate(comm, &fas->next);CHKERRQ(ierr); ierr = SNESGetOptionsPrefix(fas->fine, &optionsprefix);CHKERRQ(ierr); sprintf(tprefix,"fas_levels_%d_cycle_",(int)fas->level); ierr = SNESAppendOptionsPrefix(fas->next,optionsprefix);CHKERRQ(ierr); ierr = SNESAppendOptionsPrefix(fas->next,tprefix);CHKERRQ(ierr); ierr = SNESSetType(fas->next, SNESFAS);CHKERRQ(ierr); ierr = SNESSetTolerances(fas->next, fas->next->abstol, fas->next->rtol, fas->next->stol, fas->n_cycles, fas->next->max_funcs);CHKERRQ(ierr); ierr = PetscObjectIncrementTabLevel((PetscObject)fas->next, (PetscObject)snes, levels - i);CHKERRQ(ierr); ((SNES_FAS*)fas->next->data)->previous = prevsnes; prevsnes = fas->next; fas = (SNES_FAS*)prevsnes->data; } } PetscFunctionReturn(0); }
/* Creates the default smoother type. This is SNESNRICHARDSON on each fine level and SNESNEWTONLS on the coarse level. */ PetscErrorCode SNESFASCycleCreateSmoother_Private(SNES snes, SNES *smooth) { SNES_FAS *fas; const char *optionsprefix; char tprefix[128]; PetscErrorCode ierr; SNES nsmooth; PetscFunctionBegin; PetscValidHeaderSpecific(snes,SNES_CLASSID,1); fas = (SNES_FAS*)snes->data; ierr = SNESGetOptionsPrefix(fas->fine, &optionsprefix);CHKERRQ(ierr); /* create the default smoother */ ierr = SNESCreate(PetscObjectComm((PetscObject)snes), &nsmooth);CHKERRQ(ierr); if (fas->level == 0) { sprintf(tprefix,"fas_coarse_"); ierr = SNESAppendOptionsPrefix(nsmooth, optionsprefix);CHKERRQ(ierr); ierr = SNESAppendOptionsPrefix(nsmooth, tprefix);CHKERRQ(ierr); ierr = SNESSetType(nsmooth, SNESNEWTONLS);CHKERRQ(ierr); ierr = SNESSetTolerances(nsmooth, nsmooth->abstol, nsmooth->rtol, nsmooth->stol, nsmooth->max_its, nsmooth->max_funcs);CHKERRQ(ierr); } else { sprintf(tprefix,"fas_levels_%d_",(int)fas->level); ierr = SNESAppendOptionsPrefix(nsmooth, optionsprefix);CHKERRQ(ierr); ierr = SNESAppendOptionsPrefix(nsmooth, tprefix);CHKERRQ(ierr); ierr = SNESSetType(nsmooth, SNESNRICHARDSON);CHKERRQ(ierr); ierr = SNESSetTolerances(nsmooth, 0.0, 0.0, 0.0, fas->max_down_it, nsmooth->max_funcs);CHKERRQ(ierr); } ierr = PetscObjectIncrementTabLevel((PetscObject)nsmooth, (PetscObject)snes, 1);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)snes,(PetscObject)nsmooth);CHKERRQ(ierr); ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes, (PetscObject)nsmooth);CHKERRQ(ierr); *smooth = nsmooth; PetscFunctionReturn(0); }
static PetscErrorCode SNESCompositeAddSNES_Composite(SNES snes,SNESType type) { SNES_Composite *jac; SNES_CompositeLink next,ilink; PetscErrorCode ierr; PetscInt cnt = 0; const char *prefix; char newprefix[20]; DM dm; PetscFunctionBegin; ierr = PetscNewLog(snes,&ilink);CHKERRQ(ierr); ilink->next = 0; ierr = SNESCreate(PetscObjectComm((PetscObject)snes),&ilink->snes);CHKERRQ(ierr); ierr = PetscLogObjectParent((PetscObject)snes,(PetscObject)ilink->snes);CHKERRQ(ierr); ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); ierr = SNESSetDM(ilink->snes,dm);CHKERRQ(ierr); ierr = SNESSetTolerances(ilink->snes,ilink->snes->abstol,ilink->snes->rtol,ilink->snes->stol,1,ilink->snes->max_funcs);CHKERRQ(ierr); ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)snes,(PetscObject)ilink->snes);CHKERRQ(ierr); jac = (SNES_Composite*)snes->data; next = jac->head; if (!next) { jac->head = ilink; ilink->previous = NULL; } else { cnt++; while (next->next) { next = next->next; cnt++; } next->next = ilink; ilink->previous = next; } ierr = SNESGetOptionsPrefix(snes,&prefix);CHKERRQ(ierr); ierr = SNESSetOptionsPrefix(ilink->snes,prefix);CHKERRQ(ierr); sprintf(newprefix,"sub_%d_",(int)cnt); ierr = SNESAppendOptionsPrefix(ilink->snes,newprefix);CHKERRQ(ierr); ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->snes,(PetscObject)snes,1);CHKERRQ(ierr); ierr = SNESSetType(ilink->snes,type);CHKERRQ(ierr); ierr = SNESSetNormSchedule(ilink->snes, SNES_NORM_FINAL_ONLY);CHKERRQ(ierr); ilink->dmp = 1.0; jac->nsnes++; PetscFunctionReturn(0); }
/*@ SNESFASSetContinuation - Sets the FAS cycle to default to exact Newton solves on the upsweep Logically Collective on SNES Input Parameters: + snes - the multigrid context - n - the number of smoothing steps Options Database Key: . -snes_fas_continuation - sets continuation to true Level: advanced Notes: This sets the prefix on the upsweep smoothers to -fas_continuation .keywords: FAS, MG, smoother, continuation .seealso: SNESFAS @*/ PetscErrorCode SNESFASSetContinuation(SNES snes,PetscBool continuation) { const char *optionsprefix; char tprefix[128]; SNES_FAS *fas = (SNES_FAS*)snes->data; PetscErrorCode ierr = 0; PetscFunctionBegin; ierr = SNESGetOptionsPrefix(fas->fine, &optionsprefix);CHKERRQ(ierr); if (!fas->smoothu) { ierr = SNESFASCycleCreateSmoother_Private(snes, &fas->smoothu);CHKERRQ(ierr); } sprintf(tprefix,"fas_levels_continuation_"); ierr = SNESSetOptionsPrefix(fas->smoothu, optionsprefix);CHKERRQ(ierr); ierr = SNESAppendOptionsPrefix(fas->smoothu, tprefix);CHKERRQ(ierr); ierr = SNESSetType(fas->smoothu,SNESNEWTONLS);CHKERRQ(ierr); ierr = SNESSetTolerances(fas->smoothu,fas->fine->abstol,fas->fine->rtol,fas->fine->stol,50,100);CHKERRQ(ierr); fas->continuation = continuation; if (fas->next) { ierr = SNESFASSetContinuation(fas->next,continuation);CHKERRQ(ierr); } PetscFunctionReturn(0); }
PetscErrorCode SNESSetFromOptions_FAS(PetscOptions *PetscOptionsObject,SNES snes) { SNES_FAS *fas = (SNES_FAS*) snes->data; PetscInt levels = 1; PetscBool flg = PETSC_FALSE, upflg = PETSC_FALSE, downflg = PETSC_FALSE, monflg = PETSC_FALSE, galerkinflg = PETSC_FALSE,continuationflg = PETSC_FALSE; PetscErrorCode ierr; char monfilename[PETSC_MAX_PATH_LEN]; SNESFASType fastype; const char *optionsprefix; SNESLineSearch linesearch; PetscInt m, n_up, n_down; SNES next; PetscBool isFine; PetscFunctionBegin; ierr = SNESFASCycleIsFine(snes, &isFine);CHKERRQ(ierr); ierr = PetscOptionsHead(PetscOptionsObject,"SNESFAS Options-----------------------------------");CHKERRQ(ierr); /* number of levels -- only process most options on the finest level */ if (isFine) { ierr = PetscOptionsInt("-snes_fas_levels", "Number of Levels", "SNESFASSetLevels", levels, &levels, &flg);CHKERRQ(ierr); if (!flg && snes->dm) { ierr = DMGetRefineLevel(snes->dm,&levels);CHKERRQ(ierr); levels++; fas->usedmfornumberoflevels = PETSC_TRUE; } ierr = SNESFASSetLevels(snes, levels, NULL);CHKERRQ(ierr); fastype = fas->fastype; ierr = PetscOptionsEnum("-snes_fas_type","FAS correction type","SNESFASSetType",SNESFASTypes,(PetscEnum)fastype,(PetscEnum*)&fastype,&flg);CHKERRQ(ierr); if (flg) { ierr = SNESFASSetType(snes, fastype);CHKERRQ(ierr); } ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr); ierr = PetscOptionsInt("-snes_fas_cycles","Number of cycles","SNESFASSetCycles",fas->n_cycles,&m,&flg);CHKERRQ(ierr); if (flg) { ierr = SNESFASSetCycles(snes, m);CHKERRQ(ierr); } ierr = PetscOptionsBool("-snes_fas_continuation","Corrected grid-sequence continuation","SNESFASSetContinuation",fas->continuation,&continuationflg,&flg);CHKERRQ(ierr); if (flg) { ierr = SNESFASSetContinuation(snes,continuationflg);CHKERRQ(ierr); } ierr = PetscOptionsBool("-snes_fas_galerkin", "Form coarse problems with Galerkin","SNESFASSetGalerkin",fas->galerkin,&galerkinflg,&flg);CHKERRQ(ierr); if (flg) { ierr = SNESFASSetGalerkin(snes, galerkinflg);CHKERRQ(ierr); } if (fas->fastype == SNES_FAS_FULL) { ierr = PetscOptionsBool("-snes_fas_full_downsweep","Smooth on the initial upsweep for full FAS cycles","SNESFASFullSetDownSweep",fas->full_downsweep,&fas->full_downsweep,&flg);CHKERRQ(ierr); if (flg) {SNESFASFullSetDownSweep(snes,fas->full_downsweep);CHKERRQ(ierr);} } ierr = PetscOptionsInt("-snes_fas_smoothup","Number of post-smoothing steps","SNESFASSetNumberSmoothUp",fas->max_up_it,&n_up,&upflg);CHKERRQ(ierr); ierr = PetscOptionsInt("-snes_fas_smoothdown","Number of pre-smoothing steps","SNESFASSetNumberSmoothDown",fas->max_down_it,&n_down,&downflg);CHKERRQ(ierr); ierr = PetscOptionsString("-snes_fas_monitor","Monitor FAS progress","SNESFASSetMonitor","stdout",monfilename,PETSC_MAX_PATH_LEN,&monflg);CHKERRQ(ierr); if (monflg) ierr = SNESFASSetMonitor(snes, PETSC_TRUE);CHKERRQ(ierr); flg = PETSC_FALSE; monflg = PETSC_TRUE; ierr = PetscOptionsBool("-snes_fas_log","Log times for each FAS level","SNESFASSetLog",monflg,&monflg,&flg);CHKERRQ(ierr); if (flg) {ierr = SNESFASSetLog(snes,monflg);CHKERRQ(ierr);} } ierr = PetscOptionsTail();CHKERRQ(ierr); /* setup from the determined types if there is no pointwise procedure or smoother defined */ if (upflg) { ierr = SNESFASSetNumberSmoothUp(snes,n_up);CHKERRQ(ierr); } if (downflg) { ierr = SNESFASSetNumberSmoothDown(snes,n_down);CHKERRQ(ierr); } /* set up the default line search for coarse grid corrections */ if (fas->fastype == SNES_FAS_ADDITIVE) { if (!snes->linesearch) { ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr); ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr); } } ierr = SNESFASCycleGetCorrection(snes, &next);CHKERRQ(ierr); /* recursive option setting for the smoothers */ if (next) {ierr = SNESSetFromOptions(next);CHKERRQ(ierr);} PetscFunctionReturn(0); }
PetscErrorCode SNESSetUp_NASM(SNES snes) { SNES_NASM *nasm = (SNES_NASM*)snes->data; PetscErrorCode ierr; DM dm,subdm; DM *subdms; PetscInt i; const char *optionsprefix; Vec F; PetscMPIInt size; KSP ksp; PC pc; PetscFunctionBegin; if (!nasm->subsnes) { ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); if (dm) { nasm->usesdm = PETSC_TRUE; ierr = DMCreateDomainDecomposition(dm,&nasm->n,NULL,NULL,NULL,&subdms);CHKERRQ(ierr); if (!subdms) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"DM has no default decomposition defined. Set subsolves manually with SNESNASMSetSubdomains()."); ierr = DMCreateDomainDecompositionScatters(dm,nasm->n,subdms,&nasm->iscatter,&nasm->oscatter,&nasm->gscatter);CHKERRQ(ierr); ierr = SNESGetOptionsPrefix(snes, &optionsprefix);CHKERRQ(ierr); ierr = PetscMalloc(nasm->n*sizeof(SNES),&nasm->subsnes);CHKERRQ(ierr); for (i=0; i<nasm->n; i++) { ierr = SNESCreate(PETSC_COMM_SELF,&nasm->subsnes[i]);CHKERRQ(ierr); ierr = SNESAppendOptionsPrefix(nasm->subsnes[i],optionsprefix);CHKERRQ(ierr); ierr = SNESAppendOptionsPrefix(nasm->subsnes[i],"sub_");CHKERRQ(ierr); ierr = SNESSetDM(nasm->subsnes[i],subdms[i]);CHKERRQ(ierr); ierr = MPI_Comm_size(PetscObjectComm((PetscObject)nasm->subsnes[i]),&size);CHKERRQ(ierr); if (size == 1) { ierr = SNESGetKSP(nasm->subsnes[i],&ksp);CHKERRQ(ierr); ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); ierr = KSPSetType(ksp,KSPPREONLY);CHKERRQ(ierr); ierr = PCSetType(pc,PCLU);CHKERRQ(ierr); } ierr = SNESSetFromOptions(nasm->subsnes[i]);CHKERRQ(ierr); ierr = DMDestroy(&subdms[i]);CHKERRQ(ierr); } ierr = PetscFree(subdms);CHKERRQ(ierr); } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Cannot construct local problems automatically without a DM!"); } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must set subproblems manually if there is no DM!"); /* allocate the global vectors */ if (!nasm->x) { ierr = PetscMalloc(nasm->n*sizeof(Vec),&nasm->x);CHKERRQ(ierr); ierr = PetscMemzero(nasm->x,nasm->n*sizeof(Vec));CHKERRQ(ierr); } if (!nasm->xl) { ierr = PetscMalloc(nasm->n*sizeof(Vec),&nasm->xl);CHKERRQ(ierr); ierr = PetscMemzero(nasm->xl,nasm->n*sizeof(Vec));CHKERRQ(ierr); } if (!nasm->y) { ierr = PetscMalloc(nasm->n*sizeof(Vec),&nasm->y);CHKERRQ(ierr); ierr = PetscMemzero(nasm->y,nasm->n*sizeof(Vec));CHKERRQ(ierr); } if (!nasm->b) { ierr = PetscMalloc(nasm->n*sizeof(Vec),&nasm->b);CHKERRQ(ierr); ierr = PetscMemzero(nasm->b,nasm->n*sizeof(Vec));CHKERRQ(ierr); } for (i=0; i<nasm->n; i++) { ierr = SNESGetFunction(nasm->subsnes[i],&F,NULL,NULL);CHKERRQ(ierr); if (!nasm->x[i]) {ierr = VecDuplicate(F,&nasm->x[i]);CHKERRQ(ierr);} if (!nasm->y[i]) {ierr = VecDuplicate(F,&nasm->y[i]);CHKERRQ(ierr);} if (!nasm->b[i]) {ierr = VecDuplicate(F,&nasm->b[i]);CHKERRQ(ierr);} if (!nasm->xl[i]) { ierr = SNESGetDM(nasm->subsnes[i],&subdm);CHKERRQ(ierr); ierr = DMCreateLocalVector(subdm,&nasm->xl[i]);CHKERRQ(ierr); } ierr = DMGlobalToLocalHookAdd(subdm,DMGlobalToLocalSubDomainDirichletHook_Private,NULL,nasm->xl[i]);CHKERRQ(ierr); } if (nasm->finaljacobian) { ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr); if (nasm->fjtype == 2) { ierr = VecDuplicate(snes->vec_sol,&nasm->xinit);CHKERRQ(ierr); } for (i=0; i<nasm->n;i++) { ierr = SNESSetUpMatrices(nasm->subsnes[i]);CHKERRQ(ierr); } } PetscFunctionReturn(0); }