MODFLOW 6  version 6.7.0.dev3
USGS Modular Hydrologic Model
MpiMessageBuilder.f90
Go to the documentation of this file.
2  use kindmodule, only: i4b, lgp
3  use constantsmodule, only: linelength
4  use simmodule, only: ustop
9  use mpi
10  implicit none
11  private
12 
13  type, public :: vdcheadertype
14  integer(I4B) :: id
15  integer(I4B) :: container_type
16  integer(I4B), dimension(NR_VDC_ELEMENT_MAPS) :: map_sizes
17  end type
18 
19  type, public :: vdcreceivermapstype
20  type(vdcelementmaptype), dimension(NR_VDC_ELEMENT_MAPS) :: el_maps
21  contains
22  procedure :: create
23  procedure :: destroy
24  end type
25 
26  type, public :: mpimessagebuildertype
27  type(vdcptrtype), dimension(:), pointer :: vdc_models => null() !< the models to be build the message for
28  type(vdcptrtype), dimension(:), pointer :: vdc_exchanges => null() !< the exchanges to be build the message for
29  integer(I4B) :: imon !< the output file unit, set from outside
30  contains
31  procedure :: init
32  procedure :: attach_data
33  procedure :: release_data
34  procedure :: create_header_snd
35  procedure :: create_header_rcv
36  procedure :: create_map_snd
37  procedure :: create_map_rcv
38  procedure :: create_body_rcv
39  procedure :: create_body_snd
40  procedure :: set_monitor
41  ! private
42  procedure, private :: get_vdc_from_hdr
43  procedure, private :: create_vdc_snd_hdr
44  procedure, private :: create_vdc_snd_map
45  procedure, private :: create_vdc_snd_body
46  procedure, private :: create_vdc_rcv_body
47  end type
48 
49 contains
50 
51  subroutine create(this, map_sizes)
52  class(vdcreceivermapstype) :: this
53  integer(I4B), dimension(NR_VDC_ELEMENT_MAPS) :: map_sizes
54  ! local
55  integer(I4B) :: i
56 
57  do i = 1, nr_vdc_element_maps
58  this%el_maps(i)%nr_virt_elems = map_sizes(i)
59  allocate (this%el_maps(i)%remote_elem_shift(map_sizes(i)))
60  end do
61 
62  end subroutine create
63 
64  subroutine destroy(this)
65  class(vdcreceivermapstype) :: this
66  ! local
67  integer(I4B) :: i
68 
69  do i = 1, nr_vdc_element_maps
70  if (associated(this%el_maps(i)%remote_elem_shift)) then
71  deallocate (this%el_maps(i)%remote_elem_shift)
72  end if
73  end do
74 
75  end subroutine destroy
76 
77  subroutine init(this)
78  class(mpimessagebuildertype) :: this
79 
80  this%imon = -1
81 
82  end subroutine init
83 
84  subroutine attach_data(this, vdc_models, vdc_exchanges)
85  class(mpimessagebuildertype) :: this
86  type(vdcptrtype), dimension(:), pointer :: vdc_models
87  type(vdcptrtype), dimension(:), pointer :: vdc_exchanges
88 
89  this%vdc_models => vdc_models
90  this%vdc_exchanges => vdc_exchanges
91 
92  end subroutine attach_data
93 
94  subroutine release_data(this)
95  class(mpimessagebuildertype) :: this
96 
97  this%vdc_models => null()
98  this%vdc_exchanges => null()
99 
100  end subroutine release_data
101 
102  subroutine set_monitor(this, imon)
103  class(mpimessagebuildertype) :: this
104  integer(I4B) :: imon
105 
106  this%imon = imon
107 
108  end subroutine set_monitor
109 
110  !> @brief Create the header data type to send to
111  !! the remote process for this particular stage.
112  !! From these data, the receiver can construct the
113  !< body to send back to us.
114  subroutine create_header_snd(this, rank, stage, hdrs_snd_type)
115  class(mpimessagebuildertype) :: this
116  integer(I4B) :: rank
117  integer(I4B) :: stage
118  integer, intent(out) :: hdrs_snd_type
119  ! local
120  integer(I4B) :: i, offset, nr_types
121  class(virtualdatacontainertype), pointer :: vdc
122  integer :: ierr
123  type(stlvecint) :: model_idxs, exg_idxs
124  integer, dimension(:), allocatable :: blk_cnts, types
125  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
126 
127  call model_idxs%init()
128  call exg_idxs%init()
129 
130  ! determine which containers to include
131  do i = 1, size(this%vdc_models)
132  vdc => this%vdc_models(i)%ptr
133  if (vdc%is_active .and. vdc%orig_rank == rank) then
134  call model_idxs%push_back(i)
135  end if
136  end do
137  do i = 1, size(this%vdc_exchanges)
138  vdc => this%vdc_exchanges(i)%ptr
139  if (vdc%is_active .and. vdc%orig_rank == rank) then
140  call exg_idxs%push_back(i)
141  end if
142  end do
143 
144  nr_types = model_idxs%size + exg_idxs%size
145  allocate (blk_cnts(nr_types))
146  allocate (types(nr_types))
147  allocate (displs(nr_types))
148 
149  if (this%imon > 0) then
150  write (this%imon, '(6x,a,*(i3))') "create headers for models: ", &
151  model_idxs%get_values()
152  write (this%imon, '(6x,a,*(i3))') "create headers for exchange: ", &
153  exg_idxs%get_values()
154  end if
155 
156  ! loop over containers
157  do i = 1, model_idxs%size
158  vdc => this%vdc_models(model_idxs%at(i))%ptr
159  call mpi_get_address(vdc%id, displs(i), ierr)
160  blk_cnts(i) = 1
161  types(i) = this%create_vdc_snd_hdr(vdc, stage)
162  end do
163  offset = model_idxs%size
164  do i = 1, exg_idxs%size
165  vdc => this%vdc_exchanges(exg_idxs%at(i))%ptr
166  call mpi_get_address(vdc%id, displs(i + offset), ierr)
167  blk_cnts(i + offset) = 1
168  types(i + offset) = this%create_vdc_snd_hdr(vdc, stage)
169  end do
170 
171  ! create a MPI data type for the headers to send
172  call mpi_type_create_struct(nr_types, blk_cnts, displs, types, &
173  hdrs_snd_type, ierr)
174  call mpi_type_commit(hdrs_snd_type, ierr)
175  do i = 1, nr_types
176  call mpi_type_free(types(i), ierr)
177  end do
178 
179  call model_idxs%destroy()
180  call exg_idxs%destroy()
181 
182  deallocate (blk_cnts)
183  deallocate (types)
184  deallocate (displs)
185 
186  end subroutine create_header_snd
187 
188  subroutine create_header_rcv(this, hdr_rcv_type)
189  class(mpimessagebuildertype) :: this
190  integer, intent(out) :: hdr_rcv_type
191  ! local
192  integer :: ierr
193 
194  ! this will be for one data container, the mpi recv
195  ! call will accept an array of them, no need to create
196  ! an overarching contiguous type...
197  call mpi_type_contiguous(nr_vdc_element_maps + 2, mpi_integer, &
198  hdr_rcv_type, ierr)
199  call mpi_type_commit(hdr_rcv_type, ierr)
200 
201  end subroutine create_header_rcv
202 
203  subroutine create_map_snd(this, rank, stage, map_snd_type)
204  class(mpimessagebuildertype) :: this
205  integer(I4B) :: rank
206  integer(I4B) :: stage
207  integer, intent(out) :: map_snd_type
208  ! local
209  integer(I4B) :: i, offset, nr_types
210  class(virtualdatacontainertype), pointer :: vdc
211  integer :: ierr
212  type(stlvecint) :: model_idxs, exg_idxs
213  integer, dimension(:), allocatable :: blk_cnts, types
214  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
215 
216  call model_idxs%init()
217  call exg_idxs%init()
218 
219  ! determine which containers to include,
220  ! currently models + exchanges
221  do i = 1, size(this%vdc_models)
222  vdc => this%vdc_models(i)%ptr
223  if (vdc%is_active .and. vdc%orig_rank == rank) then
224  call model_idxs%push_back(i)
225  end if
226  end do
227  do i = 1, size(this%vdc_exchanges)
228  vdc => this%vdc_exchanges(i)%ptr
229  if (vdc%is_active .and. vdc%orig_rank == rank) then
230  call exg_idxs%push_back(i)
231  end if
232  end do
233 
234  nr_types = model_idxs%size + exg_idxs%size
235  allocate (blk_cnts(nr_types))
236  allocate (types(nr_types))
237  allocate (displs(nr_types))
238 
239  if (this%imon > 0) then
240  write (this%imon, '(6x,a,*(i3))') "create maps for models: ", &
241  model_idxs%get_values()
242  write (this%imon, '(6x,a,*(i3))') "create maps for exchange: ", &
243  exg_idxs%get_values()
244  end if
245 
246  ! loop over containers
247  do i = 1, model_idxs%size
248  vdc => this%vdc_models(model_idxs%at(i))%ptr
249  call mpi_get_address(vdc%id, displs(i), ierr)
250  blk_cnts(i) = 1
251  types(i) = this%create_vdc_snd_map(vdc, stage)
252  end do
253  offset = model_idxs%size
254  do i = 1, exg_idxs%size
255  vdc => this%vdc_exchanges(exg_idxs%at(i))%ptr
256  call mpi_get_address(vdc%id, displs(i + offset), ierr)
257  blk_cnts(i + offset) = 1
258  types(i + offset) = this%create_vdc_snd_map(vdc, stage)
259  end do
260 
261  ! create a compound MPI data type for the maps
262  call mpi_type_create_struct(nr_types, blk_cnts, displs, types, &
263  map_snd_type, ierr)
264  call mpi_type_commit(map_snd_type, ierr)
265 
266  ! free the subtypes
267  do i = 1, nr_types
268  call mpi_type_free(types(i), ierr)
269  end do
270 
271  call model_idxs%destroy()
272  call exg_idxs%destroy()
273 
274  deallocate (blk_cnts)
275  deallocate (types)
276  deallocate (displs)
277 
278  end subroutine create_map_snd
279 
280  subroutine create_map_rcv(this, rcv_map, nr_headers, map_rcv_type)
281  class(mpimessagebuildertype) :: this
282  type(vdcreceivermapstype), dimension(:) :: rcv_map
283  integer(I4B) :: nr_headers
284  integer, intent(out) :: map_rcv_type
285  ! local
286  integer(I4B) :: i, j, nr_elems, type_cnt
287  integer :: ierr, max_nr_maps
288  integer, dimension(:), allocatable :: types
289  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
290  integer, dimension(:), allocatable :: blk_cnts
291 
292  max_nr_maps = nr_headers * nr_vdc_element_maps
293  allocate (types(max_nr_maps))
294  allocate (displs(max_nr_maps))
295  allocate (blk_cnts(max_nr_maps))
296 
297  type_cnt = 0
298  do i = 1, nr_headers
299  do j = 1, nr_vdc_element_maps
300  nr_elems = rcv_map(i)%el_maps(j)%nr_virt_elems
301  if (nr_elems == 0) cycle
302 
303  type_cnt = type_cnt + 1
304  call mpi_get_address(rcv_map(i)%el_maps(j)%remote_elem_shift, &
305  displs(type_cnt), ierr)
306  call mpi_type_contiguous(nr_elems, mpi_integer, types(type_cnt), ierr)
307  blk_cnts(type_cnt) = 1
308  end do
309  end do
310 
311  call mpi_type_create_struct(type_cnt, blk_cnts, displs, types, &
312  map_rcv_type, ierr)
313  call mpi_type_commit(map_rcv_type, ierr)
314 
315  deallocate (types)
316  deallocate (displs)
317  deallocate (blk_cnts)
318 
319  end subroutine create_map_rcv
320 
321  !> @brief Create the body to receive based on the headers
322  !< that have been sent
323  subroutine create_body_rcv(this, rank, stage, body_rcv_type)
324  class(mpimessagebuildertype) :: this
325  integer(I4B) :: rank
326  integer(I4B) :: stage
327  integer, intent(out) :: body_rcv_type
328  ! local
329  integer(I4B) :: i, nr_types, offset
330  class(virtualdatacontainertype), pointer :: vdc
331  type(stlvecint) :: model_idxs, exg_idxs
332  integer :: ierr
333  integer, dimension(:), allocatable :: types
334  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
335  integer, dimension(:), allocatable :: blk_cnts
336 
337  call model_idxs%init()
338  call exg_idxs%init()
339 
340  ! gather all containers from this rank
341  do i = 1, size(this%vdc_models)
342  vdc => this%vdc_models(i)%ptr
343  if (vdc%is_active .and. vdc%orig_rank == rank) then
344  if (this%imon > 0) then
345  write (this%imon, '(6x,a,i0)') "expecting model ", vdc%id
346  end if
347  call model_idxs%push_back(i)
348  end if
349  end do
350  do i = 1, size(this%vdc_exchanges)
351  vdc => this%vdc_exchanges(i)%ptr
352  if (vdc%is_active .and. vdc%orig_rank == rank) then
353  if (this%imon > 0) then
354  write (this%imon, '(6x,a,i0)') "expecting exchange ", vdc%id
355  end if
356  call exg_idxs%push_back(i)
357  end if
358  end do
359 
360  nr_types = model_idxs%size + exg_idxs%size
361  allocate (types(nr_types))
362  allocate (displs(nr_types))
363  allocate (blk_cnts(nr_types))
364 
365  ! loop over included containers
366  do i = 1, model_idxs%size
367  vdc => this%vdc_models(model_idxs%at(i))%ptr
368  call mpi_get_address(vdc%id, displs(i), ierr)
369  types(i) = this%create_vdc_rcv_body(vdc, rank, stage)
370  blk_cnts(i) = 1
371  end do
372  offset = model_idxs%size
373  do i = 1, exg_idxs%size
374  vdc => this%vdc_exchanges(exg_idxs%at(i))%ptr
375  call mpi_get_address(vdc%id, displs(i + offset), ierr)
376  blk_cnts(i + offset) = 1
377  types(i + offset) = this%create_vdc_rcv_body(vdc, rank, stage)
378  end do
379 
380  ! create a MPI data type for the virtual data containers to receive
381  call mpi_type_create_struct(nr_types, blk_cnts, displs, types, &
382  body_rcv_type, ierr)
383  call mpi_type_commit(body_rcv_type, ierr)
384  do i = 1, nr_types
385  call mpi_type_free(types(i), ierr)
386  end do
387 
388  call model_idxs%destroy()
389  call exg_idxs%destroy()
390  deallocate (types)
391  deallocate (displs)
392  deallocate (blk_cnts)
393 
394  end subroutine create_body_rcv
395 
396  !> @brief Create the body to send based on the received headers
397  !<
398  subroutine create_body_snd(this, rank, stage, headers, maps, body_snd_type)
399  class(mpimessagebuildertype) :: this
400  integer(I4B) :: rank
401  integer(I4B) :: stage
402  type(vdcheadertype), dimension(:) :: headers
403  type(vdcreceivermapstype), dimension(:) :: maps
404  integer, intent(out) :: body_snd_type
405  ! local
406  integer(I4B) :: i, nr_headers
407  class(virtualdatacontainertype), pointer :: vdc
408  integer :: ierr
409  integer, dimension(:), allocatable :: types
410  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
411  integer, dimension(:), allocatable :: blk_cnts
412 
413  nr_headers = size(headers)
414  allocate (types(nr_headers))
415  allocate (displs(nr_headers))
416  allocate (blk_cnts(nr_headers))
417 
418  do i = 1, nr_headers
419  vdc => this%get_vdc_from_hdr(headers(i))
420  call mpi_get_address(vdc%id, displs(i), ierr)
421  types(i) = this%create_vdc_snd_body(vdc, maps(i)%el_maps, rank, stage)
422  blk_cnts(i) = 1
423  end do
424 
425  ! create the list of virtual data containers to receive
426  call mpi_type_create_struct(nr_headers, blk_cnts, displs, &
427  types, body_snd_type, ierr)
428  call mpi_type_commit(body_snd_type, ierr)
429  do i = 1, nr_headers
430  call mpi_type_free(types(i), ierr)
431  end do
432 
433  deallocate (types)
434  deallocate (displs)
435  deallocate (blk_cnts)
436 
437  end subroutine create_body_snd
438 
439  !> @brief Create send header for virtual data container, relative
440  !< to the field ...%id
441  function create_vdc_snd_hdr(this, vdc, stage) result(new_type)
442  class(mpimessagebuildertype) :: this
443  class(virtualdatacontainertype) :: vdc
444  integer(I4B) :: stage
445  integer :: new_type ! the created MPI datatype, uncommitted
446  ! local
447  integer :: i, ierr
448  integer, dimension(NR_VDC_ELEMENT_MAPS + 2) :: blk_cnts
449  integer(kind=MPI_ADDRESS_KIND), dimension(NR_VDC_ELEMENT_MAPS + 2) :: displs
450  integer, dimension(NR_VDC_ELEMENT_MAPS + 2) :: types
451 
452  call mpi_get_address(vdc%id, displs(1), ierr)
453  types(1) = mpi_integer
454  blk_cnts(1) = 1
455  call mpi_get_address(vdc%container_type, displs(2), ierr)
456  types(2) = mpi_integer
457  blk_cnts(2) = 1
458  do i = 1, nr_vdc_element_maps
459  call mpi_get_address(vdc%element_maps(i)%nr_virt_elems, displs(i + 2), ierr)
460  types(i + 2) = mpi_integer
461  blk_cnts(i + 2) = 1
462  end do
463 
464  ! rebase to id field
465  displs = displs - displs(1)
466  call mpi_type_create_struct(nr_vdc_element_maps + 2, blk_cnts, &
467  displs, types, new_type, ierr)
468  call mpi_type_commit(new_type, ierr)
469 
470  end function create_vdc_snd_hdr
471 
472  !> @brief Create a MPI datatype for sending the maps
473  !< with the type relative to the id field
474  function create_vdc_snd_map(this, vdc, stage) result(new_type)
475  class(mpimessagebuildertype) :: this
476  class(virtualdatacontainertype), pointer :: vdc
477  integer(I4B) :: stage
478  integer :: new_type
479  ! local
480  integer(I4B) :: i, type_cnt
481  integer :: n_elems, ierr
482  integer(kind=MPI_ADDRESS_KIND) :: offset
483  integer, dimension(:), allocatable :: types
484  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
485  integer, dimension(:), allocatable :: blk_cnts
486 
487  allocate (types(nr_vdc_element_maps))
488  allocate (displs(nr_vdc_element_maps))
489  allocate (blk_cnts(nr_vdc_element_maps))
490 
491  ! displ relative to id field
492  call mpi_get_address(vdc%id, offset, ierr)
493 
494  type_cnt = 0
495  do i = 1, nr_vdc_element_maps
496  n_elems = vdc%element_maps(i)%nr_virt_elems
497  if (n_elems == 0) cycle ! only non-empty maps are sent
498 
499  type_cnt = type_cnt + 1
500  call mpi_get_address(vdc%element_maps(i)%remote_elem_shift, &
501  displs(type_cnt), ierr)
502  call mpi_type_contiguous(n_elems, mpi_integer, types(type_cnt), ierr)
503  call mpi_type_commit(types(type_cnt), ierr)
504  blk_cnts(type_cnt) = 1
505  displs(type_cnt) = displs(type_cnt) - offset
506  end do
507 
508  call mpi_type_create_struct(type_cnt, blk_cnts, displs, types, &
509  new_type, ierr)
510  call mpi_type_commit(new_type, ierr)
511 
512  do i = 1, type_cnt
513  call mpi_type_free(types(i), ierr)
514  end do
515 
516  deallocate (types)
517  deallocate (displs)
518  deallocate (blk_cnts)
519 
520  end function create_vdc_snd_map
521 
522  function create_vdc_rcv_body(this, vdc, rank, stage) result(new_type)
523  class(mpimessagebuildertype) :: this
524  class(virtualdatacontainertype), pointer :: vdc
525  integer(I4B) :: rank
526  integer(I4B) :: stage
527  integer :: new_type
528  ! local
529  type(stlvecint) :: items
530  integer :: ierr
531  integer(kind=MPI_ADDRESS_KIND) :: offset
532  integer, dimension(:), allocatable :: types
533  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
534  integer, dimension(:), allocatable :: blk_cnts
535  integer(I4B) :: i
536  class(virtualdatatype), pointer :: vd
537 
538  call items%init()
539  call vdc%get_recv_items(stage, rank, items)
540  !if (this%imon > 0) call vdc%print_items(this%imon, items)
541 
542  allocate (types(items%size))
543  allocate (displs(items%size))
544  allocate (blk_cnts(items%size))
545 
546  call mpi_get_address(vdc%id, offset, ierr)
547 
548  do i = 1, items%size
549  vd => get_virtual_data_from_list(vdc%virtual_data_list, items%at(i))
550  call get_mpi_datatype(this, vd, displs(i), types(i))
551  blk_cnts(i) = 1
552  ! rebase w.r.t. id field
553  displs(i) = displs(i) - offset
554  end do
555 
556  call mpi_type_create_struct(items%size, blk_cnts, displs, &
557  types, new_type, ierr)
558  call mpi_type_commit(new_type, ierr)
559 
560  do i = 1, items%size
561  vd => get_virtual_data_from_list(vdc%virtual_data_list, items%at(i))
562  call free_mpi_datatype(vd, types(i))
563  end do
564 
565  deallocate (types)
566  deallocate (displs)
567  deallocate (blk_cnts)
568 
569  call items%destroy()
570 
571  end function create_vdc_rcv_body
572 
573  function create_vdc_snd_body(this, vdc, vdc_maps, rank, stage) result(new_type)
574  class(mpimessagebuildertype) :: this
575  class(virtualdatacontainertype), pointer :: vdc
576  type(vdcelementmaptype), dimension(:) :: vdc_maps
577  integer(I4B) :: rank
578  integer(I4B) :: stage
579  integer :: new_type
580  ! local
581  type(stlvecint) :: items
582  integer :: ierr
583  integer(kind=MPI_ADDRESS_KIND) :: offset
584  integer, dimension(:), allocatable :: types
585  integer(kind=MPI_ADDRESS_KIND), dimension(:), allocatable :: displs
586  integer, dimension(:), allocatable :: blk_cnts
587  integer(I4B) :: i
588  class(virtualdatatype), pointer :: vd
589  integer(I4B), dimension(:), pointer, contiguous :: el_map
590 
591  call items%init()
592  call vdc%get_send_items(stage, rank, items)
593  !if (this%imon > 0) call vdc%print_items(this%imon, items)
594 
595  allocate (types(items%size))
596  allocate (displs(items%size))
597  allocate (blk_cnts(items%size))
598 
599  call mpi_get_address(vdc%id, offset, ierr)
600 
601  do i = 1, items%size
602  vd => get_virtual_data_from_list(vdc%virtual_data_list, items%at(i))
603  if (vd%map_type > 0) then
604  el_map => vdc_maps(vd%map_type)%remote_elem_shift
605  else
606  el_map => null()
607  end if
608  call get_mpi_datatype(this, vd, displs(i), types(i), el_map)
609  blk_cnts(i) = 1
610  ! rebase w.r.t. id field
611  displs(i) = displs(i) - offset
612  end do
613 
614  call mpi_type_create_struct(items%size, blk_cnts, displs, &
615  types, new_type, ierr)
616  call mpi_type_commit(new_type, ierr)
617 
618  do i = 1, items%size
619  vd => get_virtual_data_from_list(vdc%virtual_data_list, items%at(i))
620  call free_mpi_datatype(vd, types(i))
621  end do
622 
623  deallocate (types)
624  deallocate (displs)
625  deallocate (blk_cnts)
626 
627  call items%destroy()
628 
629  end function create_vdc_snd_body
630 
631  function get_vdc_from_hdr(this, header) result(vdc)
632  class(mpimessagebuildertype) :: this
633  type(vdcheadertype) :: header
634  class(virtualdatacontainertype), pointer :: vdc
635  ! local
636  integer(I4B) :: i
637 
638  vdc => null()
639  if (header%container_type == vdc_gwfmodel_type .or. &
640  header%container_type == vdc_gwtmodel_type .or. &
641  header%container_type == vdc_gwemodel_type) then
642  do i = 1, size(this%vdc_models)
643  vdc => this%vdc_models(i)%ptr
644  if (vdc%id == header%id) return
645  vdc => null()
646  end do
647  else if (header%container_type == vdc_gwfexg_type .or. &
648  header%container_type == vdc_gwtexg_type .or. &
649  header%container_type == vdc_gweexg_type) then
650  do i = 1, size(this%vdc_exchanges)
651  vdc => this%vdc_exchanges(i)%ptr
652  if (vdc%id == header%id) return
653  vdc => null()
654  end do
655  end if
656 
657  end function get_vdc_from_hdr
658 
659  !> @brief Local routine to get elemental mpi data types representing
660  !! the virtual data items. Types are automatically committed unless
661  !< they are primitives (e.g. MPI_INTEGER)
662  subroutine get_mpi_datatype(this, virtual_data, el_displ, el_type, el_map_opt)
663  use simmodule, only: ustop
664  class(mpimessagebuildertype) :: this
665  class(virtualdatatype), pointer :: virtual_data
666  integer(kind=MPI_ADDRESS_KIND) :: el_displ
667  integer :: el_type
668  integer(I4B), dimension(:), pointer, contiguous, optional :: el_map_opt !< optional, and can be null
669  ! local
670  type(memorytype), pointer :: mt
671  integer(I4B), dimension(:), pointer, contiguous :: el_map
672 
673  el_map => null()
674  if (present(el_map_opt)) el_map => el_map_opt
675 
676  if (this%imon > 0) then
677  if (.not. associated(el_map)) then
678  write (this%imon, '(8x,2a,i0)') virtual_data%var_name, ' all ', &
679  virtual_data%virtual_mt%isize
680  else
681  write (this%imon, '(8x,2a,i0)') virtual_data%var_name, &
682  ' with map size ', size(el_map)
683  end if
684  end if
685 
686  mt => virtual_data%virtual_mt
687 
688  if (associated(mt%intsclr)) then
689  call get_mpitype_for_int(mt, el_displ, el_type)
690  else if (associated(mt%aint1d)) then
691  call get_mpitype_for_int1d(mt, el_displ, el_type, el_map)
692  else if (associated(mt%dblsclr)) then
693  call get_mpitype_for_dbl(mt, el_displ, el_type)
694  else if (associated(mt%adbl1d)) then
695  call get_mpitype_for_dbl1d(mt, el_displ, el_type, el_map)
696  else if (associated(mt%adbl2d)) then
697  call get_mpitype_for_dbl2d(mt, el_displ, el_type, el_map)
698  else
699  write (*, *) 'unsupported datatype in MPI messaging for ', &
700  virtual_data%var_name, virtual_data%mem_path
701  call ustop()
702  end if
703 
704  end subroutine get_mpi_datatype
705 
706  !> @brief Local routine to free elemental mpi data types representing
707  !! the virtual data items. This can't be done generally, because some
708  !< (scalar) types are primitive and freeing them causes nasty errors...
709  subroutine free_mpi_datatype(virtual_data, el_type)
710  class(virtualdatatype), pointer :: virtual_data
711  integer :: el_type
712  ! local
713  type(memorytype), pointer :: mt
714  integer :: ierr
715 
716  mt => virtual_data%virtual_mt
717  if (associated(mt%intsclr)) then
718  ! type is MPI_INTEGER, don't free this!
719  return
720  else if (associated(mt%dblsclr)) then
721  ! type is MPI_DOUBLE_PRECISION, don't free this!
722  return
723  else if (associated(mt%logicalsclr)) then
724  ! type is MPI_LOGICAL, don't free this!
725  return
726  else
727  ! all other types are freed here
728  call mpi_type_free(el_type, ierr)
729  return
730  end if
731 
732  end subroutine free_mpi_datatype
733 
734  subroutine get_mpitype_for_int(mem, el_displ, el_type)
735  type(memorytype), pointer :: mem
736  integer(kind=MPI_ADDRESS_KIND) :: el_displ
737  integer :: el_type
738  ! local
739  integer :: ierr
740 
741  call mpi_get_address(mem%intsclr, el_displ, ierr)
742  el_type = mpi_integer
743  ! no need to commit primitive type
744 
745  end subroutine get_mpitype_for_int
746 
747  subroutine get_mpitype_for_int1d(mem, el_displ, el_type, el_map)
748  type(memorytype), pointer :: mem
749  integer(kind=MPI_ADDRESS_KIND) :: el_displ
750  integer :: el_type
751  integer, dimension(:), pointer :: el_map
752  ! local
753  integer :: ierr
754 
755  ! sanity check on map
756  call check_map_int1d(mem, el_map)
757 
758  call mpi_get_address(mem%aint1d, el_displ, ierr)
759  if (associated(el_map)) then
760  call mpi_type_create_indexed_block( &
761  size(el_map), 1, el_map, mpi_integer, el_type, ierr)
762  else
763  call mpi_type_contiguous(mem%isize, mpi_integer, el_type, ierr)
764  end if
765  call mpi_type_commit(el_type, ierr)
766 
767  end subroutine get_mpitype_for_int1d
768 
769  subroutine get_mpitype_for_dbl(mem, el_displ, el_type)
770  type(memorytype), pointer :: mem
771  integer(kind=MPI_ADDRESS_KIND) :: el_displ
772  integer :: el_type
773  ! local
774  integer :: ierr
775 
776  call mpi_get_address(mem%dblsclr, el_displ, ierr)
777  el_type = mpi_double_precision
778  ! no need to commit primitive type
779 
780  end subroutine get_mpitype_for_dbl
781 
782  subroutine get_mpitype_for_dbl1d(mem, el_displ, el_type, el_map)
783  type(memorytype), pointer :: mem
784  integer(kind=MPI_ADDRESS_KIND) :: el_displ
785  integer :: el_type
786  integer, dimension(:), pointer :: el_map
787  ! local
788  integer :: ierr
789 
790  ! sanity check on map
791  call check_map_dbl1d(mem, el_map)
792 
793  call mpi_get_address(mem%adbl1d, el_displ, ierr)
794  if (associated(el_map)) then
795  call mpi_type_create_indexed_block( &
796  size(el_map), 1, el_map, mpi_double_precision, el_type, ierr)
797  else
798  call mpi_type_contiguous(mem%isize, mpi_double_precision, el_type, ierr)
799  end if
800  call mpi_type_commit(el_type, ierr)
801 
802  end subroutine get_mpitype_for_dbl1d
803 
804  subroutine get_mpitype_for_dbl2d(mem, el_displ, el_type, el_map)
805  type(memorytype), pointer :: mem
806  integer(kind=MPI_ADDRESS_KIND) :: el_displ
807  integer :: el_type
808  integer, dimension(:), pointer :: el_map
809  ! local
810  integer :: ierr
811  integer :: entry_type
812 
813  ! sanity check on map
814  call check_map_dbl2d(mem, el_map)
815 
816  call mpi_get_address(mem%adbl2d, el_displ, ierr)
817  if (associated(el_map)) then
818  call mpi_type_contiguous( &
819  size(mem%adbl2d, dim=1), mpi_double_precision, entry_type, ierr)
820  call mpi_type_create_indexed_block( &
821  size(el_map), 1, el_map, entry_type, el_type, ierr)
822  else
823  call mpi_type_contiguous(mem%isize, mpi_double_precision, el_type, ierr)
824  end if
825  call mpi_type_commit(el_type, ierr)
826 
827  end subroutine get_mpitype_for_dbl2d
828 
829  subroutine check_map_int1d(mem, map)
830  type(memorytype), pointer :: mem
831  integer, dimension(:), pointer :: map !< ZERO-based map (for creating mpi types)
832  ! local
833  logical(LGP) :: is_valid
834  integer(I4B) :: min_idx, max_idx
835 
836  if (.not. associated(map)) return
837  if (size(map) == 0) return ! nothing to check
838 
839  ! bounds check
840  min_idx = minval(map) + 1
841  max_idx = maxval(map) + 1
842  is_valid = max_idx <= size(mem%aint1d) .and. min_idx > 0
843  if (.not. is_valid) then
844  write (*, '(/,4x,4a)') &
845  'Error: invalid map in MPI datatype for ', &
846  trim(mem%name), ' in ', trim(mem%path)
847  call ustop()
848  end if
849 
850  end subroutine check_map_int1d
851 
852  !> @brief Bounds check for index maps,
853  !< terminates on error.
854  subroutine check_map_dbl1d(mem, map)
855  type(memorytype), pointer :: mem !< memory type
856  integer, dimension(:), pointer :: map !< ZERO-based map (for creating mpi types)
857  ! local
858  logical(LGP) :: is_valid
859  integer(I4B) :: min_idx, max_idx
860 
861  if (.not. associated(map)) return
862  if (size(map) == 0) return ! nothing to check
863 
864  min_idx = minval(map) + 1
865  max_idx = maxval(map) + 1
866  is_valid = max_idx <= size(mem%adbl1d) .and. min_idx > 0
867  if (.not. is_valid) then
868  write (*, '(/,4x,4a)') &
869  'Error: invalid map in MPI datatype for ', &
870  trim(mem%name), ' in ', trim(mem%path)
871  call ustop()
872  end if
873 
874  end subroutine check_map_dbl1d
875 
876  subroutine check_map_dbl2d(mem, map)
877  type(memorytype), pointer :: mem
878  integer, dimension(:), pointer :: map !< ZERO-based map (for creating mpi types)
879  ! local
880  logical(LGP) :: is_valid
881  integer(I4B) :: min_idx, max_idx
882 
883  if (.not. associated(map)) return
884  if (size(map) == 0) return ! nothing to check
885 
886  min_idx = minval(map) + 1
887  max_idx = maxval(map) + 1
888  is_valid = max_idx <= size(mem%adbl2d, 2) .and. min_idx > 0
889  if (.not. is_valid) then
890  write (*, '(/,4x,4a)') &
891  'Error: invalid map in MPI datatype for ', &
892  trim(mem%name), ' in ', trim(mem%path)
893  call ustop()
894  end if
895 
896  end subroutine check_map_dbl2d
897 
898 end module mpimessagebuildermodule
This module contains simulation constants.
Definition: Constants.f90:9
integer(i4b), parameter linelength
maximum length of a standard line
Definition: Constants.f90:45
This module defines variable data types.
Definition: kind.f90:8
subroutine get_mpitype_for_dbl2d(mem, el_displ, el_type, el_map)
subroutine set_monitor(this, imon)
subroutine check_map_dbl1d(mem, map)
Bounds check for index maps,.
subroutine release_data(this)
subroutine check_map_int1d(mem, map)
integer function create_vdc_snd_body(this, vdc, vdc_maps, rank, stage)
subroutine get_mpitype_for_int(mem, el_displ, el_type)
integer function create_vdc_snd_hdr(this, vdc, stage)
Create send header for virtual data container, relative.
subroutine get_mpitype_for_dbl(mem, el_displ, el_type)
subroutine get_mpi_datatype(this, virtual_data, el_displ, el_type, el_map_opt)
Local routine to get elemental mpi data types representing the virtual data items....
subroutine attach_data(this, vdc_models, vdc_exchanges)
subroutine create(this, map_sizes)
subroutine create_map_snd(this, rank, stage, map_snd_type)
subroutine create_body_rcv(this, rank, stage, body_rcv_type)
Create the body to receive based on the headers.
integer function create_vdc_snd_map(this, vdc, stage)
Create a MPI datatype for sending the maps.
subroutine create_map_rcv(this, rcv_map, nr_headers, map_rcv_type)
subroutine get_mpitype_for_dbl1d(mem, el_displ, el_type, el_map)
subroutine free_mpi_datatype(virtual_data, el_type)
Local routine to free elemental mpi data types representing the virtual data items....
subroutine create_body_snd(this, rank, stage, headers, maps, body_snd_type)
Create the body to send based on the received headers.
integer function create_vdc_rcv_body(this, vdc, rank, stage)
subroutine check_map_dbl2d(mem, map)
subroutine create_header_rcv(this, hdr_rcv_type)
subroutine create_header_snd(this, rank, stage, hdrs_snd_type)
Create the header data type to send to the remote process for this particular stage....
class(virtualdatacontainertype) function, pointer get_vdc_from_hdr(this, header)
subroutine get_mpitype_for_int1d(mem, el_displ, el_type, el_map)
This module contains simulation methods.
Definition: Sim.f90:10
subroutine, public ustop(stopmess, ioutlocal)
Stop the simulation.
Definition: Sim.f90:312
class(virtualdatatype) function, pointer, public get_virtual_data_from_list(list, idx)
integer(i4b), parameter, public nr_vdc_element_maps
Definition: VirtualBase.f90:16
integer(i4b), parameter, public vdc_gwtmodel_type
integer(i4b), parameter, public vdc_gwemodel_type
integer(i4b), parameter, public vdc_gwfmodel_type
integer(i4b), parameter, public vdc_gwtexg_type
integer(i4b), parameter, public vdc_gwfexg_type
integer(i4b), parameter, public vdc_gweexg_type
This is a generic data structure to virtualize pieces of memory in 2 distinct ways:
Definition: VirtualBase.f90:35
Wrapper for virtual data containers.