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