1!--------------------------------------------------------------------------------------------------!
2!   CP2K: A general program to perform molecular dynamics simulations                              !
3!   Copyright (C) 2000 - 2020  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 mp_environ(taskid=para_env%mepos, numtask=para_env%num_pe, groupid=group)
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 creates a cart (multidimensional parallel environment)
121!> \param cart the cart environment to create
122!> \param group the mpi communicator
123!> \param ndims the number of dimensions of the cart
124!> \param owns_group if this object owns the underlying cart (and should
125!>        free it)
126!> \author fawzi
127! **************************************************************************************************
128   SUBROUTINE cp_cart_create(cart, group, ndims, owns_group)
129      TYPE(cp_para_cart_type), POINTER                   :: cart
130      INTEGER, INTENT(in)                                :: group, ndims
131      LOGICAL, INTENT(in), OPTIONAL                      :: owns_group
132
133      CHARACTER(len=*), PARAMETER :: routineN = 'cp_cart_create', routineP = moduleN//':'//routineN
134
135      CPASSERT(.NOT. ASSOCIATED(cart))
136      ALLOCATE (cart)
137      cart%owns_group = .TRUE.
138      IF (PRESENT(owns_group)) cart%owns_group = owns_group
139      cart%ndims = ndims
140      cart%group = group
141
142      ALLOCATE (cart%source(ndims), cart%periodic(ndims), cart%mepos(ndims), &
143                cart%num_pe(ndims))
144
145      cart%source = 0
146      cart%mepos = 0
147      cart%periodic = .FALSE.
148      cart%ref_count = 1
149      cart%ntask = 1
150      CALL cp_cart_update(cart)
151   END SUBROUTINE cp_cart_create
152
153! **************************************************************************************************
154!> \brief updates the information about the given cart
155!> \param cart the cart to update
156!> \author fawzi
157! **************************************************************************************************
158   SUBROUTINE cp_cart_update(cart)
159      TYPE(cp_para_cart_type), POINTER                   :: cart
160
161      CHARACTER(len=*), PARAMETER :: routineN = 'cp_cart_update', routineP = moduleN//':'//routineN
162
163      CPASSERT(ASSOCIATED(cart))
164      CPASSERT(cart%ref_count > 0)
165      CALL mp_environ(cart%group, cart%ndims, cart%num_pe, task_coor=cart%mepos, &
166                      periods=cart%periodic)
167      CALL mp_environ(numtask=cart%ntask, taskid=cart%rank, groupid=cart%group)
168   END SUBROUTINE cp_cart_update
169
170! **************************************************************************************************
171!> \brief releases the given cart
172!> \param cart the cart to release
173!> \author fawzi
174! **************************************************************************************************
175   SUBROUTINE cp_cart_release(cart)
176      TYPE(cp_para_cart_type), POINTER                   :: cart
177
178      CHARACTER(len=*), PARAMETER :: routineN = 'cp_cart_release', &
179         routineP = moduleN//':'//routineN
180
181      IF (ASSOCIATED(cart)) THEN
182         CPASSERT(cart%ref_count > 0)
183         cart%ref_count = cart%ref_count - 1
184         IF (cart%ref_count == 0) THEN
185            IF (cart%owns_group) THEN
186               CALL mp_comm_free(cart%group)
187            END IF
188            DEALLOCATE (cart%source, cart%periodic, cart%mepos, cart%num_pe)
189            DEALLOCATE (cart)
190         END IF
191      END IF
192      NULLIFY (cart)
193   END SUBROUTINE cp_cart_release
194
195END MODULE cp_para_env
196