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 : }
|