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