xref: /petsc/src/snes/tests/ex12f.F90 (revision dd8e379b23d2ef935d8131fb74f7eb73fef09263)
1d8606c27SBarry Smith!
2d8606c27SBarry Smith!
3d8606c27SBarry Smith!  This example demonstrates basic use of the SNES Fortran interface.
4d8606c27SBarry Smith!
5d8606c27SBarry Smith!
677d968b7SBarry Smith        module ex12fmodule
7d8606c27SBarry Smith#include <petsc/finclude/petscsnes.h>
8d8606c27SBarry Smith        use petscsnes
9d8606c27SBarry Smith        type User
10d8606c27SBarry Smith          DM  da
11d8606c27SBarry Smith          Vec F
12d8606c27SBarry Smith          Vec xl
13d8606c27SBarry Smith          MPI_Comm comm
14d8606c27SBarry Smith          PetscInt N
15d8606c27SBarry Smith        end type User
16d8606c27SBarry Smith        save
17d8606c27SBarry Smith        type monctx
18d8606c27SBarry Smith        PetscInt :: its,lag
19d8606c27SBarry Smith        end type monctx
20d8606c27SBarry Smith      end module
21d8606c27SBarry Smith
22d8606c27SBarry Smith! ---------------------------------------------------------------------
23d8606c27SBarry Smith!  Subroutine FormMonitor
24d8606c27SBarry Smith!  This function lets up keep track of the SNES progress at each step
25d8606c27SBarry Smith!  In this routine, we determine when the Jacobian is rebuilt with the parameter 'jag'
26d8606c27SBarry Smith!
27d8606c27SBarry Smith!  Input Parameters:
28d8606c27SBarry Smith!    snes    - SNES nonlinear solver context
29d8606c27SBarry Smith!    its     - current nonlinear iteration, starting from a call of SNESSolve()
30d8606c27SBarry Smith!    norm    - 2-norm of current residual (may be approximate)
31d8606c27SBarry Smith!    snesm - monctx designed module (included in Snesmmod)
32d8606c27SBarry Smith! ---------------------------------------------------------------------
33d8606c27SBarry Smith      subroutine FormMonitor(snes,its,norm,snesm,ierr)
3477d968b7SBarry Smith      use ex12fmodule
35d8606c27SBarry Smith      implicit none
36d8606c27SBarry Smith
37d8606c27SBarry Smith      SNES ::           snes
38d8606c27SBarry Smith      PetscInt ::       its,one,mone
39d8606c27SBarry Smith      PetscScalar ::    norm
40d8606c27SBarry Smith      type(monctx) ::   snesm
41d8606c27SBarry Smith      PetscErrorCode :: ierr
42d8606c27SBarry Smith
43d8606c27SBarry Smith!      write(6,*) ' '
44d8606c27SBarry Smith!      write(6,*) '    its ',its,snesm%its,'lag',
45d8606c27SBarry Smith!     &            snesm%lag
46d8606c27SBarry Smith!      call flush(6)
47d8606c27SBarry Smith      if (mod(snesm%its,snesm%lag).eq.0) then
48d8606c27SBarry Smith        one = 1
49d8606c27SBarry Smith        PetscCall(SNESSetLagJacobian(snes,one,ierr))  ! build jacobian
50d8606c27SBarry Smith      else
51d8606c27SBarry Smith        mone = -1
52d8606c27SBarry Smith        PetscCall(SNESSetLagJacobian(snes,mone,ierr)) ! do NOT build jacobian
53d8606c27SBarry Smith      endif
54d8606c27SBarry Smith      snesm%its = snesm%its + 1
55d8606c27SBarry Smith      end subroutine FormMonitor
56d8606c27SBarry Smith
57d8606c27SBarry Smith!  Note: Any user-defined Fortran routines (such as FormJacobian)
58d8606c27SBarry Smith!  MUST be declared as external.
59d8606c27SBarry Smith!
6042ce371bSBarry Smith
61d8606c27SBarry Smith      program main
6277d968b7SBarry Smith      use ex12fmodule
63d8606c27SBarry Smith      implicit none
64d8606c27SBarry Smith      type(User) ctx
65d8606c27SBarry Smith      PetscMPIInt rank,size
66d8606c27SBarry Smith      PetscErrorCode ierr
67d8606c27SBarry Smith      PetscInt N,start,end,nn,i
68d8606c27SBarry Smith      PetscInt ii,its,i1,i0,i3
69d8606c27SBarry Smith      PetscBool  flg
70d8606c27SBarry Smith      SNES             snes
71d8606c27SBarry Smith      Mat              J
72d8606c27SBarry Smith      Vec              x,r,u
73d8606c27SBarry Smith      PetscScalar      xp,FF,UU,h
74d8606c27SBarry Smith      character*(10)   matrixname
75d8606c27SBarry Smith      external         FormJacobian,FormFunction
76d8606c27SBarry Smith      external         formmonitor
77d8606c27SBarry Smith      type(monctx) :: snesm
78d8606c27SBarry Smith
79d8606c27SBarry Smith      PetscCallA(PetscInitialize(ierr))
80d8606c27SBarry Smith      i1 = 1
81d8606c27SBarry Smith      i0 = 0
82d8606c27SBarry Smith      i3 = 3
83d8606c27SBarry Smith      N  = 10
84d8606c27SBarry Smith      PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS,PETSC_NULL_CHARACTER,'-n',N,flg,ierr))
85d8606c27SBarry Smith      h = 1.0/real(N-1)
86d8606c27SBarry Smith      ctx%N = N
87d8606c27SBarry Smith      ctx%comm = PETSC_COMM_WORLD
88d8606c27SBarry Smith
89d8606c27SBarry Smith      PetscCallMPIA(MPI_Comm_rank(PETSC_COMM_WORLD,rank,ierr))
90d8606c27SBarry Smith      PetscCallMPIA(MPI_Comm_size(PETSC_COMM_WORLD,size,ierr))
91d8606c27SBarry Smith
92d8606c27SBarry Smith! Set up data structures
93d8606c27SBarry Smith      PetscCallA(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,N,i1,i1,PETSC_NULL_INTEGER,ctx%da,ierr))
94d8606c27SBarry Smith      PetscCallA(DMSetFromOptions(ctx%da,ierr))
95d8606c27SBarry Smith      PetscCallA(DMSetUp(ctx%da,ierr))
96d8606c27SBarry Smith      PetscCallA(DMCreateGlobalVector(ctx%da,x,ierr))
97d8606c27SBarry Smith      PetscCallA(DMCreateLocalVector(ctx%da,ctx%xl,ierr))
98d8606c27SBarry Smith
99d8606c27SBarry Smith      PetscCallA(PetscObjectSetName(x,'Approximate Solution',ierr))
100d8606c27SBarry Smith      PetscCallA(VecDuplicate(x,r,ierr))
101d8606c27SBarry Smith      PetscCallA(VecDuplicate(x,ctx%F,ierr))
102d8606c27SBarry Smith      PetscCallA(VecDuplicate(x,U,ierr))
103d8606c27SBarry Smith      PetscCallA(PetscObjectSetName(U,'Exact Solution',ierr))
104d8606c27SBarry Smith
105d8606c27SBarry Smith      PetscCallA(MatCreateAIJ(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,N,N,i3,PETSC_NULL_INTEGER,i0,PETSC_NULL_INTEGER,J,ierr))
106d8606c27SBarry Smith      PetscCallA(MatSetOption(J,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE,ierr))
107d8606c27SBarry Smith      PetscCallA(MatGetType(J,matrixname,ierr))
108d8606c27SBarry Smith
109*dd8e379bSPierre Jolivet! Store right-hand side of PDE and exact solution
110d8606c27SBarry Smith      PetscCallA(VecGetOwnershipRange(x,start,end,ierr))
111d8606c27SBarry Smith      xp = h*start
112d8606c27SBarry Smith      nn = end - start
113d8606c27SBarry Smith      ii = start
114d8606c27SBarry Smith      do 10, i=0,nn-1
115d8606c27SBarry Smith        FF = 6.0*xp + (xp+1.e-12)**6.e0
116d8606c27SBarry Smith        UU = xp*xp*xp
117d8606c27SBarry Smith        PetscCallA(VecSetValues(ctx%F,i1,ii,FF,INSERT_VALUES,ierr))
118d8606c27SBarry Smith        PetscCallA(VecSetValues(U,i1,ii,UU,INSERT_VALUES,ierr))
119d8606c27SBarry Smith        xp = xp + h
120d8606c27SBarry Smith        ii = ii + 1
121d8606c27SBarry Smith 10   continue
122d8606c27SBarry Smith      PetscCallA(VecAssemblyBegin(ctx%F,ierr))
123d8606c27SBarry Smith      PetscCallA(VecAssemblyEnd(ctx%F,ierr))
124d8606c27SBarry Smith      PetscCallA(VecAssemblyBegin(U,ierr))
125d8606c27SBarry Smith      PetscCallA(VecAssemblyEnd(U,ierr))
126d8606c27SBarry Smith
127d8606c27SBarry Smith! Create nonlinear solver
128d8606c27SBarry Smith      PetscCallA(SNESCreate(PETSC_COMM_WORLD,snes,ierr))
129d8606c27SBarry Smith
130d8606c27SBarry Smith! Set various routines and options
131d8606c27SBarry Smith      PetscCallA(SNESSetFunction(snes,r,FormFunction,ctx,ierr))
132d8606c27SBarry Smith      PetscCallA(SNESSetJacobian(snes,J,J,FormJacobian,ctx,ierr))
133d8606c27SBarry Smith
134d8606c27SBarry Smith      snesm%its = 0
135d8606c27SBarry Smith      PetscCallA(SNESGetLagJacobian(snes,snesm%lag,ierr))
136d8606c27SBarry Smith      PetscCallA(SNESMonitorSet(snes,FormMonitor,snesm,PETSC_NULL_FUNCTION,ierr))
137d8606c27SBarry Smith      PetscCallA(SNESSetFromOptions(snes,ierr))
138d8606c27SBarry Smith
139d8606c27SBarry Smith! Solve nonlinear system
140d8606c27SBarry Smith      PetscCallA(FormInitialGuess(snes,x,ierr))
141d8606c27SBarry Smith      PetscCallA(SNESSolve(snes,PETSC_NULL_VEC,x,ierr))
142d8606c27SBarry Smith      PetscCallA(SNESGetIterationNumber(snes,its,ierr))
143d8606c27SBarry Smith
144d8606c27SBarry Smith!  Free work space.  All PETSc objects should be destroyed when they
145d8606c27SBarry Smith!  are no longer needed.
146d8606c27SBarry Smith      PetscCallA(VecDestroy(x,ierr))
147d8606c27SBarry Smith      PetscCallA(VecDestroy(ctx%xl,ierr))
148d8606c27SBarry Smith      PetscCallA(VecDestroy(r,ierr))
149d8606c27SBarry Smith      PetscCallA(VecDestroy(U,ierr))
150d8606c27SBarry Smith      PetscCallA(VecDestroy(ctx%F,ierr))
151d8606c27SBarry Smith      PetscCallA(MatDestroy(J,ierr))
152d8606c27SBarry Smith      PetscCallA(SNESDestroy(snes,ierr))
153d8606c27SBarry Smith      PetscCallA(DMDestroy(ctx%da,ierr))
154d8606c27SBarry Smith      PetscCallA(PetscFinalize(ierr))
155d8606c27SBarry Smith      end
156d8606c27SBarry Smith
157d8606c27SBarry Smith! --------------------  Evaluate Function F(x) ---------------------
158d8606c27SBarry Smith
159d8606c27SBarry Smith      subroutine FormFunction(snes,x,f,ctx,ierr)
16077d968b7SBarry Smith      use ex12fmodule
161d8606c27SBarry Smith      implicit none
162d8606c27SBarry Smith      SNES             snes
163d8606c27SBarry Smith      Vec              x,f
164d8606c27SBarry Smith      type(User) ctx
165d8606c27SBarry Smith      PetscMPIInt  rank,size,zero
166d8606c27SBarry Smith      PetscInt i,s,n
167d8606c27SBarry Smith      PetscErrorCode ierr
16842ce371bSBarry Smith      PetscScalar      h,d
16942ce371bSBarry Smith      PetscScalar,pointer :: vf2(:),vxx(:),vff(:)
170d8606c27SBarry Smith
171d8606c27SBarry Smith      zero = 0
172d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_rank(ctx%comm,rank,ierr))
173d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_size(ctx%comm,size,ierr))
174d8606c27SBarry Smith      h     = 1.0/(real(ctx%N) - 1.0)
175d8606c27SBarry Smith      PetscCall(DMGlobalToLocalBegin(ctx%da,x,INSERT_VALUES,ctx%xl,ierr))
176d8606c27SBarry Smith      PetscCall(DMGlobalToLocalEnd(ctx%da,x,INSERT_VALUES,ctx%xl,ierr))
177d8606c27SBarry Smith
178d8606c27SBarry Smith      PetscCall(VecGetLocalSize(ctx%xl,n,ierr))
179d8606c27SBarry Smith      if (n .gt. 1000) then
180d8606c27SBarry Smith        print*, 'Local work array not big enough'
181d8606c27SBarry Smith        call MPI_Abort(PETSC_COMM_WORLD,zero,ierr)
182d8606c27SBarry Smith      endif
183d8606c27SBarry Smith
18442ce371bSBarry Smith      PetscCall(VecGetArrayReadF90(ctx%xl,vxx,ierr))
18542ce371bSBarry Smith      PetscCall(VecGetArrayF90(f,vff,ierr))
18642ce371bSBarry Smith      PetscCall(VecGetArrayF90(ctx%F,vF2,ierr))
187d8606c27SBarry Smith
188d8606c27SBarry Smith      d = h*h
189d8606c27SBarry Smith
190d8606c27SBarry Smith!
191d8606c27SBarry Smith!  Note that the array vxx() was obtained from a ghosted local vector
192d8606c27SBarry Smith!  ctx%xl while the array vff() was obtained from the non-ghosted parallel
193d8606c27SBarry Smith!  vector F. This is why there is a need for shift variable s. Since vff()
194d8606c27SBarry Smith!  does not have locations for the ghost variables we need to index in it
195d8606c27SBarry Smith!  slightly different then indexing into vxx(). For example on processor
196d8606c27SBarry Smith!  1 (the second processor)
197d8606c27SBarry Smith!
198d8606c27SBarry Smith!        xx(1)        xx(2)             xx(3)             .....
199d8606c27SBarry Smith!      ^^^^^^^        ^^^^^             ^^^^^
200d8606c27SBarry Smith!      ghost value   1st local value   2nd local value
201d8606c27SBarry Smith!
202d8606c27SBarry Smith!                      ff(1)             ff(2)
203d8606c27SBarry Smith!                     ^^^^^^^           ^^^^^^^
204d8606c27SBarry Smith!                    1st local value   2nd local value
205d8606c27SBarry Smith!
206d8606c27SBarry Smith       if (rank .eq. 0) then
207d8606c27SBarry Smith        s = 0
20842ce371bSBarry Smith        vff(1) = vxx(1)
209d8606c27SBarry Smith      else
210d8606c27SBarry Smith        s = 1
211d8606c27SBarry Smith      endif
212d8606c27SBarry Smith
213d8606c27SBarry Smith      do 10 i=1,n-2
21442ce371bSBarry Smith       vff(i-s+1) = d*(vxx(i) - 2.0*vxx(i+1) + vxx(i+2)) + vxx(i+1)*vxx(i+1) - vF2(i-s+1)
215d8606c27SBarry Smith 10   continue
216d8606c27SBarry Smith
217d8606c27SBarry Smith      if (rank .eq. size-1) then
21842ce371bSBarry Smith        vff(n-s) = vxx(n) - 1.0
219d8606c27SBarry Smith      endif
220d8606c27SBarry Smith
22142ce371bSBarry Smith      PetscCall(VecRestoreArrayF90(f,vff,ierr))
22242ce371bSBarry Smith      PetscCall(VecRestoreArrayReadF90(ctx%xl,vxx,ierr))
22342ce371bSBarry Smith      PetscCall(VecRestoreArrayF90(ctx%F,vF2,ierr))
224d8606c27SBarry Smith      return
225d8606c27SBarry Smith      end
226d8606c27SBarry Smith
227d8606c27SBarry Smith! --------------------  Form initial approximation -----------------
228d8606c27SBarry Smith
229d8606c27SBarry Smith      subroutine FormInitialGuess(snes,x,ierr)
23077d968b7SBarry Smith      use ex12fmodule
231d8606c27SBarry Smith      implicit none
232d8606c27SBarry Smith
233d8606c27SBarry Smith      PetscErrorCode   ierr
234d8606c27SBarry Smith      Vec              x
235d8606c27SBarry Smith      SNES             snes
236d8606c27SBarry Smith      PetscScalar      five
237d8606c27SBarry Smith
238d8606c27SBarry Smith      five = .5
239d8606c27SBarry Smith      PetscCall(VecSet(x,five,ierr))
240d8606c27SBarry Smith      return
241d8606c27SBarry Smith      end
242d8606c27SBarry Smith
243d8606c27SBarry Smith! --------------------  Evaluate Jacobian --------------------
244d8606c27SBarry Smith
245d8606c27SBarry Smith      subroutine FormJacobian(snes,x,jac,B,ctx,ierr)
24677d968b7SBarry Smith      use ex12fmodule
247d8606c27SBarry Smith      implicit none
248d8606c27SBarry Smith
249d8606c27SBarry Smith      SNES             snes
250d8606c27SBarry Smith      Vec              x
251d8606c27SBarry Smith      Mat              jac,B
252d8606c27SBarry Smith      type(User) ctx
253d8606c27SBarry Smith      PetscInt  ii,istart,iend
254d8606c27SBarry Smith      PetscInt  i,j,n,end,start,i1
255d8606c27SBarry Smith      PetscErrorCode ierr
256d8606c27SBarry Smith      PetscMPIInt rank,size
25742ce371bSBarry Smith      PetscScalar      d,A,h
25842ce371bSBarry Smith      PetscScalar,pointer :: vxx(:)
259d8606c27SBarry Smith
260d8606c27SBarry Smith      i1 = 1
261d8606c27SBarry Smith      h = 1.0/(real(ctx%N) - 1.0)
262d8606c27SBarry Smith      d = h*h
263d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_rank(ctx%comm,rank,ierr))
264d8606c27SBarry Smith      PetscCallMPI(MPI_Comm_size(ctx%comm,size,ierr))
265d8606c27SBarry Smith
26642ce371bSBarry Smith      PetscCall(VecGetArrayReadF90(x,vxx,ierr))
267d8606c27SBarry Smith      PetscCall(VecGetOwnershipRange(x,start,end,ierr))
268d8606c27SBarry Smith      n = end - start
269d8606c27SBarry Smith
270d8606c27SBarry Smith      if (rank .eq. 0) then
271d8606c27SBarry Smith        A = 1.0
272d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,start,i1,start,A,INSERT_VALUES,ierr))
273d8606c27SBarry Smith        istart = 1
274d8606c27SBarry Smith      else
275d8606c27SBarry Smith        istart = 0
276d8606c27SBarry Smith      endif
277d8606c27SBarry Smith      if (rank .eq. size-1) then
278d8606c27SBarry Smith        i = INT(ctx%N-1)
279d8606c27SBarry Smith        A = 1.0
280d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,i,i1,i,A,INSERT_VALUES,ierr))
281d8606c27SBarry Smith        iend = n-1
282d8606c27SBarry Smith      else
283d8606c27SBarry Smith        iend = n
284d8606c27SBarry Smith      endif
285d8606c27SBarry Smith      do 10 i=istart,iend-1
286d8606c27SBarry Smith        ii = i + start
287d8606c27SBarry Smith        j = start + i - 1
288d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,ii,i1,j,d,INSERT_VALUES,ierr))
289d8606c27SBarry Smith        j = start + i + 1
290d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,ii,i1,j,d,INSERT_VALUES,ierr))
29142ce371bSBarry Smith        A = -2.0*d + 2.0*vxx(i+1)
292d8606c27SBarry Smith        PetscCall(MatSetValues(jac,i1,ii,i1,ii,A,INSERT_VALUES,ierr))
293d8606c27SBarry Smith 10   continue
29442ce371bSBarry Smith      PetscCall(VecRestoreArrayReadF90(x,vxx,ierr))
295d8606c27SBarry Smith      PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY,ierr))
296d8606c27SBarry Smith      PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY,ierr))
297d8606c27SBarry Smith      return
298d8606c27SBarry Smith      end
299d8606c27SBarry Smith
300d8606c27SBarry Smith!/*TEST
301d8606c27SBarry Smith!
302d8606c27SBarry Smith!   test:
303d8606c27SBarry Smith!      nsize: 2
304d8606c27SBarry Smith!      args: -ksp_gmres_cgs_refinement_type refine_always -n 10 -snes_monitor_short
305d8606c27SBarry Smith!      output_file: output/ex12_1.out
306d8606c27SBarry Smith!
307d8606c27SBarry Smith!TEST*/
308