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