xref: /petsc/src/snes/tutorials/ex1f.F90 (revision bfe80ac4a46d58cb7760074b25f5e81b2f541d8a)
1!
2!  Description: Uses the Newton method to solve a two-variable system.
3!
4
5      program main
6#include <petsc/finclude/petsc.h>
7        use petsc
8      implicit none
9
10! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
11!                   Variable declarations
12! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13!
14!  Variables:
15!     snes        - nonlinear solver
16!     ksp        - linear solver
17!     pc          - preconditioner context
18!     ksp         - Krylov subspace method context
19!     x, r        - solution, residual vectors
20!     J           - Jacobian matrix
21!     its         - iterations for convergence
22!
23      SNES     snes
24      PC       pc
25      KSP      ksp
26      Vec      x,r
27      Mat      J
28      SNESLineSearch linesearch
29      PetscErrorCode  ierr
30      PetscInt its,i2,i20
31      PetscMPIInt size,rank
32      PetscScalar   pfive
33      PetscReal   tol
34      PetscBool   setls
35      PetscReal, pointer :: rhistory(:)
36      PetscInt, pointer :: itshistory(:)
37      PetscInt nhistory
38#if defined(PETSC_USE_LOG)
39      PetscViewer viewer
40#endif
41      double precision threshold,oldthreshold
42
43!  Note: Any user-defined Fortran routines (such as FormJacobian)
44!  MUST be declared as external.
45
46      external FormFunction, FormJacobian, MyLineSearch
47
48! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49!                 Beginning of program
50! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
51
52      PetscCallA(PetscInitialize(ierr))
53      PetscCallA(PetscLogNestedBegin(ierr))
54      threshold = 1.0
55      PetscCallA(PetscLogSetThreshold(threshold,oldthreshold,ierr))
56      PetscCallMPIA(MPI_Comm_size(PETSC_COMM_WORLD,size,ierr))
57      PetscCallMPIA(MPI_Comm_rank(PETSC_COMM_WORLD,rank,ierr))
58      PetscCheckA(size .eq. 1,PETSC_COMM_SELF,PETSC_ERR_WRONG_MPI_SIZE,'Uniprocessor example')
59
60      i2  = 2
61      i20 = 20
62! - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - -
63!  Create nonlinear solver context
64! - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - - - - - - -
65
66      PetscCallA(SNESCreate(PETSC_COMM_WORLD,snes,ierr))
67
68      PetscCallA(SNESSetConvergenceHistory(snes,PETSC_NULL_REAL_ARRAY,PETSC_NULL_INTEGER_ARRAY,PETSC_DECIDE,PETSC_FALSE,ierr))
69
70! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71!  Create matrix and vector data structures; set corresponding routines
72! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73
74!  Create vectors for solution and nonlinear function
75
76      PetscCallA(VecCreateSeq(PETSC_COMM_SELF,i2,x,ierr))
77      PetscCallA(VecDuplicate(x,r,ierr))
78
79!  Create Jacobian matrix data structure
80
81      PetscCallA(MatCreate(PETSC_COMM_SELF,J,ierr))
82      PetscCallA(MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,i2,i2,ierr))
83      PetscCallA(MatSetFromOptions(J,ierr))
84      PetscCallA(MatSetUp(J,ierr))
85
86!  Set function evaluation routine and vector
87
88      PetscCallA(SNESSetFunction(snes,r,FormFunction,0,ierr))
89
90!  Set Jacobian matrix data structure and Jacobian evaluation routine
91
92      PetscCallA(SNESSetJacobian(snes,J,J,FormJacobian,0,ierr))
93
94! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
95!  Customize nonlinear solver; set runtime options
96! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
97
98!  Set linear solver defaults for this problem. By extracting the
99!  KSP, KSP, and PC contexts from the SNES context, we can then
100!  directly call any KSP, KSP, and PC routines to set various options.
101
102      PetscCallA(SNESGetKSP(snes,ksp,ierr))
103      PetscCallA(KSPGetPC(ksp,pc,ierr))
104      PetscCallA(PCSetType(pc,PCNONE,ierr))
105      tol = 1.e-4
106      PetscCallA(KSPSetTolerances(ksp,tol,PETSC_CURRENT_REAL,PETSC_CURRENT_REAL,i20,ierr))
107
108!  Set SNES/KSP/KSP/PC runtime options, e.g.,
109!      -snes_view -snes_monitor -ksp_type <ksp> -pc_type <pc>
110!  These options will override those specified above as long as
111!  SNESSetFromOptions() is called _after_ any other customization
112!  routines.
113
114      PetscCallA(SNESSetFromOptions(snes,ierr))
115
116      PetscCallA(PetscOptionsHasName(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-setls',setls,ierr))
117
118      if (setls) then
119        PetscCallA(SNESGetLineSearch(snes, linesearch, ierr))
120        PetscCallA(SNESLineSearchSetType(linesearch, 'shell', ierr))
121        PetscCallA(SNESLineSearchShellSetApply(linesearch, MyLineSearch,0,ierr))
122      endif
123
124! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125!  Evaluate initial guess; then solve nonlinear system
126! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
127
128!  Note: The user should initialize the vector, x, with the initial guess
129!  for the nonlinear solver prior to calling SNESSolve().  In particular,
130!  to employ an initial guess of zero, the user should explicitly set
131!  this vector to zero by calling VecSet().
132
133      pfive = 0.5
134      PetscCallA(VecSet(x,pfive,ierr))
135      PetscCallA(SNESSolve(snes,PETSC_NULL_VEC,x,ierr))
136
137      PetscCallA(SNESGetConvergenceHistory(snes,rhistory,itshistory,nhistory,ierr))
138      PetscCallA(SNESRestoreConvergenceHistory(snes,rhistory,itshistory,nhistory,ierr))
139
140! View solver converged reason; we could instead use the option -snes_converged_reason
141      PetscCallA(SNESConvergedReasonView(snes,PETSC_VIEWER_STDOUT_WORLD,ierr))
142
143      PetscCallA(SNESGetIterationNumber(snes,its,ierr))
144      if (rank .eq. 0) then
145         write(6,100) its
146      endif
147  100 format('Number of SNES iterations = ',i5)
148
149! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
150!  Free work space.  All PETSc objects should be destroyed when they
151!  are no longer needed.
152! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
153
154      PetscCallA(VecDestroy(x,ierr))
155      PetscCallA(VecDestroy(r,ierr))
156      PetscCallA(MatDestroy(J,ierr))
157      PetscCallA(SNESDestroy(snes,ierr))
158#if defined(PETSC_USE_LOG)
159      PetscCallA(PetscViewerASCIIOpen(PETSC_COMM_WORLD,'filename.xml',viewer,ierr))
160      PetscCallA(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_XML,ierr))
161      PetscCallA(PetscLogView(viewer,ierr))
162      PetscCallA(PetscViewerDestroy(viewer,ierr))
163#endif
164      PetscCallA(PetscFinalize(ierr))
165      end
166!
167! ------------------------------------------------------------------------
168!
169!  FormFunction - Evaluates nonlinear function, F(x).
170!
171!  Input Parameters:
172!  snes - the SNES context
173!  x - input vector
174!  dummy - optional user-defined context (not used here)
175!
176!  Output Parameter:
177!  f - function vector
178!
179      subroutine FormFunction(snes,x,f,dummy,ierr)
180      use petscvec
181      use petscsnesdef
182      implicit none
183
184      SNES     snes
185      Vec      x,f
186      PetscErrorCode ierr
187      integer dummy(*)
188
189!  Declarations for use with local arrays
190      PetscScalar,pointer :: lx_v(:),lf_v(:)
191
192!  Get pointers to vector data.
193!    - VecGetArray() returns a pointer to the data array.
194!    - You MUST call VecRestoreArray() when you no longer need access to
195!      the array.
196
197      PetscCall(VecGetArrayRead(x,lx_v,ierr))
198      PetscCall(VecGetArray(f,lf_v,ierr))
199
200!  Compute function
201
202      lf_v(1) = lx_v(1)*lx_v(1) + lx_v(1)*lx_v(2) - 3.0
203      lf_v(2) = lx_v(1)*lx_v(2) + lx_v(2)*lx_v(2) - 6.0
204
205!  Restore vectors
206
207      PetscCall(VecRestoreArrayRead(x,lx_v,ierr))
208      PetscCall(VecRestoreArray(f,lf_v,ierr))
209
210      end
211
212! ---------------------------------------------------------------------
213!
214!  FormJacobian - Evaluates Jacobian matrix.
215!
216!  Input Parameters:
217!  snes - the SNES context
218!  x - input vector
219!  dummy - optional user-defined context (not used here)
220!
221!  Output Parameters:
222!  A - Jacobian matrix
223!  B - optionally different preconditioning matrix
224!
225      subroutine FormJacobian(snes,X,jac,B,dummy,ierr)
226      use petscvec
227      use petscmat
228      use petscsnesdef
229      implicit none
230
231      SNES         snes
232      Vec          X
233      Mat          jac,B
234      PetscScalar  A(4)
235      PetscErrorCode ierr
236      PetscInt idx(2),i2
237      integer dummy(*)
238
239!  Declarations for use with local arrays
240
241      PetscScalar,pointer :: lx_v(:)
242
243!  Get pointer to vector data
244
245      i2 = 2
246      PetscCall(VecGetArrayRead(x,lx_v,ierr))
247
248!  Compute Jacobian entries and insert into matrix.
249!   - Since this is such a small problem, we set all entries for
250!     the matrix at once.
251!   - Note that MatSetValues() uses 0-based row and column numbers
252!     in Fortran as well as in C (as set here in the array idx).
253
254      idx(1) = 0
255      idx(2) = 1
256      A(1) = 2.0*lx_v(1) + lx_v(2)
257      A(2) = lx_v(1)
258      A(3) = lx_v(2)
259      A(4) = lx_v(1) + 2.0*lx_v(2)
260      PetscCall(MatSetValues(B,i2,idx,i2,idx,A,INSERT_VALUES,ierr))
261
262!  Restore vector
263
264      PetscCall(VecRestoreArrayRead(x,lx_v,ierr))
265
266!  Assemble matrix
267
268      PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY,ierr))
269      PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY,ierr))
270      if (B .ne. jac) then
271        PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY,ierr))
272        PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY,ierr))
273      endif
274
275      end
276
277      subroutine MyLineSearch(linesearch, lctx, ierr)
278      use petscsnes
279      use petscvec
280      implicit none
281
282      SNESLineSearch    linesearch
283      SNES              snes
284      integer           lctx
285      Vec               x, f,g, y, w
286      PetscReal         ynorm,gnorm,xnorm
287      PetscErrorCode    ierr
288
289      PetscScalar       mone
290
291      mone = -1.0
292      PetscCall(SNESLineSearchGetSNES(linesearch, snes, ierr))
293      PetscCall(SNESLineSearchGetVecs(linesearch, x, f, y, w, g, ierr))
294      PetscCall(VecNorm(y,NORM_2,ynorm,ierr))
295      PetscCall(VecAXPY(x,mone,y,ierr))
296      PetscCall(SNESComputeFunction(snes,x,f,ierr))
297      PetscCall(VecNorm(f,NORM_2,gnorm,ierr))
298      PetscCall(VecNorm(x,NORM_2,xnorm,ierr))
299      PetscCall(VecNorm(y,NORM_2,ynorm,ierr))
300      PetscCall(SNESLineSearchSetNorms(linesearch, xnorm, gnorm, ynorm,ierr))
301      end
302
303!/*TEST
304!
305!   test:
306!      args: -ksp_gmres_cgs_refinement_type refine_always -snes_monitor_short
307!      requires: !single
308!
309!TEST*/
310