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