MODFLOW 6  version 6.7.0.dev0
USGS Modular Hydrologic Model
VirtualDataManager.f90
Go to the documentation of this file.
1 module virtualdatamanagermodule
2  use kindmodule, only: i4b
24  implicit none
25  private
26 
27  type, public :: virtualdatamanagertype
28  integer(I4B) :: nr_solutions
29  integer(I4B), dimension(:), allocatable :: solution_ids
30  type(VirtualSolutionType), dimension(:), pointer :: virtual_solutions
31  class(RouterBaseType), pointer :: router
32  contains
33  procedure :: create => vds_create
34  procedure :: init => vds_init
35  procedure :: add_solution => vds_add_solution
36  procedure :: activate_halo => vds_activate_halo
37  procedure :: compress_halo => vds_compress_halo
38  procedure :: synchronize => vds_synchronize
39  procedure :: synchronize_sln => vds_synchronize_sln
40  procedure :: destroy
41 
42  ! private
43  procedure, private :: vds_synchronize
44  procedure, private :: prepare_all
45  procedure, private :: link_all
46  procedure, private :: vds_synchronize_sln
47  procedure, private :: prepare_sln
48  procedure, private :: link_sln
49  procedure, private :: count_nr_solutions
50  end type virtualdatamanagertype
51 
52 contains
53 
54  !> @brief Initialize the virtual data store
55  subroutine vds_create(this, sim_mode)
56  class(VirtualDataManagerType) :: this
57  character(len=*) :: sim_mode
58  ! local
59  integer(I4B) :: nr_sol
60 
61  nr_sol = this%count_nr_solutions()
62  allocate (this%virtual_solutions(nr_sol))
63  allocate (this%solution_ids(nr_sol))
64 
65  ! we use this one as a counter:
66  this%nr_solutions = 0
67 
68  ! create a router, sequential or parallel
69  this%router => create_router(sim_mode)
70 
71  end subroutine vds_create
72 
73  !> @brief Initialize internal components
74  !<
75  subroutine vds_init(this)
76  class(VirtualDataManagerType) :: this
77 
78  call this%router%initialize()
79 
80  end subroutine
81 
82  !> @brief Add the models and exchanges from the passed solution
83  !! to the virtual data structure. This can then be used
84  !< to efficiently sync only this particular solution.
85  subroutine vds_add_solution(this, num_sol)
86  class(VirtualDataManagerType) :: this
87  class(NumericalSolutionType), pointer :: num_sol
88  ! local
89  integer(I4B) :: i, im, ix, ihm, ihx
90  type(VirtualSolutionType), pointer :: virt_sol
91  class(NumericalModelType), pointer :: num_mod
92  class(DisConnExchangeType), pointer :: exg
93  class(SpatialModelConnectionType), pointer :: conn
94  integer(I4B) :: model_id, exg_id
95  type(STLVecInt) :: model_ids, exchange_ids
96  class(VirtualDataContainerType), pointer :: vdc
97  logical :: found
98 
99  this%nr_solutions = this%nr_solutions + 1
100  virt_sol => this%virtual_solutions(this%nr_solutions)
101 
102  call model_ids%init()
103  call exchange_ids%init()
104 
105  ! build the virtual solution
106  this%solution_ids(this%nr_solutions) = num_sol%id
107  virt_sol%solution_id = num_sol%id
108  virt_sol%numerical_solution => num_sol
109 
110  ! 1) adding all local models with a virtual model counterpart from the solution
111  do im = 1, num_sol%modellist%Count()
112  num_mod => getnumericalmodelfromlist(num_sol%modellist, im)
113  found = .false.
114  do i = 1, virtual_model_list%Count()
116  if (num_mod%id == vdc%id) then
117  found = .true.
118  exit
119  end if
120  end do
121  if (found) then
122  call model_ids%push_back(num_mod%id)
123  end if
124  end do
125 
126  ! 2) adding all local exchanges with a virtual exchange counterpart
127  do ix = 1, num_sol%exchangelist%Count()
128  exg => getdisconnexchangefromlist(num_sol%exchangelist, ix)
129  if (.not. associated(exg)) cycle ! interface model is handled separately
130  found = .false.
131  do i = 1, virtual_exchange_list%Count()
133  if (exg%id == vdc%id) then
134  found = .true.
135  exit
136  end if
137  end do
138  call exchange_ids%push_back_unique(exg%id)
139  end do
140 
141  ! 3) add halo models and exchanges from interface models
142  do ix = 1, num_sol%exchangelist%Count()
143  conn => get_smc_from_list(num_sol%exchangelist, ix)
144  if (.not. associated(conn)) cycle
145 
146  ! it's an interface model based exchanged, get
147  ! halo models and halo exchanges from connection
148  do ihm = 1, conn%halo_models%size
149  model_id = conn%halo_models%at(ihm)
150  call model_ids%push_back_unique(model_id)
151  end do
152  do ihx = 1, conn%halo_exchanges%size
153  exg_id = conn%halo_exchanges%at(ihx)
154  call exchange_ids%push_back_unique(exg_id)
155  end do
156  end do
157 
158  allocate (virt_sol%models(model_ids%size))
159  allocate (virt_sol%exchanges(exchange_ids%size))
160  allocate (virt_sol%interface_map)
161  call virt_sol%interface_map%init(model_ids%size, exchange_ids%size)
162 
163  ! select virtual containers for models/exchanges
164  do i = 1, model_ids%size
165  vdc => get_virtual_model(model_ids%at(i))
166  virt_sol%models(i)%ptr => vdc
167  end do
168  do i = 1, exchange_ids%size
169  vdc => get_virtual_exchange(exchange_ids%at(i))
170  virt_sol%exchanges(i)%ptr => vdc
171  end do
172 
173  ! cleanup
174  call model_ids%destroy()
175  call exchange_ids%destroy()
176 
177  end subroutine vds_add_solution
178 
179  !> @brief Activates models and exchanges in the halo,
180  !! i.e. the ones that have an actual chance of being used
181  subroutine vds_activate_halo(this)
182  class(VirtualDataManagerType) :: this
183  ! local
184  integer(I4B) :: im, ic, ix
185  type(STLVecInt) :: halo_model_ids
186  class(VirtualModelType), pointer :: vm
187  class(VirtualExchangeType), pointer :: ve
188  class(SpatialModelConnectionType), pointer :: conn
189 
190  call halo_model_ids%init()
191 
192  ! add halo models to list with ids (unique)
193  do ic = 1, baseconnectionlist%Count()
195  do im = 1, conn%halo_models%size
196  call halo_model_ids%push_back_unique(conn%halo_models%at(im))
197  end do
198  end do
199 
200  ! deactivate models that are not local, and not in halo
201  do im = 1, virtual_model_list%Count()
203  if (.not. vm%is_local) then
204  if (.not. halo_model_ids%contains(vm%id)) then
205  vm%is_active = .false.
206  end if
207  end if
208  end do
209 
210  ! deactivate exchanges that are not local and outside halo
211  ! (inside halo means both models are part of halo models)
212  do ix = 1, virtual_exchange_list%Count()
214  if (.not. ve%is_local) then
215  if (.not. halo_model_ids%contains(ve%v_model1%id) .or. &
216  .not. halo_model_ids%contains(ve%v_model2%id)) then
217  ve%is_active = .false.
218  end if
219  end if
220  end do
221 
222  this%router%halo_activated = .true.
223 
224  call halo_model_ids%destroy()
225 
226  end subroutine vds_activate_halo
227 
228  !> @brief Compress the halo for all solutions. This will
229  !! activate the mapping tables in the virtual data items
230  !< such that only relevant part of data arrays can be sync'ed
231  subroutine vds_compress_halo(this)
232  use arrayhandlersmodule, only: ifind
233  use inputoutputmodule, only: getunit
234  use simvariablesmodule, only: proc_id
235  use indexmapmodule
236  class(VirtualDataManagerType) :: this
237  ! local
238  integer(I4B) :: ivm, isol, iexg, m_idx
239  integer(I4B) :: outunit
240  character(len=128) :: monitor_file
241  type(VirtualSolutionType), pointer :: virt_sol
242  class(NumericalSolutionType), pointer :: num_sol
243  class(SpatialModelConnectionType), pointer :: conn
244  class(VirtualDataContainerType), pointer :: vdc
245  type(IndexMapType), pointer :: nmap, cmap
246 
247  ! merge the interface maps over this process
248  do isol = 1, this%nr_solutions
249  virt_sol => this%virtual_solutions(isol)
250  num_sol => castasnumericalsolutionclass(virt_sol%numerical_solution)
251  do iexg = 1, num_sol%exchangelist%Count()
252  conn => get_smc_from_list(num_sol%exchangelist, iexg)
253  if (.not. associated(conn)) cycle
254  ! these are interface models, now merge their
255  ! interface maps
256  call virt_sol%interface_map%add(conn%interface_map)
257  end do
258  end do
259 
260  ! some testing
261  if (.false.) then
262  outunit = getunit()
263  write (monitor_file, '(a,i0,a)') "iface.p", proc_id, ".log"
264  open (unit=outunit, file=monitor_file)
265  do isol = 1, this%nr_solutions
266  write (outunit, '(a,i0,/)') "interface map for solution ", &
267  this%virtual_solutions(isol)%solution_id
268  virt_sol => this%virtual_solutions(isol)
269  call virt_sol%interface_map%print_interface(outunit)
270  end do
271  close (outunit)
272  end if
273 
274  ! assign reduced maps to virtual data containers
275  do isol = 1, this%nr_solutions
276  virt_sol => this%virtual_solutions(isol)
277  do ivm = 1, size(virt_sol%models)
278  vdc => virt_sol%models(ivm)%ptr
279  if (.not. vdc%is_local .and. vdc%is_active) then
280  m_idx = ifind(virt_sol%interface_map%model_ids, vdc%id)
281  if (m_idx == -1) cycle
282 
283  nmap => virt_sol%interface_map%get_node_map(vdc%id)
284  cmap => virt_sol%interface_map%get_connection_map(vdc%id)
285  call vdc%set_element_map(nmap%src_idx, map_node_type)
286  call vdc%set_element_map(cmap%src_idx, map_conn_type)
287  end if
288  end do
289  end do
290 
291  end subroutine vds_compress_halo
292 
293  !> @brief Synchronize the full virtual data store for this stage
294  !<
295  subroutine vds_synchronize(this, stage)
296  class(VirtualDataManagerType) :: this !< this vdm
297  integer(I4B) :: stage !< the stage to sync
298 
299  call this%prepare_all(stage)
300  call this%link_all(stage)
301  call this%router%route_all(stage)
302 
303  end subroutine vds_synchronize
304 
305  subroutine prepare_all(this, stage)
306  class(VirtualDataManagerType) :: this
307  integer(I4B) :: stage
308  ! local
309  integer(I4B) :: i
310  class(VirtualDataContainerType), pointer :: vdc
311 
312  ! prepare all virtual data for this stage,
313  ! cycle inactive to avoid redundant mem allocs
314  do i = 1, virtual_model_list%Count()
316  if (.not. vdc%is_active) cycle
317  call vdc%prepare_stage(stage)
318  end do
319  do i = 1, virtual_exchange_list%Count()
321  if (.not. vdc%is_active) cycle
322  call vdc%prepare_stage(stage)
323  end do
324 
325  end subroutine prepare_all
326 
327  subroutine link_all(this, stage)
328  class(VirtualDataManagerType) :: this
329  integer(I4B) :: stage
330  ! local
331  integer(I4B) :: i
332  class(VirtualDataContainerType), pointer :: vdc
333 
334  ! link all local objects
335  do i = 1, virtual_model_list%Count()
337  call vdc%link_items(stage)
338  end do
339  do i = 1, virtual_exchange_list%Count()
341  call vdc%link_items(stage)
342  end do
343 
344  end subroutine link_all
345 
346  !> @brief Synchronize one particular solution for this stage
347  !<
348  subroutine vds_synchronize_sln(this, id_sln, stage)
349  use arrayhandlersmodule, only: ifind
350  class(VirtualDataManagerType) :: this
351  integer(I4B) :: id_sln !< the id of the solution
352  integer(I4B) :: stage
353  ! local
354  integer(I4B) :: sol_idx
355 
356  sol_idx = ifind(this%solution_ids, id_sln)
357  call this%prepare_sln(this%virtual_solutions(sol_idx), stage)
358  call this%link_sln(this%virtual_solutions(sol_idx), stage)
359  call this%router%route_sln(this%virtual_solutions(sol_idx), stage)
360 
361  end subroutine vds_synchronize_sln
362 
363  !> @brief Force the virtual data containers (models,
364  !! exchanges, etc.) to schedule their virtual data
365  !< items for synchronization
366  subroutine prepare_sln(this, virtual_sol, stage)
367  class(VirtualDataManagerType) :: this
368  type(VirtualSolutionType) :: virtual_sol
369  integer(I4B) :: stage
370  ! local
371  integer(I4B) :: i
372  class(VirtualDataContainerType), pointer :: vdc
373 
374  do i = 1, size(virtual_sol%models)
375  vdc => virtual_sol%models(i)%ptr
376  call vdc%prepare_stage(stage)
377  end do
378 
379  do i = 1, size(virtual_sol%exchanges)
380  vdc => virtual_sol%exchanges(i)%ptr
381  call vdc%prepare_stage(stage)
382  end do
383 
384  end subroutine prepare_sln
385 
386  !> @brief Connect virtual memory items to their
387  !< sources when they are local for this stage
388  subroutine link_sln(this, virtual_sol, stage)
389  class(VirtualDataManagerType) :: this
390  type(VirtualSolutionType) :: virtual_sol
391  integer(I4B) :: stage
392  ! local
393  integer(I4B) :: i
394  class(VirtualDataContainerType), pointer :: vdc
395 
396  do i = 1, size(virtual_sol%models)
397  vdc => virtual_sol%models(i)%ptr
398  call vdc%link_items(stage)
399  end do
400 
401  do i = 1, size(virtual_sol%exchanges)
402  vdc => virtual_sol%exchanges(i)%ptr
403  call vdc%link_items(stage)
404  end do
405 
406  end subroutine link_sln
407 
408  !> @brief Returns the number of Numerical Solutions
409  !< in this simulation
410  function count_nr_solutions(this) result(count)
411  use listsmodule, only: basesolutionlist
413  class(VirtualDataManagerType) :: this
414  integer(I4B) :: count
415  ! local
416  integer(I4B) :: isol
417  class(*), pointer :: sol
418 
419  ! count nr. of numerical solutions
420  count = 0
421  do isol = 1, basesolutionlist%Count()
422  sol => basesolutionlist%GetItem(isol)
423  select type (sol)
424  class is (numericalsolutiontype)
425  count = count + 1
426  end select
427  end do
428 
429  end function count_nr_solutions
430 
431  subroutine destroy(this)
432  class(VirtualDataManagerType) :: this
433  ! local
434  integer(I4B) :: i
435  class(VirtualDataContainerType), pointer :: vdc
436 
437  do i = 1, virtual_model_list%Count()
439  call vdc%destroy()
440  end do
441  call virtual_model_list%Clear(destroy=.true.)
442 
443  do i = 1, virtual_exchange_list%Count()
445  call vdc%destroy()
446  end do
447  call virtual_exchange_list%Clear(destroy=.true.)
448 
449  do i = 1, this%nr_solutions
450  deallocate (this%virtual_solutions(i)%models)
451  deallocate (this%virtual_solutions(i)%exchanges)
452  call this%virtual_solutions(i)%interface_map%destroy()
453  deallocate (this%virtual_solutions(i)%interface_map)
454  end do
455  deallocate (this%virtual_solutions)
456 
457  deallocate (this%router)
458 
459  end subroutine destroy
460 
461 end module virtualdatamanagermodule
class(disconnexchangetype) function, pointer, public getdisconnexchangefromlist(list, idx)
integer(i4b) function, public getunit()
Get a free unit number.
This module defines variable data types.
Definition: kind.f90:8
type(listtype), public baseconnectionlist
Definition: mf6lists.f90:28
type(listtype), public basesolutionlist
Definition: mf6lists.f90:19
class(numericalexchangetype) function, pointer, public getnumericalexchangefromlist(list, idx)
Retrieve a specific numerical exchange from a list.
class(numericalmodeltype) function, pointer, public getnumericalmodelfromlist(list, idx)
class(numericalsolutiontype) function, pointer, public castasnumericalsolutionclass(obj)
@ brief Cast a object as a Numerical Solution
class(routerbasetype) function, pointer, public create_router(sim_mode)
@ Brief Create the proper router, depends on simulation mode (parallel or sequential) and type of bui...
This module contains simulation variables.
Definition: SimVariables.f90:9
integer(i4b) proc_id
class(spatialmodelconnectiontype) function, pointer, public get_smc_from_list(list, idx)
Get the connection from a list.
subroutine destroy(this)
Definition: STLVecInt.f90:170
integer(i4b), parameter, public map_conn_type
Definition: VirtualBase.f90:15
integer(i4b), parameter, public map_node_type
Definition: VirtualBase.f90:14
class(virtualdatacontainertype) function, pointer, public get_vdc_from_list(list, idx)
type(listtype), public virtual_model_list
type(listtype), public virtual_exchange_list
class(virtualexchangetype) function, pointer, public get_virtual_exchange_from_list(list, idx)
class(virtualexchangetype) function, pointer, public get_virtual_exchange(exg_id)
Returns a virtual exchange with the specified id.
class(virtualmodeltype) function, pointer, public get_virtual_model_from_list(model_list, idx)
Exchange based on connection between discretizations of DisBaseType. The data specifies the connectio...
Class to manage spatial connection of a model to one or more models of the same type....
The Virtual Exchange is based on two Virtual Models and is therefore not always strictly local or rem...