MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
NumericalSolution.f90
Go to the documentation of this file.
1 ! This is the numerical solution module.
2 
4  use kindmodule, only: dp, i4b, lgp
5  use errorutilmodule, only: pstop
6  use timermodule, only: code_timer
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  call this%linear_settings%check_settings()
924  !
925  if (this%linear_settings%ilinmeth == cg_method) then
926  this%isymmetric = 1
927  end if
928  !
929  ! -- call secondary subroutine to initialize and read linear
930  ! solver parameters IMSLINEAR solver
931  if (this%solver_mode == "IMS") then
932  allocate (this%imslinear)
933  WRITE (iout, *) '***IMS LINEAR SOLVER WILL BE USED***'
934  call this%imslinear%imslinear_allocate(this%name, iout, this%iprims, &
935  this%mxiter, this%neq, &
936  this%system_matrix, this%rhs, &
937  this%x, this%linear_settings)
938  !
939  ! -- petsc linear solver flag
940  else if (this%solver_mode == "PETSC") then
941  call this%linear_solver%initialize(this%system_matrix, &
942  this%linear_settings, &
943  this%cnvg_summary)
944  !
945  ! -- incorrect linear solver flag
946  else
947  write (errmsg, '(a)') &
948  'Incorrect value for linear solution method specified.'
949  call store_error(errmsg)
950  end if
951  !
952  ! -- write message about matrix symmetry
953  if (this%isymmetric == 1) then
954  write (iout, '(1x,a,/)') 'A symmetric matrix will be solved'
955  else
956  write (iout, '(1x,a,/)') 'An asymmetric matrix will be solved'
957  end if
958  !
959  ! -- If CG, then go through each model and each exchange and check
960  ! for asymmetry
961  if (this%isymmetric == 1) then
962  !
963  ! -- Models
964  do i = 1, this%modellist%Count()
965  mp => getnumericalmodelfromlist(this%modellist, i)
966  if (mp%get_iasym() /= 0) then
967  write (errmsg, fmterrasym) 'MODEL', trim(adjustl(mp%name))
968  call store_error(errmsg)
969  end if
970  end do
971  !
972  ! -- Exchanges
973  do i = 1, this%exchangelist%Count()
974  cp => getnumericalexchangefromlist(this%exchangelist, i)
975  if (cp%get_iasym() /= 0) then
976  write (errmsg, fmterrasym) 'EXCHANGE', trim(adjustl(cp%name))
977  call store_error(errmsg)
978  end if
979  end do
980  !
981  end if
982 
983  !
984  ! determine if the x and rhs should be scaled
985  this%idv_scale = this%sln_get_idvscale()
986 
987  if (this%idv_scale > 0) then
988  write (iout, '(2(1x,a,/),1x,a,/,6x,a,/)') &
989  'X and RHS will be scaled to avoid very large positive or negative', &
990  'dependent variable values in the model IMS package.', &
991  'NOTE: Specified outer and inner DVCLOSE values in the model IMS &
992  &package', 'will be relative closure criteria.'
993  else if (this%idv_scale < 0) then
994  write (errmsg, '(2(a,1x))') &
995  'dependent_variable_scaling must be specified for all models in', &
996  'the solution and can only be used with GWT and GWE models. '
997  call store_error(errmsg)
998  end if
999  !
1000  !
1001  ! -- write solver data to output file
1002  !
1003  ! -- non-linear solver data
1004  WRITE (iout, 9002) this%dvclose, this%mxiter, &
1005  this%iprims, this%nonmeth, this%linsolver
1006  !
1007  ! -- standard outer iteration formats
1008 9002 FORMAT(1x, 'OUTER ITERATION CONVERGENCE CRITERION (DVCLOSE) = ', e15.6, &
1009  /1x, 'MAXIMUM NUMBER OF OUTER ITERATIONS (MXITER) = ', i0, &
1010  /1x, 'SOLVER PRINTOUT INDEX (IPRIMS) = ', i0, &
1011  /1x, 'NONLINEAR ITERATION METHOD (NONLINMETH) = ', i0, &
1012  /1x, 'LINEAR SOLUTION METHOD (LINMETH) = ', i0)
1013  !
1014  if (this%nonmeth == 1) then ! simple
1015  write (iout, 9003) this%gamma
1016  else if (this%nonmeth == 2) then ! cooley
1017  write (iout, 9004) this%gamma
1018  else if (this%nonmeth == 3) then ! delta bar delta
1019  write (iout, 9005) this%theta, this%akappa, this%gamma, this%amomentum
1020  end if
1021  !
1022  ! -- write backtracking information
1023  if (this%numtrack /= 0) write (iout, 9006) this%numtrack, this%btol, &
1024  this%breduc, this%res_lim
1025  !
1026  ! -- under-relaxation formats (simple, cooley, dbd)
1027 9003 FORMAT(1x, 'UNDER-RELAXATION FACTOR (GAMMA) = ', e15.6)
1028 9004 FORMAT(1x, 'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', e15.6)
1029 9005 FORMAT(1x, 'UNDER-RELAXATION WEIGHT REDUCTION FACTOR (THETA) = ', e15.6, &
1030  /1x, 'UNDER-RELAXATION WEIGHT INCREASE INCREMENT (KAPPA) = ', e15.6, &
1031  /1x, 'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', e15.6, &
1032  /1x, 'UNDER-RELAXATION MOMENTUM TERM (AMOMENTUM) = ', e15.6)
1033  !
1034  ! -- backtracking formats
1035 9006 FORMAT(1x, 'MAXIMUM NUMBER OF BACKTRACKS (NUMTRACK) = ', i0, &
1036  /1x, 'BACKTRACKING TOLERANCE FACTOR (BTOL) = ', e15.6, &
1037  /1x, 'BACKTRACKING REDUCTION FACTOR (BREDUC) = ', e15.6, &
1038  /1x, 'BACKTRACKING RESIDUAL LIMIT (RES_LIM) = ', e15.6)
1039  !
1040  ! -- linear solver data
1041  if (this%linsolver == ims_solver) then
1042  call this%imslinear%imslinear_summary(this%mxiter)
1043  else
1044  call this%linear_solver%print_summary()
1045  end if
1046 
1047  ! -- write summary of solver error messages
1048  ierr = count_errors()
1049  if (ierr > 0) then
1050  call this%parser%StoreErrorUnit()
1051  end if
1052  !
1053  ! reallocate space for nonlinear arrays and initialize
1054  call mem_reallocate(this%hncg, this%mxiter, 'HNCG', this%name)
1055  call mem_reallocate(this%lrch, 3, this%mxiter, 'LRCH', this%name)
1056 
1057  ! delta-bar-delta under-relaxation
1058  if (this%nonmeth == 3) then
1059  call mem_reallocate(this%wsave, this%neq, 'WSAVE', this%name)
1060  call mem_reallocate(this%hchold, this%neq, 'HCHOLD', this%name)
1061  call mem_reallocate(this%deold, this%neq, 'DEOLD', this%name)
1062  do i = 1, this%neq
1063  this%wsave(i) = dzero
1064  this%hchold(i) = dzero
1065  this%deold(i) = dzero
1066  end do
1067  end if
1068  this%hncg = dzero
1069  this%lrch = 0
1070 
1071  ! allocate space for saving solver convergence history
1072  if (this%iprims == 2 .or. this%icsvinnerout > 0) then
1073  this%nitermax = this%linear_settings%iter1 * this%mxiter
1074  else
1075  this%nitermax = 1
1076  end if
1077 
1078  allocate (this%caccel(this%nitermax))
1079 
1080  !
1081  ! -- resize convergence report
1082  call this%cnvg_summary%reinit(this%nitermax)
1083  !
1084  ! -- check for numerical solution errors
1085  ierr = count_errors()
1086  if (ierr > 0) then
1087  call this%parser%StoreErrorUnit()
1088  end if
1089  !
1090  ! -- close ims input file
1091  call this%parser%Clear()
1092  end subroutine sln_ar
1093 
1094  !> @ brief Calculate delt
1095  !!
1096  !! Calculate time step length.
1097  !!
1098  !<
1099  subroutine sln_dt(this)
1100  ! -- modules
1101  use tdismodule, only: kstp, kper, delt, ats
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%ats_submit_delt(kstp, kper, delt_temp, &
1132  this%memory_path, idir=idir)
1133  end if
1134  end subroutine sln_dt
1135 
1136  !> @ brief Advance solution
1137  !!
1138  !! Advance solution.
1139  !!
1140  !<
1141  subroutine sln_ad(this)
1142  ! -- modules
1143  use tdismodule, only: kstp, kper
1144  ! -- dummy variables
1145  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1146  !
1147  ! -- write headers to CSV file
1148  if (kper == 1 .and. kstp == 1) then
1149  call this%writeCSVHeader()
1150  end if
1151 
1152  ! write PTC info on models to iout
1153  call this%writePTCInfoToFile(kper)
1154 
1155  ! reset convergence flag and inner solve counter
1156  this%icnvg = 0
1157  this%itertot_timestep = 0
1158  this%iouttot_timestep = 0
1159  end subroutine sln_ad
1160 
1161  !> @ brief Output solution
1162  !!
1163  !! Output solution data. Currently does nothing.
1164  !!
1165  !<
1166  subroutine sln_ot(this)
1167  ! -- dummy variables
1168  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1169  !
1170  ! -- Nothing to do here
1171  end subroutine sln_ot
1172 
1173  !> @ brief Finalize solution
1174  !!
1175  !! Finalize a solution.
1176  !!
1177  !<
1178  subroutine sln_fp(this)
1179  use simvariablesmodule, only: iout
1180  ! -- dummy variables
1181  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1182  !
1183  ! -- write timer output
1184  if (idevelopmode == 1) then
1185  write (iout, '(//1x,a,1x,a,1x,a)') &
1186  'Solution', trim(adjustl(this%name)), 'summary'
1187  write (iout, "(1x,70('-'))")
1188  write (iout, '(1x,a,1x,g0,1x,a)') &
1189  'Total formulate time: ', this%ttform, 'seconds'
1190  write (iout, '(1x,a,1x,g0,1x,a,/)') &
1191  'Total solution time: ', this%ttsoln, 'seconds'
1192  end if
1193  end subroutine sln_fp
1194 
1195  !> @ brief Deallocate solution
1196  !!
1197  !! Deallocate a solution.
1198  !!
1199  !<
1200  subroutine sln_da(this)
1201  ! -- modules
1203  ! -- dummy variables
1204  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1205  !
1206  ! -- IMSLinearModule
1207  if (this%linsolver == ims_solver) then
1208  call this%imslinear%imslinear_da()
1209  deallocate (this%imslinear)
1210  end if
1211  !
1212  ! -- lists
1213  call this%modellist%Clear()
1214  call this%exchangelist%Clear()
1215  deallocate (this%modellist)
1216  deallocate (this%exchangelist)
1217 
1218  call this%system_matrix%destroy()
1219  deallocate (this%system_matrix)
1220  call this%vec_x%destroy()
1221  deallocate (this%vec_x)
1222  call this%vec_rhs%destroy()
1223  deallocate (this%vec_rhs)
1224 
1225  !
1226  ! -- character arrays
1227  deallocate (this%caccel)
1228  !
1229  ! -- inner iteration table object
1230  if (associated(this%innertab)) then
1231  call this%innertab%table_da()
1232  deallocate (this%innertab)
1233  nullify (this%innertab)
1234  end if
1235  !
1236  ! -- outer iteration table object
1237  if (associated(this%outertab)) then
1238  call this%outertab%table_da()
1239  deallocate (this%outertab)
1240  nullify (this%outertab)
1241  end if
1242  !
1243  ! -- arrays
1244  call mem_deallocate(this%active)
1245  call mem_deallocate(this%xtemp)
1246  call mem_deallocate(this%dxold)
1247  call mem_deallocate(this%hncg)
1248  call mem_deallocate(this%lrch)
1249  call mem_deallocate(this%wsave)
1250  call mem_deallocate(this%hchold)
1251  call mem_deallocate(this%deold)
1252  call mem_deallocate(this%convmodstart)
1253  !
1254  ! -- convergence report
1255  call this%cnvg_summary%destroy()
1256  deallocate (this%cnvg_summary)
1257  !
1258  ! -- linear solver
1259  call this%linear_solver%destroy()
1260  deallocate (this%linear_solver)
1261  !
1262  ! -- linear solver settings
1263  call this%linear_settings%destroy()
1264  deallocate (this%linear_settings)
1265  !
1266  ! -- Scalars
1267  call mem_deallocate(this%id)
1268  call mem_deallocate(this%iu)
1269  call mem_deallocate(this%ttform)
1270  call mem_deallocate(this%ttsoln)
1271  call mem_deallocate(this%isymmetric)
1272  call mem_deallocate(this%neq)
1273  call mem_deallocate(this%matrix_offset)
1274  call mem_deallocate(this%dvclose)
1275  call mem_deallocate(this%bigchold)
1276  call mem_deallocate(this%bigch)
1277  call mem_deallocate(this%relaxold)
1278  call mem_deallocate(this%res_prev)
1279  call mem_deallocate(this%res_new)
1280  call mem_deallocate(this%icnvg)
1281  call mem_deallocate(this%itertot_timestep)
1282  call mem_deallocate(this%iouttot_timestep)
1283  call mem_deallocate(this%itertot_sim)
1284  call mem_deallocate(this%mxiter)
1285  call mem_deallocate(this%linsolver)
1286  call mem_deallocate(this%nonmeth)
1287  call mem_deallocate(this%iprims)
1288  call mem_deallocate(this%theta)
1289  call mem_deallocate(this%akappa)
1290  call mem_deallocate(this%gamma)
1291  call mem_deallocate(this%amomentum)
1292  call mem_deallocate(this%breduc)
1293  call mem_deallocate(this%btol)
1294  call mem_deallocate(this%res_lim)
1295  call mem_deallocate(this%numtrack)
1296  call mem_deallocate(this%ibflag)
1297  call mem_deallocate(this%icsvouterout)
1298  call mem_deallocate(this%icsvinnerout)
1299  call mem_deallocate(this%nitermax)
1300  call mem_deallocate(this%convnmod)
1301  call mem_deallocate(this%iallowptc)
1302  call mem_deallocate(this%iptcopt)
1303  call mem_deallocate(this%iptcout)
1304  call mem_deallocate(this%l2norm0)
1305  call mem_deallocate(this%ptcdel)
1306  call mem_deallocate(this%ptcdel0)
1307  call mem_deallocate(this%ptcexp)
1308  call mem_deallocate(this%atsfrac)
1309  call mem_deallocate(this%idv_scale)
1310  call mem_deallocate(this%dscale)
1311  end subroutine sln_da
1312 
1313  !> @ brief Solve solution
1314  !!
1315  !! Solve the models in this solution for kper and kstp.
1316  !!
1317  !<
1318  subroutine sln_ca(this, isgcnvg, isuppress_output)
1319  ! -- dummy variables
1320  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1321  integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag
1322  integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output
1323  ! -- local variables
1324  class(numericalmodeltype), pointer :: mp => null()
1325  character(len=LINELENGTH) :: line
1326  character(len=LINELENGTH) :: fmt
1327  integer(I4B) :: im
1328  integer(I4B) :: kiter ! non-linear iteration counter
1329 
1330  ! advance the models, exchanges, and solution
1331  call this%prepareSolve()
1332 
1333  select case (isim_mode)
1334  case (mvalidate)
1335  line = 'mode="validation" -- Skipping matrix assembly and solution.'
1336  fmt = "(/,1x,a,/)"
1337  do im = 1, this%modellist%Count()
1338  mp => getnumericalmodelfromlist(this%modellist, im)
1339  call mp%model_message(line, fmt=fmt)
1340  end do
1341  case (mnormal)
1342  ! nonlinear iteration loop for this solution
1343  outerloop: do kiter = 1, this%mxiter
1344 
1345  ! perform a single iteration
1346  call this%solve(kiter, isuppress_output)
1347 
1348  ! exit if converged
1349  if (this%icnvg == 1) then
1350  exit outerloop
1351  end if
1352 
1353  end do outerloop
1354 
1355  ! finish up, write convergence info, CSV file, budgets and flows, ...
1356  call this%finalizeSolve(kiter, isgcnvg, isuppress_output)
1357  end select
1358  end subroutine sln_ca
1359 
1360  !> @ brief CSV header
1361  !!
1362  !! Write header for solver output to comma-separated value files.
1363  !!
1364  !<
1365  subroutine writecsvheader(this)
1366  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1367  ! local variables
1368  integer(I4B) :: im
1369  class(numericalmodeltype), pointer :: mp => null()
1370  !
1371  ! -- outer iteration csv header
1372  if (this%icsvouterout > 0) then
1373  write (this%icsvouterout, '(*(G0,:,","))') &
1374  'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', &
1375  'inner_iterations', 'solution_outer_dvmax', &
1376  'solution_outer_dvmax_model', 'solution_outer_dvmax_package', &
1377  'solution_outer_dvmax_node'
1378  end if
1379  !
1380  ! -- inner iteration csv header
1381  if (this%icsvinnerout > 0) then
1382  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1383  'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', &
1384  'ninner', 'solution_inner_dvmax', 'solution_inner_dvmax_model', &
1385  'solution_inner_dvmax_node'
1386  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1387  '', 'solution_inner_rmax', 'solution_inner_rmax_model', &
1388  'solution_inner_rmax_node'
1389  ! solver items specific to ims solver
1390  if (this%linsolver == ims_solver) then
1391  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1392  '', 'solution_inner_alpha'
1393  if (this%imslinear%ilinmeth == 2) then
1394  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1395  '', 'solution_inner_omega'
1396  end if
1397  end if
1398  ! -- check for more than one model - ims only
1399  if (this%convnmod > 1 .or. simulation_mode == "PARALLEL") then
1400  do im = 1, this%modellist%Count()
1401  mp => getnumericalmodelfromlist(this%modellist, im)
1402  write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') &
1403  '', trim(adjustl(mp%name))//'_inner_dvmax', &
1404  trim(adjustl(mp%name))//'_inner_dvmax_node', &
1405  trim(adjustl(mp%name))//'_inner_rmax', &
1406  trim(adjustl(mp%name))//'_inner_rmax_node'
1407  end do
1408  end if
1409  write (this%icsvinnerout, '(a)') ''
1410  end if
1411  end subroutine writecsvheader
1412 
1413  !> @ brief PTC header
1414  !!
1415  !! Write header for pseudo-transient continuation information to a file.
1416  !!
1417  !<
1418  subroutine writeptcinfotofile(this, kper)
1419  ! -- dummy variables
1420  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1421  integer(I4B), intent(in) :: kper !< current stress period number
1422  ! -- local variable
1423  integer(I4B) :: n, im, iallowptc, iptc
1424  class(numericalmodeltype), pointer :: mp => null()
1425 
1426  ! -- determine if PTC will be used in any model
1427  n = 1
1428  do im = 1, this%modellist%Count()
1429  !
1430  ! -- set iallowptc
1431  ! -- no_ptc_option is FIRST
1432  if (this%iallowptc < 0) then
1433  if (kper > 1) then
1434  iallowptc = 1
1435  else
1436  iallowptc = 0
1437  end if
1438  ! -- no_ptc_option is ALL (0) or using PTC (1)
1439  else
1440  iallowptc = this%iallowptc
1441  end if
1442 
1443  if (iallowptc > 0) then
1444  mp => getnumericalmodelfromlist(this%modellist, im)
1445  call mp%model_ptcchk(iptc)
1446  else
1447  iptc = 0
1448  end if
1449 
1450  if (iptc /= 0) then
1451  if (n == 1) then
1452  write (iout, '(//)')
1453  n = 0
1454  end if
1455  write (iout, '(1x,a,1x,i0,1x,3a)') &
1456  'PSEUDO-TRANSIENT CONTINUATION WILL BE APPLIED TO MODEL', im, '("', &
1457  trim(adjustl(mp%name)), '") DURING THIS TIME STEP'
1458  end if
1459  end do
1460 
1461  end subroutine writeptcinfotofile
1462 
1463  !> @ brief prepare to solve
1464  !!
1465  !! Prepare for the system solve by advancing the simulation.
1466  !!
1467  !<
1468  subroutine preparesolve(this)
1469  ! -- dummy variables
1470  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1471  ! -- local variables
1472  integer(I4B) :: ic
1473  integer(I4B) :: im
1474  class(numericalexchangetype), pointer :: cp => null()
1475  class(numericalmodeltype), pointer :: mp => null()
1476 
1477  ! start timer
1478  call g_prof%start("Prepare solve"//this%id_postfix, this%tmr_prep_solve)
1479 
1480  ! synchronize for AD
1481  call this%synchronize(stg_bfr_exg_ad, this%synchronize_ctx)
1482 
1483  ! -- Exchange advance
1484  do ic = 1, this%exchangelist%Count()
1485  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1486  call cp%exg_ad()
1487  end do
1488 
1489  ! -- Model advance
1490  do im = 1, this%modellist%Count()
1491  mp => getnumericalmodelfromlist(this%modellist, im)
1492  call mp%model_ad()
1493  end do
1494 
1495  ! advance solution
1496  call this%sln_ad()
1497 
1498  ! stop timer
1499  call g_prof%stop(this%tmr_prep_solve)
1500 
1501  end subroutine preparesolve
1502 
1503  !> @ brief Build and solve the simulation
1504  !!
1505  !! Builds and solve the system for this numerical solution.
1506  !! It roughly consists of the following steps
1507  !! (1) backtracking, (2) reset amat and rhs (3) calculate matrix
1508  !! terms (*_cf), (4) add coefficients to matrix (*_fc), (6) newton-raphson,
1509  !! (6) PTC, (7) linear solve, (8) convergence checks, (9) write output,
1510  !! and (10) underrelaxation
1511  !!
1512  !<
1513  subroutine solve(this, kiter, isuppress_output)
1514  ! -- modules
1515  use tdismodule, only: kstp, kper, totim
1516  ! -- dummy variables
1517  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1518  integer(I4B), intent(in) :: kiter !< Picard iteration number
1519  integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output
1520  ! -- local variables
1521  class(numericalmodeltype), pointer :: mp => null()
1522  class(numericalexchangetype), pointer :: cp => null()
1523  character(len=LINELENGTH) :: title
1524  character(len=LINELENGTH) :: tag
1525  character(len=LENPAKLOC) :: cmod
1526  character(len=LENPAKLOC) :: cpak
1527  character(len=LENPAKLOC) :: cpakout
1528  character(len=LENPAKLOC) :: strh
1529  character(len=25) :: cval
1530  character(len=7) :: cmsg
1531  integer(I4B) :: ic
1532  integer(I4B) :: im, m_idx, model_id
1533  integer(I4B) :: icsv0
1534  integer(I4B) :: kcsv0
1535  integer(I4B) :: ntabrows
1536  integer(I4B) :: ntabcols
1537  integer(I4B) :: i0, i1
1538  integer(I4B) :: itestmat, n
1539  integer(I4B) :: iter
1540  integer(I4B) :: inewtonur
1541  integer(I4B) :: locmax_nur
1542  integer(I4B) :: iend
1543  integer(I4B) :: icnvgmod
1544  integer(I4B) :: iptc
1545  integer(I4B) :: node_user
1546  integer(I4B) :: ipak
1547  integer(I4B) :: ipos0
1548  integer(I4B) :: ipos1
1549  real(DP) :: dxmax_nur
1550  real(DP) :: dxold_max
1551  real(DP) :: ptcf
1552  real(DP) :: ttform
1553  real(DP) :: ttsoln
1554  real(DP) :: dpak
1555  real(DP) :: outer_hncg
1556 
1557  ! start timer
1558  call g_prof%start("Solve"//this%id_postfix, this%tmr_solve)
1559 
1560  !
1561  ! -- initialize local variables
1562  icsv0 = max(1, this%itertot_sim + 1)
1563  kcsv0 = max(1, this%itertot_timestep + 1)
1564  !
1565  ! -- create header for outer iteration table
1566  if (this%iprims > 0) then
1567  if (.not. associated(this%outertab)) then
1568  !
1569  ! -- create outer iteration table
1570  ! -- table dimensions
1571  ntabrows = 1
1572  ntabcols = 6
1573  if (this%numtrack > 0) then
1574  ntabcols = ntabcols + 4
1575  end if
1576  !
1577  ! -- initialize table and define columns
1578  title = trim(this%memory_path)//' OUTER ITERATION SUMMARY'
1579  call table_cr(this%outertab, this%name, title)
1580  call this%outertab%table_df(ntabrows, ntabcols, iout, &
1581  finalize=.false.)
1582  tag = 'OUTER ITERATION STEP'
1583  call this%outertab%initialize_column(tag, 25, alignment=tableft)
1584  tag = 'OUTER ITERATION'
1585  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1586  tag = 'INNER ITERATION'
1587  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1588  if (this%numtrack > 0) then
1589  tag = 'BACKTRACK FLAG'
1590  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1591  tag = 'BACKTRACK ITERATIONS'
1592  call this%outertab%initialize_column(tag, 10, alignment=tabright)
1593  tag = 'INCOMING RESIDUAL'
1594  call this%outertab%initialize_column(tag, 15, alignment=tabright)
1595  tag = 'OUTGOING RESIDUAL'
1596  call this%outertab%initialize_column(tag, 15, alignment=tabright)
1597  end if
1598  tag = 'MAXIMUM CHANGE'
1599  call this%outertab%initialize_column(tag, 15, alignment=tabright)
1600  tag = 'STEP SUCCESS'
1601  call this%outertab%initialize_column(tag, 7, alignment=tabright)
1602  tag = 'MAXIMUM CHANGE MODEL-(CELLID) OR MODEL-PACKAGE-(NUMBER)'
1603  call this%outertab%initialize_column(tag, 34, alignment=tabright)
1604  end if
1605  end if
1606  !
1607  ! -- backtracking
1608  if (this%numtrack > 0) then
1609  call this%sln_backtracking(mp, cp, kiter)
1610  end if
1611  !
1612  call code_timer(0, ttform, this%ttform)
1613  call g_prof%start("Formulate", this%tmr_formulate)
1614  !
1615  ! -- (re)build the solution matrix
1616  call this%sln_buildsystem(kiter, inewton=1)
1617  !
1618  ! -- Calculate pseudo-transient continuation factor for each model
1619  call this%sln_calc_ptc(iptc, ptcf)
1620  !
1621  ! -- Add model Newton-Raphson terms to solution
1622  do im = 1, this%modellist%Count()
1623  mp => getnumericalmodelfromlist(this%modellist, im)
1624  call mp%model_nr(kiter, this%system_matrix, 1)
1625  end do
1626  call code_timer(1, ttform, this%ttform)
1627  call g_prof%stop(this%tmr_formulate)
1628 
1629  ! x and rhs scaling
1630  if (this%idv_scale /= 0) then
1631  call this%sln_maxval(this%neq, this%x, this%dscale)
1632  call ims_misc_dvscale(0, this%neq, this%dscale, this%x, this%rhs)
1633  end if
1634  !
1635  ! -- linear solve
1636  call code_timer(0, ttsoln, this%ttsoln)
1637  call g_prof%start("Linear solve", this%tmr_linsolve)
1638  call this%sln_ls(kiter, kstp, kper, iter, iptc, ptcf)
1639  call g_prof%stop(this%tmr_linsolve)
1640  call code_timer(1, ttsoln, this%ttsoln)
1641  !
1642  ! -- increment counters storing the total number of linear and
1643  ! non-linear iterations for this timestep and the total
1644  ! number of linear iterations for all timesteps
1645  this%itertot_timestep = this%itertot_timestep + iter
1646  this%iouttot_timestep = this%iouttot_timestep + 1
1647  this%itertot_sim = this%itertot_sim + iter
1648  !
1649  ! -- save matrix to a file
1650  ! to enable set itestmat to 1 and recompile
1651  !-------------------------------------------------------
1652  itestmat = 0
1653  if (itestmat /= 0) then
1654  open (99, file='sol_MF6.TXT')
1655  WRITE (99, *) 'MATRIX SOLUTION FOLLOWS'
1656  WRITE (99, '(10(I8,G15.4))') (n, this%x(n), n=1, this%NEQ)
1657  close (99)
1658  call pstop()
1659  end if
1660  !-------------------------------------------------------
1661  !
1662  ! -- check convergence of solution
1663  call this%sln_get_dxmax(this%hncg(kiter), this%lrch(1, kiter))
1664  if (this%icnvg /= 0) then
1665  this%icnvg = 0
1666  if (this%sln_has_converged(this%hncg(kiter))) then
1667  this%icnvg = 1
1668  end if
1669  end if
1670  !
1671  ! -- set failure flag
1672  if (this%icnvg == 0) then
1673  cmsg = ' '
1674  else
1675  cmsg = '*'
1676  end if
1677  !
1678  ! -- set flag if this is the last outer iteration
1679  iend = 0
1680  if (kiter == this%mxiter) then
1681  iend = 1
1682  end if
1683  !
1684  ! -- write maximum dependent-variable change from linear solver to list file
1685  if (this%iprims > 0) then
1686  cval = 'Model'
1687  call this%sln_get_loc(this%lrch(1, kiter), strh)
1688  !
1689  ! -- add data to outertab
1690  call this%outertab%add_term(cval)
1691  call this%outertab%add_term(kiter)
1692  call this%outertab%add_term(iter)
1693  if (this%numtrack > 0) then
1694  call this%outertab%add_term(' ')
1695  call this%outertab%add_term(' ')
1696  call this%outertab%add_term(' ')
1697  call this%outertab%add_term(' ')
1698  end if
1699  call this%outertab%add_term(this%hncg(kiter))
1700  call this%outertab%add_term(cmsg)
1701  call this%outertab%add_term(trim(strh))
1702  end if
1703  !
1704  ! -- Additional convergence check for exchanges
1705  do ic = 1, this%exchangelist%Count()
1706  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1707  call cp%exg_cc(this%icnvg)
1708  end do
1709  !
1710  ! -- additional convergence check for model packages
1711  icnvgmod = this%icnvg
1712  cpak = ' '
1713  ipak = 0
1714  dpak = dzero
1715  do im = 1, this%modellist%Count()
1716  mp => getnumericalmodelfromlist(this%modellist, im)
1717  call mp%get_mcellid(0, cmod)
1718  call mp%model_cc(this%itertot_sim, kiter, iend, icnvgmod, &
1719  cpak, ipak, dpak)
1720  if (ipak /= 0) then
1721  ipos0 = index(cpak, '-', back=.true.)
1722  ipos1 = len_trim(cpak)
1723  write (cpakout, '(a,a,"-(",i0,")",a)') &
1724  trim(cmod), cpak(1:ipos0 - 1), ipak, cpak(ipos0:ipos1)
1725  else
1726  cpakout = ' '
1727  end if
1728  end do
1729  !
1730  ! -- evaluate package convergence - only done if convergence is achieved
1731  if (this%icnvg == 1) then
1732  this%icnvg = this%sln_package_convergence(dpak, cpakout, iend)
1733  !
1734  ! -- write maximum change in package convergence check
1735  if (this%iprims > 0) then
1736  cval = 'Package'
1737  if (this%icnvg /= 1) then
1738  cmsg = ' '
1739  else
1740  cmsg = '*'
1741  end if
1742  if (len_trim(cpakout) > 0) then
1743  !
1744  ! -- add data to outertab
1745  call this%outertab%add_term(cval)
1746  call this%outertab%add_term(kiter)
1747  call this%outertab%add_term(' ')
1748  if (this%numtrack > 0) then
1749  call this%outertab%add_term(' ')
1750  call this%outertab%add_term(' ')
1751  call this%outertab%add_term(' ')
1752  call this%outertab%add_term(' ')
1753  end if
1754  call this%outertab%add_term(dpak)
1755  call this%outertab%add_term(cmsg)
1756  call this%outertab%add_term(cpakout)
1757  end if
1758  end if
1759  end if
1760  !
1761  ! -- under-relaxation - only done if convergence not achieved
1762  if (this%icnvg /= 1) then
1763  if (this%nonmeth > 0) then
1764  call this%sln_underrelax(kiter, this%hncg(kiter), this%neq, &
1765  this%active, this%x, this%xtemp)
1766  else
1767  call this%sln_calcdx(this%neq, this%active, &
1768  this%x, this%xtemp, this%dxold)
1769  end if
1770  !
1771  ! -- adjust heads by newton under-relaxation, if necessary
1772  inewtonur = 0
1773  dxmax_nur = dzero
1774  locmax_nur = 0
1775  do im = 1, this%modellist%Count()
1776  mp => getnumericalmodelfromlist(this%modellist, im)
1777  i0 = mp%moffset + 1 - this%matrix_offset
1778  i1 = i0 + mp%neq - 1
1779  call mp%model_nur(mp%neq, this%x(i0:i1), this%xtemp(i0:i1), &
1780  this%dxold(i0:i1), inewtonur, dxmax_nur, locmax_nur)
1781  end do
1782  !
1783  ! -- synchronize Newton Under-relaxation flag
1784  inewtonur = this%sln_sync_newtonur_flag(inewtonur)
1785  !
1786  ! -- check for convergence if newton under-relaxation applied
1787  if (inewtonur /= 0) then
1788  !
1789  ! -- calculate maximum change in heads in cells that have
1790  ! not been adjusted by newton under-relxation
1791  call this%sln_maxval(this%neq, this%dxold, dxold_max)
1792  !
1793  ! -- evaluate convergence
1794  if (this%sln_nur_has_converged(dxold_max, this%hncg(kiter))) then
1795  !
1796  ! -- converged
1797  this%icnvg = 1
1798  !
1799  ! -- reset outer dependent-variable change and location for output
1800  call this%sln_get_dxmax(this%hncg(kiter), this%lrch(1, kiter))
1801  !
1802  ! -- write revised dependent-variable change data after
1803  ! newton under-relaxation
1804  if (this%iprims > 0) then
1805  cval = 'Newton under-relaxation'
1806  cmsg = '*'
1807  call this%sln_get_loc(this%lrch(1, kiter), strh)
1808  !
1809  ! -- add data to outertab
1810  call this%outertab%add_term(cval)
1811  call this%outertab%add_term(kiter)
1812  call this%outertab%add_term(iter)
1813  if (this%numtrack > 0) then
1814  call this%outertab%add_term(' ')
1815  call this%outertab%add_term(' ')
1816  call this%outertab%add_term(' ')
1817  call this%outertab%add_term(' ')
1818  end if
1819  call this%outertab%add_term(this%hncg(kiter))
1820  call this%outertab%add_term(cmsg)
1821  call this%outertab%add_term(trim(strh))
1822  end if
1823  end if
1824  end if
1825  end if
1826  !
1827  ! -- write to outer iteration csv file
1828  if (this%icsvouterout > 0) then
1829  !
1830  ! -- set outer dependent-variable change variable
1831  outer_hncg = this%hncg(kiter)
1832  !
1833  ! -- model convergence error
1834  if (abs(outer_hncg) > abs(dpak)) then
1835  !
1836  ! -- get model number and user node number
1837  call this%sln_get_nodeu(this%lrch(1, kiter), m_idx, node_user)
1838  mp => getnumericalmodelfromlist(this%modellist, m_idx)
1839  model_id = mp%id
1840  cpakout = ''
1841  else if (outer_hncg == dzero .and. dpak == dzero) then ! zero change, location could be any
1842  model_id = 0
1843  node_user = 0
1844  !
1845  ! -- then it's a package convergence error
1846  else
1847  !
1848  ! -- set convergence error, model number, user node number,
1849  ! and package name
1850  outer_hncg = dpak
1851  ipos0 = index(cmod, '_')
1852  read (cmod(1:ipos0 - 1), *) model_id
1853  node_user = ipak
1854  ipos0 = index(cpak, '-', back=.true.)
1855  cpakout = cpak(1:ipos0 - 1)
1856  end if
1857 
1858  write (this%icsvouterout, '(*(G0,:,","))') &
1859  this%itertot_sim, totim, kper, kstp, kiter, iter, &
1860  outer_hncg, model_id, trim(cpakout), node_user
1861  end if
1862  !
1863  ! -- write to inner iteration csv file
1864  if (this%icsvinnerout > 0) then
1865  call this%csv_convergence_summary(this%icsvinnerout, totim, kper, kstp, &
1866  kiter, iter, icsv0, kcsv0)
1867  end if
1868 
1869  ! undo x and rhs scaling
1870  if (this%idv_scale /= 0) then
1871  call ims_misc_dvscale(1, this%neq, this%dscale, this%x, this%rhs)
1872  end if
1873 
1874  ! stop timer
1875  call g_prof%stop(this%tmr_solve)
1876 
1877  end subroutine solve
1878 
1879  !> @ brief finalize a solution
1880  !!
1881  !! Finalize the solution. Called after the outer iteration loop.
1882  !!
1883  !<
1884  subroutine finalizesolve(this, kiter, isgcnvg, isuppress_output)
1885  ! -- modules
1886  use tdismodule, only: kper, kstp
1887  ! -- dummy variables
1888  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
1889  integer(I4B), intent(in) :: kiter !< Picard iteration number after convergence or failure
1890  integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag
1891  integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output
1892  ! -- local variables
1893  integer(I4B) :: ic, im
1894  class(numericalmodeltype), pointer :: mp => null()
1895  class(numericalexchangetype), pointer :: cp => null()
1896  ! -- formats for convergence info
1897  character(len=*), parameter :: fmtnocnvg = &
1898  "(1X,'Solution ', i0, ' did not converge for stress period ', i0, &
1899  &' and time step ', i0)"
1900  character(len=*), parameter :: fmtcnvg = &
1901  "(1X, I0, ' CALLS TO NUMERICAL SOLUTION ', 'IN TIME STEP ', I0, &
1902  &' STRESS PERIOD ',I0,/1X,I0,' TOTAL ITERATIONS')"
1903 
1904  ! start timer
1905  call g_prof%start("Finalize solve"//this%id_postfix, this%tmr_final_solve)
1906 
1907  !
1908  ! -- finalize the outer iteration table
1909  if (this%iprims > 0) then
1910  call this%outertab%finalize_table()
1911  end if
1912  !
1913  ! -- write convergence info
1914  !
1915  ! -- convergence was achieved
1916  if (this%icnvg /= 0) then
1917  if (this%iprims > 0) then
1918  write (iout, fmtcnvg) kiter, kstp, kper, this%itertot_timestep
1919  end if
1920  !
1921  ! -- convergence was not achieved
1922  else
1923  write (iout, fmtnocnvg) this%id, kper, kstp
1924  end if
1925  !
1926  ! -- write inner iteration convergence summary
1927  if (this%iprims == 2) then
1928  !
1929  ! -- write summary for each model
1930  do im = 1, this%modellist%Count()
1931  mp => getnumericalmodelfromlist(this%modellist, im)
1932  call this%convergence_summary(mp%iout, im, this%itertot_timestep)
1933  end do
1934  !
1935  ! -- write summary for entire solution
1936  call this%convergence_summary(iout, this%convnmod + 1, &
1937  this%itertot_timestep)
1938  end if
1939  !
1940  ! -- set solution group convergence flag
1941  if (this%icnvg == 0) isgcnvg = 0
1942 
1943  call g_prof%start("Calculate flows", this%tmr_flows)
1944 
1945  !
1946  ! -- Calculate flow for each model
1947  do im = 1, this%modellist%Count()
1948  mp => getnumericalmodelfromlist(this%modellist, im)
1949  call mp%model_cq(this%icnvg, isuppress_output)
1950  end do
1951  !
1952  ! -- Calculate flow for each exchange
1953  do ic = 1, this%exchangelist%Count()
1954  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1955  call cp%exg_cq(isgcnvg, isuppress_output, this%id)
1956  end do
1957 
1958  call g_prof%stop(this%tmr_flows)
1959  call g_prof%start("Calculate budgets", this%tmr_budgets)
1960 
1961  !
1962  ! -- Budget terms for each model
1963  do im = 1, this%modellist%Count()
1964  mp => getnumericalmodelfromlist(this%modellist, im)
1965  call mp%model_bd(this%icnvg, isuppress_output)
1966  end do
1967  !
1968  ! -- Budget terms for each exchange
1969  do ic = 1, this%exchangelist%Count()
1970  cp => getnumericalexchangefromlist(this%exchangelist, ic)
1971  call cp%exg_bd(isgcnvg, isuppress_output, this%id)
1972  end do
1973 
1974  ! stop timer
1975  call g_prof%stop(this%tmr_budgets)
1976  call g_prof%stop(this%tmr_final_solve)
1977 
1978  end subroutine finalizesolve
1979 
1980  ! helper routine to calculate coefficients and setup the solution matrix
1981  subroutine sln_buildsystem(this, kiter, inewton)
1982  class(numericalsolutiontype) :: this
1983  integer(I4B), intent(in) :: kiter
1984  integer(I4B), intent(in) :: inewton
1985  ! local
1986  integer(I4B) :: im, ic
1987  class(numericalmodeltype), pointer :: mp
1988  class(numericalexchangetype), pointer :: cp
1989  !
1990  ! -- Set amat and rhs to zero
1991  call this%sln_reset()
1992 
1993  ! reset models
1994  do im = 1, this%modellist%Count()
1995  mp => getnumericalmodelfromlist(this%modellist, im)
1996  call mp%model_reset()
1997  end do
1998 
1999  ! synchronize for CF
2000  call this%synchronize(stg_bfr_exg_cf, this%synchronize_ctx)
2001 
2002  !
2003  ! -- Calculate the matrix terms for each exchange
2004  do ic = 1, this%exchangelist%Count()
2005  cp => getnumericalexchangefromlist(this%exchangelist, ic)
2006  call cp%exg_cf(kiter)
2007  end do
2008  !
2009  ! -- Calculate the matrix terms for each model
2010  do im = 1, this%modellist%Count()
2011  mp => getnumericalmodelfromlist(this%modellist, im)
2012  call mp%model_cf(kiter)
2013  end do
2014 
2015  ! synchronize for FC
2016  call this%synchronize(stg_bfr_exg_fc, this%synchronize_ctx)
2017 
2018  !
2019  ! -- Add exchange coefficients to the solution
2020  do ic = 1, this%exchangelist%Count()
2021  cp => getnumericalexchangefromlist(this%exchangelist, ic)
2022  call cp%exg_fc(kiter, this%system_matrix, this%rhs, inewton)
2023  end do
2024  !
2025  ! -- Add model coefficients to the solution
2026  do im = 1, this%modellist%Count()
2027  mp => getnumericalmodelfromlist(this%modellist, im)
2028  call mp%model_fc(kiter, this%system_matrix, inewton)
2029  end do
2030 
2031  end subroutine sln_buildsystem
2032 
2033  !> @ brief Solution convergence summary
2034  !!
2035  !! Save convergence summary to a File.
2036  !!
2037  !<
2038  subroutine convergence_summary(this, iu, im, itertot_timestep)
2039  ! -- modules
2040  use inputoutputmodule, only: getunit
2041  ! -- dummy variables
2042  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2043  integer(I4B), intent(in) :: iu !< file unit number for summary file
2044  integer(I4B), intent(in) :: im !< model number
2045  integer(I4B), intent(in) :: itertot_timestep !< total iteration for the time step
2046  ! -- local variables
2047  character(len=LINELENGTH) :: title
2048  character(len=LINELENGTH) :: tag
2049  character(len=LENPAKLOC) :: loc_dvmax_str
2050  character(len=LENPAKLOC) :: loc_rmax_str
2051  integer(I4B) :: ntabrows
2052  integer(I4B) :: ntabcols
2053  integer(I4B) :: iinner
2054  integer(I4B) :: i0
2055  integer(I4B) :: iouter
2056  integer(I4B) :: j
2057  integer(I4B) :: k
2058  integer(I4B) :: locdv
2059  integer(I4B) :: locdr
2060  real(DP) :: dv !< the maximum change in the dependent variable
2061  real(DP) :: res !< the maximum value of the residual vector
2062  !
2063  ! -- initialize local variables
2064  loc_dvmax_str = ''
2065  loc_rmax_str = ''
2066  iouter = 1
2067  locdv = 0
2068  locdr = 0
2069  !
2070  ! -- initialize inner iteration summary table
2071  if (.not. associated(this%innertab)) then
2072  !
2073  ! -- create outer iteration table
2074  ! -- table dimensions
2075  ntabrows = itertot_timestep
2076  ntabcols = 7
2077  !
2078  ! -- initialize table and define columns
2079  title = trim(this%memory_path)//' INNER ITERATION SUMMARY'
2080  call table_cr(this%innertab, this%name, title)
2081  call this%innertab%table_df(ntabrows, ntabcols, iu)
2082  tag = 'TOTAL ITERATION'
2083  call this%innertab%initialize_column(tag, 10, alignment=tabright)
2084  tag = 'OUTER ITERATION'
2085  call this%innertab%initialize_column(tag, 10, alignment=tabright)
2086  tag = 'INNER ITERATION'
2087  call this%innertab%initialize_column(tag, 10, alignment=tabright)
2088  tag = 'MAXIMUM CHANGE'
2089  call this%innertab%initialize_column(tag, 15, alignment=tabright)
2090  tag = 'MAXIMUM CHANGE MODEL-(CELLID)'
2091  call this%innertab%initialize_column(tag, lenpakloc, alignment=tabright)
2092  tag = 'MAXIMUM RESIDUAL'
2093  call this%innertab%initialize_column(tag, 15, alignment=tabright)
2094  tag = 'MAXIMUM RESIDUAL MODEL-(CELLID)'
2095  call this%innertab%initialize_column(tag, lenpakloc, alignment=tabright)
2096  !
2097  ! -- reset the output unit and the number of rows (maxbound)
2098  else
2099  call this%innertab%set_maxbound(itertot_timestep)
2100  call this%innertab%set_iout(iu)
2101  end if
2102  !
2103  ! -- write the inner iteration summary to unit iu
2104  i0 = 0
2105  do k = 1, itertot_timestep
2106  iinner = this%cnvg_summary%itinner(k)
2107  if (iinner <= i0) then
2108  iouter = iouter + 1
2109  end if
2110  if (im > this%convnmod) then
2111  dv = dzero
2112  res = dzero
2113  do j = 1, this%convnmod
2114  if (abs(this%cnvg_summary%convdvmax(j, k)) > abs(dv)) then
2115  locdv = this%cnvg_summary%convlocdv(j, k)
2116  dv = this%cnvg_summary%convdvmax(j, k)
2117  end if
2118  if (abs(this%cnvg_summary%convrmax(j, k)) > abs(res)) then
2119  locdr = this%cnvg_summary%convlocr(j, k)
2120  res = this%cnvg_summary%convrmax(j, k)
2121  end if
2122  end do
2123  else
2124  locdv = this%cnvg_summary%convlocdv(im, k)
2125  locdr = this%cnvg_summary%convlocr(im, k)
2126  dv = this%cnvg_summary%convdvmax(im, k)
2127  res = this%cnvg_summary%convrmax(im, k)
2128  end if
2129  call this%sln_get_loc(locdv, loc_dvmax_str)
2130  call this%sln_get_loc(locdr, loc_rmax_str)
2131  !
2132  ! -- add data to innertab
2133  call this%innertab%add_term(k)
2134  call this%innertab%add_term(iouter)
2135  call this%innertab%add_term(iinner)
2136  call this%innertab%add_term(dv)
2137  call this%innertab%add_term(adjustr(trim(loc_dvmax_str)))
2138  call this%innertab%add_term(res)
2139  call this%innertab%add_term(adjustr(trim(loc_rmax_str)))
2140  !
2141  ! -- update i0
2142  i0 = iinner
2143  end do
2144  end subroutine convergence_summary
2145 
2146  !> @ brief Solution convergence CSV summary
2147  !!
2148  !! Save convergence summary to a comma-separated value file.
2149  !!
2150  !<
2151  subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, &
2152  niter, istart, kstart)
2153  ! -- modules
2154  use inputoutputmodule, only: getunit
2155  ! -- dummy variables
2156  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2157  integer(I4B), intent(in) :: iu !< file unit number
2158  real(DP), intent(in) :: totim !< total simulation time
2159  integer(I4B), intent(in) :: kper !< stress period number
2160  integer(I4B), intent(in) :: kstp !< time step number
2161  integer(I4B), intent(in) :: kouter !< number of outer (Picard) iterations
2162  integer(I4B), intent(in) :: niter !< number of inner iteration in this time step
2163  integer(I4B), intent(in) :: istart !< starting iteration number for this time step
2164  integer(I4B), intent(in) :: kstart !< starting position in the conv* arrays
2165  ! -- local
2166  integer(I4B) :: itot
2167  integer(I4B) :: m_idx, j, k
2168  integer(I4B) :: kpos
2169  integer(I4B) :: loc_dvmax !< solution node number (row) of max. dep. var. change
2170  integer(I4B) :: loc_rmax !< solution node number (row) of max. residual
2171  integer(I4B) :: model_id, node_user
2172  real(DP) :: dvmax !< maximum dependent variable change
2173  real(DP) :: rmax !< maximum residual
2174  class(numericalmodeltype), pointer :: num_mod => null()
2175  !
2176  ! -- initialize local variables
2177  itot = istart
2178  !
2179  ! -- write inner iteration results to the inner csv output file
2180  do k = 1, niter
2181  kpos = kstart + k - 1
2182  write (iu, '(*(G0,:,","))', advance='NO') &
2183  itot, totim, kper, kstp, kouter, k
2184  !
2185  ! -- solution summary
2186  dvmax = dzero
2187  rmax = dzero
2188  do j = 1, this%convnmod
2189  if (abs(this%cnvg_summary%convdvmax(j, kpos)) > abs(dvmax)) then
2190  loc_dvmax = this%cnvg_summary%convlocdv(j, kpos)
2191  dvmax = this%cnvg_summary%convdvmax(j, kpos)
2192  end if
2193  if (abs(this%cnvg_summary%convrmax(j, kpos)) > abs(rmax)) then
2194  loc_rmax = this%cnvg_summary%convlocr(j, kpos)
2195  rmax = this%cnvg_summary%convrmax(j, kpos)
2196  end if
2197  end do
2198  !
2199  ! -- no change, could be anywhere
2200  if (dvmax == dzero) loc_dvmax = 0
2201  if (rmax == dzero) loc_rmax = 0
2202  !
2203  ! -- get model number and user node number for max. dep. var. change
2204  if (loc_dvmax > 0) then
2205  call this%sln_get_nodeu(loc_dvmax, m_idx, node_user)
2206  num_mod => getnumericalmodelfromlist(this%modellist, m_idx)
2207  model_id = num_mod%id
2208  else
2209  model_id = 0
2210  node_user = 0
2211  end if
2212  write (iu, '(*(G0,:,","))', advance='NO') '', dvmax, model_id, node_user
2213  !
2214  ! -- get model number and user node number for max. residual
2215  if (loc_rmax > 0) then
2216  call this%sln_get_nodeu(loc_rmax, m_idx, node_user)
2217  num_mod => getnumericalmodelfromlist(this%modellist, m_idx)
2218  model_id = num_mod%id
2219  else
2220  model_id = 0
2221  node_user = 0
2222  end if
2223  write (iu, '(*(G0,:,","))', advance='NO') '', rmax, model_id, node_user
2224  !
2225  ! -- write ims acceleration parameters
2226  if (this%linsolver == ims_solver) then
2227  write (iu, '(*(G0,:,","))', advance='NO') &
2228  '', trim(adjustl(this%caccel(kpos)))
2229  end if
2230  !
2231  ! -- write information for each model
2232  if (this%convnmod > 1 .or. simulation_mode == "PARALLEL") then
2233  do j = 1, this%cnvg_summary%convnmod
2234  loc_dvmax = this%cnvg_summary%convlocdv(j, kpos)
2235  dvmax = this%cnvg_summary%convdvmax(j, kpos)
2236  loc_rmax = this%cnvg_summary%convlocr(j, kpos)
2237  rmax = this%cnvg_summary%convrmax(j, kpos)
2238  !
2239  ! -- get model number and user node number for max. dep. var. change
2240  if (loc_dvmax > 0) then
2241  call this%sln_get_nodeu(loc_dvmax, m_idx, node_user)
2242  else
2243  node_user = 0
2244  end if
2245  write (iu, '(*(G0,:,","))', advance='NO') '', dvmax, node_user
2246  !
2247  ! -- get model number and user node number for max. residual
2248  if (loc_rmax > 0) then
2249  call this%sln_get_nodeu(loc_rmax, m_idx, node_user)
2250  else
2251  node_user = 0
2252  end if
2253  write (iu, '(*(G0,:,","))', advance='NO') '', rmax, node_user
2254  end do
2255  end if
2256  !
2257  ! -- write line
2258  write (iu, '(a)') ''
2259  !
2260  ! -- update itot
2261  itot = itot + 1
2262  end do
2263  !
2264  ! -- flush file
2265  flush (iu)
2266  end subroutine csv_convergence_summary
2267 
2268  !> @ brief Save solution data to a file
2269  !!
2270  !! Save solution ia vector, ja vector , coefficient matrix, right-hand side
2271  !! vector, and the dependent-variable vector to a file.
2272  !!
2273  !<
2274  subroutine save(this, filename)
2275  use sparsematrixmodule
2276  ! -- modules
2277  use inputoutputmodule, only: getunit
2278  ! -- dummy variables
2279  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2280  character(len=*), intent(in) :: filename !< filename to save solution data
2281  ! -- local variables
2282  integer(I4B) :: inunit
2283  !
2284  select type (spm => this%system_matrix)
2285  class is (sparsematrixtype)
2286  inunit = getunit()
2287  open (unit=inunit, file=filename, status='unknown')
2288  write (inunit, *) 'ia'
2289  write (inunit, *) spm%ia
2290  write (inunit, *) 'ja'
2291  write (inunit, *) spm%ja
2292  write (inunit, *) 'amat'
2293  write (inunit, *) spm%amat
2294  write (inunit, *) 'rhs'
2295  write (inunit, *) this%rhs
2296  write (inunit, *) 'x'
2297  write (inunit, *) this%x
2298  close (inunit)
2299  end select
2300  end subroutine save
2301 
2302  !> @ brief Add a model
2303  !!
2304  !! Add a model to solution.
2305  !!
2306  !<
2307  subroutine add_model(this, mp)
2308  ! -- dummy variables
2309  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2310  class(basemodeltype), pointer, intent(in) :: mp !< model instance
2311  ! -- local variables
2312  class(numericalmodeltype), pointer :: m => null()
2313  !
2314  ! -- add a model
2315  select type (mp)
2316  class is (numericalmodeltype)
2317  m => mp
2318  call addnumericalmodeltolist(this%modellist, m)
2319  end select
2320  end subroutine add_model
2321 
2322  !> @brief Get a list of models
2323  !!
2324  !! Returns a pointer to the list of models in this solution.
2325  !!
2326  !<
2327  function get_models(this) result(models)
2328  ! -- return variable
2329  type(listtype), pointer :: models !< pointer to the model list
2330  ! -- dummy variables
2331  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2332 
2333  models => this%modellist
2334 
2335  end function get_models
2336 
2337  !> @brief Add exchange
2338  !!
2339  !! Add and exchange to this%exchangelist.
2340  !!
2341  !<
2342  subroutine add_exchange(this, exchange)
2343  ! -- dummy variables
2344  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2345  class(baseexchangetype), pointer, intent(in) :: exchange !< model exchange instance
2346  ! -- local variables
2347  class(numericalexchangetype), pointer :: num_ex => null()
2348  !
2349  ! -- add exchange
2350  select type (exchange)
2351  class is (numericalexchangetype)
2352  num_ex => exchange
2353  call addnumericalexchangetolist(this%exchangelist, num_ex)
2354  end select
2355  end subroutine add_exchange
2356 
2357  !> @brief Returns a pointer to the list of exchanges in this solution
2358  !<
2359  function get_exchanges(this) result(exchanges)
2360  class(numericalsolutiontype) :: this !< instance of the numerical solution
2361  type(listtype), pointer :: exchanges !< pointer to the exchange list
2362 
2363  exchanges => this%exchangelist
2364 
2365  end function get_exchanges
2366 
2367  !> @ brief Assign solution connections
2368  !!
2369  !! Assign solution connections. This is the main workhorse method for a
2370  !! solution. The method goes through all the models and all the connections
2371  !! and builds up the sparse matrix. Steps are (1) add internal model
2372  !! connections, (2) add cross terms, (3) allocate solution arrays, (4) create
2373  !! mapping arrays, and (5) fill cross term values if necessary.
2374  !!
2375  !<
2376  subroutine sln_connect(this)
2377  ! -- modules
2379  ! -- dummy variables
2380  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2381  ! -- local variables
2382  class(numericalmodeltype), pointer :: mp => null()
2383  class(numericalexchangetype), pointer :: cp => null()
2384  integer(I4B) :: im
2385  integer(I4B) :: ic
2386  !
2387  ! -- Add internal model connections to sparse
2388  do im = 1, this%modellist%Count()
2389  mp => getnumericalmodelfromlist(this%modellist, im)
2390  call mp%model_ac(this%sparse)
2391  end do
2392  !
2393  ! -- synchronize before AC
2394  call this%synchronize(stg_bfr_exg_ac, this%synchronize_ctx)
2395  !
2396  ! -- Add the cross terms to sparse
2397  do ic = 1, this%exchangelist%Count()
2398  cp => getnumericalexchangefromlist(this%exchangelist, ic)
2399  call cp%exg_ac(this%sparse)
2400  end do
2401  !
2402  ! -- The number of non-zero array values are now known so
2403  ! -- ia and ja can be created from sparse. then destroy sparse
2404  call this%sparse%sort()
2405  call this%system_matrix%init(this%sparse, this%name)
2406  call this%sparse%destroy()
2407  !
2408  ! -- Create mapping arrays for each model. Mapping assumes
2409  ! -- that each row has the diagonal in the first position,
2410  ! -- however, rows do not need to be sorted.
2411  do im = 1, this%modellist%Count()
2412  mp => getnumericalmodelfromlist(this%modellist, im)
2413  call mp%model_mc(this%system_matrix)
2414  end do
2415  !
2416  ! -- Create arrays for mapping exchange connections to global solution
2417  do ic = 1, this%exchangelist%Count()
2418  cp => getnumericalexchangefromlist(this%exchangelist, ic)
2419  call cp%exg_mc(this%system_matrix)
2420  end do
2421  end subroutine sln_connect
2422 
2423  !> @ brief Reset the solution
2424  !!
2425  !! Reset the solution by setting the coefficient matrix and right-hand side
2426  !! vectors to zero.
2427  !!
2428  !<
2429  subroutine sln_reset(this)
2430  ! -- dummy variables
2431  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2432  !
2433  ! -- reset the solution
2434  call this%system_matrix%zero_entries()
2435  call this%vec_rhs%zero_entries()
2436  end subroutine sln_reset
2437 
2438  !> @ brief Solve the linear system of equations
2439  !!
2440  !! Solve the linear system of equations. Steps include (1) matrix cleanup,
2441  !! (2) add pseudo-transient continuation terms, and (3) residual reduction.
2442  !!
2443  !<
2444  subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf)
2445  ! -- dummy variables
2446  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2447  integer(I4B), intent(in) :: kiter
2448  integer(I4B), intent(in) :: kstp
2449  integer(I4B), intent(in) :: kper
2450  integer(I4B), intent(inout) :: in_iter
2451  integer(I4B), intent(inout) :: iptc
2452  real(DP), intent(in) :: ptcf
2453  ! -- local variables
2454  logical(LGP) :: lsame
2455  integer(I4B) :: ieq
2456  integer(I4B) :: irow_glo
2457  integer(I4B) :: itestmat
2458  integer(I4B) :: ipos
2459  integer(I4B) :: icol_s
2460  integer(I4B) :: icol_e
2461  integer(I4B) :: jcol
2462  integer(I4B) :: iptct
2463  integer(I4B) :: iallowptc
2464  real(DP) :: adiag
2465  real(DP) :: diagval
2466  real(DP) :: l2norm
2467  real(DP) :: ptcval
2468  real(DP) :: bnorm
2469  character(len=50) :: fname
2470  character(len=*), parameter :: fmtfname = "('mf6mat_', i0, '_', i0, &
2471  &'_', i0, '_', i0, '.txt')"
2472  !
2473  ! -- take care of loose ends for all nodes before call to solver
2474  do ieq = 1, this%neq
2475  !
2476  ! -- get (global) cell id
2477  irow_glo = ieq + this%matrix_offset
2478  !
2479  ! -- store x in temporary location
2480  this%xtemp(ieq) = this%x(ieq)
2481  !
2482  ! -- make adjustments to the continuity equation for the node
2483  ! -- adjust small diagonal coefficient in an active cell
2484  if (this%active(ieq) > 0) then
2485  diagval = -done
2486  adiag = abs(this%system_matrix%get_diag_value(irow_glo))
2487  if (adiag < dem15) then
2488  call this%system_matrix%set_diag_value(irow_glo, diagval)
2489  this%rhs(ieq) = this%rhs(ieq) + diagval * this%x(ieq)
2490  end if
2491  ! -- Dirichlet boundary or no-flow cell
2492  else
2493  call this%system_matrix%set_diag_value(irow_glo, done)
2494  call this%system_matrix%zero_row_offdiag(irow_glo)
2495  this%rhs(ieq) = this%x(ieq)
2496  end if
2497  end do
2498  !
2499  ! -- complete adjustments for Dirichlet boundaries for a symmetric matrix
2500  if (this%isymmetric == 1 .and. simulation_mode == "SEQUENTIAL") then
2501  do ieq = 1, this%neq
2502  if (this%active(ieq) > 0) then
2503  icol_s = this%system_matrix%get_first_col_pos(ieq)
2504  icol_e = this%system_matrix%get_last_col_pos(ieq)
2505  do ipos = icol_s, icol_e
2506  jcol = this%system_matrix%get_column(ipos)
2507  if (jcol == ieq) cycle
2508  if (this%active(jcol) < 0) then
2509  this%rhs(ieq) = this%rhs(ieq) - &
2510  (this%system_matrix%get_value_pos(ipos) * &
2511  this%x(jcol))
2512  call this%system_matrix%set_value_pos(ipos, dzero)
2513  end if
2514 
2515  end do
2516  end if
2517  end do
2518  end if
2519  !
2520  ! -- pseudo transient continuation
2521  !
2522  ! -- set iallowptc
2523  ! -- no_ptc_option is FIRST
2524  if (this%iallowptc < 0) then
2525  if (kper > 1) then
2526  iallowptc = 1
2527  else
2528  iallowptc = 0
2529  end if
2530  !
2531  ! -- no_ptc_option is ALL (0) or using PTC (1)
2532  else
2533  iallowptc = this%iallowptc
2534  end if
2535  !
2536  ! -- set iptct
2537  iptct = iptc * iallowptc
2538  !
2539  ! -- calculate or modify pseudo transient continuation terms and add
2540  ! to amat diagonals
2541  if (iptct /= 0) then
2542  call this%sln_l2norm(l2norm)
2543  ! -- confirm that the l2norm exceeds previous l2norm
2544  ! if not, there is no need to add ptc terms
2545  if (kiter == 1) then
2546  if (kper > 1 .or. kstp > 1) then
2547  if (l2norm <= this%l2norm0) then
2548  iptc = 0
2549  end if
2550  end if
2551  else
2552  lsame = is_close(l2norm, this%l2norm0)
2553  if (lsame) then
2554  iptc = 0
2555  end if
2556  end if
2557  end if
2558  iptct = iptc * iallowptc
2559  if (iptct /= 0) then
2560  if (kiter == 1) then
2561  if (this%iptcout > 0) then
2562  write (this%iptcout, '(A10,6(1x,A15))') 'OUTER ITER', &
2563  ' PTCDEL', ' L2NORM0', ' L2NORM', &
2564  ' RHSNORM', ' 1/PTCDEL', ' RHSNORM/L2NORM'
2565  end if
2566  if (this%ptcdel0 > dzero) then
2567  this%ptcdel = this%ptcdel0
2568  else
2569  if (this%iptcopt == 0) then
2570  !
2571  ! -- ptcf is the reciprocal of the pseudo-time step
2572  this%ptcdel = done / ptcf
2573  else
2574  bnorm = dzero
2575  do ieq = 1, this%neq
2576  if (this%active(ieq) .gt. 0) then
2577  bnorm = bnorm + this%rhs(ieq) * this%rhs(ieq)
2578  end if
2579  end do
2580  bnorm = sqrt(bnorm)
2581  this%ptcdel = bnorm / l2norm
2582  end if
2583  end if
2584  else
2585  if (l2norm > dzero) then
2586  this%ptcdel = this%ptcdel * (this%l2norm0 / l2norm)**this%ptcexp
2587  else
2588  this%ptcdel = dzero
2589  end if
2590  end if
2591  if (this%ptcdel > dzero) then
2592  ptcval = done / this%ptcdel
2593  else
2594  ptcval = done
2595  end if
2596  bnorm = dzero
2597  do ieq = 1, this%neq
2598  irow_glo = ieq + this%matrix_offset
2599  if (this%active(ieq) > 0) then
2600  diagval = abs(this%system_matrix%get_diag_value(irow_glo))
2601  bnorm = bnorm + this%rhs(ieq) * this%rhs(ieq)
2602  call this%system_matrix%add_diag_value(irow_glo, -ptcval)
2603  this%rhs(ieq) = this%rhs(ieq) - ptcval * this%x(ieq)
2604  end if
2605  end do
2606  bnorm = sqrt(bnorm)
2607  if (this%iptcout > 0) then
2608  write (this%iptcout, '(i10,5(1x,e15.7),1(1x,f15.6))') &
2609  kiter, this%ptcdel, this%l2norm0, l2norm, bnorm, &
2610  ptcval, bnorm / l2norm
2611  end if
2612  this%l2norm0 = l2norm
2613  end if
2614  !
2615  ! -- save rhs, amat to a file
2616  ! to enable set itestmat to 1 and recompile
2617  !-------------------------------------------------------
2618  itestmat = 0
2619  if (itestmat == 1) then
2620  write (fname, fmtfname) this%id, kper, kstp, kiter
2621  print *, 'Saving amat to: ', trim(adjustl(fname))
2622 
2623  itestmat = getunit()
2624  open (itestmat, file=trim(adjustl(fname)))
2625  write (itestmat, *) 'NODE, RHS, AMAT FOLLOW'
2626  do ieq = 1, this%neq
2627  irow_glo = ieq + this%matrix_offset
2628  icol_s = this%system_matrix%get_first_col_pos(irow_glo)
2629  icol_e = this%system_matrix%get_last_col_pos(irow_glo)
2630  write (itestmat, '(*(G0,:,","))') &
2631  irow_glo, &
2632  this%rhs(ieq), &
2633  (this%system_matrix%get_column(ipos), ipos=icol_s, icol_e), &
2634  (this%system_matrix%get_value_pos(ipos), ipos=icol_s, icol_e)
2635  end do
2636  close (itestmat)
2637  !stop
2638  end if
2639  !-------------------------------------------------------
2640  !
2641  ! -- call appropriate linear solver
2642  !
2643  ! -- ims linear solver - linmeth option 1
2644  if (this%linsolver == ims_solver) then
2645  call this%imslinear%imslinear_apply(this%icnvg, kstp, kiter, in_iter, &
2646  this%nitermax, this%convnmod, &
2647  this%convmodstart, this%caccel, &
2648  this%cnvg_summary)
2649  else if (this%linsolver == petsc_solver) then
2650  call this%linear_solver%solve(kiter, this%vec_rhs, &
2651  this%vec_x, this%cnvg_summary)
2652  in_iter = this%linear_solver%iteration_number
2653  this%icnvg = this%linear_solver%is_converged
2654  end if
2655  end subroutine sln_ls
2656 
2657  !
2658  !> @ brief Set default Picard iteration variables
2659  !!
2660  !! Set default Picard iteration variables based on passed complexity option.
2661  !!
2662  !<
2663  subroutine sln_setouter(this, ifdparam)
2664  ! -- dummy variables
2665  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2666  integer(I4B), intent(in) :: ifdparam !< complexity option (1) simple (2) moderate (3) complex
2667  !
2668  ! -- simple option
2669  select case (ifdparam)
2670  case (1)
2671  this%dvclose = dem3
2672  this%mxiter = 25
2673  this%nonmeth = 0
2674  this%theta = done
2675  this%akappa = dzero
2676  this%gamma = done
2677  this%amomentum = dzero
2678  this%numtrack = 0
2679  this%btol = dzero
2680  this%breduc = dzero
2681  this%res_lim = dzero
2682  !
2683  ! -- moderate
2684  case (2)
2685  this%dvclose = dem2
2686  this%mxiter = 50
2687  this%nonmeth = 3
2688  this%theta = 0.9d0
2689  this%akappa = 0.0001d0
2690  this%gamma = dzero
2691  this%amomentum = dzero
2692  this%numtrack = 0
2693  this%btol = dzero
2694  this%breduc = dzero
2695  this%res_lim = dzero
2696  !
2697  ! -- complex
2698  case (3)
2699  this%dvclose = dem1
2700  this%mxiter = 100
2701  this%nonmeth = 3
2702  this%theta = 0.8d0
2703  this%akappa = 0.0001d0
2704  this%gamma = dzero
2705  this%amomentum = dzero
2706  this%numtrack = 20
2707  this%btol = 1.05d0
2708  this%breduc = 0.1d0
2709  this%res_lim = 0.002d0
2710  end select
2711  end subroutine sln_setouter
2712 
2713  !> @ brief Perform backtracking
2714  !!
2715  !! Perform backtracking on the solution in the maximum number of backtrack
2716  !! iterations (nbtrack) is greater than 0 and the backtracking criteria
2717  !! are exceeded.
2718  !!
2719  !<
2720  subroutine sln_backtracking(this, mp, cp, kiter)
2721  ! -- dummy variables
2722  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2723  class(numericalmodeltype), pointer :: mp !< model pointer (currently null())
2724  class(numericalexchangetype), pointer :: cp !< exchange pointer (currently null())
2725  integer(I4B), intent(in) :: kiter !< Picard iteration number
2726  ! -- local variables
2727  character(len=7) :: cmsg
2728  integer(I4B) :: nb
2729  integer(I4B) :: btflag
2730  integer(I4B) :: ibflag
2731  integer(I4B) :: ibtcnt
2732  real(DP) :: resin
2733  !
2734  ! -- initialize local variables
2735  ibflag = 0
2736 
2737  !
2738  ! -- refill amat and rhs with standard conductance
2739  call this%sln_buildsystem(kiter, inewton=0)
2740 
2741  !
2742  ! -- calculate initial l2 norm
2743  if (kiter == 1) then
2744  call this%sln_l2norm(this%res_prev)
2745  resin = this%res_prev
2746  ibflag = 0
2747  else
2748  call this%sln_l2norm(this%res_new)
2749  resin = this%res_new
2750  end if
2751  ibtcnt = 0
2752  if (kiter > 1) then
2753  if (this%res_new > this%res_prev * this%btol) then
2754  !
2755  ! -- iterate until backtracking complete
2756  btloop: do nb = 1, this%numtrack
2757  !
2758  ! -- backtrack the dependent variable
2759  call this%sln_backtracking_xupdate(btflag)
2760  !
2761  ! -- dependent-variable change less than dvclose
2762  if (btflag == 0) then
2763  ibflag = 4
2764  exit btloop
2765  end if
2766  !
2767  ibtcnt = nb
2768 
2769  ! recalculate linear system (amat and rhs)
2770  call this%sln_buildsystem(kiter, inewton=0)
2771 
2772  !
2773  ! -- calculate updated l2norm
2774  call this%sln_l2norm(this%res_new)
2775  !
2776  ! -- evaluate if back tracking can be terminated
2777  if (nb == this%numtrack) then
2778  ibflag = 2
2779  exit btloop
2780  end if
2781  if (this%res_new < this%res_prev * this%btol) then
2782  ibflag = 1
2783  exit btloop
2784  end if
2785  if (this%res_new < this%res_lim) then
2786  exit btloop
2787  end if
2788  end do btloop
2789  end if
2790  ! -- save new residual
2791  this%res_prev = this%res_new
2792  end if
2793  !
2794  ! -- write back backtracking results
2795  if (this%iprims > 0) then
2796  if (ibtcnt > 0) then
2797  cmsg = ' '
2798  else
2799  cmsg = '*'
2800  end if
2801  !
2802  ! -- add data to outertab
2803  call this%outertab%add_term('Backtracking')
2804  call this%outertab%add_term(kiter)
2805  call this%outertab%add_term(' ')
2806  if (this%numtrack > 0) then
2807  call this%outertab%add_term(ibflag)
2808  call this%outertab%add_term(ibtcnt)
2809  call this%outertab%add_term(resin)
2810  call this%outertab%add_term(this%res_prev)
2811  end if
2812  call this%outertab%add_term(' ')
2813  call this%outertab%add_term(cmsg)
2814  call this%outertab%add_term(' ')
2815  end if
2816  end subroutine sln_backtracking
2817 
2818  !> @ brief Backtracking update of the dependent variable
2819  !!
2820  !! Backtracking update of the dependent variable if the calculated backtracking
2821  !! update exceeds the dependent variable closure criteria.
2822  !!
2823  !<
2824  subroutine sln_backtracking_xupdate(this, bt_flag)
2825  ! -- dummy variables
2826  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2827  integer(I4B), intent(inout) :: bt_flag !< backtracking flag (1) backtracking performed (0) backtracking not performed
2828 
2829  bt_flag = this%get_backtracking_flag()
2830 
2831  ! perform backtracking if ...
2832  if (bt_flag > 0) then
2833  call this%apply_backtracking()
2834  end if
2835 
2836  end subroutine sln_backtracking_xupdate
2837 
2838  !> @brief Check if backtracking should be applied for this solution,
2839  !< returns 1: yes, 0: no
2840  function get_backtracking_flag(this) result(bt_flag)
2841  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2842  integer(I4B) :: bt_flag !< backtracking flag (1) backtracking performed (0) backtracking not performed
2843  ! local
2844  integer(I4B) :: n
2845  real(dp) :: dx
2846  real(dp) :: dx_abs
2847  real(dp) :: dx_abs_max
2848 
2849  ! default is off
2850  bt_flag = 0
2851 
2852  ! find max. change
2853  dx_abs_max = 0.0
2854  do n = 1, this%neq
2855  if (this%active(n) < 1) cycle
2856  dx = this%x(n) - this%xtemp(n)
2857  dx_abs = abs(dx)
2858  if (dx_abs > dx_abs_max) dx_abs_max = dx_abs
2859  end do
2860 
2861  ! if backtracking, set flag
2862  if (this%breduc * dx_abs_max >= this%dvclose) then
2863  bt_flag = 1
2864  end if
2865 
2866  end function get_backtracking_flag
2867 
2868  !> @brief Check if dependent variable scalining should be applied for this solution,
2869  !< returns 1: yes, 0: no, -1: error
2870  function sln_get_idvscale(this) result(idv_scale)
2871  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2872  integer(I4B) :: idv_scale !< backtracking flag (1) backtracking performed (0) backtracking not performed
2873  ! local
2874  class(numericalmodeltype), pointer :: mp => null()
2875  integer(I4B) :: i
2876 
2877  idv_scale = 0
2878  do i = 1, this%modellist%Count()
2879  mp => getnumericalmodelfromlist(this%modellist, i)
2880  if (mp%get_idv_scale() /= 0) then
2881  idv_scale = 1
2882  else
2883  if (idv_scale == 1) then
2884  idv_scale = -1
2885  end if
2886  end if
2887  end do
2888 
2889  end function sln_get_idvscale
2890 
2891  !> @brief Update x with backtracking
2892  !<
2893  subroutine apply_backtracking(this)
2894  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2895  ! local
2896  integer(I4B) :: n
2897  real(DP) :: delx
2898 
2899  do n = 1, this%neq
2900  if (this%active(n) < 1) cycle
2901  delx = this%breduc * (this%x(n) - this%xtemp(n))
2902  this%x(n) = this%xtemp(n) + delx
2903  end do
2904 
2905  end subroutine
2906 
2907  !> @ brief Calculate the solution L-2 norm for all
2908  !! active cells using
2909  !!
2910  !! A = the linear system matrix
2911  !! x = the dependent variable vector
2912  !! b = the right-hand side vector
2913  !!
2914  !! r = A * x - b
2915  !! r_i = 0 if cell i is inactive
2916  !! L2norm = || r ||_2
2917  !<
2918  subroutine sln_l2norm(this, l2norm)
2919  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2920  real(DP) :: l2norm !< calculated L-2 norm
2921  ! local
2922  class(vectorbasetype), pointer :: vec_resid
2923 
2924  ! calc. residual vector
2925  vec_resid => this%system_matrix%create_vec(this%neq)
2926  call this%sln_calc_residual(vec_resid)
2927 
2928  ! 2-norm
2929  l2norm = vec_resid%norm2()
2930 
2931  ! clean up temp. vector
2932  call vec_resid%destroy()
2933  deallocate (vec_resid)
2934  end subroutine sln_l2norm
2935 
2936  !> @ brief Get the maximum value from a vector
2937  !!
2938  !! Return the maximum value in a vector using a normalized form.
2939  !!
2940  !<
2941  subroutine sln_maxval(this, nsize, v, vmax)
2942  ! -- dummy variables
2943  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
2944  integer(I4B), intent(in) :: nsize !< length of vector
2945  real(DP), dimension(nsize), intent(in) :: v !< input vector
2946  real(DP), intent(inout) :: vmax !< maximum value
2947  ! -- local variables
2948  integer(I4B) :: n
2949  real(DP) :: d
2950  real(DP) :: denom
2951  real(DP) :: dnorm
2952  !
2953  ! -- determine maximum value
2954  vmax = v(1)
2955  do n = 2, nsize
2956  d = v(n)
2957  denom = abs(vmax)
2958  if (denom == dzero) then
2959  denom = dprec
2960  end if
2961  !
2962  ! -- calculate normalized value
2963  dnorm = abs(d) / denom
2964  if (dnorm > done) then
2965  vmax = d
2966  end if
2967  end do
2968  end subroutine sln_maxval
2969 
2970  !> @ brief Calculate dependent-variable change
2971  !!
2972  !! Calculate the dependent-variable change for every cell.
2973  !!
2974  !<
2975  subroutine sln_calcdx(this, neq, active, x, xtemp, dx)
2976  ! -- dummy variables
2977  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
2978  integer(I4B), intent(in) :: neq !< number of equations
2979  integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1)
2980  real(DP), dimension(neq), intent(in) :: x !< current dependent-variable
2981  real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable
2982  real(DP), dimension(neq), intent(inout) :: dx !< dependent-variable change
2983  ! -- local
2984  integer(I4B) :: n
2985  !
2986  ! -- calculate dependent-variable change
2987  do n = 1, neq
2988  ! -- skip inactive nodes
2989  if (active(n) < 1) then
2990  dx(n) = dzero
2991  else
2992  dx(n) = x(n) - xtemp(n)
2993  end if
2994  end do
2995  end subroutine sln_calcdx
2996 
2997  !> @brief Calculate pseudo-transient continuation factor
2998  !< from the models in the solution
2999  subroutine sln_calc_ptc(this, iptc, ptcf)
3000  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3001  integer(I4B) :: iptc !< PTC (1) or not (0)
3002  real(DP) :: ptcf !< the PTC factor calculated
3003  ! local
3004  integer(I4B) :: im
3005  class(numericalmodeltype), pointer :: mp
3006  class(vectorbasetype), pointer :: vec_resid
3007 
3008  iptc = 0
3009  ptcf = dzero
3010 
3011  ! calc. residual vector
3012  vec_resid => this%system_matrix%create_vec(this%neq)
3013  call this%sln_calc_residual(vec_resid)
3014 
3015  ! determine ptc
3016  do im = 1, this%modellist%Count()
3017  mp => getnumericalmodelfromlist(this%modellist, im)
3018  call mp%model_ptc(vec_resid, iptc, ptcf)
3019  end do
3020 
3021  ! clean up temp. vector
3022  call vec_resid%destroy()
3023  deallocate (vec_resid)
3024 
3025  end subroutine sln_calc_ptc
3026 
3027  !> @brief Calculate the current residual vector r = A*x - b,
3028  !< zeroes out for inactive cells
3029  subroutine sln_calc_residual(this, vec_resid)
3030  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3031  class(vectorbasetype), pointer :: vec_resid !< the residual vector
3032  ! local
3033  integer(I4B) :: n
3034 
3035  call this%system_matrix%multiply(this%vec_x, vec_resid) ! r = A*x
3036 
3037  call vec_resid%axpy(-1.0_dp, this%vec_rhs) ! r = r - b
3038 
3039  do n = 1, this%neq
3040  if (this%active(n) < 1) then
3041  call vec_resid%set_value_local(n, 0.0_dp) ! r_i = 0 if inactive
3042  end if
3043  end do
3044 
3045  end subroutine sln_calc_residual
3046 
3047  !> @ brief Under-relaxation
3048  !!
3049  !! Under relax using the simple, cooley, or delta-bar-delta methods.
3050  !!
3051  !<
3052  subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp)
3053  ! -- dummy variables
3054  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3055  integer(I4B), intent(in) :: kiter !< Picard iteration number
3056  real(DP), intent(in) :: bigch !< maximum dependent-variable change
3057  integer(I4B), intent(in) :: neq !< number of equations
3058  integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1)
3059  real(DP), dimension(neq), intent(inout) :: x !< current dependent-variable
3060  real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable
3061  ! -- local variables
3062  integer(I4B) :: n
3063  real(DP) :: ww
3064  real(DP) :: delx
3065  real(DP) :: relax
3066  real(DP) :: es
3067  real(DP) :: aes
3068  real(DP) :: amom
3069  !
3070  ! -- option for using simple dampening (as done by MODFLOW-2005 PCG)
3071  if (this%nonmeth == 1) then
3072  do n = 1, neq
3073  !
3074  ! -- skip inactive nodes
3075  if (active(n) < 1) cycle
3076  !
3077  ! -- compute step-size (delta x)
3078  delx = x(n) - xtemp(n)
3079  this%dxold(n) = delx
3080 
3081  ! -- dampen dependent variable solution
3082  x(n) = xtemp(n) + this%gamma * delx
3083  end do
3084  !
3085  ! -- option for using cooley underrelaxation
3086  else if (this%nonmeth == 2) then
3087  !
3088  ! -- set bigch
3089  this%bigch = bigch
3090  !
3091  ! -- initialize values for first iteration
3092  if (kiter == 1) then
3093  relax = done
3094  this%relaxold = done
3095  this%bigchold = bigch
3096  else
3097  !
3098  ! -- compute relaxation factor
3099  es = this%bigch / (this%bigchold * this%relaxold)
3100  aes = abs(es)
3101  if (es < -done) then
3102  relax = dhalf / aes
3103  else
3104  relax = (dthree + es) / (dthree + aes)
3105  end if
3106  end if
3107  this%relaxold = relax
3108  !
3109  ! -- modify cooley to use weighted average of past changes
3110  this%bigchold = (done - this%gamma) * this%bigch + this%gamma * &
3111  this%bigchold
3112  !
3113  ! -- compute new dependent variable after under-relaxation
3114  if (relax < done) then
3115  do n = 1, neq
3116  !
3117  ! -- skip inactive nodes
3118  if (active(n) < 1) cycle
3119  !
3120  ! -- update dependent variable
3121  delx = x(n) - xtemp(n)
3122  this%dxold(n) = delx
3123  x(n) = xtemp(n) + relax * delx
3124  end do
3125  end if
3126  !
3127  ! -- option for using delta-bar-delta scheme to under-relax for all equations
3128  else if (this%nonmeth == 3) then
3129  do n = 1, neq
3130  !
3131  ! -- skip inactive nodes
3132  if (active(n) < 1) cycle
3133  !
3134  ! -- compute step-size (delta x) and initialize d-b-d parameters
3135  delx = x(n) - xtemp(n)
3136  !
3137  ! -- initialize values for first iteration
3138  if (kiter == 1) then
3139  this%wsave(n) = done
3140  this%hchold(n) = dem20
3141  this%deold(n) = dzero
3142  end if
3143  !
3144  ! -- compute new relaxation term as per delta-bar-delta
3145  ww = this%wsave(n)
3146  !
3147  ! for flip-flop condition, decrease factor
3148  if (this%deold(n) * delx < dzero) then
3149  ww = this%theta * this%wsave(n)
3150  ! -- when change is of same sign, increase factor
3151  else
3152  ww = this%wsave(n) + this%akappa
3153  end if
3154  if (ww > done) ww = done
3155  this%wsave(n) = ww
3156  !
3157  ! -- compute weighted average of past changes in hchold
3158  if (kiter == 1) then
3159  this%hchold(n) = delx
3160  else
3161  this%hchold(n) = (done - this%gamma) * delx + &
3162  this%gamma * this%hchold(n)
3163  end if
3164  !
3165  ! -- store slope (change) term for next iteration
3166  this%deold(n) = delx
3167  this%dxold(n) = delx
3168  !
3169  ! -- compute accepted step-size and new dependent variable
3170  amom = dzero
3171  if (kiter > 4) amom = this%amomentum
3172  delx = delx * ww + amom * this%hchold(n)
3173  x(n) = xtemp(n) + delx
3174  end do
3175  !
3176  end if
3177  end subroutine sln_underrelax
3178 
3179  !> @ brief Determine maximum dependent-variable change
3180  !!
3181  !! Determine the maximum dependent-variable change at the end of a
3182  !! Picard iteration.
3183  !!
3184  !<
3185  subroutine sln_get_dxmax(this, hncg, lrch)
3186  ! -- dummy variables
3187  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
3188  real(DP), intent(inout) :: hncg !< maximum dependent-variable change
3189  integer(I4B), intent(inout) :: lrch !< location of the maximum dependent-variable change
3190  ! -- local variables
3191  integer(I4B) :: nb
3192  real(DP) :: bigch
3193  real(DP) :: abigch
3194  integer(I4B) :: n
3195  real(DP) :: hdif
3196  real(DP) :: ahdif
3197  !
3198  ! -- determine the maximum change
3199  nb = 0
3200  bigch = dzero
3201  abigch = dzero
3202  do n = 1, this%neq
3203  if (this%active(n) < 1) cycle
3204  hdif = this%x(n) - this%xtemp(n)
3205  ahdif = abs(hdif)
3206  if (ahdif > abigch) then
3207  bigch = hdif
3208  abigch = ahdif
3209  nb = n
3210  end if
3211  end do
3212  !
3213  !-----store maximum change value and location
3214  hncg = bigch
3215  lrch = nb
3216  end subroutine sln_get_dxmax
3217 
3218  function sln_has_converged(this, max_dvc) result(has_converged)
3219  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3220  real(dp) :: max_dvc !< the maximum dependent variable change
3221  logical(LGP) :: has_converged !< True, when converged
3222 
3223  has_converged = .false.
3224  if (abs(max_dvc) <= this%dvclose) then
3225  has_converged = .true.
3226  end if
3227 
3228  end function sln_has_converged
3229 
3230  !> @brief Check package convergence
3231  !<
3232  function sln_package_convergence(this, dpak, cpakout, iend) result(ivalue)
3233  ! dummy
3234  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3235  real(dp), intent(in) :: dpak !< Newton Under-relaxation flag
3236  character(len=LENPAKLOC), intent(in) :: cpakout !< string with package that caused failure
3237  integer(I4B), intent(in) :: iend !< flag indicating if last inner iteration (iend=1)
3238  ! local
3239  integer(I4B) :: ivalue
3240  ivalue = 1
3241  if (abs(dpak) > this%dvclose) then
3242  ivalue = 0
3243  ! -- write message to stdout
3244  if (iend /= 0) then
3245  write (errmsg, '(3a)') &
3246  'PACKAGE (', trim(cpakout), ') CAUSED CONVERGENCE FAILURE'
3247  call write_message(errmsg)
3248  end if
3249  end if
3250 
3251  end function sln_package_convergence
3252 
3253  !> @brief Synchronize Newton Under-relaxation flag
3254  !<
3255  function sln_sync_newtonur_flag(this, inewtonur) result(ivalue)
3256  ! dummy
3257  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3258  integer(I4B), intent(in) :: inewtonur !< Newton Under-relaxation flag
3259  ! local
3260  integer(I4B) :: ivalue !< Default is set to current value (1 = under-relaxation applied)
3261 
3262  ivalue = inewtonur
3263 
3264  end function sln_sync_newtonur_flag
3265 
3266  !> @brief Custom convergence check for when Newton UR has been applied
3267  !<
3268  function sln_nur_has_converged(this, dxold_max, hncg) &
3269  result(has_converged)
3270  class(numericalsolutiontype) :: this !< NumericalSolutionType instance
3271  real(dp), intent(in) :: dxold_max !< the maximum dependent variable change for unrelaxed cells
3272  real(dp), intent(in) :: hncg !< largest dep. var. change at end of Picard iteration
3273  logical(LGP) :: has_converged !< True, when converged
3274 
3275  has_converged = .false.
3276  if (abs(dxold_max) <= this%dvclose .and. &
3277  abs(hncg) <= this%dvclose) then
3278  has_converged = .true.
3279  end if
3280 
3281  end function sln_nur_has_converged
3282 
3283  !> @ brief Get cell location string
3284  !!
3285  !! Get the cell location string for the provided solution node number.
3286  !< Returns empty string when node not found.
3287  subroutine sln_get_loc(this, nodesln, str)
3288  ! -- dummy variables
3289  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
3290  integer(I4B), intent(in) :: nodesln !< solution node number
3291  character(len=*), intent(inout) :: str !< string with user node number
3292  ! -- local variables
3293  class(numericalmodeltype), pointer :: mp => null()
3294  integer(I4B) :: i
3295  integer(I4B) :: istart
3296  integer(I4B) :: iend
3297  integer(I4B) :: noder
3298  integer(I4B) :: nglo
3299  !
3300  ! -- initialize dummy variables
3301  str = ''
3302  !
3303  ! -- initialize local variables
3304  noder = 0
3305  !
3306  ! -- when parallel, account for offset
3307  nglo = nodesln + this%matrix_offset
3308  !
3309  ! -- calculate and set offsets
3310  do i = 1, this%modellist%Count()
3311  mp => getnumericalmodelfromlist(this%modellist, i)
3312  istart = 0
3313  iend = 0
3314  call mp%get_mrange(istart, iend)
3315  if (nglo >= istart .and. nglo <= iend) then
3316  noder = nglo - istart + 1
3317  call mp%get_mcellid(noder, str)
3318  exit
3319  end if
3320  end do
3321  end subroutine sln_get_loc
3322 
3323  !> @ brief Get user node number
3324  !!
3325  !! Get the user node number from a model for the provided solution node number.
3326  !!
3327  !<
3328  subroutine sln_get_nodeu(this, nodesln, im, nodeu)
3329  ! -- dummy variables
3330  class(numericalsolutiontype), intent(inout) :: this !< NumericalSolutionType instance
3331  integer(I4B), intent(in) :: nodesln !< solution node number
3332  integer(I4B), intent(inout) :: im !< solution model index (index in model list for this solution)
3333  integer(I4B), intent(inout) :: nodeu !< user node number
3334  ! -- local variables
3335  class(numericalmodeltype), pointer :: mp => null()
3336  integer(I4B) :: i
3337  integer(I4B) :: istart
3338  integer(I4B) :: iend
3339  integer(I4B) :: noder, nglo
3340  !
3341  ! -- initialize local variables
3342  noder = 0
3343  !
3344  ! -- when parallel, account for offset
3345  nglo = nodesln + this%matrix_offset
3346  !
3347  ! -- calculate and set offsets
3348  do i = 1, this%modellist%Count()
3349  mp => getnumericalmodelfromlist(this%modellist, i)
3350  istart = 0
3351  iend = 0
3352  call mp%get_mrange(istart, iend)
3353  if (nglo >= istart .and. nglo <= iend) then
3354  noder = nglo - istart + 1
3355  call mp%get_mnodeu(noder, nodeu)
3356  im = i
3357  exit
3358  end if
3359  end do
3360  end subroutine sln_get_nodeu
3361 
3362  !> @ brief Cast a object as a Numerical Solution
3363  !!
3364  !! Get a numerical solution from a list.
3365  !!
3366  !<
3367  function castasnumericalsolutionclass(obj) result(res)
3368  ! -- dummy variables
3369  class(*), pointer, intent(inout) :: obj !< generic object
3370  ! -- return variable
3371  class(numericalsolutiontype), pointer :: res !< output NumericalSolutionType
3372  !
3373  ! -- initialize return variable
3374  res => null()
3375  !
3376  ! -- determine if obj is associated
3377  if (.not. associated(obj)) return
3378  !
3379  ! -- set res
3380  select type (obj)
3381  class is (numericalsolutiontype)
3382  res => obj
3383  end select
3384  end function castasnumericalsolutionclass
3385 
3386  !> @ brief Get a numerical solution
3387  !!
3388  !! Get a numerical solution from a list.
3389  !!
3390  !<
3391  function getnumericalsolutionfromlist(list, idx) result(res)
3392  ! -- dummy variables
3393  type(listtype), intent(inout) :: list !< list of numerical solutions
3394  integer(I4B), intent(in) :: idx !< value to retrieve from the list
3395  ! -- return variables
3396  class(numericalsolutiontype), pointer :: res !< numerical solution
3397  ! -- local variables
3398  class(*), pointer :: obj
3399  !
3400  obj => list%GetItem(idx)
3401  res => castasnumericalsolutionclass(obj)
3402  end function getnumericalsolutionfromlist
3403 end module numericalsolutionmodule
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:70
subroutine print(this, output_unit)
Definition: Profiler.f90:228
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:35
class(atstype), pointer, public ats
Definition: tdis.f90:48
integer(i4b), pointer, public kstp
current time step number
Definition: tdis.f90:27
integer(i4b), pointer, public kper
current stress period number
Definition: tdis.f90:26
real(dp), pointer, public delt
length of the current time step
Definition: tdis.f90:32
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:16
This structure stores the generic convergence info for a solution.
A generic heterogeneous doubly-linked list.
Definition: List.f90:14