MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
VirtualDataContainer.f90
Go to the documentation of this file.
3  use simmodule, only: ustop
4  use listmodule
5  use kindmodule, only: i4b, lgp
10  implicit none
11  private
12 
13  public :: get_vdc_from_list
14  public :: vdc_type_to_str
15 
16  integer(I4B), public, parameter :: vdc_unknown_type = 0
17  integer(I4B), public, parameter :: vdc_gwfmodel_type = 1
18  integer(I4B), public, parameter :: vdc_gwtmodel_type = 2
19  integer(I4B), public, parameter :: vdc_gwemodel_type = 3
20  integer(I4B), public, parameter :: vdc_gwfexg_type = 4
21  integer(I4B), public, parameter :: vdc_gwtexg_type = 5
22  integer(I4B), public, parameter :: vdc_gweexg_type = 6
23  integer(I4B), public, parameter :: vdc_gwfmvr_type = 7
24  integer(I4B), public, parameter :: vdc_gwtmvt_type = 8
25  integer(I4B), public, parameter :: vdc_gwemve_type = 9
26 
27  !> @brief Wrapper for virtual data containers
28  !!
29  !! We can't have an array of pointers in Fortran, so we use
30  !! this trick where we wrap the pointer and have an array
31  !< of VdcPtrType instead.
32  type, public :: vdcptrtype
33  class(virtualdatacontainertype), pointer :: ptr => null()
34  end type vdcptrtype
35 
36  type, public :: vdcelementmaptype
37  integer(I4B) :: nr_virt_elems !< nr. of virtualized elements
38  integer(I4B), dimension(:), pointer, contiguous :: remote_elem_shift => null() !< array with 0-based remote indexes
39  end type vdcelementmaptype
40 
42  integer(I4B) :: max_remote_idx !< max. remote index, also size of the lookup table
43  integer(I4B), dimension(:), pointer, contiguous :: remote_to_virtual => null() !< (sparse) array with local indexes
44  end type vdcelementluttype
45 
46  !> @brief Container (list) of virtual data items.
47  !!
48  !! A virtual model or exchange derives from this base
49  !! and can add the component-specific items to the list
50  !! of virtual data items. As far as synchronization
51  !! of virtual objects is concerned, all that is needed
52  !< is the list of virtual data items in this container.
53  type, public :: virtualdatacontainertype
54  integer(I4B) :: id !< unique identifier matching with the real counterpart
55  integer(I4B) :: container_type !< to identify the actual type of this container
56  character(LENCOMPONENTNAME) :: name !< container name (model, exchange, ...) used in the memory path
57  character(LENCONTEXTNAME) :: vmem_ctx !< prefixes virtual memory located on remote processes
58  logical(LGP) :: is_local !< when true, the physical object resides on the same process. However,
59  !! some of its variables can still be remote
60  logical(LGP) :: is_active !< when true, this container is being synchronized
61  integer(I4B) :: orig_rank !< the global rank of the process which holds the physical data for this container,
62  !< for exchanges this is set to be where model1 sits, or if model1 is local,
63  !< where model2 sits
64  type(stlvecint) :: rcv_ranks !< the ranks of processes, other than orig_rank, having this container active
65  !< (only guaranteed to be complete after synchronization)
66 
67  type(listtype) :: virtual_data_list !< a list with all virtual data items for this container
68  type(vdcelementmaptype), dimension(NR_VDC_ELEMENT_MAPS) :: element_maps !< a list with all element maps
69  type(vdcelementluttype), dimension(NR_VDC_ELEMENT_MAPS) :: element_luts !< lookup tables from remote index to local index
70  contains
71  procedure :: vdc_create
72  generic :: map => map_scalar, map_array1d, map_array2d
73  procedure :: prepare_stage => vdc_prepare_stage
74  procedure :: link_items => vdc_link_items
75  procedure :: set_element_map => vdc_set_element_map
76  procedure :: get_vrt_mem_path => vdc_get_vrt_mem_path
77  procedure :: destroy => vdc_destroy
78  procedure :: set_orig_rank => vdc_set_orig_rank
79  procedure :: get_send_items => vdc_get_send_items
80  procedure :: get_recv_items => vdc_get_recv_items
81  procedure :: get_virtual_data => vdc_get_virtual_data
82  procedure :: print_items
83  ! protected
84  procedure :: set
85  ! private
86  procedure, private :: add_to_list
87  procedure, private :: map_scalar
88  procedure, private :: map_array1d
89  procedure, private :: map_array2d
90  procedure, private :: map_internal
91  procedure, private :: vdc_get_virtual_data
92  procedure, private :: get_items_for_stage
94 
95 contains
96 
97  subroutine vdc_create(this, name, id, is_local)
98  class(virtualdatacontainertype) :: this
99  character(len=*) :: name
100  integer(I4B) :: id
101  logical(LGP) :: is_local
102  ! local
103  integer(I4B) :: i
104 
105  this%name = name
106  this%id = id
107  this%is_local = is_local
108  this%vmem_ctx = 'undefined'
109  this%orig_rank = 0
110  this%is_active = .true.
111  this%container_type = vdc_unknown_type
112 
113  do i = 1, size(this%element_maps)
114  this%element_maps(i)%nr_virt_elems = 0
115  this%element_maps(i)%remote_elem_shift => null()
116  end do
117  do i = 1, size(this%element_luts)
118  this%element_luts(i)%max_remote_idx = 0
119  this%element_luts(i)%remote_to_virtual => null()
120  end do
121 
122  call this%rcv_ranks%init()
123 
124  end subroutine vdc_create
125 
126  !> @brief Init virtual data item, without allocation,
127  !! and store it in this container. The 'is_local' flag
128  !! makes it possible to mark some fields local in an
129  !< otherwise fully remote container, or v.v.
130  subroutine set(this, field, var_name, subcmp_name, map_id, is_local)
131  class(virtualdatacontainertype) :: this
132  class(virtualdatatype), pointer :: field
133  character(len=*) :: var_name
134  character(len=*) :: subcmp_name
135  integer(I4B) :: map_id
136  logical(LGP), optional :: is_local
137 
138  field%is_remote = .not. this%is_local
139  field%map_type = map_id
140  if (present(is_local)) field%is_remote = .not. is_local
141  field%var_name = var_name
142  field%subcmp_name = subcmp_name
143  if (subcmp_name == '') then
144  field%mem_path = create_mem_path(this%name)
145  else
146  field%mem_path = create_mem_path(this%name, subcmp_name)
147  end if
148  field%is_reduced = (field%is_remote .and. field%map_type > 0)
149  field%remote_elem_shift => null()
150  field%remote_to_virtual => null()
151  field%virtual_mt => null()
152  call this%add_to_list(field)
153 
154  end subroutine set
155 
156  subroutine add_to_list(this, virtual_data)
157  class(virtualdatacontainertype) :: this
158  class(virtualdatatype), pointer :: virtual_data
159  ! local
160  class(*), pointer :: vdata_ptr
161 
162  vdata_ptr => virtual_data
163  call this%virtual_data_list%Add(vdata_ptr)
164 
165  end subroutine add_to_list
166 
167  subroutine vdc_prepare_stage(this, stage)
168  use simmodule, only: ustop
169  class(virtualdatacontainertype) :: this
170  integer(I4B) :: stage
171 
172  write (*, *) 'Error: prepare_stage should be overridden'
173  call ustop()
174 
175  end subroutine vdc_prepare_stage
176 
177  !> @brief Link all local data items to memory
178  !<
179  subroutine vdc_link_items(this, stage)
180  class(virtualdatacontainertype) :: this
181  integer(I4B) :: stage
182  ! local
183  integer(I4B) :: i
184  class(*), pointer :: vdi
185 
186  do i = 1, this%virtual_data_list%Count()
187  vdi => this%virtual_data_list%GetItem(i)
188  select type (vdi)
189  class is (virtualdatatype)
190  if (vdi%is_remote) cycle
191  if (vdi%check_stage(stage)) call vdi%link()
192  end select
193  end do
194 
195  end subroutine vdc_link_items
196 
197  !> @brief Add the source indexes associated with map_id
198  !! as a element map to this container, such that
199  !< src_indexes(1:n) = (i_orig_1 - 1, ..., i_orig_n - 1)
200  subroutine vdc_set_element_map(this, src_indexes, map_id)
201  class(virtualdatacontainertype) :: this
202  integer(I4B), dimension(:), pointer, contiguous :: src_indexes
203  integer(I4B) :: map_id
204  ! local
205  integer(I4B) :: i, idx_remote, max_remote_idx
206 
207  if (this%element_maps(map_id)%nr_virt_elems > 0) then
208  write (*, *) "Error, VDC element map already set"
209  call ustop()
210  end if
211 
212  this%element_maps(map_id)%nr_virt_elems = size(src_indexes)
213  allocate (this%element_maps(map_id)%remote_elem_shift(size(src_indexes)))
214  do i = 1, size(src_indexes)
215  this%element_maps(map_id)%remote_elem_shift(i) = src_indexes(i) - 1
216  end do
217 
218  max_remote_idx = maxval(src_indexes)
219  this%element_luts(map_id)%max_remote_idx = max_remote_idx
220  allocate (this%element_luts(map_id)%remote_to_virtual(max_remote_idx))
221  do i = 1, max_remote_idx
222  this%element_luts(map_id)%remote_to_virtual(i) = -1
223  end do
224  do i = 1, size(src_indexes)
225  idx_remote = src_indexes(i)
226  this%element_luts(map_id)%remote_to_virtual(idx_remote) = i
227  end do
228 
229  end subroutine vdc_set_element_map
230 
231  subroutine map_scalar(this, vd, stages)
232  class(virtualdatacontainertype) :: this
233  class(virtualdatatype), pointer :: vd
234  integer(I4B), dimension(:) :: stages
235 
236  call this%map_internal(vd, (/0/), stages)
237 
238  end subroutine map_scalar
239 
240  subroutine map_array1d(this, vd, nrow, stages)
241  class(virtualdatacontainertype) :: this
242  class(virtualdatatype), pointer :: vd
243  integer(I4B) :: nrow
244  integer(I4B), dimension(:) :: stages
245 
246  call this%map_internal(vd, (/nrow/), stages)
247 
248  end subroutine map_array1d
249 
250  subroutine map_array2d(this, vd, ncol, nrow, stages)
251  class(virtualdatacontainertype) :: this
252  class(virtualdatatype), pointer :: vd
253  integer(I4B) :: ncol
254  integer(I4B) :: nrow
255  integer(I4B), dimension(:) :: stages
256 
257  call this%map_internal(vd, (/ncol, nrow/), stages)
258 
259  end subroutine map_array2d
260 
261  subroutine map_internal(this, vd, shape, stages)
262  class(virtualdatacontainertype) :: this
263  class(virtualdatatype), pointer :: vd
264  integer(I4B), dimension(:) :: shape
265  integer(I4B), dimension(:) :: stages
266  ! local
267  character(len=LENMEMPATH) :: vm_pth
268  logical(LGP) :: found
269 
270  vd%sync_stages = stages
271  if (vd%is_remote) then
272  ! create new virtual memory item
273  vm_pth = this%get_vrt_mem_path(vd%var_name, vd%subcmp_name)
274  call vd%vm_allocate(vd%var_name, vm_pth, shape)
275  call get_from_memorystore(vd%var_name, vm_pth, vd%virtual_mt, found)
276  if (vd%map_type > 0) then
277  vd%remote_to_virtual => this%element_luts(vd%map_type)%remote_to_virtual
278  vd%remote_elem_shift => this%element_maps(vd%map_type)%remote_elem_shift
279  end if
280  end if
281 
282  end subroutine map_internal
283 
284  !> @brief Get indexes of virtual data items to be
285  !< sent for a given stage and rank
286  subroutine vdc_get_send_items(this, stg, rank, vi)
287  class(virtualdatacontainertype) :: this
288  integer(I4B) :: stg
289  integer(I4B) :: rank
290  type(stlvecint) :: vi
291 
292  call this%get_items_for_stage(stg, vi)
293 
294  end subroutine vdc_get_send_items
295 
296  !> @brief Get indexes of virtual data items to be
297  !< received for a given stage and rank
298  subroutine vdc_get_recv_items(this, stg, rank, vi)
299  class(virtualdatacontainertype) :: this
300  integer(I4B) :: stg
301  integer(I4B) :: rank
302  type(stlvecint) :: vi
303 
304  call this%get_items_for_stage(stg, vi)
305 
306  end subroutine vdc_get_recv_items
307 
308  subroutine get_items_for_stage(this, stage, virtual_items)
309  class(virtualdatacontainertype) :: this
310  integer(I4B) :: stage
311  type(stlvecint) :: virtual_items
312  ! local
313  integer(I4B) :: i
314  class(*), pointer :: obj_ptr
315 
316  do i = 1, this%virtual_data_list%Count()
317  obj_ptr => this%virtual_data_list%GetItem(i)
318  select type (obj_ptr)
319  class is (virtualdatatype)
320  if (.not. obj_ptr%check_stage(stage)) cycle
321  call virtual_items%push_back(i)
322  end select
323  end do
324 
325  end subroutine get_items_for_stage
326 
327  subroutine print_items(this, imon, items)
328  class(virtualdatacontainertype) :: this
329  integer(I4B) :: imon
330  type(stlvecint) :: items
331  ! local
332  integer(I4B) :: i
333  class(virtualdatatype), pointer :: vdi
334 
335  write (imon, *) "=====> items"
336  do i = 1, items%size
337  vdi => get_virtual_data_from_list(this%virtual_data_list, items%at(i))
338  write (imon, *) vdi%var_name, ":", vdi%mem_path
339  end do
340  if (items%size == 0) then
341  write (imon, *) "... empty ...", this%name
342  end if
343  write (imon, *) "<===== items"
344 
345  end subroutine print_items
346 
347  !> @brief Get virtual memory path for a certain variable
348  !<
349  function vdc_get_vrt_mem_path(this, var_name, subcomp_name) result(vrt_path)
350  class(virtualdatacontainertype) :: this
351  character(len=*) :: var_name
352  character(len=*) :: subcomp_name
353  character(len=LENMEMPATH) :: vrt_path
354  ! local
355  class(virtualdatatype), pointer :: vdi
356 
357  vdi => this%vdc_get_virtual_data(var_name, subcomp_name)
358  if (vdi%is_remote) then
359  if (subcomp_name == '') then
360  vrt_path = create_mem_path(this%name, context=this%vmem_ctx)
361  else
362  vrt_path = create_mem_path(this%name, subcomp_name, context=this%vmem_ctx)
363  end if
364  else
365  if (subcomp_name == '') then
366  vrt_path = create_mem_path(this%name)
367  else
368  vrt_path = create_mem_path(this%name, subcomp_name)
369  end if
370  end if
371 
372  end function vdc_get_vrt_mem_path
373 
374  function vdc_get_virtual_data(this, var_name, subcomp_name) result(virtual_data)
375  use simmodule, only: ustop
376  class(virtualdatacontainertype) :: this
377  character(len=*) :: var_name
378  character(len=*) :: subcomp_name
379  class(virtualdatatype), pointer :: virtual_data
380  ! local
381  integer(I4B) :: i
382  class(virtualdatatype), pointer :: vd
383 
384  virtual_data => null()
385  do i = 1, this%virtual_data_list%Count()
386  vd => get_virtual_data_from_list(this%virtual_data_list, i)
387  if (vd%var_name == var_name .and. &
388  vd%subcmp_name == subcomp_name) then
389  virtual_data => vd
390  return
391  end if
392  end do
393 
394  write (*, *) 'Error: unknown virtual variable ', var_name, ' ', subcomp_name
395  call ustop()
396 
397  end function vdc_get_virtual_data
398 
399  subroutine vdc_destroy(this)
400  class(virtualdatacontainertype) :: this
401  ! local
402  integer(I4B) :: i
403  class(*), pointer :: obj
404 
405  call this%rcv_ranks%destroy()
406 
407  do i = 1, size(this%element_maps)
408  if (associated(this%element_maps(i)%remote_elem_shift)) then
409  deallocate (this%element_maps(i)%remote_elem_shift)
410  end if
411  end do
412  do i = 1, size(this%element_luts)
413  if (associated(this%element_luts(i)%remote_to_virtual)) then
414  deallocate (this%element_luts(i)%remote_to_virtual)
415  end if
416  end do
417 
418  do i = 1, this%virtual_data_list%Count()
419  obj => this%virtual_data_list%GetItem(i)
420  select type (obj)
421  class is (virtualdatatype)
422  if (associated(obj%virtual_mt)) then
423  call obj%vm_deallocate()
424  end if
425  end select
426  end do
427  call this%virtual_data_list%Clear()
428 
429  end subroutine vdc_destroy
430 
431  subroutine vdc_set_orig_rank(this, rank)
432  class(virtualdatacontainertype) :: this
433  integer(I4B) :: rank
434 
435  this%orig_rank = rank
436  write (this%vmem_ctx, '(a,i0,a)') '__P', rank, '__'
437 
438  end subroutine vdc_set_orig_rank
439 
440  function get_vdc_from_list(list, idx) result(vdc)
441  type(listtype) :: list
442  integer(I4B) :: idx
443  class(virtualdatacontainertype), pointer :: vdc
444  ! local
445  class(*), pointer :: obj_ptr
446 
447  vdc => null()
448  obj_ptr => list%GetItem(idx)
449  select type (obj_ptr)
450  class is (virtualdatacontainertype)
451  vdc => obj_ptr
452  end select
453 
454  end function get_vdc_from_list
455 
456  !> @ Converts a virtual container type to its string representation
457  !<
458  function vdc_type_to_str(cntr_type) result(cntr_str)
459  integer(I4B) :: cntr_type
460  character(len=24) :: cntr_str
461 
462  if (cntr_type == vdc_unknown_type) then; cntr_str = "unknown"
463  else if (cntr_type == vdc_gwfmodel_type) then; cntr_str = "GWF Model"
464  else if (cntr_type == vdc_gwtmodel_type) then; cntr_str = "GWT Model"
465  else if (cntr_type == vdc_gwemodel_type) then; cntr_str = "GWE Model"
466  else if (cntr_type == vdc_gwfexg_type) then; cntr_str = "GWF Exchange"
467  else if (cntr_type == vdc_gwtexg_type) then; cntr_str = "GWT Exchange"
468  else if (cntr_type == vdc_gweexg_type) then; cntr_str = "GWE Exchange"
469  else if (cntr_type == vdc_gwfmvr_type) then; cntr_str = "GWF Mover"
470  else if (cntr_type == vdc_gwtmvt_type) then; cntr_str = "GWT Mover"
471  else if (cntr_type == vdc_gwemve_type) then; cntr_str = "GWE Mover"
472  else; cntr_str = "Undefined"
473  end if
474 
475  end function vdc_type_to_str
476 
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter lencomponentname
maximum length of a component name
Definition: Constants.f90:18
integer(i4b), parameter lencontextname
maximum length of a memory manager context
Definition: Constants.f90:19
integer(i4b), parameter lenmempath
maximum length of the memory path
Definition: Constants.f90:27
This module defines variable data types.
Definition: kind.f90:8
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
subroutine, public get_from_memorystore(name, mem_path, mt, found, check)
@ brief Get a memory type entry from the memory list
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public ustop(stopmess, ioutlocal)
Stop the simulation.
Definition: Sim.f90:312
subroutine destroy(this)
Definition: STLVecInt.f90:183
class(virtualdatatype) function, pointer, public get_virtual_data_from_list(list, idx)
class(virtualdatatype) function, pointer vdc_get_virtual_data(this, var_name, subcomp_name)
integer(i4b), parameter, public vdc_gwtmodel_type
subroutine vdc_create(this, name, id, is_local)
integer(i4b), parameter, public vdc_gwtmvt_type
subroutine map_internal(this, vd, shape, stages)
subroutine set(this, field, var_name, subcmp_name, map_id, is_local)
Init virtual data item, without allocation, and store it in this container. The 'is_local' flag makes...
integer(i4b), parameter, public vdc_gwemodel_type
character(len=24) function, public vdc_type_to_str(cntr_type)
@ Converts a virtual container type to its string representation
subroutine map_array2d(this, vd, ncol, nrow, stages)
subroutine vdc_link_items(this, stage)
Link all local data items to memory.
subroutine vdc_get_recv_items(this, stg, rank, vi)
Get indexes of virtual data items to be.
subroutine map_scalar(this, vd, stages)
subroutine vdc_set_element_map(this, src_indexes, map_id)
Add the source indexes associated with map_id as a element map to this container, such that.
subroutine add_to_list(this, virtual_data)
integer(i4b), parameter, public vdc_gwfmvr_type
integer(i4b), parameter, public vdc_unknown_type
character(len=lenmempath) function vdc_get_vrt_mem_path(this, var_name, subcomp_name)
Get virtual memory path for a certain variable.
subroutine vdc_set_orig_rank(this, rank)
integer(i4b), parameter, public vdc_gwemve_type
of VdcPtrType instead.
subroutine vdc_prepare_stage(this, stage)
subroutine vdc_get_send_items(this, stg, rank, vi)
Get indexes of virtual data items to be.
integer(i4b), parameter, public vdc_gwfmodel_type
subroutine print_items(this, imon, items)
integer(i4b), parameter, public vdc_gwtexg_type
class(virtualdatacontainertype) function, pointer, public get_vdc_from_list(list, idx)
subroutine map_array1d(this, vd, nrow, stages)
integer(i4b), parameter, public vdc_gwfexg_type
integer(i4b), parameter, public vdc_gweexg_type
subroutine get_items_for_stage(this, stage, virtual_items)
A generic heterogeneous doubly-linked list.
Definition: List.f90:14
This is a generic data structure to virtualize pieces of memory in 2 distinct ways:
Definition: VirtualBase.f90:35
Wrapper for virtual data containers.