xref: /petsc/src/snes/tutorials/ex78.c (revision b122ec5aa1bd4469eb4e0673542fb7de3f411254)
1c4762a1bSJed Brown 
2c4762a1bSJed Brown static char help[] = "Newton methods to solve u''  = f in parallel with periodic boundary conditions.\n\n";
3c4762a1bSJed Brown 
4c4762a1bSJed Brown /*T
5c4762a1bSJed Brown    Concepts: SNES^basic parallel example
6c4762a1bSJed Brown    Concepts: periodic boundary conditions
7c4762a1bSJed Brown    Processors: n
8c4762a1bSJed Brown T*/
9c4762a1bSJed Brown 
10c4762a1bSJed Brown /*
11c4762a1bSJed Brown    Compare this example to ex3.c that handles Dirichlet boundary conditions
12c4762a1bSJed Brown 
13c4762a1bSJed Brown    Though this is a linear problem it is treated as a nonlinear problem in this example to demonstrate
14c4762a1bSJed Brown    handling periodic boundary conditions for nonlinear problems.
15c4762a1bSJed Brown 
16c4762a1bSJed Brown    Include "petscdmda.h" so that we can use distributed arrays (DMDAs).
17c4762a1bSJed Brown    Include "petscsnes.h" so that we can use SNES solvers.  Note that this
18c4762a1bSJed Brown    file automatically includes:
19c4762a1bSJed Brown      petscsys.h       - base PETSc routines   petscvec.h - vectors
20c4762a1bSJed Brown      petscmat.h - matrices
21c4762a1bSJed Brown      petscis.h     - index sets            petscksp.h - Krylov subspace methods
22c4762a1bSJed Brown      petscviewer.h - viewers               petscpc.h  - preconditioners
23c4762a1bSJed Brown      petscksp.h   - linear solvers
24c4762a1bSJed Brown */
25c4762a1bSJed Brown 
26c4762a1bSJed Brown #include <petscdm.h>
27c4762a1bSJed Brown #include <petscdmda.h>
28c4762a1bSJed Brown #include <petscsnes.h>
29c4762a1bSJed Brown 
30c4762a1bSJed Brown PetscErrorCode FormJacobian(SNES,Vec,Mat,Mat,void*);
31c4762a1bSJed Brown PetscErrorCode FormFunction(SNES,Vec,Vec,void*);
32c4762a1bSJed Brown 
33c4762a1bSJed Brown int main(int argc,char **argv)
34c4762a1bSJed Brown {
35c4762a1bSJed Brown   SNES           snes;                 /* SNES context */
36c4762a1bSJed Brown   Mat            J;                    /* Jacobian matrix */
37c4762a1bSJed Brown   DM             da;
38c4762a1bSJed Brown   Vec            x,r;              /* vectors */
39c4762a1bSJed Brown   PetscInt       N = 5;
40c4762a1bSJed Brown   MatNullSpace   constants;
41c4762a1bSJed Brown 
42*b122ec5aSJacob Faibussowitsch   CHKERRQ(PetscInitialize(&argc,&argv,(char*)0,help));
435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsGetInt(NULL,NULL,"-n",&N,NULL));
44c4762a1bSJed Brown 
45c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
46c4762a1bSJed Brown      Create nonlinear solver context
47c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
48c4762a1bSJed Brown 
495f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESCreate(PETSC_COMM_WORLD,&snes));
50c4762a1bSJed Brown 
51c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
52c4762a1bSJed Brown      Create vector data structures; set function evaluation routine
53c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
54c4762a1bSJed Brown 
55c4762a1bSJed Brown   /*
56c4762a1bSJed Brown      Create distributed array (DMDA) to manage parallel grid and vectors
57c4762a1bSJed Brown   */
585f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_PERIODIC,N,1,1,NULL,&da));
595f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetFromOptions(da));
605f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(da));
61c4762a1bSJed Brown 
62c4762a1bSJed Brown   /*
63c4762a1bSJed Brown      Extract global and local vectors from DMDA; then duplicate for remaining
64c4762a1bSJed Brown      vectors that are the same types
65c4762a1bSJed Brown   */
665f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateGlobalVector(da,&x));
675f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDuplicate(x,&r));
68c4762a1bSJed Brown 
69c4762a1bSJed Brown   /*
70c4762a1bSJed Brown      Set function evaluation routine and vector.  Whenever the nonlinear
71c4762a1bSJed Brown      solver needs to compute the nonlinear function, it will call this
72c4762a1bSJed Brown      routine.
73c4762a1bSJed Brown       - Note that the final routine argument is the user-defined
74c4762a1bSJed Brown         context that provides application-specific data for the
75c4762a1bSJed Brown         function evaluation routine.
76c4762a1bSJed Brown   */
775f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetFunction(snes,r,FormFunction,da));
78c4762a1bSJed Brown 
79c4762a1bSJed Brown   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
80c4762a1bSJed Brown      Create matrix data structure; set Jacobian evaluation routine
81c4762a1bSJed Brown      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateMatrix(da,&J));
835f80ce2aSJacob Faibussowitsch   CHKERRQ(MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,0,NULL,&constants));
845f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetNullSpace(J,constants));
855f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetJacobian(snes,J,J,FormJacobian,da));
86c4762a1bSJed Brown 
875f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSetFromOptions(snes));
885f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESSolve(snes,NULL,x));
89c4762a1bSJed Brown 
905f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&x));
915f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&r));
925f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&J));
935f80ce2aSJacob Faibussowitsch   CHKERRQ(MatNullSpaceDestroy(&constants));
945f80ce2aSJacob Faibussowitsch   CHKERRQ(SNESDestroy(&snes));
955f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&da));
96*b122ec5aSJacob Faibussowitsch   CHKERRQ(PetscFinalize());
97*b122ec5aSJacob Faibussowitsch   return 0;
98c4762a1bSJed Brown }
99c4762a1bSJed Brown 
100c4762a1bSJed Brown /*
101c4762a1bSJed Brown    FormFunction - Evaluates nonlinear function, F(x).
102c4762a1bSJed Brown 
103c4762a1bSJed Brown    Input Parameters:
104c4762a1bSJed Brown .  snes - the SNES context
105c4762a1bSJed Brown .  x - input vector
106c4762a1bSJed Brown .  ctx - optional user-defined context, as set by SNESSetFunction()
107c4762a1bSJed Brown 
108c4762a1bSJed Brown    Output Parameter:
109c4762a1bSJed Brown .  f - function vector
110c4762a1bSJed Brown 
111c4762a1bSJed Brown    Note:
112c4762a1bSJed Brown    The user-defined context can contain any application-specific
113c4762a1bSJed Brown    data needed for the function evaluation.
114c4762a1bSJed Brown */
115c4762a1bSJed Brown PetscErrorCode FormFunction(SNES snes,Vec x,Vec f,void *ctx)
116c4762a1bSJed Brown {
117c4762a1bSJed Brown   DM             da    = (DM) ctx;
118c4762a1bSJed Brown   PetscScalar    *xx,*ff;
119c4762a1bSJed Brown   PetscReal      h;
120c4762a1bSJed Brown   PetscInt       i,M,xs,xm;
121c4762a1bSJed Brown   Vec            xlocal;
122c4762a1bSJed Brown 
123c4762a1bSJed Brown   PetscFunctionBeginUser;
124c4762a1bSJed Brown   /* Get local work vector */
1255f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalVector(da,&xlocal));
126c4762a1bSJed Brown 
127c4762a1bSJed Brown   /*
128c4762a1bSJed Brown      Scatter ghost points to local vector, using the 2-step process
129c4762a1bSJed Brown         DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
130c4762a1bSJed Brown      By placing code between these two statements, computations can
131c4762a1bSJed Brown      be done while messages are in transition.
132c4762a1bSJed Brown   */
1335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGlobalToLocalBegin(da,x,INSERT_VALUES,xlocal));
1345f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGlobalToLocalEnd(da,x,INSERT_VALUES,xlocal));
135c4762a1bSJed Brown 
136c4762a1bSJed Brown   /*
137c4762a1bSJed Brown      Get pointers to vector data.
138c4762a1bSJed Brown        - The vector xlocal includes ghost point; the vectors x and f do
139c4762a1bSJed Brown          NOT include ghost points.
140c4762a1bSJed Brown        - Using DMDAVecGetArray() allows accessing the values using global ordering
141c4762a1bSJed Brown   */
1425f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAVecGetArray(da,xlocal,&xx));
1435f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAVecGetArray(da,f,&ff));
144c4762a1bSJed Brown 
145c4762a1bSJed Brown   /*
146c4762a1bSJed Brown      Get local grid boundaries (for 1-dimensional DMDA):
147c4762a1bSJed Brown        xs, xm  - starting grid index, width of local grid (no ghost points)
148c4762a1bSJed Brown   */
1495f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL));
1505f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
151c4762a1bSJed Brown 
152c4762a1bSJed Brown   /*
153c4762a1bSJed Brown      Compute function over locally owned part of the grid
154c4762a1bSJed Brown      Note the [i-1] and [i+1] will automatically access the ghost points from other processes or the periodic points.
155c4762a1bSJed Brown   */
156c4762a1bSJed Brown   h = 1.0/M;
157c4762a1bSJed Brown   for (i=xs; i<xs+xm; i++) ff[i] = (xx[i-1] - 2.0*xx[i] + xx[i+1])/(h*h)  - PetscSinReal(2.0*PETSC_PI*i*h);
158c4762a1bSJed Brown 
159c4762a1bSJed Brown   /*
160c4762a1bSJed Brown      Restore vectors
161c4762a1bSJed Brown   */
1625f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAVecRestoreArray(da,xlocal,&xx));
1635f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAVecRestoreArray(da,f,&ff));
1645f80ce2aSJacob Faibussowitsch   CHKERRQ(DMRestoreLocalVector(da,&xlocal));
165c4762a1bSJed Brown   PetscFunctionReturn(0);
166c4762a1bSJed Brown }
167c4762a1bSJed Brown /* ------------------------------------------------------------------- */
168c4762a1bSJed Brown /*
169c4762a1bSJed Brown    FormJacobian - Evaluates Jacobian matrix.
170c4762a1bSJed Brown 
171c4762a1bSJed Brown    Input Parameters:
172c4762a1bSJed Brown .  snes - the SNES context
173c4762a1bSJed Brown .  x - input vector
174c4762a1bSJed Brown .  dummy - optional user-defined context (not used here)
175c4762a1bSJed Brown 
176c4762a1bSJed Brown    Output Parameters:
177c4762a1bSJed Brown .  jac - Jacobian matrix
178c4762a1bSJed Brown .  B - optionally different preconditioning matrix
179c4762a1bSJed Brown .  flag - flag indicating matrix structure
180c4762a1bSJed Brown */
181c4762a1bSJed Brown PetscErrorCode FormJacobian(SNES snes,Vec x,Mat jac,Mat B,void *ctx)
182c4762a1bSJed Brown {
183c4762a1bSJed Brown   PetscScalar    *xx,A[3];
184c4762a1bSJed Brown   PetscInt       i,M,xs,xm;
185c4762a1bSJed Brown   DM             da = (DM) ctx;
186c4762a1bSJed Brown   MatStencil     row,cols[3];
187c4762a1bSJed Brown   PetscReal      h;
188c4762a1bSJed Brown 
189c4762a1bSJed Brown   PetscFunctionBeginUser;
190c4762a1bSJed Brown   /*
191c4762a1bSJed Brown      Get pointer to vector data
192c4762a1bSJed Brown   */
1935f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAVecGetArrayRead(da,x,&xx));
1945f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetCorners(da,&xs,NULL,NULL,&xm,NULL,NULL));
195c4762a1bSJed Brown 
196c4762a1bSJed Brown   /*
197c4762a1bSJed Brown     Get range of locally owned matrix
198c4762a1bSJed Brown   */
1995f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAGetInfo(da,NULL,&M,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL));
200c4762a1bSJed Brown 
2015f80ce2aSJacob Faibussowitsch   CHKERRQ(MatZeroEntries(jac));
202c4762a1bSJed Brown   h = 1.0/M;
203c4762a1bSJed Brown   /* because of periodic boundary conditions we can simply loop over all local nodes and access to the left and right */
204c4762a1bSJed Brown   for (i=xs; i<xs+xm; i++) {
205c4762a1bSJed Brown     row.i = i;
206c4762a1bSJed Brown     cols[0].i = i - 1;
207c4762a1bSJed Brown     cols[1].i = i;
208c4762a1bSJed Brown     cols[2].i = i + 1;
209c4762a1bSJed Brown     A[0] = A[2] = 1.0/(h*h); A[1] = -2.0/(h*h);
2105f80ce2aSJacob Faibussowitsch     CHKERRQ(MatSetValuesStencil(jac,1,&row,3,cols,A,ADD_VALUES));
211c4762a1bSJed Brown   }
212c4762a1bSJed Brown 
2135f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDAVecRestoreArrayRead(da,x,&xx));
2145f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY));
2155f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY));
216c4762a1bSJed Brown   PetscFunctionReturn(0);
217c4762a1bSJed Brown }
218c4762a1bSJed Brown 
219c4762a1bSJed Brown /*TEST
220c4762a1bSJed Brown 
221c4762a1bSJed Brown    test:
222c4762a1bSJed Brown       args: -snes_monitor_short -ksp_monitor_short -pc_type sor -snes_converged_reason -da_refine 3
223c4762a1bSJed Brown       requires: !single
224c4762a1bSJed Brown 
22541ba4c6cSHeeho Park    test:
22641ba4c6cSHeeho Park       suffix: 2
22741ba4c6cSHeeho Park       args: -snes_monitor_short -ksp_monitor_short -pc_type sor -snes_converged_reason -da_refine 3 -snes_type newtontrdc
22841ba4c6cSHeeho Park       requires: !single
22941ba4c6cSHeeho Park 
23041ba4c6cSHeeho Park    test:
23141ba4c6cSHeeho Park       suffix: 3
23241ba4c6cSHeeho Park       args: -snes_monitor_short -ksp_monitor_short -pc_type sor -snes_converged_reason -da_refine 3 -snes_type newtontrdc -snes_trdc_use_cauchy false
23341ba4c6cSHeeho Park       requires: !single
23441ba4c6cSHeeho Park 
235c4762a1bSJed Brown TEST*/
236