PetscErrorCode MatMultASPIN(Mat m,Vec X,Vec Y) { PetscErrorCode ierr; void *ctx; SNES snes; PetscInt n,i; VecScatter *oscatter; SNES *subsnes; PetscBool match; MPI_Comm comm; KSP ksp; PC pc; Vec *x,*b; Vec W; SNES npc; PetscFunctionBegin; ierr = MatShellGetContext(m,&ctx);CHKERRQ(ierr); snes = (SNES)ctx; ierr = SNESGetPC(snes,&npc);CHKERRQ(ierr); ierr = SNESGetFunction(npc,&W,NULL,NULL);CHKERRQ(ierr); ierr = PetscObjectTypeCompare((PetscObject)npc,SNESNASM,&match);CHKERRQ(ierr); if (!match) { ierr = PetscObjectGetComm((PetscObject)snes,&comm); SETERRQ(comm,PETSC_ERR_ARG_WRONGSTATE,"MatMultASPIN requires that the nonlinear preconditioner be Nonlinear additive Schwarz"); } ierr = SNESNASMGetSubdomains(npc,&n,&subsnes,NULL,&oscatter,NULL);CHKERRQ(ierr); ierr = SNESNASMGetSubdomainVecs(npc,&n,&x,&b,NULL,NULL);CHKERRQ(ierr); ierr = VecSet(Y,0);CHKERRQ(ierr); ierr = MatMult(npc->jacobian_pre,X,W);CHKERRQ(ierr); for (i=0;i<n;i++) { ierr = VecScatterBegin(oscatter[i],W,b[i],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); } for (i=0;i<n;i++) { ierr = VecScatterEnd(oscatter[i],W,b[i],INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); ierr = VecSet(x[i],0.);CHKERRQ(ierr); ierr = SNESGetKSP(subsnes[i],&ksp);CHKERRQ(ierr); ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); ierr = PCApply(pc,b[i],x[i]);CHKERRQ(ierr); ierr = VecScatterBegin(oscatter[i],x[i],Y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); } for (i=0;i<n;i++) { ierr = VecScatterEnd(oscatter[i],x[i],Y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); } PetscFunctionReturn(0); }
/*MC SNESASPIN - Helper SNES type for Additive-Schwarz Preconditioned Inexact Newton Options Database: + -npc_snes_ - options prefix of the nonlinear subdomain solver (must be of type NASM) . -npc_sub_snes_ - options prefix of the subdomain nonlinear solves . -npc_sub_ksp_ - options prefix of the subdomain Krylov solver - -npc_sub_pc_ - options prefix of the subdomain preconditioner Notes: This routine sets up an instance of NETWONLS with nonlinear left preconditioning. It differs from other similar functionality in SNES as it creates a linear shell matrix that corresponds to the product: \sum_{i=0}^{N_b}J_b({X^b_{converged}})^{-1}J(X + \sum_{i=0}^{N_b}(X^b_{converged} - X^b)) which is the ASPIN preconditioned matrix. Similar solvers may be constructed by having matrix-free differencing of nonlinear solves per linear iteration, but this is far more efficient when subdomain sparse-direct preconditioner factorizations are reused on each application of J_b^{-1}. Level: intermediate .seealso: SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNASM, SNESGetPC(), SNESGetPCSide() M*/ PETSC_EXTERN PetscErrorCode SNESCreate_ASPIN(SNES snes) { PetscErrorCode ierr; SNES npc; KSP ksp; PC pc; Mat aspinmat; MPI_Comm comm; Vec F; PetscInt n; SNESLineSearch linesearch; PetscFunctionBegin; /* set up the solver */ ierr = SNESSetType(snes,SNESNEWTONLS);CHKERRQ(ierr); ierr = SNESSetPCSide(snes,PC_LEFT);CHKERRQ(ierr); ierr = SNESGetPC(snes,&npc);CHKERRQ(ierr); ierr = SNESSetType(npc,SNESNASM);CHKERRQ(ierr); ierr = SNESNASMSetComputeFinalJacobian(npc,PETSC_TRUE);CHKERRQ(ierr); ierr = SNESGetKSP(snes,&ksp);CHKERRQ(ierr); ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr); ierr = PetscObjectGetComm((PetscObject)snes,&comm);CHKERRQ(ierr); ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr); ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBT);CHKERRQ(ierr); /* set up the shell matrix */ ierr = SNESGetFunction(snes,&F,NULL,NULL);CHKERRQ(ierr); ierr = VecGetLocalSize(F,&n);CHKERRQ(ierr); ierr = MatCreateShell(comm,n,n,PETSC_DECIDE,PETSC_DECIDE,snes,&aspinmat);CHKERRQ(ierr); ierr = MatSetType(aspinmat,MATSHELL);CHKERRQ(ierr); ierr = MatShellSetOperation(aspinmat,MATOP_MULT,(void(*)(void))MatMultASPIN);CHKERRQ(ierr); ierr = SNESSetJacobian(snes,aspinmat,NULL,NULL,NULL);CHKERRQ(ierr); ierr = MatDestroy(&aspinmat);CHKERRQ(ierr); PetscFunctionReturn(0); }
int main(int argc,char **argv) { SNES snes; /* nonlinear solver */ SNES psnes; /* nonlinear Gauss-Seidel approximate solver */ Vec x,b; /* solution vector */ PetscInt its; /* iterations for convergence */ PetscErrorCode ierr; DM da; PetscBool use_ngs = PETSC_FALSE; /* use the nonlinear Gauss-Seidel approximate solver */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Initialize program - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ PetscInitialize(&argc,&argv,(char *)0,help); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create nonlinear solver context - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = SNESCreate(PETSC_COMM_WORLD,&snes);CHKERRQ(ierr); ierr = PetscOptionsGetBool(PETSC_NULL,"-use_ngs",&use_ngs,0);CHKERRQ(ierr); if (use_ngs) { ierr = SNESGetPC(snes,&psnes);CHKERRQ(ierr); ierr = SNESSetType(psnes,SNESSHELL);CHKERRQ(ierr); ierr = SNESShellSetSolve(psnes,NonlinearGS);CHKERRQ(ierr); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create distributed array (DMDA) to manage parallel grid and vectors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = DMDACreate2d(PETSC_COMM_WORLD, DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_NONE,DMDA_STENCIL_STAR,-4,-4,PETSC_DECIDE,PETSC_DECIDE,1,1,PETSC_NULL,PETSC_NULL,&da);CHKERRQ(ierr); ierr = DMDASetUniformCoordinates(da, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);CHKERRQ(ierr); ierr = SNESSetDM(snes,da);CHKERRQ(ierr); if (use_ngs) { ierr = SNESShellSetContext(psnes,da);CHKERRQ(ierr); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Extract global vectors from DMDA; then duplicate for remaining vectors that are the same types - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = DMCreateGlobalVector(da,&x);CHKERRQ(ierr); ierr = DMCreateGlobalVector(da,&b);CHKERRQ(ierr); ierr = VecSetRandom(b,PETSC_NULL);CHKERRQ(ierr); ierr = SNESSetFunction(snes,PETSC_NULL,MyComputeFunction,PETSC_NULL);CHKERRQ(ierr); ierr = SNESSetJacobian(snes,PETSC_NULL,PETSC_NULL,MyComputeJacobian,PETSC_NULL);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Customize nonlinear solver; set runtime options - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = SNESSetFromOptions(snes);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Solve nonlinear system - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = SNESSolve(snes,b,x);CHKERRQ(ierr); ierr = SNESGetIterationNumber(snes,&its);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Free work space. All PETSc objects should be destroyed when they are no longer needed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = VecDestroy(&x);CHKERRQ(ierr); ierr = VecDestroy(&b);CHKERRQ(ierr); ierr = SNESDestroy(&snes);CHKERRQ(ierr); ierr = DMDestroy(&da);CHKERRQ(ierr); ierr = PetscFinalize(); PetscFunctionReturn(0); }