LCOV - code coverage report
Current view: top level - tools - Communicator.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 170 195 87.2 %
Date: 2026-11-05 10:19:04 Functions: 36 41 87.8 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed 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
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "Communicator.h"
      23             : #include "Exception.h"
      24             : #include "AtomNumber.h"
      25             : #include <cstdlib>
      26             : #include <cstring>
      27             : #include <cstdio>
      28             : 
      29             : namespace PLMD {
      30             : 
      31         228 : bool Communicator::plumedHasMPI() {
      32             : #ifdef __PLUMED_HAS_MPI
      33         228 :   return true;
      34             : #else
      35             :   return false;
      36             : #endif
      37             : }
      38             : 
      39     1633593 : Communicator::Communicator()
      40             : #ifdef __PLUMED_HAS_MPI
      41     1633593 :   : communicator(MPI_COMM_SELF)
      42             : #endif
      43             : {
      44     1633593 : }
      45             : 
      46           0 : Communicator::Communicator(const Communicator&pc)
      47             : #ifdef __PLUMED_HAS_MPI
      48             : // communicator must be initialized before calling Set_comm, which frees it if needed
      49           0 :   : communicator(MPI_COMM_SELF)
      50             : #endif
      51             : {
      52           0 :   Set_comm(pc.communicator);
      53           0 :   standIn=pc.standIn;
      54           0 : }
      55             : 
      56             : Communicator::Status Communicator::StatusIgnore;
      57             : 
      58           0 : Communicator& Communicator::operator=(const Communicator&pc) {
      59           0 :   if (this != &pc) {
      60           0 :     Set_comm(pc.communicator);
      61           0 :     standIn=pc.standIn;
      62             :   }
      63           0 :   return *this;
      64             : }
      65             : 
      66        6174 : void Communicator::setStandIn(bool s) {
      67        6174 :   standIn=s;
      68        6174 : }
      69             : 
      70           4 : bool Communicator::isStandIn()const {
      71           4 :   return standIn;
      72             : }
      73             : 
      74    16953699 : void Communicator::checkNotStandIn()const {
      75             :   constexpr const char* msg="this communicator is a stand-in on this process: it was given to other processes but not to this one. "
      76             :                             "For multi_sim_comm, this means that only the first process of each replica can use it. "
      77             :                             "Use getNumberOfReplicas() and getReplicaIndex(), or use multi_sim_comm on the first process of comm and broadcast the result over comm.";
      78             : #ifndef NDEBUG
      79             :   if(standIn) {
      80             :     // Typically only some processes get here. The log is written collectively,
      81             :     // so the exception message might never reach it: print it right away.
      82             :     std::fprintf(stderr,"\nPLUMED: ERROR (debug build): %s\n",msg);
      83             :     std::fflush(stderr);
      84             :   }
      85             : #endif
      86             :   plumed_dbg_massert(!standIn,msg);
      87    16953699 : }
      88             : 
      89     8715065 : int Communicator::Get_rank()const {
      90     8715065 :   checkNotStandIn();
      91     8715065 :   int r=0;
      92             : #ifdef __PLUMED_HAS_MPI
      93     8715065 :   if(initialized()) {
      94     3097236 :     MPI_Comm_rank(communicator,&r);
      95             :   }
      96             : #endif
      97     8715065 :   return r;
      98             : }
      99             : 
     100     3206987 : int Communicator::Get_size()const {
     101     3206987 :   checkNotStandIn();
     102     3206987 :   int s=1;
     103             : #ifdef __PLUMED_HAS_MPI
     104     3206987 :   if(initialized()) {
     105     1192205 :     MPI_Comm_size(communicator,&s);
     106             :   }
     107             : #endif
     108     3206987 :   return s;
     109             : }
     110             : 
     111        5477 : void Communicator::Set_comm(MPI_Comm c) {
     112        5477 :   standIn=false;
     113             : #ifdef __PLUMED_HAS_MPI
     114        5477 :   if(initialized()) {
     115        4628 :     if(communicator!=MPI_COMM_SELF && communicator!=MPI_COMM_WORLD && communicator!=MPI_COMM_NULL) {
     116           0 :       MPI_Comm_free(&communicator);
     117             :     }
     118        4628 :     if(c!=MPI_COMM_SELF) {
     119        4560 :       MPI_Comm_dup(c,&communicator);
     120             :     } else {
     121             :       // MPI_Comm_free sets the freed communicator to MPI_COMM_NULL
     122          68 :       communicator=MPI_COMM_SELF;
     123             :     }
     124             :   }
     125             : #else
     126             :   (void) c;
     127             : #endif
     128        5477 : }
     129             : 
     130     3261728 : Communicator::~Communicator() {
     131             : #ifdef __PLUMED_HAS_MPI
     132     1633593 :   if(initialized() && communicator!=MPI_COMM_SELF && communicator!=MPI_COMM_WORLD && communicator!=MPI_COMM_NULL) {
     133        5226 :     MPI_Comm_free(&communicator);
     134             :   }
     135             : #endif
     136     3261728 : }
     137             : 
     138        3389 : void Communicator::Set_comm(const TypesafePtr & val) {
     139             : #ifdef __PLUMED_HAS_MPI
     140        3389 :   plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
     141        3389 :   if(val) {
     142        3389 :     Set_comm(*(const MPI_Comm*)val.get<const void*>());
     143             :   }
     144             : #else
     145             :   (void) val;
     146             :   plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
     147             : #endif
     148        3389 : }
     149             : 
     150           0 : void Communicator::Set_fcomm(const TypesafePtr & val) {
     151             : #ifdef __PLUMED_HAS_MPI
     152           0 :   plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
     153           0 :   if(val) {
     154           0 :     MPI_Comm comm=MPI_Comm_f2c(*(const MPI_Fint*)val.get<const void*>());
     155           0 :     Set_comm(comm);
     156             :   }
     157             : #else
     158             :   (void) val;
     159             :   plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
     160             : #endif
     161           0 : }
     162             : 
     163           0 : void Communicator::Abort(int errorcode) {
     164             : #ifdef __PLUMED_HAS_MPI
     165           0 :   if(initialized()) {
     166           0 :     MPI_Abort(communicator,errorcode);
     167             :   }
     168             : #endif
     169           0 :   std::fprintf(stderr,"aborting with error code %d\n",errorcode);
     170           0 :   std::abort();
     171             : }
     172             : 
     173      403829 : void Communicator::Bcast(Data data,int root) {
     174      403829 :   checkNotStandIn();
     175             : #if defined(__PLUMED_HAS_MPI)
     176      403829 :   if(initialized()) {
     177      111845 :     MPI_Bcast(data.pointer,data.size,data.type,root,communicator);
     178             :   }
     179             : #else
     180             :   (void) data;
     181             :   (void) root;
     182             : #endif
     183      403829 : }
     184             : 
     185          12 : void Communicator::Scatter(ConstData sendbuf,int sendcount,Data recvbuf,int recvcount,int root) {
     186          12 :   checkNotStandIn();
     187          12 :   void*s=const_cast<void*>((const void*)sendbuf.pointer);
     188             : #if defined(__PLUMED_HAS_MPI)
     189          12 :   if(initialized()) {
     190          11 :     MPI_Scatter(s,sendcount,sendbuf.type,recvbuf.pointer,recvcount,recvbuf.type,root,communicator);
     191             :   } else {
     192             :     // Non-MPI case: just copy from sendbuf to recvbuf
     193           1 :     plumed_assert(sendbuf.nbytes==recvbuf.nbytes);
     194           1 :     plumed_assert(sendcount==recvcount);
     195           1 :     if(s) {
     196           1 :       std::memcpy(recvbuf.pointer,s,size_t(recvcount)*recvbuf.nbytes);
     197             :     }
     198             :   }
     199             : #else
     200             :   plumed_assert(sendbuf.nbytes==recvbuf.nbytes);
     201             :   plumed_assert(sendcount==recvcount);
     202             :   if(s) {
     203             :     std::memcpy(recvbuf.pointer,s,size_t(recvcount)*recvbuf.nbytes);
     204             :   }
     205             :   (void) root;
     206             : #endif
     207          12 : }
     208             : 
     209          12 : void Communicator::Gather(ConstData sendbuf,int sendcount,Data recvbuf,int recvcount,int root) {
     210          12 :   checkNotStandIn();
     211          12 :   void*s=const_cast<void*>((const void*)sendbuf.pointer);
     212             : #if defined(__PLUMED_HAS_MPI)
     213          12 :   if(initialized()) {
     214          11 :     MPI_Gather(s,sendcount,sendbuf.type,recvbuf.pointer,recvcount,recvbuf.type,root,communicator);
     215             :   } else {
     216             :     // Non-MPI case: just copy from sendbuf to recvbuf
     217           1 :     plumed_assert(sendbuf.nbytes==recvbuf.nbytes);
     218           1 :     plumed_assert(sendcount==recvcount);
     219           1 :     if(s) {
     220           1 :       std::memcpy(recvbuf.pointer,s,size_t(recvcount)*recvbuf.nbytes);
     221             :     }
     222             :   }
     223             : #else
     224             :   plumed_assert(sendbuf.nbytes==recvbuf.nbytes);
     225             :   plumed_assert(sendcount==recvcount);
     226             :   if(s) {
     227             :     std::memcpy(recvbuf.pointer,s,size_t(recvcount)*recvbuf.nbytes);
     228             :   }
     229             :   (void) root;
     230             : #endif
     231          12 : }
     232             : 
     233     4566192 : void Communicator::Sum(Data data) {
     234     4566192 :   checkNotStandIn();
     235             : #if defined(__PLUMED_HAS_MPI)
     236     4566192 :   if(initialized()) {
     237     1939104 :     MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_SUM,communicator);
     238             :   }
     239             : #else
     240             :   (void) data;
     241             : #endif
     242     4566192 : }
     243             : 
     244           3 : void Communicator::Prod(Data data) {
     245           3 :   checkNotStandIn();
     246             : #if defined(__PLUMED_HAS_MPI)
     247           3 :   if(initialized()) {
     248           3 :     MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_PROD,communicator);
     249             :   }
     250             : #else
     251             :   (void) data;
     252             : #endif
     253           3 : }
     254             : 
     255        6393 : void Communicator::Max(Data data) {
     256        6393 :   checkNotStandIn();
     257             : #if defined(__PLUMED_HAS_MPI)
     258        6393 :   if(initialized()) {
     259        3937 :     MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_MAX,communicator);
     260             :   }
     261             : #else
     262             :   (void) data;
     263             : #endif
     264        6393 : }
     265             : 
     266         238 : void Communicator::Min(Data data) {
     267         238 :   checkNotStandIn();
     268             : #if defined(__PLUMED_HAS_MPI)
     269         238 :   if(initialized()) {
     270         167 :     MPI_Allreduce(MPI_IN_PLACE,data.pointer,data.size,data.type,MPI_MIN,communicator);
     271             :   }
     272             : #else
     273             :   (void) data;
     274             : #endif
     275         238 : }
     276             : 
     277       16503 : Communicator::Request Communicator::Isend(ConstData data,int source,int tag) {
     278       16503 :   checkNotStandIn();
     279             :   Request req;
     280             : #ifdef __PLUMED_HAS_MPI
     281       16503 :   plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
     282       16503 :   void*s=const_cast<void*>((const void*)data.pointer);
     283       16503 :   MPI_Isend(s,data.size,data.type,source,tag,communicator,&req.r);
     284             : #else
     285             :   (void) data;
     286             :   (void) source;
     287             :   (void) tag;
     288             :   plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
     289             : #endif
     290       16503 :   return req;
     291             : }
     292             : 
     293        4385 : void Communicator::Allgatherv(ConstData in,Data out,const int*recvcounts,const int*displs) {
     294        4385 :   checkNotStandIn();
     295        4385 :   void*s=const_cast<void*>((const void*)in.pointer);
     296        4385 :   void*r=const_cast<void*>((const void*)out.pointer);
     297             :   int*rc=const_cast<int*>(recvcounts);
     298             :   int*di=const_cast<int*>(displs);
     299             : #if defined(__PLUMED_HAS_MPI)
     300        4385 :   if(initialized()) {
     301        4384 :     if(s==NULL) {
     302             :       s=MPI_IN_PLACE;
     303             :     }
     304        4384 :     MPI_Allgatherv(s,in.size,in.type,r,rc,di,out.type,communicator);
     305             :   } else {
     306           1 :     plumed_assert(in.nbytes==out.nbytes);
     307           1 :     plumed_assert(in.size==out.size);
     308           1 :     plumed_assert(rc);
     309           1 :     plumed_assert(rc[0]==in.size);
     310           1 :     plumed_assert(di);
     311           1 :     if(s) {
     312           1 :       std::memcpy(static_cast<char*>(r)+displs[0]*in.nbytes,s,size_t(in.size)*in.nbytes);
     313             :     }
     314             :   }
     315             : #else
     316             :   plumed_assert(in.nbytes==out.nbytes);
     317             :   plumed_assert(in.size==out.size);
     318             :   plumed_assert(rc);
     319             :   plumed_assert(rc[0]==in.size);
     320             :   plumed_assert(di);
     321             :   if(s) {
     322             :     std::memcpy(static_cast<char*>(r)+displs[0]*in.nbytes,s,size_t(in.size)*in.nbytes);
     323             :   }
     324             : #endif
     325        4385 : }
     326             : 
     327        8353 : void Communicator::Allgather(ConstData in,Data out) {
     328        8353 :   checkNotStandIn();
     329        8353 :   void*s=const_cast<void*>((const void*)in.pointer);
     330        8353 :   void*r=const_cast<void*>((const void*)out.pointer);
     331             : #if defined(__PLUMED_HAS_MPI)
     332        8353 :   if(initialized()) {
     333        8352 :     if(s==NULL) {
     334             :       s=MPI_IN_PLACE;
     335             :     }
     336        8352 :     MPI_Allgather(s,in.size,in.type,r,out.size/Get_size(),out.type,communicator);
     337             :   } else {
     338           1 :     plumed_assert(in.nbytes==out.nbytes);
     339           1 :     plumed_assert(in.size==out.size);
     340           1 :     if(s) {
     341           1 :       std::memcpy(r,s,size_t(in.size)*in.nbytes);
     342             :     }
     343             :   }
     344             : #else
     345             :   plumed_assert(in.nbytes==out.nbytes);
     346             :   plumed_assert(in.size==out.size);
     347             :   if(s) {
     348             :     std::memcpy(r,s,size_t(in.size)*in.nbytes);
     349             :   }
     350             : #endif
     351        8353 : }
     352             : 
     353       16503 : void Communicator::Recv(Data data,int source,int tag,Status&status) {
     354       16503 :   checkNotStandIn();
     355             : #ifdef __PLUMED_HAS_MPI
     356       16503 :   plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
     357       16503 :   if(&status==&StatusIgnore) {
     358        8360 :     MPI_Recv(data.pointer,data.size,data.type,source,tag,communicator,MPI_STATUS_IGNORE);
     359             :   } else {
     360        8143 :     MPI_Recv(data.pointer,data.size,data.type,source,tag,communicator,&status.s);
     361             :   }
     362             : #else
     363             :   (void) data;
     364             :   (void) source;
     365             :   (void) tag;
     366             :   (void) status;
     367             :   plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
     368             : #endif
     369       16503 : }
     370             : 
     371        8558 : void Communicator::Barrier()const {
     372        8558 :   checkNotStandIn();
     373             : #ifdef __PLUMED_HAS_MPI
     374        8558 :   if(initialized()) {
     375        3886 :     MPI_Barrier(communicator);
     376             :   }
     377             : #endif
     378        8558 : }
     379             : 
     380        3181 : MPI_Comm & Communicator::Get_comm() {
     381        3181 :   return communicator;
     382             : }
     383             : 
     384    18631351 : bool Communicator::initialized() {
     385             : #if defined(__PLUMED_HAS_MPI)
     386    18631351 :   int flag=0;
     387    18631351 :   MPI_Initialized(&flag);
     388    18631351 :   if(flag) {
     389             :     return true;
     390             :   } else {
     391    12190458 :     return false;
     392             :   }
     393             : #endif
     394             :   return false;
     395             : }
     396             : 
     397       15935 : void Communicator::Request::wait(Status&s) {
     398             : #ifdef __PLUMED_HAS_MPI
     399       15935 :   plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
     400       15935 :   if(&s==&StatusIgnore) {
     401       15934 :     MPI_Wait(&r,MPI_STATUS_IGNORE);
     402             :   } else {
     403           1 :     MPI_Wait(&r,&s.s);
     404             :   }
     405             : #else
     406             :   (void) s;
     407             :   plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
     408             : #endif
     409       15935 : }
     410             : 
     411             : #ifdef __PLUMED_HAS_MPI
     412           4 : template<> MPI_Datatype Communicator::getMPIType<float>() {
     413           4 :   return MPI_FLOAT;
     414             : }
     415     4907392 : template<> MPI_Datatype Communicator::getMPIType<double>() {
     416     4907392 :   return MPI_DOUBLE;
     417             : }
     418      118135 : template<> MPI_Datatype Communicator::getMPIType<int>()   {
     419      118135 :   return MPI_INT;
     420             : }
     421         469 : template<> MPI_Datatype Communicator::getMPIType<char>()   {
     422         469 :   return MPI_CHAR;
     423             : }
     424       17274 : template<> MPI_Datatype Communicator::getMPIType<unsigned>()   {
     425       17274 :   return MPI_UNSIGNED;
     426             : }
     427          24 : template<> MPI_Datatype Communicator::getMPIType<AtomNumber>()   {
     428          24 :   return MPI_UNSIGNED;
     429             : }
     430          24 : template<> MPI_Datatype Communicator::getMPIType<long unsigned>()   {
     431          24 :   return MPI_UNSIGNED_LONG;
     432             : }
     433           6 : template<> MPI_Datatype Communicator::getMPIType<long long unsigned>() {
     434           6 :   return MPI_UNSIGNED_LONG_LONG;
     435             : }
     436           0 : template<> MPI_Datatype Communicator::getMPIType<long double>()   {
     437           0 :   return MPI_LONG_DOUBLE;
     438             : }
     439             : #else
     440             : template<> MPI_Datatype Communicator::getMPIType<float>() {
     441             :   return MPI_Datatype();
     442             : }
     443             : template<> MPI_Datatype Communicator::getMPIType<double>() {
     444             :   return MPI_Datatype();
     445             : }
     446             : template<> MPI_Datatype Communicator::getMPIType<int>() {
     447             :   return MPI_Datatype();
     448             : }
     449             : template<> MPI_Datatype Communicator::getMPIType<char>() {
     450             :   return MPI_Datatype();
     451             : }
     452             : template<> MPI_Datatype Communicator::getMPIType<unsigned>() {
     453             :   return MPI_Datatype();
     454             : }
     455             : template<> MPI_Datatype Communicator::getMPIType<AtomNumber>()   {
     456             :   return MPI_Datatype();
     457             : }
     458             : template<> MPI_Datatype Communicator::getMPIType<long unsigned>() {
     459             :   return MPI_Datatype();
     460             : }
     461             : template<> MPI_Datatype Communicator::getMPIType<long long unsigned>() {
     462             :   return MPI_Datatype();
     463             : }
     464             : template<> MPI_Datatype Communicator::getMPIType<long double>() {
     465             :   return MPI_Datatype();
     466             : }
     467             : #endif
     468             : 
     469         666 : void Communicator::Split(int color,int key,Communicator&pc)const {
     470         666 :   checkNotStandIn();
     471             : #ifdef __PLUMED_HAS_MPI
     472             :   // free the communicator previously held by pc (it was obtained with MPI_Comm_dup or MPI_Comm_split)
     473         666 :   if(pc.communicator!=MPI_COMM_SELF && pc.communicator!=MPI_COMM_WORLD && pc.communicator!=MPI_COMM_NULL) {
     474           0 :     MPI_Comm_free(&pc.communicator);
     475             :   }
     476         666 :   pc.standIn=false;
     477         666 :   MPI_Comm_split(communicator,color,key,&pc.communicator);
     478             : #else
     479             :   (void) color;
     480             :   (void) key;
     481             :   (void) pc;
     482             :   plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
     483             : #endif
     484         666 : }
     485             : 
     486        8143 : int Communicator::Status::Get_count(MPI_Datatype type)const {
     487             :   int i;
     488             : #ifdef __PLUMED_HAS_MPI
     489        8143 :   plumed_massert(initialized(),"you are trying to use an MPI function, but MPI is not initialized");
     490        8143 :   MPI_Get_count(const_cast<MPI_Status*>(&s),type,&i);
     491             : #else
     492             :   i=0;
     493             :   plumed_merror("you are trying to use an MPI function, but PLUMED has been compiled without MPI support");
     494             : #endif
     495        8143 :   return i;
     496             : }
     497             : 
     498             : }
     499             : 

Generated by: LCOV version 1.16