MODFLOW 6  version 6.7.0.dev2
USGS Modular Hydrologic Model
ParallelSolution.f90
Go to the documentation of this file.
2  use kindmodule, only: dp, lgp, i4b
6  use mpi
8  implicit none
9  private
10 
11  public :: parallelsolutiontype
12 
14  integer(I4B) :: tmr_convergence = -1 !< timer for convergence check
15  integer(I4B) :: tmr_pkg_cnvg = -1 !< timer for package convergence check
16  integer(I4B) :: tmr_sync_nur = -1 !< timer for NUR synchronization
17  integer(I4B) :: tmr_nur_cnvg = -1 !< timer for NUR convergence check
18  integer(I4B) :: tmr_calcptc = -1 !< timer for PTC calculation
19  integer(I4B) :: tmr_underrelax = -1 !< timer for underrelaxation
20  integer(I4B) :: tmr_backtracking = -1 !< timer for backtracking
21  contains
22  ! override
23  procedure :: sln_has_converged => par_has_converged
24  procedure :: sln_package_convergence => par_package_convergence
25  procedure :: sln_sync_newtonur_flag => par_sync_newtonur_flag
26  procedure :: sln_nur_has_converged => par_nur_has_converged
27  procedure :: sln_calc_ptc => par_calc_ptc
28  procedure :: sln_underrelax => par_underrelax
29  procedure :: sln_backtracking_xupdate => par_backtracking_xupdate
30  procedure :: sln_maxval => par_maxval
31  procedure :: sln_get_idvscale => par_get_idvscale
32 
33  end type parallelsolutiontype
34 
35 contains
36 
37  !> @brief Check global convergence. The local maximum dependent
38  !! variable change is reduced over MPI with all other processes
39  !< that are running this parallel numerical solution.
40  function par_has_converged(this, max_dvc) result(has_converged)
41  class(parallelsolutiontype) :: this !< parallel solution
42  real(dp) :: max_dvc !< the LOCAL maximum dependent variable change
43  logical(LGP) :: has_converged !< True, when GLOBALLY converged
44  ! local
45  real(dp) :: global_max_dvc
46  real(dp) :: abs_max_dvc
47  integer :: ierr
48  type(mpiworldtype), pointer :: mpi_world
49 
50  call g_prof%start("Parallel Solution (cnvg check)", this%tmr_convergence)
51 
52  mpi_world => get_mpi_world()
53 
54  has_converged = .false.
55  abs_max_dvc = abs(max_dvc)
56  call mpi_allreduce(abs_max_dvc, global_max_dvc, 1, mpi_double_precision, &
57  mpi_max, mpi_world%comm, ierr)
58  call check_mpi(ierr)
59  if (global_max_dvc <= this%dvclose) then
60  has_converged = .true.
61  end if
62 
63  call g_prof%stop(this%tmr_convergence)
64 
65  end function par_has_converged
66 
67  function par_package_convergence(this, dpak, cpakout, iend) &
68  result(icnvg_global)
69  class(parallelsolutiontype) :: this !< parallel solution instance
70  real(dp), intent(in) :: dpak !< Newton Under-relaxation flag
71  character(len=LENPAKLOC), intent(in) :: cpakout
72  integer(I4B), intent(in) :: iend
73  ! local
74  integer(I4B) :: icnvg_global
75  integer(I4B) :: icnvg_local
76  integer :: ierr
77  type(mpiworldtype), pointer :: mpi_world
78 
79  call g_prof%start("Parallel Solution (package cnvg)", this%tmr_pkg_cnvg)
80 
81  mpi_world => get_mpi_world()
82 
83  icnvg_local = &
84  this%NumericalSolutionType%sln_package_convergence(dpak, cpakout, iend)
85 
86  call mpi_allreduce(icnvg_local, icnvg_global, 1, mpi_integer, &
87  mpi_min, mpi_world%comm, ierr)
88  call check_mpi(ierr)
89 
90  call g_prof%stop(this%tmr_pkg_cnvg)
91 
92  end function par_package_convergence
93 
94  function par_sync_newtonur_flag(this, inewtonur) result(ivalue)
95  class(parallelsolutiontype) :: this !< parallel solution instance
96  integer(I4B), intent(in) :: inewtonur !< local Newton Under-relaxation flag
97  ! local
98  integer(I4B) :: ivalue !< Maximum of all local values (1 = under-relaxation applied)
99  integer :: ierr
100  type(mpiworldtype), pointer :: mpi_world
101 
102  call g_prof%start("Parallel Solution (NUR)", this%tmr_sync_nur)
103 
104  mpi_world => get_mpi_world()
105  call mpi_allreduce(inewtonur, ivalue, 1, mpi_integer, &
106  mpi_max, mpi_world%comm, ierr)
107  call check_mpi(ierr)
108 
109  call g_prof%stop(this%tmr_sync_nur)
110 
111  end function par_sync_newtonur_flag
112 
113  function par_nur_has_converged(this, dxold_max, hncg) &
114  result(has_converged)
115  class(parallelsolutiontype) :: this !< parallel solution instance
116  real(dp), intent(in) :: dxold_max !< the maximum dependent variable change for cells not adjusted by NUR
117  real(dp), intent(in) :: hncg !< largest dep. var. change at end of Picard iter.
118  logical(LGP) :: has_converged !< True, when converged
119  ! local
120  integer(I4B) :: icnvg_local
121  integer(I4B) :: icnvg_global
122  integer :: ierr
123  type(mpiworldtype), pointer :: mpi_world
124 
125  call g_prof%start("Parallel Solution (NUR cnvg)", this%tmr_nur_cnvg)
126 
127  mpi_world => get_mpi_world()
128 
129  has_converged = .false.
130  icnvg_local = 0
131  if (this%NumericalSolutionType%sln_nur_has_converged( &
132  dxold_max, hncg)) then
133  icnvg_local = 1
134  end if
135 
136  call mpi_allreduce(icnvg_local, icnvg_global, 1, mpi_integer, &
137  mpi_min, mpi_world%comm, ierr)
138  call check_mpi(ierr)
139  if (icnvg_global == 1) has_converged = .true.
140 
141  call g_prof%stop(this%tmr_nur_cnvg)
142 
143  end function par_nur_has_converged
144 
145  !> @brief Calculate pseudo-transient continuation factor
146  !< for the parallel case
147  subroutine par_calc_ptc(this, iptc, ptcf)
148  class(parallelsolutiontype) :: this !< parallel solution
149  integer(I4B) :: iptc !< PTC (1) or not (0)
150  real(DP) :: ptcf !< the (global) PTC factor calculated
151  ! local
152  integer(I4B) :: iptc_loc
153  real(DP) :: ptcf_loc, ptcf_glo_max
154  integer :: ierr
155  type(mpiworldtype), pointer :: mpi_world
156 
157  call g_prof%start("Parallel Solution (PTC calc)", this%tmr_calcptc)
158 
159  mpi_world => get_mpi_world()
160  call this%NumericalSolutionType%sln_calc_ptc(iptc_loc, ptcf_loc)
161  if (iptc_loc == 0) ptcf_loc = dzero
162 
163  ! now reduce
164  call mpi_allreduce(ptcf_loc, ptcf_glo_max, 1, mpi_double_precision, &
165  mpi_max, mpi_world%comm, ierr)
166  call check_mpi(ierr)
167 
168  iptc = 0
169  ptcf = dzero
170  if (ptcf_glo_max > dzero) then
171  iptc = 1
172  ptcf = ptcf_glo_max
173  end if
174 
175  call g_prof%stop(this%tmr_calcptc)
176 
177  end subroutine par_calc_ptc
178 
179  !> @brief apply under-relaxation in sync over all processes
180  !<
181  subroutine par_underrelax(this, kiter, bigch, neq, active, x, xtemp)
182  class(parallelsolutiontype) :: this !< parallel instance
183  integer(I4B), intent(in) :: kiter !< Picard iteration number
184  real(DP), intent(in) :: bigch !< maximum dependent-variable change
185  integer(I4B), intent(in) :: neq !< number of equations
186  integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1)
187  real(DP), dimension(neq), intent(inout) :: x !< current dependent-variable
188  real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable
189  ! local
190  real(DP) :: dvc_global_max, dvc_global_min
191  integer :: ierr
192  type(mpiworldtype), pointer :: mpi_world
193 
194  call g_prof%start("Parallel Solution (underrelax)", this%tmr_underrelax)
195 
196  mpi_world => get_mpi_world()
197 
198  ! first reduce largest change over all processes
199  call mpi_allreduce(bigch, dvc_global_max, 1, mpi_double_precision, &
200  mpi_max, mpi_world%comm, ierr)
201  call check_mpi(ierr)
202  call mpi_allreduce(bigch, dvc_global_min, 1, mpi_double_precision, &
203  mpi_min, mpi_world%comm, ierr)
204  call check_mpi(ierr)
205 
206  if (abs(dvc_global_min) > abs(dvc_global_max)) then
207  dvc_global_max = dvc_global_min
208  end if
209 
210  ! call local underrelax routine
211  call this%NumericalSolutionType%sln_underrelax(kiter, dvc_global_max, &
212  neq, active, x, xtemp)
213 
214  call g_prof%stop(this%tmr_underrelax)
215 
216  end subroutine par_underrelax
217 
218  !> @brief synchronize backtracking flag over processes
219  !<
220  subroutine par_backtracking_xupdate(this, bt_flag)
221  ! -- dummy variables
222  class(parallelsolutiontype), intent(inout) :: this !< ParallelSolutionType instance
223  integer(I4B), intent(inout) :: bt_flag !< global backtracking flag (1) backtracking performed (0) backtracking not performed
224  ! -- local variables
225  integer(I4B) :: btflag_local
226  type(mpiworldtype), pointer :: mpi_world
227  integer :: ierr
228 
229  call g_prof%start("Parallel Solution (backtrack)", this%tmr_backtracking)
230 
231  mpi_world => get_mpi_world()
232 
233  ! get local bt flag
234  btflag_local = this%NumericalSolutionType%get_backtracking_flag()
235 
236  ! reduce into global decision (if any, then all)
237  call mpi_allreduce(btflag_local, bt_flag, 1, mpi_integer, &
238  mpi_max, mpi_world%comm, ierr)
239  call check_mpi(ierr)
240 
241  ! perform backtracking if ...
242  if (bt_flag > 0) then
243  call this%NumericalSolutionType%apply_backtracking()
244  end if
245 
246  call g_prof%stop(this%tmr_backtracking)
247 
248  end subroutine par_backtracking_xupdate
249 
250  !> @brief synchronize idvscale flag over processes
251  !<
252  function par_get_idvscale(this) result(idv_scale_global)
253  ! -- dummy variables
254  class(parallelsolutiontype) :: this !< ParallelSolutionType instance
255  integer(I4B) :: idv_scale_global !< global idv_scale flag (1) dv_scaling performed (0) dv_scaling not performed (-1) error
256  ! -- local variables
257  integer(I4B) :: idv_scale_local
258  type(mpiworldtype), pointer :: mpi_world
259  integer :: ierr
260 
261  mpi_world => get_mpi_world()
262 
263  ! get local idvscale flag
264  idv_scale_local = this%NumericalSolutionType%sln_get_idvscale()
265 
266  ! reduce into global decision (if any, then all)
267  call mpi_allreduce(idv_scale_local, idv_scale_global, 1, mpi_integer, &
268  mpi_min, mpi_world%comm, ierr)
269  call check_mpi(ierr)
270 
271  end function par_get_idvscale
272 
273  !> @brief synchronize maxval over processes
274  !<
275  subroutine par_maxval(this, nsize, v, vmax)
276  ! -- dummy variables
277  class(parallelsolutiontype) :: this !< ParallelSolutionType instance
278  integer(I4B), intent(in) :: nsize !< length of vector
279  real(DP), dimension(nsize), intent(in) :: v !< input vector
280  real(DP), intent(inout) :: vmax !< maximum value
281  ! -- local variables
282  real(DP) :: vmax_local
283  real(DP) :: vmin_global
284  type(mpiworldtype), pointer :: mpi_world
285  integer :: ierr
286 
287  mpi_world => get_mpi_world()
288 
289  ! determine local vmax
290  call this%NumericalSolutionType%sln_maxval(nsize, v, vmax_local)
291 
292  ! reduce into global decision (if any, then all)
293  call mpi_allreduce(vmax_local, vmax, 1, mpi_double_precision, &
294  mpi_max, mpi_world%comm, ierr)
295  call check_mpi(ierr)
296 
297  call mpi_allreduce(vmax_local, vmin_global, 1, mpi_double_precision, &
298  mpi_min, mpi_world%comm, ierr)
299  call check_mpi(ierr)
300 
301  if (abs(vmin_global) > abs(vmax)) then
302  vmax = vmin_global
303  end if
304 
305  end subroutine par_maxval
306 
307 end module parallelsolutionmodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter lenpakloc
maximum length of a package location
Definition: Constants.f90:50
real(dp), parameter dzero
real constant zero
Definition: Constants.f90:65
real(dp), parameter done
real constant 1
Definition: Constants.f90:76
This module defines variable data types.
Definition: kind.f90:8
type(mpiworldtype) function, pointer, public get_mpi_world()
Definition: MpiWorld.f90:32
subroutine, public check_mpi(mpi_error_code)
Check the MPI error code, report, and.
Definition: MpiWorld.f90:116
logical(lgp) function par_has_converged(this, max_dvc)
Check global convergence. The local maximum dependent variable change is reduced over MPI with all ot...
integer(i4b) function par_package_convergence(this, dpak, cpakout, iend)
logical(lgp) function par_nur_has_converged(this, dxold_max, hncg)
integer(i4b) function par_sync_newtonur_flag(this, inewtonur)
integer(i4b) function par_get_idvscale(this)
synchronize idvscale flag over processes
subroutine par_underrelax(this, kiter, bigch, neq, active, x, xtemp)
apply under-relaxation in sync over all processes
subroutine par_backtracking_xupdate(this, bt_flag)
synchronize backtracking flag over processes
subroutine par_calc_ptc(this, iptc, ptcf)
Calculate pseudo-transient continuation factor.
subroutine par_maxval(this, nsize, v, vmax)
synchronize maxval over processes
type(profilertype), public g_prof
the global timer object (to reduce trivial lines of code)
Definition: Profiler.f90:65