Actual source code: ex1f.F90

  1: !
  2: !   Solves the time dependent Bratu problem using pseudo-timestepping
  3: !
  4: !   This code demonstrates how one may solve a nonlinear problem
  5: !   with pseudo-timestepping. In this simple example, the pseudo-timestep
  6: !   is the same for all grid points, i.e., this is equivalent to using
  7: !   the backward Euler method with a variable timestep.
  8: !
  9: !   Note: This example does not require pseudo-timestepping since it
 10: !   is an easy nonlinear problem, but it is included to demonstrate how
 11: !   the pseudo-timestepping may be done.
 12: !
 13: !   See snes/tutorials/ex4.c[ex4f.F] and
 14: !   snes/tutorials/ex5.c[ex5f.F] where the problem is described
 15: !   and solved using the method of Newton alone.
 16: !
 17: !
 18: !23456789012345678901234567890123456789012345678901234567890123456789012
 19: #include <petsc/finclude/petscts.h>
 20: module ex1fmodule
 21:   use petscts
 22:   implicit none
 23: contains
 24: !
 25: !  --------------------  Evaluate Function F(x) ---------------------
 26: !
 27:   subroutine FormFunction(ts, t, X, F, user, ierr)

 29:     TS ts
 30:     PetscReal t
 31:     Vec X, F
 32:     PetscReal user(3)
 33:     PetscErrorCode ierr
 34:     PetscInt i, j, row, mx, my
 35:     PetscReal two, lambda
 36:     PetscReal hx, hy, hxdhy, hydhx
 37:     PetscScalar ut, ub, ul, ur, u
 38:     PetscScalar uxx, uyy, sc
 39:     PetscScalar, pointer :: xx(:), ff(:)
 40:     PetscInt, parameter :: param = 1, lmx = 2, lmy = 3

 42:     two = 2.0

 44:     mx = int(user(lmx))
 45:     my = int(user(lmy))
 46:     lambda = user(param)

 48:     hx = 1.0/real(mx - 1)
 49:     hy = 1.0/real(my - 1)
 50:     sc = hx*hy
 51:     hxdhy = hx/hy
 52:     hydhx = hy/hx

 54:     PetscCall(VecGetArrayRead(X, xx, ierr))
 55:     PetscCall(VecGetArray(F, ff, ierr))
 56:     do j = 1, my
 57:       do i = 1, mx
 58:         row = i + (j - 1)*mx
 59:         if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
 60:           ff(row) = xx(row)
 61:         else
 62:           u = xx(row)
 63:           ub = xx(row - mx)
 64:           ul = xx(row - 1)
 65:           ut = xx(row + mx)
 66:           ur = xx(row + 1)
 67:           uxx = (-ur + two*u - ul)*hydhx
 68:           uyy = (-ut + two*u - ub)*hxdhy
 69:           ff(row) = -uxx - uyy + sc*lambda*exp(u)
 70:         end if
 71:       end do
 72:     end do

 74:     PetscCall(VecRestoreArrayRead(X, xx, ierr))
 75:     PetscCall(VecRestoreArray(F, ff, ierr))
 76:   end
 77: !
 78: !  --------------------  Evaluate Jacobian of F(x) --------------------
 79: !
 80:   subroutine FormJacobian(ts, ctime, X, JJ, B, user, ierr)

 82:     TS ts
 83:     Vec X
 84:     Mat JJ, B
 85:     PetscReal user(3), ctime
 86:     PetscErrorCode ierr
 87:     Mat jac
 88:     PetscInt i, j, row(1), mx, my
 89:     PetscInt col(5), i1, i5
 90:     PetscScalar two, one, lambda
 91:     PetscScalar v(5), sc
 92:     PetscScalar, pointer :: xx(:)
 93:     PetscReal hx, hy, hxdhy, hydhx

 95:     PetscInt, parameter :: param = 1, lmx = 2, lmy = 3

 97:     i1 = 1
 98:     i5 = 5
 99:     jac = B
100:     two = 2.0
101:     one = 1.0

103:     mx = int(user(lmx))
104:     my = int(user(lmy))
105:     lambda = user(param)

107:     hx = 1.0/real(mx - 1)
108:     hy = 1.0/real(my - 1)
109:     sc = hx*hy
110:     hxdhy = hx/hy
111:     hydhx = hy/hx

113:     PetscCall(VecGetArrayRead(X, xx, ierr))
114:     do j = 1, my
115:       do i = 1, mx
116: !
117: !      When inserting into PETSc matrices, indices start at 0
118: !
119:         row(1) = i - 1 + (j - 1)*mx
120:         if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
121:           PetscCall(MatSetValues(jac, i1, [row], i1, [row], [one], INSERT_VALUES, ierr))
122:         else
123:           v(1) = hxdhy
124:           col(1) = row(1) - mx
125:           v(2) = hydhx
126:           col(2) = row(1) - 1
127:           v(3) = -two*(hydhx + hxdhy) + sc*lambda*exp(xx(row(1)))
128:           col(3) = row(1)
129:           v(4) = hydhx
130:           col(4) = row(1) + 1
131:           v(5) = hxdhy
132:           col(5) = row(1) + mx
133:           PetscCall(MatSetValues(jac, i1, [row], i5, col, v, INSERT_VALUES, ierr))
134:         end if
135:       end do
136:     end do
137:     PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY, ierr))
138:     PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY, ierr))
139:     PetscCall(VecRestoreArray(X, xx, ierr))
140:   end
141: !
142: !  --------------------  Form initial approximation -----------------
143: !
144:   subroutine FormInitialGuess(X, user, ierr)

146:     Vec X
147:     PetscReal user(3)
148:     PetscInt i, j, row, mx, my
149:     PetscErrorCode ierr
150:     PetscReal one, lambda
151:     PetscReal temp1, temp, hx, hy
152:     PetscScalar, pointer :: xx(:)
153:     PetscInt, parameter :: param = 1, lmx = 2, lmy = 3

155:     one = 1.0

157:     mx = int(user(lmx))
158:     my = int(user(lmy))
159:     lambda = user(param)

161:     hy = one/(my - 1)
162:     hx = one/(mx - 1)

164:     PetscCall(VecGetArray(X, xx, ierr))
165:     temp1 = lambda/(lambda + one)
166:     do j = 1, my
167:       temp = min(j - 1, my - j)*hy
168:       do i = 1, mx
169:         row = i + (j - 1)*mx
170:         if (i == 1 .or. j == 1 .or. i == mx .or. j == my) then
171:           xx(row) = 0.0
172:         else
173:           xx(row) = temp1*sqrt(min(min(i - 1, mx - i)*hx, temp))
174:         end if
175:       end do
176:     end do
177:     PetscCall(VecRestoreArray(X, xx, ierr))
178:   end
179: end module ex1fmodule
180: program main
181:   use petscts
182:   use ex1fmodule
183:   implicit none
184: !
185: !  Create an application context to contain data needed by the
186: !  application-provided call-back routines, FormJacobian() and
187: !  FormFunction(). We use a double precision array with three
188: !  entries indexed by param, lmx, lmy.
189: !
190:   PetscReal user(3)
191:   PetscInt i5
192:   PetscInt, parameter :: param = 1, lmx = 2, lmy = 3
193: !
194: !   Data for problem
195: !
196:   TS ts
197:   Vec x, r
198:   Mat J
199:   PetscInt its, N, i1000, itmp
200:   PetscBool flg
201:   PetscErrorCode ierr
202:   PetscReal param_max, param_min, dt
203:   PetscReal tmax
204:   PetscReal ftime
205:   TSConvergedReason reason

207:   i5 = 5
208:   param_max = 6.81
209:   param_min = 0

211:   PetscCallA(PetscInitialize(ierr))
212:   user(lmx) = 4
213:   user(lmy) = 4
214:   user(param) = 6.0

216: !
217: !     Allow user to set the grid dimensions and nonlinearity parameter at run-time
218: !
219:   PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-mx', user(lmx), flg, ierr))
220:   itmp = 4
221:   PetscCallA(PetscOptionsGetInt(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-my', itmp, flg, ierr))
222:   user(lmy) = itmp
223:   PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-param', user(param), flg, ierr))
224:   if (user(param) >= param_max .or. user(param) <= param_min) then
225:     print *, 'Parameter is out of range'
226:   end if
227:   if (user(lmx) > user(lmy)) then
228:     dt = .5/user(lmx)
229:   else
230:     dt = .5/user(lmy)
231:   end if
232:   PetscCallA(PetscOptionsGetReal(PETSC_NULL_OPTIONS, PETSC_NULL_CHARACTER, '-dt', dt, flg, ierr))
233:   N = int(user(lmx)*user(lmy))

235: !
236: !      Create vectors to hold the solution and function value
237: !
238:   PetscCallA(VecCreateSeq(PETSC_COMM_SELF, N, x, ierr))
239:   PetscCallA(VecDuplicate(x, r, ierr))

241: !
242: !    Create matrix to hold Jacobian. Preallocate 5 nonzeros per row
243: !    in the sparse matrix. Note that this is not the optimal strategy see
244: !    the Performance chapter of the users manual for information on
245: !    preallocating memory in sparse matrices.
246: !
247:   i5 = 5
248:   PetscCallA(MatCreateSeqAIJ(PETSC_COMM_SELF, N, N, i5, PETSC_NULL_INTEGER_ARRAY, J, ierr))

250: !
251: !     Create timestepper context
252: !

254:   PetscCallA(TSCreate(PETSC_COMM_WORLD, ts, ierr))
255:   PetscCallA(TSSetProblemType(ts, TS_NONLINEAR, ierr))

257: !
258: !     Tell the timestepper context where to compute solutions
259: !

261:   PetscCallA(TSSetSolution(ts, x, ierr))

263: !
264: !    Provide the call-back for the nonlinear function we are
265: !    evaluating. Thus whenever the timestepping routines need the
266: !    function they will call this routine. Note the final argument
267: !    is the application context used by the call-back functions.
268: !

270:   PetscCallA(TSSetRHSFunction(ts, PETSC_NULL_VEC, FormFunction, user, ierr))

272: !
273: !     Set the Jacobian matrix and the function used to compute
274: !     Jacobians.
275: !

277:   PetscCallA(TSSetRHSJacobian(ts, J, J, FormJacobian, user, ierr))

279: !
280: !       For the initial guess for the problem
281: !

283:   PetscCallA(FormInitialGuess(x, user, ierr))

285: !
286: !       This indicates that we are using pseudo timestepping to
287: !     find a steady state solution to the nonlinear problem.
288: !

290:   PetscCallA(TSSetType(ts, TSPSEUDO, ierr))

292: !
293: !       Set the initial time to start at (this is arbitrary for
294: !     steady state problems and the initial timestep given above
295: !

297:   PetscCallA(TSSetTimeStep(ts, dt, ierr))

299: !
300: !      Set a large number of timesteps and final duration time
301: !     to insure convergence to steady state.
302: !
303:   i1000 = 1000
304:   tmax = 1.e12
305:   PetscCallA(TSSetMaxSteps(ts, i1000, ierr))
306:   PetscCallA(TSSetMaxTime(ts, tmax, ierr))
307:   PetscCallA(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER, ierr))

309: !
310: !      Set any additional options from the options database. This
311: !     includes all options for the nonlinear and linear solvers used
312: !     internally the timestepping routines.
313: !

315:   PetscCallA(TSSetFromOptions(ts, ierr))

317:   PetscCallA(TSSetUp(ts, ierr))

319: !
320: !      Perform the solve. This is where the timestepping takes place.
321: !
322:   PetscCallA(TSSolve(ts, x, ierr))
323:   PetscCallA(TSGetSolveTime(ts, ftime, ierr))
324:   PetscCallA(TSGetStepNumber(ts, its, ierr))
325:   PetscCallA(TSGetConvergedReason(ts, reason, ierr))

327:   write (6, 100) its, ftime, reason
328: 100 format('Number of pseudo time-steps ', i5, ' final time ', 1pe9.2, ' reason ', i3)

330: !
331: !     Free the data structures constructed above
332: !

334:   PetscCallA(VecDestroy(x, ierr))
335:   PetscCallA(VecDestroy(r, ierr))
336:   PetscCallA(MatDestroy(J, ierr))
337:   PetscCallA(TSDestroy(ts, ierr))
338:   PetscCallA(PetscFinalize(ierr))
339: end
340: !/*TEST
341: !
342: !    test:
343: !      TODO: broken
344: !      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
345: !
346: !TEST*/