source: palm/trunk/SOURCE/pmc_child_mod.f90 @ 2818

Last change on this file since 2818 was 2809, checked in by schwenkel, 7 years ago

Bugfix for gfortran: Replace the function C_SIZEOF with STORAGE_SIZE

  • Property svn:keywords set to Id
File size: 29.0 KB
RevLine 
[1933]1MODULE pmc_child
[1762]2
[2000]3!------------------------------------------------------------------------------!
[2696]4! This file is part of the PALM model system.
[1762]5!
[2000]6! PALM is free software: you can redistribute it and/or modify it under the
7! terms of the GNU General Public License as published by the Free Software
8! Foundation, either version 3 of the License, or (at your option) any later
9! version.
[1762]10!
11! PALM is distributed in the hope that it will be useful, but WITHOUT ANY
12! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13! A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14!
15! You should have received a copy of the GNU General Public License along with
16! PALM. If not, see <http://www.gnu.org/licenses/>.
17!
[2718]18! Copyright 1997-2018 Leibniz Universitaet Hannover
[2000]19!------------------------------------------------------------------------------!
[1762]20!
21! Current revisions:
22! ------------------
[1834]23!
[2001]24!
[1762]25! Former revisions:
26! -----------------
27! $Id: pmc_child_mod.f90 2809 2018-02-15 09:55:58Z maronga $
[2809]28! Bugfix for gfortran: Replace the function C_SIZEOF with STORAGE_SIZE
29!
30! 2801 2018-02-14 16:01:55Z thiele
[2801]31! Introduce particle transfer in nested models.
32!
33! 2718 2018-01-02 08:49:38Z maronga
[2716]34! Corrected "Former revisions" section
35!
36! 2696 2017-12-14 17:12:51Z kanani
37! Change in file header (GPL part)
38!
39! 2599 2017-11-01 13:18:45Z hellstea
[2599]40! Some cleanup and commenting improvements only.
41!
42! 2101 2017-01-05 16:42:31Z suehring
[1762]43!
[2001]44! 2000 2016-08-20 18:09:15Z knoop
45! Forced header and separation lines into 80 columns
46!
[1933]47! 1897 2016-05-03 08:10:23Z raasch
48! Module renamed. Code clean up. The words server/client changed to parent/child.
49!
[1897]50! 1896 2016-05-03 08:06:41Z raasch
51! re-formatted to match PALM style
52!
[1851]53! 1850 2016-04-08 13:29:27Z maronga
54! Module renamed
55!
56!
[1834]57! 1833 2016-04-07 14:23:03Z raasch
58! gfortran requires pointer attributes for some array declarations,
59! long line wrapped
60!
[1809]61! 1808 2016-04-05 19:44:00Z raasch
62! MPI module used by default on all machines
63!
[1798]64! 1797 2016-03-21 16:50:28Z raasch
65! introduction of different datatransfer modes
66!
[1792]67! 1791 2016-03-11 10:41:25Z raasch
68! Debug write-statement commented out
69!
[1787]70! 1786 2016-03-08 05:49:27Z raasch
[1933]71! change in child-parent data transfer: parent now gets data from child
72! instead of that child puts it to the parent
[1787]73!
[1784]74! 1783 2016-03-06 18:36:17Z raasch
75! Bugfix: wrong data-type in MPI_WIN_CREATE replaced
76!
[1780]77! 1779 2016-03-03 08:01:28Z raasch
78! kind=dp replaced by wp, dim_order removed
79! array management changed from linked list to sequential loop
80!
[1765]81! 1764 2016-02-28 12:45:19Z raasch
82! cpp-statement added (nesting can only be used in parallel mode),
83! all kinds given in PALM style
84!
[1763]85! 1762 2016-02-25 12:31:13Z hellstea
86! Initial revision by K. Ketelsen
[1762]87!
88! Description:
89! ------------
90!
[1933]91! Child part of Palm Model Coupler
[2801]92!------------------------------------------------------------------------------!
[1762]93
[1764]94#if defined( __parallel )
[1762]95
[1896]96    USE, INTRINSIC ::  iso_c_binding
[1762]97
[1808]98#if defined( __mpifh )
99    INCLUDE "mpif.h"
100#else
[1764]101    USE MPI
102#endif
[1896]103
104    USE kinds
[2801]105    USE pmc_general,                                                           &
106        ONLY:  arraydef, childdef, da_desclen, da_namedef, da_namelen, pedef,  &
[1896]107               pmc_da_name_err,  pmc_g_setname, pmc_max_array, pmc_status_ok
108
[2801]109    USE pmc_handle_communicator,                                               &
[1933]110        ONLY:  m_model_comm, m_model_npes, m_model_rank, m_to_parent_comm
[1896]111
[2801]112    USE pmc_mpi_wrapper,                                                       &
[1933]113        ONLY:  pmc_alloc_mem, pmc_bcast, pmc_inter_bcast, pmc_time
[1896]114
115    IMPLICIT NONE
116
[1762]117    PRIVATE
118    SAVE
119
[2801]120    TYPE(childdef), PUBLIC ::  me   !<
[1762]121
[2801]122    INTEGER(iwp) ::  myindex = 0         !< counter and unique number for data arrays
123    INTEGER(iwp) ::  next_array_in_list = 0   !<
[1762]124
125
[1933]126    INTERFACE pmc_childinit
127        MODULE PROCEDURE pmc_childinit
128    END INTERFACE pmc_childinit
[1762]129
[1896]130    INTERFACE pmc_c_clear_next_array_list
131        MODULE PROCEDURE pmc_c_clear_next_array_list
132    END INTERFACE pmc_c_clear_next_array_list
[1762]133
[1896]134    INTERFACE pmc_c_getbuffer
135        MODULE PROCEDURE pmc_c_getbuffer
136    END INTERFACE pmc_c_getbuffer
[1762]137
[1896]138    INTERFACE pmc_c_getnextarray
139        MODULE PROCEDURE pmc_c_getnextarray
140    END INTERFACE pmc_c_getnextarray
[1779]141
[1896]142    INTERFACE pmc_c_get_2d_index_list
143        MODULE PROCEDURE pmc_c_get_2d_index_list
144    END INTERFACE pmc_c_get_2d_index_list
[1762]145
[1896]146    INTERFACE pmc_c_putbuffer
147        MODULE PROCEDURE pmc_c_putbuffer
148    END INTERFACE pmc_c_putbuffer
[1762]149
[1896]150    INTERFACE pmc_c_setind_and_allocmem
151        MODULE PROCEDURE pmc_c_setind_and_allocmem
152    END INTERFACE pmc_c_setind_and_allocmem
[1762]153
[1896]154    INTERFACE pmc_c_set_dataarray
155        MODULE PROCEDURE pmc_c_set_dataarray_2d
156        MODULE PROCEDURE pmc_c_set_dataarray_3d
[2801]157        MODULE PROCEDURE pmc_c_set_dataarray_ip2d
[1896]158    END INTERFACE pmc_c_set_dataarray
[1762]159
[1896]160    INTERFACE pmc_set_dataarray_name
161        MODULE PROCEDURE pmc_set_dataarray_name
162        MODULE PROCEDURE pmc_set_dataarray_name_lastentry
163    END INTERFACE pmc_set_dataarray_name
[1762]164
165
[2801]166    PUBLIC pmc_childinit, pmc_c_clear_next_array_list, pmc_c_getbuffer,        &
167           pmc_c_getnextarray, pmc_c_putbuffer, pmc_c_setind_and_allocmem,     &
[1896]168           pmc_c_set_dataarray, pmc_set_dataarray_name, pmc_c_get_2d_index_list
[1762]169
[1896]170 CONTAINS
[1762]171
172
173
[1933]174 SUBROUTINE pmc_childinit
[1762]175
[1896]176     IMPLICIT NONE
[1762]177
[2801]178     INTEGER(iwp) ::  i        !<
179     INTEGER(iwp) ::  istat    !<
[1762]180
[1896]181!
182!--  Get / define the MPI environment
183     me%model_comm = m_model_comm
[1933]184     me%inter_comm = m_to_parent_comm
[1762]185
[1896]186     CALL MPI_COMM_RANK( me%model_comm, me%model_rank, istat )
187     CALL MPI_COMM_SIZE( me%model_comm, me%model_npes, istat )
188     CALL MPI_COMM_REMOTE_SIZE( me%inter_comm, me%inter_npes, istat )
189!
[2599]190!--  Intra-communicator is used for MPI_GET
[1896]191     CALL MPI_INTERCOMM_MERGE( me%inter_comm, .TRUE., me%intra_comm, istat )
192     CALL MPI_COMM_RANK( me%intra_comm, me%intra_rank, istat )
[1762]193
[1896]194     ALLOCATE( me%pes(me%inter_npes) )
[1779]195!
[2599]196!--  Allocate an array of type arraydef for all parent processes to store
197!--  information of then transfer array
[1896]198     DO  i = 1, me%inter_npes
199        ALLOCATE( me%pes(i)%array_list(pmc_max_array) )
200     ENDDO
[1762]201
[1933]202 END SUBROUTINE pmc_childinit
[1762]203
204
205
[2801]206 SUBROUTINE pmc_set_dataarray_name( parentarraydesc, parentarrayname,          &
[1933]207                                    childarraydesc, childarrayname, istat )
[1762]208
[1896]209    IMPLICIT NONE
[1762]210
[1933]211    CHARACTER(LEN=*), INTENT(IN) ::  parentarrayname  !<
212    CHARACTER(LEN=*), INTENT(IN) ::  parentarraydesc  !<
213    CHARACTER(LEN=*), INTENT(IN) ::  childarrayname   !<
214    CHARACTER(LEN=*), INTENT(IN) ::  childarraydesc   !<
[1762]215
[2801]216    INTEGER(iwp), INTENT(OUT) ::  istat  !<
[1896]217!
218!-- Local variables
219    TYPE(da_namedef) ::  myname  !<
[1762]220
[2801]221    INTEGER(iwp) ::  mype  !<
222    INTEGER(iwp) ::  my_addiarray = 0  !<
[1762]223
224
[1896]225    istat = pmc_status_ok
226!
227!-- Check length of array names
[2801]228    IF ( LEN( TRIM( parentarrayname) ) > da_namelen  .OR.                      &
[1933]229         LEN( TRIM( childarrayname) ) > da_namelen )  THEN
[1896]230       istat = pmc_da_name_err
231    ENDIF
[1762]232
[1896]233    IF ( m_model_rank == 0 )  THEN
234       myindex = myindex + 1
235       myname%couple_index = myIndex
[1933]236       myname%parentdesc   = TRIM( parentarraydesc )
237       myname%nameonparent = TRIM( parentarrayname )
238       myname%childdesc    = TRIM( childarraydesc )
239       myname%nameonchild  = TRIM( childarrayname )
[1896]240    ENDIF
[1762]241
[1896]242!
[2599]243!-- Broadcast to all child processes
[2801]244!
245!-- The complete description of an transfer names array is broadcasted
246
[1896]247    CALL pmc_bcast( myname%couple_index, 0, comm=m_model_comm )
[1933]248    CALL pmc_bcast( myname%parentdesc,   0, comm=m_model_comm )
249    CALL pmc_bcast( myname%nameonparent, 0, comm=m_model_comm )
250    CALL pmc_bcast( myname%childdesc,    0, comm=m_model_comm )
251    CALL pmc_bcast( myname%nameonchild,  0, comm=m_model_comm )
[1896]252!
[2599]253!-- Broadcast to all parent processes
[2801]254!-- The complete description of an transfer array names is broadcasted als to all parent processe
255!   Only the root PE of the broadcasts to parent using intra communicator
256
[1896]257    IF ( m_model_rank == 0 )  THEN
258        mype = MPI_ROOT
259    ELSE
260        mype = MPI_PROC_NULL
261    ENDIF
[1762]262
[1933]263    CALL pmc_bcast( myname%couple_index, mype, comm=m_to_parent_comm )
264    CALL pmc_bcast( myname%parentdesc,   mype, comm=m_to_parent_comm )
265    CALL pmc_bcast( myname%nameonparent, mype, comm=m_to_parent_comm )
266    CALL pmc_bcast( myname%childdesc,    mype, comm=m_to_parent_comm )
267    CALL pmc_bcast( myname%nameonchild,  mype, comm=m_to_parent_comm )
[1762]268
[1933]269    CALL pmc_g_setname( me, myname%couple_index, myname%nameonchild )
[1762]270
[1896]271 END SUBROUTINE pmc_set_dataarray_name
[1762]272
273
274
[1896]275 SUBROUTINE pmc_set_dataarray_name_lastentry( lastentry )
[1762]276
[1896]277    IMPLICIT NONE
[1762]278
[1896]279    LOGICAL, INTENT(IN), OPTIONAL ::  lastentry  !<
280!
281!-- Local variables
282    INTEGER ::  mype  !<
283    TYPE(dA_namedef) ::  myname  !<
[1762]284
[1896]285    myname%couple_index = -1
[1762]286
[1896]287    IF ( m_model_rank == 0 )  THEN
288       mype = MPI_ROOT
289    ELSE
290       mype = MPI_PROC_NULL
291    ENDIF
[1762]292
[1933]293    CALL pmc_bcast( myname%couple_index, mype, comm=m_to_parent_comm )
[1762]294
[1896]295 END SUBROUTINE pmc_set_dataarray_name_lastentry
[1762]296
297
298
[1896]299 SUBROUTINE pmc_c_get_2d_index_list
[1762]300
[1896]301    IMPLICIT NONE
[1762]302
[2801]303    INTEGER(iwp) :: dummy               !<
304    INTEGER(iwp) :: i, ierr, i2, j, nr  !<
305    INTEGER(iwp) :: indwin              !< MPI window object
306    INTEGER(iwp) :: indwin2             !< MPI window object
[1779]307
[1896]308    INTEGER(KIND=MPI_ADDRESS_KIND) :: win_size !< Size of MPI window 1 (in bytes)
309    INTEGER(KIND=MPI_ADDRESS_KIND) :: disp     !< Displacement unit (Integer = 4, floating poit = 8
310    INTEGER(KIND=MPI_ADDRESS_KIND) :: winsize  !< Size of MPI window 2 (in bytes)
[1779]311
[1896]312    INTEGER, DIMENSION(me%inter_npes*2) :: nrele  !< Number of Elements of a
313                                                  !< horizontal slice
314    INTEGER, DIMENSION(:), POINTER ::  myind  !<
[1779]315
[1896]316    TYPE(pedef), POINTER ::  ape  !> Pointer to pedef structure
[1762]317
318
[2809]319    win_size = STORAGE_SIZE( dummy )/8
[2801]320    CALL MPI_WIN_CREATE( dummy, win_size, iwp, MPI_INFO_NULL, me%intra_comm,   &
[1896]321                         indwin, ierr )
322!
[2801]323!-- Close window on child side and open on parent side
[1896]324    CALL MPI_WIN_FENCE( 0, indwin, ierr )
[2801]325
326!   Between the two MPI_WIN_FENCE calls, the parent can fill the RMA window
327
[1933]328!-- Close window on parent side and open on child side
[2801]329
[1896]330    CALL MPI_WIN_FENCE( 0, indwin, ierr )
[1762]331
[1896]332    DO  i = 1, me%inter_npes
333       disp = me%model_rank * 2
[2801]334       CALL MPI_GET( nrele((i-1)*2+1), 2, MPI_INTEGER, i-1, disp, 2,           &
[1896]335                     MPI_INTEGER, indwin, ierr )
336    ENDDO
337!
338!-- MPI_GET is non-blocking -> data in nrele is not available until MPI_FENCE is
339!-- called
340    CALL MPI_WIN_FENCE( 0, indwin, ierr )
341!
342!-- Allocate memory for index array
343    winsize = 0
344    DO  i = 1, me%inter_npes
345       ape => me%pes(i)
346       i2 = ( i-1 ) * 2 + 1
347       nr = nrele(i2+1)
348       IF ( nr > 0 )  THEN
349          ALLOCATE( ape%locind(nr) )
350       ELSE
351          NULLIFY( ape%locind )
352       ENDIF
353       winsize = MAX( nr, winsize )
354    ENDDO
[1762]355
[1896]356    ALLOCATE( myind(2*winsize) )
357    winsize = 1
358!
359!-- Local buffer used in MPI_GET can but must not be inside the MPI Window.
[2599]360!-- Here, we use a dummy for the MPI window because the parent processes do
361!-- not access the RMA window via MPI_GET or MPI_PUT
[2801]362    CALL MPI_WIN_CREATE( dummy, winsize, iwp, MPI_INFO_NULL, me%intra_comm,    &
[1896]363                         indwin2, ierr )
364!
365!-- MPI_GET is non-blocking -> data in nrele is not available until MPI_FENCE is
366!-- called
[2801]367
[1896]368    CALL MPI_WIN_FENCE( 0, indwin2, ierr )
[2801]369
370!   Between the two MPI_WIN_FENCE calls, the parent can fill the RMA window
371
[1896]372    CALL MPI_WIN_FENCE( 0, indwin2, ierr )
[1779]373
[1896]374    DO  i = 1, me%inter_npes
375       ape => me%pes(i)
376       nr = nrele(i*2)
377       IF ( nr > 0 )  THEN
378          disp = nrele(2*(i-1)+1)
379          CALL MPI_WIN_LOCK( MPI_LOCK_SHARED , i-1, 0, indwin2, ierr )
[2801]380          CALL MPI_GET( myind, 2*nr, MPI_INTEGER, i-1, disp, 2*nr,             &
[1896]381                        MPI_INTEGER, indwin2, ierr )
382          CALL MPI_WIN_UNLOCK( i-1, indwin2, ierr )
383          DO  j = 1, nr
384             ape%locind(j)%i = myind(2*j-1)
385             ape%locind(j)%j = myind(2*j)
386          ENDDO
387          ape%nrele = nr
388       ELSE
389          ape%nrele = -1
390       ENDIF
391    ENDDO
392!
393!-- Don't know why, but this barrier is necessary before we can free the windows
394    CALL MPI_BARRIER( me%intra_comm, ierr )
[1779]395
[1896]396    CALL MPI_WIN_FREE( indWin,  ierr )
397    CALL MPI_WIN_FREE( indwin2, ierr )
398    DEALLOCATE( myind )
[1762]399
[1896]400 END SUBROUTINE pmc_c_get_2d_index_list
[1762]401
[1779]402
403
[1896]404 SUBROUTINE pmc_c_clear_next_array_list
[1762]405
[1896]406    IMPLICIT NONE
[1762]407
[1896]408    next_array_in_list = 0
[1762]409
[1896]410 END SUBROUTINE pmc_c_clear_next_array_list
[1762]411
412
[1779]413
[1896]414 LOGICAL FUNCTION pmc_c_getnextarray( myname )
[1933]415
[1896]416!
417!--  List handling is still required to get minimal interaction with
418!--  pmc_interface
419     CHARACTER(LEN=*), INTENT(OUT) ::  myname  !<
420!
421!-- Local variables
422    TYPE(pedef), POINTER    :: ape
423    TYPE(arraydef), POINTER :: ar
[1779]424
425
[1896]426    next_array_in_list = next_array_in_list + 1
427!
[2599]428!-- Array names are the same on all child PEs, so take first process to
429!-- get the name   
[1896]430    ape => me%pes(1)
431!
432!-- Check if all arrays have been processed
433    IF ( next_array_in_list > ape%nr_arrays )  THEN
434       pmc_c_getnextarray = .FALSE.
435       RETURN
436    ENDIF
[1762]437
[1896]438    ar => ape%array_list( next_array_in_list )
[1762]439
[1896]440    myname = ar%name
441!
[2801]442!-- Return true if annother array
443!-- If all array have been processed, the RETURN statement a couple of lines above is active
444
[1896]445    pmc_c_getnextarray = .TRUE.
[1762]446
[2801]447 END FUNCTION pmc_c_getnextarray
[1764]448
[1762]449
[1786]450
[1896]451 SUBROUTINE pmc_c_set_dataarray_2d( array )
[1762]452
[1896]453    IMPLICIT NONE
[1762]454
[1896]455    REAL(wp), INTENT(IN) , DIMENSION(:,:), POINTER ::  array  !<
[1762]456
[2801]457    INTEGER(iwp)               ::  i       !<
458    INTEGER(iwp)               ::  nrdims  !<
459    INTEGER(iwp), DIMENSION(4) ::  dims    !<
[1786]460
[1896]461    TYPE(C_PTR)             ::  array_adr
462    TYPE(arraydef), POINTER ::  ar
463    TYPE(pedef), POINTER    ::  ape
[1762]464
465
[1896]466    dims    = 1
467    nrdims  = 2
468    dims(1) = SIZE( array, 1 )
469    dims(2) = SIZE( array, 2 )
[1762]470
[1896]471    array_adr = C_LOC( array )
[1786]472
[1896]473    DO  i = 1, me%inter_npes
474       ape => me%pes(i)
475       ar  => ape%array_list(next_array_in_list)
476       ar%nrdims = nrdims
[2801]477       ar%dimkey = nrdims
[1896]478       ar%a_dim  = dims
479       ar%data   = array_adr
480    ENDDO
[1786]481
[1896]482 END SUBROUTINE pmc_c_set_dataarray_2d
[1786]483
[2801]484 SUBROUTINE pmc_c_set_dataarray_ip2d( array )
[1786]485
[2801]486    IMPLICIT NONE
[1786]487
[2801]488    INTEGER(idp), INTENT(IN) , DIMENSION(:,:), POINTER ::  array  !<
489
490    INTEGER(iwp)               ::  i       !<
491    INTEGER(iwp)               ::  nrdims  !<
492    INTEGER(iwp), DIMENSION(4) ::  dims    !<
493
494    TYPE(C_PTR)             ::  array_adr
495    TYPE(arraydef), POINTER ::  ar
496    TYPE(pedef), POINTER    ::  ape
497
498    dims    = 1
499    nrdims  = 2
500    dims(1) = SIZE( array, 1 )
501    dims(2) = SIZE( array, 2 )
502
503    array_adr = C_LOC( array )
504
505    DO  i = 1, me%inter_npes
506       ape => me%pes(i)
507       ar  => ape%array_list(next_array_in_list)
508       ar%nrdims = nrdims
509       ar%dimkey = 22
510       ar%a_dim  = dims
511       ar%data   = array_adr
512    ENDDO
513
514 END SUBROUTINE pmc_c_set_dataarray_ip2d
515
[1896]516 SUBROUTINE pmc_c_set_dataarray_3d (array)
[1786]517
[1896]518    IMPLICIT NONE
[1786]519
[1896]520    REAL(wp), INTENT(IN), DIMENSION(:,:,:), POINTER ::  array  !<
[1786]521
[2801]522    INTEGER(iwp)                ::  i
523    INTEGER(iwp)                ::  nrdims
524    INTEGER(iwp), DIMENSION (4) ::  dims
525   
[1896]526    TYPE(C_PTR)             ::  array_adr
527    TYPE(pedef), POINTER    ::  ape
528    TYPE(arraydef), POINTER ::  ar
[1786]529
530
[1896]531    dims    = 1
532    nrdims  = 3
533    dims(1) = SIZE( array, 1 )
534    dims(2) = SIZE( array, 2 )
535    dims(3) = SIZE( array, 3 )
[1786]536
[1896]537    array_adr = C_LOC( array )
[1786]538
[1896]539    DO  i = 1, me%inter_npes
540       ape => me%pes(i)
541       ar  => ape%array_list(next_array_in_list)
542       ar%nrdims = nrdims
[2801]543       ar%dimkey = nrdims
[1896]544       ar%a_dim  = dims
545       ar%data   = array_adr
546    ENDDO
[1786]547
[1896]548 END SUBROUTINE pmc_c_set_dataarray_3d
[1762]549
550
551
[1896]552 SUBROUTINE pmc_c_setind_and_allocmem
[1762]553
[1896]554    IMPLICIT NONE
[1933]555
[1896]556!
[1933]557!-- Naming convention for appendices:  _pc  -> parent to child transfer
558!--                                    _cp  -> child to parent transfer
559!--                                    recv -> parent to child transfer
560!--                                    send -> child to parent transfer
[1896]561    CHARACTER(LEN=da_namelen) ::  myname  !<
[1786]562
[2801]563    INTEGER(iwp) ::  arlen    !<
564    INTEGER(iwp) ::  myindex  !<
565    INTEGER(iwp) ::  i        !<
566    INTEGER(iwp) ::  ierr     !<
567    INTEGER(iwp) ::  istat    !<
568    INTEGER(iwp) ::  j        !<
569    INTEGER(iwp) ::  rcount   !<
570    INTEGER(iwp) ::  tag      !<
[1762]571
[2801]572    INTEGER(iwp), PARAMETER ::  noindex = -1  !<
[1762]573
[1896]574    INTEGER(idp)                   ::  bufsize  !< size of MPI data window
575    INTEGER(KIND=MPI_ADDRESS_KIND) ::  winsize  !<
[1762]576
[2801]577    INTEGER(iwp),DIMENSION(1024) ::  req  !<
[1779]578
[1933]579    REAL(wp), DIMENSION(:), POINTER, SAVE ::  base_array_pc  !< base array
580    REAL(wp), DIMENSION(:), POINTER, SAVE ::  base_array_cp  !< base array
[1762]581
[1896]582    TYPE(pedef), POINTER    ::  ape       !<
583    TYPE(arraydef), POINTER ::  ar        !<
584    Type(C_PTR)             ::  base_ptr  !<
[1779]585
[1762]586
[1896]587    myindex = 0
588    bufsize = 8
[1797]589!
[1933]590!-- Parent to child direction.
[1896]591!-- First stride: compute size and set index
592    DO  i = 1, me%inter_npes
593       ape => me%pes(i)
594       tag = 200
595       DO  j = 1, ape%nr_arrays
596          ar => ape%array_list(j)
597!
[1933]598!--       Receive index from child
[1896]599          tag = tag + 1
[2801]600          CALL MPI_RECV( myindex, 1, MPI_INTEGER, i-1, tag, me%inter_comm,     &
[1896]601                         MPI_STATUS_IGNORE, ierr )
602          ar%recvindex = myindex
603!
[1933]604!--       Determine max, because child buffer is allocated only once
[2801]605!--       All 2D and 3d arrays use the same buffer
606
607          IF ( ar%nrdims == 3 )  THEN
[1896]608             bufsize = MAX( bufsize, ar%a_dim(1)*ar%a_dim(2)*ar%a_dim(3) )
609          ELSE
610             bufsize = MAX( bufsize, ar%a_dim(1)*ar%a_dim(2) )
611          ENDIF
612       ENDDO
613    ENDDO
[1779]614!
[1896]615!-- Create RMA (one sided communication) data buffer.
616!-- The buffer for MPI_GET can be PE local, i.e. it can but must not be part of
617!-- the MPI RMA window
[1933]618    CALL pmc_alloc_mem( base_array_pc, bufsize, base_ptr )
[1896]619    me%totalbuffersize = bufsize*wp  ! total buffer size in byte
620!
621!-- Second stride: set buffer pointer
622    DO  i = 1, me%inter_npes
623       ape => me%pes(i)
624       DO  j = 1, ape%nr_arrays
625          ar => ape%array_list(j)
626          ar%recvbuf = base_ptr
627       ENDDO
628    ENDDO
629!
[1933]630!-- Child to parent direction
[1896]631    myindex = 1
632    rcount  = 0
633    bufsize = 8
[1762]634
[1896]635    DO  i = 1, me%inter_npes
636       ape => me%pes(i)
637       tag = 300
638       DO  j = 1, ape%nr_arrays
639          ar => ape%array_list(j)
[2801]640          IF ( ar%nrdims == 2 )  THEN
[1896]641             arlen = ape%nrele
642          ELSEIF( ar%nrdims == 3 )  THEN
643             arlen = ape%nrele*ar%a_dim(1)
644          ENDIF
645          tag    = tag + 1
646          rcount = rcount + 1
647          IF ( ape%nrele > 0 )  THEN
[2801]648             CALL MPI_ISEND( myindex, 1, MPI_INTEGER, i-1, tag, me%inter_comm, &
[1896]649                             req(rcount), ierr )
650             ar%sendindex = myindex
651          ELSE
[2801]652             CALL MPI_ISEND( noindex, 1, MPI_INTEGER, i-1, tag, me%inter_comm, &
[1896]653                             req(rcount), ierr )
654             ar%sendindex = noindex
655          ENDIF
656!
[2801]657!--       Maximum of 1024 pending requests
658!         1024 is an arbitrary value just to make sure the number of pending
659!         requests is getting too large. It is possible that this value has to
660!         be adjusted in case of running the model on large number of cores.
661
[1896]662          IF ( rcount == 1024 )  THEN
663             CALL MPI_WAITALL( rcount, req, MPI_STATUSES_IGNORE, ierr )
664             rcount = 0
665          ENDIF
[1762]666
[1896]667          IF ( ape%nrele > 0 )  THEN
668             ar%sendsize = arlen
669             myindex     = myindex + arlen
670             bufsize     = bufsize + arlen
671          ENDIF
[1762]672
[1896]673       ENDDO
[1762]674
[1896]675       IF ( rcount > 0 )  THEN
676          CALL MPI_WAITALL( rcount, req, MPI_STATUSES_IGNORE, ierr )
677       ENDIF
[1762]678
[1896]679    ENDDO
680!
[1933]681!-- Create RMA (one sided communication) window for data buffer child to parent
[1896]682!-- transfer.
683!-- The buffer of MPI_GET (counter part of transfer) can be PE-local, i.e. it
684!-- can but must not be part of the MPI RMA window. Only one RMA window is
685!-- required to prepare the data
[1933]686!--        for parent -> child transfer on the parent side
[1896]687!-- and
[1933]688!--        for child -> parent transfer on the child side
689    CALL pmc_alloc_mem( base_array_cp, bufsize )
[1896]690    me%totalbuffersize = bufsize * wp  ! total buffer size in byte
691
692    winSize = me%totalbuffersize
693
[2801]694    CALL MPI_WIN_CREATE( base_array_cp, winsize, wp, MPI_INFO_NULL,            &
[1933]695                         me%intra_comm, me%win_parent_child, ierr )
696    CALL MPI_WIN_FENCE( 0, me%win_parent_child, ierr )
[1896]697    CALL MPI_BARRIER( me%intra_comm, ierr )
698!
699!-- Second stride: set buffer pointer
700    DO  i = 1, me%inter_npes
701       ape => me%pes(i)
702       DO  j = 1, ape%nr_arrays
[2599]703          ar => ape%array_list(j)         
[1896]704          IF ( ape%nrele > 0 )  THEN
[1933]705             ar%sendbuf = C_LOC( base_array_cp(ar%sendindex) )
706!
[1896]707!--          TODO: if this is an error to be really expected, replace the
708!--                following message by a meaningful standard PALM message using
709!--                the message-routine
710             IF ( ar%sendindex+ar%sendsize > bufsize )  THEN
[2801]711                WRITE( 0,'(a,i4,4i7,1x,a)') 'Child buffer too small ', i,      &
712                          ar%sendindex, ar%sendsize, ar%sendindex+ar%sendsize, &
[1896]713                          bufsize, TRIM( ar%name )
714                CALL MPI_ABORT( MPI_COMM_WORLD, istat, ierr )
715             ENDIF
716          ENDIF
717       ENDDO
718    ENDDO
719
720 END SUBROUTINE pmc_c_setind_and_allocmem
721
722
723
[2801]724 SUBROUTINE pmc_c_getbuffer( waittime, particle_transfer )
[1896]725
726    IMPLICIT NONE
727
728    REAL(wp), INTENT(OUT), OPTIONAL ::  waittime  !<
[2801]729    LOGICAL, INTENT(IN), OPTIONAL   ::  particle_transfer  !<
[1896]730
731    CHARACTER(LEN=da_namelen) ::  myname  !<
[2801]732   
733    LOGICAL                        ::  lo_ptrans!<
734   
735    INTEGER(iwp)                        ::  ierr    !<
736    INTEGER(iwp)                        ::  ij      !<
737    INTEGER(iwp)                        ::  ip      !<
738    INTEGER(iwp)                        ::  j       !<
739    INTEGER(iwp)                        ::  myindex !<
740    INTEGER(iwp)                        ::  nr      !< number of elements to get
741                                                    !< from parent
[1896]742    INTEGER(KIND=MPI_ADDRESS_KIND) ::  target_disp
743    INTEGER,DIMENSION(1)           ::  buf_shape
744
745    REAL(wp)                            ::  t1
746    REAL(wp)                            ::  t2
747
748    REAL(wp), POINTER, DIMENSION(:)     ::  buf
749    REAL(wp), POINTER, DIMENSION(:,:)   ::  data_2d
750    REAL(wp), POINTER, DIMENSION(:,:,:) ::  data_3d
751    TYPE(pedef), POINTER                ::  ape
752    TYPE(arraydef), POINTER             ::  ar
[2801]753    INTEGER(idp), POINTER, DIMENSION(:)     ::  ibuf      !<
754    INTEGER(idp), POINTER, DIMENSION(:,:)   ::  idata_2d  !<
[1896]755
756!
[1933]757!-- Synchronization of the model is done in pmci_synchronize.
758!-- Therefore the RMA window can be filled without
[1896]759!-- sychronization at this point and a barrier is not necessary.
[2801]760
761!-- In case waittime is present, the following barrier is necessary to
762!-- insure the same number of barrier calls on parent and child
763!-- This means, that here on child side two barriers are call successively
764!-- The parent is filling its buffer between the two barrier calls
765
[1896]766!-- Please note that waittime has to be set in pmc_s_fillbuffer AND
767!-- pmc_c_getbuffer
768    IF ( PRESENT( waittime ) )  THEN
769       t1 = pmc_time()
770       CALL MPI_BARRIER( me%intra_comm, ierr )
771       t2 = pmc_time()
772       waittime = t2 - t1
773    ENDIF
[2801]774
775    lo_ptrans = .FALSE.
776    IF ( PRESENT( particle_transfer))    lo_ptrans = particle_transfer
777
[1896]778!
[1933]779!-- Wait for buffer is filled.
[2801]780!
781!-- The parent side (in pmc_s_fillbuffer) is filling the buffer in the MPI RMA window
782!-- When the filling is complet, a MPI_BARRIER is called.
783!-- The child is not allowd to access the parent-buffer before it is completely filled
784!-- therefore the following barrier is required.
785
[1896]786    CALL MPI_BARRIER( me%intra_comm, ierr )
787
788    DO  ip = 1, me%inter_npes
789       ape => me%pes(ip)
790       DO  j = 1, ape%nr_arrays
791          ar => ape%array_list(j)
[2801]792
793          IF ( ar%dimkey == 2 .AND. .NOT.lo_ptrans)  THEN
[1896]794             nr = ape%nrele
[2801]795          ELSEIF ( ar%dimkey == 3 .AND. .NOT.lo_ptrans)  THEN
[1896]796             nr = ape%nrele * ar%a_dim(1)
[2801]797          ELSE IF ( ar%dimkey == 22 .AND. lo_ptrans)  THEN
798             nr = ape%nrele
799          ELSE
800             CYCLE                    ! Particle array ar not transferd here
[1896]801          ENDIF
802          buf_shape(1) = nr
[2801]803          IF ( lo_ptrans )   THEN
804             CALL C_F_POINTER( ar%recvbuf, ibuf, buf_shape )
805          ELSE
806             CALL C_F_POINTER( ar%recvbuf, buf, buf_shape )
807          ENDIF
[1896]808!
809!--       MPI passive target RMA
[2801]810!--       One data array is fetcht from MPI RMA window on parent
811
[1896]812          IF ( nr > 0 )  THEN
813             target_disp = ar%recvindex - 1
[2801]814             CALL MPI_WIN_LOCK( MPI_LOCK_SHARED , ip-1, 0,                     &
[1933]815                                me%win_parent_child, ierr )
[2801]816             IF ( lo_ptrans )   THEN
817                CALL MPI_GET( ibuf, nr*8, MPI_BYTE, ip-1, target_disp, nr*8, MPI_BYTE,  &               !There is no MPI_INTEGER8 datatype
818                                   me%win_parent_child, ierr )
819             ELSE
820                CALL MPI_GET( buf, nr, MPI_REAL, ip-1, target_disp, nr,        &
821                              MPI_REAL, me%win_parent_child, ierr )
822             ENDIF
[1933]823             CALL MPI_WIN_UNLOCK( ip-1, me%win_parent_child, ierr )
[1896]824          ENDIF
825          myindex = 1
[2801]826          IF ( ar%dimkey == 2 .AND. .NOT.lo_ptrans)  THEN
827
[1896]828             CALL C_F_POINTER( ar%data, data_2d, ar%a_dim(1:2) )
829             DO  ij = 1, ape%nrele
830                data_2d(ape%locind(ij)%j,ape%locind(ij)%i) = buf(myindex)
831                myindex = myindex + 1
832             ENDDO
[2801]833
834          ELSEIF ( ar%dimkey == 3 .AND. .NOT.lo_ptrans)  THEN
835
[1896]836             CALL C_F_POINTER( ar%data, data_3d, ar%a_dim(1:3) )
837             DO  ij = 1, ape%nrele
[2801]838                data_3d(:,ape%locind(ij)%j,ape%locind(ij)%i) =                 &
[1896]839                                              buf(myindex:myindex+ar%a_dim(1)-1)
840                myindex = myindex+ar%a_dim(1)
841             ENDDO
[2801]842
843          ELSEIF ( ar%dimkey == 22 .AND. lo_ptrans)  THEN
844             CALL C_F_POINTER( ar%data, idata_2d, ar%a_dim(1:2) )
845
846             DO  ij = 1, ape%nrele
847                idata_2d(ape%locind(ij)%j,ape%locind(ij)%i) = ibuf(myindex)
848                myindex = myindex + 1
849             ENDDO
850
[1896]851          ENDIF
852       ENDDO
853    ENDDO
854
855 END SUBROUTINE pmc_c_getbuffer
856
857
858
[2801]859 SUBROUTINE pmc_c_putbuffer( waittime , particle_transfer )
[1896]860
861    IMPLICIT NONE
862
863    REAL(wp), INTENT(OUT), OPTIONAL ::  waittime  !<
[2801]864    LOGICAL, INTENT(IN), OPTIONAL   ::  particle_transfer  !<
[1896]865
866    CHARACTER(LEN=da_namelen) ::  myname  !<
[2801]867   
868    LOGICAL ::  lo_ptrans!<
869   
870    INTEGER(iwp) ::  ierr         !<
871    INTEGER(iwp) ::  ij           !<
872    INTEGER(iwp) ::  ip           !<
873    INTEGER(iwp) ::  j            !<
874    INTEGER(iwp) ::  myindex      !<
875    INTEGER(iwp) ::  nr           !< number of elements to get from parent
876   
[1896]877    INTEGER(KIND=MPI_ADDRESS_KIND) ::  target_disp  !<
[2801]878   
[1896]879
[2801]880    INTEGER(iwp), DIMENSION(1) ::  buf_shape    !<
[1896]881
882    REAL(wp) ::  t1  !<
883    REAL(wp) ::  t2  !<
884
[2801]885    REAL(wp), POINTER, DIMENSION(:)         ::  buf      !<
886    REAL(wp), POINTER, DIMENSION(:,:)       ::  data_2d  !<
887    REAL(wp), POINTER, DIMENSION(:,:,:)     ::  data_3d  !<
888   
889    INTEGER(idp), POINTER, DIMENSION(:)     ::  ibuf      !<
890    INTEGER(idp), POINTER, DIMENSION(:,:)   ::  idata_2d  !<
[1896]891
[2801]892    TYPE(pedef), POINTER                    ::  ape  !<
893    TYPE(arraydef), POINTER                 ::  ar   !<
[1896]894
895!
896!-- Wait for empty buffer
[2801]897!-- Switch RMA epoche
898
[1896]899    t1 = pmc_time()
900    CALL MPI_BARRIER( me%intra_comm, ierr )
901    t2 = pmc_time()
902    IF ( PRESENT( waittime ) )  waittime = t2 - t1
903
[2801]904    lo_ptrans = .FALSE.
905    IF ( PRESENT( particle_transfer))    lo_ptrans = particle_transfer
906
[1896]907    DO  ip = 1, me%inter_npes
908       ape => me%pes(ip)
909       DO  j = 1, ape%nr_arrays
910          ar => aPE%array_list(j)
911          myindex = 1
[2801]912
913          IF ( ar%dimkey == 2 .AND. .NOT.lo_ptrans )  THEN
914
[1896]915             buf_shape(1) = ape%nrele
916             CALL C_F_POINTER( ar%sendbuf, buf,     buf_shape     )
917             CALL C_F_POINTER( ar%data,    data_2d, ar%a_dim(1:2) )
918             DO  ij = 1, ape%nrele
919                buf(myindex) = data_2d(ape%locind(ij)%j,ape%locind(ij)%i)
920                myindex = myindex + 1
921             ENDDO
[2801]922
923          ELSEIF ( ar%dimkey == 3 .AND. .NOT.lo_ptrans )  THEN
924
[1896]925             buf_shape(1) = ape%nrele*ar%a_dim(1)
926             CALL C_F_POINTER( ar%sendbuf, buf,     buf_shape     )
927             CALL C_F_POINTER( ar%data,    data_3d, ar%a_dim(1:3) )
928             DO  ij = 1, ape%nrele
[1933]929                buf(myindex:myindex+ar%a_dim(1)-1) =                            &
[1896]930                                    data_3d(:,ape%locind(ij)%j,ape%locind(ij)%i)
931                myindex = myindex + ar%a_dim(1)
932             ENDDO
[2801]933
934          ELSE IF ( ar%dimkey == 22 .AND. lo_ptrans)  THEN
935
936             buf_shape(1) = ape%nrele
937             CALL C_F_POINTER( ar%sendbuf, ibuf,     buf_shape     )
938             CALL C_F_POINTER( ar%data,    idata_2d, ar%a_dim(1:2) )
939
940             DO  ij = 1, ape%nrele
941                ibuf(myindex) = idata_2d(ape%locind(ij)%j,ape%locind(ij)%i)
942                myindex = myindex + 1
943             ENDDO
944
[1896]945          ENDIF
946       ENDDO
947    ENDDO
948!
949!-- Buffer is filled
[2801]950!-- Switch RMA epoche
951
[1896]952    CALL MPI_Barrier(me%intra_comm, ierr)
953
954 END SUBROUTINE pmc_c_putbuffer
955
[1764]956#endif
[1933]957 END MODULE pmc_child
Note: See TracBrowser for help on using the repository browser.