xref: /petsc/src/snes/tutorials/ex73f90t.F90 (revision bef158480efac06de457f7a665168877ab3c2fd7)
1!
2!  Description: Solves a nonlinear system in parallel with SNES.
3!  We solve the  Bratu (SFI - solid fuel ignition) problem in a 2D rectangular
4!  domain, using distributed arrays (DMDAs) to partition the parallel grid.
5!  The command line options include:
6!    -par <parameter>, where <parameter> indicates the nonlinearity of the problem
7!       problem SFI:  <parameter> = Bratu parameter (0 <= par <= 6.81)
8!
9!  This system (A) is augmented with constraints:
10!
11!    A -B   *  phi  =  rho
12!   -C  I      lam  = 0
13!
14!  where I is the identity, A is the "normal" Poisson equation, B is the "distributor" of the
15!  total flux (the first block equation is the flux surface averaging equation).  The second
16!  equation  lambda = C * x enforces the surface flux auxiliary equation.  B and C have all
17!  positive entries, areas in C and fraction of area in B.
18!
19!!/*T
20!  Concepts: SNES^parallel Bratu example
21!  Concepts: MatNest
22!  Processors: n
23!T*/
24
25
26!
27!  --------------------------------------------------------------------------
28!
29!  Solid Fuel Ignition (SFI) problem.  This problem is modeled by
30!  the partial differential equation
31!
32!          -Laplacian u - lambda*exp(u) = 0,  0 < x,y < 1,
33!
34!  with boundary conditions
35!
36!           u = 0  for  x = 0, x = 1, y = 0, y = 1.
37!
38!  A finite difference approximation with the usual 5-point stencil
39!  is used to discretize the boundary value problem to obtain a nonlinear
40!  system of equations.
41!
42!  --------------------------------------------------------------------------
43!  The following define must be used before including any PETSc include files
44!  into a module or interface. This is because they can't handle declarations
45!  in them
46!
47      module petsc_kkt_solver
48#include <petsc/finclude/petscdm.h>
49#include <petsc/finclude/petscmat.h>
50      use petscdm
51      use petscmat
52      type petsc_kkt_solver_type
53        DM::da
54!     temp A block stuff
55        PetscInt mx,my
56        PetscMPIInt rank
57        PetscReal lambda
58!     Mats
59        Mat::Amat,AmatLin,Bmat,CMat,Dmat
60        IS::isPhi,isLambda
61      end type petsc_kkt_solver_type
62
63      end module petsc_kkt_solver
64
65      module petsc_kkt_solver_interfaces
66        use petsc_kkt_solver
67
68      Interface SNESSetApplicationContext
69        Subroutine SNESSetApplicationContext(snesIn,ctx,ierr)
70#include <petsc/finclude/petscsnes.h>
71        use petscsnes
72        use petsc_kkt_solver
73          SNES::    snesIn
74          type(petsc_kkt_solver_type) ctx
75          PetscErrorCode ierr
76        End Subroutine
77      End Interface SNESSetApplicationContext
78
79      Interface SNESGetApplicationContext
80        Subroutine SNESGetApplicationContext(snesIn,ctx,ierr)
81#include <petsc/finclude/petscsnes.h>
82        use petscsnes
83        use petsc_kkt_solver
84          SNES::     snesIn
85          type(petsc_kkt_solver_type), pointer :: ctx
86          PetscErrorCode ierr
87        End Subroutine
88      End Interface SNESGetApplicationContext
89      end module petsc_kkt_solver_interfaces
90
91      program main
92#include <petsc/finclude/petscdm.h>
93#include <petsc/finclude/petscsnes.h>
94      use petscdm
95      use petscdmda
96      use petscsnes
97      use petsc_kkt_solver
98      use petsc_kkt_solver_interfaces
99      implicit none
100! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
101!                   Variable declarations
102! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
103!
104!  Variables:
105!     mysnes      - nonlinear solver
106!     x, r        - solution, residual vectors
107!     J           - Jacobian matrix
108!     its         - iterations for convergence
109!     Nx, Ny      - number of preocessors in x- and y- directions
110!
111      SNES::       mysnes
112      Vec::        x,r,x2,x1,x1loc,x2loc
113      Mat::       Amat,Bmat,Cmat,Dmat,KKTMat,matArray(4)
114!      Mat::       tmat
115      DM::       daphi,dalam
116      IS::        isglobal(2)
117      PetscErrorCode   ierr
118      PetscInt         its,N1,N2,i,j,irow,row(1)
119      PetscInt         col(1),low,high,lamlow,lamhigh
120      PetscBool        flg
121      PetscInt         ione,nfour,itwo,nloc,nloclam
122      PetscReal lambda_max,lambda_min
123      type(petsc_kkt_solver_type)  solver
124      PetscScalar      bval(1),cval(1),one
125
126!  Note: Any user-defined Fortran routines (such as FormJacobian)
127!  MUST be declared as external.
128      external FormInitialGuess,FormJacobian,FormFunction
129
130! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
131!  Initialize program
132! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133      call PetscInitialize(PETSC_NULL_CHARACTER,ierr)
134     if (ierr .ne. 0) then
135         print*,'PetscInitialize failed'
136         stop
137      endif
138      call MPI_Comm_rank(PETSC_COMM_WORLD,solver%rank,ierr);CHKERRA(ierr)
139
140!  Initialize problem parameters
141      lambda_max  = 6.81_PETSC_REAL_KIND
142      lambda_min  = 0.0
143      solver%lambda = 6.0
144      ione = 1
145      nfour = 4
146      itwo = 2
147      call PetscOptionsGetReal(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-par', solver%lambda,flg,ierr);CHKERRA(ierr)
148      if (solver%lambda .ge. lambda_max .or. solver%lambda .lt. lambda_min) then; SETERRA(PETSC_COMM_SELF,PETSC_ERR_USER,'Lambda provided with -par is out of range'); endif
149
150! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
151!  Create vector data structures; set function evaluation routine
152! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
153
154!     just get size
155      call DMDACreate2d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE, DM_BOUNDARY_NONE,DMDA_STENCIL_BOX,nfour,nfour,PETSC_DECIDE,PETSC_DECIDE,ione,ione, &
156     &     PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,daphi,ierr);CHKERRA(ierr)
157      call DMSetFromOptions(daphi,ierr);CHKERRA(ierr)
158      call DMSetUp(daphi,ierr);CHKERRA(ierr)
159      call DMDAGetInfo(daphi,PETSC_NULL_INTEGER,solver%mx,solver%my,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,                        &
160     &                 PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,ierr);CHKERRA(ierr)
161      N1 = solver%my*solver%mx
162      N2 = solver%my
163      flg = .false.
164      call PetscOptionsGetBool(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-no_constraints',flg,flg,ierr);CHKERRA(ierr)
165      if (flg) then
166         N2 = 0
167      endif
168
169      call DMDestroy(daphi,ierr);CHKERRA(ierr)
170
171! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172!  Create matrix data structure; set Jacobian evaluation routine
173! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
174      call DMShellCreate(PETSC_COMM_WORLD,daphi,ierr);CHKERRA(ierr)
175      call DMSetOptionsPrefix(daphi,'phi_',ierr);CHKERRA(ierr)
176      call DMSetFromOptions(daphi,ierr);CHKERRA(ierr)
177
178      call VecCreate(PETSC_COMM_WORLD,x1,ierr);CHKERRA(ierr)
179      call VecSetSizes(x1,PETSC_DECIDE,N1,ierr);CHKERRA(ierr)
180      call VecSetFromOptions(x1,ierr);CHKERRA(ierr)
181
182      call VecGetOwnershipRange(x1,low,high,ierr);CHKERRA(ierr)
183      nloc = high - low
184
185      call MatCreate(PETSC_COMM_WORLD,Amat,ierr);CHKERRA(ierr)
186      call MatSetSizes(Amat,PETSC_DECIDE,PETSC_DECIDE,N1,N1,ierr);CHKERRA(ierr)
187      call MatSetUp(Amat,ierr);CHKERRA(ierr)
188
189      call MatCreate(PETSC_COMM_WORLD,solver%AmatLin,ierr);CHKERRA(ierr)
190      call MatSetSizes(solver%AmatLin,PETSC_DECIDE,PETSC_DECIDE,N1,N1,ierr);CHKERRA(ierr)
191      call MatSetUp(solver%AmatLin,ierr);CHKERRA(ierr)
192
193      call FormJacobianLocal(x1,solver%AmatLin,solver,.false.,ierr);CHKERRA(ierr)
194      call MatAssemblyBegin(solver%AmatLin,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
195      call MatAssemblyEnd(solver%AmatLin,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
196
197      call DMShellSetGlobalVector(daphi,x1,ierr);CHKERRA(ierr)
198      call DMShellSetMatrix(daphi,Amat,ierr);CHKERRA(ierr)
199
200      call VecCreate(PETSC_COMM_SELF,x1loc,ierr);CHKERRA(ierr)
201      call VecSetSizes(x1loc,nloc,nloc,ierr);CHKERRA(ierr)
202      call VecSetFromOptions(x1loc,ierr);CHKERRA(ierr)
203      call DMShellSetLocalVector(daphi,x1loc,ierr);CHKERRA(ierr)
204
205! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
206!  Create B, C, & D matrices
207! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
208      call MatCreate(PETSC_COMM_WORLD,Cmat,ierr);CHKERRA(ierr)
209      call MatSetSizes(Cmat,PETSC_DECIDE,PETSC_DECIDE,N2,N1,ierr);CHKERRA(ierr)
210      call MatSetUp(Cmat,ierr);CHKERRA(ierr)
211!      create data for C and B
212      call MatCreate(PETSC_COMM_WORLD,Bmat,ierr);CHKERRA(ierr)
213      call MatSetSizes(Bmat,PETSC_DECIDE,PETSC_DECIDE,N1,N2,ierr);CHKERRA(ierr)
214      call MatSetUp(Bmat,ierr);CHKERRA(ierr)
215!     create data for D
216      call MatCreate(PETSC_COMM_WORLD,Dmat,ierr);CHKERRA(ierr)
217      call MatSetSizes(Dmat,PETSC_DECIDE,PETSC_DECIDE,N2,N2,ierr);CHKERRA(ierr)
218      call MatSetUp(Dmat,ierr);CHKERRA(ierr)
219
220      call VecCreate(PETSC_COMM_WORLD,x2,ierr);CHKERRA(ierr)
221      call VecSetSizes(x2,PETSC_DECIDE,N2,ierr);CHKERRA(ierr)
222      call VecSetFromOptions(x2,ierr);CHKERRA(ierr)
223
224      call VecGetOwnershipRange(x2,lamlow,lamhigh,ierr);CHKERRA(ierr)
225      nloclam = lamhigh-lamlow
226
227! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
228!  Set fake B and C
229! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
230      one    = 1.0
231      if (N2 .gt. 0) then
232         bval(1) = -one/(solver%mx-2)
233!     cval = -one/(solver%my*solver%mx)
234         cval(1) = -one
235         do 20 irow=low,high-1
236            j = irow/solver%mx   ! row in domain
237            i = mod(irow,solver%mx)
238            row(1) = irow
239            col(1) = j
240            if (i .eq. 0 .or. j .eq. 0 .or. i .eq. solver%mx-1 .or. j .eq. solver%my-1) then
241               !     no op
242            else
243               call MatSetValues(Bmat,ione,row,ione,col,bval,INSERT_VALUES,ierr);CHKERRA(ierr)
244            endif
245            row(1) = j
246            call MatSetValues(Cmat,ione,row,ione,row,cval,INSERT_VALUES,ierr);CHKERRA(ierr)
247 20   continue
248      endif
249      call MatAssemblyBegin(Bmat,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
250      call MatAssemblyEnd(Bmat,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
251      call MatAssemblyBegin(Cmat,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
252      call MatAssemblyEnd(Cmat,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
253
254! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
255!  Set D (indentity)
256! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
257      do 30 j=lamlow,lamhigh-1
258         row(1) = j
259         cval(1) = one
260         call MatSetValues(Dmat,ione,row,ione,row,cval,INSERT_VALUES,ierr);CHKERRA(ierr)
261 30   continue
262      call MatAssemblyBegin(Dmat,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
263      call MatAssemblyEnd(Dmat,MAT_FINAL_ASSEMBLY,ierr);CHKERRA(ierr)
264
265! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
266!  DM for lambda (dalam) : temp driver for A block, setup A block solver data
267! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
268      call DMShellCreate(PETSC_COMM_WORLD,dalam,ierr);CHKERRA(ierr)
269      call DMShellSetGlobalVector(dalam,x2,ierr);CHKERRA(ierr)
270      call DMShellSetMatrix(dalam,Dmat,ierr);CHKERRA(ierr)
271
272      call VecCreate(PETSC_COMM_SELF,x2loc,ierr);CHKERRA(ierr)
273      call VecSetSizes(x2loc,nloclam,nloclam,ierr);CHKERRA(ierr)
274      call VecSetFromOptions(x2loc,ierr);CHKERRA(ierr)
275      call DMShellSetLocalVector(dalam,x2loc,ierr);CHKERRA(ierr)
276
277      call DMSetOptionsPrefix(dalam,'lambda_',ierr);CHKERRA(ierr)
278      call DMSetFromOptions(dalam,ierr);CHKERRA(ierr)
279! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
280!  Create field split DA
281! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
282      call DMCompositeCreate(PETSC_COMM_WORLD,solver%da,ierr);CHKERRA(ierr)
283      call DMCompositeAddDM(solver%da,daphi,ierr);CHKERRA(ierr)
284      call DMCompositeAddDM(solver%da,dalam,ierr);CHKERRA(ierr)
285      call DMSetFromOptions(solver%da,ierr);CHKERRA(ierr)
286      call DMSetUp(solver%da,ierr);CHKERRA(ierr)
287      call DMCompositeGetGlobalISs(solver%da,isglobal,ierr);CHKERRA(ierr)
288      solver%isPhi = isglobal(1)
289      solver%isLambda = isglobal(2)
290
291!     cache matrices
292      solver%Amat = Amat
293      solver%Bmat = Bmat
294      solver%Cmat = Cmat
295      solver%Dmat = Dmat
296
297      matArray(1) = Amat
298      matArray(2) = Bmat
299      matArray(3) = Cmat
300      matArray(4) = Dmat
301
302      call MatCreateNest(PETSC_COMM_WORLD,itwo,isglobal,itwo,isglobal,matArray,KKTmat,ierr);CHKERRA(ierr)
303      call MatSetFromOptions(KKTmat,ierr);CHKERRA(ierr)
304
305!  Extract global and local vectors from DMDA; then duplicate for remaining
306!     vectors that are the same types
307      call MatCreateVecs(KKTmat,x,PETSC_NULL_VEC,ierr);CHKERRA(ierr)
308      call VecDuplicate(x,r,ierr);CHKERRA(ierr)
309
310      call SNESCreate(PETSC_COMM_WORLD,mysnes,ierr);CHKERRA(ierr)
311
312      call SNESSetDM(mysnes,solver%da,ierr);CHKERRA(ierr)
313
314      call SNESSetApplicationContext(mysnes,solver,ierr);CHKERRA(ierr)
315
316      call SNESSetDM(mysnes,solver%da,ierr);CHKERRA(ierr)
317
318!  Set function evaluation routine and vector
319      call SNESSetFunction(mysnes,r,FormFunction,solver,ierr);CHKERRA(ierr)
320
321      call SNESSetJacobian(mysnes,KKTmat,KKTmat,FormJacobian,solver,ierr);CHKERRA(ierr)
322
323! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
324!  Customize nonlinear solver; set runtime options
325! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
326!  Set runtime options (e.g., -snes_monitor -snes_rtol <rtol> -ksp_type <type>)
327      call SNESSetFromOptions(mysnes,ierr);CHKERRA(ierr)
328
329! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330!  Evaluate initial guess; then solve nonlinear system.
331! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
332!  Note: The user should initialize the vector, x, with the initial guess
333!  for the nonlinear solver prior to calling SNESSolve().  In particular,
334!  to employ an initial guess of zero, the user should explicitly set
335!  this vector to zero by calling VecSet().
336
337      call FormInitialGuess(mysnes,x,ierr);CHKERRA(ierr)
338      call SNESSolve(mysnes,PETSC_NULL_VEC,x,ierr);CHKERRA(ierr)
339      call SNESGetIterationNumber(mysnes,its,ierr);CHKERRA(ierr)
340      if (solver%rank .eq. 0) then
341         write(6,100) its
342      endif
343  100 format('Number of SNES iterations = ',i5)
344
345! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
346!  Free work space.  All PETSc objects should be destroyed when they
347!  are no longer needed.
348! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
349      call MatDestroy(KKTmat,ierr);CHKERRA(ierr)
350      call MatDestroy(Amat,ierr);CHKERRA(ierr)
351      call MatDestroy(Dmat,ierr);CHKERRA(ierr)
352      call MatDestroy(Bmat,ierr);CHKERRA(ierr)
353      call MatDestroy(Cmat,ierr);CHKERRA(ierr)
354      call MatDestroy(solver%AmatLin,ierr);CHKERRA(ierr)
355      call ISDestroy(solver%isPhi,ierr);CHKERRA(ierr)
356      call ISDestroy(solver%isLambda,ierr);CHKERRA(ierr)
357      call VecDestroy(x,ierr);CHKERRA(ierr)
358      call VecDestroy(x2,ierr);CHKERRA(ierr)
359      call VecDestroy(x1,ierr);CHKERRA(ierr)
360      call VecDestroy(x1loc,ierr);CHKERRA(ierr)
361      call VecDestroy(x2loc,ierr);CHKERRA(ierr)
362      call VecDestroy(r,ierr);CHKERRA(ierr)
363      call SNESDestroy(mysnes,ierr);CHKERRA(ierr)
364      call DMDestroy(solver%da,ierr);CHKERRA(ierr)
365      call DMDestroy(daphi,ierr);CHKERRA(ierr)
366      call DMDestroy(dalam,ierr);CHKERRA(ierr)
367
368      call PetscFinalize(ierr)
369      end
370
371! ---------------------------------------------------------------------
372!
373!  FormInitialGuess - Forms initial approximation.
374!
375!  Input Parameters:
376!  X - vector
377!
378!  Output Parameter:
379!  X - vector
380!
381!  Notes:
382!  This routine serves as a wrapper for the lower-level routine
383!  "InitialGuessLocal", where the actual computations are
384!  done using the standard Fortran style of treating the local
385!  vector data as a multidimensional array over the local mesh.
386!  This routine merely handles ghost point scatters and accesses
387!  the local vector data via VecGetArrayF90() and VecRestoreArrayF90().
388!
389      subroutine FormInitialGuess(mysnes,Xnest,ierr)
390#include <petsc/finclude/petscsnes.h>
391      use petscsnes
392      use petsc_kkt_solver
393      use petsc_kkt_solver_interfaces
394      implicit none
395!  Input/output variables:
396      SNES::     mysnes
397      Vec::      Xnest
398      PetscErrorCode ierr
399
400!  Declarations for use with local arrays:
401      type(petsc_kkt_solver_type), pointer:: solver
402      Vec::      Xsub(2)
403      PetscInt::  izero,ione,itwo
404
405      izero = 0
406      ione = 1
407      itwo = 2
408      ierr = 0
409      call SNESGetApplicationContext(mysnes,solver,ierr);CHKERRQ(ierr)
410      call DMCompositeGetAccessArray(solver%da,Xnest,itwo,PETSC_NULL_INTEGER,Xsub,ierr);CHKERRQ(ierr)
411
412      call InitialGuessLocal(solver,Xsub(1),ierr);CHKERRQ(ierr)
413      call VecAssemblyBegin(Xsub(1),ierr);CHKERRQ(ierr)
414      call VecAssemblyEnd(Xsub(1),ierr);CHKERRQ(ierr)
415
416!     zero out lambda
417      call VecZeroEntries(Xsub(2),ierr);CHKERRQ(ierr)
418      call DMCompositeRestoreAccessArray(solver%da,Xnest,itwo,PETSC_NULL_INTEGER,Xsub,ierr);CHKERRQ(ierr)
419
420      return
421      end subroutine FormInitialGuess
422
423! ---------------------------------------------------------------------
424!
425!  InitialGuessLocal - Computes initial approximation, called by
426!  the higher level routine FormInitialGuess().
427!
428!  Input Parameter:
429!  X1 - local vector data
430!
431!  Output Parameters:
432!  x - local vector data
433!  ierr - error code
434!
435!  Notes:
436!  This routine uses standard Fortran-style computations over a 2-dim array.
437!
438      subroutine InitialGuessLocal(solver,X1,ierr)
439#include <petsc/finclude/petscsys.h>
440      use petscsys
441      use petsc_kkt_solver
442      implicit none
443!  Input/output variables:
444      type (petsc_kkt_solver_type)         solver
445      Vec::      X1
446      PetscErrorCode ierr
447
448!  Local variables:
449      PetscInt      row,i,j,ione,low,high
450      PetscReal   temp1,temp,hx,hy,v
451      PetscReal   one
452
453!  Set parameters
454      ione = 1
455      ierr   = 0
456      one    = 1.0
457      hx     = one/(solver%mx-1)
458      hy     = one/(solver%my-1)
459      temp1  = solver%lambda/(solver%lambda + one) + one
460
461      call VecGetOwnershipRange(X1,low,high,ierr);CHKERRQ(ierr)
462
463      do 20 row=low,high-1
464         j = row/solver%mx
465         i = mod(row,solver%mx)
466         temp = min(j,solver%my-j+1)*hy
467         if (i .eq. 0 .or. j .eq. 0  .or. i .eq. solver%mx-1 .or. j .eq. solver%my-1) then
468            v = 0.0
469         else
470            v = temp1 * sqrt(min(min(i,solver%mx-i+1)*hx,temp))
471         endif
472         call VecSetValues(X1,ione,row,v,INSERT_VALUES,ierr);CHKERRQ(ierr)
473 20   continue
474
475      return
476      end subroutine InitialGuessLocal
477
478
479! ---------------------------------------------------------------------
480!
481!  FormJacobian - Evaluates Jacobian matrix.
482!
483!  Input Parameters:
484!  dummy     - the SNES context
485!  x         - input vector
486!  solver    - solver data
487!
488!  Output Parameters:
489!  jac      - Jacobian matrix
490!  jac_prec - optionally different preconditioning matrix (not used here)
491!  flag     - flag indicating matrix structure
492!
493      subroutine FormJacobian(dummy,X,jac,jac_prec,solver,ierr)
494#include <petsc/finclude/petscsnes.h>
495      use petscsnes
496      use petsc_kkt_solver
497      implicit none
498!  Input/output variables:
499      SNES::     dummy
500      Vec::      X
501     Mat::     jac,jac_prec
502      type(petsc_kkt_solver_type)  solver
503      PetscErrorCode ierr
504
505!  Declarations for use with local arrays:
506      Vec::      Xsub(1)
507     Mat::     Amat
508      PetscInt       izero,ione
509
510      izero = 0
511      ione = 1
512
513      call DMCompositeGetAccessArray(solver%da,X,ione,PETSC_NULL_INTEGER,Xsub,ierr);CHKERRQ(ierr)
514
515!     Compute entries for the locally owned part of the Jacobian preconditioner.
516      call MatCreateSubMatrix(jac_prec,solver%isPhi,solver%isPhi,MAT_INITIAL_MATRIX,Amat,ierr);CHKERRQ(ierr)
517
518      call FormJacobianLocal(Xsub(1),Amat,solver,.true.,ierr);CHKERRQ(ierr)
519      call MatDestroy(Amat,ierr);CHKERRQ(ierr) ! discard our reference
520      call DMCompositeRestoreAccessArray(solver%da,X,ione,PETSC_NULL_INTEGER,Xsub,ierr);CHKERRQ(ierr)
521
522      ! the rest of the matrix is not touched
523      call MatAssemblyBegin(jac_prec,MAT_FINAL_ASSEMBLY,ierr);CHKERRQ(ierr)
524      call MatAssemblyEnd(jac_prec,MAT_FINAL_ASSEMBLY,ierr);CHKERRQ(ierr)
525      if (jac .ne. jac_prec) then
526         call MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY,ierr);CHKERRQ(ierr)
527         call MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY,ierr);CHKERRQ(ierr)
528      end if
529
530!     Tell the matrix we will never add a new nonzero location to the
531!     matrix. If we do it will generate an error.
532      call MatSetOption(jac_prec,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_TRUE,ierr);CHKERRQ(ierr)
533
534      return
535      end subroutine FormJacobian
536
537! ---------------------------------------------------------------------
538!
539!  FormJacobianLocal - Computes Jacobian preconditioner matrix,
540!  called by the higher level routine FormJacobian().
541!
542!  Input Parameters:
543!  x        - local vector data
544!
545!  Output Parameters:
546!  jac - Jacobian preconditioner matrix
547!  ierr     - error code
548!
549!  Notes:
550!  This routine uses standard Fortran-style computations over a 2-dim array.
551!
552      subroutine FormJacobianLocal(X1,jac,solver,add_nl_term,ierr)
553#include <petsc/finclude/petscmat.h>
554      use petscmat
555      use petsc_kkt_solver
556      implicit none
557!  Input/output variables:
558      type (petsc_kkt_solver_type) solver
559      Vec::      X1
560     Mat::     jac
561      logical        add_nl_term
562      PetscErrorCode ierr
563
564!  Local variables:
565      PetscInt    irow,row(1),col(5),i,j
566      PetscInt    ione,ifive,low,high,ii
567      PetscScalar two,one,hx,hy,hy2inv
568      PetscScalar hx2inv,sc,v(5)
569      PetscScalar,pointer :: lx_v(:)
570
571!  Set parameters
572      ione   = 1
573      ifive  = 5
574      one    = 1.0
575      two    = 2.0
576      hx     = one/(solver%mx-1)
577      hy     = one/(solver%my-1)
578      sc     = solver%lambda
579      hx2inv = one/(hx*hx)
580      hy2inv = one/(hy*hy)
581
582      call VecGetOwnershipRange(X1,low,high,ierr);CHKERRQ(ierr)
583      call VecGetArrayReadF90(X1,lx_v,ierr);CHKERRQ(ierr)
584
585      ii = 0
586      do 20 irow=low,high-1
587         j = irow/solver%mx
588         i = mod(irow,solver%mx)
589         ii = ii + 1            ! one based local index
590!     boundary points
591         if (i .eq. 0 .or. j .eq. 0 .or. i .eq. solver%mx-1 .or. j .eq. solver%my-1) then
592            col(1) = irow
593            row(1) = irow
594            v(1)   = one
595            call MatSetValues(jac,ione,row,ione,col,v,INSERT_VALUES,ierr);CHKERRQ(ierr)
596!     interior grid points
597         else
598            v(1) = -hy2inv
599            if (j-1==0) v(1) = 0.0
600            v(2) = -hx2inv
601            if (i-1==0) v(2) = 0.0
602            v(3) = two*(hx2inv + hy2inv)
603            if (add_nl_term) v(3) = v(3) - sc*exp(lx_v(ii))
604            v(4) = -hx2inv
605            if (i+1==solver%mx-1) v(4) = 0.0
606            v(5) = -hy2inv
607            if (j+1==solver%my-1) v(5) = 0.0
608            col(1) = irow - solver%mx
609            col(2) = irow - 1
610            col(3) = irow
611            col(4) = irow + 1
612            col(5) = irow + solver%mx
613            row(1) = irow
614            call MatSetValues(jac,ione,row,ifive,col,v,INSERT_VALUES,ierr);CHKERRQ(ierr)
615         endif
616 20   continue
617
618      call VecRestoreArrayReadF90(X1,lx_v,ierr);CHKERRQ(ierr)
619
620      return
621      end subroutine FormJacobianLocal
622
623
624! ---------------------------------------------------------------------
625!
626!  FormFunction - Evaluates nonlinear function, F(x).
627!
628!  Input Parameters:
629!  snes - the SNES context
630!  X - input vector
631!  dummy - optional user-defined context, as set by SNESSetFunction()
632!          (not used here)
633!
634!  Output Parameter:
635!  F - function vector
636!
637      subroutine FormFunction(snesIn,X,F,solver,ierr)
638#include <petsc/finclude/petscsnes.h>
639      use petscsnes
640      use petsc_kkt_solver
641      implicit none
642!  Input/output variables:
643      SNES::     snesIn
644     Vec::      X,F
645      PetscErrorCode ierr
646      type (petsc_kkt_solver_type) solver
647
648!  Declarations for use with local arrays:
649     Vec::              Xsub(2),Fsub(2)
650      PetscInt               izero,ione,itwo
651
652!  Scatter ghost points to local vector, using the 2-step process
653!     DMGlobalToLocalBegin(), DMGlobalToLocalEnd().
654!  By placing code between these two statements, computations can
655!  be done while messages are in transition.
656
657      izero = 0
658      ione = 1
659      itwo = 2
660      call DMCompositeGetAccessArray(solver%da,X,itwo,PETSC_NULL_INTEGER,Xsub,ierr);CHKERRQ(ierr)
661      call DMCompositeGetAccessArray(solver%da,F,itwo,PETSC_NULL_INTEGER,Fsub,ierr);CHKERRQ(ierr)
662
663      call FormFunctionNLTerm( Xsub(1), Fsub(1), solver, ierr);CHKERRQ(ierr)
664      call MatMultAdd( solver%AmatLin, Xsub(1), Fsub(1), Fsub(1), ierr);CHKERRQ(ierr)
665
666!     do rest of operator (linear)
667      call MatMult(    solver%Cmat, Xsub(1),      Fsub(2), ierr);CHKERRQ(ierr)
668      call MatMultAdd( solver%Bmat, Xsub(2), Fsub(1), Fsub(1), ierr);CHKERRQ(ierr)
669      call MatMultAdd( solver%Dmat, Xsub(2), Fsub(2), Fsub(2), ierr);CHKERRQ(ierr)
670
671      call DMCompositeRestoreAccessArray(solver%da,X,itwo,PETSC_NULL_INTEGER,Xsub,ierr);CHKERRQ(ierr)
672      call DMCompositeRestoreAccessArray(solver%da,F,itwo,PETSC_NULL_INTEGER,Fsub,ierr);CHKERRQ(ierr)
673      return
674      end subroutine formfunction
675
676
677! ---------------------------------------------------------------------
678!
679!  FormFunctionNLTerm - Computes nonlinear function, called by
680!  the higher level routine FormFunction().
681!
682!  Input Parameter:
683!  x - local vector data
684!
685!  Output Parameters:
686!  f - local vector data, f(x)
687!  ierr - error code
688!
689!  Notes:
690!  This routine uses standard Fortran-style computations over a 2-dim array.
691!
692      subroutine FormFunctionNLTerm(X1,F1,solver,ierr)
693#include <petsc/finclude/petscvec.h>
694      use petscvec
695      use petsc_kkt_solver
696      implicit none
697!  Input/output variables:
698      type (petsc_kkt_solver_type) solver
699     Vec::      X1,F1
700      PetscErrorCode ierr
701!  Local variables:
702      PetscScalar one,sc
703      PetscScalar u,v(1)
704      PetscInt  i,j,low,high,ii,ione,irow,row(1)
705      PetscScalar,pointer :: lx_v(:)
706
707      one    = 1.0
708      sc     = solver%lambda
709      ione   = 1
710
711      call VecGetArrayReadF90(X1,lx_v,ierr);CHKERRQ(ierr)
712      call VecGetOwnershipRange(X1,low,high,ierr);CHKERRQ(ierr)
713
714!     Compute function over the locally owned part of the grid
715      ii = 0
716      do 20 irow=low,high-1
717         j = irow/solver%mx
718         i = mod(irow,solver%mx)
719         ii = ii + 1            ! one based local index
720         row(1) = irow
721         if (i .eq. 0 .or. j .eq. 0 .or. i .eq. solver%mx-1 .or. j .eq. solver%my-1) then
722            v(1) = 0.0
723         else
724            u = lx_v(ii)
725            v(1) = -sc*exp(u)
726         endif
727         call VecSetValues(F1,ione,row,v,INSERT_VALUES,ierr);CHKERRQ(ierr)
728 20   continue
729
730      call VecRestoreArrayReadF90(X1,lx_v,ierr);CHKERRQ(ierr)
731
732      call VecAssemblyBegin(F1,ierr);CHKERRQ(ierr)
733      call VecAssemblyEnd(F1,ierr);CHKERRQ(ierr)
734
735      ierr = 0
736      return
737      end subroutine FormFunctionNLTerm
738
739!/*TEST
740!
741!   build:
742!      requires: !single !pgf90_compiler !complex
743!
744!   test:
745!      nsize: 4
746!      args: -par 5.0 -da_grid_x 10 -da_grid_y 10 -snes_monitor_short -snes_linesearch_type basic -snes_converged_reason -ksp_type fgmres -ksp_norm_type unpreconditioned -pc_type fieldsplit -pc_fieldsplit_type schur -pc_fieldsplit_schur_fact_type upper -ksp_monitor_short -fieldsplit_lambda_ksp_type preonly -fieldsplit_lambda_pc_type jacobi -fieldsplit_phi_pc_type gamg -fieldsplit_phi_pc_gamg_agg_nsmooths 1 -fieldsplit_phi_pc_gamg_threshold 0. -fieldsplit_phi_pc_gamg_esteig_ksp_type cg
747!
748!TEST*/
749