1!--------------------------------------------------------------------------------------------------!
2!   CP2K: A general program to perform molecular dynamics simulations                              !
3!   Copyright (C) 2000 - 2019  CP2K developers group                                               !
4!--------------------------------------------------------------------------------------------------!
5
6! **************************************************************************************************
7!> \brief type to store parallelization informations (at the moment assumes 1d
8!>      position and uses mpi)
9!> \par History
10!>      07.2002 created [fawzi]
11!> \author Fawzi Mohamed
12! **************************************************************************************************
13MODULE cp_para_env
14   USE cp_para_types,                   ONLY: cp_para_cart_type,&
15                                              cp_para_env_type
16   USE message_passing,                 ONLY: mp_comm_free,&
17                                              mp_environ
18#include "../base/base_uses.f90"
19
20   IMPLICIT NONE
21   PRIVATE
22
23   LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .TRUE.
24   CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'cp_para_env'
25
26   PUBLIC :: cp_para_env_retain, cp_para_env_release, cp_para_env_create
27   PUBLIC :: cp_cart_create, cp_cart_release
28!***
29CONTAINS
30
31! **************************************************************************************************
32!> \brief creates a new para environment
33!> \param para_env the new parallel environment
34!> \param group the id of the actual mpi_group
35!> \param source the id of the special (master) processor (defaults to 0)
36!> \param mepos the id of the actual processor
37!> \param num_pe the number of processors in the group
38!> \param owns_group if the group is owned by this object (defaults to true)
39!> \par History
40!>      08.2002 created [fawzi]
41!> \author Fawzi Mohamed
42! **************************************************************************************************
43   SUBROUTINE cp_para_env_create(para_env, group, source, mepos, num_pe, &
44                                 owns_group)
45      TYPE(cp_para_env_type), POINTER                    :: para_env
46      INTEGER, INTENT(in)                                :: group
47      INTEGER, INTENT(in), OPTIONAL                      :: source, mepos, num_pe
48      LOGICAL, INTENT(in), OPTIONAL                      :: owns_group
49
50      CHARACTER(len=*), PARAMETER :: routineN = 'cp_para_env_create', &
51         routineP = moduleN//':'//routineN
52
53      CPASSERT(.NOT. ASSOCIATED(para_env))
54      ALLOCATE (para_env)
55      para_env%group = group
56      para_env%source = 0
57      para_env%ref_count = 1
58      para_env%owns_group = .TRUE.
59      IF (PRESENT(source)) para_env%source = source
60      IF (PRESENT(owns_group)) para_env%owns_group = owns_group
61      IF (.NOT. (PRESENT(mepos) .AND. PRESENT(num_pe))) THEN
62         CALL cp_para_env_update(para_env)
63      ELSE
64         para_env%mepos = mepos
65         para_env%num_pe = num_pe
66      END IF
67      para_env%ionode = para_env%mepos == para_env%source
68   END SUBROUTINE cp_para_env_create
69
70! **************************************************************************************************
71!> \brief retains the para object (to be called when you want to keep a
72!>      shared copy of this object)
73!> \param para_env the new group
74!> \par History
75!>      08.2002 created [fawzi]
76!> \author Fawzi Mohamed
77! **************************************************************************************************
78   SUBROUTINE cp_para_env_retain(para_env)
79      TYPE(cp_para_env_type), POINTER                    :: para_env
80
81      CHARACTER(len=*), PARAMETER :: routineN = 'cp_para_env_retain', &
82         routineP = moduleN//':'//routineN
83
84      CPASSERT(ASSOCIATED(para_env))
85      CPASSERT(para_env%ref_count > 0)
86      para_env%ref_count = para_env%ref_count + 1
87   END SUBROUTINE cp_para_env_retain
88
89! **************************************************************************************************
90!> \brief releases the para object (to be called when you don't want anymore
91!>      the shared copy of this object)
92!> \param para_env the new group
93!> \par History
94!>      08.2002 created [fawzi]
95!> \author Fawzi Mohamed
96!> \note
97!>      to avoid circular dependencies cp_log_handling has a private copy
98!>      of this method (see cp_log_handling:my_cp_para_env_release)!
99! **************************************************************************************************
100   SUBROUTINE cp_para_env_release(para_env)
101      TYPE(cp_para_env_type), POINTER                    :: para_env
102
103      CHARACTER(len=*), PARAMETER :: routineN = 'cp_para_env_release', &
104         routineP = moduleN//':'//routineN
105
106      IF (ASSOCIATED(para_env)) THEN
107         CPASSERT(para_env%ref_count > 0)
108         para_env%ref_count = para_env%ref_count - 1
109         IF (para_env%ref_count < 1) THEN
110            IF (para_env%owns_group) THEN
111               CALL mp_comm_free(para_env%group)
112            END IF
113            DEALLOCATE (para_env)
114         END IF
115      END IF
116      NULLIFY (para_env)
117   END SUBROUTINE cp_para_env_release
118
119! **************************************************************************************************
120!> \brief gets again the position and size of the group from the mpi_group
121!> \param para_env the new group
122!> \par History
123!>      08.2002 created [fawzi]
124!> \author Fawzi Mohamed
125! **************************************************************************************************
126   SUBROUTINE cp_para_env_update(para_env)
127      TYPE(cp_para_env_type), POINTER                    :: para_env
128
129      CHARACTER(len=*), PARAMETER :: routineN = 'cp_para_env_update', &
130         routineP = moduleN//':'//routineN
131
132      CPASSERT(ASSOCIATED(para_env))
133      CPASSERT(para_env%ref_count > 0)
134      CALL mp_environ(taskid=para_env%mepos, numtask=para_env%num_pe, &
135                      groupid=para_env%group)
136      para_env%ionode = para_env%mepos == para_env%source
137   END SUBROUTINE cp_para_env_update
138
139! **************************************************************************************************
140!> \brief creates a cart (multidimensional parallel environment)
141!> \param cart the cart environment to create
142!> \param group the mpi communicator
143!> \param ndims the number of dimensions of the cart
144!> \param owns_group if this object owns the underlying cart (and should
145!>        free it)
146!> \author fawzi
147! **************************************************************************************************
148   SUBROUTINE cp_cart_create(cart, group, ndims, owns_group)
149      TYPE(cp_para_cart_type), POINTER                   :: cart
150      INTEGER, INTENT(in)                                :: group, ndims
151      LOGICAL, INTENT(in), OPTIONAL                      :: owns_group
152
153      CHARACTER(len=*), PARAMETER :: routineN = 'cp_cart_create', routineP = moduleN//':'//routineN
154
155      CPASSERT(.NOT. ASSOCIATED(cart))
156      ALLOCATE (cart)
157      cart%owns_group = .TRUE.
158      IF (PRESENT(owns_group)) cart%owns_group = owns_group
159      cart%ndims = ndims
160      cart%group = group
161
162      ALLOCATE (cart%source(ndims), cart%periodic(ndims), cart%mepos(ndims), &
163                cart%num_pe(ndims))
164
165      cart%source = 0
166      cart%mepos = 0
167      cart%periodic = .FALSE.
168      cart%ref_count = 1
169      cart%ntask = 1
170      CALL cp_cart_update(cart)
171   END SUBROUTINE cp_cart_create
172
173! **************************************************************************************************
174!> \brief updates the information about the given cart
175!> \param cart the cart to update
176!> \author fawzi
177! **************************************************************************************************
178   SUBROUTINE cp_cart_update(cart)
179      TYPE(cp_para_cart_type), POINTER                   :: cart
180
181      CHARACTER(len=*), PARAMETER :: routineN = 'cp_cart_update', routineP = moduleN//':'//routineN
182
183      CPASSERT(ASSOCIATED(cart))
184      CPASSERT(cart%ref_count > 0)
185      CALL mp_environ(cart%group, cart%ndims, cart%num_pe, task_coor=cart%mepos, &
186                      periods=cart%periodic)
187      CALL mp_environ(numtask=cart%ntask, taskid=cart%rank, groupid=cart%group)
188   END SUBROUTINE cp_cart_update
189
190! **************************************************************************************************
191!> \brief releases the given cart
192!> \param cart the cart to release
193!> \author fawzi
194! **************************************************************************************************
195   SUBROUTINE cp_cart_release(cart)
196      TYPE(cp_para_cart_type), POINTER                   :: cart
197
198      CHARACTER(len=*), PARAMETER :: routineN = 'cp_cart_release', &
199         routineP = moduleN//':'//routineN
200
201      IF (ASSOCIATED(cart)) THEN
202         CPASSERT(cart%ref_count > 0)
203         cart%ref_count = cart%ref_count - 1
204         IF (cart%ref_count == 0) THEN
205            IF (cart%owns_group) THEN
206               CALL mp_comm_free(cart%group)
207            END IF
208            DEALLOCATE (cart%source, cart%periodic, cart%mepos, cart%num_pe)
209            DEALLOCATE (cart)
210         END IF
211      END IF
212      NULLIFY (cart)
213   END SUBROUTINE cp_cart_release
214
215END MODULE cp_para_env
216