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