MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
PetscSolver.F90
Go to the documentation of this file.
2 #include <petsc/finclude/petscksp.h>
3  use petscksp
4  use kindmodule, only: i4b, dp, lgp
9  use petscmatrixmodule
17 
18  implicit none
19  private
20 
21  public :: create_petsc_solver
22 
23  !< Linear solver using PETSc KSP
24  type, public, extends(linearsolverbasetype) :: petscsolvertype
25  ksp :: ksp_petsc !< the KSP linear solver object
26  class(petscmatrixtype), pointer :: matrix => null() !< the system matrix in PETSc compatible format
27  mat, pointer :: mat_petsc => null() !< the PETSc internal matrix format
28 
29  type(imslinearsettingstype), pointer :: linear_settings => null() !< pointer to linear settings from IMS
30  logical(LGP) :: use_ims_pc !< when true, use custom IMS-style preconditioning
31  ksptype :: ksp_type !< the KSP solver type (CG, BCGS, ...)
32  pctype :: pc_type !< the (global) preconditioner type, should be parallel
33  pctype :: sub_pc_type !< the block preconditioner type (for the subdomain)
34  class(petsccnvgctxtype), pointer :: petsc_ctx => null() !< context for the PETSc custom convergence check
35  type(pcshellctxtype), pointer :: pc_context => null() !< context for the custom (IMS) precondioner
36  type(convergencesummarytype), pointer :: convergence_summary => null() !< data structure wrapping the convergence data
37 
38  contains
39  procedure :: initialize => petsc_initialize
40  procedure :: solve => petsc_solve
41  procedure :: print_summary => petsc_print_summary
42  procedure :: destroy => petsc_destroy
43  procedure :: create_matrix => petsc_create_matrix
44 
45  ! private
46  procedure, private :: petsc_check_settings
47  procedure, private :: get_options_mf6
48  procedure, private :: create_ksp
49  procedure, private :: create_convergence_check
50  procedure, private :: set_petsc_pc
51  procedure, private :: set_ims_pc
52  procedure, private :: print_vec
53  procedure, private :: print_petsc_version
54  end type petscsolvertype
55 
56 contains
57 
58  !> @brief Create a PETSc solver object
59  !<
60  function create_petsc_solver(sln_name) result(solver)
61  class(linearsolverbasetype), pointer :: solver !< Uninitialized instance of the PETSc solver
62  character(len=LENSOLUTIONNAME) :: sln_name !< the solution name
63  ! local
64  class(petscsolvertype), pointer :: petsc_solver
65  character(len=LINELENGTH) :: errmsg
66 
67  allocate (petsc_solver)
68  allocate (petsc_solver%petsc_ctx)
69 
70  solver => petsc_solver
71  solver%name = sln_name
72 
73  if (simulation_mode /= 'PARALLEL') then
74  write (errmsg, '(a,a)') 'PETSc solver not supported for run mode: ', &
75  trim(simulation_mode)
76  call store_error(errmsg, terminate=.true.)
77  end if
78 
79  end function create_petsc_solver
80 
81  !> @brief Initialize PETSc KSP solver with
82  !< options from the petsc database file
83  subroutine petsc_initialize(this, matrix, linear_settings, convergence_summary)
84  class(petscsolvertype) :: this !< This solver instance
85  class(matrixbasetype), pointer :: matrix !< The solution matrix as KSP operator
86  type(imslinearsettingstype), pointer :: linear_settings !< the settings for the linear solver from the .ims file
87  type(convergencesummarytype), pointer :: convergence_summary !< a convergence record for diagnostics
88 
89  this%linear_settings => linear_settings
90 
91  call this%print_petsc_version()
92 
93  this%mat_petsc => null()
94  select type (pm => matrix)
95  class is (petscmatrixtype)
96  this%matrix => pm
97  this%mat_petsc => pm%mat
98  end select
99 
100  call this%petsc_check_settings(linear_settings)
101 
102  this%use_ims_pc = .true. ! default is true, override with .petscrc
103  allocate (this%pc_context)
104  call this%pc_context%create(this%matrix, linear_settings)
105 
106  if (linear_settings%ilinmeth == cg_method) then
107  this%ksp_type = kspcg
108  else
109  this%ksp_type = kspbcgs
110  end if
111 
112  this%pc_type = pcbjacobi
113  this%sub_pc_type = pcilu
114 
115  ! get MODFLOW options from PETSc database file
116  call this%get_options_mf6()
117 
118  ! create the solver object
119  call this%create_ksp()
120 
121  ! Create custom convergence check
122  call this%create_convergence_check(convergence_summary)
123 
124  end subroutine petsc_initialize
125 
126  subroutine petsc_check_settings(this, linear_settings)
127  class(petscsolvertype) :: this
128  type(imslinearsettingstype), pointer :: linear_settings
129  ! local
130  character(len=LINELENGTH) :: warnmsg, errmsg
131 
132  ! errors
133  if (linear_settings%ilinmeth /= cg_method .and. &
134  linear_settings%ilinmeth /= bcgs_method) then
135  write (errmsg, '(a,a)') 'PETSc: unknown linear solver method in ', &
136  this%name
137  call store_error(errmsg, terminate=.true.)
138  end if
139 
140  ! warnings
141  if (linear_settings%iord > 0) then
142  linear_settings%iord = 0
143  write (warnmsg, '(a)') 'PETSc: IMS reordering not supported'
144  call store_warning(warnmsg)
145  end if
146  if (linear_settings%iscl > 0) then
147  linear_settings%iscl = 0
148  write (warnmsg, '(a)') 'PETSc: IMS matrix scaling not supported'
149  call store_warning(warnmsg)
150  end if
151  if (linear_settings%north > 0) then
152  linear_settings%north = 0
153  write (warnmsg, '(a)') 'PETSc: IMS orthogonalization not supported'
154  call store_warning(warnmsg)
155  end if
156 
157  end subroutine petsc_check_settings
158 
159  !> @brief Print PETSc version string from shared lib
160  !<
161  subroutine print_petsc_version(this)
162  class(petscsolvertype) :: this
163  ! local
164  petscerrorcode :: ierr
165  petscint :: major, minor, subminor, release
166  character(len=128) :: petsc_version, release_str
167 
168  call petscgetversionnumber(major, minor, subminor, release, ierr)
169  chkerrq(ierr)
170 
171  if (release == 1) then
172  release_str = "(release)"
173  else
174  release_str = "(unofficial)"
175  end if
176  write (petsc_version, '(i0,a,i0,a,i0,a,a)') &
177  major, ".", minor, ".", subminor, " ", trim(release_str)
178  write (iout, '(/,1x,4a,/)') "PETSc Linear Solver will be used for ", &
179  trim(this%name), ": version ", petsc_version
180 
181  end subroutine print_petsc_version
182 
183  !> @brief Get the MODFLOW specific options from the PETSc database
184  !<
185  subroutine get_options_mf6(this)
186  class(petscsolvertype) :: this
187  ! local
188  petscerrorcode :: ierr
189  logical(LGP) :: found
190 
191  call petscoptionsgetbool(petsc_null_options, petsc_null_character, &
192  '-ims_pc', this%use_ims_pc, found, ierr)
193  chkerrq(ierr)
194 
195  end subroutine get_options_mf6
196 
197  !> @brief Create the PETSc KSP object
198  !<
199  subroutine create_ksp(this)
200  class(petscsolvertype) :: this !< This solver instance
201  ! local
202  petscerrorcode :: ierr
203 
204  call kspcreate(petsc_comm_world, this%ksp_petsc, ierr)
205  chkerrq(ierr)
206 
207  call kspsetoperators(this%ksp_petsc, this%mat_petsc, this%mat_petsc, ierr)
208  chkerrq(ierr)
209 
210  call kspsetinitialguessnonzero(this%ksp_petsc, .true., ierr)
211  chkerrq(ierr)
212 
213  call kspsettype(this%ksp_petsc, this%ksp_type, ierr)
214  chkerrq(ierr)
215 
216  if (this%use_ims_pc) then
217  call this%set_ims_pc()
218  else
219  call this%set_petsc_pc()
220  end if
221 
222  call kspseterrorifnotconverged(this%ksp_petsc, .false., ierr)
223  chkerrq(ierr)
224 
225  ! finally override these options from the
226  ! optional .petscrc file
227  call kspsetfromoptions(this%ksp_petsc, ierr)
228  chkerrq(ierr)
229 
230  end subroutine create_ksp
231 
232  !> @brief Set up a standard PETSc preconditioner from
233  !< the configured settings
234  subroutine set_petsc_pc(this)
235  class(petscsolvertype) :: this !< This solver instance
236  ! local
237  pc :: pc, sub_pc
238  ksp, dimension(1) :: sub_ksp
239  petscint :: n_local, n_first
240  petscerrorcode :: ierr
241 
242  call kspgetpc(this%ksp_petsc, pc, ierr)
243  chkerrq(ierr)
244  call pcsettype(pc, this%pc_type, ierr)
245  chkerrq(ierr)
246  call pcsetup(pc, ierr)
247  chkerrq(ierr)
248  call pcbjacobigetsubksp(pc, n_local, n_first, sub_ksp, ierr)
249  chkerrq(ierr)
250  call kspgetpc(sub_ksp(1), sub_pc, ierr)
251  chkerrq(ierr)
252  call pcsettype(sub_pc, this%sub_pc_type, ierr)
253  chkerrq(ierr)
254  call pcsetfromoptions(sub_pc, ierr)
255  chkerrq(ierr)
256  call pcfactorsetlevels(sub_pc, this%linear_settings%level, ierr)
257  chkerrq(ierr)
258 
259  end subroutine set_petsc_pc
260 
261  !> @brief Set up a custom preconditioner following the ones
262  !< we have in IMS, i.e. Modified ILU(T)
263  subroutine set_ims_pc(this)
264  class(petscsolvertype) :: this !< This solver instance
265  ! local
266  pc :: pc, sub_pc
267  ksp, dimension(1) :: sub_ksp
268  petscint :: n_local, n_first
269  petscerrorcode :: ierr
270 
271  this%sub_pc_type = pcshell
272 
273  call kspgetpc(this%ksp_petsc, pc, ierr)
274  chkerrq(ierr)
275  call pcsettype(pc, this%pc_type, ierr)
276  chkerrq(ierr)
277  call pcsetup(pc, ierr)
278  chkerrq(ierr)
279  call pcbjacobigetsubksp(pc, n_local, n_first, sub_ksp, ierr)
280  chkerrq(ierr)
281  call kspgetpc(sub_ksp(1), sub_pc, ierr)
282  chkerrq(ierr)
283  call pcsettype(sub_pc, this%sub_pc_type, ierr)
284  chkerrq(ierr)
285  call pcshellsetapply(sub_pc, pcshell_apply, ierr)
286  chkerrq(ierr)
287  call pcshellsetsetup(sub_pc, pcshell_setup, ierr)
288  chkerrq(ierr)
289  call pcshellsetcontext(sub_pc, this%pc_context, ierr)
290  chkerrq(ierr)
291 
292  end subroutine set_ims_pc
293 
294  !> @brief Create and assign a custom convergence
295  !< check for this solver
296  subroutine create_convergence_check(this, convergence_summary)
298  class(petscsolvertype) :: this !< This solver instance
299  type(convergencesummarytype), pointer :: convergence_summary
300  ! local
301  petscerrorcode :: ierr
302 
303  call this%petsc_ctx%create(this%mat_petsc, this%linear_settings, &
304  convergence_summary)
305 
306  call kspsetconvergencetest(this%ksp_petsc, petsc_check_convergence, &
307  this%petsc_ctx, petsc_null_function, ierr)
308  chkerrq(ierr)
309 
310  end subroutine create_convergence_check
311 
312  subroutine petsc_solve(this, kiter, rhs, x, cnvg_summary)
313  class(petscsolvertype) :: this
314  integer(I4B) :: kiter
315  class(vectorbasetype), pointer :: rhs
316  class(vectorbasetype), pointer :: x
317  type(convergencesummarytype) :: cnvg_summary
318  ! local
319  petscerrorcode :: ierr
320  class(petscvectortype), pointer :: rhs_petsc, x_petsc
321  kspconvergedreason :: cnvg_reason
322  integer :: it_number
323  character(len=LINELENGTH) :: errmsg
324 
325  rhs_petsc => null()
326  select type (rhs)
327  class is (petscvectortype)
328  rhs_petsc => rhs
329  end select
330 
331  x_petsc => null()
332  select type (x)
333  class is (petscvectortype)
334  x_petsc => x
335  end select
336 
337  this%iteration_number = 0
338  this%is_converged = 0
339  if (kiter == 1) then
340  this%petsc_ctx%cnvg_summary%iter_cnt = 0
341  end if
342 
343  ! update matrix coefficients
344  call this%matrix%update()
345  call kspsolve(this%ksp_petsc, rhs_petsc%vec_impl, x_petsc%vec_impl, ierr)
346  chkerrq(ierr)
347 
348  call kspgetiterationnumber(this%ksp_petsc, it_number, ierr)
349  chkerrq(ierr)
350  this%iteration_number = it_number
351 
352  call kspgetconvergedreason(this%ksp_petsc, cnvg_reason, ierr)
353  chkerrq(ierr)
354  if (cnvg_reason > 0) then
355  if (this%petsc_ctx%icnvg_ims == -1) then
356  ! move to next Picard iteration (e.g. with 'STRICT' option)
357  this%is_converged = 0
358  else
359  ! linear convergence reached
360  this%is_converged = 1
361  end if
362  end if
363 
364  if (cnvg_reason < 0 .and. cnvg_reason /= ksp_diverged_its) then
365  write (errmsg, '(1x,3a,i0)') "PETSc convergence failure in ", &
366  trim(this%name), ": ", cnvg_reason
367  call store_error(errmsg, terminate=.true.)
368  end if
369 
370  end subroutine petsc_solve
371 
372  subroutine petsc_print_summary(this)
373  class(petscsolvertype) :: this
374  ! local
375  character(len=128) :: ksp_str, pc_str, subpc_str, &
376  dvclose_str, rclose_str, relax_str, dtol_str
377  integer :: ierr
378  pc :: pc
379 
380  call kspgettype(this%ksp_petsc, ksp_str, ierr)
381  chkerrq(ierr)
382  call kspgetpc(this%ksp_petsc, pc, ierr)
383  chkerrq(ierr)
384  call pcgettype(pc, pc_str, ierr)
385  chkerrq(ierr)
386  if (this%use_ims_pc) then
387  subpc_str = this%pc_context%ims_pc_type
388  else
389  subpc_str = this%sub_pc_type
390  end if
391 
392  write (dvclose_str, '(e15.5)') this%linear_settings%dvclose
393  write (rclose_str, '(e15.5)') this%linear_settings%rclose
394  write (relax_str, '(e15.5)') this%linear_settings%relax
395  write (dtol_str, '(e15.5)') this%linear_settings%droptol
396 
397  write (iout, '(/,7x,a)') "PETSc linear solver settings: "
398  write (iout, '(1x,a)') repeat('-', 66)
399  write (iout, '(1x,a,a)') "Linear acceleration method: ", trim(ksp_str)
400  write (iout, '(1x,a,a)') "Preconditioner type: ", trim(pc_str)
401  write (iout, '(1x,a,a)') "Sub-preconditioner type: ", trim(subpc_str)
402  write (iout, '(1x,a,i0)') "Maximum nr. of iterations: ", &
403  this%linear_settings%iter1
404  write (iout, '(1x,a,a)') &
405  "Dep. var. closure criterion: ", trim(adjustl(dvclose_str))
406  write (iout, '(1x,a,a)') &
407  "Residual closure criterion: ", trim(adjustl(rclose_str))
408  write (iout, '(1x,a,i0)') &
409  "Residual convergence option: ", this%linear_settings%icnvgopt
410  write (iout, '(1x,a,a)') &
411  "Relaxation factor MILU(T): ", trim(adjustl(relax_str))
412  write (iout, '(1x,a,i0)') &
413  "Fill level in factorization: ", this%linear_settings%level
414  write (iout, '(1x,a,a,/)') &
415  "Drop tolerance level fill: ", trim(adjustl(dtol_str))
416 
417  end subroutine petsc_print_summary
418 
419  subroutine petsc_destroy(this)
420  class(petscsolvertype) :: this
421  ! local
422  petscerrorcode :: ierr
423 
424  call kspdestroy(this%ksp_petsc, ierr)
425  chkerrq(ierr)
426 
427  ! delete context
428  call this%petsc_ctx%destroy()
429  deallocate (this%petsc_ctx)
430 
431  call this%pc_context%destroy()
432  deallocate (this%pc_context)
433 
434  end subroutine petsc_destroy
435 
436  function petsc_create_matrix(this) result(matrix)
437  class(petscsolvertype) :: this
438  class(matrixbasetype), pointer :: matrix
439  ! local
440  class(petscmatrixtype), pointer :: petsc_matrix
441 
442  allocate (petsc_matrix)
443  matrix => petsc_matrix
444 
445  end function petsc_create_matrix
446 
447  subroutine print_vec(this, vec, vec_name, kiter)
448  use tdismodule, only: nper, kstp
449  class(petscsolvertype) :: this
450  class(petscvectortype) :: vec
451  character(len=*) :: vec_name
452  integer(I4B) :: kiter
453  ! local
454  petscviewer :: viewer
455  character(len=24) :: filename
456  petscerrorcode :: ierr
457 
458  write (filename, '(2a,i0,a,i0,a,i0,a)') vec_name, '_', nper, &
459  '_', kstp, '_', kiter, '.txt'
460  call petscviewerasciiopen(petsc_comm_world, filename, viewer, ierr)
461  chkerrq(ierr)
462  call vecview(vec%vec_impl, viewer, ierr)
463  chkerrq(ierr)
464  call petscviewerdestroy(viewer, ierr)
465  chkerrq(ierr)
466 
467  end subroutine print_vec
468 
469 end module petscsolvermodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:44
integer(i4b), parameter lensolutionname
maximum length of the solution name
Definition: Constants.f90:20
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:64
subroutine destroy(this)
Cleanup.
This module contains the IMS linear accelerator subroutines.
real(dp) function ims_base_epfact(icnvgopt, kstp)
Function returning EPFACT.
integer(i4b), parameter, public cg_method
integer(i4b), parameter, public bcgs_method
This module defines variable data types.
Definition: kind.f90:8
subroutine, public petsc_check_convergence(ksp, n, rnorm_L2, flag, context, ierr)
Routine to check the convergence. This is called.
subroutine, public pcshell_setup(pc, ierr)
Set up the custom preconditioner.
subroutine, public pcshell_apply(pc, x, y, ierr)
Apply shell preconditioner.
class(linearsolverbasetype) function, pointer, public create_petsc_solver(sln_name)
Create a PETSc solver object.
Definition: PetscSolver.F90:61
subroutine print_vec(this, vec, vec_name, kiter)
subroutine petsc_check_settings(this, linear_settings)
subroutine petsc_solve(this, kiter, rhs, x, cnvg_summary)
subroutine petsc_initialize(this, matrix, linear_settings, convergence_summary)
Initialize PETSc KSP solver with.
Definition: PetscSolver.F90:84
subroutine set_ims_pc(this)
Set up a custom preconditioner following the ones.
subroutine print_petsc_version(this)
Print PETSc version string from shared lib.
subroutine set_petsc_pc(this)
Set up a standard PETSc preconditioner from.
class(matrixbasetype) function, pointer petsc_create_matrix(this)
subroutine get_options_mf6(this)
Get the MODFLOW specific options from the PETSc database.
subroutine create_convergence_check(this, convergence_summary)
Create and assign a custom convergence.
subroutine petsc_destroy(this)
subroutine petsc_print_summary(this)
subroutine create_ksp(this)
Create the PETSc KSP object.
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_warning(msg, substring)
Store warning message.
Definition: Sim.f90:236
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=linelength) simulation_mode
integer(i4b) iout
file unit number for simulation output
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:24
integer(i4b), pointer, public nper
number of stress period
Definition: tdis.f90:21
This structure stores the generic convergence info for a solution.
x vector from the previous iteration