2020#include < mpi.h>
2121namespace coreneuron {
2222
23+
2324MPI_Comm nrnmpi_world_comm;
2425MPI_Comm nrnmpi_comm;
2526int nrnmpi_numprocs_;
@@ -34,6 +35,8 @@ static void nrn_fatal_error(const char* msg) {
3435 nrnmpi_abort_impl (-1 );
3536}
3637
38+ void corenrn_subworld ();
39+
3740nrnmpi_init_ret_t nrnmpi_init_impl (int * pargc, char *** pargv, bool is_quiet) {
3841 // Execute at most once per launch. Avoid memory leak.
3942 static bool executed = false ;
@@ -54,10 +57,13 @@ nrnmpi_init_ret_t nrnmpi_init_impl(int* pargc, char*** pargv, bool is_quiet) {
5457 nrn_assert (MPI_Init (pargc, pargv) == MPI_SUCCESS );
5558#endif
5659 }
60+
5761 nrn_assert (MPI_Comm_dup (MPI_COMM_WORLD , &nrnmpi_world_comm) == MPI_SUCCESS );
5862 nrn_assert (MPI_Comm_dup (nrnmpi_world_comm, &nrnmpi_comm) == MPI_SUCCESS );
59- nrn_assert (MPI_Comm_rank (nrnmpi_world_comm, &nrnmpi_myid_) == MPI_SUCCESS );
60- nrn_assert (MPI_Comm_size (nrnmpi_world_comm, &nrnmpi_numprocs_) == MPI_SUCCESS );
63+ corenrn_subworld (); // split nrnmpi_comm if ParallelContext.subworlds has been used
64+ nrn_assert (MPI_Comm_rank (nrnmpi_comm, &nrnmpi_myid_) == MPI_SUCCESS );
65+ nrn_assert (MPI_Comm_size (nrnmpi_comm, &nrnmpi_numprocs_) == MPI_SUCCESS );
66+
6167 nrnmpi_spike_initialize ();
6268
6369 if (nrnmpi_myid_ == 0 && !is_quiet) {
@@ -82,6 +88,53 @@ void nrnmpi_finalize_impl(void) {
8288 }
8389}
8490
91+ extern " C" {
92+ extern void (*nrn2core_subworld_info_)(int &, int &, int &, int &, int &);
93+ }
94+
95+ void corenrn_subworld () {
96+ // If ParallelContext.subworlds has been invoked, split the world
97+ // communicator according to the subworld partitioning.
98+ static int change_cnt{0 };
99+ int nrn_subworld_change_cnt, nrn_subworld_index, nrn_subworld_rank, nrn_mpi_numprocs_subworld,
100+ nrn_mpi_numprocs_world;
101+ if (!nrn2core_subworld_info_) {
102+ return ;
103+ }
104+ (*nrn2core_subworld_info_)(nrn_subworld_change_cnt,
105+ nrn_subworld_index,
106+ nrn_subworld_rank,
107+ nrn_mpi_numprocs_subworld,
108+ nrn_mpi_numprocs_world);
109+ if (nrn_subworld_change_cnt == change_cnt) {
110+ return ;
111+ }
112+ change_cnt = nrn_subworld_change_cnt;
113+
114+ // clean up / free old nrn_mpi_comm
115+ nrn_assert (MPI_Comm_free (&nrnmpi_comm) == MPI_SUCCESS );
116+
117+ // ensure world size is the same as NEURON
118+ int world_size{-1 };
119+ nrn_assert (MPI_Comm_size (nrnmpi_world_comm, &world_size) == MPI_SUCCESS );
120+ nrn_assert (world_size == nrn_mpi_numprocs_world);
121+
122+ // create a new nrnmpi_comm based on subworld partitioning
123+ nrn_assert (
124+ MPI_Comm_split (nrnmpi_world_comm, nrn_subworld_index, nrn_subworld_rank, &nrnmpi_comm) ==
125+ MPI_SUCCESS );
126+
127+ // assert that rank order and size is consistent between NEURON and CoreNEURON
128+ int subworld_rank{-1 };
129+ nrn_assert (MPI_Comm_rank (nrnmpi_comm, &subworld_rank) == MPI_SUCCESS );
130+ nrn_assert (nrn_subworld_rank == subworld_rank);
131+
132+ int subworld_size{-1 };
133+ nrn_assert (MPI_Comm_size (nrnmpi_comm, &subworld_size) == MPI_SUCCESS );
134+ nrn_assert (subworld_size == nrn_mpi_numprocs_subworld);
135+ }
136+
137+
85138// check if appropriate threading level supported (i.e. MPI_THREAD_FUNNELED)
86139void nrnmpi_check_threading_support_impl () {
87140 int th = 0 ;
0 commit comments