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