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 "Action.h"
23 : #include "ActionAtomistic.h"
24 : #include "ActionWithValue.h"
25 : #include "ActionWithArguments.h"
26 : #include "ActionWithVirtualAtom.h"
27 : #include "ActionForInterface.h"
28 : #include "DomainDecomposition.h"
29 : #include "PbcAction.h"
30 : #include "ActionToPutData.h"
31 : #include "ActionToGetData.h"
32 : #include "PlumedMain.h"
33 : #include "tools/Log.h"
34 : #include "tools/Exception.h"
35 : #include "tools/Communicator.h"
36 : #include "ActionSet.h"
37 : #include <iomanip>
38 : #include <iostream>
39 : #include <algorithm>
40 : namespace PLMD {
41 :
42 : Keywords ActionOptions::emptyKeys;
43 :
44 49178 : ActionOptions::ActionOptions(PlumedMain&p,const std::vector<std::string>&l):
45 49178 : plumed(p),
46 49178 : line(l),
47 49178 : keys(emptyKeys) {
48 49178 : }
49 :
50 49176 : ActionOptions::ActionOptions(const ActionOptions&ao,const Keywords&mykeys):
51 49176 : plumed(ao.plumed),
52 49176 : line(ao.line),
53 49176 : keys(mykeys) {
54 49176 : }
55 :
56 70028 : void Action::registerKeywords( Keywords& keys ) {
57 70028 : plumed_assert( keys.size()==0 );
58 70028 : keys.add( "hidden", "LABEL", "a label for the action so that its output can be referenced in the input to other actions. Actions with scalar output are referenced using their label only. Actions with vector output must have a separate label for every component. Individual components are then referred to using label.component" );
59 70028 : keys.reserve("optional","UPDATE_FROM","Only update this action from this time");
60 70028 : keys.reserve("optional","UPDATE_UNTIL","Only update this action until this time");
61 70028 : keys.reserve("optional","RESTART","allows per-action setting of restart (YES/NO/AUTO)");
62 70028 : }
63 :
64 49176 : Action::Action(const ActionOptions&ao):
65 49176 : actionName(ao.line[0]),
66 : //skipping the name with the +1
67 49176 : linemap(ao.line.begin()+1,ao.line.end()),
68 49176 : update_from(std::numeric_limits<double>::max()),
69 49176 : update_until(std::numeric_limits<double>::max()),
70 49176 : timestep(0),
71 49176 : active(false),
72 49176 : restart(ao.plumed.getRestart()),
73 49176 : doCheckPoint(ao.plumed.getCPT()),
74 49176 : never_activate(actionName=="CONSTANT"),
75 49176 : plumed(ao.plumed),
76 49176 : log(plumed.getLog()),
77 49176 : comm(plumed.comm),
78 49176 : multi_sim_comm(plumed.multi_sim_comm),
79 98352 : keywords(ao.keys) {
80 : // Retrieve the timestep and save it
81 49176 : resetStoredTimestep();
82 :
83 : //line.erase(line.begin());
84 : //making the line map
85 49176 : if( !keywords.exists("NO_ACTION_LOG") ) {
86 34373 : log.printf("Action %s\n",actionName.c_str());
87 34373 : if(ao.fullPath.length()>0) {
88 41 : log<<" from library: "<<ao.fullPath<<"\n";
89 : }
90 : }
91 :
92 49176 : if(comm.Get_rank()==0) {
93 35228 : replica_index=multi_sim_comm.Get_rank();
94 : }
95 49176 : comm.Bcast(replica_index,0);
96 :
97 49176 : if ( keywords.exists("LABEL") ) {
98 97884 : parse("LABEL",actionLabel);
99 : }
100 49176 : if(actionLabel.length()==0) {
101 : std::string s;
102 3278 : Tools::convert(plumed.getActionSet().size()-plumed.getActionSet().select<ActionForInterface*>().size(),s);
103 6556 : actionLabel="@"+s;
104 45898 : } else if ( actionLabel.find(".")!=std::string::npos ) {
105 14 : warning("using full stop in an action label should be avaoided as . has a special meaning in PLUMED action labels");
106 : }
107 49176 : if( plumed.getActionSet().selectWithLabel<Action*>(actionLabel) ) {
108 0 : error("label " + actionLabel + " has been already used");
109 : }
110 49176 : if( !keywords.exists("NO_ACTION_LOG") ) {
111 34373 : log.printf(" with label %s\n",actionLabel.c_str());
112 : }
113 49176 : if ( keywords.exists("UPDATE_FROM") ) {
114 4574 : parse("UPDATE_FROM",update_from);
115 : }
116 49176 : if( !keywords.exists("NO_ACTION_LOG") && update_from!=std::numeric_limits<double>::max()) {
117 5 : log.printf(" only update from time %f\n",update_from);
118 : }
119 49176 : if ( keywords.exists("UPDATE_UNTIL") ) {
120 4574 : parse("UPDATE_UNTIL",update_until);
121 : }
122 49176 : if( !keywords.exists("NO_ACTION_LOG") && update_until!=std::numeric_limits<double>::max()) {
123 5 : log.printf(" only update until time %f\n",update_until);
124 : }
125 49176 : if ( keywords.exists("RESTART") ) {
126 2250 : std::string srestart="AUTO";
127 2249 : parse("RESTART",srestart);
128 2249 : if( plumed.parseOnlyMode() ) {
129 0 : restart=false;
130 2249 : } else if(srestart=="YES") {
131 170 : restart=true;
132 2079 : } else if(srestart=="NO") {
133 22 : restart=false;
134 2057 : } else if(srestart=="AUTO") {
135 : // do nothing, this is the default
136 : } else {
137 2 : error("RESTART should be either YES, NO, or AUTO");
138 : }
139 : }
140 49175 : }
141 :
142 96821 : void Action::resetStoredTimestep() {
143 96821 : ActionWithValue* ts = plumed.getActionSet().selectWithLabel<ActionWithValue*>("timestep");
144 96821 : if( ts ) {
145 90416 : timestep = (ts->copyOutput(0))->get();
146 : }
147 96821 : }
148 :
149 98350 : Action::~Action() {
150 49175 : if(files.size()!=0) {
151 0 : std::cerr<<"WARNING: some files open in action "+getLabel()+" where not properly closed. This could lead to data loss!!\n";
152 : }
153 98350 : }
154 :
155 82 : FILE* Action::fopen(const char *path, const char *mode) {
156 : bool write(false);
157 164 : for(const char*p=mode; *p; p++)
158 82 : if(*p=='w' || *p=='a' || *p=='+') {
159 : write=true;
160 : }
161 : FILE* fp;
162 82 : if(write && comm.Get_rank()!=0) {
163 0 : fp=plumed.fopen("/dev/null",mode);
164 : } else {
165 82 : fp=plumed.fopen(path,mode);
166 : }
167 81 : files.insert(fp);
168 81 : return fp;
169 : }
170 :
171 99 : int Action::fclose(FILE*fp) {
172 : files.erase(fp);
173 99 : return plumed.fclose(fp);
174 : }
175 :
176 59598 : void Action::fflush() {
177 59598 : for(const auto & p : files) {
178 0 : std::fflush(p);
179 : }
180 59598 : }
181 :
182 0 : std::string Action::getKeyword(const std::string& key) {
183 : // Check keyword has been registered
184 0 : plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
185 :
186 0 : std::string outkey=linemap.getKeyword(key);
187 0 : if(!outkey.empty()) {
188 : return outkey;
189 : }
190 0 : if( keywords.style(key,"compulsory") ) {
191 0 : if( keywords.getDefaultValue(key,outkey) ) {
192 0 : if( outkey.length()==0 ) {
193 0 : error("keyword " + key + " has weird default value");
194 : }
195 0 : return key + "=" + outkey;
196 : } else {
197 0 : error("keyword " + key + " is compulsory for this action");
198 : }
199 : }
200 0 : return "";
201 : }
202 :
203 98175 : void Action::parseFlag(const std::string&key,bool & t) {
204 : // Check keyword has been registered
205 98175 : plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
206 : // Check keyword is a flag
207 200650 : plumed_massert( keywords.style(key,"deprecated") || keywords.style(key,"flag") || keywords.style(key,"hidden"), "keyword " + key + " is not a flag");
208 :
209 : // Read in the flag otherwise get the default value from the keywords object
210 98175 : t = linemap.readAndRemoveFlag(key);
211 98175 : if(!t) {
212 171926 : if( keywords.style(key,"nohtml") ) {
213 0 : t=false;
214 85963 : } else if ( !keywords.getLogicalDefault(key,t) ) {
215 0 : log.printf("ERROR in action %s with label %s : flag %s has no default",actionName.c_str(),actionLabel.c_str(),key.c_str() );
216 0 : plumed_error();
217 : }
218 : }
219 98175 : }
220 :
221 1250224 : void Action::addDependency(Action*action) {
222 : bool found=false;
223 38394201 : for(const auto & d : after ) {
224 37396026 : if( action==d ) {
225 : found=true;
226 : break;
227 : }
228 : }
229 1250224 : if( !found ) {
230 998175 : after.push_back(action);
231 : }
232 1250224 : }
233 :
234 70 : bool Action::checkForDependency( Action* action ) {
235 135 : for(const auto & d : after) {
236 70 : if( action==d ) {
237 : return true;
238 : }
239 65 : if( d->checkForDependency(action) ) {
240 : return true;
241 : }
242 : }
243 : return false;
244 : }
245 :
246 5385406 : void Action::activate() {
247 : // This is set to true if actions are only need to be computed in setup (during checkRead)
248 5385406 : if( never_activate ) {
249 : return;
250 : }
251 : // preparation step is called only the first time an Action is activated.
252 : // since it could change its dependences (e.g. in an ActionAtomistic which is
253 : // accessing to a virtual atom), this is done just before dependencies are
254 : // activated
255 5268371 : if(!active) {
256 2709746 : this->unlockRequests();
257 2709746 : prepare();
258 2709746 : this->lockRequests();
259 : } else {
260 : return;
261 : }
262 6730488 : for(const auto & p : after) {
263 4020742 : p->activate();
264 : }
265 2709746 : active=true;
266 : }
267 :
268 2228 : void Action::setOption(const std::string &s) {
269 : // This overloads the action and activate some options
270 2228 : actionOptions.insert(s);
271 4370 : for(const auto & p : after) {
272 2142 : p->setOption(s);
273 : }
274 2228 : }
275 :
276 0 : void Action::clearOptions() {
277 : // This overloads the action and activate some options
278 : actionOptions.clear();
279 0 : }
280 :
281 :
282 198579 : void Action::clearDependencies() {
283 : after.clear();
284 198579 : }
285 :
286 65188 : void Action::checkRead() {
287 65188 : if (!linemap.empty()) {
288 1 : std::string msg="cannot understand the following words from the input line : ";
289 2 : msg += linemap.keyList(", ");
290 1 : error(msg);
291 : }
292 :
293 65187 : setupConstantValues(false);
294 65187 : }
295 :
296 93432 : void Action::setupConstantValues( const bool& have_atoms ) {
297 93432 : if( have_atoms ) {
298 : // This ensures that we switch off actions that only depend on constant when passed from the
299 : // MD code on the first step
300 28245 : ActionAtomistic* at = castToActionAtomistic();
301 28245 : ActionWithValue* av = castToActionWithValue();
302 28245 : if( at && av ) {
303 15006 : never_activate=av->getNumberOfComponents()>0;
304 15037 : for(unsigned i=0; i<av->getNumberOfComponents(); ++i) {
305 15006 : if( !av->copyOutput(i)->isConstant() ) {
306 14975 : never_activate=false;
307 14975 : break;
308 : }
309 : }
310 : }
311 : }
312 93432 : ActionWithArguments* aa = castToActionWithArguments();
313 111010 : if( aa && aa->getNumberOfArguments()>0 && getName()!="BIASVALUE" ) {
314 16849 : never_activate = aa->calculateConstantValues( have_atoms );
315 : }
316 93432 : }
317 :
318 5470497 : long long int Action::getStep()const {
319 5470497 : return plumed.getStep();
320 : }
321 :
322 3705407 : double Action::getTime()const {
323 3705407 : return timestep*getStep();
324 : }
325 :
326 219886 : double Action::getTimeStep()const {
327 219886 : return timestep;
328 : }
329 :
330 682 : double Action::getkBT() {
331 682 : double temp=-1.0;
332 682 : if( keywords.exists("TEMP") ) {
333 1336 : parse("TEMP",temp);
334 : }
335 1698 : if(temp>=0.0 && keywords.style("TEMP","optional") ) {
336 421 : return getKBoltzmann()*temp;
337 : }
338 261 : ActionForInterface* kb=plumed.getActionSet().selectWithLabel<ActionForInterface*>("kBT");
339 : double kbt=0;
340 261 : if(kb) {
341 3 : kbt=(kb->copyOutput(0))->get();
342 : }
343 377 : if( temp>=0 && keywords.style("TEMP","compulsory") ) {
344 58 : double kB=getKBoltzmann();
345 58 : if( kbt>0 && std::abs(kbt-kB*temp)>1e-4) {
346 : std::string strt1, strt2;
347 0 : Tools::convert( temp, strt1 );
348 0 : Tools::convert( kbt/kB, strt2 );
349 0 : warning("using TEMP=" + strt1 + " while MD engine uses " + strt2 + "\n");
350 : }
351 58 : kbt = kB*temp;
352 58 : plumed_massert(kbt>0,"your MD engine does not pass the temperature to plumed, you must specify it using TEMP");
353 : return kbt;
354 : }
355 : return kbt;
356 : }
357 :
358 0 : void Action::exit(int c) {
359 0 : plumed.exit(c);
360 0 : }
361 :
362 0 : void Action::calculateNumericalDerivatives( ActionWithValue* a ) {
363 0 : plumed_merror("if you get here it means that you are trying to use numerical derivatives for a class that does not implement them");
364 : }
365 :
366 1118070 : void Action::prepare() {
367 1118070 : return;
368 : }
369 :
370 28 : [[noreturn]] void Action::error( const std::string & msg ) const {
371 28 : log.printf("ERROR in input to action %s with label %s : %s \n \n", actionName.c_str(), actionLabel.c_str(), msg.c_str() );
372 84 : plumed_merror("ERROR in input to action " + actionName + " with label " + actionLabel + " : " + msg );
373 : }
374 :
375 4240 : void Action::warning( const std::string & msg ) {
376 4240 : log.printf("WARNING for action %s with label %s : %s \n", actionName.c_str(), actionLabel.c_str(), msg.c_str() );
377 4240 : }
378 :
379 0 : void Action::calculateFromPDB( const PDB& pdb ) {
380 0 : activate();
381 0 : for(const auto & p : after) {
382 0 : ActionWithValue*av=castToActionWithValue();
383 0 : if(av) {
384 0 : av->clearInputForces();
385 0 : av->clearDerivatives();
386 : }
387 0 : p->readAtomsFromPDB( pdb );
388 0 : p->calculate();
389 : }
390 0 : readAtomsFromPDB( pdb );
391 0 : calculate();
392 0 : }
393 :
394 30480 : bool Action::getExchangeStep()const {
395 30480 : return plumed.getExchangeStep();
396 : }
397 :
398 41 : std::string Action::cite(const std::string&s) {
399 41 : return plumed.cite(s);
400 : }
401 :
402 : /// Check if action should be updated.
403 2568758 : bool Action::checkUpdate()const {
404 2568758 : double t=getTime();
405 2568758 : if(t<update_until && (update_from==std::numeric_limits<double>::max() || t>=update_from)) {
406 : return true;
407 : } else {
408 510 : return false;
409 : }
410 : }
411 :
412 1340 : bool Action::getCPT() const {
413 1340 : return plumed.getCPT();
414 : }
415 :
416 16247442 : const Units& Action::getUnits() const {
417 16247442 : return plumed.getUnits();
418 : }
419 :
420 2199 : bool Action::usingNaturalUnits() const {
421 2199 : return plumed.usingNaturalUnits();
422 : }
423 :
424 714 : double Action::getKBoltzmann() const {
425 714 : if( usingNaturalUnits() ) {
426 : return 1.0;
427 : } else {
428 714 : return kBoltzmann/getUnits().getEnergy();
429 : }
430 : }
431 :
432 56 : std::string Action::writeInGraph() const {
433 56 : std::string nam=getName();
434 56 : std::size_t u=nam.find_last_of("_");
435 56 : std::string sub=nam.substr(u+1);
436 154 : if( sub=="SCALAR" || sub=="VECTOR" || sub=="GRID" ) {
437 8 : return nam.substr(0,u);
438 : }
439 : return nam;
440 : }
441 :
442 : }
443 :
|