6c912add49a9217f272d2d2831d7ed85c883b5d6
[alexxy/gromacs.git] / src / gromacs / utility / physicalnodecommunicator.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2018, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Defines functionality for communicators across physical nodes.
38  *
39  * \ingroup module_utility
40  */
41 #include "gmxpre.h"
42
43 #include "physicalnodecommunicator.h"
44
45 #include "config.h"
46
47 #include "gromacs/utility/basedefinitions.h"
48 #include "gromacs/utility/gmxmpi.h"
49
50 namespace gmx
51 {
52
53 void
54 MPI_Comm_free_wrapper(MPI_Comm *comm)
55 {
56 #if GMX_MPI
57     // With thread-MPI *comm is shared between ranks which causes issues with
58     // freeing. But all thread-mpi data is anyhow freed in tMPI_Finalize()
59     // and in practice *comm is always MPI_COMM_WORLD with thread-MPI.
60     // Only the thread-affinity test code uses *comm != MPI_COMM_WORLD.
61     if (!GMX_THREAD_MPI)
62     {
63         MPI_Comm_free(comm);
64     }
65 #else
66     GMX_UNUSED_VALUE(comm);
67 #endif
68 }
69
70 PhysicalNodeCommunicator::PhysicalNodeCommunicator(MPI_Comm world, int physicalNodeId)
71 {
72 #if GMX_MPI
73     int isInitialized;
74     MPI_Initialized(&isInitialized);
75     if (isInitialized)
76     {
77         int sizeOfWorld;
78         MPI_Comm_size(world, &sizeOfWorld);
79         if (sizeOfWorld > 1)
80         {
81             int rankWithinWorld;
82             MPI_Comm_rank(world, &rankWithinWorld);
83             MPI_Comm_split(world, physicalNodeId, rankWithinWorld, &comm_);
84             auto ptr = MPI_Comm_ptr(&comm_);
85             commGuard_.swap(ptr);
86             MPI_Comm_size(comm_, &size_);
87             MPI_Comm_rank(comm_, &rank_);
88         }
89         else
90         {
91             // Handle this trivial case separately, because thread-MPI
92             // doesn't have a valid communicator when there is only
93             // one rank.
94             comm_ = world;
95             size_ = 1;
96             rank_ = 0;
97         }
98     }
99     else
100     {
101         comm_ = MPI_COMM_NULL;
102         size_ = 1;
103         rank_ = 0;
104     }
105 #else
106     // Trivial case when there is no MPI support or not initialized
107     GMX_UNUSED_VALUE(world);
108     GMX_UNUSED_VALUE(physicalNodeId);
109     comm_ = nullptr;
110     size_ = 1;
111     rank_ = 0;
112 #endif
113 }
114
115 void PhysicalNodeCommunicator::barrier() const
116 {
117 #if GMX_MPI
118     if (size_ > 1)
119     {
120         MPI_Barrier(comm_);
121     }
122 #else
123     // Nothing to do
124 #endif
125 }
126
127 } // namespace