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