MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
ImsLinearSettings.f90
Go to the documentation of this file.
2  use kindmodule
7  implicit none
8  private
9 
10  integer(I4B), public, parameter :: cg_method = 1
11  integer(I4B), public, parameter :: bcgs_method = 2
12 
13  !> @brief IMS linear preconditioner types
14  !<
15  enum, bind(C)
16  enumerator :: ipc_unknown = 0 !< preconditioner type not set
17  enumerator :: ipc_ilu0 = 1 !< ILU0 (incomplete LU, zero fill)
18  enumerator :: ipc_milu0 = 2 !< modified ILU0
19  enumerator :: ipc_ilut = 3 !< ILUT (incomplete LU with threshold)
20  enumerator :: ipc_milut = 4 !< modified ILUT
21  end enum
23  public :: resolve_ipc
24 
25  type, public :: imslinearsettingstype
26  character(len=LENMEMPATH) :: memory_path
27  real(dp), pointer :: dvclose => null() !< dependent variable closure criterion
28  real(dp), pointer :: rclose => null() !< residual closure criterion
29  integer(I4B), pointer :: icnvgopt => null() !< convergence option
30  integer(I4B), pointer :: iter1 => null() !< max. iterations
31  integer(I4B), pointer :: ilinmeth => null() !< linear solver method
32  integer(I4B), pointer :: iscl => null() !< scaling method
33  integer(I4B), pointer :: iord => null() !< reordering method
34  integer(I4B), pointer :: north => null() !< number of orthogonalizations
35  real(dp), pointer :: relax => null() !< relaxation factor
36  integer(I4B), pointer :: level => null() !< nr. of preconditioner levels
37  real(dp), pointer :: droptol => null() !< drop tolerance for preconditioner
38  integer(I4B), pointer :: ifdparam => null() !< complexity option
39  contains
40  procedure :: init
41  procedure :: preset_config
42  procedure :: read_from_file
43  procedure :: check_settings
44  procedure :: destroy
45  end type
46 
47 contains
48 
49  subroutine init(this, mem_path)
51  class(imslinearsettingstype) :: this !< linear settings
52  character(len=LENMEMPATH) :: mem_path !< solution memory path
53 
54  this%memory_path = create_mem_path(mem_path, 'IMSLINEAR')
55 
56  call mem_allocate(this%dvclose, 'DVCLOSE', this%memory_path)
57  call mem_allocate(this%rclose, 'RCLOSE', this%memory_path)
58  call mem_allocate(this%icnvgopt, 'ICNVGOPT', this%memory_path)
59  call mem_allocate(this%iter1, 'ITER1', this%memory_path)
60  call mem_allocate(this%ilinmeth, 'ILINMETH', this%memory_path)
61  call mem_allocate(this%iscl, 'ISCL', this%memory_path)
62  call mem_allocate(this%iord, 'IORD', this%memory_path)
63  call mem_allocate(this%north, 'NORTH', this%memory_path)
64  call mem_allocate(this%relax, 'RELAX', this%memory_path)
65  call mem_allocate(this%level, 'LEVEL', this%memory_path)
66  call mem_allocate(this%droptol, 'DROPTOL', this%memory_path)
67  call mem_allocate(this%ifdparam, 'IDFPARAM', this%memory_path)
68 
69  ! defaults
70  this%dvclose = dzero
71  this%rclose = dzero
72  this%icnvgopt = 0
73  this%iter1 = 0
74  this%ilinmeth = 0
75  this%iscl = 0
76  this%iord = 0
77  this%north = 0
78  this%relax = dzero
79  this%level = 0
80  this%droptol = dzero
81  this%ifdparam = 0
82 
83  end subroutine init
84 
85  !> @brief Set solver pre-configured settings based on complexity option
86  !<
87  subroutine preset_config(this, idfparam)
88  class(imslinearsettingstype) :: this !< linear settings
89  integer(I4B) :: idfparam !< complexity option
90 
91  this%ifdparam = idfparam
92 
93  select case (idfparam)
94  case (1) ! Simple option
95  this%iter1 = 50
96  this%ilinmeth = 1
97  this%iscl = 0
98  this%iord = 0
99  this%dvclose = dem3
100  this%rclose = dem1
101  this%relax = dzero
102  this%level = 0
103  this%droptol = dzero
104  this%north = 0
105  case (2) ! Moderate
106  this%iter1 = 100
107  this%ilinmeth = 2
108  this%iscl = 0
109  this%iord = 0
110  this%dvclose = dem2
111  this%rclose = dem1
112  this%relax = 0.97d0
113  this%level = 0
114  this%droptol = dzero
115  this%north = 0
116  case (3) ! Complex
117  this%iter1 = 500
118  this%ilinmeth = 2
119  this%iscl = 0
120  this%iord = 0
121  this%dvclose = dem1
122  this%rclose = dem1
123  this%relax = dzero
124  this%level = 5
125  this%droptol = dem4
126  this%north = 2
127  end select
128 
129  end subroutine preset_config
130 
131  !> @brief Read the settings for the linear solver from the .ims file,
132  !< overriding a possible pre-set configuration with set_complexity
133  subroutine read_from_file(this, parser, iout)
134  class(imslinearsettingstype) :: this !< linear settings
135  type(blockparsertype) :: parser !< block parser
136  integer(I4B) :: iout !< listing file
137  ! local
138  logical(LGP) :: block_found, end_of_block
139  integer(I4B) :: ierr
140  character(len=LINELENGTH) :: errmsg
141  character(len=LINELENGTH) :: keyword
142  integer(I4B) :: iscaling, iordering
143 
144  call parser%GetBlock('LINEAR', block_found, ierr, supportopenclose=.true., &
145  blockrequired=.false.)
146 
147  if (block_found) then
148  write (iout, '(/1x,a)') 'PROCESSING LINEAR DATA'
149  do
150  call parser%GetNextLine(end_of_block)
151  if (end_of_block) exit
152  call parser%GetStringCaps(keyword)
153  ! -- parse keyword
154  select case (keyword)
155  case ('INNER_DVCLOSE')
156  this%dvclose = parser%GetDouble()
157  case ('INNER_RCLOSE')
158  this%rclose = parser%GetDouble()
159  ! -- look for additional key words
160  call parser%GetStringCaps(keyword)
161  if (keyword == 'STRICT') then
162  this%icnvgopt = 1
163  else if (keyword == 'L2NORM_RCLOSE') then
164  this%icnvgopt = 2
165  else if (keyword == 'RELATIVE_RCLOSE') then
166  this%icnvgopt = 3
167  else if (keyword == 'L2NORM_RELATIVE_RCLOSE') then
168  this%icnvgopt = 4
169  end if
170  case ('INNER_MAXIMUM')
171  this%iter1 = parser%GetInteger()
172  case ('LINEAR_ACCELERATION')
173  call parser%GetStringCaps(keyword)
174  if (keyword .eq. 'CG') then
175  this%ilinmeth = 1
176  else if (keyword .eq. 'BICGSTAB') then
177  this%ilinmeth = 2
178  else
179  this%ilinmeth = 0
180  write (errmsg, '(3a)') &
181  'Unknown IMSLINEAR LINEAR_ACCELERATION method (', &
182  trim(keyword), ').'
183  call store_error(errmsg)
184  end if
185  case ('SCALING_METHOD')
186  call parser%GetStringCaps(keyword)
187  iscaling = 0
188  if (keyword .eq. 'NONE') then
189  iscaling = 0
190  else if (keyword .eq. 'DIAGONAL') then
191  iscaling = 1
192  else if (keyword .eq. 'L2NORM') then
193  iscaling = 2
194  else
195  write (errmsg, '(3a)') &
196  'Unknown IMSLINEAR SCALING_METHOD (', trim(keyword), ').'
197  call store_error(errmsg)
198  end if
199  this%iscl = iscaling
200  case ('RED_BLACK_ORDERING')
201  iordering = 0
202  case ('REORDERING_METHOD')
203  call parser%GetStringCaps(keyword)
204  iordering = 0
205  if (keyword == 'NONE') then
206  iordering = 0
207  else if (keyword == 'RCM') then
208  iordering = 1
209  else if (keyword == 'MD') then
210  iordering = 2
211  else
212  write (errmsg, '(3a)') &
213  'Unknown IMSLINEAR REORDERING_METHOD (', trim(keyword), ').'
214  call store_error(errmsg)
215  end if
216  this%iord = iordering
217  case ('NUMBER_ORTHOGONALIZATIONS')
218  this%north = parser%GetInteger()
219  case ('RELAXATION_FACTOR')
220  this%relax = parser%GetDouble()
221  case ('PRECONDITIONER_LEVELS')
222  this%level = parser%GetInteger()
223  if (this%level < 0) then
224  write (errmsg, '(a,1x,a)') &
225  'IMSLINEAR PRECONDITIONER_LEVELS must be greater than', &
226  'or equal to zero'
227  call store_error(errmsg)
228  end if
229  case ('PRECONDITIONER_DROP_TOLERANCE')
230  this%droptol = parser%GetDouble()
231  if (this%droptol < dzero) then
232  write (errmsg, '(a,1x,a)') &
233  'IMSLINEAR PRECONDITIONER_DROP_TOLERANCE', &
234  'must be greater than or equal to zero'
235  call store_error(errmsg)
236  end if
237  !
238  ! -- default
239  case default
240  write (errmsg, '(3a)') &
241  'Unknown IMSLINEAR keyword (', trim(keyword), ').'
242  call store_error(errmsg)
243  end select
244  end do
245  write (iout, '(1x,a)') 'END OF LINEAR DATA'
246  else
247  if (this%ifdparam == 0) THEN
248  write (errmsg, '(a)') 'NO LINEAR block detected.'
249  call store_error(errmsg)
250  end if
251  end if
252 
253  end subroutine read_from_file
254 
255  !> @brief Check the settings after reading the configuration from file
256  !<
257  subroutine check_settings(this)
258  class(imslinearsettingstype) :: this !< linear settings
259  ! local
260  character(len=LINELENGTH) :: warnmsg
261 
262  if (this%level == 0 .and. this%droptol > 0.0_dp) then
263  write (warnmsg, '(a)') "PRECONDITIONER_DROP_TOLERANCE is ignored because &
264  &PRECONDITIONER_LEVELS equals zero."
265  call store_warning(warnmsg)
266  end if
267 
268  end subroutine check_settings
269 
270  subroutine destroy(this)
271  class(imslinearsettingstype) :: this !< linear settings
272 
273  call mem_deallocate(this%dvclose)
274  call mem_deallocate(this%rclose)
275  call mem_deallocate(this%icnvgopt)
276  call mem_deallocate(this%iter1)
277  call mem_deallocate(this%ilinmeth)
278  call mem_deallocate(this%iscl)
279  call mem_deallocate(this%iord)
280  call mem_deallocate(this%north)
281  call mem_deallocate(this%relax)
282  call mem_deallocate(this%level)
283  call mem_deallocate(this%droptol)
284  call mem_deallocate(this%ifdparam)
285 
286  end subroutine destroy
287 
288  !> @brief Resolve the preconditioner enum from the ILU controls
289  !!
290  !! Maps the ILU fill level and relaxation factor to a specific IPC_*
291  !! preconditioner:
292  !! level > 0 -> IPC_ILUT (-> IPC_MILUT when relax > 0)
293  !! level == 0 -> IPC_ILU0 (-> IPC_MILU0 when relax > 0)
294  !!
295  !! Extracted into a pure function so the same resolution can be reused when
296  !! preconditioner settings change at runtime (e.g. by stress period).
297  !<
298  pure function resolve_ipc(level, relax) result(ipc)
299  integer(I4B), intent(in) :: level !< ILU fill level
300  real(dp), intent(in) :: relax !< relaxation factor (> 0 selects the modified ILU)
301  integer(I4B) :: ipc !< resolved preconditioner enum (IPC_*)
302  !
303  ! -- map explicitly to the target enum (do not rely on IPC_* being
304  ! consecutive); relax > 0 selects the modified variant
305  if (level > 0) then
306  if (relax > dzero) then
307  ipc = ipc_milut
308  else
309  ipc = ipc_ilut
310  end if
311  else
312  if (relax > dzero) then
313  ipc = ipc_milu0
314  else
315  ipc = ipc_ilu0
316  end if
317  end if
318  end function resolve_ipc
319 
320 end module
subroutine init()
Definition: GridSorting.f90:25
This module contains block parser methods.
Definition: BlockParser.f90:7
This module contains simulation constants.
Definition: Constants.f90:9
real(dp), parameter dem1
real constant 1e-1
Definition: Constants.f90:103
real(dp), parameter dem3
real constant 1e-3
Definition: Constants.f90:106
real(dp), parameter dem4
real constant 1e-4
Definition: Constants.f90:107
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter dem2
real constant 1e-2
Definition: Constants.f90:105
integer(i4b), parameter, public cg_method
subroutine read_from_file(this, parser, iout)
Read the settings for the linear solver from the .ims file,.
subroutine preset_config(this, idfparam)
Set solver pre-configured settings based on complexity option.
@, public ipc_ilu0
ILU0 (incomplete LU, zero fill)
@, public ipc_milut
modified ILUT
subroutine check_settings(this)
Check the settings after reading the configuration from file.
@, public ipc_unknown
preconditioner type not set
integer(i4b), parameter, public bcgs_method
@, public ipc_milu0
modified ILU0
pure integer(i4b) function, public resolve_ipc(level, relax)
Resolve the preconditioner enum from the ILU controls.
@, public ipc_ilut
ILUT (incomplete LU with threshold)
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory 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
subroutine, public deprecation_warning(cblock, cvar, cver, endmsg, iunit)
Store deprecation warning message.
Definition: Sim.f90:256