MODFLOW 6  version 6.7.0.dev0
USGS Modular Hydrologic Model
NumericalSolution.f90
Go to the documentation of this file.
1 ! This is the numerical solution module.
2 
4  use kindmodule, only: dp, i4b, lgp
5  use errorutilmodule, only: pstop
6  use timermodule, only: code_timer
8  dprec, dzero, dem20, dem15, dem6, &
11  tableft, tabright, &
12  mnormal, mvalidate, &
15  use tablemodule, only: tabletype, table_cr
16  Use messagemodule, only: write_message
17  use mathutilmodule, only: is_close
18  use versionmodule, only: idevelopmode
22  use listmodule, only: listtype
23  use listsmodule, only: basesolutionlist
31  use sparsemodule, only: sparsematrix
32  use simvariablesmodule, only: iout, isim_mode, errmsg, &
34  use simstagesmodule
36  use imslinearmodule
44 
45  implicit none
46  private
47 
48  public :: numericalsolutiontype
52 
53  integer(I4B), parameter :: ims_solver = 1
54  integer(I4B), parameter :: petsc_solver = 2
55 
57  character(len=LENMEMPATH) :: memory_path !< the path for storing solution variables in the memory manager
58  character(len=LINELENGTH) :: fname !< input file name
59  character(len=16) :: solver_mode !< the type of solve: sequential, parallel, mayve block, etc.
60  type(listtype), pointer :: modellist !< list of models in solution
61  type(listtype), pointer :: exchangelist !< list of exchanges in solution
62  integer(I4B), pointer :: id !< solution number
63  integer(I4B), pointer :: iu !< input file unit
64  real(dp), pointer :: ttform !< timer - total formulation time
65  real(dp), pointer :: ttsoln !< timer - total solution time
66  integer(I4B), pointer :: isymmetric => null() !< flag indicating if matrix symmetry is required
67  integer(I4B), pointer :: neq => null() !< number of equations
68  integer(I4B), pointer :: matrix_offset => null() !< offset of linear system when part of distributed solution
69  class(linearsolverbasetype), pointer :: linear_solver => null() !< the linear solver for this solution
70  class(matrixbasetype), pointer :: system_matrix => null() !< sparse A-matrix for the system of equations
71  class(vectorbasetype), pointer :: vec_rhs => null() !< the right-hand side vector
72  class(vectorbasetype), pointer :: vec_x => null() !< the dependent-variable vector
73  real(dp), dimension(:), pointer, contiguous :: rhs => null() !< right-hand side vector values
74  real(dp), dimension(:), pointer, contiguous :: x => null() !< dependent-variable vector values
75  integer(I4B), dimension(:), pointer, contiguous :: active => null() !< active cell array
76  real(dp), dimension(:), pointer, contiguous :: xtemp => null() !< temporary vector for previous dependent-variable iterate
77  type(blockparsertype) :: parser !< block parser object
78  !
79  ! -- sparse matrix data
80  real(dp), pointer :: theta => null() !< under-relaxation theta
81  real(dp), pointer :: akappa => null() !< under-relaxation kappa
82  real(dp), pointer :: gamma => null() !< under-relaxation gamma
83  real(dp), pointer :: amomentum => null() !< under-relaxation momentum term
84  real(dp), pointer :: breduc => null() !< backtracking reduction factor
85  real(dp), pointer :: btol => null() !< backtracking tolerance
86  real(dp), pointer :: res_lim => null() !< backtracking residual threshold
87  real(dp), pointer :: dvclose => null() !< dependent-variable closure criteria
88  real(dp), pointer :: bigchold => null() !< cooley under-relaxation weight
89  real(dp), pointer :: bigch => null() !< under-relaxation maximum dependent-variable change
90  real(dp), pointer :: relaxold => null() !< under-relaxation previous relaxation factor
91  real(dp), pointer :: res_prev => null() !< previous L-2 norm
92  real(dp), pointer :: res_new => null() !< current L-2 norm
93  integer(I4B), pointer :: icnvg => null() !< convergence flag (1) non-convergence (0)
94  integer(I4B), pointer :: itertot_timestep => null() !< total nr. of linear solves per call to sln_ca
95  integer(I4B), pointer :: iouttot_timestep => null() !< total nr. of outer iterations per call to sln_ca
96  integer(I4B), pointer :: itertot_sim => null() !< total nr. of inner iterations for simulation
97  integer(I4B), pointer :: mxiter => null() !< maximum number of Picard iterations
98  integer(I4B), pointer :: linsolver => null() !< linear solver used (IMS, PETSC, ...)
99  integer(I4B), pointer :: nonmeth => null() !< under-relaxation method used
100  integer(I4B), pointer :: numtrack => null() !< maximum number of backtracks
101  integer(I4B), pointer :: iprims => null() !< solver print option
102  integer(I4B), pointer :: ibflag => null() !< backtracking flag (1) on (0) off
103  integer(I4B), dimension(:, :), pointer, contiguous :: lrch => null() !< location of the largest dependent-variable change at the end of a Picard iteration
104  real(dp), dimension(:), pointer, contiguous :: hncg => null() !< largest dependent-variable change at the end of a Picard iteration
105  real(dp), dimension(:), pointer, contiguous :: dxold => null() !< DBD under-relaxation previous dependent-variable change
106  real(dp), dimension(:), pointer, contiguous :: deold => null() !< DBD under-relaxation dependent-variable change variable
107  real(dp), dimension(:), pointer, contiguous :: wsave => null() !< DBD under-relaxation sign-change factor
108  real(dp), dimension(:), pointer, contiguous :: hchold => null() !< DBD under-relaxation weighted dependent-variable change
109  !
110  ! -- convergence summary information
111  character(len=31), dimension(:), pointer, contiguous :: caccel => null() !< convergence string
112  integer(I4B), pointer :: icsvouterout => null() !< Picard iteration CSV output flag and file unit
113  integer(I4B), pointer :: icsvinnerout => null() !< Inner iteration CSV output flag and file unit
114  integer(I4B), pointer :: nitermax => null() !< maximum number of iterations in a time step (maxiter * maxinner)
115  integer(I4B), pointer :: convnmod => null() !< number of models in the solution
116  integer(I4B), dimension(:), pointer, contiguous :: convmodstart => null() !< pointer to the start of each model in the convmod* arrays
117  !
118  ! -- refactoring
119  type(convergencesummarytype), pointer :: cnvg_summary => null() !< details on the convergence behavior within a timestep
120  type(imslinearsettingstype), pointer :: linear_settings => null() !< IMS settings for linear solver
121  !
122  ! -- pseudo-transient continuation
123  integer(I4B), pointer :: iallowptc => null() !< flag indicating if ptc applied this time step
124  integer(I4B), pointer :: iptcopt => null() !< option for how to calculate the initial PTC value (ptcdel0)
125  integer(I4B), pointer :: iptcout => null() !< PTC output flag and file unit
126  real(dp), pointer :: l2norm0 => null() !< L-2 norm at the start of the first Picard iteration
127  real(dp), pointer :: ptcdel => null() !< PTC delta value
128  real(dp), pointer :: ptcdel0 => null() !< initial PTC delta value
129  real(dp), pointer :: ptcexp => null() !< PTC exponent
130  !
131  ! -- adaptive time step
132  real(dp), pointer :: atsfrac => null() !< adaptive time step faction
133  !
134  ! -- linear accelerator storage
135  type(imslineardatatype), pointer :: imslinear => null() !< IMS linear acceleration object
136  !
137  ! -- sparse object
138  type(sparsematrix) :: sparse !< sparse object
139  !
140  ! -- table objects
141  type(tabletype), pointer :: innertab => null() !< inner iteration table object
142  type(tabletype), pointer :: outertab => null() !< Picard iteration table object
143  !
144  ! -- for synchronization of exchanges
145  class(*), pointer :: synchronize_ctx => null()
146  procedure(synchronize_iface), pointer :: synchronize => null()
147 
148  contains
149  procedure :: sln_df
150  procedure :: sln_ar
151  procedure :: sln_dt
152  procedure :: sln_ad
153  procedure :: sln_ot
154  procedure :: sln_ca
155  procedure :: sln_fp
156  procedure :: sln_da
157  procedure :: add_model
158  procedure :: add_exchange
159  procedure :: get_models
160  procedure :: get_exchanges
161  procedure :: save
162 
163  ! 'protected' (this can be overridden)
164  procedure :: sln_has_converged
168  procedure :: sln_calc_ptc
169  procedure :: sln_underrelax
172  procedure :: apply_backtracking
173 
174  ! private
175  procedure, private :: sln_connect
176  procedure, private :: sln_reset
177  procedure, private :: sln_ls
178  procedure, private :: sln_setouter
179  procedure, private :: sln_backtracking
180  procedure, private :: sln_maxval
181  procedure, private :: sln_calcdx
182  procedure, private :: sln_calc_residual
183  procedure, private :: sln_l2norm
184  procedure, private :: sln_get_dxmax
185  procedure, private :: sln_get_loc
186  procedure, private :: sln_get_nodeu
187  procedure, private :: allocate_scalars
188  procedure, private :: allocate_arrays
189  procedure, private :: convergence_summary
190  procedure, private :: csv_convergence_summary
191  procedure, private :: sln_buildsystem
192  procedure, private :: writecsvheader
193  procedure, private :: writeptcinfotofile
194 
195  ! Expose these for use through the BMI/XMI:
196  procedure, public :: preparesolve
197  procedure, public :: solve
198  procedure, public :: finalizesolve
199 
200  end type numericalsolutiontype
201 
202  abstract interface
203  subroutine synchronize_iface(solution, stage, ctx)
204  import numericalsolutiontype
205  import i4b
206  class(numericalsolutiontype) :: solution
207  integer(I4B) :: stage
208  class(*), pointer :: ctx
209  end subroutine synchronize_iface
210  end interface
211 
212 contains
213 
214  !> @ brief Create a new solution
215  !!
216  !! Create a new solution using the data in filename, assign this new
217  !! solution an id number and store the solution in the basesolutionlist.
218  !! Also open the filename for later reading.
219  !!
220  !<
221  subroutine create_numerical_solution(num_sol, filename, id)
222  ! -- modules
223  use simvariablesmodule, only: iout
225  ! -- dummy variables
226  class(numericalsolutiontype), pointer :: num_sol !< the create solution
227  character(len=*), intent(in) :: filename !< solution input file name
228  integer(I4B), intent(in) :: id !< solution id
229  ! -- local variables
230  integer(I4B) :: inunit
231  class(basesolutiontype), pointer :: solbase => null()
232  character(len=LENSOLUTIONNAME) :: solutionname
233  !
234  ! -- Create a new solution and add it to the basesolutionlist container
235  solbase => num_sol
236  write (solutionname, '(a, i0)') 'SLN_', id
237  !
238  num_sol%name = solutionname
239  num_sol%memory_path = create_mem_path(solutionname)
240  allocate (num_sol%modellist)
241  allocate (num_sol%exchangelist)
242  !
243  call num_sol%allocate_scalars()
244  !
246  !
247  num_sol%id = id
248  !
249  ! -- Open solution input file for reading later after problem size is known
250  ! Check to see if the file is already opened, which can happen when
251  ! running in single model mode
252  inquire (file=filename, number=inunit)
253 
254  if (inunit < 0) inunit = getunit()
255  num_sol%iu = inunit
256  write (iout, '(/a,a)') ' Creating solution: ', num_sol%name
257  call openfile(num_sol%iu, iout, filename, 'IMS')
258  !
259  ! -- Initialize block parser
260  call num_sol%parser%Initialize(num_sol%iu, iout)
261  end subroutine create_numerical_solution
262 
263  !> @ brief Allocate scalars
264  !!
265  !! Allocate scalars for a new solution.
266  !!
267  !<
268  subroutine allocate_scalars(this)
269  ! -- modules
271  ! -- dummy variables
272  class(numericalsolutiontype) :: this
273  !
274  ! -- allocate scalars
275  call mem_allocate(this%id, 'ID', this%memory_path)
276  call mem_allocate(this%iu, 'IU', this%memory_path)
277  call mem_allocate(this%ttform, 'TTFORM', this%memory_path)
278  call mem_allocate(this%ttsoln, 'TTSOLN', this%memory_path)
279  call mem_allocate(this%isymmetric, 'ISYMMETRIC', this%memory_path)
280  call mem_allocate(this%neq, 'NEQ', this%memory_path)
281  call mem_allocate(this%matrix_offset, 'MATRIX_OFFSET', this%memory_path)
282  call mem_allocate(this%dvclose, 'DVCLOSE', this%memory_path)
283  call mem_allocate(this%bigchold, 'BIGCHOLD', this%memory_path)
284  call mem_allocate(this%bigch, 'BIGCH', this%memory_path)
285  call mem_allocate(this%relaxold, 'RELAXOLD', this%memory_path)
286  call mem_allocate(this%res_prev, 'RES_PREV', this%memory_path)
287  call mem_allocate(this%res_new, 'RES_NEW', this%memory_path)
288  call mem_allocate(this%icnvg, 'ICNVG', this%memory_path)
289  call mem_allocate(this%itertot_timestep, 'ITERTOT_TIMESTEP', this%memory_path)
290  call mem_allocate(this%iouttot_timestep, 'IOUTTOT_TIMESTEP', this%memory_path)
291  call mem_allocate(this%itertot_sim, 'INNERTOT_SIM', this%memory_path)
292  call mem_allocate(this%mxiter, 'MXITER', this%memory_path)
293  call mem_allocate(this%linsolver, 'LINSOLVER', this%memory_path)
294  call mem_allocate(this%nonmeth, 'NONMETH', this%memory_path)
295  call mem_allocate(this%iprims, 'IPRIMS', this%memory_path)
296  call mem_allocate(this%theta, 'THETA', this%memory_path)
297  call mem_allocate(this%akappa, 'AKAPPA', this%memory_path)
298  call mem_allocate(this%gamma, 'GAMMA', this%memory_path)
299  call mem_allocate(this%amomentum, 'AMOMENTUM', this%memory_path)
300  call mem_allocate(this%breduc, 'BREDUC', this%memory_path)
301  call mem_allocate(this%btol, 'BTOL', this%memory_path)
302  call mem_allocate(this%res_lim, 'RES_LIM', this%memory_path)
303  call mem_allocate(this%numtrack, 'NUMTRACK', this%memory_path)
304  call mem_allocate(this%ibflag, 'IBFLAG', this%memory_path)
305  call mem_allocate(this%icsvouterout, 'ICSVOUTEROUT', this%memory_path)
306  call mem_allocate(this%icsvinnerout, 'ICSVINNEROUT', this%memory_path)
307  call mem_allocate(this%nitermax, 'NITERMAX', this%memory_path)
308  call mem_allocate(this%convnmod, 'CONVNMOD', this%memory_path)
309  call mem_allocate(this%iallowptc, 'IALLOWPTC', this%memory_path)
310  call mem_allocate(this%iptcopt, 'IPTCOPT', this%memory_path)
311  call mem_allocate(this%iptcout, 'IPTCOUT', this%memory_path)
312  call mem_allocate(this%l2norm0, 'L2NORM0', this%memory_path)
313  call mem_allocate(this%ptcdel, 'PTCDEL', this%memory_path)
314  call mem_allocate(this%ptcdel0, 'PTCDEL0', this%memory_path)
315  call mem_allocate(this%ptcexp, 'PTCEXP', this%memory_path)
316  call mem_allocate(this%atsfrac, 'ATSFRAC', this%memory_path)
317  !
318  ! -- initialize scalars
319  this%isymmetric = 0
320  this%id = 0
321  this%iu = 0
322  this%ttform = dzero
323  this%ttsoln = dzero
324  this%neq = 0
325  this%dvclose = dzero
326  this%bigchold = dzero
327  this%bigch = dzero
328  this%relaxold = dzero
329  this%res_prev = dzero
330  this%icnvg = 0
331  this%itertot_timestep = 0
332  this%iouttot_timestep = 0
333  this%itertot_sim = 0
334  this%mxiter = 0
335  this%linsolver = ims_solver
336  this%nonmeth = 0
337  this%iprims = 0
338  this%theta = done
339  this%akappa = dzero
340  this%gamma = done
341  this%amomentum = dzero
342  this%breduc = dzero
343  this%btol = 0
344  this%res_lim = dzero
345  this%numtrack = 0
346  this%ibflag = 0
347  this%icsvouterout = 0
348  this%icsvinnerout = 0
349  this%nitermax = 0
350  this%convnmod = 0
351  this%iallowptc = 1
352  this%iptcopt = 0
353  this%iptcout = 0
354  this%l2norm0 = dzero
355  this%ptcdel = dzero
356  this%ptcdel0 = dzero
357  this%ptcexp = done
358  this%atsfrac = donethird
359  end subroutine allocate_scalars
360 
361  !> @ brief Allocate arrays
362  !!
363  !! Allocate arrays for a new solution.
364  !!
365  !<
366  subroutine allocate_arrays(this)
367  ! -- modules
369  ! -- dummy variables
370  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
371  ! -- local variables
372  class(numericalmodeltype), pointer :: mp => null()
373  integer(I4B) :: i
374  integer(I4B) :: ieq
375  !
376  ! -- initialize the number of models in the solution
377  this%convnmod = this%modellist%Count()
378  !
379  ! -- allocate arrays
380  call mem_allocate(this%active, this%neq, 'IACTIVE', this%memory_path)
381  call mem_allocate(this%xtemp, this%neq, 'XTEMP', this%memory_path)
382  call mem_allocate(this%dxold, this%neq, 'DXOLD', this%memory_path)
383  call mem_allocate(this%hncg, 0, 'HNCG', this%memory_path)
384  call mem_allocate(this%lrch, 3, 0, 'LRCH', this%memory_path)
385  call mem_allocate(this%wsave, 0, 'WSAVE', this%memory_path)
386  call mem_allocate(this%hchold, 0, 'HCHOLD', this%memory_path)
387  call mem_allocate(this%deold, 0, 'DEOLD', this%memory_path)
388  call mem_allocate(this%convmodstart, this%convnmod + 1, 'CONVMODSTART', &
389  this%memory_path)
390  !
391  ! -- initialize allocated arrays
392  do i = 1, this%neq
393  this%xtemp(i) = dzero
394  this%dxold(i) = dzero
395  this%active(i) = 1 !default is active
396  end do
397  !
398  ! -- initialize convmodstart
399  ieq = 1
400  this%convmodstart(1) = ieq
401  do i = 1, this%modellist%Count()
402  mp => getnumericalmodelfromlist(this%modellist, i)
403  ieq = ieq + mp%neq
404  this%convmodstart(i + 1) = ieq
405  end do
406  end subroutine allocate_arrays
407 
408  !> @ brief Define the solution
409  !!
410  !! Define a new solution. Must be called after the models and exchanges have
411  !! been added to solution. The order of the steps is (1) Allocate neq and nja,
412  !! (2) Assign model offsets and solution ids, (3) Allocate and initialize
413  !! the solution arrays, (4) Point each model's x and rhs arrays, and
414  !! (5) Initialize the sparsematrix instance
415  !!
416  !<
417  subroutine sln_df(this)
418  ! modules
421  ! -- dummy variables
422  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
423  ! -- local variables
424  class(numericalmodeltype), pointer :: mp => null()
425  integer(I4B) :: i
426  integer(I4B), allocatable, dimension(:) :: rowmaxnnz
427  integer(I4B) :: ncol, irow_start, irow_end
428  integer(I4B) :: mod_offset
429  !
430  ! -- set sol id and determine nr. of equation in this solution
431  do i = 1, this%modellist%Count()
432  mp => getnumericalmodelfromlist(this%modellist, i)
433  call mp%set_idsoln(this%id)
434  this%neq = this%neq + mp%neq
435  end do
436  !
437  ! -- set up the (possibly parallel) linear system
438  if (simulation_mode == 'PARALLEL') then
439  this%solver_mode = 'PETSC'
440  else
441  this%solver_mode = 'IMS'
442  end if
443  !
444  ! -- allocate settings structure
445  allocate (this%linear_settings)
446  !
447  ! -- create linear system matrix and compatible vectors
448  this%linear_solver => create_linear_solver(this%solver_mode, this%name)
449  this%system_matrix => this%linear_solver%create_matrix()
450  this%vec_x => this%system_matrix%create_vec_mm(this%neq, 'X', &
451  this%memory_path)
452  this%x => this%vec_x%get_array()
453  this%vec_rhs => this%system_matrix%create_vec_mm(this%neq, 'RHS', &
454  this%memory_path)
455  this%rhs => this%vec_rhs%get_array()
456  !
457  call this%vec_rhs%get_ownership_range(irow_start, irow_end)
458  ncol = this%vec_rhs%get_size()
459  !
460  ! -- calculate and set offsets
461  mod_offset = irow_start - 1
462  this%matrix_offset = irow_start - 1
463  do i = 1, this%modellist%Count()
464  mp => getnumericalmodelfromlist(this%modellist, i)
465  call mp%set_moffset(mod_offset)
466  mod_offset = mod_offset + mp%neq
467  end do
468  !
469  ! -- Allocate and initialize solution arrays
470  call this%allocate_arrays()
471  !
472  ! -- Create convergence summary report
473  allocate (this%cnvg_summary)
474  call this%cnvg_summary%init(this%modellist%Count(), this%convmodstart, &
475  this%memory_path)
476  !
477  ! -- Go through each model and point x, ibound, and rhs to solution
478  do i = 1, this%modellist%Count()
479  mp => getnumericalmodelfromlist(this%modellist, i)
480  call mp%set_xptr(this%x, this%matrix_offset, 'X', this%name)
481  call mp%set_rhsptr(this%rhs, this%matrix_offset, 'RHS', this%name)
482  call mp%set_iboundptr(this%active, this%matrix_offset, 'IBOUND', this%name)
483  end do
484  !
485  ! -- Create the sparsematrix instance
486  allocate (rowmaxnnz(this%neq))
487  do i = 1, this%neq
488  rowmaxnnz(i) = 4
489  end do
490  call this%sparse%init(this%neq, ncol, rowmaxnnz)
491  this%sparse%offset = this%matrix_offset
492  deallocate (rowmaxnnz)
493  !
494  ! -- Assign connections, fill ia/ja, map connections
495  call this%sln_connect()
496  end subroutine sln_df
497 
498  !> @ brief Allocate and read data
499  !!
500  !! Allocate and read data for a solution.
501  !!
502  !<
503  subroutine sln_ar(this)
504  ! -- modules
506  use simvariablesmodule, only: iout
509  ! -- dummy variables
510  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
511  ! -- local variables
512  class(numericalmodeltype), pointer :: mp => null()
513  class(numericalexchangetype), pointer :: cp => null()
514  character(len=linelength) :: warnmsg
515  character(len=linelength) :: keyword
516  character(len=linelength) :: fname
517  character(len=linelength) :: msg
518  integer(I4B) :: i
519  integer(I4B) :: ifdparam, mxvl, npp
520  integer(I4B) :: ierr
521  logical(LGP) :: isfound, endOfBlock
522  integer(I4B) :: ival
523  real(DP) :: rval
524  character(len=*), parameter :: fmtcsvout = &
525  "(4x, 'CSV OUTPUT WILL BE SAVED TO FILE: ', a, &
526  &/4x, 'OPENED ON UNIT: ', I7)"
527  character(len=*), parameter :: fmtptcout = &
528  "(4x, 'PTC OUTPUT WILL BE SAVED TO FILE: ', a, &
529  &/4x, 'OPENED ON UNIT: ', I7)"
530  character(len=*), parameter :: fmterrasym = &
531  "(a,' **',a,'** PRODUCES AN ASYMMETRIC COEFFICIENT MATRIX, BUT THE &
532  &CONJUGATE GRADIENT METHOD WAS SELECTED. USE BICGSTAB INSTEAD. ')"
533  !
534  ! identify package and initialize.
535  WRITE (iout, 1) this%iu
536 00001 FORMAT(1x, /1x, 'IMS -- ITERATIVE MODEL SOLUTION PACKAGE, VERSION 6', &
537  ', 4/28/2017', /, 9x, 'INPUT READ FROM UNIT', i5)
538  !
539  ! -- initialize
540  i = 1
541  ifdparam = 1
542  npp = 0
543  mxvl = 0
544  !
545  ! -- get options block
546  call this%parser%GetBlock('OPTIONS', isfound, ierr, &
547  supportopenclose=.true., blockrequired=.false.)
548  !
549  ! -- parse options block if detected
550  if (isfound) then
551  write (iout, '(/1x,a)') 'PROCESSING IMS OPTIONS'
552  do
553  call this%parser%GetNextLine(endofblock)
554  if (endofblock) exit
555  call this%parser%GetStringCaps(keyword)
556  select case (keyword)
557  case ('PRINT_OPTION')
558  call this%parser%GetStringCaps(keyword)
559  if (keyword .eq. 'NONE') then
560  this%iprims = 0
561  else if (keyword .eq. 'SUMMARY') then
562  this%iprims = 1
563  else if (keyword .eq. 'ALL') then
564  this%iprims = 2
565  else
566  write (errmsg, '(3a)') &
567  'Unknown IMS print option (', trim(keyword), ').'
568  call store_error(errmsg)
569  end if
570  case ('COMPLEXITY')
571  call this%parser%GetStringCaps(keyword)
572  if (keyword .eq. 'SIMPLE') then
573  ifdparam = 1
574  WRITE (iout, 21)
575  else if (keyword .eq. 'MODERATE') then
576  ifdparam = 2
577  WRITE (iout, 23)
578  else if (keyword .eq. 'COMPLEX') then
579  ifdparam = 3
580  WRITE (iout, 25)
581  else
582  write (errmsg, '(3a)') &
583  'Unknown IMS COMPLEXITY option (', trim(keyword), ').'
584  call store_error(errmsg)
585  end if
586  case ('CSV_OUTER_OUTPUT')
587  call this%parser%GetStringCaps(keyword)
588  if (keyword == 'FILEOUT') then
589  call this%parser%GetString(fname)
590  if (nr_procs > 1) then
591  call append_processor_id(fname, proc_id)
592  end if
593  this%icsvouterout = getunit()
594  call openfile(this%icsvouterout, iout, fname, 'CSV_OUTER_OUTPUT', &
595  filstat_opt='REPLACE')
596  write (iout, fmtcsvout) trim(fname), this%icsvouterout
597  else
598  write (errmsg, '(a)') 'Optional CSV_OUTER_OUTPUT '// &
599  'keyword must be followed by FILEOUT'
600  call store_error(errmsg)
601  end if
602  case ('CSV_INNER_OUTPUT')
603  call this%parser%GetStringCaps(keyword)
604  if (keyword == 'FILEOUT') then
605  call this%parser%GetString(fname)
606  if (nr_procs > 1) then
607  call append_processor_id(fname, proc_id)
608  end if
609  this%icsvinnerout = getunit()
610  call openfile(this%icsvinnerout, iout, fname, 'CSV_INNER_OUTPUT', &
611  filstat_opt='REPLACE')
612  write (iout, fmtcsvout) trim(fname), this%icsvinnerout
613  else
614  write (errmsg, '(a)') 'Optional CSV_INNER_OUTPUT '// &
615  'keyword must be followed by FILEOUT'
616  call store_error(errmsg)
617  end if
618  case ('NO_PTC')
619  call this%parser%GetStringCaps(keyword)
620  select case (keyword)
621  case ('ALL')
622  ival = 0
623  msg = 'ALL'
624  case ('FIRST')
625  ival = -1
626  msg = 'THE FIRST'
627  case default
628  ival = 0
629  msg = 'ALL'
630  end select
631  this%iallowptc = ival
632  write (iout, '(1x,A)') 'PSEUDO-TRANSIENT CONTINUATION DISABLED FOR'// &
633  ' '//trim(adjustl(msg))//' STRESS-PERIOD(S)'
634  case ('ATS_OUTER_MAXIMUM_FRACTION')
635  rval = this%parser%GetDouble()
636  if (rval < dzero .or. rval > dhalf) then
637  write (errmsg, '(a,G0)') 'Value for ATS_OUTER_MAXIMUM_FRAC must be &
638  &between 0 and 0.5. Found ', rval
639  call store_error(errmsg)
640  end if
641  this%atsfrac = rval
642  write (iout, '(1x,A,G0)') 'ADAPTIVE TIME STEP SETTING FOUND. FRACTION &
643  &OF OUTER MAXIMUM USED TO INCREASE OR DECREASE TIME STEP SIZE IS ',&
644  &this%atsfrac
645  !
646  ! -- DEPRECATED OPTIONS
647  case ('CSV_OUTPUT')
648  call this%parser%GetStringCaps(keyword)
649  if (keyword == 'FILEOUT') then
650  call this%parser%GetString(fname)
651  this%icsvouterout = getunit()
652  call openfile(this%icsvouterout, iout, fname, 'CSV_OUTPUT', &
653  filstat_opt='REPLACE')
654  write (iout, fmtcsvout) trim(fname), this%icsvouterout
655  !
656  ! -- create warning message
657  write (warnmsg, '(a)') &
658  'OUTER ITERATION INFORMATION WILL BE SAVED TO '//trim(fname)
659  !
660  ! -- create deprecation warning
661  call deprecation_warning('OPTIONS', 'CSV_OUTPUT', '6.1.1', &
662  warnmsg, this%parser%GetUnit())
663  else
664  write (errmsg, '(a)') 'Optional CSV_OUTPUT '// &
665  'keyword must be followed by FILEOUT'
666  call store_error(errmsg)
667  end if
668  !
669  ! -- right now these are options that are only available in the
670  ! development version and are not included in the documentation.
671  ! These options are only available when IDEVELOPMODE in
672  ! constants module is set to 1
673  case ('DEV_PTC')
674  call this%parser%DevOpt()
675  this%iallowptc = 1
676  write (iout, '(1x,A)') 'PSEUDO-TRANSIENT CONTINUATION ENABLED'
677  case ('DEV_PTC_OUTPUT')
678  call this%parser%DevOpt()
679  this%iallowptc = 1
680  call this%parser%GetStringCaps(keyword)
681  if (keyword == 'FILEOUT') then
682  call this%parser%GetString(fname)
683  if (nr_procs > 1) then
684  call append_processor_id(fname, proc_id)
685  end if
686  this%iptcout = getunit()
687  call openfile(this%iptcout, iout, fname, 'PTC-OUT', &
688  filstat_opt='REPLACE')
689  write (iout, fmtptcout) trim(fname), this%iptcout
690  else
691  write (errmsg, '(a)') &
692  'Optional PTC_OUTPUT keyword must be followed by FILEOUT'
693  call store_error(errmsg)
694  end if
695  case ('DEV_PTC_OPTION')
696  call this%parser%DevOpt()
697  this%iallowptc = 1
698  this%iptcopt = 1
699  write (iout, '(1x,A)') &
700  'PSEUDO-TRANSIENT CONTINUATION USES BNORM AND L2NORM TO '// &
701  'SET INITIAL VALUE'
702  case ('DEV_PTC_EXPONENT')
703  call this%parser%DevOpt()
704  rval = this%parser%GetDouble()
705  if (rval < dzero) then
706  write (errmsg, '(a)') 'PTC_EXPONENT must be > 0.'
707  call store_error(errmsg)
708  else
709  this%iallowptc = 1
710  this%ptcexp = rval
711  write (iout, '(1x,A,1x,g15.7)') &
712  'PSEUDO-TRANSIENT CONTINUATION EXPONENT', this%ptcexp
713  end if
714  case ('DEV_PTC_DEL0')
715  call this%parser%DevOpt()
716  rval = this%parser%GetDouble()
717  if (rval < dzero) then
718  write (errmsg, '(a)') 'IMS sln_ar: PTC_DEL0 must be > 0.'
719  call store_error(errmsg)
720  else
721  this%iallowptc = 1
722  this%ptcdel0 = rval
723  write (iout, '(1x,A,1x,g15.7)') &
724  'PSEUDO-TRANSIENT CONTINUATION INITIAL TIMESTEP', this%ptcdel0
725  end if
726  case default
727  write (errmsg, '(a,2(1x,a))') &
728  'Unknown IMS option (', trim(keyword), ').'
729  call store_error(errmsg)
730  end select
731  end do
732  write (iout, '(1x,a)') 'END OF IMS OPTIONS'
733  else
734  write (iout, '(1x,a)') 'NO IMS OPTION BLOCK DETECTED.'
735  end if
736 
737 00021 FORMAT(1x, 'SIMPLE OPTION:', /, &
738  1x, 'DEFAULT SOLVER INPUT VALUES FOR FAST SOLUTIONS')
739 00023 FORMAT(1x, 'MODERATE OPTION:', /, 1x, 'DEFAULT SOLVER', &
740  ' INPUT VALUES REFLECT MODERATELY NONLINEAR MODEL')
741 00025 FORMAT(1x, 'COMPLEX OPTION:', /, 1x, 'DEFAULT SOLVER', &
742  ' INPUT VALUES REFLECT STRONGLY NONLINEAR MODEL')
743 
744  !-------READ NONLINEAR ITERATION PARAMETERS AND LINEAR SOLVER SELECTION INDEX
745  ! -- set default nonlinear parameters
746  call this%sln_setouter(ifdparam)
747  !
748  ! -- get NONLINEAR block
749  call this%parser%GetBlock('NONLINEAR', isfound, ierr, &
750  supportopenclose=.true., blockrequired=.false.)
751  !
752  ! -- parse NONLINEAR block if detected
753  if (isfound) then
754  write (iout, '(/1x,a)') 'PROCESSING IMS NONLINEAR'
755  do
756  call this%parser%GetNextLine(endofblock)
757  if (endofblock) exit
758  call this%parser%GetStringCaps(keyword)
759  ! -- parse keyword
760  select case (keyword)
761  case ('OUTER_DVCLOSE')
762  this%dvclose = this%parser%GetDouble()
763  case ('OUTER_MAXIMUM')
764  this%mxiter = this%parser%GetInteger()
765  case ('UNDER_RELAXATION')
766  call this%parser%GetStringCaps(keyword)
767  ival = 0
768  if (keyword == 'NONE') then
769  ival = 0
770  else if (keyword == 'SIMPLE') then
771  ival = 1
772  else if (keyword == 'COOLEY') then
773  ival = 2
774  else if (keyword == 'DBD') then
775  ival = 3
776  else
777  write (errmsg, '(3a)') &
778  'Unknown UNDER_RELAXATION specified (', trim(keyword), ').'
779  call store_error(errmsg)
780  end if
781  this%nonmeth = ival
782  case ('LINEAR_SOLVER')
783  call this%parser%GetStringCaps(keyword)
784  ival = ims_solver
785  if (keyword .eq. 'DEFAULT' .or. &
786  keyword .eq. 'LINEAR') then
787  ival = ims_solver
788  else
789  write (errmsg, '(3a)') &
790  'Unknown LINEAR_SOLVER specified (', trim(keyword), ').'
791  call store_error(errmsg)
792  end if
793  this%linsolver = ival
794  case ('UNDER_RELAXATION_THETA')
795  this%theta = this%parser%GetDouble()
796  case ('UNDER_RELAXATION_KAPPA')
797  this%akappa = this%parser%GetDouble()
798  case ('UNDER_RELAXATION_GAMMA')
799  this%gamma = this%parser%GetDouble()
800  case ('UNDER_RELAXATION_MOMENTUM')
801  this%amomentum = this%parser%GetDouble()
802  case ('BACKTRACKING_NUMBER')
803  this%numtrack = this%parser%GetInteger()
804  IF (this%numtrack > 0) this%ibflag = 1
805  case ('BACKTRACKING_TOLERANCE')
806  this%btol = this%parser%GetDouble()
807  case ('BACKTRACKING_REDUCTION_FACTOR')
808  this%breduc = this%parser%GetDouble()
809  case ('BACKTRACKING_RESIDUAL_LIMIT')
810  this%res_lim = this%parser%GetDouble()
811  !
812  ! -- deprecated variables
813  case ('OUTER_HCLOSE')
814  this%dvclose = this%parser%GetDouble()
815  !
816  ! -- create warning message
817  write (warnmsg, '(a)') &
818  'SETTING OUTER_DVCLOSE TO OUTER_HCLOSE VALUE'
819  !
820  ! -- create deprecation warning
821  call deprecation_warning('NONLINEAR', 'OUTER_HCLOSE', '6.1.1', &
822  warnmsg, this%parser%GetUnit())
823  case ('OUTER_RCLOSEBND')
824  !
825  ! -- create warning message
826  write (warnmsg, '(a)') &
827  'OUTER_DVCLOSE IS USED TO EVALUATE PACKAGE CONVERGENCE'
828  !
829  ! -- create deprecation warning
830  call deprecation_warning('NONLINEAR', 'OUTER_RCLOSEBND', '6.1.1', &
831  warnmsg, this%parser%GetUnit())
832  case default
833  write (errmsg, '(3a)') &
834  'Unknown IMS NONLINEAR keyword (', trim(keyword), ').'
835  call store_error(errmsg)
836  end select
837  end do
838  write (iout, '(1x,a)') 'END OF IMS NONLINEAR DATA'
839  else
840  if (ifdparam .EQ. 0) then
841  write (errmsg, '(a)') 'NO IMS NONLINEAR block detected.'
842  call store_error(errmsg)
843  end if
844  end if
845  !
846  if (this%theta < dem3) then
847  this%theta = dem3
848  end if
849  !
850  ! -- backtracking should only be used if this%nonmeth > 0
851  if (this%nonmeth < 1) then
852  this%ibflag = 0
853  end if
854  !
855  ! -- check that MXITER is greater than zero
856  if (this%mxiter <= 0) then
857  write (errmsg, '(a)') 'Outer iteration number must be > 0.'
858  call store_error(errmsg)
859  END IF
860  !
861  ! -- write under-relaxation option
862  if (this%nonmeth > 0) then
863  WRITE (iout, *) '**UNDER-RELAXATION WILL BE USED***'
864  WRITE (iout, *)
865  elseif (this%nonmeth == 0) then
866  WRITE (iout, *) '***UNDER-RELAXATION WILL NOT BE USED***'
867  WRITE (iout, *)
868  else
869  WRITE (errmsg, '(a)') &
870  'Incorrect value for variable NONMETH was specified.'
871  call store_error(errmsg)
872  end if
873  !
874  ! -- ensure gamma is > 0 for simple
875  if (this%nonmeth == 1) then
876  if (this%gamma == 0) then
877  WRITE (errmsg, '(a)') &
878  'GAMMA must be greater than zero if SIMPLE under-relaxation is used.'
879  call store_error(errmsg)
880  end if
881  end if
882 
883  if (this%solver_mode == 'PETSC') then
884  this%linsolver = petsc_solver
885  end if
886 
887  ! configure linear settings
888  call this%linear_settings%init(this%memory_path)
889  call this%linear_settings%preset_config(ifdparam)
890  call this%linear_settings%read_from_file(this%parser, iout)
891  !
892  if (this%linear_settings%ilinmeth == cg_method) then
893  this%isymmetric = 1
894  end if
895  !
896  ! -- call secondary subroutine to initialize and read linear
897  ! solver parameters IMSLINEAR solver
898  if (this%solver_mode == "IMS") then
899  allocate (this%imslinear)
900  WRITE (iout, *) '***IMS LINEAR SOLVER WILL BE USED***'
901  call this%imslinear%imslinear_allocate(this%name, iout, this%iprims, &
902  this%mxiter, this%neq, &
903  this%system_matrix, this%rhs, &
904  this%x, this%linear_settings)
905  !
906  ! -- petsc linear solver flag
907  else if (this%solver_mode == "PETSC") then
908  call this%linear_solver%initialize(this%system_matrix, &
909  this%linear_settings, &
910  this%cnvg_summary)
911  !
912  ! -- incorrect linear solver flag
913  else
914  write (errmsg, '(a)') &
915  'Incorrect value for linear solution method specified.'
916  call store_error(errmsg)
917  end if
918  !
919  ! -- write message about matrix symmetry
920  if (this%isymmetric == 1) then
921  write (iout, '(1x,a,/)') 'A symmetric matrix will be solved'
922  else
923  write (iout, '(1x,a,/)') 'An asymmetric matrix will be solved'
924  end if
925  !
926  ! -- If CG, then go through each model and each exchange and check
927  ! for asymmetry
928  if (this%isymmetric == 1) then
929  !
930  ! -- Models
931  do i = 1, this%modellist%Count()
932  mp => getnumericalmodelfromlist(this%modellist, i)
933  if (mp%get_iasym() /= 0) then
934  write (errmsg, fmterrasym) 'MODEL', trim(adjustl(mp%name))
935  call store_error(errmsg)
936  end if
937  end do
938  !
939  ! -- Exchanges
940  do i = 1, this%exchangelist%Count()
941  cp => getnumericalexchangefromlist(this%exchangelist, i)
942  if (cp%get_iasym() /= 0) then
943  write (errmsg, fmterrasym) 'EXCHANGE', trim(adjustl(cp%name))
944  call store_error(errmsg)
945  end if
946  end do
947  !
948  end if
949  !
950  ! -- write solver data to output file
951  !
952  ! -- non-linear solver data
953  WRITE (iout, 9002) this%dvclose, this%mxiter, &
954  this%iprims, this%nonmeth, this%linsolver
955  !
956  ! -- standard outer iteration formats
957 9002 FORMAT(1x, 'OUTER ITERATION CONVERGENCE CRITERION (DVCLOSE) = ', e15.6, &
958  /1x, 'MAXIMUM NUMBER OF OUTER ITERATIONS (MXITER) = ', i0, &
959  /1x, 'SOLVER PRINTOUT INDEX (IPRIMS) = ', i0, &
960  /1x, 'NONLINEAR ITERATION METHOD (NONLINMETH) = ', i0, &
961  /1x, 'LINEAR SOLUTION METHOD (LINMETH) = ', i0)
962  !
963  if (this%nonmeth == 1) then ! simple
964  write (iout, 9003) this%gamma
965  else if (this%nonmeth == 2) then ! cooley
966  write (iout, 9004) this%gamma
967  else if (this%nonmeth == 3) then ! delta bar delta
968  write (iout, 9005) this%theta, this%akappa, this%gamma, this%amomentum
969  end if
970  !
971  ! -- write backtracking information
972  if (this%numtrack /= 0) write (iout, 9006) this%numtrack, this%btol, &
973  this%breduc, this%res_lim
974  !
975  ! -- under-relaxation formats (simple, cooley, dbd)
976 9003 FORMAT(1x, 'UNDER-RELAXATION FACTOR (GAMMA) = ', e15.6)
977 9004 FORMAT(1x, 'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', e15.6)
978 9005 FORMAT(1x, 'UNDER-RELAXATION WEIGHT REDUCTION FACTOR (THETA) = ', e15.6, &
979  /1x, 'UNDER-RELAXATION WEIGHT INCREASE INCREMENT (KAPPA) = ', e15.6, &
980  /1x, 'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', e15.6, &
981  /1x, 'UNDER-RELAXATION MOMENTUM TERM (AMOMENTUM) = ', e15.6)
982  !
983  ! -- backtracking formats
984 9006 FORMAT(1x, 'MAXIMUM NUMBER OF BACKTRACKS (NUMTRACK) = ', i0, &
985  /1x, 'BACKTRACKING TOLERANCE FACTOR (BTOL) = ', e15.6, &
986  /1x, 'BACKTRACKING REDUCTION FACTOR (BREDUC) = ', e15.6, &
987  /1x, 'BACKTRACKING RESIDUAL LIMIT (RES_LIM) = ', e15.6)
988  !
989  ! -- linear solver data
990  if (this%linsolver == ims_solver) then
991  call this%imslinear%imslinear_summary(this%mxiter)
992  else
993  call this%linear_solver%print_summary()
994  end if
995 
996  ! -- write summary of solver error messages
997  ierr = count_errors()
998  if (ierr > 0) then
999  call this%parser%StoreErrorUnit()
1000  end if
1001  !
1002  ! reallocate space for nonlinear arrays and initialize
1003  call mem_reallocate(this%hncg, this%mxiter, 'HNCG', this%name)
1004  call mem_reallocate(this%lrch, 3, this%mxiter, 'LRCH', this%name)
1005 
1006  ! delta-bar-delta under-relaxation
1007  if (this%nonmeth == 3) then
1008  call mem_reallocate(this%wsave, this%neq, 'WSAVE', this%name)
1009  call mem_reallocate(this%hchold, this%neq, 'HCHOLD', this%name)
1010  call mem_reallocate(this%deold, this%neq, 'DEOLD', this%name)
1011  do i = 1, this%neq
1012  this%wsave(i) = dzero
1013  this%hchold(i) = dzero
1014  this%deold(i) = dzero
1015  end do
1016  end if
1017  this%hncg = dzero
1018  this%lrch = 0
1019 
1020  ! allocate space for saving solver convergence history
1021  if (this%iprims == 2 .or. this%icsvinnerout > 0) then
1022  this%nitermax = this%linear_settings%iter1 * this%mxiter
1023  else
1024  this%nitermax = 1
1025  end if
1026 
1027  allocate (this%caccel(this%nitermax))
1028 
1029  !
1030  ! -- resize convergence report
1031  call this%cnvg_summary%reinit(this%nitermax)
1032  !
1033  ! -- check for numerical solution errors
1034  ierr = count_errors()
1035  if (ierr > 0) then
1036  call this%parser%StoreErrorUnit()
1037  end if
1038  !
1039  ! -- close ims input file
1040  call this%parser%Clear()
1041  end subroutine sln_ar
1042 
1043  !> @ brief Calculate delt
1044  !!
1045  !! Calculate time step length.
1046  !!
1047  !<
1048  subroutine sln_dt(this)
1049  ! -- modules
1050  use tdismodule, only: kstp, kper, delt
1052  use constantsmodule, only: dtwo, dthree
1053  ! -- dummy variables
1054  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1055  ! -- local variables
1056  integer(I4B) :: idir
1057  real(DP) :: delt_temp
1058  real(DP) :: fact_lower
1059  real(DP) :: fact_upper
1060  !
1061  ! -- increase or decrease delt based on kiter fraction. atsfrac should be
1062  ! a value of about 1/3. If the number of outer iterations is less than
1063  ! 1/3 of mxiter, then increase step size. If the number of outer
1064  ! iterations is greater than 2/3 of mxiter, then decrease step size.
1065  if (this%atsfrac > dzero) then
1066  delt_temp = delt
1067  fact_lower = this%mxiter * this%atsfrac
1068  fact_upper = this%mxiter - fact_lower
1069  if (this%iouttot_timestep < int(fact_lower)) then
1070  ! -- increase delt according to tsfactats
1071  idir = 1
1072  else if (this%iouttot_timestep > int(fact_upper)) then
1073  ! -- decrease delt according to tsfactats
1074  idir = -1
1075  else
1076  ! -- do not change delt
1077  idir = 0
1078  end if
1079  !
1080  ! -- submit stable dt for upcoming step
1081  call ats_submit_delt(kstp, kper, delt_temp, this%memory_path, idir=idir)
1082  end if
1083  end subroutine sln_dt
1084 
1085  !> @ brief Advance solution
1086  !!
1087  !! Advance solution.
1088  !!
1089  !<
1090  subroutine sln_ad(this)
1091  ! -- modules
1092  use tdismodule, only: kstp, kper
1093  ! -- dummy variables
1094  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1095  !
1096  ! -- write headers to CSV file
1097  if (kper == 1 .and. kstp == 1) then
1098  call this%writeCSVHeader()
1099  end if
1100 
1101  ! write PTC info on models to iout
1102  call this%writePTCInfoToFile(kper)
1103 
1104  ! reset convergence flag and inner solve counter
1105  this%icnvg = 0
1106  this%itertot_timestep = 0
1107  this%iouttot_timestep = 0
1108  end subroutine sln_ad
1109 
1110  !> @ brief Output solution
1111  !!
1112  !! Output solution data. Currently does nothing.
1113  !!
1114  !<
1115  subroutine sln_ot(this)
1116  ! -- dummy variables
1117  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1118  !
1119  ! -- Nothing to do here
1120  end subroutine sln_ot
1121 
1122  !> @ brief Finalize solution
1123  !!
1124  !! Finalize a solution.
1125  !!
1126  !<
1127  subroutine sln_fp(this)
1128  use simvariablesmodule, only: iout
1129  ! -- dummy variables
1130  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1131  !
1132  ! -- write timer output
1133  if (idevelopmode == 1) then
1134  write (iout, '(//1x,a,1x,a,1x,a)') &
1135  'Solution', trim(adjustl(this%name)), 'summary'
1136  write (iout, "(1x,70('-'))")
1137  write (iout, '(1x,a,1x,g0,1x,a)') &
1138  'Total formulate time: ', this%ttform, 'seconds'
1139  write (iout, '(1x,a,1x,g0,1x,a,/)') &
1140  'Total solution time: ', this%ttsoln, 'seconds'
1141  end if
1142  end subroutine sln_fp
1143 
1144  !> @ brief Deallocate solution
1145  !!
1146  !! Deallocate a solution.
1147  !!
1148  !<
1149  subroutine sln_da(this)
1150  ! -- modules
1152  ! -- dummy variables
1153  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1154  !
1155  ! -- IMSLinearModule
1156  if (this%linsolver == ims_solver) then
1157  call this%imslinear%imslinear_da()
1158  deallocate (this%imslinear)
1159  end if
1160  !
1161  ! -- lists
1162  call this%modellist%Clear()
1163  call this%exchangelist%Clear()
1164  deallocate (this%modellist)
1165  deallocate (this%exchangelist)
1166 
1167  call this%system_matrix%destroy()
1168  deallocate (this%system_matrix)
1169  call this%vec_x%destroy()
1170  deallocate (this%vec_x)
1171  call this%vec_rhs%destroy()
1172  deallocate (this%vec_rhs)
1173 
1174  !
1175  ! -- character arrays
1176  deallocate (this%caccel)
1177  !
1178  ! -- inner iteration table object
1179  if (associated(this%innertab)) then
1180  call this%innertab%table_da()
1181  deallocate (this%innertab)
1182  nullify (this%innertab)
1183  end if
1184  !
1185  ! -- outer iteration table object
1186  if (associated(this%outertab)) then
1187  call this%outertab%table_da()
1188  deallocate (this%outertab)
1189  nullify (this%outertab)
1190  end if
1191  !
1192  ! -- arrays
1193  call mem_deallocate(this%active)
1194  call mem_deallocate(this%xtemp)
1195  call mem_deallocate(this%dxold)
1196  call mem_deallocate(this%hncg)
1197  call mem_deallocate(this%lrch)
1198  call mem_deallocate(this%wsave)
1199  call mem_deallocate(this%hchold)
1200  call mem_deallocate(this%deold)
1201  call mem_deallocate(this%convmodstart)
1202  !
1203  ! -- convergence report
1204  call this%cnvg_summary%destroy()
1205  deallocate (this%cnvg_summary)
1206  !
1207  ! -- linear solver
1208  call this%linear_solver%destroy()
1209  deallocate (this%linear_solver)
1210  !
1211  ! -- linear solver settings
1212  call this%linear_settings%destroy()
1213  deallocate (this%linear_settings)
1214  !
1215  ! -- Scalars
1216  call mem_deallocate(this%id)
1217  call mem_deallocate(this%iu)
1218  call mem_deallocate(this%ttform)
1219  call mem_deallocate(this%ttsoln)
1220  call mem_deallocate(this%isymmetric)
1221  call mem_deallocate(this%neq)
1222  call mem_deallocate(this%matrix_offset)
1223  call mem_deallocate(this%dvclose)
1224  call mem_deallocate(this%bigchold)
1225  call mem_deallocate(this%bigch)
1226  call mem_deallocate(this%relaxold)
1227  call mem_deallocate(this%res_prev)
1228  call mem_deallocate(this%res_new)
1229  call mem_deallocate(this%icnvg)
1230  call mem_deallocate(this%itertot_timestep)
1231  call mem_deallocate(this%iouttot_timestep)
1232  call mem_deallocate(this%itertot_sim)
1233  call mem_deallocate(this%mxiter)
1234  call mem_deallocate(this%linsolver)
1235  call mem_deallocate(this%nonmeth)
1236  call mem_deallocate(this%iprims)
1237  call mem_deallocate(this%theta)
1238  call mem_deallocate(this%akappa)
1239  call mem_deallocate(this%gamma)
1240  call mem_deallocate(this%amomentum)
1241  call mem_deallocate(this%breduc)
1242  call mem_deallocate(this%btol)
1243  call mem_deallocate(this%res_lim)
1244  call mem_deallocate(this%numtrack)
1245  call mem_deallocate(this%ibflag)
1246  call mem_deallocate(this%icsvouterout)
1247  call mem_deallocate(this%icsvinnerout)
1248  call mem_deallocate(this%nitermax)
1249  call mem_deallocate(this%convnmod)
1250  call mem_deallocate(this%iallowptc)
1251  call mem_deallocate(this%iptcopt)
1252  call mem_deallocate(this%iptcout)
1253  call mem_deallocate(this%l2norm0)
1254  call mem_deallocate(this%ptcdel)
1255  call mem_deallocate(this%ptcdel0)
1256  call mem_deallocate(this%ptcexp)
1257  call mem_deallocate(this%atsfrac)
1258  end subroutine sln_da
1259 
1260  !> @ brief Solve solution
1261  !!
1262  !! Solve the models in this solution for kper and kstp.
1263  !!
1264  !<
1265  subroutine sln_ca(this, isgcnvg, isuppress_output)
1266  ! -- dummy variables
1267  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1268  integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag
1269  integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output
1270  ! -- local variables
1271  class(numericalmodeltype), pointer :: mp => null()
1272  character(len=LINELENGTH) :: line
1273  character(len=LINELENGTH) :: fmt
1274  integer(I4B) :: im
1275  integer(I4B) :: kiter ! non-linear iteration counter
1276 
1277  ! advance the models, exchanges, and solution
1278  call this%prepareSolve()
1279 
1280  select case (isim_mode)
1281  case (mvalidate)
1282  line = 'mode="validation" -- Skipping matrix assembly and solution.'
1283  fmt = "(/,1x,a,/)"
1284  do im = 1, this%modellist%Count()
1285  mp => getnumericalmodelfromlist(this%modellist, im)
1286  call mp%model_message(line, fmt=fmt)
1287  end do
1288  case (mnormal)
1289  ! nonlinear iteration loop for this solution
1290  outerloop: do kiter = 1, this%mxiter
1291 
1292  ! perform a single iteration
1293  call this%solve(kiter)
1294 
1295  ! exit if converged
1296  if (this%icnvg == 1) then
1297  exit outerloop
1298  end if
1299 
1300  end do outerloop
1301 
1302  ! finish up, write convergence info, CSV file, budgets and flows, ...
1303  call this%finalizeSolve(kiter, isgcnvg, isuppress_output)
1304  end select
1305  end subroutine sln_ca
1306 
1307  !> @ brief CSV header
1308  !!
1309  !! Write header for solver output to comma-separated value files.
1310  !!
1311  !<
1312  subroutine writecsvheader(this)
1313  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1314  ! local variables
1315  integer(I4B) :: im
1316  class(numericalmodeltype), pointer :: mp => null()
1317  !
1318  ! -- outer iteration csv header
1319  if (this%icsvouterout > 0) then
1320  write (this%icsvouterout, '(*(G0,:,","))') &
1321  'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', &
1322  'inner_iterations', 'solution_outer_dvmax', &
1323  'solution_outer_dvmax_model', 'solution_outer_dvmax_package', &
1324  'solution_outer_dvmax_node'
1325  end if
1326  !
1327  ! -- inner iteration csv header
1328  if (this%icsvinnerout > 0) then
1329  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1330  'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', &
1331  'ninner', 'solution_inner_dvmax', 'solution_inner_dvmax_model', &
1332  'solution_inner_dvmax_node'
1333  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1334  '', 'solution_inner_rmax', 'solution_inner_rmax_model', &
1335  'solution_inner_rmax_node'
1336  ! solver items specific to ims solver
1337  if (this%linsolver == ims_solver) then
1338  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1339  '', 'solution_inner_alpha'
1340  if (this%imslinear%ilinmeth == 2) then
1341  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1342  '', 'solution_inner_omega'
1343  end if
1344  end if
1345  ! -- check for more than one model - ims only
1346  if (this%convnmod > 1 .or. simulation_mode == "PARALLEL") then
1347  do im = 1, this%modellist%Count()
1348  mp => getnumericalmodelfromlist(this%modellist, im)
1349  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1350  '', trim(adjustl(mp%name))//'_inner_dvmax', &
1351  trim(adjustl(mp%name))//'_inner_dvmax_node', &
1352  trim(adjustl(mp%name))//'_inner_rmax', &
1353  trim(adjustl(mp%name))//'_inner_rmax_node'
1354  end do
1355  end if
1356  write (this%icsvinnerout, '(a)') ''
1357  end if
1358  end subroutine writecsvheader
1359 
1360  !> @ brief PTC header
1361  !!
1362  !! Write header for pseudo-transient continuation information to a file.
1363  !!
1364  !<
1365  subroutine writeptcinfotofile(this, kper)
1366  ! -- dummy variables
1367  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1368  integer(I4B), intent(in) :: kper !< current stress period number
1369  ! -- local variable
1370  integer(I4B) :: n, im, iallowptc, iptc
1371  class(numericalmodeltype), pointer :: mp => null()
1372 
1373  ! -- determine if PTC will be used in any model
1374  n = 1
1375  do im = 1, this%modellist%Count()
1376  !
1377  ! -- set iallowptc
1378  ! -- no_ptc_option is FIRST
1379  if (this%iallowptc < 0) then
1380  if (kper > 1) then
1381  iallowptc = 1
1382  else
1383  iallowptc = 0
1384  end if
1385  ! -- no_ptc_option is ALL (0) or using PTC (1)
1386  else
1387  iallowptc = this%iallowptc
1388  end if
1389 
1390  if (iallowptc > 0) then
1391  mp => getnumericalmodelfromlist(this%modellist, im)
1392  call mp%model_ptcchk(iptc)
1393  else
1394  iptc = 0
1395  end if
1396 
1397  if (iptc /= 0) then
1398  if (n == 1) then
1399  write (iout, '(//)')
1400  n = 0
1401  end if
1402  write (iout, '(1x,a,1x,i0,1x,3a)') &
1403  'PSEUDO-TRANSIENT CONTINUATION WILL BE APPLIED TO MODEL', im, '("', &
1404  trim(adjustl(mp%name)), '") DURING THIS TIME STEP'
1405  end if
1406  end do
1407 
1408  end subroutine writeptcinfotofile
1409 
1410  !> @ brief prepare to solve
1411  !!
1412  !! Prepare for the system solve by advancing the simulation.
1413  !!
1414  !<
1415  subroutine preparesolve(this)
1416  ! -- dummy variables
1417  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1418  ! -- local variables
1419  integer(I4B) :: ic
1420  integer(I4B) :: im
1421  class(numericalexchangetype), pointer :: cp => null()
1422  class(numericalmodeltype), pointer :: mp => null()
1423 
1424  ! synchronize for AD
1425  call this%synchronize(stg_bfr_exg_ad, this%synchronize_ctx)
1426 
1427  ! -- Exchange advance
1428  do ic = 1, this%exchangelist%Count()
1429  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1430  call cp%exg_ad()
1431  end do
1432 
1433  ! -- Model advance
1434  do im = 1, this%modellist%Count()
1435  mp => getnumericalmodelfromlist(this%modellist, im)
1436  call mp%model_ad()
1437  end do
1438 
1439  ! advance solution
1440  call this%sln_ad()
1441 
1442  end subroutine preparesolve
1443 
1444  !> @ brief Build and solve the simulation
1445  !!
1446  !! Builds and solve the system for this numerical solution.
1447  !! It roughly consists of the following steps
1448  !! (1) backtracking, (2) reset amat and rhs (3) calculate matrix
1449  !! terms (*_cf), (4) add coefficients to matrix (*_fc), (6) newton-raphson,
1450  !! (6) PTC, (7) linear solve, (8) convergence checks, (9) write output,
1451  !! and (10) underrelaxation
1452  !!
1453  !<
1454  subroutine solve(this, kiter)
1455  ! -- modules
1456  use tdismodule, only: kstp, kper, totim
1457  ! -- dummy variables
1458  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1459  integer(I4B), intent(in) :: kiter !< Picard iteration number
1460  ! -- local variables
1461  class(numericalmodeltype), pointer :: mp => null()
1462  class(numericalexchangetype), pointer :: cp => null()
1463  character(len=LINELENGTH) :: title
1464  character(len=LINELENGTH) :: tag
1465  character(len=LENPAKLOC) :: cmod
1466  character(len=LENPAKLOC) :: cpak
1467  character(len=LENPAKLOC) :: cpakout
1468  character(len=LENPAKLOC) :: strh
1469  character(len=25) :: cval
1470  character(len=7) :: cmsg
1471  integer(I4B) :: ic
1472  integer(I4B) :: im, m_idx, model_id
1473  integer(I4B) :: icsv0
1474  integer(I4B) :: kcsv0
1475  integer(I4B) :: ntabrows
1476  integer(I4B) :: ntabcols
1477  integer(I4B) :: i0, i1
1478  integer(I4B) :: itestmat, n
1479  integer(I4B) :: iter
1480  integer(I4B) :: inewtonur
1481  integer(I4B) :: locmax_nur
1482  integer(I4B) :: iend
1483  integer(I4B) :: icnvgmod
1484  integer(I4B) :: iptc
1485  integer(I4B) :: node_user
1486  integer(I4B) :: ipak
1487  integer(I4B) :: ipos0
1488  integer(I4B) :: ipos1
1489  real(DP) :: dxmax_nur
1490  real(DP) :: dxold_max
1491  real(DP) :: ptcf
1492  real(DP) :: ttform
1493  real(DP) :: ttsoln
1494  real(DP) :: dpak
1495  real(DP) :: outer_hncg
1496  !
1497  ! -- initialize local variables
1498  icsv0 = max(1, this%itertot_sim + 1)
1499  kcsv0 = max(1, this%itertot_timestep + 1)
1500  !
1501  ! -- create header for outer iteration table
1502  if (this%iprims > 0) then
1503  if (.not. associated(this%outertab)) then
1504  !
1505  ! -- create outer iteration table
1506  ! -- table dimensions
1507  ntabrows = 1
1508  ntabcols = 6
1509  if (this%numtrack > 0) then
1510  ntabcols = ntabcols + 4
1511  end if
1512  !
1513  ! -- initialize table and define columns
1514  title = trim(this%memory_path)//' OUTER ITERATION SUMMARY'
1515  call table_cr(this%outertab, this%name, title)
1516  call this%outertab%table_df(ntabrows, ntabcols, iout, &
1517  finalize=.false.)
1518  tag = 'OUTER ITERATION STEP'
1519  call this%outertab%initialize_column(tag, 25, alignment=tableft)
1520  tag = 'OUTER ITERATION'
1521  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1522  tag = 'INNER ITERATION'
1523  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1524  if (this%numtrack > 0) then
1525  tag = 'BACKTRACK FLAG'
1526  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1527  tag = 'BACKTRACK ITERATIONS'
1528  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1529  tag = 'INCOMING RESIDUAL'
1530  call this%outertab%initialize_column(tag, 15, alignment=tabright)
1531  tag = 'OUTGOING RESIDUAL'
1532  call this%outertab%initialize_column(tag, 15, alignment=tabright)
1533  end if
1534  tag = 'MAXIMUM CHANGE'
1535  call this%outertab%initialize_column(tag, 15, alignment=tabright)
1536  tag = 'STEP SUCCESS'
1537  call this%outertab%initialize_column(tag, 7, alignment=tabright)
1538  tag = 'MAXIMUM CHANGE MODEL-(CELLID) OR MODEL-PACKAGE-(NUMBER)'
1539  call this%outertab%initialize_column(tag, 34, alignment=tabright)
1540  end if
1541  end if
1542  !
1543  ! -- backtracking
1544  if (this%numtrack > 0) then
1545  call this%sln_backtracking(mp, cp, kiter)
1546  end if
1547  !
1548  call code_timer(0, ttform, this%ttform)
1549  !
1550  ! -- (re)build the solution matrix
1551  call this%sln_buildsystem(kiter, inewton=1)
1552  !
1553  ! -- Calculate pseudo-transient continuation factor for each model
1554  call this%sln_calc_ptc(iptc, ptcf)
1555  !
1556  ! -- Add model Newton-Raphson terms to solution
1557  do im = 1, this%modellist%Count()
1558  mp => getnumericalmodelfromlist(this%modellist, im)
1559  call mp%model_nr(kiter, this%system_matrix, 1)
1560  end do
1561  call code_timer(1, ttform, this%ttform)
1562  !
1563  ! -- linear solve
1564  call code_timer(0, ttsoln, this%ttsoln)
1565  call this%sln_ls(kiter, kstp, kper, iter, iptc, ptcf)
1566  call code_timer(1, ttsoln, this%ttsoln)
1567  !
1568  ! -- increment counters storing the total number of linear and
1569  ! non-linear iterations for this timestep and the total
1570  ! number of linear iterations for all timesteps
1571  this%itertot_timestep = this%itertot_timestep + iter
1572  this%iouttot_timestep = this%iouttot_timestep + 1
1573  this%itertot_sim = this%itertot_sim + iter
1574  !
1575  ! -- save matrix to a file
1576  ! to enable set itestmat to 1 and recompile
1577  !-------------------------------------------------------
1578  itestmat = 0
1579  if (itestmat /= 0) then
1580  open (99, file='sol_MF6.TXT')
1581  WRITE (99, *) 'MATRIX SOLUTION FOLLOWS'
1582  WRITE (99, '(10(I8,G15.4))') (n, this%x(n), n=1, this%NEQ)
1583  close (99)
1584  call pstop()
1585  end if
1586  !-------------------------------------------------------
1587  !
1588  ! -- check convergence of solution
1589  call this%sln_get_dxmax(this%hncg(kiter), this%lrch(1, kiter))
1590  this%icnvg = 0
1591  if (this%sln_has_converged(this%hncg(kiter))) then
1592  this%icnvg = 1
1593  end if
1594  !
1595  ! -- set failure flag
1596  if (this%icnvg == 0) then
1597  cmsg = ' '
1598  else
1599  cmsg = '*'
1600  end if
1601  !
1602  ! -- set flag if this is the last outer iteration
1603  iend = 0
1604  if (kiter == this%mxiter) then
1605  iend = 1
1606  end if
1607  !
1608  ! -- write maximum dependent-variable change from linear solver to list file
1609  if (this%iprims > 0) then
1610  cval = 'Model'
1611  call this%sln_get_loc(this%lrch(1, kiter), strh)
1612  !
1613  ! -- add data to outertab
1614  call this%outertab%add_term(cval)
1615  call this%outertab%add_term(kiter)
1616  call this%outertab%add_term(iter)
1617  if (this%numtrack > 0) then
1618  call this%outertab%add_term(' ')
1619  call this%outertab%add_term(' ')
1620  call this%outertab%add_term(' ')
1621  call this%outertab%add_term(' ')
1622  end if
1623  call this%outertab%add_term(this%hncg(kiter))
1624  call this%outertab%add_term(cmsg)
1625  call this%outertab%add_term(trim(strh))
1626  end if
1627  !
1628  ! -- Additional convergence check for exchanges
1629  do ic = 1, this%exchangelist%Count()
1630  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1631  call cp%exg_cc(this%icnvg)
1632  end do
1633  !
1634  ! -- additional convergence check for model packages
1635  icnvgmod = this%icnvg
1636  cpak = ' '
1637  ipak = 0
1638  dpak = dzero
1639  do im = 1, this%modellist%Count()
1640  mp => getnumericalmodelfromlist(this%modellist, im)
1641  call mp%get_mcellid(0, cmod)
1642  call mp%model_cc(this%itertot_sim, kiter, iend, icnvgmod, &
1643  cpak, ipak, dpak)
1644  if (ipak /= 0) then
1645  ipos0 = index(cpak, '-', back=.true.)
1646  ipos1 = len_trim(cpak)
1647  write (cpakout, '(a,a,"-(",i0,")",a)') &
1648  trim(cmod), cpak(1:ipos0 - 1), ipak, cpak(ipos0:ipos1)
1649  else
1650  cpakout = ' '
1651  end if
1652  end do
1653  !
1654  ! -- evaluate package convergence - only done if convergence is achieved
1655  if (this%icnvg == 1) then
1656  this%icnvg = this%sln_package_convergence(dpak, cpakout, iend)
1657  !
1658  ! -- write maximum change in package convergence check
1659  if (this%iprims > 0) then
1660  cval = 'Package'
1661  if (this%icnvg /= 1) then
1662  cmsg = ' '
1663  else
1664  cmsg = '*'
1665  end if
1666  if (len_trim(cpakout) > 0) then
1667  !
1668  ! -- add data to outertab
1669  call this%outertab%add_term(cval)
1670  call this%outertab%add_term(kiter)
1671  call this%outertab%add_term(' ')
1672  if (this%numtrack > 0) then
1673  call this%outertab%add_term(' ')
1674  call this%outertab%add_term(' ')
1675  call this%outertab%add_term(' ')
1676  call this%outertab%add_term(' ')
1677  end if
1678  call this%outertab%add_term(dpak)
1679  call this%outertab%add_term(cmsg)
1680  call this%outertab%add_term(cpakout)
1681  end if
1682  end if
1683  end if
1684  !
1685  ! -- under-relaxation - only done if convergence not achieved
1686  if (this%icnvg /= 1) then
1687  if (this%nonmeth > 0) then
1688  call this%sln_underrelax(kiter, this%hncg(kiter), this%neq, &
1689  this%active, this%x, this%xtemp)
1690  else
1691  call this%sln_calcdx(this%neq, this%active, &
1692  this%x, this%xtemp, this%dxold)
1693  end if
1694  !
1695  ! -- adjust heads by newton under-relaxation, if necessary
1696  inewtonur = 0
1697  dxmax_nur = dzero
1698  locmax_nur = 0
1699  do im = 1, this%modellist%Count()
1700  mp => getnumericalmodelfromlist(this%modellist, im)
1701  i0 = mp%moffset + 1 - this%matrix_offset
1702  i1 = i0 + mp%neq - 1
1703  call mp%model_nur(mp%neq, this%x(i0:i1), this%xtemp(i0:i1), &
1704  this%dxold(i0:i1), inewtonur, dxmax_nur, locmax_nur)
1705  end do
1706  !
1707  ! -- synchronize Newton Under-relaxation flag
1708  inewtonur = this%sln_sync_newtonur_flag(inewtonur)
1709  !
1710  ! -- check for convergence if newton under-relaxation applied
1711  if (inewtonur /= 0) then
1712  !
1713  ! -- calculate maximum change in heads in cells that have
1714  ! not been adjusted by newton under-relxation
1715  call this%sln_maxval(this%neq, this%dxold, dxold_max)
1716  !
1717  ! -- evaluate convergence
1718  if (this%sln_nur_has_converged(dxold_max, this%hncg(kiter))) then
1719  !
1720  ! -- converged
1721  this%icnvg = 1
1722  !
1723  ! -- reset outer dependent-variable change and location for output
1724  call this%sln_get_dxmax(this%hncg(kiter), this%lrch(1, kiter))
1725  !
1726  ! -- write revised dependent-variable change data after
1727  ! newton under-relaxation
1728  if (this%iprims > 0) then
1729  cval = 'Newton under-relaxation'
1730  cmsg = '*'
1731  call this%sln_get_loc(this%lrch(1, kiter), strh)
1732  !
1733  ! -- add data to outertab
1734  call this%outertab%add_term(cval)
1735  call this%outertab%add_term(kiter)
1736  call this%outertab%add_term(iter)
1737  if (this%numtrack > 0) then
1738  call this%outertab%add_term(' ')
1739  call this%outertab%add_term(' ')
1740  call this%outertab%add_term(' ')
1741  call this%outertab%add_term(' ')
1742  end if
1743  call this%outertab%add_term(this%hncg(kiter))
1744  call this%outertab%add_term(cmsg)
1745  call this%outertab%add_term(trim(strh))
1746  end if
1747  end if
1748  end if
1749  end if
1750  !
1751  ! -- write to outer iteration csv file
1752  if (this%icsvouterout > 0) then
1753  !
1754  ! -- set outer dependent-variable change variable
1755  outer_hncg = this%hncg(kiter)
1756  !
1757  ! -- model convergence error
1758  if (abs(outer_hncg) > abs(dpak)) then
1759  !
1760  ! -- get model number and user node number
1761  call this%sln_get_nodeu(this%lrch(1, kiter), m_idx, node_user)
1762  cpakout = ''
1763  else if (outer_hncg == dzero .and. dpak == dzero) then ! zero change, location could be any
1764  m_idx = 0
1765  node_user = 0
1766  !
1767  ! -- then it's a package convergence error
1768  else
1769  !
1770  ! -- set convergence error, model number, user node number,
1771  ! and package name
1772  outer_hncg = dpak
1773  ipos0 = index(cmod, '_')
1774  read (cmod(1:ipos0 - 1), *) m_idx
1775  node_user = ipak
1776  ipos0 = index(cpak, '-', back=.true.)
1777  cpakout = cpak(1:ipos0 - 1)
1778  end if
1779  !
1780  ! -- write line to outer iteration csv file
1781  if (m_idx > 0) then
1782  mp => getnumericalmodelfromlist(this%modellist, m_idx) ! TODO_MJR: right list?
1783  model_id = mp%id
1784  else
1785  model_id = 0
1786  end if
1787  write (this%icsvouterout, '(*(G0,:,","))') &
1788  this%itertot_sim, totim, kper, kstp, kiter, iter, &
1789  outer_hncg, model_id, trim(cpakout), node_user
1790  end if
1791  !
1792  ! -- write to inner iteration csv file
1793  if (this%icsvinnerout > 0) then
1794  call this%csv_convergence_summary(this%icsvinnerout, totim, kper, kstp, &
1795  kiter, iter, icsv0, kcsv0)
1796  end if
1797 
1798  end subroutine solve
1799 
1800  !> @ brief finalize a solution
1801  !!
1802  !! Finalize the solution. Called after the outer iteration loop.
1803  !!
1804  !<
1805  subroutine finalizesolve(this, kiter, isgcnvg, isuppress_output)
1806  ! -- modules
1807  use tdismodule, only: kper, kstp
1808  ! -- dummy variables
1809  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1810  integer(I4B), intent(in) :: kiter !< Picard iteration number after convergence or failure
1811  integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag
1812  integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output
1813  ! -- local variables
1814  integer(I4B) :: ic, im
1815  class(numericalmodeltype), pointer :: mp => null()
1816  class(numericalexchangetype), pointer :: cp => null()
1817  ! -- formats for convergence info
1818  character(len=*), parameter :: fmtnocnvg = &
1819  "(1X,'Solution ', i0, ' did not converge for stress period ', i0, &
1820  &' and time step ', i0)"
1821  character(len=*), parameter :: fmtcnvg = &
1822  "(1X, I0, ' CALLS TO NUMERICAL SOLUTION ', 'IN TIME STEP ', I0, &
1823  &' STRESS PERIOD ',I0,/1X,I0,' TOTAL ITERATIONS')"
1824  !
1825  ! -- finalize the outer iteration table
1826  if (this%iprims > 0) then
1827  call this%outertab%finalize_table()
1828  end if
1829  !
1830  ! -- write convergence info
1831  !
1832  ! -- convergence was achieved
1833  if (this%icnvg /= 0) then
1834  if (this%iprims > 0) then
1835  write (iout, fmtcnvg) kiter, kstp, kper, this%itertot_timestep
1836  end if
1837  !
1838  ! -- convergence was not achieved
1839  else
1840  write (iout, fmtnocnvg) this%id, kper, kstp
1841  end if
1842  !
1843  ! -- write inner iteration convergence summary
1844  if (this%iprims == 2) then
1845  !
1846  ! -- write summary for each model
1847  do im = 1, this%modellist%Count()
1848  mp => getnumericalmodelfromlist(this%modellist, im)
1849  call this%convergence_summary(mp%iout, im, this%itertot_timestep)
1850  end do
1851  !
1852  ! -- write summary for entire solution
1853  call this%convergence_summary(iout, this%convnmod + 1, &
1854  this%itertot_timestep)
1855  end if
1856  !
1857  ! -- set solution group convergence flag
1858  if (this%icnvg == 0) isgcnvg = 0
1859  !
1860  ! -- Calculate flow for each model
1861  do im = 1, this%modellist%Count()
1862  mp => getnumericalmodelfromlist(this%modellist, im)
1863  call mp%model_cq(this%icnvg, isuppress_output)
1864  end do
1865  !
1866  ! -- Calculate flow for each exchange
1867  do ic = 1, this%exchangelist%Count()
1868  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1869  call cp%exg_cq(isgcnvg, isuppress_output, this%id)
1870  end do
1871  !
1872  ! -- Budget terms for each model
1873  do im = 1, this%modellist%Count()
1874  mp => getnumericalmodelfromlist(this%modellist, im)
1875  call mp%model_bd(this%icnvg, isuppress_output)
1876  end do
1877  !
1878  ! -- Budget terms for each exchange
1879  do ic = 1, this%exchangelist%Count()
1880  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1881  call cp%exg_bd(isgcnvg, isuppress_output, this%id)
1882  end do
1883 
1884  end subroutine finalizesolve
1885 
1886  ! helper routine to calculate coefficients and setup the solution matrix
1887  subroutine sln_buildsystem(this, kiter, inewton)
1888  class(numericalsolutiontype) :: this
1889  integer(I4B), intent(in) :: kiter
1890  integer(I4B), intent(in) :: inewton
1891  ! local
1892  integer(I4B) :: im, ic
1893  class(numericalmodeltype), pointer :: mp
1894  class(numericalexchangetype), pointer :: cp
1895  !
1896  ! -- Set amat and rhs to zero
1897  call this%sln_reset()
1898 
1899  ! reset models
1900  do im = 1, this%modellist%Count()
1901  mp => getnumericalmodelfromlist(this%modellist, im)
1902  call mp%model_reset()
1903  end do
1904 
1905  ! synchronize for CF
1906  call this%synchronize(stg_bfr_exg_cf, this%synchronize_ctx)
1907 
1908  !
1909  ! -- Calculate the matrix terms for each exchange
1910  do ic = 1, this%exchangelist%Count()
1911  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1912  call cp%exg_cf(kiter)
1913  end do
1914  !
1915  ! -- Calculate the matrix terms for each model
1916  do im = 1, this%modellist%Count()
1917  mp => getnumericalmodelfromlist(this%modellist, im)
1918  call mp%model_cf(kiter)
1919  end do
1920 
1921  ! synchronize for FC
1922  call this%synchronize(stg_bfr_exg_fc, this%synchronize_ctx)
1923 
1924  !
1925  ! -- Add exchange coefficients to the solution
1926  do ic = 1, this%exchangelist%Count()
1927  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1928  call cp%exg_fc(kiter, this%system_matrix, this%rhs, inewton)
1929  end do
1930  !
1931  ! -- Add model coefficients to the solution
1932  do im = 1, this%modellist%Count()
1933  mp => getnumericalmodelfromlist(this%modellist, im)
1934  call mp%model_fc(kiter, this%system_matrix, inewton)
1935  end do
1936 
1937  end subroutine sln_buildsystem
1938 
1939  !> @ brief Solution convergence summary
1940  !!
1941  !! Save convergence summary to a File.
1942  !!
1943  !<
1944  subroutine convergence_summary(this, iu, im, itertot_timestep)
1945  ! -- modules
1946  use inputoutputmodule, only: getunit
1947  ! -- dummy variables
1948  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1949  integer(I4B), intent(in) :: iu !< file unit number for summary file
1950  integer(I4B), intent(in) :: im !< model number
1951  integer(I4B), intent(in) :: itertot_timestep !< total iteration for the time step
1952  ! -- local variables
1953  character(len=LINELENGTH) :: title
1954  character(len=LINELENGTH) :: tag
1955  character(len=LENPAKLOC) :: loc_dvmax_str
1956  character(len=LENPAKLOC) :: loc_rmax_str
1957  integer(I4B) :: ntabrows
1958  integer(I4B) :: ntabcols
1959  integer(I4B) :: iinner
1960  integer(I4B) :: i0
1961  integer(I4B) :: iouter
1962  integer(I4B) :: j
1963  integer(I4B) :: k
1964  integer(I4B) :: locdv
1965  integer(I4B) :: locdr
1966  real(DP) :: dv !< the maximum change in the dependent variable
1967  real(DP) :: res !< the maximum value of the residual vector
1968  !
1969  ! -- initialize local variables
1970  loc_dvmax_str = ''
1971  loc_rmax_str = ''
1972  iouter = 1
1973  locdv = 0
1974  locdr = 0
1975  !
1976  ! -- initialize inner iteration summary table
1977  if (.not. associated(this%innertab)) then
1978  !
1979  ! -- create outer iteration table
1980  ! -- table dimensions
1981  ntabrows = itertot_timestep
1982  ntabcols = 7
1983  !
1984  ! -- initialize table and define columns
1985  title = trim(this%memory_path)//' INNER ITERATION SUMMARY'
1986  call table_cr(this%innertab, this%name, title)
1987  call this%innertab%table_df(ntabrows, ntabcols, iu)
1988  tag = 'TOTAL ITERATION'
1989  call this%innertab%initialize_column(tag, 10, alignment=tabright)
1990  tag = 'OUTER ITERATION'
1991  call this%innertab%initialize_column(tag, 10, alignment=tabright)
1992  tag = 'INNER ITERATION'
1993  call this%innertab%initialize_column(tag, 10, alignment=tabright)
1994  tag = 'MAXIMUM CHANGE'
1995  call this%innertab%initialize_column(tag, 15, alignment=tabright)
1996  tag = 'MAXIMUM CHANGE MODEL-(CELLID)'
1997  call this%innertab%initialize_column(tag, lenpakloc, alignment=tabright)
1998  tag = 'MAXIMUM RESIDUAL'
1999  call this%innertab%initialize_column(tag, 15, alignment=tabright)
2000  tag = 'MAXIMUM RESIDUAL MODEL-(CELLID)'
2001  call this%innertab%initialize_column(tag, lenpakloc, alignment=tabright)
2002  !
2003  ! -- reset the output unit and the number of rows (maxbound)
2004  else
2005  call this%innertab%set_maxbound(itertot_timestep)
2006  call this%innertab%set_iout(iu)
2007  end if
2008  !
2009  ! -- write the inner iteration summary to unit iu
2010  i0 = 0
2011  do k = 1, itertot_timestep
2012  iinner = this%cnvg_summary%itinner(k)
2013  if (iinner <= i0) then
2014  iouter = iouter + 1
2015  end if
2016  if (im > this%convnmod) then
2017  dv = dzero
2018  res = dzero
2019  do j = 1, this%convnmod
2020  if (abs(this%cnvg_summary%convdvmax(j, k)) > abs(dv)) then
2021  locdv = this%cnvg_summary%convlocdv(j, k)
2022  dv = this%cnvg_summary%convdvmax(j, k)
2023  end if
2024  if (abs(this%cnvg_summary%convrmax(j, k)) > abs(res)) then
2025  locdr = this%cnvg_summary%convlocr(j, k)
2026  res = this%cnvg_summary%convrmax(j, k)
2027  end if
2028  end do
2029  else
2030  locdv = this%cnvg_summary%convlocdv(im, k)
2031  locdr = this%cnvg_summary%convlocr(im, k)
2032  dv = this%cnvg_summary%convdvmax(im, k)
2033  res = this%cnvg_summary%convrmax(im, k)
2034  end if
2035  call this%sln_get_loc(locdv, loc_dvmax_str)
2036  call this%sln_get_loc(locdr, loc_rmax_str)
2037  !
2038  ! -- add data to innertab
2039  call this%innertab%add_term(k)
2040  call this%innertab%add_term(iouter)
2041  call this%innertab%add_term(iinner)
2042  call this%innertab%add_term(dv)
2043  call this%innertab%add_term(adjustr(trim(loc_dvmax_str)))
2044  call this%innertab%add_term(res)
2045  call this%innertab%add_term(adjustr(trim(loc_rmax_str)))
2046  !
2047  ! -- update i0
2048  i0 = iinner
2049  end do
2050  end subroutine convergence_summary
2051 
2052  !> @ brief Solution convergence CSV summary
2053  !!
2054  !! Save convergence summary to a comma-separated value file.
2055  !!
2056  !<
2057  subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, &
2058  niter, istart, kstart)
2059  ! -- modules
2060  use inputoutputmodule, only: getunit
2061  ! -- dummy variables
2062  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2063  integer(I4B), intent(in) :: iu !< file unit number
2064  real(DP), intent(in) :: totim !< total simulation time
2065  integer(I4B), intent(in) :: kper !< stress period number
2066  integer(I4B), intent(in) :: kstp !< time step number
2067  integer(I4B), intent(in) :: kouter !< number of outer (Picard) iterations
2068  integer(I4B), intent(in) :: niter !< number of inner iteration in this time step
2069  integer(I4B), intent(in) :: istart !< starting iteration number for this time step
2070  integer(I4B), intent(in) :: kstart !< starting position in the conv* arrays
2071  ! -- local
2072  integer(I4B) :: itot
2073  integer(I4B) :: m_idx, j, k
2074  integer(I4B) :: kpos
2075  integer(I4B) :: loc_dvmax !< solution node number (row) of max. dep. var. change
2076  integer(I4B) :: loc_rmax !< solution node number (row) of max. residual
2077  integer(I4B) :: model_id, node_user
2078  real(DP) :: dvmax !< maximum dependent variable change
2079  real(DP) :: rmax !< maximum residual
2080  class(numericalmodeltype), pointer :: num_mod => null()
2081  !
2082  ! -- initialize local variables
2083  itot = istart
2084  !
2085  ! -- write inner iteration results to the inner csv output file
2086  do k = 1, niter
2087  kpos = kstart + k - 1
2088  write (iu, '(*(G0,:,","))', advance='NO') &
2089  itot, totim, kper, kstp, kouter, k
2090  !
2091  ! -- solution summary
2092  dvmax = dzero
2093  rmax = dzero
2094  do j = 1, this%convnmod
2095  if (abs(this%cnvg_summary%convdvmax(j, kpos)) > abs(dvmax)) then
2096  loc_dvmax = this%cnvg_summary%convlocdv(j, kpos)
2097  dvmax = this%cnvg_summary%convdvmax(j, kpos)
2098  end if
2099  if (abs(this%cnvg_summary%convrmax(j, kpos)) > abs(rmax)) then
2100  loc_rmax = this%cnvg_summary%convlocr(j, kpos)
2101  rmax = this%cnvg_summary%convrmax(j, kpos)
2102  end if
2103  end do
2104  !
2105  ! -- no change, could be anywhere
2106  if (dvmax == dzero) loc_dvmax = 0
2107  if (rmax == dzero) loc_rmax = 0
2108  !
2109  ! -- get model number and user node number for max. dep. var. change
2110  if (loc_dvmax > 0) then
2111  call this%sln_get_nodeu(loc_dvmax, m_idx, node_user)
2112  num_mod => getnumericalmodelfromlist(this%modellist, m_idx)
2113  model_id = num_mod%id
2114  else
2115  model_id = 0
2116  node_user = 0
2117  end if
2118  write (iu, '(*(G0,:,","))', advance='NO') '', dvmax, model_id, node_user
2119  !
2120  ! -- get model number and user node number for max. residual
2121  if (loc_rmax > 0) then
2122  call this%sln_get_nodeu(loc_rmax, m_idx, node_user)
2123  num_mod => getnumericalmodelfromlist(this%modellist, m_idx)
2124  model_id = num_mod%id
2125  else
2126  model_id = 0
2127  node_user = 0
2128  end if
2129  write (iu, '(*(G0,:,","))', advance='NO') '', rmax, model_id, node_user
2130  !
2131  ! -- write ims acceleration parameters
2132  if (this%linsolver == ims_solver) then
2133  write (iu, '(*(G0,:,","))', advance='NO') &
2134  '', trim(adjustl(this%caccel(kpos)))
2135  end if
2136  !
2137  ! -- write information for each model
2138  if (this%convnmod > 1 .or. simulation_mode == "PARALLEL") then
2139  do j = 1, this%cnvg_summary%convnmod
2140  loc_dvmax = this%cnvg_summary%convlocdv(j, kpos)
2141  dvmax = this%cnvg_summary%convdvmax(j, kpos)
2142  loc_rmax = this%cnvg_summary%convlocr(j, kpos)
2143  rmax = this%cnvg_summary%convrmax(j, kpos)
2144  !
2145  ! -- get model number and user node number for max. dep. var. change
2146  if (loc_dvmax > 0) then
2147  call this%sln_get_nodeu(loc_dvmax, m_idx, node_user)
2148  else
2149  node_user = 0
2150  end if
2151  write (iu, '(*(G0,:,","))', advance='NO') '', dvmax, node_user
2152  !
2153  ! -- get model number and user node number for max. residual
2154  if (loc_rmax > 0) then
2155  call this%sln_get_nodeu(loc_rmax, m_idx, node_user)
2156  else
2157  node_user = 0
2158  end if
2159  write (iu, '(*(G0,:,","))', advance='NO') '', rmax, node_user
2160  end do
2161  end if
2162  !
2163  ! -- write line
2164  write (iu, '(a)') ''
2165  !
2166  ! -- update itot
2167  itot = itot + 1
2168  end do
2169  !
2170  ! -- flush file
2171  flush (iu)
2172  end subroutine csv_convergence_summary
2173 
2174  !> @ brief Save solution data to a file
2175  !!
2176  !! Save solution ia vector, ja vector , coefficient matrix, right-hand side
2177  !! vector, and the dependent-variable vector to a file.
2178  !!
2179  !<
2180  subroutine save(this, filename)
2181  use sparsematrixmodule
2182  ! -- modules
2183  use inputoutputmodule, only: getunit
2184  ! -- dummy variables
2185  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2186  character(len=*), intent(in) :: filename !< filename to save solution data
2187  ! -- local variables
2188  integer(I4B) :: inunit
2189  !
2190  select type (spm => this%system_matrix)
2191  class is (sparsematrixtype)
2192  inunit = getunit()
2193  open (unit=inunit, file=filename, status='unknown')
2194  write (inunit, *) 'ia'
2195  write (inunit, *) spm%ia
2196  write (inunit, *) 'ja'
2197  write (inunit, *) spm%ja
2198  write (inunit, *) 'amat'
2199  write (inunit, *) spm%amat
2200  write (inunit, *) 'rhs'
2201  write (inunit, *) this%rhs
2202  write (inunit, *) 'x'
2203  write (inunit, *) this%x
2204  close (inunit)
2205  end select
2206  end subroutine save
2207 
2208  !> @ brief Add a model
2209  !!
2210  !! Add a model to solution.
2211  !!
2212  !<
2213  subroutine add_model(this, mp)
2214  ! -- dummy variables
2215  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2216  class(basemodeltype), pointer, intent(in) :: mp !< model instance
2217  ! -- local variables
2218  class(numericalmodeltype), pointer :: m => null()
2219  !
2220  ! -- add a model
2221  select type (mp)
2222  class is (numericalmodeltype)
2223  m => mp
2224  call addnumericalmodeltolist(this%modellist, m)
2225  end select
2226  end subroutine add_model
2227 
2228  !> @brief Get a list of models
2229  !!
2230  !! Returns a pointer to the list of models in this solution.
2231  !!
2232  !<
2233  function get_models(this) result(models)
2234  ! -- return variable
2235  type(listtype), pointer :: models !< pointer to the model list
2236  ! -- dummy variables
2237  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2238 
2239  models => this%modellist
2240 
2241  end function get_models
2242 
2243  !> @brief Add exchange
2244  !!
2245  !! Add and exchange to this%exchangelist.
2246  !!
2247  !<
2248  subroutine add_exchange(this, exchange)
2249  ! -- dummy variables
2250  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2251  class(baseexchangetype), pointer, intent(in) :: exchange !< model exchange instance
2252  ! -- local variables
2253  class(numericalexchangetype), pointer :: num_ex => null()
2254  !
2255  ! -- add exchange
2256  select type (exchange)
2257  class is (numericalexchangetype)
2258  num_ex => exchange
2259  call addnumericalexchangetolist(this%exchangelist, num_ex)
2260  end select
2261  end subroutine add_exchange
2262 
2263  !> @brief Returns a pointer to the list of exchanges in this solution
2264  !<
2265  function get_exchanges(this) result(exchanges)
2266  class(numericalsolutiontype) :: this !< instance of the numerical solution
2267  type(listtype), pointer :: exchanges !< pointer to the exchange list
2268 
2269  exchanges => this%exchangelist
2270 
2271  end function get_exchanges
2272 
2273  !> @ brief Assign solution connections
2274  !!
2275  !! Assign solution connections. This is the main workhorse method for a
2276  !! solution. The method goes through all the models and all the connections
2277  !! and builds up the sparse matrix. Steps are (1) add internal model
2278  !! connections, (2) add cross terms, (3) allocate solution arrays, (4) create
2279  !! mapping arrays, and (5) fill cross term values if necessary.
2280  !!
2281  !<
2282  subroutine sln_connect(this)
2283  ! -- modules
2285  ! -- dummy variables
2286  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2287  ! -- local variables
2288  class(numericalmodeltype), pointer :: mp => null()
2289  class(numericalexchangetype), pointer :: cp => null()
2290  integer(I4B) :: im
2291  integer(I4B) :: ic
2292  !
2293  ! -- Add internal model connections to sparse
2294  do im = 1, this%modellist%Count()
2295  mp => getnumericalmodelfromlist(this%modellist, im)
2296  call mp%model_ac(this%sparse)
2297  end do
2298  !
2299  ! -- synchronize before AC
2300  call this%synchronize(stg_bfr_exg_ac, this%synchronize_ctx)
2301  !
2302  ! -- Add the cross terms to sparse
2303  do ic = 1, this%exchangelist%Count()
2304  cp => getnumericalexchangefromlist(this%exchangelist, ic)
2305  call cp%exg_ac(this%sparse)
2306  end do
2307  !
2308  ! -- The number of non-zero array values are now known so
2309  ! -- ia and ja can be created from sparse. then destroy sparse
2310  call this%sparse%sort()
2311  call this%system_matrix%init(this%sparse, this%name)
2312  call this%sparse%destroy()
2313  !
2314  ! -- Create mapping arrays for each model. Mapping assumes
2315  ! -- that each row has the diagonal in the first position,
2316  ! -- however, rows do not need to be sorted.
2317  do im = 1, this%modellist%Count()
2318  mp => getnumericalmodelfromlist(this%modellist, im)
2319  call mp%model_mc(this%system_matrix)
2320  end do
2321  !
2322  ! -- Create arrays for mapping exchange connections to global solution
2323  do ic = 1, this%exchangelist%Count()
2324  cp => getnumericalexchangefromlist(this%exchangelist, ic)
2325  call cp%exg_mc(this%system_matrix)
2326  end do
2327  end subroutine sln_connect
2328 
2329  !> @ brief Reset the solution
2330  !!
2331  !! Reset the solution by setting the coefficient matrix and right-hand side
2332  !! vectors to zero.
2333  !!
2334  !<
2335  subroutine sln_reset(this)
2336  ! -- dummy variables
2337  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2338  !
2339  ! -- reset the solution
2340  call this%system_matrix%zero_entries()
2341  call this%vec_rhs%zero_entries()
2342  end subroutine sln_reset
2343 
2344  !> @ brief Solve the linear system of equations
2345  !!
2346  !! Solve the linear system of equations. Steps include (1) matrix cleanup,
2347  !! (2) add pseudo-transient continuation terms, and (3) residual reduction.
2348  !!
2349  !<
2350  subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf)
2351  ! -- dummy variables
2352  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2353  integer(I4B), intent(in) :: kiter
2354  integer(I4B), intent(in) :: kstp
2355  integer(I4B), intent(in) :: kper
2356  integer(I4B), intent(inout) :: in_iter
2357  integer(I4B), intent(inout) :: iptc
2358  real(DP), intent(in) :: ptcf
2359  ! -- local variables
2360  logical(LGP) :: lsame
2361  integer(I4B) :: ieq
2362  integer(I4B) :: irow_glo
2363  integer(I4B) :: itestmat
2364  integer(I4B) :: ipos
2365  integer(I4B) :: icol_s
2366  integer(I4B) :: icol_e
2367  integer(I4B) :: jcol
2368  integer(I4B) :: iptct
2369  integer(I4B) :: iallowptc
2370  real(DP) :: adiag
2371  real(DP) :: diagval
2372  real(DP) :: l2norm
2373  real(DP) :: ptcval
2374  real(DP) :: bnorm
2375  character(len=50) :: fname
2376  character(len=*), parameter :: fmtfname = "('mf6mat_', i0, '_', i0, &
2377  &'_', i0, '_', i0, '.txt')"
2378  !
2379  ! -- take care of loose ends for all nodes before call to solver
2380  do ieq = 1, this%neq
2381  !
2382  ! -- get (global) cell id
2383  irow_glo = ieq + this%matrix_offset
2384  !
2385  ! -- store x in temporary location
2386  this%xtemp(ieq) = this%x(ieq)
2387  !
2388  ! -- make adjustments to the continuity equation for the node
2389  ! -- adjust small diagonal coefficient in an active cell
2390  if (this%active(ieq) > 0) then
2391  diagval = -done
2392  adiag = abs(this%system_matrix%get_diag_value(irow_glo))
2393  if (adiag < dem15) then
2394  call this%system_matrix%set_diag_value(irow_glo, diagval)
2395  this%rhs(ieq) = this%rhs(ieq) + diagval * this%x(ieq)
2396  end if
2397  ! -- Dirichlet boundary or no-flow cell
2398  else
2399  call this%system_matrix%set_diag_value(irow_glo, done)
2400  call this%system_matrix%zero_row_offdiag(irow_glo)
2401  this%rhs(ieq) = this%x(ieq)
2402  end if
2403  end do
2404  !
2405  ! -- complete adjustments for Dirichlet boundaries for a symmetric matrix
2406  if (this%isymmetric == 1 .and. simulation_mode == "SEQUENTIAL") then
2407  do ieq = 1, this%neq
2408  if (this%active(ieq) > 0) then
2409  icol_s = this%system_matrix%get_first_col_pos(ieq)
2410  icol_e = this%system_matrix%get_last_col_pos(ieq)
2411  do ipos = icol_s, icol_e
2412  jcol = this%system_matrix%get_column(ipos)
2413  if (jcol == ieq) cycle
2414  if (this%active(jcol) < 0) then
2415  this%rhs(ieq) = this%rhs(ieq) - &
2416  (this%system_matrix%get_value_pos(ipos) * &
2417  this%x(jcol))
2418  call this%system_matrix%set_value_pos(ipos, dzero)
2419  end if
2420 
2421  end do
2422  end if
2423  end do
2424  end if
2425  !
2426  ! -- pseudo transient continuation
2427  !
2428  ! -- set iallowptc
2429  ! -- no_ptc_option is FIRST
2430  if (this%iallowptc < 0) then
2431  if (kper > 1) then
2432  iallowptc = 1
2433  else
2434  iallowptc = 0
2435  end if
2436  !
2437  ! -- no_ptc_option is ALL (0) or using PTC (1)
2438  else
2439  iallowptc = this%iallowptc
2440  end if
2441  !
2442  ! -- set iptct
2443  iptct = iptc * iallowptc
2444  !
2445  ! -- calculate or modify pseudo transient continuation terms and add
2446  ! to amat diagonals
2447  if (iptct /= 0) then
2448  call this%sln_l2norm(l2norm)
2449  ! -- confirm that the l2norm exceeds previous l2norm
2450  ! if not, there is no need to add ptc terms
2451  if (kiter == 1) then
2452  if (kper > 1 .or. kstp > 1) then
2453  if (l2norm <= this%l2norm0) then
2454  iptc = 0
2455  end if
2456  end if
2457  else
2458  lsame = is_close(l2norm, this%l2norm0)
2459  if (lsame) then
2460  iptc = 0
2461  end if
2462  end if
2463  end if
2464  iptct = iptc * iallowptc
2465  if (iptct /= 0) then
2466  if (kiter == 1) then
2467  if (this%iptcout > 0) then
2468  write (this%iptcout, '(A10,6(1x,A15))') 'OUTER ITER', &
2469  ' PTCDEL', ' L2NORM0', ' L2NORM', &
2470  ' RHSNORM', ' 1/PTCDEL', ' RHSNORM/L2NORM'
2471  end if
2472  if (this%ptcdel0 > dzero) then
2473  this%ptcdel = this%ptcdel0
2474  else
2475  if (this%iptcopt == 0) then
2476  !
2477  ! -- ptcf is the reciprocal of the pseudo-time step
2478  this%ptcdel = done / ptcf
2479  else
2480  bnorm = dzero
2481  do ieq = 1, this%neq
2482  if (this%active(ieq) .gt. 0) then
2483  bnorm = bnorm + this%rhs(ieq) * this%rhs(ieq)
2484  end if
2485  end do
2486  bnorm = sqrt(bnorm)
2487  this%ptcdel = bnorm / l2norm
2488  end if
2489  end if
2490  else
2491  if (l2norm > dzero) then
2492  this%ptcdel = this%ptcdel * (this%l2norm0 / l2norm)**this%ptcexp
2493  else
2494  this%ptcdel = dzero
2495  end if
2496  end if
2497  if (this%ptcdel > dzero) then
2498  ptcval = done / this%ptcdel
2499  else
2500  ptcval = done
2501  end if
2502  bnorm = dzero
2503  do ieq = 1, this%neq
2504  irow_glo = ieq + this%matrix_offset
2505  if (this%active(ieq) > 0) then
2506  diagval = abs(this%system_matrix%get_diag_value(irow_glo))
2507  bnorm = bnorm + this%rhs(ieq) * this%rhs(ieq)
2508  call this%system_matrix%add_diag_value(irow_glo, -ptcval)
2509  this%rhs(ieq) = this%rhs(ieq) - ptcval * this%x(ieq)
2510  end if
2511  end do
2512  bnorm = sqrt(bnorm)
2513  if (this%iptcout > 0) then
2514  write (this%iptcout, '(i10,5(1x,e15.7),1(1x,f15.6))') &
2515  kiter, this%ptcdel, this%l2norm0, l2norm, bnorm, &
2516  ptcval, bnorm / l2norm
2517  end if
2518  this%l2norm0 = l2norm
2519  end if
2520  !
2521  ! -- save rhs, amat to a file
2522  ! to enable set itestmat to 1 and recompile
2523  !-------------------------------------------------------
2524  itestmat = 0
2525  if (itestmat == 1) then
2526  write (fname, fmtfname) this%id, kper, kstp, kiter
2527  print *, 'Saving amat to: ', trim(adjustl(fname))
2528 
2529  itestmat = getunit()
2530  open (itestmat, file=trim(adjustl(fname)))
2531  write (itestmat, *) 'NODE, RHS, AMAT FOLLOW'
2532  do ieq = 1, this%neq
2533  irow_glo = ieq + this%matrix_offset
2534  icol_s = this%system_matrix%get_first_col_pos(irow_glo)
2535  icol_e = this%system_matrix%get_last_col_pos(irow_glo)
2536  write (itestmat, '(*(G0,:,","))') &
2537  irow_glo, &
2538  this%rhs(ieq), &
2539  (this%system_matrix%get_column(ipos), ipos=icol_s, icol_e), &
2540  (this%system_matrix%get_value_pos(ipos), ipos=icol_s, icol_e)
2541  end do
2542  close (itestmat)
2543  !stop
2544  end if
2545  !-------------------------------------------------------
2546  !
2547  ! -- call appropriate linear solver
2548  !
2549  ! -- ims linear solver - linmeth option 1
2550  if (this%linsolver == ims_solver) then
2551  call this%imslinear%imslinear_apply(this%icnvg, kstp, kiter, in_iter, &
2552  this%nitermax, this%convnmod, &
2553  this%convmodstart, this%caccel, &
2554  this%cnvg_summary)
2555  else if (this%linsolver == petsc_solver) then
2556  call this%linear_solver%solve(kiter, this%vec_rhs, &
2557  this%vec_x, this%cnvg_summary)
2558  in_iter = this%linear_solver%iteration_number
2559  this%icnvg = this%linear_solver%is_converged
2560  end if
2561  end subroutine sln_ls
2562 
2563  !
2564  !> @ brief Set default Picard iteration variables
2565  !!
2566  !! Set default Picard iteration variables based on passed complexity option.
2567  !!
2568  !<
2569  subroutine sln_setouter(this, ifdparam)
2570  ! -- dummy variables
2571  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2572  integer(I4B), intent(in) :: ifdparam !< complexity option (1) simple (2) moderate (3) complex
2573  !
2574  ! -- simple option
2575  select case (ifdparam)
2576  case (1)
2577  this%dvclose = dem3
2578  this%mxiter = 25
2579  this%nonmeth = 0
2580  this%theta = done
2581  this%akappa = dzero
2582  this%gamma = done
2583  this%amomentum = dzero
2584  this%numtrack = 0
2585  this%btol = dzero
2586  this%breduc = dzero
2587  this%res_lim = dzero
2588  !
2589  ! -- moderate
2590  case (2)
2591  this%dvclose = dem2
2592  this%mxiter = 50
2593  this%nonmeth = 3
2594  this%theta = 0.9d0
2595  this%akappa = 0.0001d0
2596  this%gamma = dzero
2597  this%amomentum = dzero
2598  this%numtrack = 0
2599  this%btol = dzero
2600  this%breduc = dzero
2601  this%res_lim = dzero
2602  !
2603  ! -- complex
2604  case (3)
2605  this%dvclose = dem1
2606  this%mxiter = 100
2607  this%nonmeth = 3
2608  this%theta = 0.8d0
2609  this%akappa = 0.0001d0
2610  this%gamma = dzero
2611  this%amomentum = dzero
2612  this%numtrack = 20
2613  this%btol = 1.05d0
2614  this%breduc = 0.1d0
2615  this%res_lim = 0.002d0
2616  end select
2617  end subroutine sln_setouter
2618 
2619  !> @ brief Perform backtracking
2620  !!
2621  !! Perform backtracking on the solution in the maximum number of backtrack
2622  !! iterations (nbtrack) is greater than 0 and the backtracking criteria
2623  !! are exceeded.
2624  !!
2625  !<
2626  subroutine sln_backtracking(this, mp, cp, kiter)
2627  ! -- dummy variables
2628  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2629  class(numericalmodeltype), pointer :: mp !< model pointer (currently null())
2630  class(numericalexchangetype), pointer :: cp !< exchange pointer (currently null())
2631  integer(I4B), intent(in) :: kiter !< Picard iteration number
2632  ! -- local variables
2633  character(len=7) :: cmsg
2634  integer(I4B) :: nb
2635  integer(I4B) :: btflag
2636  integer(I4B) :: ibflag
2637  integer(I4B) :: ibtcnt
2638  real(DP) :: resin
2639  !
2640  ! -- initialize local variables
2641  ibflag = 0
2642 
2643  !
2644  ! -- refill amat and rhs with standard conductance
2645  call this%sln_buildsystem(kiter, inewton=0)
2646 
2647  !
2648  ! -- calculate initial l2 norm
2649  if (kiter == 1) then
2650  call this%sln_l2norm(this%res_prev)
2651  resin = this%res_prev
2652  ibflag = 0
2653  else
2654  call this%sln_l2norm(this%res_new)
2655  resin = this%res_new
2656  end if
2657  ibtcnt = 0
2658  if (kiter > 1) then
2659  if (this%res_new > this%res_prev * this%btol) then
2660  !
2661  ! -- iterate until backtracking complete
2662  btloop: do nb = 1, this%numtrack
2663  !
2664  ! -- backtrack the dependent variable
2665  call this%sln_backtracking_xupdate(btflag)
2666  !
2667  ! -- dependent-variable change less than dvclose
2668  if (btflag == 0) then
2669  ibflag = 4
2670  exit btloop
2671  end if
2672  !
2673  ibtcnt = nb
2674 
2675  ! recalculate linear system (amat and rhs)
2676  call this%sln_buildsystem(kiter, inewton=0)
2677 
2678  !
2679  ! -- calculate updated l2norm
2680  call this%sln_l2norm(this%res_new)
2681  !
2682  ! -- evaluate if back tracking can be terminated
2683  if (nb == this%numtrack) then
2684  ibflag = 2
2685  exit btloop
2686  end if
2687  if (this%res_new < this%res_prev * this%btol) then
2688  ibflag = 1
2689  exit btloop
2690  end if
2691  if (this%res_new < this%res_lim) then
2692  exit btloop
2693  end if
2694  end do btloop
2695  end if
2696  ! -- save new residual
2697  this%res_prev = this%res_new
2698  end if
2699  !
2700  ! -- write back backtracking results
2701  if (this%iprims > 0) then
2702  if (ibtcnt > 0) then
2703  cmsg = ' '
2704  else
2705  cmsg = '*'
2706  end if
2707  !
2708  ! -- add data to outertab
2709  call this%outertab%add_term('Backtracking')
2710  call this%outertab%add_term(kiter)
2711  call this%outertab%add_term(' ')
2712  if (this%numtrack > 0) then
2713  call this%outertab%add_term(ibflag)
2714  call this%outertab%add_term(ibtcnt)
2715  call this%outertab%add_term(resin)
2716  call this%outertab%add_term(this%res_prev)
2717  end if
2718  call this%outertab%add_term(' ')
2719  call this%outertab%add_term(cmsg)
2720  call this%outertab%add_term(' ')
2721  end if
2722  end subroutine sln_backtracking
2723 
2724  !> @ brief Backtracking update of the dependent variable
2725  !!
2726  !! Backtracking update of the dependent variable if the calculated backtracking
2727  !! update exceeds the dependent variable closure criteria.
2728  !!
2729  !<
2730  subroutine sln_backtracking_xupdate(this, bt_flag)
2731  ! -- dummy variables
2732  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2733  integer(I4B), intent(inout) :: bt_flag !< backtracking flag (1) backtracking performed (0) backtracking not performed
2734 
2735  bt_flag = this%get_backtracking_flag()
2736 
2737  ! perform backtracking if ...
2738  if (bt_flag > 0) then
2739  call this%apply_backtracking()
2740  end if
2741 
2742  end subroutine sln_backtracking_xupdate
2743 
2744  !> @brief Check if backtracking should be applied for this solution,
2745  !< returns 1: yes, 0: no
2746  function get_backtracking_flag(this) result(bt_flag)
2747  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2748  integer(I4B) :: bt_flag !< backtracking flag (1) backtracking performed (0) backtracking not performed
2749  ! local
2750  integer(I4B) :: n
2751  real(dp) :: dx
2752  real(dp) :: dx_abs
2753  real(dp) :: dx_abs_max
2754 
2755  ! default is off
2756  bt_flag = 0
2757 
2758  ! find max. change
2759  dx_abs_max = 0.0
2760  do n = 1, this%neq
2761  if (this%active(n) < 1) cycle
2762  dx = this%x(n) - this%xtemp(n)
2763  dx_abs = abs(dx)
2764  if (dx_abs > dx_abs_max) dx_abs_max = dx_abs
2765  end do
2766 
2767  ! if backtracking, set flag
2768  if (this%breduc * dx_abs_max >= this%dvclose) then
2769  bt_flag = 1
2770  end if
2771 
2772  end function get_backtracking_flag
2773 
2774  !> @brief Update x with backtracking
2775  !<
2776  subroutine apply_backtracking(this)
2777  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2778  ! local
2779  integer(I4B) :: n
2780  real(DP) :: delx
2781 
2782  do n = 1, this%neq
2783  if (this%active(n) < 1) cycle
2784  delx = this%breduc * (this%x(n) - this%xtemp(n))
2785  this%x(n) = this%xtemp(n) + delx
2786  end do
2787 
2788  end subroutine
2789 
2790  !> @ brief Calculate the solution L-2 norm for all
2791  !! active cells using
2792  !!
2793  !! A = the linear system matrix
2794  !! x = the dependent variable vector
2795  !! b = the right-hand side vector
2796  !!
2797  !! r = A * x - b
2798  !! r_i = 0 if cell i is inactive
2799  !! L2norm = || r ||_2
2800  !<
2801  subroutine sln_l2norm(this, l2norm)
2802  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2803  real(DP) :: l2norm !< calculated L-2 norm
2804  ! local
2805  class(vectorbasetype), pointer :: vec_resid
2806 
2807  ! calc. residual vector
2808  vec_resid => this%system_matrix%create_vec(this%neq)
2809  call this%sln_calc_residual(vec_resid)
2810 
2811  ! 2-norm
2812  l2norm = vec_resid%norm2()
2813 
2814  ! clean up temp. vector
2815  call vec_resid%destroy()
2816  deallocate (vec_resid)
2817  end subroutine sln_l2norm
2818 
2819  !> @ brief Get the maximum value from a vector
2820  !!
2821  !! Return the maximum value in a vector using a normalized form.
2822  !!
2823  !<
2824  subroutine sln_maxval(this, nsize, v, vmax)
2825  ! -- dummy variables
2826  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2827  integer(I4B), intent(in) :: nsize !< length of vector
2828  real(DP), dimension(nsize), intent(in) :: v !< input vector
2829  real(DP), intent(inout) :: vmax !< maximum value
2830  ! -- local variables
2831  integer(I4B) :: n
2832  real(DP) :: d
2833  real(DP) :: denom
2834  real(DP) :: dnorm
2835  !
2836  ! -- determine maximum value
2837  vmax = v(1)
2838  do n = 2, nsize
2839  d = v(n)
2840  denom = abs(vmax)
2841  if (denom == dzero) then
2842  denom = dprec
2843  end if
2844  !
2845  ! -- calculate normalized value
2846  dnorm = abs(d) / denom
2847  if (dnorm > done) then
2848  vmax = d
2849  end if
2850  end do
2851  end subroutine sln_maxval
2852 
2853  !> @ brief Calculate dependent-variable change
2854  !!
2855  !! Calculate the dependent-variable change for every cell.
2856  !!
2857  !<
2858  subroutine sln_calcdx(this, neq, active, x, xtemp, dx)
2859  ! -- dummy variables
2860  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2861  integer(I4B), intent(in) :: neq !< number of equations
2862  integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1)
2863  real(DP), dimension(neq), intent(in) :: x !< current dependent-variable
2864  real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable
2865  real(DP), dimension(neq), intent(inout) :: dx !< dependent-variable change
2866  ! -- local
2867  integer(I4B) :: n
2868  !
2869  ! -- calculate dependent-variable change
2870  do n = 1, neq
2871  ! -- skip inactive nodes
2872  if (active(n) < 1) then
2873  dx(n) = dzero
2874  else
2875  dx(n) = x(n) - xtemp(n)
2876  end if
2877  end do
2878  end subroutine sln_calcdx
2879 
2880  !> @brief Calculate pseudo-transient continuation factor
2881  !< from the models in the solution
2882  subroutine sln_calc_ptc(this, iptc, ptcf)
2883  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2884  integer(I4B) :: iptc !< PTC (1) or not (0)
2885  real(DP) :: ptcf !< the PTC factor calculated
2886  ! local
2887  integer(I4B) :: im
2888  class(numericalmodeltype), pointer :: mp
2889  class(vectorbasetype), pointer :: vec_resid
2890 
2891  iptc = 0
2892  ptcf = dzero
2893 
2894  ! calc. residual vector
2895  vec_resid => this%system_matrix%create_vec(this%neq)
2896  call this%sln_calc_residual(vec_resid)
2897 
2898  ! determine ptc
2899  do im = 1, this%modellist%Count()
2900  mp => getnumericalmodelfromlist(this%modellist, im)
2901  call mp%model_ptc(vec_resid, iptc, ptcf)
2902  end do
2903 
2904  ! clean up temp. vector
2905  call vec_resid%destroy()
2906  deallocate (vec_resid)
2907 
2908  end subroutine sln_calc_ptc
2909 
2910  !> @brief Calculate the current residual vector r = A*x - b,
2911  !< zeroes out for inactive cells
2912  subroutine sln_calc_residual(this, vec_resid)
2913  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2914  class(vectorbasetype), pointer :: vec_resid !< the residual vector
2915  ! local
2916  integer(I4B) :: n
2917 
2918  call this%system_matrix%multiply(this%vec_x, vec_resid) ! r = A*x
2919 
2920  call vec_resid%axpy(-1.0_dp, this%vec_rhs) ! r = r - b
2921 
2922  do n = 1, this%neq
2923  if (this%active(n) < 1) then
2924  call vec_resid%set_value_local(n, 0.0_dp) ! r_i = 0 if inactive
2925  end if
2926  end do
2927 
2928  end subroutine sln_calc_residual
2929 
2930  !> @ brief Under-relaxation
2931  !!
2932  !! Under relax using the simple, cooley, or delta-bar-delta methods.
2933  !!
2934  !<
2935  subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp)
2936  ! -- dummy variables
2937  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2938  integer(I4B), intent(in) :: kiter !< Picard iteration number
2939  real(DP), intent(in) :: bigch !< maximum dependent-variable change
2940  integer(I4B), intent(in) :: neq !< number of equations
2941  integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1)
2942  real(DP), dimension(neq), intent(inout) :: x !< current dependent-variable
2943  real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable
2944  ! -- local variables
2945  integer(I4B) :: n
2946  real(DP) :: ww
2947  real(DP) :: delx
2948  real(DP) :: relax
2949  real(DP) :: es
2950  real(DP) :: aes
2951  real(DP) :: amom
2952  !
2953  ! -- option for using simple dampening (as done by MODFLOW-2005 PCG)
2954  if (this%nonmeth == 1) then
2955  do n = 1, neq
2956  !
2957  ! -- skip inactive nodes
2958  if (active(n) < 1) cycle
2959  !
2960  ! -- compute step-size (delta x)
2961  delx = x(n) - xtemp(n)
2962  this%dxold(n) = delx
2963 
2964  ! -- dampen dependent variable solution
2965  x(n) = xtemp(n) + this%gamma * delx
2966  end do
2967  !
2968  ! -- option for using cooley underrelaxation
2969  else if (this%nonmeth == 2) then
2970  !
2971  ! -- set bigch
2972  this%bigch = bigch
2973  !
2974  ! -- initialize values for first iteration
2975  if (kiter == 1) then
2976  relax = done
2977  this%relaxold = done
2978  this%bigchold = bigch
2979  else
2980  !
2981  ! -- compute relaxation factor
2982  es = this%bigch / (this%bigchold * this%relaxold)
2983  aes = abs(es)
2984  if (es < -done) then
2985  relax = dhalf / aes
2986  else
2987  relax = (dthree + es) / (dthree + aes)
2988  end if
2989  end if
2990  this%relaxold = relax
2991  !
2992  ! -- modify cooley to use weighted average of past changes
2993  this%bigchold = (done - this%gamma) * this%bigch + this%gamma * &
2994  this%bigchold
2995  !
2996  ! -- compute new dependent variable after under-relaxation
2997  if (relax < done) then
2998  do n = 1, neq
2999  !
3000  ! -- skip inactive nodes
3001  if (active(n) < 1) cycle
3002  !
3003  ! -- update dependent variable
3004  delx = x(n) - xtemp(n)
3005  this%dxold(n) = delx
3006  x(n) = xtemp(n) + relax * delx
3007  end do
3008  end if
3009  !
3010  ! -- option for using delta-bar-delta scheme to under-relax for all equations
3011  else if (this%nonmeth == 3) then
3012  do n = 1, neq
3013  !
3014  ! -- skip inactive nodes
3015  if (active(n) < 1) cycle
3016  !
3017  ! -- compute step-size (delta x) and initialize d-b-d parameters
3018  delx = x(n) - xtemp(n)
3019  !
3020  ! -- initialize values for first iteration
3021  if (kiter == 1) then
3022  this%wsave(n) = done
3023  this%hchold(n) = dem20
3024  this%deold(n) = dzero
3025  end if
3026  !
3027  ! -- compute new relaxation term as per delta-bar-delta
3028  ww = this%wsave(n)
3029  !
3030  ! for flip-flop condition, decrease factor
3031  if (this%deold(n) * delx < dzero) then
3032  ww = this%theta * this%wsave(n)
3033  ! -- when change is of same sign, increase factor
3034  else
3035  ww = this%wsave(n) + this%akappa
3036  end if
3037  if (ww > done) ww = done
3038  this%wsave(n) = ww
3039  !
3040  ! -- compute weighted average of past changes in hchold
3041  if (kiter == 1) then
3042  this%hchold(n) = delx
3043  else
3044  this%hchold(n) = (done - this%gamma) * delx + &
3045  this%gamma * this%hchold(n)
3046  end if
3047  !
3048  ! -- store slope (change) term for next iteration
3049  this%deold(n) = delx
3050  this%dxold(n) = delx
3051  !
3052  ! -- compute accepted step-size and new dependent variable
3053  amom = dzero
3054  if (kiter > 4) amom = this%amomentum
3055  delx = delx * ww + amom * this%hchold(n)
3056  x(n) = xtemp(n) + delx
3057  end do
3058  !
3059  end if
3060  end subroutine sln_underrelax
3061 
3062  !> @ brief Determine maximum dependent-variable change
3063  !!
3064  !! Determine the maximum dependent-variable change at the end of a
3065  !! Picard iteration.
3066  !!
3067  !<
3068  subroutine sln_get_dxmax(this, hncg, lrch)
3069  ! -- dummy variables
3070  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
3071  real(DP), intent(inout) :: hncg !< maximum dependent-variable change
3072  integer(I4B), intent(inout) :: lrch !< location of the maximum dependent-variable change
3073  ! -- local variables
3074  integer(I4B) :: nb
3075  real(DP) :: bigch
3076  real(DP) :: abigch
3077  integer(I4B) :: n
3078  real(DP) :: hdif
3079  real(DP) :: ahdif
3080  !
3081  ! -- determine the maximum change
3082  nb = 0
3083  bigch = dzero
3084  abigch = dzero
3085  do n = 1, this%neq
3086  if (this%active(n) < 1) cycle
3087  hdif = this%x(n) - this%xtemp(n)
3088  ahdif = abs(hdif)
3089  if (ahdif > abigch) then
3090  bigch = hdif
3091  abigch = ahdif
3092  nb = n
3093  end if
3094  end do
3095  !
3096  !-----store maximum change value and location
3097  hncg = bigch
3098  lrch = nb
3099  end subroutine sln_get_dxmax
3100 
3101  function sln_has_converged(this, max_dvc) result(has_converged)
3102  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3103  real(dp) :: max_dvc !< the maximum dependent variable change
3104  logical(LGP) :: has_converged !< True, when converged
3105 
3106  has_converged = .false.
3107  if (abs(max_dvc) <= this%dvclose) then
3108  has_converged = .true.
3109  end if
3110 
3111  end function sln_has_converged
3112 
3113  !> @brief Check package convergence
3114  !<
3115  function sln_package_convergence(this, dpak, cpakout, iend) result(ivalue)
3116  ! dummy
3117  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3118  real(dp), intent(in) :: dpak !< Newton Under-relaxation flag
3119  character(len=LENPAKLOC), intent(in) :: cpakout !< string with package that caused failure
3120  integer(I4B), intent(in) :: iend !< flag indicating if last inner iteration (iend=1)
3121  ! local
3122  integer(I4B) :: ivalue
3123  ivalue = 1
3124  if (abs(dpak) > this%dvclose) then
3125  ivalue = 0
3126  ! -- write message to stdout
3127  if (iend /= 0) then
3128  write (errmsg, '(3a)') &
3129  'PACKAGE (', trim(cpakout), ') CAUSED CONVERGENCE FAILURE'
3130  call write_message(errmsg)
3131  end if
3132  end if
3133 
3134  end function sln_package_convergence
3135 
3136  !> @brief Synchronize Newton Under-relaxation flag
3137  !<
3138  function sln_sync_newtonur_flag(this, inewtonur) result(ivalue)
3139  ! dummy
3140  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3141  integer(I4B), intent(in) :: inewtonur !< Newton Under-relaxation flag
3142  ! local
3143  integer(I4B) :: ivalue !< Default is set to current value (1 = under-relaxation applied)
3144 
3145  ivalue = inewtonur
3146 
3147  end function sln_sync_newtonur_flag
3148 
3149  !> @brief Custom convergence check for when Newton UR has been applied
3150  !<
3151  function sln_nur_has_converged(this, dxold_max, hncg) &
3152  result(has_converged)
3153  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3154  real(dp), intent(in) :: dxold_max !< the maximum dependent variable change for unrelaxed cells
3155  real(dp), intent(in) :: hncg !< largest dep. var. change at end of Picard iteration
3156  logical(LGP) :: has_converged !< True, when converged
3157 
3158  has_converged = .false.
3159  if (abs(dxold_max) <= this%dvclose .and. &
3160  abs(hncg) <= this%dvclose) then
3161  has_converged = .true.
3162  end if
3163 
3164  end function sln_nur_has_converged
3165 
3166  !> @ brief Get cell location string
3167  !!
3168  !! Get the cell location string for the provided solution node number.
3169  !< Returns empty string when node not found.
3170  subroutine sln_get_loc(this, nodesln, str)
3171  ! -- dummy variables
3172  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
3173  integer(I4B), intent(in) :: nodesln !< solution node number
3174  character(len=*), intent(inout) :: str !< string with user node number
3175  ! -- local variables
3176  class(numericalmodeltype), pointer :: mp => null()
3177  integer(I4B) :: i
3178  integer(I4B) :: istart
3179  integer(I4B) :: iend
3180  integer(I4B) :: noder
3181  integer(I4B) :: nglo
3182  !
3183  ! -- initialize dummy variables
3184  str = ''
3185  !
3186  ! -- initialize local variables
3187  noder = 0
3188  !
3189  ! -- when parallel, account for offset
3190  nglo = nodesln + this%matrix_offset
3191  !
3192  ! -- calculate and set offsets
3193  do i = 1, this%modellist%Count()
3194  mp => getnumericalmodelfromlist(this%modellist, i)
3195  istart = 0
3196  iend = 0
3197  call mp%get_mrange(istart, iend)
3198  if (nglo >= istart .and. nglo <= iend) then
3199  noder = nglo - istart + 1
3200  call mp%get_mcellid(noder, str)
3201  exit
3202  end if
3203  end do
3204  end subroutine sln_get_loc
3205 
3206  !> @ brief Get user node number
3207  !!
3208  !! Get the user node number from a model for the provided solution node number.
3209  !!
3210  !<
3211  subroutine sln_get_nodeu(this, nodesln, im, nodeu)
3212  ! -- dummy variables
3213  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
3214  integer(I4B), intent(in) :: nodesln !< solution node number
3215  integer(I4B), intent(inout) :: im !< solution model index (index in model list for this solution)
3216  integer(I4B), intent(inout) :: nodeu !< user node number
3217  ! -- local variables
3218  class(numericalmodeltype), pointer :: mp => null()
3219  integer(I4B) :: i
3220  integer(I4B) :: istart
3221  integer(I4B) :: iend
3222  integer(I4B) :: noder, nglo
3223  !
3224  ! -- initialize local variables
3225  noder = 0
3226  !
3227  ! -- when parallel, account for offset
3228  nglo = nodesln + this%matrix_offset
3229  !
3230  ! -- calculate and set offsets
3231  do i = 1, this%modellist%Count()
3232  mp => getnumericalmodelfromlist(this%modellist, i)
3233  istart = 0
3234  iend = 0
3235  call mp%get_mrange(istart, iend)
3236  if (nglo >= istart .and. nglo <= iend) then
3237  noder = nglo - istart + 1
3238  call mp%get_mnodeu(noder, nodeu)
3239  im = i
3240  exit
3241  end if
3242  end do
3243  end subroutine sln_get_nodeu
3244 
3245  !> @ brief Cast a object as a Numerical Solution
3246  !!
3247  !! Get a numerical solution from a list.
3248  !!
3249  !<
3250  function castasnumericalsolutionclass(obj) result(res)
3251  ! -- dummy variables
3252  class(*), pointer, intent(inout) :: obj !< generic object
3253  ! -- return variable
3254  class(numericalsolutiontype), pointer :: res !< output NumericalSolutionType
3255  !
3256  ! -- initialize return variable
3257  res => null()
3258  !
3259  ! -- determine if obj is associated
3260  if (.not. associated(obj)) return
3261  !
3262  ! -- set res
3263  select type (obj)
3264  class is (numericalsolutiontype)
3265  res => obj
3266  end select
3267  end function castasnumericalsolutionclass
3268 
3269  !> @ brief Get a numerical solution
3270  !!
3271  !! Get a numerical solution from a list.
3272  !!
3273  !<
3274  function getnumericalsolutionfromlist(list, idx) result(res)
3275  ! -- dummy variables
3276  type(listtype), intent(inout) :: list !< list of numerical solutions
3277  integer(I4B), intent(in) :: idx !< value to retrieve from the list
3278  ! -- return variables
3279  class(numericalsolutiontype), pointer :: res !< numerical solution
3280  ! -- local variables
3281  class(*), pointer :: obj
3282  !
3283  obj => list%GetItem(idx)
3284  res => castasnumericalsolutionclass(obj)
3285  end function getnumericalsolutionfromlist
3286 end module numericalsolutionmodule
subroutine, public ats_submit_delt(kstp, kper, dt, sloc, idir)
@ brief Allow and external caller to submit preferred time step
Definition: ats.f90:493
subroutine, public addbasesolutiontolist(list, solution)
This module contains block parser methods.
Definition: BlockParser.f90:7
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
@ tabright
right justified table column
Definition: Constants.f90:173
@ tableft
left justified table column
Definition: Constants.f90:171
@ mvalidate
validation mode - do not run time steps
Definition: Constants.f90:205
@ mnormal
normal output mode
Definition: Constants.f90:206
real(dp), parameter dem20
real constant 1e-20
Definition: Constants.f90:117
real(dp), parameter dep3
real constant 1000
Definition: Constants.f90:88
integer(i4b), parameter lensolutionname
maximum length of the solution name
Definition: Constants.f90:21
real(dp), parameter dep6
real constant 1000000
Definition: Constants.f90:89
real(dp), parameter donethird
real constant 1/3
Definition: Constants.f90:67
real(dp), parameter dnodata
real no data constant
Definition: Constants.f90:95
integer(i4b), parameter lenpakloc
maximum length of a package location
Definition: Constants.f90:50
real(dp), parameter dep20
real constant 1e20
Definition: Constants.f90:91
real(dp), parameter dem1
real constant 1e-1
Definition: Constants.f90:103
real(dp), parameter dhalf
real constant 1/2
Definition: Constants.f90:68
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 dem6
real constant 1e-6
Definition: Constants.f90:109
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter dprec
real constant machine precision
Definition: Constants.f90:120
real(dp), parameter dem15
real constant 1e-15
Definition: Constants.f90:116
real(dp), parameter dem2
real constant 1e-2
Definition: Constants.f90:105
real(dp), parameter dtwo
real constant 2
Definition: Constants.f90:79
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
real(dp), parameter dthree
real constant 3
Definition: Constants.f90:80
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition: ErrorUtil.f90:24
subroutine allocate_scalars(this)
@ brief Allocate and initialize scalars
Definition: ImsLinear.f90:456
integer(i4b), parameter, public cg_method
integer(i4b) function, public getunit()
Get a free unit number.
subroutine, public append_processor_id(name, proc_id)
Append processor id to a string.
subroutine, public openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, filstat_opt, mode_opt)
Open a file.
Definition: InputOutput.f90:30
This module defines variable data types.
Definition: kind.f90:8
class(linearsolverbasetype) function, pointer, public create_linear_solver(solver_mode, sln_name)
Factory method to create the linear solver object.
type(listtype), public basesolutionlist
Definition: mf6lists.f90:19
pure logical function, public is_close(a, b, rtol, atol, symmetric)
Check if a real value is approximately equal to another.
Definition: MathUtil.f90:46
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
Store and issue logging messages to output units.
Definition: Message.f90:2
subroutine, public write_message(text, iunit, fmt, skipbefore, skipafter, advance)
Write a message to an output unit.
Definition: Message.f90:210
class(numericalexchangetype) function, pointer, public getnumericalexchangefromlist(list, idx)
Retrieve a specific numerical exchange from a list.
subroutine, public addnumericalexchangetolist(list, exchange)
Add numerical exchange to a list.
subroutine, public addnumericalmodeltolist(list, model)
class(numericalmodeltype) function, pointer, public getnumericalmodelfromlist(list, idx)
subroutine convergence_summary(this, iu, im, itertot_timestep)
@ brief Solution convergence summary
subroutine sln_get_nodeu(this, nodesln, im, nodeu)
@ brief Get user node number
integer(i4b) function sln_sync_newtonur_flag(this, inewtonur)
Synchronize Newton Under-relaxation flag.
subroutine save(this, filename)
@ brief Save solution data to a file
subroutine sln_backtracking_xupdate(this, bt_flag)
@ brief Backtracking update of the dependent variable
logical(lgp) function sln_nur_has_converged(this, dxold_max, hncg)
Custom convergence check for when Newton UR has been applied.
logical(lgp) function sln_has_converged(this, max_dvc)
integer(i4b), parameter petsc_solver
integer(i4b) function sln_package_convergence(this, dpak, cpakout, iend)
Check package convergence.
type(listtype) function, pointer get_exchanges(this)
Returns a pointer to the list of exchanges in this solution.
subroutine sln_l2norm(this, l2norm)
@ brief Calculate the solution L-2 norm for all active cells using
subroutine sln_connect(this)
@ brief Assign solution connections
subroutine sln_get_loc(this, nodesln, str)
@ brief Get cell location string
subroutine apply_backtracking(this)
Update x with backtracking.
subroutine writecsvheader(this)
@ brief CSV header
subroutine sln_buildsystem(this, kiter, inewton)
subroutine sln_maxval(this, nsize, v, vmax)
@ brief Get the maximum value from a vector
subroutine sln_calc_residual(this, vec_resid)
Calculate the current residual vector r = A*x - b,.
subroutine sln_backtracking(this, mp, cp, kiter)
@ brief Perform backtracking
subroutine sln_calc_ptc(this, iptc, ptcf)
Calculate pseudo-transient continuation factor.
subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp)
@ brief Under-relaxation
class(numericalsolutiontype) function, pointer, public castasnumericalsolutionclass(obj)
@ brief Cast a object as a Numerical Solution
type(listtype) function, pointer get_models(this)
Get a list of models.
subroutine finalizesolve(this, kiter, isgcnvg, isuppress_output)
@ brief finalize a solution
subroutine sln_setouter(this, ifdparam)
@ brief Set default Picard iteration variables
subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf)
@ brief Solve the linear system of equations
subroutine sln_calcdx(this, neq, active, x, xtemp, dx)
@ brief Calculate dependent-variable change
integer(i4b), parameter ims_solver
subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, niter, istart, kstart)
@ brief Solution convergence CSV summary
subroutine sln_reset(this)
@ brief Reset the solution
class(numericalsolutiontype) function, pointer, public getnumericalsolutionfromlist(list, idx)
@ brief Get a numerical solution
subroutine allocate_arrays(this)
@ brief Allocate arrays
integer(i4b) function get_backtracking_flag(this)
Check if backtracking should be applied for this solution,.
subroutine preparesolve(this)
@ brief prepare to solve
subroutine writeptcinfotofile(this, kper)
@ brief PTC header
subroutine add_exchange(this, exchange)
Add exchange.
subroutine add_model(this, mp)
@ brief Add a model
subroutine, public create_numerical_solution(num_sol, filename, id)
@ brief Create a new solution
subroutine sln_get_dxmax(this, hncg, lrch)
@ brief Determine maximum dependent-variable change
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public store_error(msg, terminate)
Store an error message.
Definition: Sim.f90:92
integer(i4b) function, public count_errors()
Return number of errors.
Definition: Sim.f90:59
subroutine, public deprecation_warning(cblock, cvar, cver, endmsg, iunit)
Store deprecation warning message.
Definition: Sim.f90:256
integer(i4b), parameter, public stg_bfr_exg_ad
before exchange advance (per solution)
Definition: SimStages.f90:21
integer(i4b), parameter, public stg_bfr_exg_cf
before exchange calculate (per solution)
Definition: SimStages.f90:22
integer(i4b), parameter, public stg_bfr_exg_fc
before exchange formulate (per solution)
Definition: SimStages.f90:23
integer(i4b), parameter, public stg_bfr_exg_ac
before exchange add connections (per solution)
Definition: SimStages.f90:16
This module contains simulation variables.
Definition: SimVariables.f90:9
character(len=maxcharlen) errmsg
error message string
character(len=linelength) simulation_mode
integer(i4b) nr_procs
integer(i4b) iout
file unit number for simulation output
integer(i4b) proc_id
integer(i4b) isim_mode
simulation mode
subroutine, public table_cr(this, name, title)
Definition: Table.f90:87
real(dp), pointer, public totim
time relative to start of simulation
Definition: tdis.f90:32
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:24
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:23
real(dp), pointer, public delt
length of the current time step
Definition: tdis.f90:29
subroutine, public code_timer(it, t1, ts)
Get end time and calculate elapsed time.
Definition: Timer.f90:159
This module contains version information.
Definition: version.f90:7
integer(i4b), parameter idevelopmode
Definition: version.f90:19
Highest level model type. All models extend this parent type.
Definition: BaseModel.f90:13
This structure stores the generic convergence info for a solution.
A generic heterogeneous doubly-linked list.
Definition: List.f90:14