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 "ActionRegister.h"
26 : #include "ActionSet.h"
27 : #include "ActionWithValue.h"
28 : #include "ActionWithVirtualAtom.h"
29 : #include "Atoms.h"
30 : #include "CLToolMain.h"
31 : #include "ExchangePatterns.h"
32 : #include "GREX.h"
33 : #include "config/Config.h"
34 : #include "tools/Citations.h"
35 : #include "tools/Communicator.h"
36 : #include "tools/DLLoader.h"
37 : #include "tools/Exception.h"
38 : #include "tools/IFile.h"
39 : #include "tools/Log.h"
40 : #include "tools/OpenMP.h"
41 : #include "tools/Tools.h"
42 : #include "tools/Stopwatch.h"
43 : #include "tools/TypesafePtr.h"
44 : #include "lepton/Exception.h"
45 : #include "DataFetchingObject.h"
46 : #include <cstdlib>
47 : #include <cstdio>
48 : #include <cstring>
49 : #include <set>
50 : #include <unordered_map>
51 : #include <exception>
52 : #include <stdexcept>
53 : #include <ios>
54 : #include <new>
55 : #include <typeinfo>
56 : #include <iostream>
57 : #include <algorithm>
58 : #ifdef __PLUMED_LIBCXX11
59 : #include <system_error>
60 : #include <future>
61 : #include <memory>
62 : #include <functional>
63 : #endif
64 :
65 :
66 : namespace PLMD {
67 :
68 : /// Small utility just used in this file to throw arbitrary exceptions
69 38 : [[noreturn]] static void testThrow(const char* what) {
70 76 : auto words=Tools::getWords(what);
71 38 : plumed_assert(words.size()>0);
72 : #define __PLUMED_THROW_NOMSG(type) if(words[0]==#type) throw type()
73 : #define __PLUMED_THROW_MSG(type) if(words[0]==#type) throw type(what)
74 39 : __PLUMED_THROW_MSG(PLMD::ExceptionError);
75 38 : __PLUMED_THROW_MSG(PLMD::ExceptionDebug);
76 37 : __PLUMED_THROW_MSG(PLMD::Exception);
77 36 : __PLUMED_THROW_MSG(PLMD::lepton::Exception);
78 34 : __PLUMED_THROW_NOMSG(std::bad_exception);
79 : #ifdef __PLUMED_LIBCXX11
80 33 : __PLUMED_THROW_NOMSG(std::bad_array_new_length);
81 : #endif
82 32 : __PLUMED_THROW_NOMSG(std::bad_alloc);
83 : #ifdef __PLUMED_LIBCXX11
84 31 : __PLUMED_THROW_NOMSG(std::bad_function_call);
85 30 : __PLUMED_THROW_NOMSG(std::bad_weak_ptr);
86 : #endif
87 29 : __PLUMED_THROW_NOMSG(std::bad_cast);
88 28 : __PLUMED_THROW_NOMSG(std::bad_typeid);
89 27 : __PLUMED_THROW_MSG(std::underflow_error);
90 26 : __PLUMED_THROW_MSG(std::overflow_error);
91 25 : __PLUMED_THROW_MSG(std::range_error);
92 24 : __PLUMED_THROW_MSG(std::runtime_error);
93 23 : __PLUMED_THROW_MSG(std::out_of_range);
94 22 : __PLUMED_THROW_MSG(std::length_error);
95 21 : __PLUMED_THROW_MSG(std::domain_error);
96 20 : __PLUMED_THROW_MSG(std::invalid_argument);
97 19 : __PLUMED_THROW_MSG(std::logic_error);
98 :
99 : #ifdef __PLUMED_LIBCXX11
100 18 : if(words[0]=="std::system_error") {
101 4 : plumed_assert(words.size()>2);
102 : int error_code;
103 4 : Tools::convert(words[2],error_code);
104 4 : if(words[1]=="std::generic_category") {
105 1 : throw std::system_error(error_code,std::generic_category(),what);
106 : }
107 3 : if(words[1]=="std::system_category") {
108 1 : throw std::system_error(error_code,std::system_category(),what);
109 : }
110 2 : if(words[1]=="std::iostream_category") {
111 1 : throw std::system_error(error_code,std::iostream_category(),what);
112 : }
113 1 : if(words[1]=="std::future_category") {
114 1 : throw std::system_error(error_code,std::future_category(),what);
115 : }
116 : }
117 : #endif
118 :
119 14 : if(words[0]=="std::ios_base::failure") {
120 : #ifdef __PLUMED_LIBCXX11
121 1 : int error_code=0;
122 1 : if(words.size()>2) {
123 0 : Tools::convert(words[2],error_code);
124 : }
125 1 : if(words.size()>1 && words[1]=="std::generic_category") {
126 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::generic_category()));
127 : }
128 1 : if(words.size()>1 && words[1]=="std::system_category") {
129 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::system_category()));
130 : }
131 1 : if(words.size()>1 && words[1]=="std::iostream_category") {
132 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::iostream_category()));
133 : }
134 1 : if(words.size()>1 && words[1]=="std::future_category") {
135 0 : throw std::ios_base::failure(what,std::error_code(error_code,std::future_category()));
136 : }
137 : #endif
138 2 : throw std::ios_base::failure(what);
139 : }
140 :
141 13 : if(words[0]=="int") {
142 1 : int value=0;
143 1 : if(words.size()>1) {
144 0 : Tools::convert(words[1],value);
145 : }
146 1 : throw value;
147 : }
148 :
149 12 : if(words[0]=="test_nested1") {
150 : try {
151 12 : throw Exception(std::string("inner ")+what);
152 6 : } catch(...) {
153 : try {
154 18 : std::throw_with_nested(Exception(std::string("middle ")+what));
155 6 : } catch(...) {
156 18 : std::throw_with_nested(Exception(std::string("outer ")+what));
157 6 : }
158 6 : }
159 : }
160 :
161 6 : if(words[0]=="test_nested2") {
162 : try {
163 3 : throw std::bad_alloc();
164 3 : } catch(...) {
165 : try {
166 9 : std::throw_with_nested(Exception(std::string("middle ")+what));
167 3 : } catch(...) {
168 9 : std::throw_with_nested(Exception(std::string("outer ")+what));
169 3 : }
170 3 : }
171 : }
172 :
173 3 : if(words[0]=="test_nested3") {
174 : try {
175 2 : throw "inner";
176 2 : } catch(...) {
177 : try {
178 6 : std::throw_with_nested(Exception(std::string("middle ")+what));
179 2 : } catch(...) {
180 6 : std::throw_with_nested(Exception(std::string("outer ")+what));
181 2 : }
182 2 : }
183 : }
184 :
185 2 : plumed_error() << "unknown exception " << what;
186 38 : }
187 :
188 : namespace {
189 : // This is an internal tool used to count how many PlumedMain objects have been created
190 : // and if they were correctly destroyed.
191 : // When using debug options, it leads to a crash
192 : // Otherwise, it just prints a message
193 : class CountInstances {
194 : std::atomic<int> counter{};
195 : public:
196 : void increase() noexcept {
197 : ++counter;
198 : }
199 : void decrease() noexcept {
200 : --counter;
201 : }
202 4595 : ~CountInstances() {
203 4595 : if(counter!=0) {
204 0 : std::cerr<<"WARNING: internal inconsistency in allocated PlumedMain instances (" <<counter<< ")\n";
205 : #ifndef NDEBUG
206 : std::abort();
207 : #endif
208 : }
209 4595 : }
210 : };
211 : static CountInstances countInstances;
212 : }
213 :
214 :
215 805723 : PlumedMain::PlumedMain():
216 805723 : initialized(false),
217 : // automatically write on log in destructor
218 805723 : stopwatch_fwd(log),
219 805723 : step(0),
220 805723 : active(false),
221 805723 : mydatafetcher(DataFetchingObject::create(sizeof(double),*this)),
222 805723 : endPlumed(false),
223 805723 : atoms_fwd(*this),
224 805723 : actionSet_fwd(*this),
225 805723 : bias(0.0),
226 805723 : work(0.0),
227 805723 : exchangeStep(false),
228 805723 : restart(false),
229 805723 : doCheckPoint(false),
230 805723 : doParseOnly(false),
231 805723 : stopNow(false),
232 805723 : novirial(false),
233 805723 : detailedTimers(false),
234 1611446 : gpuDeviceId(-1) {
235 805723 : increaseReferenceCounter();
236 805723 : log.link(comm);
237 1611446 : log.setLinePrefix("PLUMED: ");
238 : // this is at last so as to avoid inconsistencies if an exception is thrown
239 : countInstances.increase(); // noexcept
240 805723 : }
241 :
242 : // destructor needed to delete forward declarated objects
243 1610606 : PlumedMain::~PlumedMain() {
244 : countInstances.decrease();
245 3222052 : }
246 :
247 : /////////////////////////////////////////////////////////////
248 : // MAIN INTERPRETER
249 :
250 : #define CHECK_INIT(ini,word) plumed_massert(ini,"cmd(\"" + word +"\") should be only used after plumed initialization")
251 : #define CHECK_NOTINIT(ini,word) plumed_massert(!(ini),"cmd(\"" + word +"\") should be only used before plumed initialization")
252 : #define CHECK_NOTNULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"" + word + "\")");
253 :
254 :
255 1141613 : void PlumedMain::cmd(const std::string & word,const TypesafePtr & val) {
256 :
257 : // Enumerate all possible commands:
258 : enum {
259 : #include "PlumedMainEnum.inc"
260 : };
261 :
262 : // Static object (initialized once) containing the map of commands:
263 : const static std::unordered_map<std::string, int> word_map = {
264 : #include "PlumedMainMap.inc"
265 1512107 : };
266 :
267 : try {
268 :
269 1141613 : auto ss=stopwatch.startPause();
270 :
271 1141613 : std::vector<std::string> words=Tools::getWords(word);
272 1141613 : unsigned nw=words.size();
273 1141613 : if(nw==0) {
274 : // do nothing
275 : } else {
276 : int iword=-1;
277 : double d;
278 : const auto it=word_map.find(words[0]);
279 1141613 : if(it!=word_map.end()) {
280 1141606 : iword=it->second;
281 : }
282 1141606 : switch(iword) {
283 53986 : case cmd_setBox:
284 53986 : CHECK_INIT(initialized,word);
285 53986 : CHECK_NOTNULL(val,word);
286 53986 : atoms.setBox(val);
287 : break;
288 58127 : case cmd_setPositions:
289 58127 : CHECK_INIT(initialized,word);
290 58127 : atoms.setPositions(val);
291 : break;
292 58131 : case cmd_setMasses:
293 58131 : CHECK_INIT(initialized,word);
294 58131 : atoms.setMasses(val);
295 : break;
296 48220 : case cmd_setCharges:
297 48220 : CHECK_INIT(initialized,word);
298 48220 : atoms.setCharges(val);
299 : break;
300 1 : case cmd_setPositionsX:
301 1 : CHECK_INIT(initialized,word);
302 1 : atoms.setPositions(val,0);
303 : break;
304 1 : case cmd_setPositionsY:
305 1 : CHECK_INIT(initialized,word);
306 1 : atoms.setPositions(val,1);
307 : break;
308 1 : case cmd_setPositionsZ:
309 1 : CHECK_INIT(initialized,word);
310 1 : atoms.setPositions(val,2);
311 : break;
312 48328 : case cmd_setVirial:
313 48328 : CHECK_INIT(initialized,word);
314 48328 : CHECK_NOTNULL(val,word);
315 48328 : atoms.setVirial(val);
316 : break;
317 9792 : case cmd_setEnergy:
318 9792 : CHECK_INIT(initialized,word);
319 9792 : CHECK_NOTNULL(val,word);
320 9792 : atoms.setEnergy(val);
321 : break;
322 58127 : case cmd_setForces:
323 58127 : CHECK_INIT(initialized,word);
324 58127 : atoms.setForces(val);
325 : break;
326 1 : case cmd_setForcesX:
327 1 : CHECK_INIT(initialized,word);
328 1 : atoms.setForces(val,0);
329 : break;
330 1 : case cmd_setForcesY:
331 1 : CHECK_INIT(initialized,word);
332 1 : atoms.setForces(val,1);
333 : break;
334 1 : case cmd_setForcesZ:
335 1 : CHECK_INIT(initialized,word);
336 1 : atoms.setForces(val,2);
337 : break;
338 256368 : case cmd_calc:
339 256368 : CHECK_INIT(initialized,word);
340 256368 : calc();
341 : break;
342 99 : case cmd_prepareDependencies:
343 99 : CHECK_INIT(initialized,word);
344 99 : prepareDependencies();
345 : break;
346 84 : case cmd_shareData:
347 84 : CHECK_INIT(initialized,word);
348 84 : shareData();
349 : break;
350 2070 : case cmd_prepareCalc:
351 2070 : CHECK_INIT(initialized,word);
352 2070 : prepareCalc();
353 : break;
354 10 : case cmd_performCalc:
355 10 : CHECK_INIT(initialized,word);
356 10 : performCalc();
357 : break;
358 2134 : case cmd_performCalcNoUpdate:
359 2134 : CHECK_INIT(initialized,word);
360 2134 : performCalcNoUpdate();
361 : break;
362 10 : case cmd_performCalcNoForces:
363 10 : CHECK_INIT(initialized,word);
364 10 : performCalcNoForces();
365 : break;
366 79 : case cmd_update:
367 79 : CHECK_INIT(initialized,word);
368 79 : update();
369 : break;
370 6092 : case cmd_setStep:
371 6092 : CHECK_INIT(initialized,word);
372 6098 : CHECK_NOTNULL(val,word);
373 6089 : step=val.get<int>();
374 6089 : atoms.startStep();
375 : break;
376 0 : case cmd_setStepLong:
377 0 : CHECK_INIT(initialized,word);
378 0 : CHECK_NOTNULL(val,word);
379 0 : step=val.get<long int>();
380 0 : atoms.startStep();
381 : break;
382 252394 : case cmd_setStepLongLong:
383 252394 : CHECK_INIT(initialized,word);
384 252394 : CHECK_NOTNULL(val,word);
385 252394 : step=val.get<long long int>();
386 252394 : atoms.startStep();
387 : break;
388 : // words used less frequently:
389 1142 : case cmd_setAtomsNlocal:
390 1142 : CHECK_INIT(initialized,word);
391 1142 : CHECK_NOTNULL(val,word);
392 1142 : atoms.setAtomsNlocal(val.get<int>());
393 : break;
394 988 : case cmd_setAtomsGatindex:
395 988 : CHECK_INIT(initialized,word);
396 988 : atoms.setAtomsGatindex(val,false);
397 : break;
398 2 : case cmd_setAtomsFGatindex:
399 2 : CHECK_INIT(initialized,word);
400 2 : atoms.setAtomsGatindex(val,true);
401 : break;
402 152 : case cmd_setAtomsContiguous:
403 152 : CHECK_INIT(initialized,word);
404 152 : CHECK_NOTNULL(val,word);
405 152 : atoms.setAtomsContiguous(val.get<int>());
406 : break;
407 116 : case cmd_createFullList:
408 116 : CHECK_INIT(initialized,word);
409 116 : CHECK_NOTNULL(val,word);
410 116 : atoms.createFullList(val);
411 : break;
412 116 : case cmd_getFullList:
413 116 : CHECK_INIT(initialized,word);
414 116 : CHECK_NOTNULL(val,word);
415 116 : atoms.getFullList(val);
416 : break;
417 116 : case cmd_clearFullList:
418 116 : CHECK_INIT(initialized,word);
419 116 : atoms.clearFullList();
420 : break;
421 : /* ADDED WITH API==6 */
422 64 : case cmd_getDataRank:
423 64 : CHECK_INIT(initialized,words[0]);
424 64 : plumed_assert(nw==2 || nw==3);
425 64 : if( nw==2 ) {
426 128 : DataFetchingObject::get_rank( actionSet, words[1], "", val);
427 : } else {
428 0 : DataFetchingObject::get_rank( actionSet, words[1], words[2], val);
429 : }
430 : break;
431 : /* ADDED WITH API==6 */
432 0 : case cmd_getDataShape:
433 0 : CHECK_INIT(initialized,words[0]);
434 0 : plumed_assert(nw==2 || nw==3);
435 0 : if( nw==2 ) {
436 0 : DataFetchingObject::get_shape( actionSet, words[1], "", val );
437 : } else {
438 0 : DataFetchingObject::get_shape( actionSet, words[1], words[2], val );
439 : }
440 : break;
441 : /* ADDED WITH API==6 */
442 64 : case cmd_setMemoryForData:
443 64 : CHECK_INIT(initialized,words[0]);
444 64 : plumed_assert(nw==2 || nw==3);
445 64 : if( nw==2 ) {
446 128 : mydatafetcher->setData( words[1], "", val );
447 : } else {
448 0 : mydatafetcher->setData( words[1], words[2], val );
449 : }
450 : break;
451 : /* ADDED WITH API==6 */
452 : case cmd_setErrorHandler: {
453 0 : if(val) {
454 0 : error_handler=*static_cast<const plumed_error_handler*>(val.get<const void*>());
455 : } else {
456 0 : error_handler.handler=NULL;
457 : }
458 : }
459 : break;
460 0 : case cmd_read:
461 0 : CHECK_INIT(initialized,word);
462 0 : if(val) {
463 0 : readInputFile(val.get<const char*>());
464 : } else {
465 0 : readInputFile("plumed.dat");
466 : }
467 : break;
468 276 : case cmd_readInputLine:
469 276 : CHECK_INIT(initialized,word);
470 276 : CHECK_NOTNULL(val,word);
471 276 : readInputLine(val.get<const char*>());
472 236 : break;
473 1 : case cmd_readInputLines:
474 1 : CHECK_INIT(initialized,word);
475 1 : CHECK_NOTNULL(val,word);
476 1 : readInputLines(val.get<const char*>());
477 1 : break;
478 1 : case cmd_clear:
479 1 : CHECK_INIT(initialized,word);
480 1 : actionSet.clearDelete();
481 : break;
482 : case cmd_getApiVersion:
483 42 : CHECK_NOTNULL(val,word);
484 42 : val.set(int(10));
485 : break;
486 : // commands which can be used only before initialization:
487 1036 : case cmd_init:
488 1036 : CHECK_NOTINIT(initialized,word);
489 1036 : init();
490 : break;
491 905 : case cmd_setRealPrecision:
492 905 : CHECK_NOTINIT(initialized,word);
493 905 : CHECK_NOTNULL(val,word);
494 905 : atoms.setRealPrecision(val.get<int>());
495 1808 : mydatafetcher=DataFetchingObject::create(val.get<int>(),*this);
496 904 : break;
497 837 : case cmd_setMDLengthUnits:
498 837 : CHECK_NOTINIT(initialized,word);
499 837 : CHECK_NOTNULL(val,word);
500 837 : atoms.MD2double(val,d);
501 837 : atoms.setMDLengthUnits(d);
502 : break;
503 837 : case cmd_setMDChargeUnits:
504 837 : CHECK_NOTINIT(initialized,word);
505 837 : CHECK_NOTNULL(val,word);
506 837 : atoms.MD2double(val,d);
507 837 : atoms.setMDChargeUnits(d);
508 : break;
509 837 : case cmd_setMDMassUnits:
510 837 : CHECK_NOTINIT(initialized,word);
511 837 : CHECK_NOTNULL(val,word);
512 837 : atoms.MD2double(val,d);
513 837 : atoms.setMDMassUnits(d);
514 : break;
515 45 : case cmd_setMDEnergyUnits:
516 45 : CHECK_NOTINIT(initialized,word);
517 45 : CHECK_NOTNULL(val,word);
518 45 : atoms.MD2double(val,d);
519 45 : atoms.setMDEnergyUnits(d);
520 : break;
521 6 : case cmd_setMDTimeUnits:
522 6 : CHECK_NOTINIT(initialized,word);
523 6 : CHECK_NOTNULL(val,word);
524 6 : atoms.MD2double(val,d);
525 6 : atoms.setMDTimeUnits(d);
526 : break;
527 0 : case cmd_setNaturalUnits:
528 : // set the boltzman constant for MD in natural units (kb=1)
529 : // only needed in LJ codes if the MD is passing temperatures to plumed (so, not yet...)
530 : // use as cmd("setNaturalUnits")
531 0 : CHECK_NOTINIT(initialized,word);
532 0 : atoms.setMDNaturalUnits(true);
533 : break;
534 52 : case cmd_setNoVirial:
535 52 : CHECK_NOTINIT(initialized,word);
536 52 : novirial=true;
537 52 : break;
538 892 : case cmd_setPlumedDat:
539 892 : CHECK_NOTINIT(initialized,word);
540 892 : CHECK_NOTNULL(val,word);
541 892 : plumedDat=val.get<const char*>();
542 : break;
543 348 : case cmd_setMPIComm:
544 348 : CHECK_NOTINIT(initialized,word);
545 348 : comm.Set_comm(val);
546 348 : atoms.setDomainDecomposition(comm);
547 : break;
548 0 : case cmd_setMPIFComm:
549 0 : CHECK_NOTINIT(initialized,word);
550 0 : comm.Set_fcomm(val);
551 0 : atoms.setDomainDecomposition(comm);
552 : break;
553 0 : case cmd_setMPImultiSimComm:
554 0 : CHECK_NOTINIT(initialized,word);
555 0 : multi_sim_comm.Set_comm(val);
556 : break;
557 1019 : case cmd_setNatoms:
558 1019 : CHECK_NOTINIT(initialized,word);
559 1019 : CHECK_NOTNULL(val,word);
560 1019 : atoms.setNatoms(val.get<int>());
561 : break;
562 893 : case cmd_setTimestep:
563 893 : CHECK_NOTINIT(initialized,word);
564 893 : CHECK_NOTNULL(val,word);
565 893 : atoms.setTimeStep(val);
566 : break;
567 : /* ADDED WITH API==2 */
568 59 : case cmd_setKbT:
569 59 : CHECK_NOTINIT(initialized,word);
570 59 : CHECK_NOTNULL(val,word);
571 59 : atoms.setKbT(val);
572 : break;
573 : /* ADDED WITH API==3 */
574 8 : case cmd_setRestart:
575 8 : CHECK_NOTINIT(initialized,word);
576 8 : CHECK_NOTNULL(val,word);
577 8 : if(val.get<int>()!=0) {
578 2 : restart=true;
579 : }
580 : break;
581 : /* ADDED WITH API==4 */
582 0 : case cmd_doCheckPoint:
583 0 : CHECK_INIT(initialized,word);
584 0 : CHECK_NOTNULL(val,word);
585 0 : doCheckPoint = false;
586 0 : if(val.get<int>()!=0) {
587 0 : doCheckPoint = true;
588 : }
589 : break;
590 : /* ADDED WITH API==6 */
591 : case cmd_setNumOMPthreads:
592 0 : CHECK_NOTNULL(val,word);
593 : {
594 0 : auto nt=val.get<unsigned>();
595 : if(nt==0) {
596 : nt=1;
597 : }
598 0 : OpenMP::setNumThreads(nt);
599 : }
600 : break;
601 : /* ADDED WITH API==10 */
602 : case cmd_setGpuDeviceId:
603 0 : CHECK_NOTNULL(val,word);
604 : {
605 0 : auto id=val.get<int>();
606 0 : if(id>=0) {
607 0 : gpuDeviceId=id;
608 : }
609 : }
610 : break;
611 : /* ADDED WITH API==6 */
612 : /* only used for testing */
613 : case cmd_throw:
614 38 : CHECK_NOTNULL(val,word);
615 38 : testThrow(val.get<const char*>());
616 : /* ADDED WITH API==10 */
617 : case cmd_setNestedExceptions:
618 25 : CHECK_NOTNULL(val,word);
619 25 : if(val.get<int>()!=0) {
620 24 : nestedExceptions=true;
621 : } else {
622 1 : nestedExceptions=false;
623 : }
624 : break;
625 : /* STOP API */
626 890 : case cmd_setMDEngine:
627 890 : CHECK_NOTINIT(initialized,word);
628 890 : CHECK_NOTNULL(val,word);
629 890 : MDEngine=val.get<const char*>();
630 : break;
631 877 : case cmd_setLog:
632 877 : CHECK_NOTINIT(initialized,word);
633 877 : log.link(val.get<FILE*>());
634 : break;
635 53 : case cmd_setLogFile:
636 53 : CHECK_NOTINIT(initialized,word);
637 53 : CHECK_NOTNULL(val,word);
638 152 : log.open(val.get<const char*>());
639 53 : break;
640 : // other commands that should be used after initialization:
641 256293 : case cmd_setStopFlag:
642 256293 : CHECK_INIT(initialized,word);
643 256293 : CHECK_NOTNULL(val,word);
644 256293 : val.get<int*>(); // just check type and discard pointer
645 256292 : stopFlag=val.copy();
646 256292 : break;
647 0 : case cmd_getExchangesFlag:
648 0 : CHECK_INIT(initialized,word);
649 0 : CHECK_NOTNULL(val,word);
650 0 : exchangePatterns.getFlag(*val.get<int*>()); // note: getFlag changes the value of the reference!
651 : break;
652 0 : case cmd_setExchangesSeed:
653 0 : CHECK_INIT(initialized,word);
654 0 : CHECK_NOTNULL(val,word);
655 0 : exchangePatterns.setSeed(val.get<int>());
656 : break;
657 0 : case cmd_setNumberOfReplicas:
658 0 : CHECK_INIT(initialized,word);
659 0 : CHECK_NOTNULL(val,word);
660 0 : exchangePatterns.setNofR(val.get<int>());
661 : break;
662 0 : case cmd_getExchangesList:
663 0 : CHECK_INIT(initialized,word);
664 0 : CHECK_NOTNULL(val,word);
665 0 : exchangePatterns.getList(val.get<int*>());
666 0 : break;
667 840 : case cmd_runFinalJobs:
668 840 : CHECK_INIT(initialized,word);
669 840 : runJobsAtEndOfCalculation();
670 : break;
671 96 : case cmd_isEnergyNeeded:
672 96 : CHECK_INIT(initialized,word);
673 96 : CHECK_NOTNULL(val,word);
674 96 : if(atoms.isEnergyNeeded()) {
675 0 : val.set(int(1));
676 : } else {
677 96 : val.set(int(0));
678 : }
679 : break;
680 2172 : case cmd_getBias:
681 2172 : CHECK_INIT(initialized,word);
682 2172 : CHECK_NOTNULL(val,word);
683 2172 : atoms.double2MD(getBias()/(atoms.getMDUnits().getEnergy()/atoms.getUnits().getEnergy()),val);
684 2172 : break;
685 : case cmd_checkAction:
686 2 : CHECK_NOTNULL(val,word);
687 2 : plumed_assert(nw==2);
688 3 : val.set(int(actionRegister().check(words[1]) ? 1:0));
689 : break;
690 : case cmd_setExtraCV:
691 30 : CHECK_NOTNULL(val,word);
692 30 : plumed_assert(nw==2);
693 30 : atoms.setExtraCV(words[1],val);
694 : break;
695 : case cmd_setExtraCVForce:
696 30 : CHECK_NOTNULL(val,word);
697 30 : plumed_assert(nw==2);
698 30 : atoms.setExtraCVForce(words[1],val);
699 : break;
700 : /* ADDED WITH API==10 */
701 : case cmd_isExtraCVNeeded:
702 10 : CHECK_NOTNULL(val,word);
703 10 : plumed_assert(nw==2);
704 10 : if(atoms.isExtraCVNeeded(words[1])) {
705 4 : val.set(int(1));
706 : } else {
707 6 : val.set(int(0));
708 : }
709 : break;
710 1089 : case cmd_GREX:
711 1089 : if(!grex) {
712 208 : grex=Tools::make_unique<GREX>(*this);
713 : }
714 1089 : plumed_massert(grex,"error allocating grex");
715 : {
716 1089 : std::string kk=words[1];
717 1260 : for(unsigned i=2; i<words.size(); i++) {
718 342 : kk+=" "+words[i];
719 : }
720 2178 : grex->cmd(kk.c_str(),val);
721 : }
722 1089 : break;
723 14193 : case cmd_CLTool:
724 14193 : CHECK_NOTINIT(initialized,word);
725 14193 : if(!cltool) {
726 4643 : cltool=Tools::make_unique<CLToolMain>();
727 : }
728 : {
729 14193 : std::string kk=words[1];
730 14193 : for(unsigned i=2; i<words.size(); i++) {
731 0 : kk+=" "+words[i];
732 : }
733 28386 : cltool->cmd(kk.c_str(),val);
734 : }
735 14193 : break;
736 : /* ADDED WITH API==7 */
737 : case cmd_convert: {
738 : double v;
739 57 : plumed_assert(words.size()==2);
740 57 : if(Tools::convertNoexcept(words[1],v)) {
741 47 : atoms.double2MD(v,val);
742 : }
743 : }
744 57 : break;
745 7 : default:
746 21 : plumed_merror("cannot interpret cmd(\"" + word + "\"). check plumed developers manual to see the available commands.");
747 : break;
748 : }
749 : }
750 :
751 1141811 : } catch (...) {
752 99 : if(log.isOpen()) {
753 : try {
754 54 : log<<"\n################################################################################\n";
755 54 : log<<Tools::concatenateExceptionMessages();
756 54 : log<<"\n################################################################################\n";
757 54 : log.flush();
758 0 : } catch(...) {
759 : // ignore errors here.
760 : // in any case, we are rethrowing this below
761 0 : }
762 : }
763 99 : throw;
764 99 : }
765 1141514 : }
766 :
767 : ////////////////////////////////////////////////////////////////////////
768 :
769 1036 : void PlumedMain::init() {
770 : // check that initialization just happens once
771 1036 : initialized=true;
772 1036 : atoms.init();
773 1036 : if(!log.isOpen()) {
774 106 : log.link(stdout);
775 : }
776 1036 : log<<"PLUMED is starting\n";
777 3108 : log<<"Version: "<<config::getVersionLong()<<" (git: "<<config::getVersionGit()<<") "
778 4144 : <<"compiled on " <<config::getCompilationDate() << " at " << config::getCompilationTime() << "\n";
779 1036 : log<<"Please cite these papers when using PLUMED ";
780 2072 : log<<cite("The PLUMED consortium, Nat. Methods 16, 670 (2019)");
781 2072 : log<<cite("Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014)");
782 1036 : log<<"\n";
783 1036 : log<<"For further information see the PLUMED web page at http://www.plumed.org\n";
784 1036 : log<<"Root: "<<config::getPlumedRoot()<<"\n";
785 2072 : log<<"For installed feature, see "<<config::getPlumedRoot() + "/src/config/config.txt\n";
786 1036 : log.printf("Molecular dynamics engine: %s\n",MDEngine.c_str());
787 1036 : log.printf("Precision of reals: %d\n",atoms.getRealPrecision());
788 1840 : log.printf("Running over %d %s\n",comm.Get_size(),(comm.Get_size()>1?"nodes":"node"));
789 1036 : log<<"Number of threads: "<<OpenMP::getNumThreads()<<"\n";
790 1036 : log<<"Cache line size: "<<OpenMP::getCachelineSize()<<"\n";
791 1036 : log.printf("Number of atoms: %d\n",atoms.getNatoms());
792 1036 : if(grex) {
793 208 : log.printf("GROMACS-like replica exchange is on\n");
794 : }
795 1036 : log.printf("File suffix: %s\n",getSuffix().c_str());
796 1036 : if(plumedDat.length()>0) {
797 892 : readInputFile(plumedDat);
798 : plumedDat="";
799 : }
800 1036 : atoms.updateUnits();
801 1036 : log.printf("Timestep: %f\n",atoms.getTimeStep());
802 1036 : if(atoms.getKbT()>0.0) {
803 53 : log.printf("KbT: %f\n",atoms.getKbT());
804 : } else {
805 983 : log.printf("KbT has not been set by the MD engine\n");
806 983 : log.printf("It should be set by hand where needed\n");
807 : }
808 1036 : log<<"Relevant bibliography:\n";
809 1036 : log<<citations;
810 1036 : log<<"Please read and cite where appropriate!\n";
811 1036 : log<<"Finished setup\n";
812 1036 : }
813 :
814 910 : void PlumedMain::readInputFile(const std::string & str) {
815 910 : plumed_assert(initialized);
816 910 : log<<"FILE: "<<str<<"\n";
817 910 : IFile ifile;
818 910 : ifile.link(*this);
819 910 : ifile.open(str);
820 910 : ifile.allowNoEOL();
821 910 : readInputFile(ifile);
822 910 : log<<"END FILE: "<<str<<"\n";
823 910 : log.flush();
824 :
825 910 : }
826 :
827 911 : void PlumedMain::readInputFile(IFile & ifile) {
828 : std::vector<std::string> words;
829 15236 : while(Tools::getParsedLine(ifile,words) && !endPlumed) {
830 14325 : readInputWords(words);
831 : }
832 911 : endPlumed=false;
833 911 : pilots=actionSet.select<ActionPilot*>();
834 911 : }
835 :
836 360 : void PlumedMain::readInputLine(const std::string & str) {
837 360 : plumed_assert(initialized);
838 360 : if(str.empty()) {
839 0 : return;
840 : }
841 360 : std::vector<std::string> words=Tools::getWords(str);
842 360 : citations.clear();
843 360 : readInputWords(words);
844 320 : if(!citations.empty()) {
845 2 : log<<"Relevant bibliography:\n";
846 2 : log<<citations;
847 2 : log<<"Please read and cite where appropriate!\n";
848 : }
849 360 : }
850 :
851 1 : void PlumedMain::readInputLines(const std::string & str) {
852 1 : plumed_assert(initialized);
853 1 : if(str.empty()) {
854 0 : return;
855 : }
856 :
857 1 : log<<"FILE: (temporary)\n";
858 :
859 : // Open a temporary file
860 1 : auto fp=std::tmpfile();
861 1 : plumed_assert(fp);
862 :
863 : // make sure file is closed (and thus deleted) also if an exception occurs
864 : auto deleter=[](FILE* fp) {
865 1 : std::fclose(fp);
866 : };
867 : std::unique_ptr<FILE,decltype(deleter)> fp_deleter(fp,deleter);
868 :
869 1 : auto ret=std::fputs(str.c_str(),fp);
870 1 : plumed_assert(ret!=EOF);
871 :
872 1 : std::rewind(fp);
873 :
874 1 : IFile ifile;
875 1 : ifile.link(*this);
876 1 : ifile.link(fp);
877 1 : ifile.allowNoEOL();
878 :
879 1 : readInputFile(ifile);
880 1 : log<<"END FILE: (temporary)\n";
881 1 : }
882 :
883 14711 : void PlumedMain::readInputWords(const std::vector<std::string> & words) {
884 14711 : plumed_assert(initialized);
885 14711 : if(words.empty()) {
886 : return;
887 14555 : } else if(words[0]=="_SET_SUFFIX") {
888 3 : plumed_assert(words.size()==2);
889 : setSuffix(words[1]);
890 : } else {
891 14552 : std::vector<std::string> interpreted(words);
892 14552 : Tools::interpretLabel(interpreted);
893 29066 : auto action=actionRegister().create(ActionOptions(*this,interpreted));
894 14514 : if(!action) {
895 : std::string msg;
896 : msg ="ERROR\nI cannot understand line:";
897 8 : for(unsigned i=0; i<interpreted.size(); ++i) {
898 14 : msg+=" "+interpreted[i];
899 : }
900 : msg+="\nMaybe a missing space or a typo?";
901 2 : log << msg;
902 2 : log.flush();
903 4 : plumed_merror(msg);
904 : }
905 14512 : action->checkRead();
906 14512 : actionSet.emplace_back(std::move(action));
907 14554 : };
908 :
909 29030 : pilots=actionSet.select<ActionPilot*>();
910 : }
911 :
912 : ////////////////////////////////////////////////////////////////////////
913 :
914 0 : void PlumedMain::exit(int c) {
915 0 : comm.Abort(c);
916 0 : }
917 :
918 14550 : Log& PlumedMain::getLog() {
919 14550 : return log;
920 : }
921 :
922 256368 : void PlumedMain::calc() {
923 256368 : prepareCalc();
924 256368 : performCalc();
925 256368 : }
926 :
927 258438 : void PlumedMain::prepareCalc() {
928 258438 : prepareDependencies();
929 258438 : shareData();
930 258438 : }
931 :
932 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
933 : // here we have the main steps in "calc()"
934 : // they can be called individually, but the standard thing is to
935 : // traverse them in this order:
936 258765 : void PlumedMain::prepareDependencies() {
937 :
938 : // Stopwatch is stopped when sw goes out of scope
939 258765 : auto sw=stopwatch.startStop("1 Prepare dependencies");
940 :
941 : // activate all the actions which are on step
942 : // activation is recursive and enables also the dependencies
943 : // before doing that, the prepare() method is called to see if there is some
944 : // new/changed dependency (up to now, only useful for dependences on virtual atoms,
945 : // which can be dynamically changed).
946 :
947 : // First switch off all actions
948 2109359 : for(const auto & p : actionSet) {
949 1850594 : p->deactivate();
950 : }
951 :
952 : // for optimization, an "active" flag remains false if no action at all is active
953 258765 : active=mydatafetcher->activate();
954 1615751 : for(unsigned i=0; i<pilots.size(); ++i) {
955 1356986 : if(pilots[i]->onStep()) {
956 1286891 : pilots[i]->activate();
957 1286891 : active=true;
958 : }
959 : };
960 :
961 : // also, if one of them is the total energy, tell to atoms that energy should be collected
962 2109359 : for(const auto & p : actionSet) {
963 1850594 : if(p->isActive()) {
964 1665305 : if(p->checkNeedsGradients()) {
965 172 : p->setOption("GRADIENTS");
966 : }
967 : }
968 : }
969 :
970 258765 : }
971 :
972 258522 : void PlumedMain::shareData() {
973 : // atom positions are shared (but only if there is something to do)
974 258522 : if(!active) {
975 1648 : return;
976 : }
977 : // Stopwatch is stopped when sw goes out of scope
978 256874 : auto sw=stopwatch.startStop("2 Sharing data");
979 256874 : if(atoms.getNatoms()>0) {
980 56534 : atoms.share();
981 : }
982 256874 : }
983 :
984 2134 : void PlumedMain::performCalcNoUpdate() {
985 2134 : waitData();
986 2134 : justCalculate();
987 2134 : backwardPropagate();
988 2134 : }
989 :
990 10 : void PlumedMain::performCalcNoForces() {
991 10 : waitData();
992 10 : justCalculate();
993 10 : }
994 :
995 256378 : void PlumedMain::performCalc() {
996 256378 : waitData();
997 256378 : justCalculate();
998 256378 : backwardPropagate();
999 256378 : update();
1000 256378 : mydatafetcher->finishDataGrab();
1001 256378 : }
1002 :
1003 258636 : void PlumedMain::waitData() {
1004 258636 : if(!active) {
1005 1648 : return;
1006 : }
1007 : // Stopwatch is stopped when sw goes out of scope
1008 256988 : auto sw=stopwatch.startStop("3 Waiting for data");
1009 256988 : if(atoms.getNatoms()>0) {
1010 56648 : atoms.wait();
1011 : }
1012 256988 : }
1013 :
1014 258636 : void PlumedMain::justCalculate() {
1015 258636 : if(!active) {
1016 1648 : return;
1017 : }
1018 : // Stopwatch is stopped when sw goes out of scope
1019 256988 : auto sw=stopwatch.startStop("4 Calculating (forward loop)");
1020 256988 : bias=0.0;
1021 256988 : work=0.0;
1022 :
1023 256988 : int iaction=0;
1024 : // calculate the active actions in order (assuming *backward* dependence)
1025 2097206 : for(const auto & pp : actionSet) {
1026 : Action* p(pp.get());
1027 : try {
1028 1840218 : if(p->isActive()) {
1029 : // Stopwatch is stopped when sw goes out of scope.
1030 : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
1031 1664441 : Stopwatch::Handler sw;
1032 1664441 : if(detailedTimers) {
1033 : std::string actionNumberLabel;
1034 1690 : Tools::convert(iaction,actionNumberLabel);
1035 1690 : const unsigned m=actionSet.size();
1036 : unsigned k=0;
1037 : unsigned n=1;
1038 5070 : while(n<m) {
1039 3380 : n*=10;
1040 3380 : k++;
1041 : }
1042 1690 : const int pad=k-actionNumberLabel.length();
1043 2815 : for(int i=0; i<pad; i++) {
1044 2250 : actionNumberLabel=" "+actionNumberLabel;
1045 : }
1046 1690 : sw=stopwatch.startStop("4A "+actionNumberLabel+" "+p->getLabel());
1047 : }
1048 1664441 : ActionWithValue*av=dynamic_cast<ActionWithValue*>(p);
1049 1664441 : ActionAtomistic*aa=dynamic_cast<ActionAtomistic*>(p);
1050 : {
1051 1664441 : if(av) {
1052 1397729 : av->clearInputForces();
1053 : }
1054 1664441 : if(av) {
1055 1397729 : av->clearDerivatives();
1056 : }
1057 : }
1058 : {
1059 1664441 : if(aa) {
1060 174709 : aa->clearOutputForces();
1061 : }
1062 1664441 : if(aa)
1063 174709 : if(aa->isActive()) {
1064 174709 : aa->retrieveAtoms();
1065 : }
1066 : }
1067 1664441 : if(p->checkNumericalDerivatives()) {
1068 568 : p->calculateNumericalDerivatives();
1069 : } else {
1070 1663873 : p->calculate();
1071 : }
1072 : // This retrieves components called bias
1073 1664441 : if(av) {
1074 1397729 : bias+=av->getOutputQuantity("bias");
1075 1397729 : work+=av->getOutputQuantity("work");
1076 1397729 : av->setGradientsIfNeeded();
1077 : }
1078 1664441 : ActionWithVirtualAtom*avv=dynamic_cast<ActionWithVirtualAtom*>(p);
1079 1664441 : if(avv) {
1080 14422 : avv->setGradientsIfNeeded();
1081 : }
1082 1664441 : }
1083 0 : } catch(...) {
1084 0 : plumed_error_nested() << "An error happened while calculating " << p->getLabel();
1085 0 : }
1086 1840218 : iaction++;
1087 : }
1088 256988 : }
1089 :
1090 0 : void PlumedMain::justApply() {
1091 0 : backwardPropagate();
1092 0 : update();
1093 0 : }
1094 :
1095 258512 : void PlumedMain::backwardPropagate() {
1096 258512 : if(!active) {
1097 1648 : return;
1098 : }
1099 256864 : int iaction=0;
1100 : // Stopwatch is stopped when sw goes out of scope
1101 256864 : auto sw=stopwatch.startStop("5 Applying (backward loop)");
1102 : // apply them in reverse order
1103 2096128 : for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) {
1104 : const auto & p(pp->get());
1105 1839264 : if(p->isActive()) {
1106 :
1107 : // Stopwatch is stopped when sw goes out of scope.
1108 : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
1109 1663679 : Stopwatch::Handler sw;
1110 1663679 : if(detailedTimers) {
1111 : std::string actionNumberLabel;
1112 1690 : Tools::convert(iaction,actionNumberLabel);
1113 1690 : const unsigned m=actionSet.size();
1114 : unsigned k=0;
1115 : unsigned n=1;
1116 5070 : while(n<m) {
1117 3380 : n*=10;
1118 3380 : k++;
1119 : }
1120 1690 : const int pad=k-actionNumberLabel.length();
1121 2815 : for(int i=0; i<pad; i++) {
1122 2250 : actionNumberLabel=" "+actionNumberLabel;
1123 : }
1124 1690 : sw=stopwatch.startStop("5A "+actionNumberLabel+" "+p->getLabel());
1125 : }
1126 :
1127 1663679 : p->apply();
1128 1663679 : ActionAtomistic*a=dynamic_cast<ActionAtomistic*>(p);
1129 : // still ActionAtomistic has a special treatment, since they may need to add forces on atoms
1130 1663679 : if(a) {
1131 174225 : a->applyForces();
1132 : }
1133 :
1134 1663679 : }
1135 1839264 : iaction++;
1136 : }
1137 :
1138 : // Stopwatch is stopped when sw goes out of scope.
1139 : // We explicitly declare a Stopwatch::Handler here to allow for conditional initialization.
1140 256864 : Stopwatch::Handler sw1;
1141 256864 : if(detailedTimers) {
1142 113 : sw1=stopwatch.startStop("5B Update forces");
1143 : }
1144 : // this is updating the MD copy of the forces
1145 256864 : if(atoms.getNatoms()>0) {
1146 56524 : atoms.updateForces();
1147 : }
1148 256864 : }
1149 :
1150 256457 : void PlumedMain::update() {
1151 256457 : if(!active) {
1152 1648 : return;
1153 : }
1154 :
1155 : // Stopwatch is stopped when sw goes out of scope
1156 254809 : auto sw=stopwatch.startStop("6 Update");
1157 :
1158 : // update step (for statistics, etc)
1159 254809 : updateFlags.push(true);
1160 2087586 : for(const auto & p : actionSet) {
1161 1832777 : p->beforeUpdate();
1162 3489611 : if(p->isActive() && p->checkUpdate() && updateFlagsTop()) {
1163 1656814 : p->update();
1164 : }
1165 : }
1166 509622 : while(!updateFlags.empty()) {
1167 : updateFlags.pop();
1168 : }
1169 : if(!updateFlags.empty()) {
1170 : plumed_merror("non matching changes in the update flags");
1171 : }
1172 : // Check that no action has told the calculation to stop
1173 254809 : if(stopNow) {
1174 65 : if(stopFlag) {
1175 65 : stopFlag.set(int(1));
1176 : } else {
1177 0 : plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)");
1178 : }
1179 : }
1180 :
1181 : // flush by default every 10000 steps
1182 : // hopefully will not affect performance
1183 : // also if receive checkpointing signal
1184 254809 : if(step%10000==0||doCheckPoint) {
1185 1005 : fflush();
1186 1005 : log.flush();
1187 15927 : for(const auto & p : actionSet) {
1188 14922 : p->fflush();
1189 : }
1190 : }
1191 254809 : }
1192 :
1193 2 : void PlumedMain::load(const std::string& ss) {
1194 2 : if(DLLoader::installed()) {
1195 2 : std::string s=ss;
1196 2 : size_t n=s.find_last_of(".");
1197 3 : std::string extension="";
1198 2 : std::string base=s;
1199 2 : if(n!=std::string::npos && n<s.length()-1) {
1200 4 : extension=s.substr(n+1);
1201 : }
1202 2 : if(n!=std::string::npos && n<s.length()) {
1203 4 : base=s.substr(0,n);
1204 : }
1205 2 : if(extension=="cpp") {
1206 : // full path command, including environment setup
1207 : // this will work even if plumed is not in the execution path or if it has been
1208 : // installed with a name different from "plumed"
1209 4 : std::string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh "+s;
1210 2 : log<<"Executing: "<<cmd;
1211 2 : if(comm.Get_size()>0) {
1212 2 : log<<" (only on master node)";
1213 : }
1214 2 : log<<"\n";
1215 2 : if(comm.Get_rank()==0) {
1216 2 : int ret=std::system(cmd.c_str());
1217 2 : if(ret!=0) {
1218 2 : plumed_error() <<"An error happened while executing command "<<cmd<<"\n";
1219 : }
1220 : }
1221 1 : comm.Barrier();
1222 2 : base="./"+base;
1223 : }
1224 2 : s=base+"."+config::getSoExt();
1225 1 : void *p=dlloader.load(s);
1226 1 : if(!p) {
1227 0 : plumed_error()<<"I cannot load library " << ss << " " << dlloader.error();
1228 : }
1229 2 : log<<"Loading shared library "<<s.c_str()<<"\n";
1230 1 : log<<"Here is the new list of available actions\n";
1231 1 : log<<actionRegister();
1232 : } else {
1233 0 : plumed_error()<<"While loading library "<< ss << " loading was not enabled, please check if dlopen was found at configure time";
1234 : }
1235 1 : }
1236 :
1237 2805 : double PlumedMain::getBias() const {
1238 2805 : return bias;
1239 : }
1240 :
1241 450 : double PlumedMain::getWork() const {
1242 450 : return work;
1243 : }
1244 :
1245 73 : FILE* PlumedMain::fopen(const char *path, const char *mode) {
1246 73 : std::string mmode(mode);
1247 73 : std::string ppath(path);
1248 73 : std::string suffix(getSuffix());
1249 73 : std::string ppathsuf=ppath+suffix;
1250 73 : FILE*fp=std::fopen(const_cast<char*>(ppathsuf.c_str()),const_cast<char*>(mmode.c_str()));
1251 73 : if(!fp) {
1252 0 : fp=std::fopen(const_cast<char*>(ppath.c_str()),const_cast<char*>(mmode.c_str()));
1253 : }
1254 73 : plumed_massert(fp,"file " + ppath + " cannot be found");
1255 73 : return fp;
1256 : }
1257 :
1258 91 : int PlumedMain::fclose(FILE*fp) {
1259 91 : return std::fclose(fp);
1260 : }
1261 :
1262 4005 : std::string PlumedMain::cite(const std::string&item) {
1263 4005 : return citations.cite(item);
1264 : }
1265 :
1266 1566 : void PlumedMain::fflush() {
1267 4919 : for(const auto & p : files) {
1268 3353 : p->flush();
1269 : }
1270 1566 : }
1271 :
1272 4671 : void PlumedMain::insertFile(FileBase&f) {
1273 4671 : files.insert(&f);
1274 4671 : }
1275 :
1276 4989 : void PlumedMain::eraseFile(FileBase&f) {
1277 4989 : files.erase(&f);
1278 4989 : }
1279 :
1280 65 : void PlumedMain::stop() {
1281 65 : stopNow=true;
1282 65 : }
1283 :
1284 840 : void PlumedMain::runJobsAtEndOfCalculation() {
1285 14834 : for(const auto & p : actionSet) {
1286 13994 : p->runFinalJobs();
1287 : }
1288 840 : }
1289 :
1290 8805798 : unsigned PlumedMain::increaseReferenceCounter() noexcept {
1291 8805798 : return ++referenceCounter;
1292 : }
1293 :
1294 8804856 : unsigned PlumedMain::decreaseReferenceCounter() noexcept {
1295 8804856 : return --referenceCounter;
1296 : }
1297 :
1298 42 : unsigned PlumedMain::useCountReferenceCounter() const noexcept {
1299 42 : return referenceCounter;
1300 : }
1301 :
1302 0 : void PlumedMain::activateParseOnlyMode() {
1303 0 : doParseOnly=true;
1304 0 : }
1305 :
1306 1915 : bool PlumedMain::parseOnlyMode() const {
1307 1915 : return doParseOnly;
1308 : }
1309 :
1310 : #ifdef __PLUMED_HAS_PYTHON
1311 : // This is here to stop cppcheck throwing an error
1312 : #endif
1313 :
1314 : }
1315 :
1316 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|