Actual source code: ex22f.F90

  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: !

 17: #include <petsc/finclude/petscts.h>
 18: #include <petsc/finclude/petscdmda.h>
 19: program main
 20:   use petscts
 21:   implicit none

 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)

 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

 46:   im11 = 11
 47:   i2 = 2
 48:   one = 1.0
 49:   pone = one/10

 51:   PetscCallA(PetscInitialize(ierr))

 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))

 60: ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 61: !    Extract global vectors from DMDA
 62: ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 63:   PetscCallA(DMCreateGlobalVector(da, X, ierr))

 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))

 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))

 92:   PetscCallA(TSGetSNES(ts, snes, ierr))
 93:   PetscCallA(SNESGetLineSearch(snes, linesearch, ierr))
 94:   PetscCallA(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC, ierr))

 96:   ftime = 1.0
 97:   PetscCallA(TSSetMaxTime(ts, ftime, ierr))
 98:   PetscCallA(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER, ierr))

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))

110: ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111: !   Set runtime options
112: ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113:   PetscCallA(TSSetFromOptions(ts, ierr))

115: ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
116: !  Solve nonlinear system
117: ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
118:   PetscCallA(TSSolve(ts, X, ierr))

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))
128: contains

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

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

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

163:   subroutine FormIFunction(ts, t, X, Xdot, F, user, ierr)
164:     use petscts
165:     implicit none

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)

175:     DM da
176:     PetscInt mx, xs, xe, gxs, gxe
177:     PetscScalar, pointer :: xx(:), xxdot(:), ff(:)

179:     PetscCall(TSGetDM(ts, da, ierr))
180:     PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))

182: ! Get access to vector data
183:     PetscCall(VecGetArrayRead(X, xx, ierr))
184:     PetscCall(VecGetArrayRead(Xdot, xxdot, ierr))
185:     PetscCall(VecGetArray(F, ff, ierr))

187:     PetscCall(FormIFunctionLocal(mx, xs, xe, gxs, gxe, xx, xxdot, ff, user(user_a), user(user_k), user(user_s), ierr))

189:     PetscCall(VecRestoreArrayRead(X, xx, ierr))
190:     PetscCall(VecRestoreArrayRead(Xdot, xxdot, ierr))
191:     PetscCall(VecRestoreArray(F, ff, ierr))
192:   end subroutine

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

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

244:   subroutine FormRHSFunction(ts, t, X, F, user, ierr)
245:     use petscts
246:     implicit none

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(:)

260:     PetscCall(TSGetDM(ts, da, ierr))
261:     PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))

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))

271: ! Get access to vector data
272:     PetscCall(VecGetArrayRead(Xloc, xx, ierr))
273:     PetscCall(VecGetArray(F, ff, ierr))

275:     PetscCall(FormRHSFunctionLocal(mx, xs, xe, gxs, gxe, t, xx, ff, user(user_a), user(user_k), user(user_s), ierr))

277:     PetscCall(VecRestoreArrayRead(Xloc, xx, ierr))
278:     PetscCall(VecRestoreArray(F, ff, ierr))
279:     PetscCall(DMRestoreLocalVector(da, Xloc, ierr))
280:   end subroutine

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

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)

299:     DM da
300:     PetscInt mx, xs, xe, gxs, gxe
301:     PetscInt i, i1, row, col
302:     PetscReal k1, k2
303:     PetscScalar val(4)

305:     PetscCall(TSGetDM(ts, da, ierr))
306:     PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))

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

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

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

351:   subroutine FormInitialSolution(ts, X, user, ierr)
352:     use petscts
353:     implicit none

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)

362:     DM da
363:     PetscInt mx, xs, xe, gxs, gxe
364:     PetscScalar, pointer :: xx(:)

366:     PetscCall(TSGetDM(ts, da, ierr))
367:     PetscCall(GetLayout(da, mx, xs, xe, gxs, gxe, ierr))

369: ! Get access to vector data
370:     PetscCall(VecGetArray(X, xx, ierr))

372:     PetscCall(FormInitialSolutionLocal(mx, xs, xe, gxs, gxe, xx, user(user_a), user(user_k), user(user_s), ierr))

374:     PetscCall(VecRestoreArray(X, xx, ierr))
375:   end subroutine
376: end 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*/