xref: /petsc/src/snes/tutorials/ex5f.F90 (revision e7a95102f46630f317be643b805dc1c3f4655aeb)
1c4762a1bSJed Brown!
242ce371bSBarry Smith!  This example shows how to avoid Fortran line lengths larger than 132 characters.
3dcb3e689SBarry Smith!  It avoids used of certain macros such as PetscCallA() and PetscCheckA() that
4dcb3e689SBarry Smith!  generate very long lines
5dcb3e689SBarry Smith!
642ce371bSBarry Smith!  We recommend starting from src/snes/tutorials/ex5f90.F90 instead of this example
7dcb3e689SBarry Smith!  because that does not have the restricted formatting that makes this version
8dcb3e689SBarry Smith!  more difficult to read
942ce371bSBarry Smith!
10c4762a1bSJed Brown!  Description: This example solves a nonlinear system in parallel with SNES.
11c4762a1bSJed Brown!  We solve the  Bratu (SFI - solid fuel ignition) problem in a 2D rectangular
12c4762a1bSJed Brown!  domain, using distributed arrays (DMDAs) to partition the parallel grid.
13c4762a1bSJed Brown!  The command line options include:
14c4762a1bSJed Brown!    -par <param>, where <param> indicates the nonlinearity of the problem
15c4762a1bSJed Brown!       problem SFI:  <parameter> = Bratu parameter (0 <= par <= 6.81)
16c4762a1bSJed Brown!
17c4762a1bSJed Brown!  --------------------------------------------------------------------------
18c4762a1bSJed Brown!
19c4762a1bSJed Brown!  Solid Fuel Ignition (SFI) problem.  This problem is modeled by
20c4762a1bSJed Brown!  the partial differential equation
21c4762a1bSJed Brown!
22c4762a1bSJed Brown!          -Laplacian u - lambda*exp(u) = 0,  0 < x,y < 1,
23c4762a1bSJed Brown!
24c4762a1bSJed Brown!  with boundary conditions
25c4762a1bSJed Brown!
26c4762a1bSJed Brown!           u = 0  for  x = 0, x = 1, y = 0, y = 1.
27c4762a1bSJed Brown!
28c4762a1bSJed Brown!  A finite difference approximation with the usual 5-point stencil
29c4762a1bSJed Brown!  is used to discretize the boundary value problem to obtain a nonlinear
30c4762a1bSJed Brown!  system of equations.
31c4762a1bSJed Brown!
32c4762a1bSJed Brown!  --------------------------------------------------------------------------
33c5e229c2SMartin Diehl#include <petsc/finclude/petscsnes.h>
34c5e229c2SMartin Diehl#include <petsc/finclude/petscdmda.h>
35*e7a95102SMartin Diehlmodule ex5f_mod
36dfbbaf82SBarry Smith  use petscsnes
37dfbbaf82SBarry Smith  use petscdmda
38*e7a95102SMartin Diehl  implicit none
39dfbbaf82SBarry Smith  PetscInt xs, xe, xm, gxs, gxe, gxm
40dfbbaf82SBarry Smith  PetscInt ys, ye, ym, gys, gye, gym
41dfbbaf82SBarry Smith  PetscInt mx, my
42dfbbaf82SBarry Smith  PetscMPIInt rank, size
43dfbbaf82SBarry Smith  PetscReal lambda
44*e7a95102SMartin Diehlcontains
45*e7a95102SMartin Diehl! ---------------------------------------------------------------------
46*e7a95102SMartin Diehl!
47*e7a95102SMartin Diehl!  FormInitialGuess - Forms initial approximation.
48*e7a95102SMartin Diehl!
49*e7a95102SMartin Diehl!  Input Parameters:
50*e7a95102SMartin Diehl!  X - vector
51*e7a95102SMartin Diehl!
52*e7a95102SMartin Diehl!  Output Parameter:
53*e7a95102SMartin Diehl!  X - vector
54*e7a95102SMartin Diehl!
55*e7a95102SMartin Diehl!  Notes:
56*e7a95102SMartin Diehl!  This routine serves as a wrapper for the lower-level routine
57*e7a95102SMartin Diehl!  "ApplicationInitialGuess", where the actual computations are
58*e7a95102SMartin Diehl!  done using the standard Fortran style of treating the local
59*e7a95102SMartin Diehl!  vector data as a multidimensional array over the local mesh.
60*e7a95102SMartin Diehl!  This routine merely handles ghost point scatters and accesses
61*e7a95102SMartin Diehl!  the local vector data via VecGetArray() and VecRestoreArray().
62*e7a95102SMartin Diehl!
63*e7a95102SMartin Diehl  subroutine FormInitialGuess(X, ierr)
64*e7a95102SMartin Diehl
65*e7a95102SMartin Diehl!  Input/output variables:
66*e7a95102SMartin Diehl    Vec X
67*e7a95102SMartin Diehl    PetscErrorCode ierr
68*e7a95102SMartin Diehl!  Declarations for use with local arrays:
69*e7a95102SMartin Diehl    PetscScalar, pointer :: lx_v(:)
70*e7a95102SMartin Diehl
71*e7a95102SMartin Diehl    ierr = 0
72*e7a95102SMartin Diehl
73*e7a95102SMartin Diehl!  Get a pointer to vector data.
74*e7a95102SMartin Diehl!    - For default PETSc vectors, VecGetArray() returns a pointer to
75*e7a95102SMartin Diehl!      the data array.  Otherwise, the routine is implementation dependent.
76*e7a95102SMartin Diehl!    - You MUST call VecRestoreArray() when you no longer need access to
77*e7a95102SMartin Diehl!      the array.
78*e7a95102SMartin Diehl!    - Note that the Fortran interface to VecGetArray() differs from the
79*e7a95102SMartin Diehl!      C version.  See the users manual for details.
80*e7a95102SMartin Diehl
81*e7a95102SMartin Diehl    call VecGetArray(X, lx_v, ierr)
82*e7a95102SMartin Diehl    CHKERRQ(ierr)
83*e7a95102SMartin Diehl
84*e7a95102SMartin Diehl!  Compute initial guess over the locally owned part of the grid
85*e7a95102SMartin Diehl
86*e7a95102SMartin Diehl    call InitialGuessLocal(lx_v, ierr)
87*e7a95102SMartin Diehl    CHKERRQ(ierr)
88*e7a95102SMartin Diehl
89*e7a95102SMartin Diehl!  Restore vector
90*e7a95102SMartin Diehl
91*e7a95102SMartin Diehl    call VecRestoreArray(X, lx_v, ierr)
92*e7a95102SMartin Diehl    CHKERRQ(ierr)
93*e7a95102SMartin Diehl
94*e7a95102SMartin Diehl  end
95*e7a95102SMartin Diehl
96*e7a95102SMartin Diehl! ---------------------------------------------------------------------
97*e7a95102SMartin Diehl!
98*e7a95102SMartin Diehl!  InitialGuessLocal - Computes initial approximation, called by
99*e7a95102SMartin Diehl!  the higher level routine FormInitialGuess().
100*e7a95102SMartin Diehl!
101*e7a95102SMartin Diehl!  Input Parameter:
102*e7a95102SMartin Diehl!  x - local vector data
103*e7a95102SMartin Diehl!
104*e7a95102SMartin Diehl!  Output Parameters:
105*e7a95102SMartin Diehl!  x - local vector data
106*e7a95102SMartin Diehl!  ierr - error code
107*e7a95102SMartin Diehl!
108*e7a95102SMartin Diehl!  Notes:
109*e7a95102SMartin Diehl!  This routine uses standard Fortran-style computations over a 2-dim array.
110*e7a95102SMartin Diehl!
111*e7a95102SMartin Diehl  subroutine InitialGuessLocal(x, ierr)
112*e7a95102SMartin Diehl
113*e7a95102SMartin Diehl!  Input/output variables:
114*e7a95102SMartin Diehl    PetscScalar x(xs:xe, ys:ye)
115*e7a95102SMartin Diehl    PetscErrorCode ierr
116*e7a95102SMartin Diehl
117*e7a95102SMartin Diehl!  Local variables:
118*e7a95102SMartin Diehl    PetscInt i, j
119*e7a95102SMartin Diehl    PetscReal temp1, temp, one, hx, hy
120*e7a95102SMartin Diehl
121*e7a95102SMartin Diehl!  Set parameters
122*e7a95102SMartin Diehl
123*e7a95102SMartin Diehl    ierr = 0
124*e7a95102SMartin Diehl    one = 1.0
125*e7a95102SMartin Diehl    hx = one/((real(mx) - 1))
126*e7a95102SMartin Diehl    hy = one/((real(my) - 1))
127*e7a95102SMartin Diehl    temp1 = lambda/(lambda + one)
128*e7a95102SMartin Diehl
129*e7a95102SMartin Diehl    do j = ys, ye
130*e7a95102SMartin Diehl      temp = (real(min(j - 1, my - j)))*hy
131*e7a95102SMartin Diehl      do i = xs, xe
132*e7a95102SMartin Diehl        if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
133*e7a95102SMartin Diehl          x(i, j) = 0.0
134*e7a95102SMartin Diehl        else
135*e7a95102SMartin Diehl          x(i, j) = temp1*sqrt(min(real(min(i - 1, mx - i))*hx, (temp)))
136*e7a95102SMartin Diehl        end if
137*e7a95102SMartin Diehl      end do
138*e7a95102SMartin Diehl    end do
139*e7a95102SMartin Diehl
140*e7a95102SMartin Diehl  end
141*e7a95102SMartin Diehl
142*e7a95102SMartin Diehl! ---------------------------------------------------------------------
143*e7a95102SMartin Diehl!
144*e7a95102SMartin Diehl!  FormFunctionLocal - Computes nonlinear function, called by
145*e7a95102SMartin Diehl!  the higher level routine FormFunction().
146*e7a95102SMartin Diehl!
147*e7a95102SMartin Diehl!  Input Parameter:
148*e7a95102SMartin Diehl!  x - local vector data
149*e7a95102SMartin Diehl!
150*e7a95102SMartin Diehl!  Output Parameters:
151*e7a95102SMartin Diehl!  f - local vector data, f(x)
152*e7a95102SMartin Diehl!  ierr - error code
153*e7a95102SMartin Diehl!
154*e7a95102SMartin Diehl!  Notes:
155*e7a95102SMartin Diehl!  This routine uses standard Fortran-style computations over a 2-dim array.
156*e7a95102SMartin Diehl!
157*e7a95102SMartin Diehl!
158*e7a95102SMartin Diehl  subroutine FormFunctionLocal(info, x, f, da, ierr)
159*e7a95102SMartin Diehl
160*e7a95102SMartin Diehl    DM da
161*e7a95102SMartin Diehl
162*e7a95102SMartin Diehl!  Input/output variables:
163*e7a95102SMartin Diehl    DMDALocalInfo info
164*e7a95102SMartin Diehl    PetscScalar x(gxs:gxe, gys:gye)
165*e7a95102SMartin Diehl    PetscScalar f(xs:xe, ys:ye)
166*e7a95102SMartin Diehl    PetscErrorCode ierr
167*e7a95102SMartin Diehl
168*e7a95102SMartin Diehl!  Local variables:
169*e7a95102SMartin Diehl    PetscScalar two, one, hx, hy
170*e7a95102SMartin Diehl    PetscScalar hxdhy, hydhx, sc
171*e7a95102SMartin Diehl    PetscScalar u, uxx, uyy
172*e7a95102SMartin Diehl    PetscInt i, j
173*e7a95102SMartin Diehl
174*e7a95102SMartin Diehl    xs = info%XS + 1
175*e7a95102SMartin Diehl    xe = xs + info%XM - 1
176*e7a95102SMartin Diehl    ys = info%YS + 1
177*e7a95102SMartin Diehl    ye = ys + info%YM - 1
178*e7a95102SMartin Diehl    mx = info%MX
179*e7a95102SMartin Diehl    my = info%MY
180*e7a95102SMartin Diehl
181*e7a95102SMartin Diehl    one = 1.0
182*e7a95102SMartin Diehl    two = 2.0
183*e7a95102SMartin Diehl    hx = one/(real(mx) - 1)
184*e7a95102SMartin Diehl    hy = one/(real(my) - 1)
185*e7a95102SMartin Diehl    sc = hx*hy*lambda
186*e7a95102SMartin Diehl    hxdhy = hx/hy
187*e7a95102SMartin Diehl    hydhx = hy/hx
188*e7a95102SMartin Diehl
189*e7a95102SMartin Diehl!  Compute function over the locally owned part of the grid
190*e7a95102SMartin Diehl
191*e7a95102SMartin Diehl    do j = ys, ye
192*e7a95102SMartin Diehl      do i = xs, xe
193*e7a95102SMartin Diehl        if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
194*e7a95102SMartin Diehl          f(i, j) = x(i, j)
195*e7a95102SMartin Diehl        else
196*e7a95102SMartin Diehl          u = x(i, j)
197*e7a95102SMartin Diehl          uxx = hydhx*(two*u - x(i - 1, j) - x(i + 1, j))
198*e7a95102SMartin Diehl          uyy = hxdhy*(two*u - x(i, j - 1) - x(i, j + 1))
199*e7a95102SMartin Diehl          f(i, j) = uxx + uyy - sc*exp(u)
200*e7a95102SMartin Diehl        end if
201*e7a95102SMartin Diehl      end do
202*e7a95102SMartin Diehl    end do
203*e7a95102SMartin Diehl
204*e7a95102SMartin Diehl    call PetscLogFlops(11.0d0*ym*xm, ierr)
205*e7a95102SMartin Diehl    CHKERRQ(ierr)
206*e7a95102SMartin Diehl
207*e7a95102SMartin Diehl  end
208*e7a95102SMartin Diehl
209*e7a95102SMartin Diehl! ---------------------------------------------------------------------
210*e7a95102SMartin Diehl!
211*e7a95102SMartin Diehl!  FormJacobianLocal - Computes Jacobian matrix, called by
212*e7a95102SMartin Diehl!  the higher level routine FormJacobian().
213*e7a95102SMartin Diehl!
214*e7a95102SMartin Diehl!  Input Parameters:
215*e7a95102SMartin Diehl!  x        - local vector data
216*e7a95102SMartin Diehl!
217*e7a95102SMartin Diehl!  Output Parameters:
218*e7a95102SMartin Diehl!  jac      - Jacobian matrix
219*e7a95102SMartin Diehl!  jac_prec - optionally different matrix used to construct the preconditioner (not used here)
220*e7a95102SMartin Diehl!  ierr     - error code
221*e7a95102SMartin Diehl!
222*e7a95102SMartin Diehl!  Notes:
223*e7a95102SMartin Diehl!  This routine uses standard Fortran-style computations over a 2-dim array.
224*e7a95102SMartin Diehl!
225*e7a95102SMartin Diehl!  Notes:
226*e7a95102SMartin Diehl!  Due to grid point reordering with DMDAs, we must always work
227*e7a95102SMartin Diehl!  with the local grid points, and then transform them to the new
228*e7a95102SMartin Diehl!  global numbering with the "ltog" mapping
229*e7a95102SMartin Diehl!  We cannot work directly with the global numbers for the original
230*e7a95102SMartin Diehl!  uniprocessor grid!
231*e7a95102SMartin Diehl!
232*e7a95102SMartin Diehl!  Two methods are available for imposing this transformation
233*e7a95102SMartin Diehl!  when setting matrix entries:
234*e7a95102SMartin Diehl!    (A) MatSetValuesLocal(), using the local ordering (including
235*e7a95102SMartin Diehl!        ghost points!)
236*e7a95102SMartin Diehl!          by calling MatSetValuesLocal()
237*e7a95102SMartin Diehl!    (B) MatSetValues(), using the global ordering
238*e7a95102SMartin Diehl!        - Use DMDAGetGlobalIndices() to extract the local-to-global map
239*e7a95102SMartin Diehl!        - Then apply this map explicitly yourself
240*e7a95102SMartin Diehl!        - Set matrix entries using the global ordering by calling
241*e7a95102SMartin Diehl!          MatSetValues()
242*e7a95102SMartin Diehl!  Option (A) seems cleaner/easier in many cases, and is the procedure
243*e7a95102SMartin Diehl!  used in this example.
244*e7a95102SMartin Diehl!
245*e7a95102SMartin Diehl  subroutine FormJacobianLocal(info, x, A, jac, da, ierr)
246*e7a95102SMartin Diehl
247*e7a95102SMartin Diehl    DM da
248*e7a95102SMartin Diehl
249*e7a95102SMartin Diehl!  Input/output variables:
250*e7a95102SMartin Diehl    PetscScalar x(gxs:gxe, gys:gye)
251*e7a95102SMartin Diehl    Mat A, jac
252*e7a95102SMartin Diehl    PetscErrorCode ierr
253*e7a95102SMartin Diehl    DMDALocalInfo info
254*e7a95102SMartin Diehl
255*e7a95102SMartin Diehl!  Local variables:
256*e7a95102SMartin Diehl    PetscInt row, col(5), i, j, i1, i5
257*e7a95102SMartin Diehl    PetscScalar two, one, hx, hy, v(5)
258*e7a95102SMartin Diehl    PetscScalar hxdhy, hydhx, sc
259*e7a95102SMartin Diehl
260*e7a95102SMartin Diehl!  Set parameters
261*e7a95102SMartin Diehl
262*e7a95102SMartin Diehl    i1 = 1
263*e7a95102SMartin Diehl    i5 = 5
264*e7a95102SMartin Diehl    one = 1.0
265*e7a95102SMartin Diehl    two = 2.0
266*e7a95102SMartin Diehl    hx = one/(real(mx) - 1)
267*e7a95102SMartin Diehl    hy = one/(real(my) - 1)
268*e7a95102SMartin Diehl    sc = hx*hy
269*e7a95102SMartin Diehl    hxdhy = hx/hy
270*e7a95102SMartin Diehl    hydhx = hy/hx
271*e7a95102SMartin Diehl! -Wmaybe-uninitialized
272*e7a95102SMartin Diehl    v = 0.0
273*e7a95102SMartin Diehl    col = 0
274*e7a95102SMartin Diehl
275*e7a95102SMartin Diehl!  Compute entries for the locally owned part of the Jacobian.
276*e7a95102SMartin Diehl!   - Currently, all PETSc parallel matrix formats are partitioned by
277*e7a95102SMartin Diehl!     contiguous chunks of rows across the processors.
278*e7a95102SMartin Diehl!   - Each processor needs to insert only elements that it owns
279*e7a95102SMartin Diehl!     locally (but any non-local elements will be sent to the
280*e7a95102SMartin Diehl!     appropriate processor during matrix assembly).
281*e7a95102SMartin Diehl!   - Here, we set all entries for a particular row at once.
282*e7a95102SMartin Diehl!   - We can set matrix entries either using either
283*e7a95102SMartin Diehl!     MatSetValuesLocal() or MatSetValues(), as discussed above.
284*e7a95102SMartin Diehl!   - Note that MatSetValues() uses 0-based row and column numbers
285*e7a95102SMartin Diehl!     in Fortran as well as in C.
286*e7a95102SMartin Diehl
287*e7a95102SMartin Diehl    do j = ys, ye
288*e7a95102SMartin Diehl      row = (j - gys)*gxm + xs - gxs - 1
289*e7a95102SMartin Diehl      do i = xs, xe
290*e7a95102SMartin Diehl        row = row + 1
291*e7a95102SMartin Diehl!           boundary points
292*e7a95102SMartin Diehl        if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
293*e7a95102SMartin Diehl!       Some f90 compilers need 4th arg to be of same type in both calls
294*e7a95102SMartin Diehl          col(1) = row
295*e7a95102SMartin Diehl          v(1) = one
296*e7a95102SMartin Diehl          call MatSetValuesLocal(jac, i1, [row], i1, [col], [v], INSERT_VALUES, ierr)
297*e7a95102SMartin Diehl          CHKERRQ(ierr)
298*e7a95102SMartin Diehl!           interior grid points
299*e7a95102SMartin Diehl        else
300*e7a95102SMartin Diehl          v(1) = -hxdhy
301*e7a95102SMartin Diehl          v(2) = -hydhx
302*e7a95102SMartin Diehl          v(3) = two*(hydhx + hxdhy) - sc*lambda*exp(x(i, j))
303*e7a95102SMartin Diehl          v(4) = -hydhx
304*e7a95102SMartin Diehl          v(5) = -hxdhy
305*e7a95102SMartin Diehl          col(1) = row - gxm
306*e7a95102SMartin Diehl          col(2) = row - 1
307*e7a95102SMartin Diehl          col(3) = row
308*e7a95102SMartin Diehl          col(4) = row + 1
309*e7a95102SMartin Diehl          col(5) = row + gxm
310*e7a95102SMartin Diehl          call MatSetValuesLocal(jac, i1, [row], i5, [col], [v], INSERT_VALUES, ierr)
311*e7a95102SMartin Diehl          CHKERRQ(ierr)
312*e7a95102SMartin Diehl        end if
313*e7a95102SMartin Diehl      end do
314*e7a95102SMartin Diehl    end do
315*e7a95102SMartin Diehl    call MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY, ierr)
316*e7a95102SMartin Diehl    CHKERRQ(ierr)
317*e7a95102SMartin Diehl    call MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY, ierr)
318*e7a95102SMartin Diehl    CHKERRQ(ierr)
319*e7a95102SMartin Diehl    if (A /= jac) then
320*e7a95102SMartin Diehl      call MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY, ierr)
321*e7a95102SMartin Diehl      CHKERRQ(ierr)
322*e7a95102SMartin Diehl      call MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY, ierr)
323*e7a95102SMartin Diehl      CHKERRQ(ierr)
324*e7a95102SMartin Diehl    end if
325*e7a95102SMartin Diehl  end
326*e7a95102SMartin Diehl
327*e7a95102SMartin Diehl!
328*e7a95102SMartin Diehl!     Simple convergence test based on the infinity norm of the residual being small
329*e7a95102SMartin Diehl!
330*e7a95102SMartin Diehl  subroutine MySNESConverged(snes, it, xnorm, snorm, fnorm, reason, dummy, ierr)
331*e7a95102SMartin Diehl
332*e7a95102SMartin Diehl    SNES snes
333*e7a95102SMartin Diehl    PetscInt it, dummy
334*e7a95102SMartin Diehl    PetscReal xnorm, snorm, fnorm, nrm
335*e7a95102SMartin Diehl    SNESConvergedReason reason
336*e7a95102SMartin Diehl    Vec f
337*e7a95102SMartin Diehl    PetscErrorCode ierr
338*e7a95102SMartin Diehl
339*e7a95102SMartin Diehl    call SNESGetFunction(snes, f, PETSC_NULL_FUNCTION, dummy, ierr)
340*e7a95102SMartin Diehl    CHKERRQ(ierr)
341*e7a95102SMartin Diehl    call VecNorm(f, NORM_INFINITY, nrm, ierr)
342*e7a95102SMartin Diehl    CHKERRQ(ierr)
343*e7a95102SMartin Diehl    if (nrm <= 1.e-5) reason = SNES_CONVERGED_FNORM_ABS
344*e7a95102SMartin Diehl
345*e7a95102SMartin Diehl  end
346*e7a95102SMartin Diehl
347*e7a95102SMartin Diehlend module ex5f_mod
348c4762a1bSJed Brown
349c4762a1bSJed Brownprogram main
350*e7a95102SMartin Diehl  use ex5f_mod
351c4762a1bSJed Brown  implicit none
352c4762a1bSJed Brown
353c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
354c4762a1bSJed Brown!                   Variable declarations
355c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
356c4762a1bSJed Brown!
357c4762a1bSJed Brown!  Variables:
358c4762a1bSJed Brown!     snes        - nonlinear solver
359c4762a1bSJed Brown!     x, r        - solution, residual vectors
360c4762a1bSJed Brown!     its         - iterations for convergence
361c4762a1bSJed Brown!
362c4762a1bSJed Brown!  See additional variable declarations in the file ex5f.h
363c4762a1bSJed Brown!
364c4762a1bSJed Brown  SNES snes
365c4762a1bSJed Brown  Vec x, r
366c4762a1bSJed Brown  PetscInt its, i1, i4
367c4762a1bSJed Brown  PetscErrorCode ierr
368c4762a1bSJed Brown  PetscReal lambda_max, lambda_min
369c4762a1bSJed Brown  PetscBool flg
370c4762a1bSJed Brown  DM da
371c4762a1bSJed Brown
372c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
373c4762a1bSJed Brown!  Initialize program
374c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
375c4762a1bSJed Brown
37665afa91aSSatish Balay  call PetscInitialize(ierr)
37765afa91aSSatish Balay  CHKERRA(ierr)
37865afa91aSSatish Balay  call MPI_Comm_size(PETSC_COMM_WORLD, size, ierr)
37965afa91aSSatish Balay  CHKERRMPIA(ierr)
38065afa91aSSatish Balay  call MPI_Comm_rank(PETSC_COMM_WORLD, rank, ierr)
38165afa91aSSatish Balay  CHKERRMPIA(ierr)
382c4762a1bSJed Brown!  Initialize problem parameters
383c4762a1bSJed Brown
384c4762a1bSJed Brown  i1 = 1
385c4762a1bSJed Brown  i4 = 4
386c4762a1bSJed Brown  lambda_max = 6.81
387c4762a1bSJed Brown  lambda_min = 0.0
388c4762a1bSJed Brown  lambda = 6.0
38965afa91aSSatish Balay  call PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-par', lambda, PETSC_NULL_BOOL, ierr)
39065afa91aSSatish Balay  CHKERRA(ierr)
39165afa91aSSatish Balay
392c4762a1bSJed Brown! this statement is split into multiple-lines to keep lines under 132 char limit - required by 'make check'
3934820e4eaSBarry Smith  if (lambda >= lambda_max .or. lambda <= lambda_min) then
394ccfd86f1SBarry Smith    ierr = PETSC_ERR_ARG_OUTOFRANGE
395dcb3e689SBarry Smith    SETERRA(PETSC_COMM_WORLD, ierr, 'Lambda')
396c4762a1bSJed Brown  end if
397c4762a1bSJed Brown
398c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
399c4762a1bSJed Brown!  Create nonlinear solver context
400c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
401c4762a1bSJed Brown
40265afa91aSSatish Balay  call SNESCreate(PETSC_COMM_WORLD, snes, ierr)
40365afa91aSSatish Balay  CHKERRA(ierr)
404c4762a1bSJed Brown
405c4762a1bSJed Brown!  Set convergence test routine if desired
406c4762a1bSJed Brown
40765afa91aSSatish Balay  call PetscOptionsHasName(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-my_snes_convergence', flg, ierr)
40865afa91aSSatish Balay  CHKERRA(ierr)
409c4762a1bSJed Brown  if (flg) then
41065afa91aSSatish Balay    call SNESSetConvergenceTest(snes, MySNESConverged, 0, PETSC_NULL_FUNCTION, ierr)
41165afa91aSSatish Balay    CHKERRA(ierr)
412c4762a1bSJed Brown  end if
413c4762a1bSJed Brown
414c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
415c4762a1bSJed Brown!  Create vector data structures; set function evaluation routine
416c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
417c4762a1bSJed Brown
418c4762a1bSJed Brown!  Create distributed array (DMDA) to manage parallel grid and vectors
419c4762a1bSJed Brown
42042ce371bSBarry Smith!     This really needs only the star-type stencil, but we use the box stencil
42160cf0239SBarry Smith
42265afa91aSSatish Balay  call DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DMDA_STENCIL_STAR, i4, i4, PETSC_DECIDE, PETSC_DECIDE, &
4235d83a8b1SBarry Smith                    i1, i1, PETSC_NULL_INTEGER_ARRAY, PETSC_NULL_INTEGER_ARRAY, da, ierr)
42465afa91aSSatish Balay  CHKERRA(ierr)
42565afa91aSSatish Balay  call DMSetFromOptions(da, ierr)
42665afa91aSSatish Balay  CHKERRA(ierr)
42765afa91aSSatish Balay  call DMSetUp(da, ierr)
42865afa91aSSatish Balay  CHKERRA(ierr)
429c4762a1bSJed Brown
430c4762a1bSJed Brown!  Extract global and local vectors from DMDA; then duplicate for remaining
431c4762a1bSJed Brown!  vectors that are the same types
432c4762a1bSJed Brown
43365afa91aSSatish Balay  call DMCreateGlobalVector(da, x, ierr)
43465afa91aSSatish Balay  CHKERRA(ierr)
43565afa91aSSatish Balay  call VecDuplicate(x, r, ierr)
43665afa91aSSatish Balay  CHKERRA(ierr)
437c4762a1bSJed Brown
438c4762a1bSJed Brown!  Get local grid boundaries (for 2-dimensional DMDA)
439c4762a1bSJed Brown
44060cf0239SBarry Smith  call DMDAGetInfo(da, PETSC_NULL_INTEGER, mx, my, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, &
441ce78bad3SBarry Smith                   PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_DMBOUNDARYTYPE, PETSC_NULL_DMBOUNDARYTYPE, &
442ce78bad3SBarry Smith                   PETSC_NULL_DMBOUNDARYTYPE, PETSC_NULL_DMDASTENCILTYPE, ierr)
44365afa91aSSatish Balay  CHKERRA(ierr)
44465afa91aSSatish Balay  call DMDAGetCorners(da, xs, ys, PETSC_NULL_INTEGER, xm, ym, PETSC_NULL_INTEGER, ierr)
44565afa91aSSatish Balay  CHKERRA(ierr)
44665afa91aSSatish Balay  call DMDAGetGhostCorners(da, gxs, gys, PETSC_NULL_INTEGER, gxm, gym, PETSC_NULL_INTEGER, ierr)
44765afa91aSSatish Balay  CHKERRA(ierr)
448c4762a1bSJed Brown
449c4762a1bSJed Brown!  Here we shift the starting indices up by one so that we can easily
450c4762a1bSJed Brown!  use the Fortran convention of 1-based indices (rather 0-based indices).
451c4762a1bSJed Brown
452c4762a1bSJed Brown  xs = xs + 1
453c4762a1bSJed Brown  ys = ys + 1
454c4762a1bSJed Brown  gxs = gxs + 1
455c4762a1bSJed Brown  gys = gys + 1
456c4762a1bSJed Brown
457c4762a1bSJed Brown  ye = ys + ym - 1
458c4762a1bSJed Brown  xe = xs + xm - 1
459c4762a1bSJed Brown  gye = gys + gym - 1
460c4762a1bSJed Brown  gxe = gxs + gxm - 1
461c4762a1bSJed Brown
462c4762a1bSJed Brown!  Set function evaluation routine and vector
463c4762a1bSJed Brown
46465afa91aSSatish Balay  call DMDASNESSetFunctionLocal(da, INSERT_VALUES, FormFunctionLocal, da, ierr)
46565afa91aSSatish Balay  CHKERRA(ierr)
46665afa91aSSatish Balay  call DMDASNESSetJacobianLocal(da, FormJacobianLocal, da, ierr)
46765afa91aSSatish Balay  CHKERRA(ierr)
46865afa91aSSatish Balay  call SNESSetDM(snes, da, ierr)
46965afa91aSSatish Balay  CHKERRA(ierr)
470c4762a1bSJed Brown
471c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
472c4762a1bSJed Brown!  Customize nonlinear solver; set runtime options
473c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
474c4762a1bSJed Brown
475c4762a1bSJed Brown!  Set runtime options (e.g., -snes_monitor -snes_rtol <rtol> -ksp_type <type>)
476c4762a1bSJed Brown
47765afa91aSSatish Balay  call SNESSetFromOptions(snes, ierr)
47865afa91aSSatish Balay  CHKERRA(ierr)
479c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
480c4762a1bSJed Brown!  Evaluate initial guess; then solve nonlinear system.
481c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
482c4762a1bSJed Brown
483c4762a1bSJed Brown!  Note: The user should initialize the vector, x, with the initial guess
484c4762a1bSJed Brown!  for the nonlinear solver prior to calling SNESSolve().  In particular,
485c4762a1bSJed Brown!  to employ an initial guess of zero, the user should explicitly set
486c4762a1bSJed Brown!  this vector to zero by calling VecSet().
487c4762a1bSJed Brown
48865afa91aSSatish Balay  call FormInitialGuess(x, ierr)
48965afa91aSSatish Balay  CHKERRA(ierr)
49065afa91aSSatish Balay  call SNESSolve(snes, PETSC_NULL_VEC, x, ierr)
49165afa91aSSatish Balay  CHKERRA(ierr)
49265afa91aSSatish Balay  call SNESGetIterationNumber(snes, its, ierr)
49365afa91aSSatish Balay  CHKERRA(ierr)
4944820e4eaSBarry Smith  if (rank == 0) then
495c4762a1bSJed Brown    write (6, 100) its
496c4762a1bSJed Brown  end if
497c4762a1bSJed Brown100 format('Number of SNES iterations = ', i5)
498c4762a1bSJed Brown
499c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
500c4762a1bSJed Brown!  Free work space.  All PETSc objects should be destroyed when they
501c4762a1bSJed Brown!  are no longer needed.
502c4762a1bSJed Brown! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
503c4762a1bSJed Brown
50465afa91aSSatish Balay  call VecDestroy(x, ierr)
50565afa91aSSatish Balay  CHKERRA(ierr)
50665afa91aSSatish Balay  call VecDestroy(r, ierr)
50765afa91aSSatish Balay  CHKERRA(ierr)
50865afa91aSSatish Balay  call SNESDestroy(snes, ierr)
50965afa91aSSatish Balay  CHKERRA(ierr)
51065afa91aSSatish Balay  call DMDestroy(da, ierr)
51165afa91aSSatish Balay  CHKERRA(ierr)
51265afa91aSSatish Balay  call PetscFinalize(ierr)
51365afa91aSSatish Balay  CHKERRA(ierr)
514c4762a1bSJed Brownend
515c4762a1bSJed Brown!/*TEST
516c4762a1bSJed Brown!
517c4762a1bSJed Brown!   build:
518c4762a1bSJed Brown!      requires: !complex !single
519c4762a1bSJed Brown!
520c4762a1bSJed Brown!   test:
521c4762a1bSJed Brown!      nsize: 4
5228f8b3c79SStefano Zampini!      args: -snes_mf -pc_type none -da_processors_x 4 -da_processors_y 1 -snes_monitor_short \
5238f8b3c79SStefano Zampini!            -ksp_gmres_cgs_refinement_type refine_always
524c4762a1bSJed Brown!
525c4762a1bSJed Brown!   test:
526c4762a1bSJed Brown!      suffix: 2
527c4762a1bSJed Brown!      nsize: 4
528c4762a1bSJed Brown!      args: -da_processors_x 2 -da_processors_y 2 -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always
529c4762a1bSJed Brown!
530c4762a1bSJed Brown!   test:
531c4762a1bSJed Brown!      suffix: 3
532c4762a1bSJed Brown!      nsize: 3
533c4762a1bSJed Brown!      args: -snes_fd -snes_monitor_short -ksp_gmres_cgs_refinement_type refine_always
534c4762a1bSJed Brown!
535c4762a1bSJed Brown!   test:
536c4762a1bSJed Brown!      suffix: 6
537c4762a1bSJed Brown!      nsize: 1
538c4762a1bSJed Brown!      args: -snes_monitor_short -my_snes_convergence
539c4762a1bSJed Brown!
540c4762a1bSJed Brown!TEST*/
541