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 "ActionWithValue.h"
24 : #include "PlumedMain.h"
25 : #include "tools/Log.h"
26 : #include "tools/Exception.h"
27 : #include "Atoms.h"
28 : #include "ActionSet.h"
29 : #include <iostream>
30 :
31 : namespace PLMD {
32 :
33 : Keywords ActionOptions::emptyKeys;
34 :
35 14552 : ActionOptions::ActionOptions(PlumedMain&p,const std::vector<std::string>&l):
36 14552 : plumed(p),
37 14552 : line(l),
38 14552 : keys(emptyKeys) {
39 14552 : }
40 :
41 14550 : ActionOptions::ActionOptions(const ActionOptions&ao,const Keywords&keys):
42 14550 : plumed(ao.plumed),
43 14550 : line(ao.line),
44 14550 : keys(keys) {
45 14550 : }
46 :
47 15711 : void Action::registerKeywords( Keywords& keys ) {
48 15711 : plumed_assert( keys.size()==0 );
49 31422 : 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" );
50 31422 : keys.reserve("optional","UPDATE_FROM","Only update this action from this time");
51 31422 : keys.reserve("optional","UPDATE_UNTIL","Only update this action until this time");
52 31422 : keys.reserve("optional","RESTART","allows per-action setting of restart (YES/NO/AUTO)");
53 15711 : }
54 :
55 14550 : Action::Action(const ActionOptions&ao):
56 14550 : name(ao.line[0]),
57 14550 : line(ao.line),
58 14550 : update_from(std::numeric_limits<double>::max()),
59 14550 : update_until(std::numeric_limits<double>::max()),
60 14550 : active(false),
61 14550 : restart(ao.plumed.getRestart()),
62 14550 : doCheckPoint(ao.plumed.getCPT()),
63 14550 : plumed(ao.plumed),
64 14550 : log(plumed.getLog()),
65 14550 : comm(plumed.comm),
66 14550 : multi_sim_comm(plumed.multi_sim_comm),
67 14550 : keywords(ao.keys) {
68 : line.erase(line.begin());
69 14550 : log.printf("Action %s\n",name.c_str());
70 :
71 14550 : if(comm.Get_rank()==0) {
72 8099 : replica_index=multi_sim_comm.Get_rank();
73 : }
74 14550 : comm.Bcast(replica_index,0);
75 :
76 29100 : if ( keywords.exists("LABEL") ) {
77 28672 : parse("LABEL",label);
78 : }
79 :
80 14550 : if(label.length()==0) {
81 : std::string s;
82 2537 : Tools::convert(plumed.getActionSet().size(),s);
83 5074 : label="@"+s;
84 : }
85 14550 : if( plumed.getActionSet().selectWithLabel<Action*>(label) ) {
86 0 : error("label " + label + " has been already used");
87 : }
88 14550 : log.printf(" with label %s\n",label.c_str());
89 29100 : if ( keywords.exists("UPDATE_FROM") ) {
90 3634 : parse("UPDATE_FROM",update_from);
91 : }
92 14550 : if(update_from!=std::numeric_limits<double>::max()) {
93 3 : log.printf(" only update from time %f\n",update_from);
94 : }
95 29100 : if ( keywords.exists("UPDATE_UNTIL") ) {
96 3634 : parse("UPDATE_UNTIL",update_until);
97 : }
98 14550 : if(update_until!=std::numeric_limits<double>::max()) {
99 3 : log.printf(" only update until time %f\n",update_until);
100 : }
101 29100 : if ( keywords.exists("RESTART") ) {
102 1916 : std::string srestart="AUTO";
103 1915 : parse("RESTART",srestart);
104 1915 : if( plumed.parseOnlyMode() ) {
105 0 : restart=false;
106 1915 : } else if(srestart=="YES") {
107 91 : restart=true;
108 1824 : } else if(srestart=="NO") {
109 22 : restart=false;
110 1802 : } else if(srestart=="AUTO") {
111 : // do nothing, this is the default
112 : } else {
113 2 : error("RESTART should be either YES, NO, or AUTO");
114 : }
115 : }
116 14550 : }
117 :
118 29098 : Action::~Action() {
119 14549 : if(files.size()!=0) {
120 0 : std::cerr<<"WARNING: some files open in action "+getLabel()+" where not properly closed. This could lead to data loss!!\n";
121 : }
122 29098 : }
123 :
124 73 : FILE* Action::fopen(const char *path, const char *mode) {
125 : bool write(false);
126 146 : for(const char*p=mode; *p; p++)
127 73 : if(*p=='w' || *p=='a' || *p=='+') {
128 : write=true;
129 : }
130 : FILE* fp;
131 73 : if(write && comm.Get_rank()!=0) {
132 0 : fp=plumed.fopen("/dev/null",mode);
133 : } else {
134 73 : fp=plumed.fopen(path,mode);
135 : }
136 73 : files.insert(fp);
137 73 : return fp;
138 : }
139 :
140 91 : int Action::fclose(FILE*fp) {
141 : files.erase(fp);
142 91 : return plumed.fclose(fp);
143 : }
144 :
145 18303 : void Action::fflush() {
146 18303 : for(const auto & p : files) {
147 0 : std::fflush(p);
148 : }
149 18303 : }
150 :
151 33 : std::string Action::getKeyword(const std::string& key) {
152 : // Check keyword has been registered
153 33 : plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
154 :
155 : std::string outkey;
156 33 : if( Tools::getKey(line,key,outkey ) ) {
157 33 : return key + outkey;
158 : }
159 :
160 0 : if( keywords.style(key,"compulsory") ) {
161 0 : if( keywords.getDefaultValue(key,outkey) ) {
162 0 : if( outkey.length()==0 ) {
163 0 : error("keyword " + key + " has weird default value");
164 : }
165 0 : return key + "=" + outkey;
166 : } else {
167 0 : error("keyword " + key + " is compulsory for this action");
168 : }
169 : }
170 0 : return "";
171 : }
172 :
173 41585 : void Action::parseFlag(const std::string&key,bool & t) {
174 : // Check keyword has been registered
175 41585 : plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
176 : // Check keyword is a flag
177 83170 : if(!keywords.style(key,"nohtml")) {
178 80535 : plumed_massert( keywords.style(key,"vessel") || keywords.style(key,"flag") || keywords.style(key,"hidden"), "keyword " + key + " is not a flag");
179 : }
180 :
181 : // Read in the flag otherwise get the default value from the keywords object
182 41585 : if(!Tools::parseFlag(line,key,t)) {
183 82860 : if( keywords.style(key,"nohtml") || keywords.style(key,"vessel") ) {
184 2734 : t=false;
185 37329 : } else if ( !keywords.getLogicalDefault(key,t) ) {
186 0 : log.printf("ERROR in action %s with label %s : flag %s has no default",name.c_str(),label.c_str(),key.c_str() );
187 0 : plumed_error();
188 : }
189 : }
190 41585 : }
191 :
192 1084396 : void Action::addDependency(Action*action) {
193 1084396 : after.push_back(action);
194 1084396 : }
195 :
196 3236286 : void Action::activate() {
197 : // preparation step is called only the first time an Action is activated.
198 : // since it could change its dependences (e.g. in an ActionAtomistic which is
199 : // accessing to a virtual atom), this is done just before dependencies are
200 : // activated
201 3236286 : if(!active) {
202 1665305 : this->unlockRequests();
203 1665305 : prepare();
204 1665305 : this->lockRequests();
205 : } else {
206 : return;
207 : }
208 3614060 : for(const auto & p : after) {
209 1948755 : p->activate();
210 : }
211 1665305 : active=true;
212 : }
213 :
214 267 : void Action::setOption(const std::string &s) {
215 : // This overloads the action and activate some options
216 267 : options.insert(s);
217 448 : for(const auto & p : after) {
218 181 : p->setOption(s);
219 : }
220 267 : }
221 :
222 0 : void Action::clearOptions() {
223 : // This overloads the action and activate some options
224 : options.clear();
225 0 : }
226 :
227 :
228 189379 : void Action::clearDependencies() {
229 : after.clear();
230 189379 : }
231 :
232 28311 : void Action::checkRead() {
233 28311 : if(!line.empty()) {
234 0 : std::string msg="cannot understand the following words from the input line : ";
235 0 : for(unsigned i=0; i<line.size(); i++) {
236 0 : if(i>0) {
237 0 : msg = msg + ", ";
238 : }
239 0 : msg = msg + line[i];
240 : }
241 0 : error(msg);
242 : }
243 28311 : }
244 :
245 4613973 : long long int Action::getStep()const {
246 4613973 : return plumed.getStep();
247 : }
248 :
249 3029665 : double Action::getTime()const {
250 3029665 : return plumed.getAtoms().getTimeStep()*getStep();
251 : }
252 :
253 18180 : double Action::getTimeStep()const {
254 18180 : return plumed.getAtoms().getTimeStep();
255 : }
256 :
257 :
258 :
259 0 : void Action::exit(int c) {
260 0 : plumed.exit(c);
261 0 : }
262 :
263 0 : void Action::calculateNumericalDerivatives( ActionWithValue* a ) {
264 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");
265 : }
266 :
267 334899 : void Action::prepare() {
268 334899 : return;
269 : }
270 :
271 30 : [[noreturn]] void Action::error( const std::string & msg ) const {
272 30 : log.printf("ERROR in input to action %s with label %s : %s \n \n", name.c_str(), label.c_str(), msg.c_str() );
273 90 : plumed_merror("ERROR in input to action " + name + " with label " + label + " : " + msg );
274 : }
275 :
276 139 : void Action::warning( const std::string & msg ) {
277 139 : log.printf("WARNING for action %s with label %s : %s \n", name.c_str(), label.c_str(), msg.c_str() );
278 139 : }
279 :
280 0 : void Action::calculateFromPDB( const PDB& pdb ) {
281 0 : activate();
282 0 : for(const auto & p : after) {
283 0 : ActionWithValue*av=dynamic_cast<ActionWithValue*>(p);
284 0 : if(av) {
285 0 : av->clearInputForces();
286 0 : av->clearDerivatives();
287 : }
288 0 : p->readAtomsFromPDB( pdb );
289 0 : p->calculate();
290 : }
291 0 : readAtomsFromPDB( pdb );
292 0 : calculate();
293 0 : }
294 :
295 30198 : bool Action::getExchangeStep()const {
296 30198 : return plumed.getExchangeStep();
297 : }
298 :
299 40 : std::string Action::cite(const std::string&s) {
300 40 : return plumed.cite(s);
301 : }
302 :
303 : /// Check if action should be updated.
304 1657344 : bool Action::checkUpdate()const {
305 1657344 : double t=getTime();
306 1657344 : if(t<update_until && (update_from==std::numeric_limits<double>::max() || t>=update_from)) {
307 : return true;
308 : } else {
309 510 : return false;
310 : }
311 : }
312 :
313 1340 : bool Action::getCPT()const {
314 1340 : return plumed.getCPT();
315 : }
316 :
317 : }
318 :
|