xref: /petsc/src/ts/tutorials/ex1f.F90 (revision 4820e4ea99a084ae862a8c395f732bc7c0e1a6d0)
1d8606c27SBarry Smith!
2d8606c27SBarry Smith!   Solves the time dependent Bratu problem using pseudo-timestepping
3d8606c27SBarry Smith!
4d8606c27SBarry Smith!   This code demonstrates how one may solve a nonlinear problem
5d8606c27SBarry Smith!   with pseudo-timestepping. In this simple example, the pseudo-timestep
6d8606c27SBarry Smith!   is the same for all grid points, i.e., this is equivalent to using
7d8606c27SBarry Smith!   the backward Euler method with a variable timestep.
8d8606c27SBarry Smith!
9d8606c27SBarry Smith!   Note: This example does not require pseudo-timestepping since it
10d8606c27SBarry Smith!   is an easy nonlinear problem, but it is included to demonstrate how
11d8606c27SBarry Smith!   the pseudo-timestepping may be done.
12d8606c27SBarry Smith!
13d8606c27SBarry Smith!   See snes/tutorials/ex4.c[ex4f.F] and
14d8606c27SBarry Smith!   snes/tutorials/ex5.c[ex5f.F] where the problem is described
15d8606c27SBarry Smith!   and solved using the method of Newton alone.
16d8606c27SBarry Smith!
17d8606c27SBarry Smith!
18d8606c27SBarry Smith!23456789012345678901234567890123456789012345678901234567890123456789012
19d8606c27SBarry Smithprogram main
20d8606c27SBarry Smith#include <petsc/finclude/petscts.h>
21d8606c27SBarry Smith  use petscts
22d8606c27SBarry Smith  implicit none
23d8606c27SBarry Smith
24d8606c27SBarry Smith!
25d8606c27SBarry Smith!  Create an application context to contain data needed by the
26d8606c27SBarry Smith!  application-provided call-back routines, FormJacobian() and
27d8606c27SBarry Smith!  FormFunction(). We use a double precision array with three
28d8606c27SBarry Smith!  entries indexed by param, lmx, lmy.
29d8606c27SBarry Smith!
30d8606c27SBarry Smith  PetscReal user(3)
31d8606c27SBarry Smith  PetscInt param, lmx, lmy, i5
32d8606c27SBarry Smith  parameter(param=1, lmx=2, lmy=3)
33d8606c27SBarry Smith!
34d8606c27SBarry Smith!   User-defined routines
35d8606c27SBarry Smith!
36d8606c27SBarry Smith  external FormJacobian, FormFunction
37d8606c27SBarry Smith!
38d8606c27SBarry Smith!   Data for problem
39d8606c27SBarry Smith!
40d8606c27SBarry Smith  TS ts
41d8606c27SBarry Smith  Vec x, r
42d8606c27SBarry Smith  Mat J
43d8606c27SBarry Smith  PetscInt its, N, i1000, itmp
44d8606c27SBarry Smith  PetscBool flg
45d8606c27SBarry Smith  PetscErrorCode ierr
46d8606c27SBarry Smith  PetscReal param_max, param_min, dt
47d8606c27SBarry Smith  PetscReal tmax
48d8606c27SBarry Smith  PetscReal ftime
49d8606c27SBarry Smith  TSConvergedReason reason
50d8606c27SBarry Smith
51d8606c27SBarry Smith  i5 = 5
52d8606c27SBarry Smith  param_max = 6.81
53d8606c27SBarry Smith  param_min = 0
54d8606c27SBarry Smith
55d8606c27SBarry Smith  PetscCallA(PetscInitialize(ierr))
56d8606c27SBarry Smith  user(lmx) = 4
57d8606c27SBarry Smith  user(lmy) = 4
58d8606c27SBarry Smith  user(param) = 6.0
59d8606c27SBarry Smith
60d8606c27SBarry Smith!
61d8606c27SBarry Smith!     Allow user to set the grid dimensions and nonlinearity parameter at run-time
62d8606c27SBarry Smith!
63d8606c27SBarry Smith  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-mx', user(lmx), flg, ierr))
64d8606c27SBarry Smith  itmp = 4
65d8606c27SBarry Smith  PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-my', itmp, flg, ierr))
66d8606c27SBarry Smith  user(lmy) = itmp
67d8606c27SBarry Smith  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-param', user(param), flg, ierr))
68*4820e4eaSBarry Smith  if (user(param) >= param_max .or. user(param) <= param_min) then
69d8606c27SBarry Smith    print *, 'Parameter is out of range'
70d8606c27SBarry Smith  end if
71*4820e4eaSBarry Smith  if (user(lmx) > user(lmy)) then
72d8606c27SBarry Smith    dt = .5/user(lmx)
73d8606c27SBarry Smith  else
74d8606c27SBarry Smith    dt = .5/user(lmy)
75d8606c27SBarry Smith  end if
76d8606c27SBarry Smith  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-dt', dt, flg, ierr))
77d8606c27SBarry Smith  N = int(user(lmx)*user(lmy))
78d8606c27SBarry Smith
79d8606c27SBarry Smith!
80d8606c27SBarry Smith!      Create vectors to hold the solution and function value
81d8606c27SBarry Smith!
82d8606c27SBarry Smith  PetscCallA(VecCreateSeq(PETSC_COMM_SELF, N, x, ierr))
83d8606c27SBarry Smith  PetscCallA(VecDuplicate(x, r, ierr))
84d8606c27SBarry Smith
85d8606c27SBarry Smith!
86d8606c27SBarry Smith!    Create matrix to hold Jacobian. Preallocate 5 nonzeros per row
87d8606c27SBarry Smith!    in the sparse matrix. Note that this is not the optimal strategy see
88d8606c27SBarry Smith!    the Performance chapter of the users manual for information on
89d8606c27SBarry Smith!    preallocating memory in sparse matrices.
90d8606c27SBarry Smith!
91d8606c27SBarry Smith  i5 = 5
925d83a8b1SBarry Smith  PetscCallA(MatCreateSeqAIJ(PETSC_COMM_SELF, N, N, i5, PETSC_NULL_INTEGER_ARRAY, J, ierr))
93d8606c27SBarry Smith
94d8606c27SBarry Smith!
95d8606c27SBarry Smith!     Create timestepper context
96d8606c27SBarry Smith!
97d8606c27SBarry Smith
98d8606c27SBarry Smith  PetscCallA(TSCreate(PETSC_COMM_WORLD, ts, ierr))
99d8606c27SBarry Smith  PetscCallA(TSSetProblemType(ts, TS_NONLINEAR, ierr))
100d8606c27SBarry Smith
101d8606c27SBarry Smith!
102d8606c27SBarry Smith!     Tell the timestepper context where to compute solutions
103d8606c27SBarry Smith!
104d8606c27SBarry Smith
105d8606c27SBarry Smith  PetscCallA(TSSetSolution(ts, x, ierr))
106d8606c27SBarry Smith
107d8606c27SBarry Smith!
108d8606c27SBarry Smith!    Provide the call-back for the nonlinear function we are
109d8606c27SBarry Smith!    evaluating. Thus whenever the timestepping routines need the
110d8606c27SBarry Smith!    function they will call this routine. Note the final argument
111d8606c27SBarry Smith!    is the application context used by the call-back functions.
112d8606c27SBarry Smith!
113d8606c27SBarry Smith
114d8606c27SBarry Smith  PetscCallA(TSSetRHSFunction(ts, PETSC_NULL_VEC, FormFunction, user, ierr))
115d8606c27SBarry Smith
116d8606c27SBarry Smith!
117d8606c27SBarry Smith!     Set the Jacobian matrix and the function used to compute
118d8606c27SBarry Smith!     Jacobians.
119d8606c27SBarry Smith!
120d8606c27SBarry Smith
121d8606c27SBarry Smith  PetscCallA(TSSetRHSJacobian(ts, J, J, FormJacobian, user, ierr))
122d8606c27SBarry Smith
123d8606c27SBarry Smith!
124d8606c27SBarry Smith!       For the initial guess for the problem
125d8606c27SBarry Smith!
126d8606c27SBarry Smith
127d8606c27SBarry Smith  PetscCallA(FormInitialGuess(x, user, ierr))
128d8606c27SBarry Smith
129d8606c27SBarry Smith!
130d8606c27SBarry Smith!       This indicates that we are using pseudo timestepping to
131d8606c27SBarry Smith!     find a steady state solution to the nonlinear problem.
132d8606c27SBarry Smith!
133d8606c27SBarry Smith
134d8606c27SBarry Smith  PetscCallA(TSSetType(ts, TSPSEUDO, ierr))
135d8606c27SBarry Smith
136d8606c27SBarry Smith!
137d8606c27SBarry Smith!       Set the initial time to start at (this is arbitrary for
138d8606c27SBarry Smith!     steady state problems and the initial timestep given above
139d8606c27SBarry Smith!
140d8606c27SBarry Smith
141d8606c27SBarry Smith  PetscCallA(TSSetTimeStep(ts, dt, ierr))
142d8606c27SBarry Smith
143d8606c27SBarry Smith!
144d8606c27SBarry Smith!      Set a large number of timesteps and final duration time
145d8606c27SBarry Smith!     to insure convergence to steady state.
146d8606c27SBarry Smith!
147d8606c27SBarry Smith  i1000 = 1000
148d8606c27SBarry Smith  tmax = 1.e12
149d8606c27SBarry Smith  PetscCallA(TSSetMaxSteps(ts, i1000, ierr))
150d8606c27SBarry Smith  PetscCallA(TSSetMaxTime(ts, tmax, ierr))
151d8606c27SBarry Smith  PetscCallA(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER, ierr))
152d8606c27SBarry Smith
153d8606c27SBarry Smith!
154d8606c27SBarry Smith!      Set any additional options from the options database. This
155d8606c27SBarry Smith!     includes all options for the nonlinear and linear solvers used
156d8606c27SBarry Smith!     internally the timestepping routines.
157d8606c27SBarry Smith!
158d8606c27SBarry Smith
159d8606c27SBarry Smith  PetscCallA(TSSetFromOptions(ts, ierr))
160d8606c27SBarry Smith
161d8606c27SBarry Smith  PetscCallA(TSSetUp(ts, ierr))
162d8606c27SBarry Smith
163d8606c27SBarry Smith!
164d8606c27SBarry Smith!      Perform the solve. This is where the timestepping takes place.
165d8606c27SBarry Smith!
166d8606c27SBarry Smith  PetscCallA(TSSolve(ts, x, ierr))
167d8606c27SBarry Smith  PetscCallA(TSGetSolveTime(ts, ftime, ierr))
168d8606c27SBarry Smith  PetscCallA(TSGetStepNumber(ts, its, ierr))
169d8606c27SBarry Smith  PetscCallA(TSGetConvergedReason(ts, reason, ierr))
170d8606c27SBarry Smith
171d8606c27SBarry Smith  write (6, 100) its, ftime, reason
172d8606c27SBarry Smith100 format('Number of pseudo time-steps ', i5, ' final time ', 1pe9.2, ' reason ', i3)
173d8606c27SBarry Smith
174d8606c27SBarry Smith!
175d8606c27SBarry Smith!     Free the data structures constructed above
176d8606c27SBarry Smith!
177d8606c27SBarry Smith
178d8606c27SBarry Smith  PetscCallA(VecDestroy(x, ierr))
179d8606c27SBarry Smith  PetscCallA(VecDestroy(r, ierr))
180d8606c27SBarry Smith  PetscCallA(MatDestroy(J, ierr))
181d8606c27SBarry Smith  PetscCallA(TSDestroy(ts, ierr))
182d8606c27SBarry Smith  PetscCallA(PetscFinalize(ierr))
183d8606c27SBarry Smithend
184d8606c27SBarry Smith
185d8606c27SBarry Smith!
186d8606c27SBarry Smith!  --------------------  Form initial approximation -----------------
187d8606c27SBarry Smith!
188d8606c27SBarry Smithsubroutine FormInitialGuess(X, user, ierr)
189d8606c27SBarry Smith  use petscts
190d8606c27SBarry Smith  implicit none
191d8606c27SBarry Smith
192d8606c27SBarry Smith  Vec X
193d8606c27SBarry Smith  PetscReal user(3)
194d8606c27SBarry Smith  PetscInt i, j, row, mx, my
195d8606c27SBarry Smith  PetscErrorCode ierr
196d8606c27SBarry Smith  PetscReal one, lambda
197d8606c27SBarry Smith  PetscReal temp1, temp, hx, hy
19842ce371bSBarry Smith  PetscScalar, pointer :: xx(:)
199d8606c27SBarry Smith  PetscInt param, lmx, lmy
200d8606c27SBarry Smith  parameter(param=1, lmx=2, lmy=3)
201d8606c27SBarry Smith
202d8606c27SBarry Smith  one = 1.0
203d8606c27SBarry Smith
204d8606c27SBarry Smith  mx = int(user(lmx))
205d8606c27SBarry Smith  my = int(user(lmy))
206d8606c27SBarry Smith  lambda = user(param)
207d8606c27SBarry Smith
208d8606c27SBarry Smith  hy = one/(my - 1)
209d8606c27SBarry Smith  hx = one/(mx - 1)
210d8606c27SBarry Smith
211ce78bad3SBarry Smith  PetscCall(VecGetArray(X, xx, ierr))
212d8606c27SBarry Smith  temp1 = lambda/(lambda + one)
213d8606c27SBarry Smith  do 10, j = 1, my
214d8606c27SBarry Smith    temp = min(j - 1, my - j)*hy
215d8606c27SBarry Smith    do 20 i = 1, mx
216d8606c27SBarry Smith      row = i + (j - 1)*mx
217*4820e4eaSBarry Smith      if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
21842ce371bSBarry Smith        xx(row) = 0.0
219d8606c27SBarry Smith      else
22042ce371bSBarry Smith        xx(row) = temp1*sqrt(min(min(i - 1, mx - i)*hx, temp))
221d8606c27SBarry Smith      end if
222d8606c27SBarry Smith20    continue
223d8606c27SBarry Smith10    continue
224ce78bad3SBarry Smith      PetscCall(VecRestoreArray(X, xx, ierr))
225d8606c27SBarry Smith    end
226d8606c27SBarry Smith!
227d8606c27SBarry Smith!  --------------------  Evaluate Function F(x) ---------------------
228d8606c27SBarry Smith!
229d8606c27SBarry Smith    subroutine FormFunction(ts, t, X, F, user, ierr)
230d8606c27SBarry Smith      use petscts
231d8606c27SBarry Smith      implicit none
232d8606c27SBarry Smith
233d8606c27SBarry Smith      TS ts
234d8606c27SBarry Smith      PetscReal t
235d8606c27SBarry Smith      Vec X, F
236d8606c27SBarry Smith      PetscReal user(3)
237d8606c27SBarry Smith      PetscErrorCode ierr
238d8606c27SBarry Smith      PetscInt i, j, row, mx, my
239d8606c27SBarry Smith      PetscReal two, lambda
240d8606c27SBarry Smith      PetscReal hx, hy, hxdhy, hydhx
241d8606c27SBarry Smith      PetscScalar ut, ub, ul, ur, u
242d8606c27SBarry Smith      PetscScalar uxx, uyy, sc
24342ce371bSBarry Smith      PetscScalar, pointer :: xx(:), ff(:)
244d8606c27SBarry Smith      PetscInt param, lmx, lmy
245d8606c27SBarry Smith      parameter(param=1, lmx=2, lmy=3)
246d8606c27SBarry Smith
247d8606c27SBarry Smith      two = 2.0
248d8606c27SBarry Smith
249d8606c27SBarry Smith      mx = int(user(lmx))
250d8606c27SBarry Smith      my = int(user(lmy))
251d8606c27SBarry Smith      lambda = user(param)
252d8606c27SBarry Smith
253d8606c27SBarry Smith      hx = 1.0/real(mx - 1)
254d8606c27SBarry Smith      hy = 1.0/real(my - 1)
255d8606c27SBarry Smith      sc = hx*hy
256d8606c27SBarry Smith      hxdhy = hx/hy
257d8606c27SBarry Smith      hydhx = hy/hx
258d8606c27SBarry Smith
259ce78bad3SBarry Smith      PetscCall(VecGetArrayRead(X, xx, ierr))
260ce78bad3SBarry Smith      PetscCall(VecGetArray(F, ff, ierr))
261d8606c27SBarry Smith      do 10 j = 1, my
262d8606c27SBarry Smith        do 20 i = 1, mx
263d8606c27SBarry Smith          row = i + (j - 1)*mx
264*4820e4eaSBarry Smith          if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
26542ce371bSBarry Smith            ff(row) = xx(row)
266d8606c27SBarry Smith          else
26742ce371bSBarry Smith            u = xx(row)
26842ce371bSBarry Smith            ub = xx(row - mx)
26942ce371bSBarry Smith            ul = xx(row - 1)
27042ce371bSBarry Smith            ut = xx(row + mx)
27142ce371bSBarry Smith            ur = xx(row + 1)
272d8606c27SBarry Smith            uxx = (-ur + two*u - ul)*hydhx
273d8606c27SBarry Smith            uyy = (-ut + two*u - ub)*hxdhy
27442ce371bSBarry Smith            ff(row) = -uxx - uyy + sc*lambda*exp(u)
275d8606c27SBarry Smith          end if
276d8606c27SBarry Smith20        continue
277d8606c27SBarry Smith10        continue
278d8606c27SBarry Smith
279ce78bad3SBarry Smith          PetscCall(VecRestoreArrayRead(X, xx, ierr))
280ce78bad3SBarry Smith          PetscCall(VecRestoreArray(F, ff, ierr))
281d8606c27SBarry Smith        end
282d8606c27SBarry Smith!
283d8606c27SBarry Smith!  --------------------  Evaluate Jacobian of F(x) --------------------
284d8606c27SBarry Smith!
285d8606c27SBarry Smith        subroutine FormJacobian(ts, ctime, X, JJ, B, user, ierr)
286d8606c27SBarry Smith          use petscts
287d8606c27SBarry Smith          implicit none
288d8606c27SBarry Smith
289d8606c27SBarry Smith          TS ts
290d8606c27SBarry Smith          Vec X
291d8606c27SBarry Smith          Mat JJ, B
292d8606c27SBarry Smith          PetscReal user(3), ctime
293d8606c27SBarry Smith          PetscErrorCode ierr
294d8606c27SBarry Smith          Mat jac
295d8606c27SBarry Smith          PetscInt i, j, row(1), mx, my
296d8606c27SBarry Smith          PetscInt col(5), i1, i5
297d8606c27SBarry Smith          PetscScalar two, one, lambda
29842ce371bSBarry Smith          PetscScalar v(5), sc
29942ce371bSBarry Smith          PetscScalar, pointer :: xx(:)
300d8606c27SBarry Smith          PetscReal hx, hy, hxdhy, hydhx
301d8606c27SBarry Smith
302d8606c27SBarry Smith          PetscInt param, lmx, lmy
303d8606c27SBarry Smith          parameter(param=1, lmx=2, lmy=3)
304d8606c27SBarry Smith
305d8606c27SBarry Smith          i1 = 1
306d8606c27SBarry Smith          i5 = 5
307d8606c27SBarry Smith          jac = B
308d8606c27SBarry Smith          two = 2.0
309d8606c27SBarry Smith          one = 1.0
310d8606c27SBarry Smith
311d8606c27SBarry Smith          mx = int(user(lmx))
312d8606c27SBarry Smith          my = int(user(lmy))
313d8606c27SBarry Smith          lambda = user(param)
314d8606c27SBarry Smith
315d8606c27SBarry Smith          hx = 1.0/real(mx - 1)
316d8606c27SBarry Smith          hy = 1.0/real(my - 1)
317d8606c27SBarry Smith          sc = hx*hy
318d8606c27SBarry Smith          hxdhy = hx/hy
319d8606c27SBarry Smith          hydhx = hy/hx
320d8606c27SBarry Smith
321ce78bad3SBarry Smith          PetscCall(VecGetArrayRead(X, xx, ierr))
322d8606c27SBarry Smith          do 10 j = 1, my
323d8606c27SBarry Smith            do 20 i = 1, mx
324d8606c27SBarry Smith!
325d8606c27SBarry Smith!      When inserting into PETSc matrices, indices start at 0
326d8606c27SBarry Smith!
327d8606c27SBarry Smith              row(1) = i - 1 + (j - 1)*mx
328*4820e4eaSBarry Smith              if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
3295d83a8b1SBarry Smith                PetscCall(MatSetValues(jac, i1, [row], i1, [row], [one], INSERT_VALUES, ierr))
330d8606c27SBarry Smith              else
331d8606c27SBarry Smith                v(1) = hxdhy
332d8606c27SBarry Smith                col(1) = row(1) - mx
333d8606c27SBarry Smith                v(2) = hydhx
334d8606c27SBarry Smith                col(2) = row(1) - 1
33542ce371bSBarry Smith                v(3) = -two*(hydhx + hxdhy) + sc*lambda*exp(xx(row(1)))
336d8606c27SBarry Smith                col(3) = row(1)
337d8606c27SBarry Smith                v(4) = hydhx
338d8606c27SBarry Smith                col(4) = row(1) + 1
339d8606c27SBarry Smith                v(5) = hxdhy
340d8606c27SBarry Smith                col(5) = row(1) + mx
3415d83a8b1SBarry Smith                PetscCall(MatSetValues(jac, i1, [row], i5, col, v, INSERT_VALUES, ierr))
342d8606c27SBarry Smith              end if
343d8606c27SBarry Smith20            continue
344d8606c27SBarry Smith10            continue
345d8606c27SBarry Smith              PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY, ierr))
346d8606c27SBarry Smith              PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY, ierr))
347ce78bad3SBarry Smith              PetscCall(VecRestoreArray(X, xx, ierr))
348d8606c27SBarry Smith            end
349d8606c27SBarry Smith
350d8606c27SBarry Smith!/*TEST
351d8606c27SBarry Smith!
352d8606c27SBarry Smith!    test:
353d8606c27SBarry Smith!      TODO: broken
354d8606c27SBarry Smith!      args: -ksp_gmres_cgs_refinement_type refine_always -snes_type newtonls -ts_monitor_pseudo -ts_max_snes_failures 3 -ts_pseudo_frtol 1.e-5 -snes_stol 1e-5
355d8606c27SBarry Smith!
356d8606c27SBarry Smith!TEST*/
357