LCOV - code coverage report
Current view: top level - core - GREX.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 112 148 75.7 %
Date: 2026-11-05 10:19:04 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-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 "GREX.h"
      23             : #include "PlumedMain.h"
      24             : #include "ActionSet.h"
      25             : #include "DomainDecomposition.h"
      26             : #include "tools/Tools.h"
      27             : #include "tools/Communicator.h"
      28             : #include <sstream>
      29             : 
      30             : namespace PLMD {
      31             : 
      32         802 : GREX::GREX(PlumedMain&p):
      33         802 :   initialized(false),
      34         802 :   plumedMain(p),
      35         802 :   partner(-1), // = unset
      36         802 :   localDeltaBias(0),
      37         802 :   foreignDeltaBias(0),
      38         802 :   localUNow(0),
      39         802 :   localUSwap(0),
      40         802 :   myreplica(-1) { // = unset
      41         802 :   p.setSuffix(".NA");
      42         802 : }
      43             : 
      44        1604 : GREX::~GREX() {
      45             : // empty destructor to delete unique_ptr
      46        1604 : }
      47             : 
      48             : #define CHECK_INIT(ini,word) plumed_assert(ini) << "cmd(\"" << word <<"\") should be only used after GREX initialization"
      49             : #define CHECK_NOTINIT(ini,word) plumed_assert(!(ini)) << "cmd(\"" << word <<"\") should be only used before GREX initialization"
      50             : #define CHECK_NOTNULL(val,word) plumed_assert(val) << "NULL pointer received in cmd(\"GREX " << word << "\")"
      51             : 
      52        2672 : void GREX::cmd(std::string_view key,const TypesafePtr & val) {
      53             : // Enumerate all possible commands:
      54             :   enum {
      55             : #include "GREXEnum.inc"
      56             :   };
      57             : 
      58             : // Static object (initialized once) containing the map of commands:
      59             :   const static Tools::FastStringUnorderedMap<int> word_map = {
      60             : #include "GREXMap.inc"
      61        2672 :   };
      62             : 
      63             :   gch::small_vector<std::string_view> words;
      64        2672 :   Tools::getWordsSimple(words,key);
      65        2672 :   unsigned nw=words.size();
      66        2672 :   if(nw==0) {
      67             :     // do nothing
      68             :   } else {
      69             :     int iword=-1;
      70             :     const auto it=word_map.find(words[0]);
      71        2672 :     if(it!=word_map.end()) {
      72        2672 :       iword=it->second;
      73             :     }
      74        2672 :     switch(iword) {
      75             :     case cmd_initialized:
      76           0 :       CHECK_NOTNULL(val,key);
      77           0 :       val.set(int(initialized));
      78             :       break;
      79         802 :     case cmd_setMPIIntracomm:
      80         802 :       CHECK_NOTINIT(initialized,key);
      81        1604 :       intracomm.Set_comm(val.get<const void*>());
      82         802 :       break;
      83         519 :     case cmd_setMPIIntercomm:
      84         519 :       CHECK_NOTINIT(initialized,key);
      85        1038 :       intercomm.Set_comm(val.get<const void*>());
      86        1038 :       plumedMain.multi_sim_comm.Set_comm(val.get<const void*>());
      87         519 :       break;
      88           0 :     case cmd_setMPIFIntracomm:
      89           0 :       CHECK_NOTINIT(initialized,key);
      90           0 :       intracomm.Set_fcomm(val.get<const void*>());
      91           0 :       break;
      92           0 :     case cmd_setMPIFIntercomm:
      93           0 :       CHECK_NOTINIT(initialized,key);
      94           0 :       intercomm.Set_fcomm(val.get<const void*>());
      95           0 :       plumedMain.multi_sim_comm.Set_fcomm(val.get<const void*>());
      96           0 :       break;
      97         802 :     case cmd_init:
      98         802 :       CHECK_NOTINIT(initialized,key);
      99         802 :       initialized=true;
     100             : // note that for PEs!=root this is automatically 0 (comm defaults to MPI_COMM_SELF)
     101         802 :       myreplica=intercomm.Get_rank();
     102         802 :       intracomm.Sum(myreplica);
     103         802 :       plumedMain.updateReplicaIdentity(intracomm);
     104             :       {
     105             :         std::string s;
     106         802 :         Tools::convert(myreplica,s);
     107        1604 :         plumedMain.setSuffix("."+s);
     108             :       }
     109         802 :       break;
     110          57 :     case cmd_prepare:
     111          57 :       CHECK_INIT(initialized,key);
     112          57 :       if(intracomm.Get_rank()==0) {
     113             :         return;
     114             :       }
     115          57 :       intracomm.Bcast(partner,0);
     116          57 :       calculate();
     117             :       break;
     118          69 :     case cmd_setPartner:
     119          69 :       CHECK_INIT(initialized,key);
     120          69 :       partner=val.get<int>();
     121          69 :       break;
     122         126 :     case cmd_savePositions:
     123         126 :       CHECK_INIT(initialized,key);
     124         126 :       savePositions();
     125             :       break;
     126          69 :     case cmd_calculate:
     127          69 :       CHECK_INIT(initialized,key);
     128          69 :       if(intracomm.Get_rank()!=0) {
     129             :         return;
     130             :       }
     131          69 :       intracomm.Bcast(partner,0);
     132          69 :       calculate();
     133             :       break;
     134           0 :     case cmd_getLocalDeltaBias:
     135           0 :       CHECK_INIT(initialized,key);
     136           0 :       CHECK_NOTNULL(val,key);
     137           0 :       plumedMain.plumedQuantityToMD("energy",localDeltaBias,val);
     138           0 :       break;
     139           0 :     case cmd_cacheLocalUNow:
     140           0 :       CHECK_INIT(initialized,key);
     141           0 :       CHECK_NOTNULL(val,key);
     142             :       {
     143           0 :         localUNow=plumedMain.MDQuantityToPLUMED("energy",val);
     144           0 :         intracomm.Sum(localUNow);
     145             :       }
     146             :       break;
     147           0 :     case cmd_cacheLocalUSwap:
     148           0 :       CHECK_INIT(initialized,key);
     149           0 :       CHECK_NOTNULL(val,key);
     150             :       {
     151           0 :         localUSwap=plumedMain.MDQuantityToPLUMED("energy",val);
     152           0 :         intracomm.Sum(localUSwap);
     153             :       }
     154             :       break;
     155           0 :     case cmd_getForeignDeltaBias:
     156           0 :       CHECK_INIT(initialized,key);
     157           0 :       CHECK_NOTNULL(val,key);
     158           0 :       plumedMain.plumedQuantityToMD("energy",foreignDeltaBias,val);
     159           0 :       break;
     160          57 :     case cmd_shareAllDeltaBias:
     161          57 :       CHECK_INIT(initialized,key);
     162          57 :       if(intracomm.Get_rank()!=0) {
     163             :         return;
     164             :       }
     165          57 :       allDeltaBias.assign(intercomm.Get_size(),0.0);
     166          57 :       allDeltaBias[intercomm.Get_rank()]=localDeltaBias;
     167          57 :       intercomm.Sum(allDeltaBias);
     168             :       break;
     169         171 :     case cmd_getDeltaBias:
     170         171 :       CHECK_INIT(initialized,key);
     171         171 :       CHECK_NOTNULL(val,key);
     172         171 :       plumed_assert(nw==2);
     173         171 :       plumed_massert(allDeltaBias.size()==static_cast<unsigned>(intercomm.Get_size()),
     174             :                      "to retrieve bias with cmd(\"GREX getDeltaBias\"), first share it with cmd(\"GREX shareAllDeltaBias\")");
     175             :       {
     176             :         unsigned rep;
     177         171 :         Tools::convert(std::string(words[1]),rep);
     178         171 :         plumed_massert(rep<allDeltaBias.size(),"replica index passed to cmd(\"GREX getDeltaBias\") is out of range");
     179         171 :         plumedMain.plumedQuantityToMD("energy",allDeltaBias[rep],val);
     180             :       }
     181         171 :       break;
     182           0 :     default:
     183           0 :       plumed_error() << "cannot interpret cmd(\" GREX" << key << "\"). check plumed developers manual to see the available commands.";
     184             :       break;
     185             :     }
     186             :   }
     187             : }
     188             : 
     189         126 : void GREX::savePositions() {
     190         126 :   plumedMain.prepareDependencies();
     191         126 :   plumedMain.resetActive(true);
     192         126 :   plumedMain.shareAll();
     193         126 :   plumedMain.waitData();
     194             :   // shareAll() also starts the exchange of the domain decomposition when no action needs atoms on this
     195             :   // step, but waitData() only completes the exchanges of the active inputs. Complete it here, or the
     196             :   // next exchange waits for messages that were never received (with asynchronous sharing).
     197         252 :   for(const auto & dd : plumedMain.getActionSet().select<DomainDecomposition*>()) {
     198         126 :     if(!dd->isActive() && dd->hasBeenSet()) {
     199           0 :       dd->wait();
     200             :     }
     201             :   }
     202         126 :   std::ostringstream o;
     203         126 :   plumedMain.writeBinary(o);
     204         126 :   buffer=o.str();
     205         126 : }
     206             : 
     207         126 : void GREX::calculate() {
     208         126 :   unsigned nn=buffer.size();
     209             :   // the buffers of the two replicas must have the same size, otherwise the partner
     210             :   // state would be read from a truncated or partially filled buffer
     211         126 :   unsigned partner_nn=nn;
     212         126 :   if(intracomm.Get_rank()==0) {
     213          69 :     Communicator::Request req=intercomm.Isend(nn,partner,1065);
     214          69 :     intercomm.Recv(partner_nn,partner,1065);
     215          69 :     req.wait();
     216             :   }
     217         126 :   intracomm.Bcast(partner_nn,0);
     218         126 :   if(partner_nn!=nn) {
     219           0 :     plumed_error()<<"GREX: the state of replica "<<partner<<" has a different size ("<<partner_nn<<" bytes instead of "<<nn
     220           0 :                   <<"): replicas must use PLUMED inputs that define the same values";
     221             :   }
     222         126 :   std::vector<char> rbuf(nn);
     223         126 :   localDeltaBias=-plumedMain.getBias();
     224         126 :   if(intracomm.Get_rank()==0) {
     225          69 :     Communicator::Request req=intercomm.Isend(buffer,partner,1066);
     226          69 :     intercomm.Recv(rbuf,partner,1066);
     227          69 :     req.wait();
     228             :   }
     229         126 :   intracomm.Bcast(rbuf,0);
     230         126 :   std::istringstream i(std::string(rbuf.data(),rbuf.size()));
     231         126 :   plumedMain.readBinary(i);
     232         126 :   plumedMain.setExchangeStep(true);
     233         126 :   plumedMain.prepareDependencies();
     234         126 :   plumedMain.justCalculate();
     235         126 :   plumedMain.setExchangeStep(false);
     236         126 :   localDeltaBias+=plumedMain.getBias();
     237         126 :   localDeltaBias+=localUSwap-localUNow;
     238         126 :   if(intracomm.Get_rank()==0) {
     239          69 :     Communicator::Request req=intercomm.Isend(localDeltaBias,partner,1067);
     240          69 :     intercomm.Recv(foreignDeltaBias,partner,1067);
     241          69 :     req.wait();
     242             :   }
     243         126 :   intracomm.Bcast(foreignDeltaBias,0);
     244         126 : }
     245             : 
     246             : }

Generated by: LCOV version 1.16