MODFLOW 6  version 6.8.0.dev0
USGS Modular Hydrologic Model
VirtualExchange.f90
Go to the documentation of this file.
5  use kindmodule, only: i4b, lgp
6  use listmodule, only: listtype
10  implicit none
11  private
12 
13  public :: get_virtual_exchange
15  private :: cast_as_virtual_exchange
16 
17  !> The Virtual Exchange is based on two Virtual Models
18  !! and is therefore not always strictly local or remote.
19  !! We have to consider three different cases:
20  !!
21  !! 1) both virtual models are local
22  !!
23  !! RECV: In this case this virtual data container will have
24  !! no data items to receive from other processes.
25  !! SEND: Whenever it is called to send its virtual data items
26  !! to other processes, it simply sends everything.
27  !!
28  !! 2) one model is local, one model is remote
29  !!
30  !! Consequently, there is another exchange which
31  !! has the reverse, we call this our _dual_ exchange.
32  !!
33  !! RECV: The sender is our dual exchange, and we have all data
34  !! except its list of reduced model node numbers, either
35  !! this%nodem1 or this%nodem2. We receive the missing
36  !! array. Receiving from a sender that is not the dual
37  !! exchange cannot occur.
38  !!
39  !! SEND: here we have to consider two cases
40  !! a) The receiver is our dual exchange, we return the favor
41  !! and send the list of model node numbers that is present
42  !! on this process, this
43  !! would be either this%nodem1 or this%nodem2
44  !! b) The receiver is not the dual exchange. And here we will
45  !! send everything.
46  !!
47  !! 3) both models are remote
48  !!
49  !! RECV: we will receive everything. In case the source
50  !! exchange is fully local, i.e. type 1) above, we get
51  !! all the data at the first attempt. Otherwise, it will
52  !! take a second attempt before all the data is in.
53  !! (To allow for two attempts, the nodem1 and nodem2
54  !! arrays are registered to be synchronized at two
55  !! consecutive stages)
56  !!
57  !! SEND: nothing to be sent.
58  !!
59  !! Exchange mover data follows the pattern described above for nodem1/m2
60  !! except that when both models are remote, none of the mover data is
61  !! will be synchronized.
62  !!
63  !! This behavior is different from the general VirtualDataContainer,
64  !! so the get_send_items and get_recv_items subroutines are
65  !! overridden accordingly.
66  !! Additionally, for case 2) the container will have a mix of
67  !< local and remote virtual data items.
69  class(virtualmodeltype), pointer :: v_model1 => null()
70  class(virtualmodeltype), pointer :: v_model2 => null()
71  ! scalars
72  type(virtualinttype), pointer :: nexg => null()
73  type(virtualinttype), pointer :: naux => null()
74  type(virtualinttype), pointer :: ianglex => null()
75  ! arrays
76  type(virtualint1dtype), pointer :: nodem1 => null()
77  type(virtualint1dtype), pointer :: nodem2 => null()
78  type(virtualint1dtype), pointer :: ihc => null()
79  type(virtualdbl1dtype), pointer :: cl1 => null()
80  type(virtualdbl1dtype), pointer :: cl2 => null()
81  type(virtualdbl1dtype), pointer :: hwva => null()
82  type(virtualdbl2dtype), pointer :: auxvar => null()
83  contains
84  procedure :: create => vx_create
85  procedure :: prepare_stage => vx_prepare_stage
86  procedure :: get_send_items => vx_get_send_items
87  procedure :: get_recv_items => vx_get_recv_items
88  procedure :: has_mover => vx_has_mover
89  procedure :: destroy => vx_destroy
90  ! protected
91  procedure :: add_vdi_for_stage
92  ! private
93  procedure, private :: init_virtual_data
94  procedure, private :: allocate_data
95  procedure, private :: deallocate_data
96  end type virtualexchangetype
97 
98 contains
99 
100  !> @brief Create the virtual exchange base
101  !<
102  subroutine vx_create(this, name, exg_id, m1_id, m2_id)
103  class(virtualexchangetype) :: this
104  character(len=*) :: name
105  integer(I4B) :: exg_id
106  integer(I4B) :: m1_id
107  integer(I4B) :: m2_id
108  ! local
109  logical(LGP) :: is_local
110 
111  this%v_model1 => get_virtual_model(m1_id)
112  this%v_model2 => get_virtual_model(m2_id)
113 
114  ! 1) both models local: is_local = true
115  ! 2) only one of them: is_local = true
116  ! 3) both models remote: is_local = false
117  is_local = this%v_model1%is_local .or. this%v_model2%is_local
118  call this%VirtualDataContainerType%vdc_create(name, exg_id, is_local)
119 
120  call this%allocate_data()
121  call this%init_virtual_data()
122 
123  end subroutine vx_create
124 
125  subroutine init_virtual_data(this)
126  class(virtualexchangetype) :: this
127  ! local
128 
129  call this%set(this%nexg%base(), 'NEXG', '', map_all_type)
130  call this%set(this%naux%base(), 'NAUX', '', map_all_type)
131  call this%set(this%ianglex%base(), 'IANGLEX', '', map_all_type)
132 
133  ! exchanges can be hybrid with both local and remote
134  ! fields, nodem1/2 array only local when corresponding
135  ! model sits on the same process, so we pass the
136  ! optional "is_local" argument to the following:
137  call this%set(this%nodem1%base(), 'NODEM1', '', &
138  map_all_type, this%v_model1%is_local)
139  call this%set(this%nodem2%base(), 'NODEM2', '', &
140  map_all_type, this%v_model2%is_local)
141 
142  call this%set(this%ihc%base(), 'IHC', '', map_all_type)
143  call this%set(this%cl1%base(), 'CL1', '', map_all_type)
144  call this%set(this%cl2%base(), 'CL2', '', map_all_type)
145  call this%set(this%hwva%base(), 'HWVA', '', map_all_type)
146  call this%set(this%auxvar%base(), 'AUXVAR', '', map_all_type)
147 
148  end subroutine init_virtual_data
149 
150  subroutine vx_prepare_stage(this, stage)
151  class(virtualexchangetype) :: this
152  integer(I4B) :: stage
153  ! local
154  integer(I4B) :: nexg, naux
155 
156  if (stage == stg_aft_exg_df) then
157 
158  call this%map(this%nexg%base(), (/stg_aft_exg_df/))
159  call this%map(this%naux%base(), (/stg_aft_exg_df/))
160  call this%map(this%ianglex%base(), (/stg_aft_exg_df/))
161 
162  else if (stage == stg_aft_con_cr) then
163 
164  nexg = this%nexg%get()
165  naux = this%naux%get()
166  call this%map(this%nodem1%base(), nexg, (/stg_aft_con_cr, &
167  stg_bfr_con_df/))
168  call this%map(this%nodem2%base(), nexg, (/stg_aft_con_cr, &
169  stg_bfr_con_df/))
170  call this%map(this%ihc%base(), nexg, (/stg_aft_con_cr/))
171  call this%map(this%cl1%base(), nexg, (/stg_aft_con_cr/))
172  call this%map(this%cl2%base(), nexg, (/stg_aft_con_cr/))
173  call this%map(this%hwva%base(), nexg, (/stg_aft_con_cr/))
174  call this%map(this%auxvar%base(), naux, nexg, (/stg_aft_con_cr/))
175 
176  end if
177 
178  end subroutine vx_prepare_stage
179 
180  subroutine vx_get_recv_items(this, stg, rank, vi)
181  class(virtualexchangetype) :: this
182  integer(I4B) :: stg
183  integer(I4B) :: rank
184  type(stlvecint) :: vi
185 
186  if (this%is_local .and. rank == this%orig_rank) then
187  ! treat the primary exchange case independently, we
188  ! have all data available except for nodem1 or nodem2
189  if (stg < stg_bfr_con_df) then
190  if (this%nodem1%is_remote) then
191  call this%add_vdi_for_stage(this%nodem1%base(), stg, vi)
192  end if
193  if (this%nodem2%is_remote) then
194  call this%add_vdi_for_stage(this%nodem2%base(), stg, vi)
195  end if
196  end if
197  else
198  ! send/receive all
199  call this%add_vdi_for_stage(this%nexg%base(), stg, vi)
200  call this%add_vdi_for_stage(this%naux%base(), stg, vi)
201  call this%add_vdi_for_stage(this%ianglex%base(), stg, vi)
202  call this%add_vdi_for_stage(this%nodem1%base(), stg, vi)
203  call this%add_vdi_for_stage(this%nodem2%base(), stg, vi)
204  call this%add_vdi_for_stage(this%ihc%base(), stg, vi)
205  call this%add_vdi_for_stage(this%cl1%base(), stg, vi)
206  call this%add_vdi_for_stage(this%cl2%base(), stg, vi)
207  call this%add_vdi_for_stage(this%hwva%base(), stg, vi)
208  call this%add_vdi_for_stage(this%auxvar%base(), stg, vi)
209  end if
210 
211  end subroutine vx_get_recv_items
212 
213  subroutine vx_get_send_items(this, stg, rank, vi)
214  class(virtualexchangetype) :: this
215  integer(I4B) :: stg
216  integer(I4B) :: rank
217  type(stlvecint) :: vi
218 
219  if (this%is_local .and. rank == this%orig_rank) then
220  ! this is a primary exchange, all we need to send are
221  ! the node numbers nodem1 or nodem2
222  if (stg < stg_bfr_con_df) then
223  if (.not. this%nodem1%is_remote) then
224  call this%add_vdi_for_stage(this%nodem1%base(), stg, vi)
225  end if
226  if (.not. this%nodem2%is_remote) then
227  call this%add_vdi_for_stage(this%nodem2%base(), stg, vi)
228  end if
229  end if
230  else
231  ! send/receive all
232  call this%add_vdi_for_stage(this%nexg%base(), stg, vi)
233  call this%add_vdi_for_stage(this%naux%base(), stg, vi)
234  call this%add_vdi_for_stage(this%ianglex%base(), stg, vi)
235  call this%add_vdi_for_stage(this%nodem1%base(), stg, vi)
236  call this%add_vdi_for_stage(this%nodem2%base(), stg, vi)
237  call this%add_vdi_for_stage(this%ihc%base(), stg, vi)
238  call this%add_vdi_for_stage(this%cl1%base(), stg, vi)
239  call this%add_vdi_for_stage(this%cl2%base(), stg, vi)
240  call this%add_vdi_for_stage(this%hwva%base(), stg, vi)
241  call this%add_vdi_for_stage(this%auxvar%base(), stg, vi)
242  end if
243 
244  end subroutine vx_get_send_items
245 
246  !> @brief Convenience routine to add virtual data item to a list
247  !< after checking the stage
248  subroutine add_vdi_for_stage(this, vdata_item, stage, virtual_items)
249  class(virtualexchangetype) :: this
250  class(virtualdatatype), pointer :: vdata_item
251  integer(I4B) :: stage
252  type(stlvecint) :: virtual_items
253  ! local
254  class(*), pointer :: vdi
255  integer(I4B) :: idx
256 
257  vdi => vdata_item
258  idx = this%virtual_data_list%GetIndex(vdi)
259  if (vdata_item%check_stage(stage)) then
260  call virtual_items%push_back(idx)
261  end if
262 
263  end subroutine add_vdi_for_stage
264 
265  !> @brief Checks if there is an active mover in the exchange
266  !<
267  function vx_has_mover(this) result(has_mover)
268  class(virtualexchangetype) :: this
269  logical(LGP) :: has_mover
270 
271  has_mover = .false.
272 
273  end function vx_has_mover
274 
275  subroutine vx_destroy(this)
276  class(virtualexchangetype) :: this
277 
278  call this%VirtualDataContainerType%destroy()
279  call this%deallocate_data()
280 
281  end subroutine vx_destroy
282 
283  subroutine allocate_data(this)
284  class(virtualexchangetype) :: this
285 
286  allocate (this%nexg)
287  allocate (this%naux)
288  allocate (this%ianglex)
289  allocate (this%nodem1)
290  allocate (this%nodem2)
291  allocate (this%ihc)
292  allocate (this%cl1)
293  allocate (this%cl2)
294  allocate (this%hwva)
295  allocate (this%auxvar)
296 
297  end subroutine allocate_data
298 
299  subroutine deallocate_data(this)
300  class(virtualexchangetype) :: this
301 
302  deallocate (this%nexg)
303  deallocate (this%naux)
304  deallocate (this%ianglex)
305  deallocate (this%nodem1)
306  deallocate (this%nodem2)
307  deallocate (this%ihc)
308  deallocate (this%cl1)
309  deallocate (this%cl2)
310  deallocate (this%hwva)
311  deallocate (this%auxvar)
312 
313  end subroutine deallocate_data
314 
315  !> @brief Returns a virtual exchange with the specified id
316  !< from the global list
317  function get_virtual_exchange(exg_id) result(virtual_exg)
319  integer(I4B) :: exg_id
320  class(virtualexchangetype), pointer :: virtual_exg
321  ! local
322  integer(I4B) :: i
323  class(*), pointer :: ve
324 
325  virtual_exg => null()
326  do i = 1, virtual_exchange_list%Count()
327  ve => virtual_exchange_list%GetItem(i)
328  select type (ve)
329  class is (virtualexchangetype)
330  if (ve%id == exg_id) then
331  virtual_exg => ve
332  return
333  end if
334  end select
335  end do
336 
337  end function get_virtual_exchange
338 
339  function get_virtual_exchange_from_list(list, idx) result(virtual_exg)
340  type(listtype) :: list
341  integer(I4B) :: idx
342  class(virtualexchangetype), pointer :: virtual_exg
343  ! local
344  class(*), pointer :: obj_ptr
345 
346  obj_ptr => list%GetItem(idx)
347  virtual_exg => cast_as_virtual_exchange(obj_ptr)
348 
349  end function get_virtual_exchange_from_list
350 
351  function cast_as_virtual_exchange(obj_ptr) result(virtual_exg)
352  class(*), pointer :: obj_ptr
353  class(virtualexchangetype), pointer :: virtual_exg
354 
355  virtual_exg => null()
356  select type (obj_ptr)
357  class is (virtualexchangetype)
358  virtual_exg => obj_ptr
359  end select
360 
361  end function cast_as_virtual_exchange
362 
363 end module virtualexchangemodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter lenexchangename
maximum length of the exchange name
Definition: Constants.f90:24
This module defines variable data types.
Definition: kind.f90:8
integer(i4b), parameter, public stg_aft_exg_df
after exchange define
Definition: SimStages.f90:12
integer(i4b), parameter, public stg_aft_con_cr
after connection create
Definition: SimStages.f90:13
integer(i4b), parameter, public stg_bfr_con_df
before connection define
Definition: SimStages.f90:14
subroutine destroy(this)
Definition: STLVecInt.f90:183
integer(i4b), parameter, public map_all_type
Definition: VirtualBase.f90:13
type(listtype), public virtual_exchange_list
subroutine deallocate_data(this)
subroutine init_virtual_data(this)
logical(lgp) function vx_has_mover(this)
Checks if there is an active mover in the exchange.
subroutine allocate_data(this)
subroutine add_vdi_for_stage(this, vdata_item, stage, virtual_items)
Convenience routine to add virtual data item to a list.
class(virtualexchangetype) function, pointer, private cast_as_virtual_exchange(obj_ptr)
subroutine vx_get_recv_items(this, stg, rank, vi)
class(virtualexchangetype) function, pointer, public get_virtual_exchange_from_list(list, idx)
subroutine vx_create(this, name, exg_id, m1_id, m2_id)
Create the virtual exchange base.
class(virtualexchangetype) function, pointer, public get_virtual_exchange(exg_id)
Returns a virtual exchange with the specified id.
subroutine vx_prepare_stage(this, stage)
subroutine vx_get_send_items(this, stg, rank, vi)
subroutine vx_destroy(this)
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
The Virtual Exchange is based on two Virtual Models and is therefore not always strictly local or rem...