static char help[] = "Solves a variable Poisson problem with KSP.\n\n"; /*T Concepts: KSP^basic sequential example Concepts: KSP^Laplacian, 2d Concepts: Laplacian, 2d Processors: 1 T*/ /* Include "petscksp.h" so that we can use KSP solvers. Note that this file automatically includes: petsc.h - base PETSc routines petscvec.h - vectors petscsys.h - system routines petscmat.h - matrices petscis.h - index sets petscksp.h - Krylov subspace methods petscviewer.h - viewers petscpc.h - preconditioners */ #include "petscksp.h" /* User-defined context that contains all the data structures used in the linear solution process. */ typedef struct { Vec x,b; /* solution vector, right-hand-side vector */ Mat A; /* sparse matrix */ KSP ksp; /* linear solver context */ PetscInt m,n; /* grid dimensions */ PetscScalar hx2,hy2; /* 1/(m+1)*(m+1) and 1/(n+1)*(n+1) */ } UserCtx; extern PetscErrorCode UserInitializeLinearSolver(PetscInt,PetscInt,UserCtx *); extern PetscErrorCode UserFinalizeLinearSolver(UserCtx *); extern PetscErrorCode UserDoLinearSolver(PetscScalar *,UserCtx *userctx,PetscScalar *b,PetscScalar *x); #undef __FUNCT__ #define __FUNCT__ "main" int main(int argc,char **args) { UserCtx userctx; PetscErrorCode ierr; PetscInt m = 6,n = 7,t,tmax = 2,i,Ii,j,N; PetscScalar *userx,*rho,*solution,*userb,hx,hy,x,y; PetscReal enorm; /* Initialize the PETSc libraries */ PetscInitialize(&argc,&args,(char *)0,help); /* The next two lines are for testing only; these allow the user to decide the grid size at runtime. */ ierr = PetscOptionsGetInt(PETSC_NULL,"-m",&m,PETSC_NULL);CHKERRQ(ierr); ierr = PetscOptionsGetInt(PETSC_NULL,"-n",&n,PETSC_NULL);CHKERRQ(ierr); /* Create the empty sparse matrix and linear solver data structures */ ierr = UserInitializeLinearSolver(m,n,&userctx);CHKERRQ(ierr); N = m*n; /* Allocate arrays to hold the solution to the linear system. This is not normally done in PETSc programs, but in this case, since we are calling these routines from a non-PETSc program, we would like to reuse the data structures from another code. So in the context of a larger application these would be provided by other (non-PETSc) parts of the application code. */ ierr = PetscMalloc(N*sizeof(PetscScalar),&userx);CHKERRQ(ierr); ierr = PetscMalloc(N*sizeof(PetscScalar),&userb);CHKERRQ(ierr); ierr = PetscMalloc(N*sizeof(PetscScalar),&solution);CHKERRQ(ierr); /* Allocate an array to hold the coefficients in the elliptic operator */ ierr = PetscMalloc(N*sizeof(PetscScalar),&rho);CHKERRQ(ierr); /* Fill up the array rho[] with the function rho(x,y) = x; fill the right-hand-side b[] and the solution with a known problem for testing. */ hx = 1.0/(m+1); hy = 1.0/(n+1); y = hy; Ii = 0; for (j=0; jm = m; userctx->n = n; userctx->hx2 = (m+1)*(m+1); userctx->hy2 = (n+1)*(n+1); N = m*n; /* Create the sparse matrix. Preallocate 5 nonzeros per row. */ ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,N,N,5,0,&userctx->A);CHKERRQ(ierr); /* Create vectors. Here we create vectors with no memory allocated. This way, we can use the data structures already in the program by using VecPlaceArray() subroutine at a later stage. */ ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,N,PETSC_NULL,&userctx->b);CHKERRQ(ierr); ierr = VecDuplicate(userctx->b,&userctx->x);CHKERRQ(ierr); /* Create linear solver context. This will be used repeatedly for all the linear solves needed. */ ierr = KSPCreate(PETSC_COMM_SELF,&userctx->ksp);CHKERRQ(ierr); return 0; } #undef __FUNCT__ #define __FUNCT__ "UserDoLinearSolve" /* Solves -div (rho grad psi) = F using finite differences. rho is a 2-dimensional array of size m by n, stored in Fortran style by columns. userb is a standard one-dimensional array. */ /* ------------------------------------------------------------------------*/ PetscErrorCode UserDoLinearSolver(PetscScalar *rho,UserCtx *userctx,PetscScalar *userb,PetscScalar *userx) { PetscErrorCode ierr; PetscInt i,j,Ii,J,m = userctx->m,n = userctx->n; Mat A = userctx->A; PC pc; PetscScalar v,hx2 = userctx->hx2,hy2 = userctx->hy2; /* This is not the most efficient way of generating the matrix but let's not worry about it. We should have separate code for the four corners, each edge and then the interior. Then we won't have the slow if-tests inside the loop. Computes the operator -div rho grad on an m by n grid with zero Dirichlet boundary conditions. The rho is assumed to be given on the same grid as the finite difference stencil is applied. For a staggered grid, one would have to change things slightly. */ Ii = 0; for (j=0; j0) { J = Ii - m; v = -.5*(rho[Ii] + rho[J])*hy2; ierr = MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr); } if (j0) { J = Ii - 1; v = -.5*(rho[Ii] + rho[J])*hx2; ierr = MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr); } if (iksp,A,A,SAME_NONZERO_PATTERN);CHKERRQ(ierr); /* Set linear solver defaults for this problem (optional). - Here we set it to use direct LU factorization for the solution */ ierr = KSPGetPC(userctx->ksp,&pc);CHKERRQ(ierr); ierr = PCSetType(pc,PCLU);CHKERRQ(ierr); /* Set runtime options, e.g., -ksp_type -pc_type -ksp_monitor -ksp_rtol These options will override those specified above as long as KSPSetFromOptions() is called _after_ any other customization routines. Run the program with the option -help to see all the possible linear solver options. */ ierr = KSPSetFromOptions(userctx->ksp);CHKERRQ(ierr); /* This allows the PETSc linear solvers to compute the solution directly in the user's array rather than in the PETSc vector. This is essentially a hack and not highly recommend unless you are quite comfortable with using PETSc. In general, users should write their entire application using PETSc vectors rather than arrays. */ ierr = VecPlaceArray(userctx->x,userx);CHKERRQ(ierr); ierr = VecPlaceArray(userctx->b,userb);CHKERRQ(ierr); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Solve the linear system - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ierr = KSPSolve(userctx->ksp,userctx->b,userctx->x);CHKERRQ(ierr); /* Put back the PETSc array that belongs in the vector xuserctx->x */ ierr = VecResetArray(userctx->x);CHKERRQ(ierr); ierr = VecResetArray(userctx->b);CHKERRQ(ierr); return 0; } /* ------------------------------------------------------------------------*/ #undef __FUNCT__ #define __FUNCT__ "UserFinalizeLinearSolve" PetscErrorCode UserFinalizeLinearSolver(UserCtx *userctx) { PetscErrorCode ierr; /* We are all done and don't need to solve any more linear systems, so we free the work space. All PETSc objects should be destroyed when they are no longer needed. */ ierr = KSPDestroy(userctx->ksp);CHKERRQ(ierr); ierr = VecDestroy(userctx->x);CHKERRQ(ierr); ierr = VecDestroy(userctx->b);CHKERRQ(ierr); ierr = MatDestroy(userctx->A);CHKERRQ(ierr); return 0; }