xref: /petsc/src/ts/tutorials/ex22f.F90 (revision b6fc232f590e1b277d693b71998c6db2a5e7c9c8)
1! Time-dependent advection-reaction PDE in 1d. Demonstrates IMEX methods
2!
3!   u_t + a1*u_x = -k1*u + k2*v + s1
4!   v_t + a2*v_x = k1*u - k2*v + s2
5!   0 < x < 1
6!   a1 = 1, k1 = 10^6, s1 = 0,
7!   a2 = 0, k2 = 2*k1, s2 = 1
8!
9!   Initial conditions:
10!   u(x,0) = 1 + s2*x
11!   v(x,0) = k0/k1*u(x,0) + s1/k1
12!
13!   Upstream boundary conditions:
14!   u(0,t) = 1-sin(12*t)^4
15!
16
17#include <petsc/finclude/petscts.h>
18#include <petsc/finclude/petscdmda.h>
19program main
20  use petscts
21  implicit none
22
23!
24!  Create an application context to contain data needed by the
25!  application-provided call-back routines, FormJacobian() and
26!  FormFunction(). We use a double precision array with six
27!  entries, two for each problem parameter a, k, s.
28!
29  PetscReal user(6)
30  integer user_a, user_k, user_s
31  parameter(user_a=0, user_k=2, user_s=4)
32
33  TS ts
34  SNES snes
35  SNESLineSearch linesearch
36  Vec X
37  Mat J
38  PetscInt mx
39  PetscErrorCode ierr
40  DM da
41  PetscReal ftime, dt
42  PetscReal one, pone
43  PetscInt im11, i2
44  PetscBool flg
45
46  im11 = 11
47  i2 = 2
48  one = 1.0
49  pone = one/10
50
51  PetscCallA(PetscInitialize(ierr))
52
53! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54!  Create distributed array (DMDA) to manage parallel grid and vectors
55! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
56  PetscCallA(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, im11, i2, i2, PETSC_NULL_INTEGER, da, ierr))
57  PetscCallA(DMSetFromOptions(da, ierr))
58  PetscCallA(DMSetUp(da, ierr))
59
60! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
61!    Extract global vectors from DMDA
62! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
63  PetscCallA(DMCreateGlobalVector(da, X, ierr))
64
65! Initialize user application context
66! Use zero-based indexing for command line parameters to match ex22.c
67  user(user_a + 1) = 1.0
68  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-a0', user(user_a + 1), flg, ierr))
69  user(user_a + 2) = 0.0
70  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-a1', user(user_a + 2), flg, ierr))
71  user(user_k + 1) = 1000000.0
72  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-k0', user(user_k + 1), flg, ierr))
73  user(user_k + 2) = 2*user(user_k + 1)
74  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-k1', user(user_k + 2), flg, ierr))
75  user(user_s + 1) = 0.0
76  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-s0', user(user_s + 1), flg, ierr))
77  user(user_s + 2) = 1.0
78  PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-s1', user(user_s + 2), flg, ierr))
79
80! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
81!    Create timestepping solver context
82! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
83  PetscCallA(TSCreate(PETSC_COMM_WORLD, ts, ierr))
84  PetscCallA(TSSetDM(ts, da, ierr))
85  PetscCallA(TSSetType(ts, TSARKIMEX, ierr))
86  PetscCallA(TSSetRHSFunction(ts, PETSC_NULL_VEC, FormRHSFunction, user, ierr))
87  PetscCallA(TSSetIFunction(ts, PETSC_NULL_VEC, FormIFunction, user, ierr))
88  PetscCallA(DMSetMatType(da, MATAIJ, ierr))
89  PetscCallA(DMCreateMatrix(da, J, ierr))
90  PetscCallA(TSSetIJacobian(ts, J, J, FormIJacobian, user, ierr))
91
92  PetscCallA(TSGetSNES(ts, snes, ierr))
93  PetscCallA(SNESGetLineSearch(snes, linesearch, ierr))
94  PetscCallA(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC, ierr))
95
96  ftime = 1.0
97  PetscCallA(TSSetMaxTime(ts, ftime, ierr))
98  PetscCallA(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER, ierr))
99
100! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
101!  Set initial conditions
102! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
103  PetscCallA(FormInitialSolution(ts, X, user, ierr))
104  PetscCallA(TSSetSolution(ts, X, ierr))
105  PetscCallA(VecGetSize(X, mx, ierr))
106!  Advective CFL, I don't know why it needs so much safety factor.
107  dt = pone*max(user(user_a + 1), user(user_a + 2))/mx
108  PetscCallA(TSSetTimeStep(ts, dt, ierr))
109
110! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111!   Set runtime options
112! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113  PetscCallA(TSSetFromOptions(ts, ierr))
114
115! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
116!  Solve nonlinear system
117! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
118  PetscCallA(TSSolve(ts, X, ierr))
119
120! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
121!  Free work space.
122! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123  PetscCallA(MatDestroy(J, ierr))
124  PetscCallA(VecDestroy(X, ierr))
125  PetscCallA(TSDestroy(ts, ierr))
126  PetscCallA(DMDestroy(da, ierr))
127  PetscCallA(PetscFinalize(ierr))
128contains
129
130! Small helper to extract the layout, result uses 1-based indexing.
131  subroutine GetLayout(da, mx, xs, xe, gxs, gxe, ierr)
132    use petscdm
133    implicit none
134
135    DM da
136    PetscInt mx, xs, xe, gxs, gxe
137    PetscErrorCode ierr
138    PetscInt xm, gxm
139    PetscCall(DMDAGetInfo(da, PETSC_NULL_INTEGER, mx, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, PETSC_NULL_ENUM, PETSC_NULL_ENUM, PETSC_NULL_ENUM, PETSC_NULL_ENUM, ierr))
140    PetscCall(DMDAGetCorners(da, xs, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, xm, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, ierr))
141    PetscCall(DMDAGetGhostCorners(da, gxs, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, gxm, PETSC_NULL_INTEGER, PETSC_NULL_INTEGER, ierr))
142    xs = xs + 1
143    gxs = gxs + 1
144    xe = xs + xm - 1
145    gxe = gxs + gxm - 1
146  end subroutine
147
148  subroutine FormIFunctionLocal(mx, xs, xe, gxs, gxe, x, xdot, f, a, k, s, ierr)
149    implicit none
150    PetscInt mx, xs, xe, gxs, gxe
151    PetscScalar x(2, xs:xe)
152    PetscScalar xdot(2, xs:xe)
153    PetscScalar f(2, xs:xe)
154    PetscReal a(2), k(2), s(2)
155    PetscErrorCode ierr
156    PetscInt i
157    do i = xs, xe
158      f(1, i) = xdot(1, i) + k(1)*x(1, i) - k(2)*x(2, i) - s(1)
159      f(2, i) = xdot(2, i) - k(1)*x(1, i) + k(2)*x(2, i) - s(2)
160    end do
161  end subroutine
162
163  subroutine FormIFunction(ts, t, X, Xdot, F, user, ierr)
164    use petscts
165    implicit none
166
167    TS ts
168    PetscReal t
169    Vec X, Xdot, F
170    PetscReal user(6)
171    PetscErrorCode ierr
172    integer user_a, user_k, user_s
173    parameter(user_a=1, user_k=3, user_s=5)
174
175    DM da
176    PetscInt mx, xs, xe, gxs, gxe
177    PetscScalar, pointer :: xx(:), xxdot(:), ff(:)
178
179    PetscCall(TSGetDM(ts, da, ierr))
180    PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))
181
182! Get access to vector data
183    PetscCall(VecGetArrayRead(X, xx, ierr))
184    PetscCall(VecGetArrayRead(Xdot, xxdot, ierr))
185    PetscCall(VecGetArray(F, ff, ierr))
186
187    PetscCall(FormIFunctionLocal(mx, xs, xe, gxs, gxe, xx, xxdot, ff, user(user_a), user(user_k), user(user_s), ierr))
188
189    PetscCall(VecRestoreArrayRead(X, xx, ierr))
190    PetscCall(VecRestoreArrayRead(Xdot, xxdot, ierr))
191    PetscCall(VecRestoreArray(F, ff, ierr))
192  end subroutine
193
194  subroutine FormRHSFunctionLocal(mx, xs, xe, gxs, gxe, t, x, f, a, k, s, ierr)
195    implicit none
196    PetscInt mx, xs, xe, gxs, gxe
197    PetscReal t
198    PetscScalar x(2, gxs:gxe), f(2, xs:xe)
199    PetscReal a(2), k(2), s(2)
200    PetscErrorCode ierr
201    PetscInt i, j
202    PetscReal hx, u0t(2)
203    PetscReal one, two, three, four, six, twelve
204    PetscReal half, third, twothird, sixth
205    PetscReal twelfth
206
207    one = 1.0
208    two = 2.0
209    three = 3.0
210    four = 4.0
211    six = 6.0
212    twelve = 12.0
213    hx = one/mx
214!     The Fortran standard only allows positive base for power functions; Nag compiler fails on this
215    u0t(1) = one - abs(sin(twelve*t))**four
216    u0t(2) = 0.0
217    half = one/two
218    third = one/three
219    twothird = two/three
220    sixth = one/six
221    twelfth = one/twelve
222    do i = xs, xe
223      do j = 1, 2
224        if (i == 1) then
225          f(j, i) = a(j)/hx*(third*u0t(j) + half*x(j, i) - x(j, i + 1)  &
226&              + sixth*x(j, i + 2))
227        else if (i == 2) then
228          f(j, i) = a(j)/hx*(-twelfth*u0t(j) + twothird*x(j, i - 1)    &
229&              - twothird*x(j, i + 1) + twelfth*x(j, i + 2))
230        else if (i == mx - 1) then
231          f(j, i) = a(j)/hx*(-sixth*x(j, i - 2) + x(j, i - 1)             &
232&         - half*x(j, i) - third*x(j, i + 1))
233        else if (i == mx) then
234          f(j, i) = a(j)/hx*(-x(j, i) + x(j, i - 1))
235        else
236          f(j, i) = a(j)/hx*(-twelfth*x(j, i - 2)                      &
237&              + twothird*x(j, i - 1)                                 &
238&              - twothird*x(j, i + 1) + twelfth*x(j, i + 2))
239        end if
240      end do
241    end do
242  end subroutine
243
244  subroutine FormRHSFunction(ts, t, X, F, user, ierr)
245    use petscts
246    implicit none
247
248    TS ts
249    PetscReal t
250    Vec X, F
251    PetscReal user(6)
252    PetscErrorCode ierr
253    integer user_a, user_k, user_s
254    parameter(user_a=1, user_k=3, user_s=5)
255    DM da
256    Vec Xloc
257    PetscInt mx, xs, xe, gxs, gxe
258    PetscScalar, pointer :: xx(:), ff(:)
259
260    PetscCall(TSGetDM(ts, da, ierr))
261    PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))
262
263!     Scatter ghost points to local vector,using the 2-step process
264!        DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
265!     By placing code between these two statements, computations can be
266!     done while messages are in transition.
267    PetscCall(DMGetLocalVector(da, Xloc, ierr))
268    PetscCall(DMGlobalToLocalBegin(da, X, INSERT_VALUES, Xloc, ierr))
269    PetscCall(DMGlobalToLocalEnd(da, X, INSERT_VALUES, Xloc, ierr))
270
271! Get access to vector data
272    PetscCall(VecGetArrayRead(Xloc, xx, ierr))
273    PetscCall(VecGetArray(F, ff, ierr))
274
275    PetscCall(FormRHSFunctionLocal(mx, xs, xe, gxs, gxe, t, xx, ff, user(user_a), user(user_k), user(user_s), ierr))
276
277    PetscCall(VecRestoreArrayRead(Xloc, xx, ierr))
278    PetscCall(VecRestoreArray(F, ff, ierr))
279    PetscCall(DMRestoreLocalVector(da, Xloc, ierr))
280  end subroutine
281
282! ---------------------------------------------------------------------
283!
284!  IJacobian - Compute IJacobian = dF/dU + shift*dF/dUdot
285!
286  subroutine FormIJacobian(ts, t, X, Xdot, shift, J, Jpre, user, ierr)
287    use petscts
288    implicit none
289
290    TS ts
291    PetscReal t, shift
292    Vec X, Xdot
293    Mat J, Jpre
294    PetscReal user(6)
295    PetscErrorCode ierr
296    integer user_a, user_k, user_s
297    parameter(user_a=0, user_k=2, user_s=4)
298
299    DM da
300    PetscInt mx, xs, xe, gxs, gxe
301    PetscInt i, i1, row, col
302    PetscReal k1, k2
303    PetscScalar val(4)
304
305    PetscCall(TSGetDM(ts, da, ierr))
306    PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))
307
308    i1 = 1
309    k1 = user(user_k + 1)
310    k2 = user(user_k + 2)
311    do i = xs, xe
312      row = i - gxs
313      col = i - gxs
314      val(1) = shift + k1
315      val(2) = -k2
316      val(3) = -k1
317      val(4) = shift + k2
318      PetscCall(MatSetValuesBlockedLocal(Jpre, i1, [row], i1, [col], val, INSERT_VALUES, ierr))
319    end do
320    PetscCall(MatAssemblyBegin(Jpre, MAT_FINAL_ASSEMBLY, ierr))
321    PetscCall(MatAssemblyEnd(Jpre, MAT_FINAL_ASSEMBLY, ierr))
322    if (J /= Jpre) then
323      PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY, ierr))
324      PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY, ierr))
325    end if
326  end subroutine
327
328  subroutine FormInitialSolutionLocal(mx, xs, xe, gxs, gxe, x, a, k, s, ierr)
329    implicit none
330    PetscInt mx, xs, xe, gxs, gxe
331    PetscScalar x(2, xs:xe)
332    PetscReal a(2), k(2), s(2)
333    PetscErrorCode ierr
334
335    PetscInt i
336    PetscReal one, hx, r, ik
337    one = 1.0
338    hx = one/mx
339    do i = xs, xe
340      r = i*hx
341      if (k(2) /= 0.0) then
342        ik = one/k(2)
343      else
344        ik = one
345      end if
346      x(1, i) = one + s(2)*r
347      x(2, i) = k(1)*ik*x(1, i) + s(2)*ik
348    end do
349  end subroutine
350
351  subroutine FormInitialSolution(ts, X, user, ierr)
352    use petscts
353    implicit none
354
355    TS ts
356    Vec X
357    PetscReal user(6)
358    PetscErrorCode ierr
359    integer user_a, user_k, user_s
360    parameter(user_a=1, user_k=3, user_s=5)
361
362    DM da
363    PetscInt mx, xs, xe, gxs, gxe
364    PetscScalar, pointer :: xx(:)
365
366    PetscCall(TSGetDM(ts, da, ierr))
367    PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))
368
369! Get access to vector data
370    PetscCall(VecGetArray(X, xx, ierr))
371
372    PetscCall(FormInitialSolutionLocal(mx, xs, xe, gxs, gxe, xx, user(user_a), user(user_k), user(user_s), ierr))
373
374    PetscCall(VecRestoreArray(X, xx, ierr))
375  end subroutine
376end program
377!/*TEST
378!
379!    test:
380!      args: -da_grid_x 200 -ts_arkimex_type 4
381!      requires: !single
382!      output_file: output/empty.out
383!
384!TEST*/
385