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 350 : GREX::GREX(PlumedMain&p):
33 350 : initialized(false),
34 350 : plumedMain(p),
35 350 : partner(-1), // = unset
36 350 : localDeltaBias(0),
37 350 : foreignDeltaBias(0),
38 350 : localUNow(0),
39 350 : localUSwap(0),
40 350 : myreplica(-1) { // = unset
41 350 : p.setSuffix(".NA");
42 350 : }
43 :
44 700 : GREX::~GREX() {
45 : // empty destructor to delete unique_ptr
46 700 : }
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 1445 : 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 1445 : };
62 :
63 : gch::small_vector<std::string_view> words;
64 1445 : Tools::getWordsSimple(words,key);
65 1445 : unsigned nw=words.size();
66 1445 : if(nw==0) {
67 : // do nothing
68 : } else {
69 : int iword=-1;
70 : const auto it=word_map.find(words[0]);
71 1445 : if(it!=word_map.end()) {
72 1445 : iword=it->second;
73 : }
74 1445 : switch(iword) {
75 : case cmd_initialized:
76 0 : CHECK_NOTNULL(val,key);
77 0 : val.set(int(initialized));
78 : break;
79 350 : case cmd_setMPIIntracomm:
80 350 : CHECK_NOTINIT(initialized,key);
81 700 : intracomm.Set_comm(val.get<const void*>());
82 350 : break;
83 232 : case cmd_setMPIIntercomm:
84 232 : CHECK_NOTINIT(initialized,key);
85 464 : intercomm.Set_comm(val.get<const void*>());
86 464 : plumedMain.multi_sim_comm.Set_comm(val.get<const void*>());
87 232 : 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 350 : case cmd_init:
98 350 : CHECK_NOTINIT(initialized,key);
99 350 : initialized=true;
100 : // note that for PEs!=root this is automatically 0 (comm defaults to MPI_COMM_SELF)
101 350 : myreplica=intercomm.Get_rank();
102 350 : intracomm.Sum(myreplica);
103 : {
104 : std::string s;
105 350 : Tools::convert(myreplica,s);
106 700 : plumedMain.setSuffix("."+s);
107 : }
108 350 : break;
109 57 : case cmd_prepare:
110 57 : CHECK_INIT(initialized,key);
111 57 : if(intracomm.Get_rank()==0) {
112 : return;
113 : }
114 57 : intracomm.Bcast(partner,0);
115 57 : calculate();
116 : break;
117 57 : case cmd_setPartner:
118 57 : CHECK_INIT(initialized,key);
119 57 : partner=val.get<int>();
120 57 : break;
121 114 : case cmd_savePositions:
122 114 : CHECK_INIT(initialized,key);
123 114 : savePositions();
124 : break;
125 57 : case cmd_calculate:
126 57 : CHECK_INIT(initialized,key);
127 57 : if(intracomm.Get_rank()!=0) {
128 : return;
129 : }
130 57 : intracomm.Bcast(partner,0);
131 57 : calculate();
132 : break;
133 0 : case cmd_getLocalDeltaBias:
134 0 : CHECK_INIT(initialized,key);
135 0 : CHECK_NOTNULL(val,key);
136 0 : plumedMain.plumedQuantityToMD("energy",localDeltaBias,val);
137 0 : break;
138 0 : case cmd_cacheLocalUNow:
139 0 : CHECK_INIT(initialized,key);
140 0 : CHECK_NOTNULL(val,key);
141 : {
142 0 : localUNow=plumedMain.MDQuantityToPLUMED("energy",val);
143 0 : intracomm.Sum(localUNow);
144 : }
145 : break;
146 0 : case cmd_cacheLocalUSwap:
147 0 : CHECK_INIT(initialized,key);
148 0 : CHECK_NOTNULL(val,key);
149 : {
150 0 : localUSwap=plumedMain.MDQuantityToPLUMED("energy",val);
151 0 : intracomm.Sum(localUSwap);
152 : }
153 : break;
154 0 : case cmd_getForeignDeltaBias:
155 0 : CHECK_INIT(initialized,key);
156 0 : CHECK_NOTNULL(val,key);
157 0 : plumedMain.plumedQuantityToMD("energy",foreignDeltaBias,val);
158 0 : break;
159 57 : case cmd_shareAllDeltaBias:
160 57 : CHECK_INIT(initialized,key);
161 57 : if(intracomm.Get_rank()!=0) {
162 : return;
163 : }
164 57 : allDeltaBias.assign(intercomm.Get_size(),0.0);
165 57 : allDeltaBias[intercomm.Get_rank()]=localDeltaBias;
166 57 : intercomm.Sum(allDeltaBias);
167 : break;
168 171 : case cmd_getDeltaBias:
169 171 : CHECK_INIT(initialized,key);
170 171 : CHECK_NOTNULL(val,key);
171 171 : plumed_assert(nw==2);
172 171 : plumed_massert(allDeltaBias.size()==static_cast<unsigned>(intercomm.Get_size()),
173 : "to retrieve bias with cmd(\"GREX getDeltaBias\"), first share it with cmd(\"GREX shareAllDeltaBias\")");
174 : {
175 : unsigned rep;
176 171 : Tools::convert(std::string(words[1]),rep);
177 171 : plumed_massert(rep<allDeltaBias.size(),"replica index passed to cmd(\"GREX getDeltaBias\") is out of range");
178 171 : plumedMain.plumedQuantityToMD("energy",allDeltaBias[rep],val);
179 : }
180 171 : break;
181 0 : default:
182 0 : plumed_error() << "cannot interpret cmd(\" GREX" << key << "\"). check plumed developers manual to see the available commands.";
183 : break;
184 : }
185 : }
186 : }
187 :
188 114 : void GREX::savePositions() {
189 114 : plumedMain.prepareDependencies();
190 114 : plumedMain.resetActive(true);
191 114 : plumedMain.shareAll();
192 114 : plumedMain.waitData();
193 : // shareAll() also starts the exchange of the domain decomposition when no action needs atoms on this
194 : // step, but waitData() only completes the exchanges of the active inputs. Complete it here, or the
195 : // next exchange waits for messages that were never received (with asynchronous sharing).
196 228 : for(const auto & dd : plumedMain.getActionSet().select<DomainDecomposition*>()) {
197 114 : if(!dd->isActive() && dd->hasBeenSet()) {
198 0 : dd->wait();
199 : }
200 : }
201 114 : std::ostringstream o;
202 114 : plumedMain.writeBinary(o);
203 114 : buffer=o.str();
204 114 : }
205 :
206 114 : void GREX::calculate() {
207 : unsigned nn=buffer.size();
208 114 : std::vector<char> rbuf(nn);
209 114 : localDeltaBias=-plumedMain.getBias();
210 114 : if(intracomm.Get_rank()==0) {
211 57 : Communicator::Request req=intercomm.Isend(buffer,partner,1066);
212 57 : intercomm.Recv(rbuf,partner,1066);
213 57 : req.wait();
214 : }
215 114 : intracomm.Bcast(rbuf,0);
216 114 : std::istringstream i(std::string(&rbuf[0],rbuf.size()));
217 114 : plumedMain.readBinary(i);
218 114 : plumedMain.setExchangeStep(true);
219 114 : plumedMain.prepareDependencies();
220 114 : plumedMain.justCalculate();
221 114 : plumedMain.setExchangeStep(false);
222 114 : localDeltaBias+=plumedMain.getBias();
223 114 : localDeltaBias+=localUSwap-localUNow;
224 114 : if(intracomm.Get_rank()==0) {
225 57 : Communicator::Request req=intercomm.Isend(localDeltaBias,partner,1067);
226 57 : intercomm.Recv(foreignDeltaBias,partner,1067);
227 57 : req.wait();
228 : }
229 114 : intracomm.Bcast(foreignDeltaBias,0);
230 228 : }
231 :
232 : }
|