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 "PlumedMain.h"
23 : #include "ActionAtomistic.h"
24 : #include "ActionPilot.h"
25 : #include "ActionForInterface.h"
26 : #include "ActionRegister.h"
27 : #include "ActionSet.h"
28 : #include "ActionWithValue.h"
29 : #include "ActionWithVirtualAtom.h"
30 : #include "ActionToGetData.h"
31 : #include "ActionToPutData.h"
32 : #include "CLToolMain.h"
33 : #include "ExchangePatterns.h"
34 : #include "GREX.h"
35 : #include "DomainDecomposition.h"
36 : #include "config/Config.h"
37 : #include "tools/Citations.h"
38 : #include "tools/Communicator.h"
39 : #include "tools/DLLoader.h"
40 : #include "tools/Exception.h"
41 : #include "tools/IFile.h"
42 : #include "tools/Log.h"
43 : #include "tools/OpenMP.h"
44 : #include "tools/Tools.h"
45 : #include "tools/Stopwatch.h"
46 : #include "tools/TypesafePtr.h"
47 : #include "lepton/Exception.h"
48 : #include "DataPassingTools.h"
49 : #include "small_vector/small_vector.h"
50 : #include <cstdlib>
51 : #include <cstdio>
52 : #include <cstring>
53 : #include <set>
54 : #include <exception>
55 : #include <stdexcept>
56 : #include <ios>
57 : #include <new>
58 : #include <typeinfo>
59 : #include <iostream>
60 : #include <algorithm>
61 : #include <system_error>
62 : #include <future>
63 : #include <memory>
64 : #include <functional>
65 : #include <regex>
66 : #include <any>
67 : #include <optional>
68 : #include <variant>
69 : #include <filesystem>
70 :
71 : namespace PLMD {
72 :
73 : /// Small utility just used in this file to throw arbitrary exceptions
74 61 : [[noreturn]] static void testThrow(const char* what) {
75 61 : auto words=Tools::getWords(what);
76 61 : plumed_assert(words.size()>0);
77 : #define __PLUMED_THROW_NOMSG(type) if(words[0]==#type) throw type()
78 : #define __PLUMED_THROW_MSG(type) if(words[0]==#type) throw type(what)
79 62 : __PLUMED_THROW_MSG(PLMD::ExceptionError);
80 61 : __PLUMED_THROW_MSG(PLMD::ExceptionDebug);
81 60 : __PLUMED_THROW_MSG(PLMD::Exception);
82 59 : __PLUMED_THROW_MSG(PLMD::lepton::Exception);
83 57 : __PLUMED_THROW_NOMSG(std::bad_exception);
84 56 : __PLUMED_THROW_NOMSG(std::bad_array_new_length);
85 55 : __PLUMED_THROW_NOMSG(std::bad_alloc);
86 54 : __PLUMED_THROW_NOMSG(std::bad_function_call);
87 53 : __PLUMED_THROW_NOMSG(std::bad_weak_ptr);
88 52 : __PLUMED_THROW_NOMSG(std::bad_cast);
89 51 : __PLUMED_THROW_NOMSG(std::bad_typeid);
90 50 : __PLUMED_THROW_NOMSG(std::bad_variant_access);
91 49 : __PLUMED_THROW_NOMSG(std::bad_optional_access);
92 48 : __PLUMED_THROW_NOMSG(std::bad_any_cast);
93 47 : __PLUMED_THROW_MSG(std::underflow_error);
94 46 : __PLUMED_THROW_MSG(std::overflow_error);
95 45 : __PLUMED_THROW_MSG(std::range_error);
96 44 : __PLUMED_THROW_MSG(std::runtime_error);
97 43 : __PLUMED_THROW_MSG(std::out_of_range);
98 42 : __PLUMED_THROW_MSG(std::length_error);
99 41 : __PLUMED_THROW_MSG(std::domain_error);
100 40 : __PLUMED_THROW_MSG(std::invalid_argument);
101 39 : __PLUMED_THROW_MSG(std::logic_error);
102 :
103 :
104 :
105 38 : if(words[0]=="std::system_error") {
106 4 : plumed_assert(words.size()>2);
107 : int error_code;
108 4 : Tools::convert(words[2],error_code);
109 4 : if(words[1]=="std::generic_category") {
110 1 : throw std::system_error(error_code,std::generic_category(),what);
111 : }
112 3 : if(words[1]=="std::system_category") {
113 1 : throw std::system_error(error_code,std::system_category(),what);
114 : }
115 2 : if(words[1]=="std::iostream_category") {
116 1 : throw std::system_error(error_code,std::iostream_category(),what);
117 : }
118 1 : if(words[1]=="std::future_category") {
119 1 : throw std::system_error(error_code,std::future_category(),what);
120 : }
121 : }
122 :
123 34 : if(words[0]=="std::filesystem::filesystem_error") {
124 : int error_code;
125 3 : plumed_assert(words.size()>2);
126 3 : Tools::convert(words[2],error_code);
127 : std::error_code x_error_code;
128 3 : if(words[1]=="std::generic_category") {
129 3 : x_error_code=::std::error_code(error_code,::std::generic_category());
130 : }
131 3 : if(words[1]=="std::system_category") {
132 0 : x_error_code=::std::error_code(error_code,::std::system_category());
133 : }
134 3 : if(words[1]=="std::iostream_category") {
135 0 : x_error_code=::std::error_code(error_code,::std::iostream_category());
136 : }
137 3 : if(words[1]=="std::future_category") {
138 0 : x_error_code=::std::error_code(error_code,::std::future_category());
139 : }
140 :
141 3 : if(words.size()<4) {
142 2 : throw std::filesystem::filesystem_error(what,x_error_code);
143 : }
144 2 : if(words.size()<5) {
145 3 : throw std::filesystem::filesystem_error(what,std::filesystem::path(words[3]),x_error_code);
146 : }
147 4 : throw std::filesystem::filesystem_error(what,std::filesystem::path(words[3]),std::filesystem::path(words[4]),x_error_code);
148 : }
149 :
150 : #define __PLUMED_THROW_REGEX(name) if(words[1]=="std::regex_constants::error_" #name) throw std::regex_error(std::regex_constants::error_ ##name)
151 31 : if(words[0]=="std::regex_error") {
152 13 : plumed_assert(words.size()>1);
153 13 : __PLUMED_THROW_REGEX(collate);
154 12 : __PLUMED_THROW_REGEX(ctype);
155 11 : __PLUMED_THROW_REGEX(escape);
156 10 : __PLUMED_THROW_REGEX(backref);
157 9 : __PLUMED_THROW_REGEX(brack);
158 8 : __PLUMED_THROW_REGEX(paren);
159 7 : __PLUMED_THROW_REGEX(brace);
160 6 : __PLUMED_THROW_REGEX(badbrace);
161 5 : __PLUMED_THROW_REGEX(range);
162 4 : __PLUMED_THROW_REGEX(space);
163 3 : __PLUMED_THROW_REGEX(badrepeat);
164 2 : __PLUMED_THROW_REGEX(complexity);
165 1 : __PLUMED_THROW_REGEX(stack);
166 : }
167 :
168 : #define __PLUMED_THROW_FUTURE(name) if(words[1]=="std::future_errc::" #name) throw std::future_error(::std::future_errc::name)
169 18 : if(words[0]=="std::future_error") {
170 4 : plumed_assert(words.size()>1);
171 4 : __PLUMED_THROW_FUTURE(broken_promise);
172 3 : __PLUMED_THROW_FUTURE(future_already_retrieved);
173 2 : __PLUMED_THROW_FUTURE(promise_already_satisfied);
174 1 : __PLUMED_THROW_FUTURE(no_state);
175 : }
176 :
177 14 : if(words[0]=="std::ios_base::failure") {
178 1 : int error_code=0;
179 1 : if(words.size()>2) {
180 0 : Tools::convert(words[2],error_code);
181 : }
182 1 : if(words.size()>1 && words[1]=="std::generic_category") {
183 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::generic_category()));
184 : }
185 1 : if(words.size()>1 && words[1]=="std::system_category") {
186 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::system_category()));
187 : }
188 1 : if(words.size()>1 && words[1]=="std::iostream_category") {
189 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::iostream_category()));
190 : }
191 1 : if(words.size()>1 && words[1]=="std::future_category") {
192 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::future_category()));
193 : }
194 2 : throw std::ios_base::failure(what);
195 : }
196 :
197 13 : if(words[0]=="int") {
198 1 : int value=0;
199 1 : if(words.size()>1) {
200 0 : Tools::convert(words[1],value);
201 : }
202 1 : throw value;
203 : }
204 :
205 12 : if(words[0]=="test_nested1") {
206 : try {
207 12 : throw Exception(std::string("inner ")+what);
208 6 : } catch(...) {
209 : try {
210 18 : std::throw_with_nested(Exception(std::string("middle ")+what));
211 6 : } catch(...) {
212 18 : std::throw_with_nested(Exception(std::string("outer ")+what));
213 6 : }
214 6 : }
215 : }
216 :
217 6 : if(words[0]=="test_nested2") {
218 : try {
219 3 : throw std::bad_alloc();
220 3 : } catch(...) {
221 : try {
222 9 : std::throw_with_nested(Exception(std::string("middle ")+what));
223 3 : } catch(...) {
224 9 : std::throw_with_nested(Exception(std::string("outer ")+what));
225 3 : }
226 3 : }
227 : }
228 :
229 3 : if(words[0]=="test_nested3") {
230 : try {
231 2 : throw "inner";
232 2 : } catch(...) {
233 : try {
234 6 : std::throw_with_nested(Exception(std::string("middle ")+what));
235 2 : } catch(...) {
236 6 : std::throw_with_nested(Exception(std::string("outer ")+what));
237 2 : }
238 2 : }
239 : }
240 :
241 2 : plumed_error() << "unknown exception " << what;
242 61 : }
243 :
244 : namespace {
245 : /// This is an internal tool used to count how many PlumedMain objects have been created
246 : /// and if they were correctly destroyed.
247 : /// When using debug options, it leads to a crash
248 : /// Otherwise, it just prints a message
249 : class CountInstances {
250 : std::atomic<int> counter{};
251 : // private constructor to avoid direct usage
252 6108 : CountInstances() noexcept {}
253 6108 : ~CountInstances() {
254 6108 : if(counter!=0) {
255 0 : std::cerr<<"WARNING: internal inconsistency in allocated PlumedMain instances (" <<counter<< ")\n";
256 0 : std::cerr<<"Might be a consequence of incorrectly paired plumed_create/plumed_finalize in the C interface\n";
257 0 : std::cerr<<"Or it could be due to incorrect calls to std::exit, without properly destroying all PlumedMain objects\n";
258 : #ifndef NDEBUG
259 : std::cerr<<"This is a debug build, so the warning will make PLUMED abort\n";
260 : std::abort();
261 : #endif
262 : }
263 6108 : }
264 1615692 : static CountInstances & instance() {
265 1615692 : static CountInstances counter;
266 1615692 : return counter;
267 : }
268 : public:
269 : /// Only access through these static functions
270 : /// The first call to increase() ensures the instance is constructed
271 : /// This should provide the correct construction and destruction order
272 : /// also in cases where the PlumedMain object is constructed in the
273 : /// constructor of a static object
274 807846 : static void increase() noexcept {
275 807846 : ++instance().counter;
276 807846 : }
277 : /// See increase()
278 807846 : static void decrease() noexcept {
279 807846 : --instance().counter;
280 807846 : }
281 : };
282 :
283 : }
284 :
285 :
286 807846 : PlumedMain::PlumedMain():
287 807846 : datoms_fwd(*this),
288 : // automatically write on log in destructor
289 807846 : stopwatch_fwd(log),
290 807846 : actionSet_fwd(*this),
291 807846 : passtools(DataPassingTools::create(sizeof(double))) {
292 807846 : passtools->usingNaturalUnits=false;
293 807846 : OpenMP::retainRuntime();
294 807846 : increaseReferenceCounter();
295 807846 : log.link(comm);
296 807846 : log.setLinePrefix("PLUMED: ");
297 : // this is at last so as to avoid inconsistencies if an exception is thrown
298 807846 : CountInstances::increase(); // noexcept
299 807846 : }
300 :
301 : // destructor needed to delete forward declarated objects
302 1614654 : PlumedMain::~PlumedMain() {
303 807846 : CountInstances::decrease();
304 4846038 : }
305 :
306 : /////////////////////////////////////////////////////////////
307 : // MAIN INTERPRETER
308 :
309 : #define CHECK_INIT(ini,word) plumed_assert(ini)<<"cmd(\"" << word << "\") should be only used after plumed initialization"
310 : #define CHECK_NOTINIT(ini,word) plumed_assert(!(ini))<<"cmd(\"" << word << "\") should be only used before plumed initialization"
311 : #define CHECK_NOTNULL(val,word) plumed_assert(val)<<"NULL pointer received in cmd(\"" << word << "\")"
312 :
313 :
314 1931779 : void PlumedMain::cmd(std::string_view word,const TypesafePtr & val) {
315 :
316 : // Enumerate all possible commands:
317 : enum {
318 : #include "PlumedMainEnum.inc"
319 : };
320 :
321 : // Static object (initialized once) containing the map of commands:
322 : const static Tools::FastStringUnorderedMap<int> word_map = {
323 : #include "PlumedMainMap.inc"
324 1931779 : };
325 :
326 : try {
327 :
328 1931779 : auto ss=stopwatch.startPause();
329 :
330 : gch::small_vector<std::string_view> words;
331 1931779 : Tools::getWordsSimple(words,word);
332 :
333 1931779 : unsigned nw=words.size();
334 1931779 : if(nw==0) {
335 : // do nothing
336 : } else {
337 : int iword=-1;
338 : const auto it=word_map.find(words[0]);
339 1931778 : if(it!=word_map.end()) {
340 1931771 : iword=it->second;
341 : }
342 :
343 1931771 : switch(iword) {
344 136729 : case cmd_setBox:
345 136729 : CHECK_INIT(initialized,word);
346 136729 : CHECK_NOTNULL(val,word);
347 136729 : setInputValue( "Box", 0, 1, val );
348 136728 : break;
349 140906 : case cmd_setPositions:
350 140906 : CHECK_INIT(initialized,word);
351 140906 : setInputValue("posx", 0, 3, val );
352 140906 : setInputValue("posy", 1, 3, val );
353 140906 : setInputValue("posz", 2, 3, val );
354 140906 : break;
355 140869 : case cmd_setMasses:
356 140869 : CHECK_INIT(initialized,word);
357 140869 : setInputValue("Masses", 0, 1, val );
358 140866 : break;
359 67667 : case cmd_setCharges:
360 67667 : CHECK_INIT(initialized,word);
361 67667 : setInputValue("Charges", 0, 1, val);
362 67667 : break;
363 1 : case cmd_setPositionsX:
364 1 : CHECK_INIT(initialized,word);
365 1 : setInputValue("posx", 0, 1, val);
366 1 : break;
367 1 : case cmd_setPositionsY:
368 1 : CHECK_INIT(initialized,word);
369 1 : setInputValue("posy", 0, 1, val);
370 1 : break;
371 1 : case cmd_setPositionsZ:
372 1 : CHECK_INIT(initialized,word);
373 1 : setInputValue("posz", 0, 1, val);
374 1 : break;
375 132993 : case cmd_setVirial:
376 132993 : CHECK_INIT(initialized,word);
377 132993 : CHECK_NOTNULL(val,word);
378 132993 : setInputForce("Box",val);
379 132975 : break;
380 7892 : case cmd_setEnergy:
381 7892 : CHECK_INIT(initialized,word);
382 7892 : CHECK_NOTNULL(val,word);
383 7892 : if( name_of_energy!="" ) {
384 3989 : setInputValue( name_of_energy, 0, 1, val );
385 : }
386 : break;
387 140873 : case cmd_setForces:
388 140873 : CHECK_INIT(initialized,word);
389 140873 : setInputForce("posx",val);
390 140873 : setInputForce("posy",val);
391 140873 : setInputForce("posz",val);
392 140873 : break;
393 1 : case cmd_setForcesX:
394 1 : CHECK_INIT(initialized,word);
395 1 : setInputForce("posx",val);
396 1 : break;
397 1 : case cmd_setForcesY:
398 1 : CHECK_INIT(initialized,word);
399 1 : setInputForce("posy",val);
400 1 : break;
401 1 : case cmd_setForcesZ:
402 1 : CHECK_INIT(initialized,word);
403 1 : setInputForce("posz",val);
404 1 : break;
405 357689 : case cmd_calc:
406 357689 : CHECK_INIT(initialized,word);
407 357689 : calc();
408 : break;
409 99 : case cmd_prepareDependencies:
410 99 : CHECK_INIT(initialized,word);
411 99 : prepareDependencies();
412 : break;
413 84 : case cmd_shareData:
414 84 : CHECK_INIT(initialized,word);
415 84 : shareData();
416 : break;
417 6985 : case cmd_prepareCalc:
418 6985 : CHECK_INIT(initialized,word);
419 6985 : prepareCalc();
420 : break;
421 10 : case cmd_performCalc:
422 10 : CHECK_INIT(initialized,word);
423 10 : performCalc();
424 : break;
425 7045 : case cmd_performCalcNoUpdate:
426 7045 : CHECK_INIT(initialized,word);
427 7045 : performCalcNoUpdate();
428 : break;
429 10 : case cmd_performCalcNoForces:
430 10 : CHECK_INIT(initialized,word);
431 10 : performCalcNoForces();
432 : break;
433 79 : case cmd_update:
434 79 : CHECK_INIT(initialized,word);
435 79 : update();
436 : break;
437 92643 : case cmd_setStep:
438 92643 : CHECK_INIT(initialized,word);
439 92646 : CHECK_NOTNULL(val,word);
440 92640 : step=val.get<int>();
441 92639 : startStep();
442 : break;
443 0 : case cmd_setStepLong:
444 0 : CHECK_INIT(initialized,word);
445 0 : CHECK_NOTNULL(val,word);
446 0 : step=val.get<long int>();
447 0 : startStep();
448 : break;
449 272032 : case cmd_setStepLongLong:
450 272032 : CHECK_INIT(initialized,word);
451 272032 : CHECK_NOTNULL(val,word);
452 272032 : step=val.get<long long int>();
453 272032 : startStep();
454 : break;
455 46398 : case cmd_setValue: {
456 46398 : CHECK_INIT(initialized,words[0]);
457 46398 : plumed_assert(nw==2);
458 46398 : setInputValue( std::string(words[1]), 0, 1, val );
459 : }
460 46398 : break;
461 : /* ADDED WITH API=7 */
462 0 : case cmd_setValueForces: {
463 0 : CHECK_INIT(initialized,words[0]);
464 0 : plumed_assert(nw==2);
465 0 : setInputForce( std::string(words[1]), val );
466 : }
467 0 : break;
468 : // words used less frequently:
469 1194 : case cmd_setAtomsNlocal:
470 1194 : CHECK_INIT(initialized,word);
471 1194 : CHECK_NOTNULL(val,word);
472 4796 : for(const auto & pp : inputs ) {
473 3602 : plumed_assert(pp);
474 3602 : DomainDecomposition* dd=pp->castToDomainDecomposition();
475 3602 : if( dd ) {
476 1194 : dd->setAtomsNlocal(val.get<int>());
477 : }
478 : }
479 : break;
480 1040 : case cmd_setAtomsGatindex:
481 1040 : CHECK_INIT(initialized,word);
482 4182 : for(const auto & pp : inputs ) {
483 3142 : plumed_assert(pp);
484 3142 : DomainDecomposition* dd=pp->castToDomainDecomposition();
485 3142 : if( dd ) {
486 1040 : dd->setAtomsGatindex(val,false);
487 : }
488 : }
489 : break;
490 2 : case cmd_setAtomsFGatindex:
491 2 : CHECK_INIT(initialized,word);
492 6 : for(const auto & pp : inputs ) {
493 4 : plumed_assert(pp);
494 4 : DomainDecomposition* dd=pp->castToDomainDecomposition();
495 4 : if( dd ) {
496 2 : dd->setAtomsGatindex(val,true);
497 : }
498 : }
499 : break;
500 152 : case cmd_setAtomsContiguous:
501 152 : CHECK_INIT(initialized,word);
502 152 : CHECK_NOTNULL(val,word);
503 608 : for(const auto & pp : inputs ) {
504 456 : plumed_assert(pp);
505 456 : DomainDecomposition* dd=pp->castToDomainDecomposition();
506 456 : if( dd ) {
507 152 : dd->setAtomsContiguous(val.get<int>());
508 : }
509 : }
510 : break;
511 116 : case cmd_createFullList:
512 116 : CHECK_INIT(initialized,word);
513 116 : CHECK_NOTNULL(val,word);
514 553 : for(const auto & pp : inputs ) {
515 437 : plumed_assert(pp);
516 437 : DomainDecomposition* dd=pp->castToDomainDecomposition();
517 437 : if( dd ) {
518 116 : dd->createFullList(val);
519 : }
520 : }
521 : break;
522 116 : case cmd_getFullList: {
523 116 : CHECK_INIT(initialized,word);
524 116 : CHECK_NOTNULL(val,word);
525 : unsigned nlists=0;
526 553 : for(const auto & pp : inputs ) {
527 437 : plumed_assert(pp);
528 437 : DomainDecomposition* dd=pp->castToDomainDecomposition();
529 437 : if( dd ) {
530 116 : dd->getFullList(val);
531 116 : nlists++;
532 : }
533 : }
534 116 : plumed_assert( nlists==1 );
535 : }
536 : break;
537 116 : case cmd_clearFullList:
538 116 : CHECK_INIT(initialized,word);
539 553 : for(const auto & pp : inputs ) {
540 437 : plumed_assert(pp);
541 437 : DomainDecomposition* dd=pp->castToDomainDecomposition();
542 437 : if( dd ) {
543 116 : dd->clearFullList();
544 : }
545 : }
546 : break;
547 : /* ADDED WITH API==6 */
548 121 : case cmd_getDataRank: {
549 121 : CHECK_INIT(initialized,words[0]);
550 121 : plumed_assert(nw==2 || nw==3);
551 121 : std::string vtype="";
552 121 : if( nw==3 ) {
553 0 : vtype=" TYPE="+std::string(words[2]);
554 : }
555 363 : readInputLine( "grab_" + std::string(words[1]) + ": GET ARG=" + std::string(words[1]) + vtype );
556 242 : ActionToGetData* as=actionSet.selectWithLabel<ActionToGetData*>("grab_"+std::string(words[1]));
557 121 : plumed_assert( as );
558 121 : as->get_rank( val );
559 : }
560 121 : break;
561 : /* ADDED WITH API==6 */
562 57 : case cmd_getDataShape: {
563 57 : CHECK_INIT(initialized,std::string(words[0]));
564 114 : ActionToGetData* as1=actionSet.selectWithLabel<ActionToGetData*>("grab_"+std::string(words[1]));
565 57 : plumed_assert( as1 );
566 57 : as1->get_shape( val );
567 : }
568 : break;
569 : /* ADDED WITH API==6 */
570 121 : case cmd_setMemoryForData: {
571 121 : CHECK_INIT(initialized,words[0]);
572 121 : plumed_assert(nw==2 || nw==3);
573 242 : ActionToGetData* as2=actionSet.selectWithLabel<ActionToGetData*>("grab_"+std::string(words[1]));
574 121 : plumed_assert( as2 );
575 121 : as2->set_memory( val );
576 : }
577 : break;
578 : /* ADDED WITH API==6 */
579 : case cmd_setErrorHandler: {
580 0 : if(val) {
581 0 : error_handler=*static_cast<const plumed_error_handler*>(val.get<const void*>());
582 : } else {
583 0 : error_handler.handler=NULL;
584 : }
585 : }
586 : break;
587 0 : case cmd_read:
588 0 : CHECK_INIT(initialized,word);
589 0 : if(val) {
590 0 : readInputFile(val.getCString());
591 : } else {
592 0 : readInputFile("plumed.dat");
593 : }
594 : break;
595 1672 : case cmd_readInputLine:
596 1672 : CHECK_INIT(initialized,word);
597 1672 : CHECK_NOTNULL(val,word);
598 1672 : readInputLine(val.getCString());
599 1613 : break;
600 6 : case cmd_readInputLines:
601 6 : CHECK_INIT(initialized,word);
602 6 : CHECK_NOTNULL(val,word);
603 6 : readInputLines(val.getCString());
604 6 : break;
605 3 : case cmd_clear: {
606 3 : CHECK_INIT(initialized,word);
607 : std::vector<int> natoms;
608 7 : for(const auto & pp : inputs ) {
609 4 : plumed_assert(pp);
610 4 : DomainDecomposition* dd=pp->castToDomainDecomposition();
611 4 : if ( dd ) {
612 1 : natoms.push_back( dd->getNumberOfAtoms() );
613 : }
614 : }
615 3 : actionSet.clearDelete();
616 : inputs.clear();
617 4 : for(unsigned i=0; i<natoms.size(); ++i) {
618 : std::string str_natoms;
619 1 : Tools::convert( natoms[i], str_natoms );
620 3 : readInputLine( MDEngine + ": DOMAIN_DECOMPOSITION NATOMS=" + str_natoms +
621 2 : " VALUE1=posx UNIT1=length PERIODIC1=NO CONSTANT1=False ROLE1=x" +
622 2 : " VALUE2=posy UNIT2=length PERIODIC2=NO CONSTANT2=False ROLE2=y" +
623 2 : " VALUE3=posz UNIT3=length PERIODIC3=NO CONSTANT3=False ROLE3=z" +
624 2 : " VALUE4=Masses UNIT4=mass PERIODIC4=NO CONSTANT4=True ROLE4=m" +
625 : " VALUE5=Charges UNIT5=charge PERIODIC5=NO CONSTANT5=True ROLE5=q");
626 :
627 : }
628 3 : setUnits( passtools->usingNaturalUnits, passtools->units );
629 : }
630 3 : break;
631 : case cmd_getApiVersion:
632 49 : CHECK_NOTNULL(val,word);
633 49 : val.set(int(10));
634 : break;
635 : // commands which can be used only before initialization:
636 1636 : case cmd_init:
637 1636 : CHECK_NOTINIT(initialized,word);
638 1636 : init();
639 : break;
640 1148 : case cmd_setRealPrecision:
641 1148 : CHECK_NOTINIT(initialized,word);
642 1148 : CHECK_NOTNULL(val,word);
643 2295 : passtools=DataPassingTools::create(val.get<int>());
644 1147 : passtools->usingNaturalUnits=false;
645 1147 : break;
646 1011 : case cmd_setMDLengthUnits:
647 1011 : CHECK_NOTINIT(initialized,word);
648 1011 : CHECK_NOTNULL(val,word);
649 1011 : passtools->MDUnits.setLength(passtools->MD2double(val));
650 : break;
651 1011 : case cmd_setMDChargeUnits:
652 1011 : CHECK_NOTINIT(initialized,word);
653 1011 : CHECK_NOTNULL(val,word);
654 1011 : passtools->MDUnits.setCharge(passtools->MD2double(val));
655 : break;
656 1011 : case cmd_setMDMassUnits:
657 1011 : CHECK_NOTINIT(initialized,word);
658 1011 : CHECK_NOTNULL(val,word);
659 1011 : passtools->MDUnits.setMass(passtools->MD2double(val));
660 : break;
661 45 : case cmd_setMDEnergyUnits:
662 45 : CHECK_NOTINIT(initialized,word);
663 45 : CHECK_NOTNULL(val,word);
664 45 : passtools->MDUnits.setEnergy(passtools->MD2double(val));
665 : break;
666 6 : case cmd_setMDTimeUnits:
667 6 : CHECK_NOTINIT(initialized,word);
668 6 : CHECK_NOTNULL(val,word);
669 6 : passtools->MDUnits.setTime(passtools->MD2double(val));
670 : break;
671 0 : case cmd_setNaturalUnits:
672 : // set the boltzman constant for MD in natural units (kb=1)
673 : // only needed in LJ codes if the MD is passing temperatures to plumed (so, not yet...)
674 : // use as cmd("setNaturalUnits")
675 0 : CHECK_NOTINIT(initialized,word);
676 0 : passtools->usingNaturalUnits=true;
677 0 : break;
678 69 : case cmd_setNoVirial: {
679 69 : CHECK_NOTINIT(initialized,word);
680 69 : ActionToPutData* ap=actionSet.selectWithLabel<ActionToPutData*>("Box");
681 69 : if( ap ) {
682 53 : ap->noforce=true;
683 : } else {
684 16 : ActionForInterface* af = actionSet.selectWithLabel<ActionForInterface*>(MDEngine);
685 16 : if( af ) {
686 0 : plumed_merror("setNoVirial should be called after number of atoms have been set");
687 : }
688 : }
689 : }
690 : break;
691 1062 : case cmd_setPlumedDat:
692 1062 : CHECK_NOTINIT(initialized,word);
693 1062 : CHECK_NOTNULL(val,word);
694 1062 : plumedDat=val.getCString();
695 : break;
696 522 : case cmd_setMPIComm:
697 522 : CHECK_NOTINIT(initialized,word);
698 522 : comm.Set_comm(val);
699 524 : for(const auto & pp : inputs ) {
700 2 : pp->Set_comm(comm);
701 : }
702 : break;
703 0 : case cmd_setMPIFComm:
704 0 : CHECK_NOTINIT(initialized,word);
705 0 : comm.Set_fcomm(val);
706 0 : for(const auto & pp : inputs ) {
707 0 : pp->Set_comm(comm);
708 : }
709 : break;
710 0 : case cmd_setMPImultiSimComm:
711 0 : CHECK_NOTINIT(initialized,word);
712 0 : multi_sim_comm.Set_comm(val);
713 : break;
714 1618 : case cmd_setNatoms: {
715 1618 : CHECK_NOTINIT(initialized,word);
716 1618 : CHECK_NOTNULL(val,word);
717 1618 : int natoms = val.get<int>();
718 : std::string str_natoms;
719 1608 : Tools::convert( natoms, str_natoms );
720 1608 : ActionForInterface* dd=actionSet.selectWithLabel<ActionForInterface*>(MDEngine);
721 1608 : if( !dd && natoms>0 )
722 4599 : readInputLine( MDEngine + ": DOMAIN_DECOMPOSITION NATOMS=" + str_natoms + +
723 3066 : " VALUE1=posx UNIT1=length PERIODIC1=NO CONSTANT1=False ROLE1=x" +
724 3066 : " VALUE2=posy UNIT2=length PERIODIC2=NO CONSTANT2=False ROLE2=y" +
725 3066 : " VALUE3=posz UNIT3=length PERIODIC3=NO CONSTANT3=False ROLE3=z" +
726 3066 : " VALUE4=Masses UNIT4=mass PERIODIC4=NO CONSTANT4=True ROLE4=m" +
727 3066 : " VALUE5=Charges UNIT5=charge PERIODIC5=NO CONSTANT5=True ROLE5=q", true );
728 : }
729 1608 : break;
730 1362 : case cmd_setTimestep: {
731 1362 : CHECK_NOTINIT(initialized,word);
732 1362 : CHECK_NOTNULL(val,word);
733 1362 : ActionToPutData* ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
734 1362 : if( !ts ) {
735 1360 : readInputLine("timestep: PUT UNIT=time PERIODIC=NO CONSTANT ROUND_TO_BASE_TEN", true);
736 2720 : ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
737 : }
738 2724 : if( !ts->setValuePointer("timestep", val ) ) {
739 0 : plumed_error();
740 : }
741 1362 : ts->updateUnits( passtools.get() );
742 : }
743 : break;
744 : /* ADDED WITH API==2 */
745 220 : case cmd_setKbT: {
746 220 : CHECK_NOTINIT(initialized,word);
747 220 : CHECK_NOTNULL(val,word);
748 220 : readInputLine("kBT: PUT CONSTANT PERIODIC=NO UNIT=energy", true);
749 220 : ActionToPutData* kb = actionSet.selectWithLabel<ActionToPutData*>("kBT");
750 440 : if( !kb->setValuePointer("kBT", val ) ) {
751 0 : plumed_error();
752 : }
753 220 : kb->updateUnits( passtools.get() );
754 : }
755 : break;
756 : /* ADDED WITH API==3 */
757 8 : case cmd_setRestart:
758 8 : CHECK_NOTINIT(initialized,word);
759 8 : CHECK_NOTNULL(val,word);
760 8 : if(val.get<int>()!=0) {
761 2 : restart=true;
762 : }
763 : break;
764 : /* ADDED WITH API==4 */
765 0 : case cmd_doCheckPoint:
766 0 : CHECK_INIT(initialized,word);
767 0 : CHECK_NOTNULL(val,word);
768 0 : doCheckPoint = false;
769 0 : if(val.get<int>()!=0) {
770 0 : doCheckPoint = true;
771 : }
772 : break;
773 : /* ADDED WITH API==6 */
774 : case cmd_setNumOMPthreads:
775 3 : CHECK_NOTNULL(val,word);
776 : {
777 3 : auto nt=val.get<unsigned>();
778 : if(nt==0) {
779 : nt=1;
780 : }
781 3 : OpenMP::setNumThreads(nt);
782 : }
783 : break;
784 : /* ADDED WITH API==10 */
785 : case cmd_setGpuDeviceId:
786 0 : CHECK_NOTNULL(val,word);
787 : {
788 0 : auto id=val.get<int>();
789 0 : if(id>=0) {
790 0 : gpuDeviceId=id;
791 : }
792 : }
793 : break;
794 : /* ADDED WITH API==6 */
795 : /* only used for testing */
796 : case cmd_throw:
797 61 : CHECK_NOTNULL(val,word);
798 61 : testThrow(val.getCString());
799 : /* ADDED WITH API==10 */
800 : case cmd_setNestedExceptions:
801 31 : CHECK_NOTNULL(val,word);
802 31 : if(val.get<int>()!=0) {
803 30 : nestedExceptions=true;
804 : } else {
805 1 : nestedExceptions=false;
806 : }
807 : break;
808 : /* STOP API */
809 1083 : case cmd_setMDEngine:
810 1083 : CHECK_NOTINIT(initialized,word);
811 1083 : CHECK_NOTNULL(val,word);
812 1083 : MDEngine=val.getCString();
813 : break;
814 1051 : case cmd_setLog:
815 1051 : CHECK_NOTINIT(initialized,word);
816 1051 : log.link(val.get<FILE*>());
817 : break;
818 290 : case cmd_setLogFile:
819 290 : CHECK_NOTINIT(initialized,word);
820 290 : CHECK_NOTNULL(val,word);
821 290 : log.open(val.getCString());
822 290 : break;
823 : // other commands that should be used after initialization:
824 269225 : case cmd_setStopFlag:
825 269225 : CHECK_INIT(initialized,word);
826 269225 : CHECK_NOTNULL(val,word);
827 269225 : val.get<int*>(); // just check type and discard pointer
828 269224 : stopFlag=val.copy();
829 269224 : break;
830 0 : case cmd_getExchangesFlag:
831 0 : CHECK_INIT(initialized,word);
832 0 : CHECK_NOTNULL(val,word);
833 0 : exchangePatterns.getFlag(*val.get<int*>()); // note: getFlag changes the value of the reference!
834 : break;
835 0 : case cmd_setExchangesSeed:
836 0 : CHECK_INIT(initialized,word);
837 0 : CHECK_NOTNULL(val,word);
838 0 : exchangePatterns.setSeed(val.get<int>());
839 : break;
840 0 : case cmd_setNumberOfReplicas:
841 0 : CHECK_INIT(initialized,word);
842 0 : CHECK_NOTNULL(val,word);
843 0 : exchangePatterns.setNofR(val.get<int>());
844 : break;
845 0 : case cmd_getExchangesList:
846 0 : CHECK_INIT(initialized,word);
847 0 : CHECK_NOTNULL(val,word);
848 0 : exchangePatterns.getList(val);
849 : break;
850 1002 : case cmd_runFinalJobs:
851 1002 : CHECK_INIT(initialized,word);
852 1002 : runJobsAtEndOfCalculation();
853 : break;
854 96 : case cmd_isEnergyNeeded: {
855 96 : CHECK_INIT(initialized,word);
856 96 : CHECK_NOTNULL(val,word);
857 96 : if( name_of_energy =="" ) {
858 96 : val.set(int(0));
859 : } else {
860 0 : ActionToPutData* ap=actionSet.selectWithLabel<ActionToPutData*>(name_of_energy);
861 0 : if(ap->isActive()) {
862 0 : val.set(int(1));
863 : } else {
864 0 : val.set(int(0));
865 : }
866 : }
867 : }
868 : break;
869 72062 : case cmd_getBias:
870 72062 : CHECK_INIT(initialized,word);
871 72062 : CHECK_NOTNULL(val,word);
872 72062 : plumedQuantityToMD( "energy", getBias(), val );
873 72062 : break;
874 : case cmd_checkAction:
875 2 : CHECK_NOTNULL(val,word);
876 2 : plumed_assert(nw==2);
877 3 : val.set(int(actionRegister().check(dlloader.getHandles(), std::string(words[1])) ? 1:0));
878 2 : break;
879 : case cmd_setExtraCV: {
880 30 : CHECK_NOTNULL(val,word);
881 30 : plumed_assert(nw==2);
882 60 : if( valueExists(std::string(words[1])) ) {
883 60 : setInputValue( std::string(words[1]), 0, 1, val );
884 : }
885 : }
886 : break;
887 : case cmd_setExtraCVForce: {
888 30 : CHECK_NOTNULL(val,word);
889 30 : plumed_assert(nw==2);
890 60 : if( valueExists(std::string(words[1])) ) {
891 60 : setInputForce( std::string(words[1]), val );
892 : }
893 : }
894 : break;
895 : /* ADDED WITH API==10 */
896 : case cmd_isExtraCVNeeded:
897 10 : CHECK_NOTNULL(val,word);
898 10 : plumed_assert(nw==2);
899 10 : val.set(int(0));
900 56 : for(const auto & p : inputs) {
901 50 : if( p->getLabel()==words[1] && p->isActive() ) {
902 4 : val.set(int(1));
903 : break;
904 : }
905 : }
906 : break;
907 1445 : case cmd_GREX:
908 1445 : if(!grex) {
909 350 : grex=Tools::make_unique<GREX>(*this);
910 : }
911 1445 : plumed_massert(grex,"error allocating grex");
912 : {
913 1445 : std::string kk=std::string(words[1]);
914 1616 : for(unsigned i=2; i<words.size(); i++) {
915 342 : kk+=" "+std::string(words[i]);
916 : }
917 1445 : grex->cmd(kk.c_str(),val);
918 : }
919 1445 : break;
920 18790 : case cmd_CLTool:
921 18790 : CHECK_NOTINIT(initialized,word);
922 18790 : if(!cltool) {
923 6160 : cltool=Tools::make_unique<CLToolMain>();
924 : }
925 : {
926 18790 : std::string kk(words[1]);
927 18790 : for(unsigned i=2; i<words.size(); i++) {
928 0 : kk+=" "+std::string(words[i]);
929 : }
930 18790 : cltool->cmd(kk.c_str(),val);
931 : }
932 18790 : break;
933 : break;
934 : /* ADDED WITH API==7 */
935 : case cmd_convert: {
936 : double v;
937 57 : plumed_assert(words.size()==2);
938 297 : if(Tools::convertNoexcept(std::string(words[1]),v)) {
939 47 : passtools->double2MD(v,val);
940 : }
941 : }
942 57 : break;
943 7 : default:
944 14 : plumed_error() << "cannot interpret cmd(\"" << word << "\"). check plumed developers manual to see the available commands.";
945 : break;
946 : }
947 : }
948 :
949 1931962 : } catch (...) {
950 183 : if(log.isOpen()) {
951 : try {
952 109 : log<<"\n################################################################################\n";
953 109 : log<<Tools::concatenateExceptionMessages();
954 109 : log<<"\n################################################################################\n";
955 109 : log.flush();
956 0 : } catch(...) {
957 : // ignore errors here.
958 : // in any case, we are rethrowing this below
959 0 : }
960 : }
961 183 : throw;
962 183 : }
963 1931596 : }
964 :
965 : ////////////////////////////////////////////////////////////////////////
966 :
967 1636 : void PlumedMain::init() {
968 : // check that initialization just happens once
969 1636 : initialized=true;
970 1636 : if(!log.isOpen()) {
971 295 : log.link(stdout);
972 : }
973 1636 : log<<"PLUMED is starting\n";
974 4908 : log<<"Version: "<<config::getVersionLong()<<" (git: "<<config::getVersionGit()<<") "
975 6544 : <<"compiled on " <<config::getCompilationDate() << " at " << config::getCompilationTime() << "\n";
976 1636 : log<<"Please cite these papers when using PLUMED ";
977 3272 : log<<cite("The PLUMED consortium, Nat. Methods 16, 670 (2019)");
978 3272 : log<<cite("Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014)");
979 1636 : log<<"\n";
980 1636 : log<<"For further information see the PLUMED web page at http://www.plumed.org\n";
981 1636 : log<<"Root: "<<config::getPlumedRoot()<<"\n";
982 1636 : log<<"LibraryPath: "<<config::getLibraryPath()<<"\n";
983 3272 : log<<"For installed feature, see "<<config::getPlumedRoot() + "/src/config/config.txt\n";
984 1636 : log.printf("Molecular dynamics engine: %s\n",MDEngine.c_str());
985 1636 : log.printf("Precision of reals: %d\n",passtools->getRealPrecision());
986 2868 : log.printf("Running over %d %s\n",comm.Get_size(),(comm.Get_size()>1?"nodes":"node"));
987 1636 : log<<"Number of threads: "<<OpenMP::getNumThreads()<<"\n";
988 1636 : log<<"Cache line size: "<<OpenMP::getCachelineSize()<<"\n";
989 6312 : for(const auto & pp : inputs ) {
990 4676 : plumed_assert(pp);
991 4676 : DomainDecomposition* dd=pp->castToDomainDecomposition();
992 4676 : if ( dd ) {
993 1532 : log.printf("Number of atoms: %d\n",dd->getNumberOfAtoms());
994 : }
995 : }
996 1636 : if(grex) {
997 350 : log.printf("GROMACS-like replica exchange is on\n");
998 : }
999 1636 : log.printf("File suffix: %s\n",getSuffix().c_str());
1000 1636 : if(plumedDat.length()>0) {
1001 1062 : readInputFile(plumedDat);
1002 : plumedDat="";
1003 : }
1004 1636 : setUnits( passtools->usingNaturalUnits, passtools->units );
1005 1636 : ActionToPutData* ts = actionSet.selectWithLabel<ActionToPutData*>("timestep");
1006 1636 : if(ts) {
1007 1360 : log.printf("Timestep: %f\n",(ts->copyOutput(0))->get());
1008 : }
1009 1636 : ActionToPutData* kb = actionSet.selectWithLabel<ActionToPutData*>("kBT");
1010 1636 : if(kb) {
1011 220 : log.printf("KbT: %f\n",(kb->copyOutput(0))->get());
1012 : } else {
1013 1416 : log.printf("KbT has not been set by the MD engine\n");
1014 1416 : log.printf("It should be set by hand where needed\n");
1015 : }
1016 1636 : log<<"Relevant bibliography:\n";
1017 1636 : log<<citations;
1018 1636 : log<<"Please read and cite where appropriate!\n";
1019 1636 : log<<"Finished setup\n";
1020 1636 : }
1021 :
1022 56497 : void PlumedMain::setupInterfaceActions() {
1023 56497 : inputs.clear();
1024 56497 : std::vector<ActionForInterface*> ap=actionSet.select<ActionForInterface*>();
1025 453199 : for(unsigned i=0; i<ap.size(); ++i) {
1026 396702 : if( ap[i]->getName()=="ENERGY" || ap[i]->getDependencies().size()==0 ) {
1027 151497 : inputs.push_back( ap[i] );
1028 : }
1029 : }
1030 56497 : }
1031 :
1032 1085 : void PlumedMain::readInputFile(const std::string & str) {
1033 1085 : plumed_assert(initialized);
1034 1085 : log<<"FILE: "<<str<<"\n";
1035 1085 : IFile ifile;
1036 1085 : ifile.link(*this);
1037 1085 : ifile.open(str);
1038 1085 : ifile.allowNoEOL();
1039 1085 : readInputFile(ifile);
1040 1085 : log<<"END FILE: "<<str<<"\n";
1041 1085 : log.flush();
1042 :
1043 1085 : }
1044 :
1045 1091 : void PlumedMain::readInputFile(IFile & ifile) {
1046 : std::vector<std::string> words;
1047 19932 : while(Tools::getParsedLine(ifile,words) && !endPlumed) {
1048 18841 : readInputWords(words,false);
1049 : }
1050 1091 : endPlumed=false;
1051 1091 : pilots=actionSet.select<ActionPilot*>();
1052 1091 : setupInterfaceActions();
1053 1091 : }
1054 :
1055 14191 : void PlumedMain::readInputLine(const std::string & str, const bool& before_init) {
1056 14191 : if( !before_init ) {
1057 1842 : plumed_assert(initialized);
1058 : }
1059 14191 : if(str.empty()) {
1060 0 : return;
1061 : }
1062 14191 : std::vector<std::string> words=Tools::getWords(str);
1063 14191 : if( before_init ) {
1064 12349 : plumed_assert( citations.empty() );
1065 : }
1066 14191 : citations.clear();
1067 14191 : readInputWords(words,before_init);
1068 14134 : if(!citations.empty()) {
1069 27 : log<<"Relevant bibliography:\n";
1070 27 : log<<citations;
1071 27 : log<<"Please read and cite where appropriate!\n";
1072 : }
1073 14191 : }
1074 :
1075 6 : void PlumedMain::readInputLines(const std::string & str) {
1076 6 : plumed_assert(initialized);
1077 6 : if(str.empty()) {
1078 0 : return;
1079 : }
1080 :
1081 6 : log<<"FILE: (temporary)\n";
1082 :
1083 : // Open a temporary file
1084 6 : auto fp=std::tmpfile();
1085 6 : plumed_assert(fp);
1086 :
1087 : // make sure file is closed (and thus deleted) also if an exception occurs
1088 : auto deleter=[](auto fp) {
1089 6 : std::fclose(fp);
1090 : };
1091 : std::unique_ptr<FILE,decltype(deleter)> fp_deleter(fp,deleter);
1092 :
1093 6 : auto ret=std::fputs(str.c_str(),fp);
1094 6 : plumed_assert(ret!=EOF);
1095 :
1096 6 : std::rewind(fp);
1097 :
1098 6 : IFile ifile;
1099 6 : ifile.link(*this);
1100 6 : ifile.link(fp);
1101 6 : ifile.allowNoEOL();
1102 :
1103 6 : readInputFile(ifile);
1104 6 : log<<"END FILE: (temporary)\n";
1105 6 : }
1106 :
1107 55650 : void PlumedMain::readInputWords(const std::vector<std::string> & words, const bool& before_init) {
1108 55650 : if( !before_init ) {
1109 43301 : plumed_assert(initialized);
1110 : }
1111 55650 : if(words.empty()) {
1112 : return;
1113 55478 : } else if(words[0]=="_SET_SUFFIX") {
1114 3 : plumed_assert(words.size()==2);
1115 : setSuffix(words[1]);
1116 : } else {
1117 55475 : std::vector<std::string> interpreted(words);
1118 55475 : Tools::interpretLabel(interpreted);
1119 110878 : auto action=actionRegister().create(dlloader.getHandles(),ActionOptions(*this,interpreted));
1120 55403 : if(!action) {
1121 : std::string msg;
1122 : msg ="ERROR\nI cannot understand line:";
1123 0 : for(unsigned i=0; i<interpreted.size(); ++i) {
1124 0 : msg+=" "+interpreted[i];
1125 : }
1126 : msg+="\nMaybe a missing space or a typo?";
1127 0 : log << msg;
1128 0 : log.flush();
1129 0 : plumed_merror(msg);
1130 : }
1131 55403 : action->checkRead();
1132 55403 : actionSet.emplace_back(std::move(action));
1133 55475 : };
1134 :
1135 55406 : pilots=actionSet.select<ActionPilot*>();
1136 55406 : setupInterfaceActions();
1137 : }
1138 :
1139 : ////////////////////////////////////////////////////////////////////////
1140 :
1141 0 : void PlumedMain::exit(int c) {
1142 0 : comm.Abort(c);
1143 0 : }
1144 :
1145 55473 : Log& PlumedMain::getLog() {
1146 55473 : return log;
1147 : }
1148 :
1149 357689 : void PlumedMain::calc() {
1150 357689 : prepareCalc();
1151 357673 : performCalc();
1152 357671 : }
1153 :
1154 364674 : void PlumedMain::prepareCalc() {
1155 364674 : prepareDependencies();
1156 364674 : shareData();
1157 364658 : }
1158 :
1159 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1160 : // here we have the main steps in "calc()"
1161 : // they can be called individually, but the standard thing is to
1162 : // traverse them in this order:
1163 365001 : void PlumedMain::prepareDependencies() {
1164 :
1165 : // Stopwatch is stopped when sw goes out of scope
1166 365001 : auto sw=stopwatch.startStop("1 Prepare dependencies");
1167 :
1168 : // activate all the actions which are on step
1169 : // activation is recursive and enables also the dependencies
1170 : // before doing that, the prepare() method is called to see if there is some
1171 : // new/changed dependency (up to now, only useful for dependences on virtual atoms,
1172 : // which can be dynamically changed).
1173 :
1174 : // First switch off all actions
1175 5754068 : for(const auto & p : actionSet) {
1176 5389067 : p->deactivate();
1177 : }
1178 :
1179 : // for optimization, an "active" flag remains false if no action at all is active
1180 365001 : active=false;
1181 1889631 : for(unsigned i=0; i<pilots.size(); ++i) {
1182 1524630 : if(pilots[i]->onStep()) {
1183 1429488 : pilots[i]->activate();
1184 1429488 : active=true;
1185 : }
1186 : };
1187 :
1188 : // This stops the driver calculation if there is not a read action
1189 365001 : if( !active && !inputsAreActive() ) {
1190 2 : stopFlag.set(int(1));
1191 : }
1192 :
1193 : // also, if one of them is the total energy, tell to atoms that energy should be collected
1194 5754068 : for(const auto & p : actionSet) {
1195 5389067 : if(p->isActive()) {
1196 3361967 : if(p->checkNeedsGradients()) {
1197 172 : p->setOption("GRADIENTS");
1198 : }
1199 : }
1200 : }
1201 :
1202 365001 : }
1203 :
1204 1808 : bool PlumedMain::inputsAreActive() const {
1205 5268 : for(const auto & ip : inputs) {
1206 5212 : if( ip->onStep() ) {
1207 : return true;
1208 : }
1209 : }
1210 : return false;
1211 : }
1212 :
1213 114 : void PlumedMain::shareAll() {
1214 456 : for(const auto & ip : inputs) {
1215 342 : ip->shareAll();
1216 : }
1217 114 : }
1218 :
1219 364758 : void PlumedMain::shareData() {
1220 : // atom positions are shared (but only if there is something to do)
1221 364758 : if(!active) {
1222 1748 : return;
1223 : }
1224 : // Stopwatch is stopped when sw goes out of scope
1225 363010 : auto sw=stopwatch.startStop("2 Sharing data");
1226 1127440 : for(const auto & ip : inputs) {
1227 764446 : ip->share();
1228 : }
1229 363010 : }
1230 :
1231 7045 : void PlumedMain::performCalcNoUpdate() {
1232 7045 : waitData();
1233 7045 : justCalculate();
1234 7045 : backwardPropagate();
1235 7045 : resetInputs();
1236 7045 : }
1237 :
1238 10 : void PlumedMain::performCalcNoForces() {
1239 10 : waitData();
1240 10 : justCalculate();
1241 10 : }
1242 :
1243 357683 : void PlumedMain::performCalc() {
1244 357683 : waitData();
1245 357683 : justCalculate();
1246 357683 : backwardPropagate();
1247 357681 : update();
1248 357681 : resetInputs();
1249 357681 : }
1250 :
1251 364852 : void PlumedMain::waitData() {
1252 364852 : if(!active) {
1253 1748 : return;
1254 : }
1255 : // Stopwatch is stopped when sw goes out of scope
1256 363104 : auto sw=stopwatch.startStop("3 Waiting for data");
1257 1127852 : for(const auto & ip : inputs) {
1258 : // shareData also starts the first-step domain exchange for inactive
1259 : // inputs, to initialize fixed masses and charges. Complete that exchange
1260 : // before clearing firststep, or later atomic actions receive stale data.
1261 764748 : if( (ip->isActive() || ip->firststep) && ip->hasBeenSet() ) {
1262 325311 : ip->wait();
1263 439437 : } else if( ip->isActive() ) {
1264 8084 : ip->warning("input requested but this quantity has not been set");
1265 : }
1266 : }
1267 363104 : }
1268 :
1269 364852 : void PlumedMain::justCalculate() {
1270 364852 : if(!active) {
1271 1748 : return;
1272 : }
1273 : // Stopwatch is stopped when sw goes out of scope
1274 363104 : auto sw=stopwatch.startStop("4 Calculating (forward loop)");
1275 363104 : bias=0.0;
1276 363104 : work=0.0;
1277 :
1278 : // Check the input actions to determine if we need to calculate constants that
1279 : // depend on masses and charges
1280 : bool firststep=false;
1281 1127852 : for(const auto & ip : inputs) {
1282 764748 : if( ip->firststep ) {
1283 : firststep=true;
1284 : }
1285 : }
1286 363104 : if( firststep ) {
1287 5938 : for(const auto & ip : inputs) {
1288 4450 : ip->firststep=false;
1289 : }
1290 : }
1291 :
1292 : int iaction=0;
1293 : // calculate the active actions in order (assuming *backward* dependence)
1294 5720633 : for(const auto & pp : actionSet) {
1295 : Action* p(pp.get());
1296 5357529 : plumed_assert(p);
1297 : try {
1298 5357529 : if(p->isActive()) {
1299 : // Stopwatch is stopped when sw goes out of scope.
1300 : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
1301 3359972 : Stopwatch::Handler sw;
1302 3359972 : if(detailedTimers) {
1303 2481 : auto actionNumberLabel=std::to_string(iaction);
1304 2481 : const unsigned m=actionSet.size();
1305 : unsigned k=0;
1306 : unsigned n=1;
1307 7443 : while(n<m) {
1308 4962 : n*=10;
1309 4962 : k++;
1310 : }
1311 2481 : auto spaces=std::string(k-actionNumberLabel.length(),' ');
1312 2481 : sw=stopwatch.startStop("4A " + spaces + actionNumberLabel+" "+p->getLabel());
1313 : }
1314 3359972 : ActionWithValue*av=p->castToActionWithValue();
1315 3359972 : ActionAtomistic*aa=p->castToActionAtomistic();
1316 : {
1317 3359972 : if(av) {
1318 3063973 : av->clearInputForces();
1319 : }
1320 3359972 : if(av) {
1321 3063973 : av->clearDerivatives();
1322 : }
1323 3359972 : if( av && av->calculateOnUpdate() ) {
1324 : continue ;
1325 : }
1326 : }
1327 : {
1328 3355957 : if(aa)
1329 630092 : if(aa->isActive()) {
1330 630092 : aa->retrieveAtoms();
1331 : }
1332 : }
1333 3355957 : if(p->checkNumericalDerivatives()) {
1334 246 : p->calculateNumericalDerivatives();
1335 : } else {
1336 3355711 : p->calculate();
1337 : }
1338 : // This retrieves components called bias
1339 3355957 : if(av) {
1340 3059958 : bias+=av->getOutputQuantity("bias");
1341 3059958 : work+=av->getOutputQuantity("work");
1342 3059958 : av->setGradientsIfNeeded();
1343 : }
1344 : // This makes all values that depend on the (fixed) masses and charges constant
1345 3355957 : if( firststep ) {
1346 31263 : p->setupConstantValues( true );
1347 : }
1348 3355957 : ActionWithVirtualAtom*avv=p->castToActionWithVirtualAtom();
1349 3355957 : if(avv) {
1350 35094 : avv->setGradientsIfNeeded();
1351 : }
1352 3359972 : }
1353 0 : } catch(...) {
1354 0 : plumed_error_nested() << "An error happened while calculating " << p->getLabel();
1355 0 : }
1356 5353514 : iaction++;
1357 : }
1358 363104 : }
1359 :
1360 0 : void PlumedMain::justApply() {
1361 0 : backwardPropagate();
1362 0 : update();
1363 0 : resetInputs();
1364 0 : }
1365 :
1366 364728 : void PlumedMain::backwardPropagate() {
1367 364728 : if(!active) {
1368 1748 : return;
1369 : }
1370 : int iaction=0;
1371 : // Stopwatch is stopped when sw goes out of scope
1372 362980 : auto sw=stopwatch.startStop("5 Applying (backward loop)");
1373 : // apply them in reverse order
1374 5718167 : for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) {
1375 : const auto & p(pp->get());
1376 5355189 : if(p->isActive()) {
1377 :
1378 : // Stopwatch is stopped when sw goes out of scope.
1379 : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
1380 3358296 : Stopwatch::Handler sw;
1381 3358296 : if(detailedTimers) {
1382 2481 : auto actionNumberLabel=std::to_string(iaction);
1383 2481 : const unsigned m=actionSet.size();
1384 : unsigned k=0;
1385 : unsigned n=1;
1386 7443 : while(n<m) {
1387 4962 : n*=10;
1388 4962 : k++;
1389 : }
1390 2481 : auto spaces=std::string(k-actionNumberLabel.length(),' ');
1391 2481 : sw=stopwatch.startStop("5A " + spaces + actionNumberLabel+" "+p->getLabel());
1392 : }
1393 :
1394 3358296 : p->apply();
1395 3358296 : }
1396 5355187 : iaction++;
1397 : }
1398 :
1399 : // Stopwatch is stopped when sw goes out of scope.
1400 : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
1401 362978 : Stopwatch::Handler sw1;
1402 362978 : if(detailedTimers) {
1403 113 : sw1=stopwatch.startStop("5B Update forces");
1404 : }
1405 362980 : }
1406 :
1407 357760 : void PlumedMain::update() {
1408 357760 : if(!active) {
1409 1748 : return;
1410 : }
1411 :
1412 : // Stopwatch is stopped when sw goes out of scope
1413 356012 : auto sw=stopwatch.startStop("6 Update");
1414 :
1415 : // update step (for statistics, etc)
1416 356012 : updateFlags.push(true);
1417 5493490 : for(const auto & p : actionSet) {
1418 5137478 : p->beforeUpdate();
1419 8400451 : if(p->isActive() && p->checkUpdate() && updateFlagsTop()) {
1420 3262953 : ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
1421 3262953 : if( av && av->calculateOnUpdate() ) {
1422 4015 : p->prepare();
1423 4015 : p->calculate();
1424 : } else {
1425 3258938 : p->update();
1426 : }
1427 : }
1428 : }
1429 712028 : while(!updateFlags.empty()) {
1430 : updateFlags.pop();
1431 : }
1432 : if(!updateFlags.empty()) {
1433 : plumed_merror("non matching changes in the update flags");
1434 : }
1435 : // Check that no action has told the calculation to stop
1436 356012 : if(stopNow) {
1437 65 : if(stopFlag) {
1438 65 : stopFlag.set(int(1));
1439 : } else {
1440 0 : plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)");
1441 : }
1442 : }
1443 :
1444 : // flush by default every 10000 steps
1445 : // hopefully will not affect performance
1446 : // also if receive checkpointing signal
1447 356012 : if(step%10000==0||doCheckPoint) {
1448 2290 : fflush();
1449 2290 : log.flush();
1450 69963 : for(const auto & p : actionSet) {
1451 67673 : p->fflush();
1452 : }
1453 : }
1454 : // invalidate the checkpoint status
1455 : // this fix issues like #1428
1456 356012 : doCheckPoint = false;
1457 356012 : }
1458 :
1459 45 : void PlumedMain::load(const std::string& fileName) {
1460 45 : if(DLLoader::installed()) {
1461 45 : std::string libName=fileName;
1462 45 : size_t n=libName.find_last_of(".");
1463 46 : std::string extension="";
1464 45 : std::string base=libName;
1465 45 : if(n!=std::string::npos && n<libName.length()-1) {
1466 90 : extension=libName.substr(n+1);
1467 : }
1468 45 : if(n!=std::string::npos && n<libName.length()) {
1469 90 : base=libName.substr(0,n);
1470 : }
1471 :
1472 45 : if(extension=="cpp") {
1473 50 : libName="./"+base+"."+config::getVersionLong()+"."+config::getSoExt();
1474 : // full path command, including environment setup
1475 : // this will work even if plumed is not in the execution path or if it has been
1476 : // installed with a name different from "plumed"
1477 50 : std::string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh -n -o "+libName+" "+fileName;
1478 :
1479 25 : if(std::getenv("PLUMED_LOAD_ACTION_DEBUG")) {
1480 0 : log<<"Executing: "<<cmd;
1481 : } else {
1482 25 : log<<"Compiling: "<<fileName<<" to "<<libName;
1483 : }
1484 :
1485 25 : if(comm.Get_size()>0) {
1486 25 : log<<" (only on master node)";
1487 : }
1488 25 : log<<"\n";
1489 :
1490 : // On MPI process (intracomm), we use Get_rank to make sure a single process does the compilation
1491 : // Processes from multiple replicas might simultaneously do the compilation.
1492 25 : if(comm.Get_rank()==0) {
1493 25 : static Tools::CriticalSectionWithKey<std::string> section;
1494 : // This is only locking commands that are running with identical arguments.
1495 : // It is not necessary for correctness (a second mklib would just result in a no op since
1496 : // the library is already there, even if running simultaneously).
1497 : // It however decreases the system load if many threads are used.
1498 : auto s=section.startStop(cmd);
1499 25 : int ret=std::system(cmd.c_str());
1500 25 : if(ret!=0) {
1501 2 : plumed_error() <<"An error happened while executing command "<<cmd<<"\n";
1502 : }
1503 25 : }
1504 24 : comm.Barrier();
1505 : } else {
1506 40 : libName=base+"."+config::getSoExt();
1507 : }
1508 :
1509 : // If we have multiple threads (each holding a Plumed object), each of them
1510 : // will load the library, but each of them will only see actions registered
1511 : // from the owned library
1512 44 : auto *p=dlloader.load(libName);
1513 45 : log<<"Loading shared library "<<libName.c_str()<<" at "<<p<<"\n";
1514 44 : log<<"Here is the list of new actions\n";
1515 44 : log<<"\n";
1516 88 : for(const auto & a : actionRegister().getKeysWithDLHandle(p)) {
1517 44 : log<<a<<"\n";
1518 44 : }
1519 44 : log<<"\n";
1520 : } else {
1521 0 : plumed_error()<<"While loading library "<< fileName << " loading was not enabled, please check if dlopen was found at configure time";
1522 : }
1523 44 : }
1524 :
1525 364726 : void PlumedMain::resetInputs() {
1526 1134413 : for(const auto & ip : inputs) {
1527 769687 : if( ip->isActive() && ip->hasBeenSet() ) {
1528 323465 : ip->reset();
1529 : }
1530 : }
1531 364726 : }
1532 :
1533 72695 : double PlumedMain::getBias() const {
1534 72695 : return bias;
1535 : }
1536 :
1537 450 : double PlumedMain::getWork() const {
1538 450 : return work;
1539 : }
1540 :
1541 82 : FILE* PlumedMain::fopen(const char *path, const char *mode) {
1542 82 : std::string mmode(mode);
1543 83 : std::string ppath(path);
1544 82 : std::string suffix(getSuffix());
1545 82 : std::string ppathsuf=ppath+suffix;
1546 82 : FILE*fp=std::fopen(const_cast<char*>(ppathsuf.c_str()),const_cast<char*>(mmode.c_str()));
1547 82 : if(!fp) {
1548 1 : fp=std::fopen(const_cast<char*>(ppath.c_str()),const_cast<char*>(mmode.c_str()));
1549 : }
1550 84 : plumed_massert(fp,"file " + ppath + " cannot be found");
1551 81 : return fp;
1552 : }
1553 :
1554 99 : int PlumedMain::fclose(FILE*fp) {
1555 99 : return std::fclose(fp);
1556 : }
1557 :
1558 5553 : std::string PlumedMain::cite(const std::string&item) {
1559 5553 : return citations.cite(item);
1560 : }
1561 :
1562 2851 : void PlumedMain::fflush() {
1563 6485 : for(const auto & p : files) {
1564 3634 : p->flush();
1565 : }
1566 2851 : }
1567 :
1568 5309 : void PlumedMain::insertFile(FileBase&f) {
1569 5309 : files.insert(&f);
1570 5309 : }
1571 :
1572 5620 : void PlumedMain::eraseFile(FileBase&f) {
1573 5620 : files.erase(&f);
1574 5620 : }
1575 :
1576 65 : void PlumedMain::stop() {
1577 65 : stopNow=true;
1578 65 : }
1579 :
1580 1002 : void PlumedMain::runJobsAtEndOfCalculation() {
1581 48249 : for(const auto & p : actionSet) {
1582 47247 : ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
1583 47247 : if( av && av->calculateOnUpdate() ) {
1584 422 : p->activate();
1585 : }
1586 : }
1587 48249 : for(const auto & p : actionSet) {
1588 47247 : ActionPilot* ap=dynamic_cast<ActionPilot*>(p.get());
1589 47247 : ActionWithValue* av=dynamic_cast<ActionWithValue*>(p.get());
1590 47247 : if( av && av->calculateOnUpdate() ) {
1591 422 : p->calculate();
1592 46825 : } else if( ap && !av && ap->getStride()==0 ) {
1593 78 : p->update();
1594 : } else {
1595 46747 : p->runFinalJobs();
1596 : }
1597 : }
1598 1002 : }
1599 :
1600 8808517 : unsigned PlumedMain::increaseReferenceCounter() noexcept {
1601 8808517 : return ++referenceCounter;
1602 : }
1603 :
1604 8807376 : unsigned PlumedMain::decreaseReferenceCounter() noexcept {
1605 8807376 : return --referenceCounter;
1606 : }
1607 :
1608 42 : unsigned PlumedMain::useCountReferenceCounter() const noexcept {
1609 42 : return referenceCounter;
1610 : }
1611 :
1612 60 : bool PlumedMain::valueExists( const std::string& name ) const {
1613 240 : for(const auto & p : inputs) {
1614 240 : if( p->getLabel()==name ) {
1615 : return true;
1616 : }
1617 : }
1618 : return false;
1619 : }
1620 :
1621 818403 : void PlumedMain::setInputValue( const std::string& name, const unsigned& start, const unsigned& stride, const TypesafePtr & val ) {
1622 : bool found=false;
1623 1894997 : for(const auto & pp : inputs) {
1624 1894997 : if( pp->setValuePointer( name, val ) ) {
1625 818399 : pp->setStart(name, start);
1626 818399 : pp->setStride(name, stride);
1627 : found=true;
1628 : break;
1629 : }
1630 : }
1631 0 : plumed_massert( found, "found no action to set named " + name );
1632 818399 : }
1633 :
1634 555645 : void PlumedMain::setInputForce( const std::string& name, const TypesafePtr & val ) {
1635 : bool found=false;
1636 1249069 : for(const auto & pp : inputs) {
1637 1249069 : if( pp->setForcePointer( name, val ) ) {
1638 : found=true;
1639 : break;
1640 : }
1641 : }
1642 555627 : plumed_massert( found, "found no action to set named " + name );
1643 555627 : }
1644 :
1645 1674 : void PlumedMain::setUnits( const bool& natural, const Units& u ) {
1646 1674 : passtools->usingNaturalUnits = natural;
1647 1674 : passtools->units=u;
1648 1674 : std::vector<ActionToPutData*> idata = actionSet.select<ActionToPutData*>();
1649 12771 : for(const auto & ip : idata) {
1650 11097 : ip->updateUnits( passtools.get() );
1651 : }
1652 54327 : for(const auto & p : actionSet ) {
1653 52653 : p->resetStoredTimestep();
1654 : }
1655 1674 : }
1656 :
1657 364671 : void PlumedMain::startStep() {
1658 1134150 : for(const auto & ip : inputs) {
1659 769479 : ip->resetForStepStart();
1660 : }
1661 364671 : }
1662 :
1663 114 : void PlumedMain::writeBinary(std::ostream&o)const {
1664 456 : for(const auto & ip : inputs) {
1665 342 : ip->writeBinary(o);
1666 : }
1667 114 : }
1668 :
1669 114 : void PlumedMain::readBinary(std::istream&i) {
1670 456 : for(const auto & ip : inputs) {
1671 342 : ip->readBinary(i);
1672 : }
1673 114 : }
1674 :
1675 40 : void PlumedMain::setEnergyValue( const std::string& name ) {
1676 40 : name_of_energy = name;
1677 40 : }
1678 :
1679 10990 : int PlumedMain::getRealPrecision() const {
1680 10990 : return passtools->getRealPrecision();
1681 : }
1682 :
1683 5271 : bool PlumedMain::usingNaturalUnits() const {
1684 5271 : return passtools->usingNaturalUnits;
1685 : }
1686 :
1687 14356855 : const Units& PlumedMain::getUnits() {
1688 14356855 : return passtools->units;
1689 : }
1690 :
1691 4 : PlumedMain::DeprecatedAtoms& PlumedMain::getAtoms() {
1692 4 : return datoms;
1693 : }
1694 :
1695 72233 : void PlumedMain::plumedQuantityToMD( const std::string& unit, const double& eng, const TypesafePtr & m) const {
1696 72233 : passtools->double2MD( eng/passtools->getUnitConversion(unit),m );
1697 72233 : }
1698 :
1699 0 : double PlumedMain::MDQuantityToPLUMED( const std::string& unit, const TypesafePtr & m) const {
1700 0 : double x=passtools->MD2double(m);
1701 0 : return x*passtools->getUnitConversion(unit);
1702 : }
1703 :
1704 1 : double PlumedMain::DeprecatedAtoms::getKBoltzmann() const {
1705 1 : if( plumed.usingNaturalUnits() ) {
1706 : return 1.0;
1707 : }
1708 1 : return kBoltzmann/plumed.getUnits().getEnergy();
1709 : }
1710 :
1711 1 : double PlumedMain::DeprecatedAtoms::getKbT() const {
1712 1 : ActionForInterface* kb=plumed.getActionSet().selectWithLabel<ActionForInterface*>("kBT");
1713 1 : if( kb ) {
1714 1 : return (kb->copyOutput(0))->get();
1715 : }
1716 : return 0.0;
1717 : }
1718 :
1719 1 : int PlumedMain::DeprecatedAtoms::getNatoms() const {
1720 1 : std::vector<ActionToPutData*> inputs=plumed.getActionSet().select<ActionToPutData*>();
1721 1 : for(const auto & pp : inputs ) {
1722 2 : if( pp->getRole()=="x" ) {
1723 1 : return (pp->copyOutput(0))->getShape()[0];
1724 : }
1725 : }
1726 : return 0;
1727 : }
1728 :
1729 1 : bool PlumedMain::DeprecatedAtoms::usingNaturalUnits() const {
1730 1 : return plumed.usingNaturalUnits();
1731 : }
1732 :
1733 0 : void PlumedMain::DeprecatedAtoms::setCollectEnergy(bool b) const {
1734 0 : plumed.readInputWords( Tools::getWords(plumed.MDEngine + "_energy: ENERGY"), false );
1735 0 : plumed.setEnergyValue( plumed.MDEngine + "_energy" );
1736 0 : }
1737 :
1738 0 : double PlumedMain::DeprecatedAtoms::getEnergy() const {
1739 0 : ActionToPutData* av = plumed.getActionSet().selectWithLabel<ActionToPutData*>( plumed.MDEngine + "_energy" );
1740 0 : return (av->copyOutput(0))->get();
1741 : }
1742 :
1743 5 : void PlumedMain::activateParseOnlyMode() {
1744 5 : doParseOnly=true;
1745 5 : }
1746 :
1747 2338 : bool PlumedMain::parseOnlyMode() const {
1748 2338 : return doParseOnly;
1749 : }
1750 :
1751 97 : void PlumedMain::getKeywordsForAction( const std::string& action, Keywords& keys ) const {
1752 97 : actionRegister().getKeywords( dlloader.getHandles(), action, keys );
1753 97 : }
1754 :
1755 : #ifdef __PLUMED_HAS_PYTHON
1756 : // This is here to stop cppcheck throwing an error
1757 : #endif
1758 :
1759 : #ifdef __PLUMED_HAS_DLADDR
1760 : // This is here to stop cppcheck throwing an error
1761 : #endif
1762 :
1763 : }
1764 :
1765 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|