OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
Main.cpp
Go to the documentation of this file.
1//
2// Copyright (c) 2008 - 2020, Paul Scherrer Institut, Villigen PSI, Switzerland
3//
4// All rights reserved
5//
6// This file is part of OPAL.
7//
8// OPAL is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12//
13// You should have received a copy of the GNU General Public License
14// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
15//
16#include "opal.h"
17
18#include "H5hut.h"
19
23#include "Parser/FileStream.h"
24#include "Utilities/Timer.h"
25#include "Fields/Fieldmap.h"
26#include "FixedAlgebra/FTps.h"
27
28#include "BasicActions/Option.h"
29#include "Utilities/Options.h"
32#include "Utilities/Util.h"
33
35
36#include "OPALconfig.h"
37
38#ifdef ENABLE_AMR
39#include <AMReX_ParallelDescriptor.H>
40#endif
41
42// IPPL
43#include "Message/Communicate.h"
44#include "Utility/Inform.h"
46#include "Utility/IpplInfo.h"
47#include "Utility/IpplTimings.h"
48#include "GSLErrorHandling.h"
49
50#include <gsl/gsl_errno.h>
51
52#include <boost/system/error_code.hpp>
53
54#include <cstring>
55#include <filesystem>
56#include <iomanip>
57#include <iostream>
58#include <set>
59
60// ippl and gmsg need to be defined within the python module (these global
61// objects are shared across several python modules (dynamically loaded libs).
62// if we are using non-python OPAL, they are defined here, else they are defined
63// in PyOpal::Globals
64#ifdef DONT_DEFINE_IPPL_GMSG
65 extern Ippl *ippl;
66 extern Inform *gmsg;
67 extern Inform *gmsgALL;
68#else
72#endif
73
74namespace {
75 void printStdoutHeader() {
76 OPALTimer::Timer simtimer;
77 std::string dateStr(simtimer.date());
78 std::string timeStr(simtimer.time());
79 std::string mySpace(" ");
80
81 *gmsg << mySpace << " ____ _____ ___ " << endl;
82 *gmsg << mySpace << " / __ \\| __ \\ /\\ | | " << endl;
83 *gmsg << mySpace << " | | | | |__) / \\ | |" << endl;
84 *gmsg << mySpace << " | | | | ___/ /\\ \\ | |" << endl ;
85 *gmsg << mySpace << " | |__| | | / ____ \\| |____" << endl;
86 *gmsg << mySpace << " \\____/|_| /_/ \\_\\______|" << endl;
87
88 std::string gitRevision = "git rev. " + Util::getGitRevision();
89 std::string copyRight = "(c) PSI, http://amas.web.psi.ch";
90 *gmsg << endl
91 << "This is OPAL (Object Oriented Parallel Accelerator Library) Version " << OPAL_PROJECT_VERSION << "\n"
92 << std::setw(37 + gitRevision.length() / 2) << std::right << gitRevision << "\n\n" << endl
93 << std::setw(37 + copyRight.length() / 2) << std::right << copyRight << "\n\n" << endl
94 << "The optimiser (former opt-Pilot) is integrated " << endl
95 << endl;
96
97 *gmsg << "Please send cookies, goodies or other motivations (wine and beer ... ) \nto the OPAL developers " << PACKAGE_BUGREPORT << "\n" << endl;
98 *gmsg << "Time: " << timeStr << " date: " << dateStr << "\n" << endl;
99 }
100
101 void printHelp() {
102 ::printStdoutHeader();
103
104 INFOMSG("\n");
105 INFOMSG("Usage: opal [<option> <option> ...]\n");
106 INFOMSG(" The possible values for <option> are:\n");
107 INFOMSG(" --version : Print the version of opal.\n");
108 INFOMSG(" --version-full : Print the version of opal with additional informations.\n");
109 INFOMSG(" --git-revision : Print the revision hash of the repository.\n");
110 INFOMSG(" --input <fname> : Specifies the input file <fname>.\n");
111 INFOMSG(" --restart <n> : Performes a restart from step <n>.\n");
112 INFOMSG(" --restartfn <fname> : Uses the file <fname> to restart from.\n");
113#ifdef ENABLE_AMR
114 INFOMSG(" --noInitAMR : Disable initialization of AMR\n");
115#endif
117 INFOMSG(" --help-command <command> : Display the help for the command <command>\n");
118 INFOMSG(" --help : Display this command-line summary.\n");
119 INFOMSG(endl);
120 }
121}
122
123
124bool checkInitAmrFlag(int argc, char* argv[]) {
125 std::string noamr = "noInitAMR";
126 bool initAMR = true;
127 for (int i = 0; i < argc; ++i) {
128 std::string sargv = std::string(argv[i]);
129 if ( sargv.find(noamr) != std::string::npos ) {
130 initAMR = false;
131 break;
132 }
133 }
134 return initAMR;
135}
136
137int opalMain(int argc, char *argv[]);
138
139int main(int argc, char *argv[]) {
140 // python has its own main function that can interfere with opal main;
141 // so when calling from python we call opalMain instead
142 new Ippl(argc, argv);
143 gmsg = new Inform("OPAL");
144 gmsgALL = new Inform("OPAL", INFORM_ALL_NODES);
145 return opalMain(argc, argv);
146}
147
148int opalMain(int argc, char *argv[]) {
149
150 namespace fs = std::filesystem;
151
152#ifdef ENABLE_AMR
153 bool initAMR = checkInitAmrFlag(argc, argv);
154 if ( initAMR ) {
155 // false: build no parmparse, we use the OPAL parser instead.
156 amrex::Initialize(argc, argv, false, Ippl::getComm());
157 }
158#endif
159
160 H5SetVerbosityLevel(1); //65535);
161
162 gsl_set_error_handler(&handleGSLErrors);
163
164 static IpplTimings::TimerRef mainTimer = IpplTimings::getTimer("mainTimer");
165 IpplTimings::startTimer(mainTimer);
166
167
168 if(Ippl::myNode() == 0) remove("errormsg.txt");
169
170 const OpalParser parser;
171
172 std::cout.precision(16);
173 std::cout.setf(std::ios::scientific, std::ios::floatfield);
174 std::cerr.precision(16);
175 std::cerr.setf(std::ios::scientific, std::ios::floatfield);
176
177 // Set global truncation orders.
181
183
184 /*
185 Make a directory data for some of the output
186 */
187 if(Ippl::myNode() == 0) {
188 if (!fs::exists(opal->getAuxiliaryOutputDirectory())) {
189 std::error_code error_code;
190 if (!fs::create_directory(opal->getAuxiliaryOutputDirectory(), error_code)) {
191 std::cerr << error_code.message() << std::endl;
192 // use error code to prevent create_directory from throwing an exception
193 }
194 }
195 }
196 Ippl::Comm->barrier();
197 if (!fs::is_directory(opal->getAuxiliaryOutputDirectory())) {
198 std::cerr << "unable to create directory; aborting" << std::endl;
199 abort();
200 }
201
202 opal->storeArguments(argc, argv);
203 try {
205
206 // Read startup file.
208
209 char *startup = getenv("HOME");
210 std::filesystem::path p = strncat(startup, "/init.opal", 20);
211 if (startup != nullptr && is_regular_file(p)) {
212
213 FileStream::setEcho(false);
214 FileStream *is;
215
216 try {
217 is = new FileStream(startup);
218 } catch(...) {
219 is = 0;
220 ERRORMSG("Could not open startup file '" << startup << "'\n"
221 << "Note: this is not mandatory for an OPAL simulation!\n");
222 }
223
224 if(is) {
225 *gmsg << "Reading startup file '" << startup << "'" << endl;
226 parser.run(is);
227 *gmsg << "Finished reading startup file." << endl;
228 }
230 } else {
231 *gmsg << level5
232 << "Couldn't find startup file '" << startup << "'\n"
233 << "Note: this is not mandatory for an OPAL simulation!\n" << endl;
234 }
235
236 if(argc <= 1) {
237 ::printHelp();
238 exit(1);
239 }
240 int inputFileArgument = -1;
241 std::string fname;
242 std::string restartFileName;
243
244 for(int ii = 1; ii < argc; ++ ii) {
245 std::string argStr = std::string(argv[ii]);
246 if (argStr == std::string("-h") ||
247 argStr == std::string("-help") ||
248 argStr == std::string("--help")) {
249 ::printHelp();
250 exit(0);
251 } else if (argStr == std::string("--help-command")) {
252 if (argc < ii + 2) {
253 ::printHelp();
254 exit(1);
255 }
256 ::printStdoutHeader();
257 const std::string cmdName = Util::toUpper(argv[ii + 1]);
258 Object *object = OpalData::getInstance()->find(cmdName);
259
260 if(object == 0) {
261 *gmsg << "\nOpalParser::printHelp(): Unknown object \""
262 << cmdName << "\".\n" << endl;
263 exit(1);
264 }
265
266 object->printHelp(std::cout);
267 exit(0);
268 } else if (argStr == std::string("--version")) {
269 if (Ippl::myNode() == 0) {
270 std::cout << OPAL_PROJECT_VERSION << std::endl;
271 }
272 exit(0);
273 } else if (argStr == std::string("--version-full")) {
274 ::printStdoutHeader();
275 INFOMSG("OPAL Version " << OPAL_PROJECT_VERSION << ", git rev. " << Util::getGitRevision() << endl);
277 std::string options = (IpplInfo::compileOptions() +
278 std::string(" ") +
279 std::string(OPAL_COMPILE_OPTIONS) +
280 std::string(" "));
281 std::set<std::string> uniqOptions;
282 while (options.length() > 0) {
283 size_t n = options.find_first_of(' ');
284 while (n == 0) {
285 options = options.substr(n + 1);
286 n = options.find_first_of(' ');
287 }
288
289 uniqOptions.insert(options.substr(0, n));
290 options = options.substr(n + 1);
291 }
292 for (auto it: uniqOptions) {
293 options += it + " ";
294 }
295
296 std::string header("Compile-time options: ");
297 while (options.length() > 58) {
298 std::string line = options.substr(0, 58);
299 size_t n = line.find_last_of(' ');
300 INFOMSG(header << line.substr(0, n) << "\n");
301
302 header = std::string(22, ' ');
303 options = options.substr(n + 1);
304 }
305 INFOMSG(header << options << endl);
306 exit(0);
307 } else if (argStr == std::string("--git-revision")) {
308 if (Ippl::myNode() == 0) {
309 std::cout << Util::getGitRevision() << std::endl;
310 }
311 exit(0);
312 } else if (argStr == std::string("--input")) {
313 ++ ii;
314 inputFileArgument = ii;
315 continue;
316 } else if (argStr == std::string("-restart") ||
317 argStr == std::string("--restart")) {
318 opal->setRestartRun();
319 opal->setRestartStep(atoi(argv[++ ii]));
320 continue;
321 } else if (argStr == std::string("-restartfn") ||
322 argStr == std::string("--restartfn")) {
323 restartFileName = std::string(argv[++ ii]);
324 continue;
325 } else if ( argStr.find("noInitAMR") != std::string::npos) {
326 // do nothing here
327 } else {
328 if (inputFileArgument == -1 &&
329 (ii == 1 || ii + 1 == argc) &&
330 argv[ii][0] != '-') {
331 inputFileArgument = ii;
332 continue;
333 } else {
334 INFOMSG("Unknown argument \"" << argStr << "\"" << endl);
335 ::printHelp();
336 exit(1);
337 }
338 }
339 }
340
341 ::printStdoutHeader();
342 if (inputFileArgument == -1) {
343 INFOMSG("No input file provided!" << endl);
344 exit(1);
345 }
346
347 fname = std::string(argv[inputFileArgument]);
348 if (!fs::exists(fname)) {
349 INFOMSG("Input file '" << fname << "' doesn't exist!" << endl);
350 exit(1);
351 }
352
353 opal->storeInputFn(fname);
354
355 if (opal->inRestartRun()) {
356 if (restartFileName.empty()) {
357 restartFileName = opal->getInputBasename() + std::string(".h5");
358 }
359 if (!fs::exists(restartFileName)) {
360 INFOMSG("Restart file '" << restartFileName << "' doesn't exist!" << endl);
361 exit(1);
362 }
363 opal->setRestartFileName(restartFileName);
364 }
365
366 FileStream *is;
367
368 try {
369 is = new FileStream(fname);
370 } catch(...) {
371 is = 0;
372 *gmsg << "Input file '" << fname << "' not found." << endl;
373 }
374
375 if(is) {
376 *gmsg << "* Reading input stream '" << fname << "'" << endl;
377 parser.run(is);
378 *gmsg << "* End of input stream '" << fname << "'" << endl;
379 }
380
381 if(Ippl::myNode() == 0) {
382 std::ifstream errormsg("errormsg.txt");
383 if(errormsg.good()) {
384 char buffer[256];
385 std::string closure(" *\n");
386 ERRORMSG("\n"
387 << "* **********************************************************************************\n"
388 << "* ************** W A R N I N G / E R R O R * * M E S S A G E S *********************\n"
389 << "* **********************************************************************************"
390 << endl);
391 errormsg.getline(buffer, 256);
392 while(errormsg.good()) {
393 ERRORMSG("* ");
394 if(errormsg.gcount() == 1) {
395 ERRORMSG(closure);
396 } else if ((size_t)errormsg.gcount() <= closure.size()) {
397 ERRORMSG(buffer << closure.substr(errormsg.gcount() - 1));
398 } else {
399 ERRORMSG(buffer << endl);
400 }
401 errormsg.getline(buffer, 256);
402 }
403 ERRORMSG("* " << closure
404 << "* **********************************************************************************\n"
405 << "* **********************************************************************************"
406 << endl);
407 }
408 errormsg.close();
409 }
410
411 } catch(EarlyLeaveException& ex) {
412 // do nothing here
413 } catch(OpalException &ex) {
414 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
415 errorMsg << "\n*** User error detected by function \""
416 << ex.where() << "\"\n";
417 // stat->printWhere(errorMsg, true);
418 std::string what = ex.what();
419 size_t pos = what.find_first_of('\n');
420 do {
421 errorMsg << " " << what.substr(0, pos) << endl;
422 what = what.substr(pos + 1, std::string::npos);
423 pos = what.find_first_of('\n');
424 } while (pos != std::string::npos);
425 errorMsg << " " << what << endl;
426
427 MPI_Abort(MPI_COMM_WORLD, -100);
428 } catch(ClassicException &ex) {
429 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
430 errorMsg << "\n*** User error detected by function \""
431 << ex.where() << "\"\n";
432 // stat->printWhere(errorMsg, true);
433 std::string what = ex.what();
434 size_t pos = what.find_first_of('\n');
435 do {
436 errorMsg << " " << what.substr(0, pos) << endl;
437 what = what.substr(pos + 1, std::string::npos);
438 pos = what.find_first_of('\n');
439 } while (pos != std::string::npos);
440 errorMsg << " " << what << endl;
441
442 MPI_Abort(MPI_COMM_WORLD, -100);
443 } catch(SDDSParserException &ex) {
444 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
445
446 errorMsg << "\n*** Error detected by function \""
447 << ex.where() << "\"\n";
448 std::string what = ex.what();
449 size_t pos = what.find_first_of('\n');
450 do {
451 errorMsg << " " << what.substr(0, pos) << endl;
452 what = what.substr(pos + 1, std::string::npos);
453 pos = what.find_first_of('\n');
454 } while (pos != std::string::npos);
455 errorMsg << " " << what << endl;
456
457 MPI_Abort(MPI_COMM_WORLD, -100);
458 } catch(IpplException &ex) {
459 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
460
461 errorMsg << "\n*** Error detected by function \""
462 << ex.where() << "\"\n";
463 std::string what = ex.what();
464 size_t pos = what.find_first_of('\n');
465 do {
466 errorMsg << " " << what.substr(0, pos) << endl;
467 what = what.substr(pos + 1, std::string::npos);
468 pos = what.find_first_of('\n');
469 } while (pos != std::string::npos);
470 errorMsg << " " << what << endl;
471
472 MPI_Abort(MPI_COMM_WORLD, -100);
473 } catch(std::bad_alloc &ex) {
474 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
475 errorMsg << "\n*** Error:\n";
476 errorMsg << " Sorry, virtual memory exhausted.\n"
477 << ex.what()
478 << endl;
479
480 MPI_Abort(MPI_COMM_WORLD, -100);
481 } catch(assertion &ex) {
482 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
483 errorMsg << "\n*** Runtime-error ******************\n";
484 std::string what = ex.what();
485 size_t pos = what.find_first_of('\n');
486 do {
487 errorMsg << " " << what.substr(0, pos) << endl;
488 what = what.substr(pos + 1, std::string::npos);
489 pos = what.find_first_of('\n');
490 } while (pos != std::string::npos);
491 errorMsg << " " << what << endl;
492
493 errorMsg << "\n************************************\n" << endl;
494 throw std::runtime_error("in Parser");
495 } catch(std::exception &ex) {
496 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
497 errorMsg << "\n"
498 << "*** Error:\n"
499 << " Internal OPAL error: \n";
500 std::string what = ex.what();
501 size_t pos = what.find_first_of('\n');
502 do {
503 errorMsg << " " << what.substr(0, pos) << endl;
504 what = what.substr(pos + 1, std::string::npos);
505 pos = what.find_first_of('\n');
506 } while (pos != std::string::npos);
507 errorMsg << " " << what << endl;
508
509 MPI_Abort(MPI_COMM_WORLD, -100);
510 } catch(...) {
511 Inform errorMsg("Error", std::cerr, INFORM_ALL_NODES);
512 errorMsg << "\n*** Error:\n"
513 << " Unexpected exception caught.\n" << endl;
514
515 MPI_Abort(MPI_COMM_WORLD, -100);
516 }
517
518
519 IpplTimings::stopTimer(mainTimer);
520
522
523 IpplTimings::print(std::string("timing.dat"),
524 OpalData::getInstance()->getProblemCharacteristicValues());
525
526 Ippl::Comm->barrier();
529 delete gmsg;
530
531#ifdef ENABLE_AMR
532 if ( initAMR ) {
533 amrex::Finalize(true);
534 }
535#endif
536
537 delete ippl;
538 delete Ippl::Info;
539 delete Ippl::Warn;
540 delete Ippl::Error;
541 delete Ippl::Debug;
542
543 return 0;
544}
Inform * gmsgALL
Definition Main.cpp:71
Inform * gmsg
Definition Main.cpp:70
int opalMain(int argc, char *argv[])
Definition Main.cpp:148
int main(int argc, char *argv[])
Definition Main.cpp:139
Ippl * ippl
Definition Main.cpp:69
bool checkInitAmrFlag(int argc, char *argv[])
Definition Main.cpp:124
void handleGSLErrors(const char *reason, const char *file, int, int)
Inform & endl(Inform &inf)
Definition Inform.cpp:42
Inform & level5(Inform &inf)
Definition Inform.cpp:49
#define INFORM_ALL_NODES
Definition Inform.h:39
#define ERRORMSG(msg)
Definition IpplInfo.h:350
IpplInfo Ippl
Definition IpplInfo.h:353
#define INFOMSG(msg)
Definition IpplInfo.h:348
bool echo
Echo flag.
Definition Options.cpp:26
std::string toUpper(const std::string &str)
Definition Util.cpp:147
std::string getGitRevision()
Definition Util.cpp:33
void configure()
Configure all commands.
The base class for all OPAL objects.
Definition Object.h:48
virtual void printHelp(std::ostream &) const
Print help.
Definition Object.cpp:201
The global OPAL structure.
Definition OpalData.h:49
void storeInputFn(const std::string &fn)
store opals input filename
Definition OpalData.cpp:654
std::string getInputBasename()
get input file name without extension
Definition OpalData.cpp:674
void setRestartRun(const bool &value=true)
set OPAL in restart mode
Definition OpalData.cpp:316
Object * find(const std::string &name)
Find entry.
Definition OpalData.cpp:571
static void deleteInstance()
Definition OpalData.cpp:206
void setRestartFileName(std::string s)
store opals restart h5 format filename
Definition OpalData.cpp:332
static OpalData * getInstance()
Definition OpalData.cpp:196
void storeArguments(int argc, char *argv[])
Definition OpalData.cpp:768
void setRestartStep(int s)
store the location where to restart
Definition OpalData.cpp:320
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:666
bool inRestartRun()
true if we do a restart run
Definition OpalData.cpp:312
static void clearDictionary()
Definition Fieldmap.cpp:274
static void setGlobalTruncOrder(int order)
Set the global truncation order.
Definition FTps.hpp:419
A stream of input tokens.
Definition FileStream.h:32
static void setEcho(bool flag)
Set echo flag.
The abstract base class for all exceptions in CLASSIC.
The default parser for OPAL-9.
Definition OpalParser.h:44
virtual void run() const
Read current stream.
virtual const std::string & what() const
Return the message string for the exception.
virtual const std::string & where() const
Return the name of the method or function which detected the exception.
The base class for all OPAL exceptions.
std::string date() const
Return date.
std::string time() const
Return time.
static void printVersion(void)
Definition IpplInfo.cpp:736
static Inform * Warn
Definition IpplInfo.h:79
static void printHelp()
Definition IpplInfo.cpp:744
static Inform * Info
Definition IpplInfo.h:78
static Inform * Error
Definition IpplInfo.h:80
static MPI_Comm getComm()
Definition IpplInfo.h:152
static Inform * Debug
Definition IpplInfo.h:81
static int myNode()
Definition IpplInfo.cpp:691
static Communicate * Comm
Definition IpplInfo.h:84
static const char * compileOptions()
Definition IpplInfo.cpp:836
Timing::TimerRef TimerRef
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static void print()
static void startTimer(TimerRef t)