static char help[] = "Tests the multigrid code. The input parameters are:\n\ -x N Use a mesh in the x direction of N. \n\ -c N Use N V-cycles. \n\ -l N Use N Levels. \n\ -smooths N Use N pre smooths and N post smooths. \n\ -j Use Jacobi smoother. \n\ -a use additive multigrid \n\ -f use full multigrid (preconditioner variant) \n\ This example also demonstrates matrix-free methods\n\n"; /* This is not a good example to understand the use of multigrid with PETSc. */ #include PetscErrorCode residual(Mat,Vec,Vec,Vec); PetscErrorCode gauss_seidel(PC,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal,PetscInt,PetscBool,PetscInt*,PCRichardsonConvergedReason*); PetscErrorCode jacobi_smoother(PC,Vec,Vec,Vec,PetscReal,PetscReal,PetscReal,PetscInt,PetscBool,PetscInt*,PCRichardsonConvergedReason*); PetscErrorCode interpolate(Mat,Vec,Vec,Vec); PetscErrorCode restrct(Mat,Vec,Vec); PetscErrorCode Create1dLaplacian(PetscInt,Mat*); PetscErrorCode CalculateRhs(Vec); PetscErrorCode CalculateError(Vec,Vec,Vec,PetscReal*); PetscErrorCode CalculateSolution(PetscInt,Vec*); PetscErrorCode amult(Mat,Vec,Vec); PetscErrorCode apply_pc(PC,Vec,Vec); int main(int Argc,char **Args) { PetscInt x_mesh = 15,levels = 3,cycles = 1,use_jacobi = 0; PetscInt i,smooths = 1,*N,its; PCMGType am = PC_MG_MULTIPLICATIVE; Mat cmat,mat[20],fmat; KSP cksp,ksp[20],kspmg; PetscReal e[3]; /* l_2 error,max error, residual */ const char *shellname; Vec x,solution,X[20],R[20],B[20]; PC pcmg,pc; PetscBool flg; PetscCall(PetscInitialize(&Argc,&Args,(char*)0,help)); PetscCall(PetscOptionsGetInt(NULL,NULL,"-x",&x_mesh,NULL)); PetscCall(PetscOptionsGetInt(NULL,NULL,"-l",&levels,NULL)); PetscCall(PetscOptionsGetInt(NULL,NULL,"-c",&cycles,NULL)); PetscCall(PetscOptionsGetInt(NULL,NULL,"-smooths",&smooths,NULL)); PetscCall(PetscOptionsHasName(NULL,NULL,"-a",&flg)); if (flg) am = PC_MG_ADDITIVE; PetscCall(PetscOptionsHasName(NULL,NULL,"-f",&flg)); if (flg) am = PC_MG_FULL; PetscCall(PetscOptionsHasName(NULL,NULL,"-j",&flg)); if (flg) use_jacobi = 1; PetscCall(PetscMalloc1(levels,&N)); N[0] = x_mesh; for (i=1; i= 1,PETSC_COMM_WORLD,PETSC_ERR_USER,"Too many levels or N is not large enough"); } PetscCall(Create1dLaplacian(N[levels-1],&cmat)); PetscCall(KSPCreate(PETSC_COMM_WORLD,&kspmg)); PetscCall(KSPGetPC(kspmg,&pcmg)); PetscCall(KSPSetFromOptions(kspmg)); PetscCall(PCSetType(pcmg,PCMG)); PetscCall(PCMGSetLevels(pcmg,levels,NULL)); PetscCall(PCMGSetType(pcmg,am)); PetscCall(PCMGGetCoarseSolve(pcmg,&cksp)); PetscCall(KSPSetOperators(cksp,cmat,cmat)); PetscCall(KSPGetPC(cksp,&pc)); PetscCall(PCSetType(pc,PCLU)); PetscCall(KSPSetType(cksp,KSPPREONLY)); /* zero is finest level */ for (i=0; i 0) { PetscCall(PCMGSetX(pcmg,levels - 1 - i,x)); } PetscCall(VecCreateSeq(PETSC_COMM_SELF,N[i],&x)); B[levels -1 - i] = x; if (i > 0) { PetscCall(PCMGSetRhs(pcmg,levels - 1 - i,x)); } PetscCall(VecCreateSeq(PETSC_COMM_SELF,N[i],&x)); R[levels - 1 - i] = x; PetscCall(PCMGSetR(pcmg,levels - 1 - i,x)); } /* create coarse level vectors */ PetscCall(VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x)); PetscCall(PCMGSetX(pcmg,0,x)); X[0] = x; PetscCall(VecCreateSeq(PETSC_COMM_SELF,N[levels-1],&x)); PetscCall(PCMGSetRhs(pcmg,0,x)); B[0] = x; /* create matrix multiply for finest level */ PetscCall(MatCreateShell(PETSC_COMM_WORLD,N[0],N[0],N[0],N[0],NULL,&fmat)); PetscCall(MatShellSetOperation(fmat,MATOP_MULT,(void (*)(void))amult)); PetscCall(KSPSetOperators(kspmg,fmat,fmat)); PetscCall(CalculateSolution(N[0],&solution)); PetscCall(CalculateRhs(B[levels-1])); PetscCall(VecSet(X[levels-1],0.0)); PetscCall(residual((Mat)0,B[levels-1],X[levels-1],R[levels-1])); PetscCall(CalculateError(solution,X[levels-1],R[levels-1],e)); PetscCall(PetscPrintf(PETSC_COMM_SELF,"l_2 error %g max error %g resi %g\n",(double)e[0],(double)e[1],(double)e[2])); PetscCall(KSPSolve(kspmg,B[levels-1],X[levels-1])); PetscCall(KSPGetIterationNumber(kspmg,&its)); PetscCall(residual((Mat)0,B[levels-1],X[levels-1],R[levels-1])); PetscCall(CalculateError(solution,X[levels-1],R[levels-1],e)); PetscCall(PetscPrintf(PETSC_COMM_SELF,"its %D l_2 error %g max error %g resi %g\n",its,(double)e[0],(double)e[1],(double)e[2])); PetscCall(PetscFree(N)); PetscCall(VecDestroy(&solution)); /* note we have to keep a list of all vectors allocated, this is not ideal, but putting it in MGDestroy is not so good either*/ for (i=0; i0; i--) x[i] = .5*(x[i+1] + x[i-1] + b[i]); x[0] = .5*(x[1] + b[0]); } PetscCall(VecRestoreArrayRead(bb,&b)); PetscCall(VecRestoreArray(xx,&x)); PetscFunctionReturn(0); } /* --------------------------------------------------------------------- */ PetscErrorCode jacobi_smoother(PC pc,Vec bb,Vec xx,Vec w,PetscReal rtol,PetscReal abstol,PetscReal dtol,PetscInt m,PetscBool guesszero,PetscInt *its,PCRichardsonConvergedReason *reason) { PetscInt i,n,n1; PetscScalar *r,*x; const PetscScalar *b; PetscFunctionBegin; *its = m; *reason = PCRICHARDSON_CONVERGED_ITS; PetscCall(VecGetSize(bb,&n)); n1 = n - 1; PetscCall(VecGetArrayRead(bb,&b)); PetscCall(VecGetArray(xx,&x)); PetscCall(VecGetArray(w,&r)); while (m--) { r[0] = .5*(x[1] + b[0]); for (i=1; i