1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3 *
4 * (C) 2001 by Argonne National Laboratory.
5 * See COPYRIGHT in top-level directory.
6 */
7
8 #include "mpiimpl.h"
9 #include "topo.h"
10
11 /* -- Begin Profiling Symbol Block for routine MPI_Cart_sub */
12 #if defined(HAVE_PRAGMA_WEAK)
13 #pragma weak MPI_Cart_sub = PMPI_Cart_sub
14 #elif defined(HAVE_PRAGMA_HP_SEC_DEF)
15 #pragma _HP_SECONDARY_DEF PMPI_Cart_sub MPI_Cart_sub
16 #elif defined(HAVE_PRAGMA_CRI_DUP)
17 #pragma _CRI duplicate MPI_Cart_sub as PMPI_Cart_sub
18 #endif
19 /* -- End Profiling Symbol Block */
20
21 /* Define MPICH_MPI_FROM_PMPI if weak symbols are not supported to build
22 the MPI routines */
23 #ifndef MPICH_MPI_FROM_PMPI
24 #undef MPI_Cart_sub
25 #define MPI_Cart_sub PMPI_Cart_sub
26
27 #endif
28
29 #undef FUNCNAME
30 #define FUNCNAME MPI_Cart_sub
31 #undef FCNAME
32 #define FCNAME MPIU_QUOTE(FUNCNAME)
33 /*@
34
35 MPI_Cart_sub - Partitions a communicator into subgroups which
36 form lower-dimensional cartesian subgrids
37
38 Input Parameters:
39 + comm - communicator with cartesian structure (handle)
40 - remain_dims - the 'i'th entry of remain_dims specifies whether the 'i'th
41 dimension is kept in the subgrid (true) or is dropped (false) (logical
42 vector)
43
44 Output Parameter:
45 . newcomm - communicator containing the subgrid that includes the calling
46 process (handle)
47
48 .N ThreadSafe
49
50 .N Fortran
51
52 .N Errors
53 .N MPI_SUCCESS
54 .N MPI_ERR_TOPOLOGY
55 .N MPI_ERR_COMM
56 .N MPI_ERR_ARG
57 @*/
MPI_Cart_sub(MPI_Comm comm,MPICH2_CONST int * remain_dims,MPI_Comm * comm_new)58 int MPI_Cart_sub(MPI_Comm comm, MPICH2_CONST int *remain_dims, MPI_Comm *comm_new)
59 {
60 int mpi_errno = MPI_SUCCESS, all_false;
61 int ndims, key, color, ndims_in_subcomm, nnodes_in_subcomm, i, j, rank;
62 MPID_Comm *comm_ptr = NULL, *newcomm_ptr;
63 MPIR_Topology *topo_ptr, *toponew_ptr;
64 MPIU_CHKPMEM_DECL(4);
65 MPID_MPI_STATE_DECL(MPID_STATE_MPI_CART_SUB);
66
67 MPIR_ERRTEST_INITIALIZED_ORDIE();
68
69 MPIU_THREAD_CS_ENTER(ALLFUNC,);
70 MPID_MPI_FUNC_ENTER(MPID_STATE_MPI_CART_SUB);
71
72 /* Validate parameters, especially handles needing to be converted */
73 # ifdef HAVE_ERROR_CHECKING
74 {
75 MPID_BEGIN_ERROR_CHECKS;
76 {
77 MPIR_ERRTEST_COMM(comm, mpi_errno);
78 }
79 MPID_END_ERROR_CHECKS;
80 }
81 # endif
82
83 /* Convert MPI object handles to object pointers */
84 MPID_Comm_get_ptr( comm, comm_ptr );
85
86 /* Validate parameters and objects (post conversion) */
87 # ifdef HAVE_ERROR_CHECKING
88 {
89 MPID_BEGIN_ERROR_CHECKS;
90 {
91 /* Validate comm_ptr */
92 MPID_Comm_valid_ptr( comm_ptr, mpi_errno );
93 /* If comm_ptr is not valid, it will be reset to null */
94 if (mpi_errno) goto fn_fail;
95 }
96 MPID_END_ERROR_CHECKS;
97 }
98 # endif /* HAVE_ERROR_CHECKING */
99
100 /* ... body of routine ... */
101
102 /* Check that the communicator already has a Cartesian topology */
103 topo_ptr = MPIR_Topology_get( comm_ptr );
104
105 MPIU_ERR_CHKANDJUMP(!topo_ptr,mpi_errno,MPI_ERR_TOPOLOGY,"**notopology");
106 MPIU_ERR_CHKANDJUMP(topo_ptr->kind != MPI_CART,mpi_errno,MPI_ERR_TOPOLOGY,
107 "**notcarttopo");
108
109 ndims = topo_ptr->topo.cart.ndims;
110
111 all_false = 1; /* all entries in remain_dims are false */
112 for (i=0; i<ndims; i++) {
113 if (remain_dims[i]) {
114 /* any 1 is true, set flag to 0 and break */
115 all_false = 0;
116 break;
117 }
118 }
119
120 if (all_false) {
121 /* ndims=0, or all entries in remain_dims are false.
122 MPI 2.1 says return a 0D Cartesian topology. */
123 mpi_errno = MPIR_Cart_create_impl(comm_ptr, 0, NULL, NULL, 0, comm_new);
124 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
125 } else {
126 /* Determine the number of remaining dimensions */
127 ndims_in_subcomm = 0;
128 nnodes_in_subcomm = 1;
129 for (i=0; i<ndims; i++) {
130 if (remain_dims[i]) {
131 ndims_in_subcomm ++;
132 nnodes_in_subcomm *= topo_ptr->topo.cart.dims[i];
133 }
134 }
135
136 /* Split this communicator. Do this even if there are no remaining
137 dimensions so that the topology information is attached */
138 key = 0;
139 color = 0;
140 for (i=0; i<ndims; i++) {
141 if (remain_dims[i]) {
142 key = (key * topo_ptr->topo.cart.dims[i]) +
143 topo_ptr->topo.cart.position[i];
144 }
145 else {
146 color = (color * topo_ptr->topo.cart.dims[i]) +
147 topo_ptr->topo.cart.position[i];
148 }
149 }
150 mpi_errno = MPIR_Comm_split_impl( comm_ptr, color, key, &newcomm_ptr );
151 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
152
153 *comm_new = newcomm_ptr->handle;
154
155 /* Save the topology of this new communicator */
156 MPIU_CHKPMEM_MALLOC(toponew_ptr,MPIR_Topology*,sizeof(MPIR_Topology),
157 mpi_errno,"toponew_ptr");
158
159 toponew_ptr->kind = MPI_CART;
160 toponew_ptr->topo.cart.ndims = ndims_in_subcomm;
161 toponew_ptr->topo.cart.nnodes = nnodes_in_subcomm;
162 if (ndims_in_subcomm) {
163 MPIU_CHKPMEM_MALLOC(toponew_ptr->topo.cart.dims,int*,
164 ndims_in_subcomm*sizeof(int),mpi_errno,"cart.dims");
165 MPIU_CHKPMEM_MALLOC(toponew_ptr->topo.cart.periodic,int*,
166 ndims_in_subcomm*sizeof(int),mpi_errno,"cart.periodic");
167 MPIU_CHKPMEM_MALLOC(toponew_ptr->topo.cart.position,int*,
168 ndims_in_subcomm*sizeof(int),mpi_errno,"cart.position");
169 }
170 else {
171 toponew_ptr->topo.cart.dims = 0;
172 toponew_ptr->topo.cart.periodic = 0;
173 toponew_ptr->topo.cart.position = 0;
174 }
175
176 j = 0;
177 for (i=0; i<ndims; i++) {
178 if (remain_dims[i]) {
179 toponew_ptr->topo.cart.dims[j] = topo_ptr->topo.cart.dims[i];
180 toponew_ptr->topo.cart.periodic[j] = topo_ptr->topo.cart.periodic[i];
181 j++;
182 }
183 }
184
185 /* Compute the position of this process in the new communicator */
186 rank = newcomm_ptr->rank;
187 for (i=0; i<ndims_in_subcomm; i++) {
188 nnodes_in_subcomm /= toponew_ptr->topo.cart.dims[i];
189 toponew_ptr->topo.cart.position[i] = rank / nnodes_in_subcomm;
190 rank = rank % nnodes_in_subcomm;
191 }
192
193 mpi_errno = MPIR_Topology_put( newcomm_ptr, toponew_ptr );
194 if (mpi_errno) goto fn_fail;
195 }
196 /* ... end of body of routine ... */
197
198 fn_exit:
199 MPID_MPI_FUNC_EXIT(MPID_STATE_MPI_CART_SUB);
200 MPIU_THREAD_CS_EXIT(ALLFUNC,);
201 return mpi_errno;
202
203 fn_fail:
204 /* --BEGIN ERROR HANDLING-- */
205 MPIU_CHKPMEM_REAP();
206 # ifdef HAVE_ERROR_CHECKING
207 {
208 mpi_errno = MPIR_Err_create_code(
209 mpi_errno, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER, "**mpi_cart_sub",
210 "**mpi_cart_sub %C %p %p", comm, remain_dims, comm_new);
211 }
212 # endif
213 mpi_errno = MPIR_Err_return_comm( comm_ptr, FCNAME, mpi_errno );
214 goto fn_exit;
215 /* --END ERROR HANDLING-- */
216 }
217