Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2019 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 <cstdlib>
44 : #include <cstring>
45 : #include <set>
46 : #include <unordered_map>
47 :
48 : using namespace std;
49 :
50 : #include "PlumedMainEnum.inc"
51 :
52 : namespace PLMD {
53 :
54 565146 : const std::unordered_map<std::string, int> & plumedMainWordMap() {
55 565146 : static std::unordered_map<std::string, int> word_map;
56 : static bool init=false;
57 565146 : if(!init) {
58 : #include "PlumedMainMap.inc"
59 : }
60 565146 : init=true;
61 565146 : return word_map;
62 : }
63 :
64 2225 : PlumedMain::PlumedMain():
65 2225 : comm(*new Communicator),
66 2225 : multi_sim_comm(*new Communicator),
67 2225 : dlloader(*new DLLoader),
68 : cltool(NULL),
69 2225 : stopwatch(*new Stopwatch),
70 : grex(NULL),
71 : initialized(false),
72 2225 : log(*new Log),
73 2225 : citations(*new Citations),
74 : step(0),
75 : active(false),
76 : endPlumed(false),
77 2225 : atoms(*new Atoms(*this)),
78 2225 : actionSet(*new ActionSet(*this)),
79 : bias(0.0),
80 : work(0.0),
81 2225 : exchangePatterns(*new(ExchangePatterns)),
82 : exchangeStep(false),
83 : restart(false),
84 : doCheckPoint(false),
85 : stopFlag(NULL),
86 : stopNow(false),
87 : novirial(false),
88 22250 : detailedTimers(false)
89 : {
90 2225 : log.link(comm);
91 2225 : log.setLinePrefix("PLUMED: ");
92 2225 : stopwatch.start();
93 2225 : stopwatch.pause();
94 2225 : }
95 :
96 6668 : PlumedMain::~PlumedMain() {
97 2225 : stopwatch.start();
98 2225 : stopwatch.stop();
99 2225 : if(initialized) log<<stopwatch;
100 2225 : delete &exchangePatterns;
101 2225 : delete &actionSet;
102 2225 : delete &citations;
103 2225 : delete &atoms;
104 2225 : delete &log;
105 2225 : if(grex) delete grex;
106 2225 : delete &stopwatch;
107 2225 : if(cltool) delete cltool;
108 2225 : delete &dlloader;
109 2225 : delete &comm;
110 2225 : delete &multi_sim_comm;
111 4443 : }
112 :
113 : /////////////////////////////////////////////////////////////
114 : // MAIN INTERPRETER
115 :
116 : #define CHECK_INIT(ini,word) plumed_massert(ini,"cmd(\"" + word +"\") should be only used after plumed initialization")
117 : #define CHECK_NOTINIT(ini,word) plumed_massert(!(ini),"cmd(\"" + word +"\") should be only used before plumed initialization")
118 : #define CHECK_NOTNULL(val,word) plumed_massert(val,"NULL pointer received in cmd(\"" + word + "\")");
119 :
120 :
121 282573 : void PlumedMain::cmd(const std::string & word,void*val) {
122 :
123 282573 : stopwatch.start();
124 :
125 282573 : std::vector<std::string> words=Tools::getWords(word);
126 282573 : unsigned nw=words.size();
127 282573 : if(nw==0) {
128 : // do nothing
129 : } else {
130 282573 : int iword=-1;
131 : double d;
132 282573 : const auto it=plumedMainWordMap().find(words[0]);
133 282573 : if(it!=plumedMainWordMap().end()) iword=it->second;
134 282573 : switch(iword) {
135 : case cmd_setBox:
136 26796 : CHECK_INIT(initialized,word);
137 26796 : CHECK_NOTNULL(val,word);
138 26796 : atoms.setBox(val);
139 26796 : break;
140 : case cmd_setPositions:
141 30614 : CHECK_INIT(initialized,word);
142 30614 : atoms.setPositions(val);
143 30614 : break;
144 : case cmd_setMasses:
145 30617 : CHECK_INIT(initialized,word);
146 30617 : atoms.setMasses(val);
147 30614 : break;
148 : case cmd_setCharges:
149 24553 : CHECK_INIT(initialized,word);
150 24553 : atoms.setCharges(val);
151 24553 : break;
152 : case cmd_setPositionsX:
153 0 : CHECK_INIT(initialized,word);
154 0 : atoms.setPositions(val,0);
155 0 : break;
156 : case cmd_setPositionsY:
157 0 : CHECK_INIT(initialized,word);
158 0 : atoms.setPositions(val,1);
159 0 : break;
160 : case cmd_setPositionsZ:
161 0 : CHECK_INIT(initialized,word);
162 0 : atoms.setPositions(val,2);
163 0 : break;
164 : case cmd_setVirial:
165 24616 : CHECK_INIT(initialized,word);
166 24616 : CHECK_NOTNULL(val,word);
167 24616 : atoms.setVirial(val);
168 24616 : break;
169 : case cmd_setEnergy:
170 5988 : CHECK_INIT(initialized,word);
171 5988 : CHECK_NOTNULL(val,word);
172 5988 : atoms.setEnergy(val);
173 5988 : break;
174 : case cmd_setForces:
175 30614 : CHECK_INIT(initialized,word);
176 30614 : atoms.setForces(val);
177 30614 : break;
178 : case cmd_setForcesX:
179 0 : CHECK_INIT(initialized,word);
180 0 : atoms.setForces(val,0);
181 0 : break;
182 : case cmd_setForcesY:
183 0 : CHECK_INIT(initialized,word);
184 0 : atoms.setForces(val,1);
185 0 : break;
186 : case cmd_setForcesZ:
187 0 : CHECK_INIT(initialized,word);
188 0 : atoms.setForces(val,2);
189 0 : break;
190 : case cmd_calc:
191 31030 : CHECK_INIT(initialized,word);
192 31030 : calc();
193 31030 : break;
194 : case cmd_prepareDependencies:
195 10 : CHECK_INIT(initialized,word);
196 10 : prepareDependencies();
197 10 : break;
198 : case cmd_shareData:
199 10 : CHECK_INIT(initialized,word);
200 10 : shareData();
201 10 : break;
202 : case cmd_prepareCalc:
203 260 : CHECK_INIT(initialized,word);
204 260 : prepareCalc();
205 260 : break;
206 : case cmd_performCalc:
207 10 : CHECK_INIT(initialized,word);
208 10 : performCalc();
209 10 : break;
210 : case cmd_performCalcNoUpdate:
211 260 : CHECK_INIT(initialized,word);
212 260 : performCalcNoUpdate();
213 260 : break;
214 : case cmd_update:
215 10 : CHECK_INIT(initialized,word);
216 10 : update();
217 10 : break;
218 : case cmd_setStep:
219 6074 : CHECK_INIT(initialized,word);
220 6074 : CHECK_NOTNULL(val,word);
221 6071 : step=(*static_cast<int*>(val));
222 6071 : atoms.startStep();
223 6071 : break;
224 : case cmd_setStepLong:
225 25219 : CHECK_INIT(initialized,word);
226 25219 : CHECK_NOTNULL(val,word);
227 25219 : step=(*static_cast<long int*>(val));
228 25219 : atoms.startStep();
229 25219 : break;
230 : // words used less frequently:
231 : case cmd_setAtomsNlocal:
232 1056 : CHECK_INIT(initialized,word);
233 1056 : CHECK_NOTNULL(val,word);
234 1056 : atoms.setAtomsNlocal(*static_cast<int*>(val));
235 1056 : break;
236 : case cmd_setAtomsGatindex:
237 920 : CHECK_INIT(initialized,word);
238 920 : atoms.setAtomsGatindex(static_cast<int*>(val),false);
239 920 : break;
240 : case cmd_setAtomsFGatindex:
241 0 : CHECK_INIT(initialized,word);
242 0 : atoms.setAtomsGatindex(static_cast<int*>(val),true);
243 0 : break;
244 : case cmd_setAtomsContiguous:
245 136 : CHECK_INIT(initialized,word);
246 136 : CHECK_NOTNULL(val,word);
247 136 : atoms.setAtomsContiguous(*static_cast<int*>(val));
248 136 : break;
249 : case cmd_createFullList:
250 15 : CHECK_INIT(initialized,word);
251 15 : CHECK_NOTNULL(val,word);
252 15 : atoms.createFullList(static_cast<int*>(val));
253 15 : break;
254 : case cmd_getFullList:
255 15 : CHECK_INIT(initialized,word);
256 15 : CHECK_NOTNULL(val,word);
257 15 : atoms.getFullList(static_cast<int**>(val));
258 15 : break;
259 : case cmd_clearFullList:
260 15 : CHECK_INIT(initialized,word);
261 15 : atoms.clearFullList();
262 15 : break;
263 : case cmd_read:
264 0 : CHECK_INIT(initialized,word);
265 0 : if(val)readInputFile(static_cast<char*>(val));
266 0 : else readInputFile("plumed.dat");
267 0 : break;
268 : case cmd_readInputLine:
269 112 : CHECK_INIT(initialized,word);
270 112 : CHECK_NOTNULL(val,word);
271 151 : readInputLine(static_cast<char*>(val));
272 73 : break;
273 : case cmd_clear:
274 0 : CHECK_INIT(initialized,word);
275 0 : actionSet.clearDelete();
276 0 : break;
277 : case cmd_getApiVersion:
278 5 : CHECK_NOTNULL(val,word);
279 5 : *(static_cast<int*>(val))=5;
280 5 : break;
281 : // commands which can be used only before initialization:
282 : case cmd_init:
283 633 : CHECK_NOTINIT(initialized,word);
284 633 : init();
285 633 : break;
286 : case cmd_setRealPrecision:
287 554 : CHECK_NOTINIT(initialized,word);
288 554 : CHECK_NOTNULL(val,word);
289 554 : atoms.setRealPrecision(*static_cast<int*>(val));
290 553 : break;
291 : case cmd_setMDLengthUnits:
292 510 : CHECK_NOTINIT(initialized,word);
293 510 : CHECK_NOTNULL(val,word);
294 510 : atoms.MD2double(val,d);
295 510 : atoms.setMDLengthUnits(d);
296 510 : break;
297 : case cmd_setMDChargeUnits:
298 510 : CHECK_NOTINIT(initialized,word);
299 510 : CHECK_NOTNULL(val,word);
300 510 : atoms.MD2double(val,d);
301 510 : atoms.setMDChargeUnits(d);
302 510 : break;
303 : case cmd_setMDMassUnits:
304 510 : CHECK_NOTINIT(initialized,word);
305 510 : CHECK_NOTNULL(val,word);
306 510 : atoms.MD2double(val,d);
307 510 : atoms.setMDMassUnits(d);
308 510 : break;
309 : case cmd_setMDEnergyUnits:
310 37 : CHECK_NOTINIT(initialized,word);
311 37 : CHECK_NOTNULL(val,word);
312 37 : atoms.MD2double(val,d);
313 37 : atoms.setMDEnergyUnits(d);
314 37 : break;
315 : case cmd_setMDTimeUnits:
316 0 : CHECK_NOTINIT(initialized,word);
317 0 : CHECK_NOTNULL(val,word);
318 0 : atoms.MD2double(val,d);
319 0 : atoms.setMDTimeUnits(d);
320 0 : break;
321 : case cmd_setNaturalUnits:
322 : // set the boltzman constant for MD in natural units (kb=1)
323 : // only needed in LJ codes if the MD is passing temperatures to plumed (so, not yet...)
324 : // use as cmd("setNaturalUnits")
325 0 : CHECK_NOTINIT(initialized,word);
326 0 : atoms.setMDNaturalUnits(true);
327 0 : break;
328 : case cmd_setNoVirial:
329 44 : CHECK_NOTINIT(initialized,word);
330 44 : novirial=true;
331 44 : break;
332 : case cmd_setPlumedDat:
333 557 : CHECK_NOTINIT(initialized,word);
334 557 : CHECK_NOTNULL(val,word);
335 557 : plumedDat=static_cast<char*>(val);
336 557 : break;
337 : case cmd_setMPIComm:
338 245 : CHECK_NOTINIT(initialized,word);
339 245 : comm.Set_comm(val);
340 245 : atoms.setDomainDecomposition(comm);
341 245 : break;
342 : case cmd_setMPIFComm:
343 0 : CHECK_NOTINIT(initialized,word);
344 0 : comm.Set_fcomm(val);
345 0 : atoms.setDomainDecomposition(comm);
346 0 : break;
347 : case cmd_setMPImultiSimComm:
348 0 : CHECK_NOTINIT(initialized,word);
349 0 : multi_sim_comm.Set_comm(val);
350 0 : break;
351 : case cmd_setNatoms:
352 633 : CHECK_NOTINIT(initialized,word);
353 633 : CHECK_NOTNULL(val,word);
354 633 : atoms.setNatoms(*static_cast<int*>(val));
355 633 : break;
356 : case cmd_setTimestep:
357 554 : CHECK_NOTINIT(initialized,word);
358 554 : CHECK_NOTNULL(val,word);
359 554 : atoms.setTimeStep(val);
360 554 : break;
361 : /* ADDED WITH API==2 */
362 : case cmd_setKbT:
363 43 : CHECK_NOTINIT(initialized,word);
364 43 : CHECK_NOTNULL(val,word);
365 43 : atoms.setKbT(val);
366 43 : break;
367 : /* ADDED WITH API==3 */
368 : case cmd_setRestart:
369 0 : CHECK_NOTINIT(initialized,word);
370 0 : CHECK_NOTNULL(val,word);
371 0 : if(*static_cast<int*>(val)!=0) restart=true;
372 0 : break;
373 : /* ADDED WITH API==4 */
374 : case cmd_doCheckPoint:
375 0 : CHECK_INIT(initialized,word);
376 0 : CHECK_NOTNULL(val,word);
377 0 : doCheckPoint = false;
378 0 : if(*static_cast<int*>(val)!=0) doCheckPoint = true;
379 0 : break;
380 : /* STOP API */
381 : case cmd_setMDEngine:
382 553 : CHECK_NOTINIT(initialized,word);
383 553 : CHECK_NOTNULL(val,word);
384 553 : MDEngine=static_cast<char*>(val);
385 553 : break;
386 : case cmd_setLog:
387 547 : CHECK_NOTINIT(initialized,word);
388 547 : log.link(static_cast<FILE*>(val));
389 547 : break;
390 : case cmd_setLogFile:
391 43 : CHECK_NOTINIT(initialized,word);
392 43 : CHECK_NOTNULL(val,word);
393 43 : log.open(static_cast<char*>(val));
394 43 : break;
395 : // other commands that should be used after initialization:
396 : case cmd_setStopFlag:
397 30929 : CHECK_INIT(initialized,word);
398 30929 : CHECK_NOTNULL(val,word);
399 30929 : stopFlag=static_cast<int*>(val);
400 30929 : break;
401 : case cmd_getExchangesFlag:
402 0 : CHECK_INIT(initialized,word);
403 0 : CHECK_NOTNULL(val,word);
404 0 : exchangePatterns.getFlag((*static_cast<int*>(val)));
405 0 : break;
406 : case cmd_setExchangesSeed:
407 0 : CHECK_INIT(initialized,word);
408 0 : CHECK_NOTNULL(val,word);
409 0 : exchangePatterns.setSeed((*static_cast<int*>(val)));
410 0 : break;
411 : case cmd_setNumberOfReplicas:
412 0 : CHECK_INIT(initialized,word);
413 0 : CHECK_NOTNULL(val,word);
414 0 : exchangePatterns.setNofR((*static_cast<int*>(val)));
415 0 : break;
416 : case cmd_getExchangesList:
417 0 : CHECK_INIT(initialized,word);
418 0 : CHECK_NOTNULL(val,word);
419 0 : exchangePatterns.getList((static_cast<int*>(val)));
420 0 : break;
421 : case cmd_runFinalJobs:
422 515 : CHECK_INIT(initialized,word);
423 515 : runJobsAtEndOfCalculation();
424 515 : break;
425 : case cmd_isEnergyNeeded:
426 0 : CHECK_INIT(initialized,word);
427 0 : CHECK_NOTNULL(val,word);
428 0 : if(atoms.isEnergyNeeded()) *(static_cast<int*>(val))=1;
429 0 : else *(static_cast<int*>(val))=0;
430 0 : break;
431 : case cmd_getBias:
432 275 : CHECK_INIT(initialized,word);
433 275 : CHECK_NOTNULL(val,word);
434 275 : atoms.double2MD(getBias()/(atoms.getMDUnits().getEnergy()/atoms.getUnits().getEnergy()),val);
435 275 : break;
436 : case cmd_checkAction:
437 0 : CHECK_NOTNULL(val,word);
438 0 : plumed_assert(nw==2);
439 0 : *(static_cast<int*>(val))=(actionRegister().check(words[1]) ? 1:0);
440 0 : break;
441 : case cmd_GREX:
442 797 : if(!grex) grex=new GREX(*this);
443 797 : plumed_massert(grex,"error allocating grex");
444 : {
445 797 : std::string kk=words[1];
446 797 : for(unsigned i=2; i<words.size(); i++) kk+=" "+words[i];
447 797 : grex->cmd(kk.c_str(),val);
448 : }
449 797 : break;
450 : case cmd_CLTool:
451 5128 : CHECK_NOTINIT(initialized,word);
452 5128 : if(!cltool) cltool=new CLToolMain;
453 : {
454 5128 : std::string kk=words[1];
455 5128 : for(unsigned i=2; i<words.size(); i++) kk+=" "+words[i];
456 5128 : cltool->cmd(kk.c_str(),val);
457 : }
458 5128 : break;
459 : default:
460 1 : plumed_merror("cannot interpret cmd(\"" + word + "\"). check plumed developers manual to see the available commands.");
461 : break;
462 : }
463 : }
464 282573 : stopwatch.pause();
465 282526 : }
466 :
467 : ////////////////////////////////////////////////////////////////////////
468 :
469 633 : void PlumedMain::init() {
470 : // check that initialization just happens once
471 633 : initialized=true;
472 633 : atoms.init();
473 633 : if(!log.isOpen()) log.link(stdout);
474 633 : log<<"PLUMED is starting\n";
475 633 : log<<"Version: "<<config::getVersionLong()<<" (git: "<<config::getVersionGit()<<") compiled on " __DATE__ " at " __TIME__ "\n";
476 633 : log<<"Please cite this paper when using PLUMED ";
477 633 : log<<cite("Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014)");
478 633 : log<<"\n";
479 633 : log<<"For further information see the PLUMED web page at http://www.plumed.org\n";
480 633 : log<<"Root: "<<config::getPlumedRoot()<<"\n";
481 633 : log<<"For installed feature, see "<<config::getPlumedRoot() + "/src/config/config.txt\n";
482 633 : log.printf("Molecular dynamics engine: %s\n",MDEngine.c_str());
483 633 : log.printf("Precision of reals: %d\n",atoms.getRealPrecision());
484 633 : log.printf("Running over %d %s\n",comm.Get_size(),(comm.Get_size()>1?"nodes":"node"));
485 633 : log<<"Number of threads: "<<OpenMP::getNumThreads()<<"\n";
486 633 : log<<"Cache line size: "<<OpenMP::getCachelineSize()<<"\n";
487 633 : log.printf("Number of atoms: %d\n",atoms.getNatoms());
488 633 : if(grex) log.printf("GROMACS-like replica exchange is on\n");
489 633 : log.printf("File suffix: %s\n",getSuffix().c_str());
490 633 : if(plumedDat.length()>0) {
491 557 : readInputFile(plumedDat);
492 557 : plumedDat="";
493 : }
494 633 : atoms.updateUnits();
495 633 : log.printf("Timestep: %f\n",atoms.getTimeStep());
496 633 : if(atoms.getKbT()>0.0)
497 43 : log.printf("KbT: %f\n",atoms.getKbT());
498 : else {
499 590 : log.printf("KbT has not been set by the MD engine\n");
500 590 : log.printf("It should be set by hand where needed\n");
501 : }
502 633 : log<<"Relevant bibliography:\n";
503 633 : log<<citations;
504 633 : log<<"Please read and cite where appropriate!\n";
505 633 : log<<"Finished setup\n";
506 633 : }
507 :
508 570 : void PlumedMain::readInputFile(std::string str) {
509 570 : plumed_assert(initialized);
510 570 : log.printf("FILE: %s\n",str.c_str());
511 570 : IFile ifile;
512 570 : ifile.link(*this);
513 570 : ifile.open(str);
514 570 : ifile.allowNoEOL();
515 1140 : std::vector<std::string> words;
516 570 : while(Tools::getParsedLine(ifile,words) && !endPlumed) readInputWords(words);
517 570 : endPlumed=false;
518 570 : log.printf("END FILE: %s\n",str.c_str());
519 570 : log.flush();
520 :
521 1140 : pilots=actionSet.select<ActionPilot*>();
522 570 : }
523 :
524 155 : void PlumedMain::readInputLine(const std::string & str) {
525 155 : plumed_assert(initialized);
526 271 : if(str.empty()) return;
527 155 : std::vector<std::string> words=Tools::getWords(str);
528 155 : citations.clear();
529 155 : readInputWords(words);
530 116 : if(!citations.empty()) {
531 4 : log<<"Relevant bibliography:\n";
532 4 : log<<citations;
533 4 : log<<"Please read and cite where appropriate!\n";
534 155 : }
535 : }
536 :
537 5263 : void PlumedMain::readInputWords(const std::vector<std::string> & words) {
538 5263 : plumed_assert(initialized);
539 10487 : if(words.empty())return;
540 5263 : else if(words[0]=="_SET_SUFFIX") {
541 3 : plumed_assert(words.size()==2);
542 3 : setSuffix(words[1]);
543 : } else {
544 5260 : std::vector<std::string> interpreted(words);
545 5260 : Tools::interpretLabel(interpreted);
546 5297 : Action* action=actionRegister().create(ActionOptions(*this,interpreted));
547 5223 : if(!action) {
548 2 : std::string msg;
549 2 : msg ="ERROR\nI cannot understand line:";
550 2 : for(unsigned i=0; i<interpreted.size(); ++i) msg+=" "+interpreted[i];
551 2 : msg+="\nMaybe a missing space or a typo?";
552 2 : log << msg;
553 2 : log.flush();
554 2 : plumed_merror(msg);
555 : };
556 5221 : action->checkRead();
557 5260 : actionSet.push_back(action);
558 : };
559 :
560 5224 : pilots=actionSet.select<ActionPilot*>();
561 : }
562 :
563 : ////////////////////////////////////////////////////////////////////////
564 :
565 0 : void PlumedMain::exit(int c) {
566 0 : comm.Abort(c);
567 0 : }
568 :
569 5258 : Log& PlumedMain::getLog() {
570 5258 : return log;
571 : }
572 :
573 31030 : void PlumedMain::calc() {
574 31030 : prepareCalc();
575 31030 : performCalc();
576 31030 : }
577 :
578 31290 : void PlumedMain::prepareCalc() {
579 31290 : prepareDependencies();
580 31290 : shareData();
581 31290 : }
582 :
583 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
584 : // here we have the main steps in "calc()"
585 : // they can be called individually, but the standard thing is to
586 : // traverse them in this order:
587 31468 : void PlumedMain::prepareDependencies() {
588 :
589 31468 : stopwatch.start("1 Prepare dependencies");
590 :
591 : // activate all the actions which are on step
592 : // activation is recursive and enables also the dependencies
593 : // before doing that, the prepare() method is called to see if there is some
594 : // new/changed dependency (up to now, only useful for dependences on virtual atoms,
595 : // which can be dynamically changed).
596 :
597 : // First switch off all actions
598 267746 : for(const auto & p : actionSet) {
599 236278 : p->deactivate();
600 : }
601 :
602 : // for optimization, an "active" flag remains false if no action at all is active
603 31468 : active=false;
604 113722 : for(unsigned i=0; i<pilots.size(); ++i) {
605 82254 : if(pilots[i]->onStep()) {
606 73651 : pilots[i]->activate();
607 73651 : active=true;
608 : }
609 : };
610 :
611 : // also, if one of them is the total energy, tell to atoms that energy should be collected
612 267746 : for(const auto & p : actionSet) {
613 236278 : if(p->isActive()) {
614 190097 : if(p->checkNeedsGradients()) p->setOption("GRADIENTS");
615 : }
616 : }
617 :
618 31468 : stopwatch.stop("1 Prepare dependencies");
619 31468 : }
620 :
621 31300 : void PlumedMain::shareData() {
622 : // atom positions are shared (but only if there is something to do)
623 62600 : if(!active)return;
624 29812 : stopwatch.start("2 Sharing data");
625 29812 : if(atoms.getNatoms()>0) atoms.share();
626 29812 : stopwatch.stop("2 Sharing data");
627 : }
628 :
629 260 : void PlumedMain::performCalcNoUpdate() {
630 260 : waitData();
631 260 : justCalculate();
632 260 : backwardPropagate();
633 260 : }
634 :
635 31040 : void PlumedMain::performCalc() {
636 31040 : waitData();
637 31040 : justCalculate();
638 31040 : backwardPropagate();
639 31040 : update();
640 31040 : }
641 :
642 31384 : void PlumedMain::waitData() {
643 62768 : if(!active)return;
644 29896 : stopwatch.start("3 Waiting for data");
645 29896 : if(atoms.getNatoms()>0) atoms.wait();
646 29896 : stopwatch.stop("3 Waiting for data");
647 : }
648 :
649 31384 : void PlumedMain::justCalculate() {
650 62768 : if(!active)return;
651 29896 : stopwatch.start("4 Calculating (forward loop)");
652 29896 : bias=0.0;
653 29896 : work=0.0;
654 :
655 29896 : int iaction=0;
656 : // calculate the active actions in order (assuming *backward* dependence)
657 256985 : for(const auto & p : actionSet) {
658 227089 : if(p->isActive()) {
659 189455 : std::string actionNumberLabel;
660 189455 : if(detailedTimers) {
661 0 : Tools::convert(iaction,actionNumberLabel);
662 0 : actionNumberLabel="4A "+actionNumberLabel+" "+p->getLabel();
663 0 : stopwatch.start(actionNumberLabel);
664 : }
665 189455 : ActionWithValue*av=dynamic_cast<ActionWithValue*>(p);
666 189455 : ActionAtomistic*aa=dynamic_cast<ActionAtomistic*>(p);
667 : {
668 189455 : if(av) av->clearInputForces();
669 189455 : if(av) av->clearDerivatives();
670 : }
671 : {
672 189455 : if(aa) aa->clearOutputForces();
673 189455 : if(aa) if(aa->isActive()) aa->retrieveAtoms();
674 : }
675 189455 : if(p->checkNumericalDerivatives()) p->calculateNumericalDerivatives();
676 188913 : else p->calculate();
677 : // This retrieves components called bias
678 189455 : if(av) bias+=av->getOutputQuantity("bias");
679 189455 : if(av) work+=av->getOutputQuantity("work");
680 189455 : if(av)av->setGradientsIfNeeded();
681 189455 : ActionWithVirtualAtom*avv=dynamic_cast<ActionWithVirtualAtom*>(p);
682 189455 : if(avv)avv->setGradientsIfNeeded();
683 189455 : if(detailedTimers) stopwatch.stop(actionNumberLabel);
684 : }
685 227089 : iaction++;
686 : }
687 29896 : stopwatch.stop("4 Calculating (forward loop)");
688 : }
689 :
690 0 : void PlumedMain::justApply() {
691 0 : backwardPropagate();
692 0 : update();
693 0 : }
694 :
695 31300 : void PlumedMain::backwardPropagate() {
696 62600 : if(!active)return;
697 29812 : int iaction=0;
698 29812 : stopwatch.start("5 Applying (backward loop)");
699 : // apply them in reverse order
700 256079 : for(auto pp=actionSet.rbegin(); pp!=actionSet.rend(); ++pp) {
701 226267 : const auto & p(*pp);
702 226267 : if(p->isActive()) {
703 :
704 188813 : std::string actionNumberLabel;
705 188813 : if(detailedTimers) {
706 0 : Tools::convert(iaction,actionNumberLabel);
707 0 : actionNumberLabel="5A "+actionNumberLabel+" "+p->getLabel();
708 0 : stopwatch.start(actionNumberLabel);
709 : }
710 :
711 188813 : p->apply();
712 188813 : ActionAtomistic*a=dynamic_cast<ActionAtomistic*>(p);
713 : // still ActionAtomistic has a special treatment, since they may need to add forces on atoms
714 188813 : if(a) a->applyForces();
715 :
716 188813 : if(detailedTimers) stopwatch.stop(actionNumberLabel);
717 : }
718 226267 : iaction++;
719 : }
720 :
721 : // this is updating the MD copy of the forces
722 29812 : if(detailedTimers) stopwatch.start("5B Update forces");
723 29812 : if(atoms.getNatoms()>0) atoms.updateForces();
724 29812 : if(detailedTimers) stopwatch.stop("5B Update forces");
725 29812 : stopwatch.stop("5 Applying (backward loop)");
726 : }
727 :
728 31050 : void PlumedMain::update() {
729 62100 : if(!active)return;
730 :
731 29562 : stopwatch.start("6 Update");
732 : // update step (for statistics, etc)
733 29562 : updateFlags.push(true);
734 253969 : for(const auto & p : actionSet) {
735 224407 : p->beforeUpdate();
736 224407 : if(p->isActive() && p->checkUpdate() && updateFlagsTop()) p->update();
737 : }
738 29562 : while(!updateFlags.empty()) updateFlags.pop();
739 29562 : if(!updateFlags.empty()) plumed_merror("non matching changes in the update flags");
740 : // Check that no action has told the calculation to stop
741 29562 : if(stopNow) {
742 36 : if(stopFlag) (*stopFlag)=1;
743 0 : else plumed_merror("your md code cannot handle plumed stop events - add a call to plumed.comm(stopFlag,stopCondition)");
744 : }
745 :
746 : // flush by default every 10000 steps
747 : // hopefully will not affect performance
748 : // also if receive checkpointing signal
749 29562 : if(step%10000==0||doCheckPoint) {
750 648 : fflush();
751 648 : log.flush();
752 648 : for(const auto & p : actionSet) p->fflush();
753 : }
754 29562 : stopwatch.stop("6 Update");
755 : }
756 :
757 2 : void PlumedMain::load(const std::string& ss) {
758 2 : if(DLLoader::installed()) {
759 2 : std::string s=ss;
760 2 : size_t n=s.find_last_of(".");
761 4 : std::string extension="";
762 4 : std::string base=s;
763 2 : if(n!=std::string::npos && n<s.length()-1) extension=s.substr(n+1);
764 2 : if(n!=std::string::npos && n<s.length()) base=s.substr(0,n);
765 2 : if(extension=="cpp") {
766 : // full path command, including environment setup
767 : // this will work even if plumed is not in the execution path or if it has been
768 : // installed with a name different from "plumed"
769 2 : std::string cmd=config::getEnvCommand()+" \""+config::getPlumedRoot()+"\"/scripts/mklib.sh "+s;
770 2 : log<<"Executing: "<<cmd;
771 2 : if(comm.Get_size()>0) log<<" (only on master node)";
772 2 : log<<"\n";
773 2 : if(comm.Get_rank()==0) system(cmd.c_str());
774 2 : comm.Barrier();
775 2 : base="./"+base;
776 : }
777 2 : s=base+"."+config::getSoExt();
778 2 : void *p=dlloader.load(s);
779 2 : if(!p) {
780 1 : const std::string error_msg="I cannot load library " + ss + " " + dlloader.error();
781 1 : log<<"ERROR\n";
782 1 : log<<error_msg<<"\n";
783 1 : plumed_merror(error_msg);
784 : }
785 1 : log<<"Loading shared library "<<s.c_str()<<"\n";
786 1 : log<<"Here is the new list of available actions\n";
787 3 : log<<actionRegister();
788 0 : } else plumed_merror("loading not enabled, please recompile with -D__PLUMED_HAS_DLOPEN");
789 1 : }
790 :
791 848 : double PlumedMain::getBias() const {
792 848 : return bias;
793 : }
794 :
795 450 : double PlumedMain::getWork() const {
796 450 : return work;
797 : }
798 :
799 39 : FILE* PlumedMain::fopen(const char *path, const char *mode) {
800 39 : std::string mmode(mode);
801 78 : std::string ppath(path);
802 78 : std::string suffix(getSuffix());
803 78 : std::string ppathsuf=ppath+suffix;
804 39 : FILE*fp=std::fopen(const_cast<char*>(ppathsuf.c_str()),const_cast<char*>(mmode.c_str()));
805 39 : if(!fp) fp=std::fopen(const_cast<char*>(ppath.c_str()),const_cast<char*>(mmode.c_str()));
806 39 : plumed_massert(fp,"file " + ppath + " cannot be found");
807 78 : return fp;
808 : }
809 :
810 39 : int PlumedMain::fclose(FILE*fp) {
811 39 : return std::fclose(fp);
812 : }
813 :
814 1917 : std::string PlumedMain::cite(const std::string&item) {
815 1917 : return citations.cite(item);
816 : }
817 :
818 1101 : void PlumedMain::fflush() {
819 3489 : for(const auto & p : files) {
820 2388 : p->flush();
821 : }
822 1101 : }
823 :
824 3305 : void PlumedMain::insertFile(FileBase&f) {
825 3305 : files.insert(&f);
826 3305 : }
827 :
828 3520 : void PlumedMain::eraseFile(FileBase&f) {
829 3520 : files.erase(&f);
830 3520 : }
831 :
832 35 : void PlumedMain::stop() {
833 35 : stopNow=true;
834 35 : }
835 :
836 515 : void PlumedMain::runJobsAtEndOfCalculation() {
837 5472 : for(const auto & p : actionSet) {
838 4957 : p->runFinalJobs();
839 : }
840 515 : }
841 :
842 4821 : }
843 :
844 : //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|