PageRenderTime 29ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ksp/ksp/examples/tutorials/ex13.c

https://bitbucket.org/alexei-matveev/petsc-debian-pkg
C | 316 lines | 141 code | 33 blank | 142 comment | 10 complexity | a223598eb60e8eceafca1b21107f3f32 MD5 | raw file
  1. static char help[] = "Solves a variable Poisson problem with KSP.\n\n";
  2. /*T
  3. Concepts: KSP^basic sequential example
  4. Concepts: KSP^Laplacian, 2d
  5. Concepts: Laplacian, 2d
  6. Processors: 1
  7. T*/
  8. /*
  9. Include "petscksp.h" so that we can use KSP solvers. Note that this file
  10. automatically includes:
  11. petscsys.h - base PETSc routines petscvec.h - vectors
  12. petscmat.h - matrices
  13. petscis.h - index sets petscksp.h - Krylov subspace methods
  14. petscviewer.h - viewers petscpc.h - preconditioners
  15. */
  16. #include <petscksp.h>
  17. /*
  18. User-defined context that contains all the data structures used
  19. in the linear solution process.
  20. */
  21. typedef struct {
  22. Vec x,b; /* solution vector, right-hand-side vector */
  23. Mat A; /* sparse matrix */
  24. KSP ksp; /* linear solver context */
  25. PetscInt m,n; /* grid dimensions */
  26. PetscScalar hx2,hy2; /* 1/(m+1)*(m+1) and 1/(n+1)*(n+1) */
  27. } UserCtx;
  28. extern PetscErrorCode UserInitializeLinearSolver(PetscInt,PetscInt,UserCtx *);
  29. extern PetscErrorCode UserFinalizeLinearSolver(UserCtx *);
  30. extern PetscErrorCode UserDoLinearSolver(PetscScalar *,UserCtx *userctx,PetscScalar *b,PetscScalar *x);
  31. #undef __FUNCT__
  32. #define __FUNCT__ "main"
  33. int main(int argc,char **args)
  34. {
  35. UserCtx userctx;
  36. PetscErrorCode ierr;
  37. PetscInt m = 6,n = 7,t,tmax = 2,i,Ii,j,N;
  38. PetscScalar *userx,*rho,*solution,*userb,hx,hy,x,y;
  39. PetscReal enorm;
  40. /*
  41. Initialize the PETSc libraries
  42. */
  43. PetscInitialize(&argc,&args,(char *)0,help);
  44. /*
  45. The next two lines are for testing only; these allow the user to
  46. decide the grid size at runtime.
  47. */
  48. ierr = PetscOptionsGetInt(PETSC_NULL,"-m",&m,PETSC_NULL);CHKERRQ(ierr);
  49. ierr = PetscOptionsGetInt(PETSC_NULL,"-n",&n,PETSC_NULL);CHKERRQ(ierr);
  50. /*
  51. Create the empty sparse matrix and linear solver data structures
  52. */
  53. ierr = UserInitializeLinearSolver(m,n,&userctx);CHKERRQ(ierr);
  54. N = m*n;
  55. /*
  56. Allocate arrays to hold the solution to the linear system.
  57. This is not normally done in PETSc programs, but in this case,
  58. since we are calling these routines from a non-PETSc program, we
  59. would like to reuse the data structures from another code. So in
  60. the context of a larger application these would be provided by
  61. other (non-PETSc) parts of the application code.
  62. */
  63. ierr = PetscMalloc(N*sizeof(PetscScalar),&userx);CHKERRQ(ierr);
  64. ierr = PetscMalloc(N*sizeof(PetscScalar),&userb);CHKERRQ(ierr);
  65. ierr = PetscMalloc(N*sizeof(PetscScalar),&solution);CHKERRQ(ierr);
  66. /*
  67. Allocate an array to hold the coefficients in the elliptic operator
  68. */
  69. ierr = PetscMalloc(N*sizeof(PetscScalar),&rho);CHKERRQ(ierr);
  70. /*
  71. Fill up the array rho[] with the function rho(x,y) = x; fill the
  72. right-hand-side b[] and the solution with a known problem for testing.
  73. */
  74. hx = 1.0/(m+1);
  75. hy = 1.0/(n+1);
  76. y = hy;
  77. Ii = 0;
  78. for (j=0; j<n; j++) {
  79. x = hx;
  80. for (i=0; i<m; i++) {
  81. rho[Ii] = x;
  82. solution[Ii] = PetscSinScalar(2.*PETSC_PI*x)*PetscSinScalar(2.*PETSC_PI*y);
  83. userb[Ii] = -2*PETSC_PI*PetscCosScalar(2*PETSC_PI*x)*PetscSinScalar(2*PETSC_PI*y) +
  84. 8*PETSC_PI*PETSC_PI*x*PetscSinScalar(2*PETSC_PI*x)*PetscSinScalar(2*PETSC_PI*y);
  85. x += hx;
  86. Ii++;
  87. }
  88. y += hy;
  89. }
  90. /*
  91. Loop over a bunch of timesteps, setting up and solver the linear
  92. system for each time-step.
  93. Note this is somewhat artificial. It is intended to demonstrate how
  94. one may reuse the linear solver stuff in each time-step.
  95. */
  96. for (t=0; t<tmax; t++) {
  97. ierr = UserDoLinearSolver(rho,&userctx,userb,userx);CHKERRQ(ierr);
  98. /*
  99. Compute error: Note that this could (and usually should) all be done
  100. using the PETSc vector operations. Here we demonstrate using more
  101. standard programming practices to show how they may be mixed with
  102. PETSc.
  103. */
  104. enorm = 0.0;
  105. for (i=0; i<N; i++) {
  106. enorm += PetscRealPart(PetscConj(solution[i]-userx[i])*(solution[i]-userx[i]));
  107. }
  108. enorm *= PetscRealPart(hx*hy);
  109. ierr = PetscPrintf(PETSC_COMM_WORLD,"m %D n %D error norm %G\n",m,n,enorm);CHKERRQ(ierr);
  110. }
  111. /*
  112. We are all finished solving linear systems, so we clean up the
  113. data structures.
  114. */
  115. ierr = PetscFree(rho);CHKERRQ(ierr);
  116. ierr = PetscFree(solution);CHKERRQ(ierr);
  117. ierr = PetscFree(userx);CHKERRQ(ierr);
  118. ierr = PetscFree(userb);CHKERRQ(ierr);
  119. ierr = UserFinalizeLinearSolver(&userctx);CHKERRQ(ierr);
  120. ierr = PetscFinalize();
  121. return 0;
  122. }
  123. /* ------------------------------------------------------------------------*/
  124. #undef __FUNCT__
  125. #define __FUNCT__ "UserInitializedLinearSolve"
  126. PetscErrorCode UserInitializeLinearSolver(PetscInt m,PetscInt n,UserCtx *userctx)
  127. {
  128. PetscErrorCode ierr;
  129. PetscInt N;
  130. /*
  131. Here we assume use of a grid of size m x n, with all points on the
  132. interior of the domain, i.e., we do not include the points corresponding
  133. to homogeneous Dirichlet boundary conditions. We assume that the domain
  134. is [0,1]x[0,1].
  135. */
  136. userctx->m = m;
  137. userctx->n = n;
  138. userctx->hx2 = (m+1)*(m+1);
  139. userctx->hy2 = (n+1)*(n+1);
  140. N = m*n;
  141. /*
  142. Create the sparse matrix. Preallocate 5 nonzeros per row.
  143. */
  144. ierr = MatCreateSeqAIJ(PETSC_COMM_SELF,N,N,5,0,&userctx->A);CHKERRQ(ierr);
  145. /*
  146. Create vectors. Here we create vectors with no memory allocated.
  147. This way, we can use the data structures already in the program
  148. by using VecPlaceArray() subroutine at a later stage.
  149. */
  150. ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,1,N,PETSC_NULL,&userctx->b);CHKERRQ(ierr);
  151. ierr = VecDuplicate(userctx->b,&userctx->x);CHKERRQ(ierr);
  152. /*
  153. Create linear solver context. This will be used repeatedly for all
  154. the linear solves needed.
  155. */
  156. ierr = KSPCreate(PETSC_COMM_SELF,&userctx->ksp);CHKERRQ(ierr);
  157. return 0;
  158. }
  159. #undef __FUNCT__
  160. #define __FUNCT__ "UserDoLinearSolve"
  161. /*
  162. Solves -div (rho grad psi) = F using finite differences.
  163. rho is a 2-dimensional array of size m by n, stored in Fortran
  164. style by columns. userb is a standard one-dimensional array.
  165. */
  166. /* ------------------------------------------------------------------------*/
  167. PetscErrorCode UserDoLinearSolver(PetscScalar *rho,UserCtx *userctx,PetscScalar *userb,PetscScalar *userx)
  168. {
  169. PetscErrorCode ierr;
  170. PetscInt i,j,Ii,J,m = userctx->m,n = userctx->n;
  171. Mat A = userctx->A;
  172. PC pc;
  173. PetscScalar v,hx2 = userctx->hx2,hy2 = userctx->hy2;
  174. /*
  175. This is not the most efficient way of generating the matrix
  176. but let's not worry about it. We should have separate code for
  177. the four corners, each edge and then the interior. Then we won't
  178. have the slow if-tests inside the loop.
  179. Computes the operator
  180. -div rho grad
  181. on an m by n grid with zero Dirichlet boundary conditions. The rho
  182. is assumed to be given on the same grid as the finite difference
  183. stencil is applied. For a staggered grid, one would have to change
  184. things slightly.
  185. */
  186. Ii = 0;
  187. for (j=0; j<n; j++) {
  188. for (i=0; i<m; i++) {
  189. if (j>0) {
  190. J = Ii - m;
  191. v = -.5*(rho[Ii] + rho[J])*hy2;
  192. ierr = MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);
  193. }
  194. if (j<n-1) {
  195. J = Ii + m;
  196. v = -.5*(rho[Ii] + rho[J])*hy2;
  197. ierr = MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);
  198. }
  199. if (i>0) {
  200. J = Ii - 1;
  201. v = -.5*(rho[Ii] + rho[J])*hx2;
  202. ierr = MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);
  203. }
  204. if (i<m-1) {
  205. J = Ii + 1;
  206. v = -.5*(rho[Ii] + rho[J])*hx2;
  207. ierr = MatSetValues(A,1,&Ii,1,&J,&v,INSERT_VALUES);CHKERRQ(ierr);
  208. }
  209. v = 2.0*rho[Ii]*(hx2+hy2);
  210. ierr = MatSetValues(A,1,&Ii,1,&Ii,&v,INSERT_VALUES);CHKERRQ(ierr);
  211. Ii++;
  212. }
  213. }
  214. /*
  215. Assemble matrix
  216. */
  217. ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
  218. ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
  219. /*
  220. Set operators. Here the matrix that defines the linear system
  221. also serves as the preconditioning matrix. Since all the matrices
  222. will have the same nonzero pattern here, we indicate this so the
  223. linear solvers can take advantage of this.
  224. */
  225. ierr = KSPSetOperators(userctx->ksp,A,A,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
  226. /*
  227. Set linear solver defaults for this problem (optional).
  228. - Here we set it to use direct LU factorization for the solution
  229. */
  230. ierr = KSPGetPC(userctx->ksp,&pc);CHKERRQ(ierr);
  231. ierr = PCSetType(pc,PCLU);CHKERRQ(ierr);
  232. /*
  233. Set runtime options, e.g.,
  234. -ksp_type <type> -pc_type <type> -ksp_monitor -ksp_rtol <rtol>
  235. These options will override those specified above as long as
  236. KSPSetFromOptions() is called _after_ any other customization
  237. routines.
  238. Run the program with the option -help to see all the possible
  239. linear solver options.
  240. */
  241. ierr = KSPSetFromOptions(userctx->ksp);CHKERRQ(ierr);
  242. /*
  243. This allows the PETSc linear solvers to compute the solution
  244. directly in the user's array rather than in the PETSc vector.
  245. This is essentially a hack and not highly recommend unless you
  246. are quite comfortable with using PETSc. In general, users should
  247. write their entire application using PETSc vectors rather than
  248. arrays.
  249. */
  250. ierr = VecPlaceArray(userctx->x,userx);CHKERRQ(ierr);
  251. ierr = VecPlaceArray(userctx->b,userb);CHKERRQ(ierr);
  252. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  253. Solve the linear system
  254. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  255. ierr = KSPSolve(userctx->ksp,userctx->b,userctx->x);CHKERRQ(ierr);
  256. /*
  257. Put back the PETSc array that belongs in the vector xuserctx->x
  258. */
  259. ierr = VecResetArray(userctx->x);CHKERRQ(ierr);
  260. ierr = VecResetArray(userctx->b);CHKERRQ(ierr);
  261. return 0;
  262. }
  263. /* ------------------------------------------------------------------------*/
  264. #undef __FUNCT__
  265. #define __FUNCT__ "UserFinalizeLinearSolve"
  266. PetscErrorCode UserFinalizeLinearSolver(UserCtx *userctx)
  267. {
  268. PetscErrorCode ierr;
  269. /*
  270. We are all done and don't need to solve any more linear systems, so
  271. we free the work space. All PETSc objects should be destroyed when
  272. they are no longer needed.
  273. */
  274. ierr = KSPDestroy(&userctx->ksp);CHKERRQ(ierr);
  275. ierr = VecDestroy(&userctx->x);CHKERRQ(ierr);
  276. ierr = VecDestroy(&userctx->b);CHKERRQ(ierr);
  277. ierr = MatDestroy(&userctx->A);CHKERRQ(ierr);
  278. return 0;
  279. }