40 #include "ac/getopt.h"
44 #ifdef HAVE_SYS_TIMES_H
45 #include <sys/times.h>
52 static void __attribute__ ((constructor))
57 feenableexcept(FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW);
63 MPI::Intracomm MBDynComm = MPI::COMM_SELF;
66 std::list<MPI::Intercomm> InterfaceComms;
70 #define MB_EXIT(what, err) \
72 if (mbp.using_mpi) { \
73 External::SendClose(); \
74 if ((err) != EXIT_SUCCESS) { \
75 MBDynComm.Abort((err)); \
82 #else // !USE_EXTERNAL
84 #define MB_EXIT(what, err) \
86 if (mbp.using_mpi) { \
87 if ((err) != EXIT_SUCCESS) { \
88 MBDynComm.Abort((err)); \
94 #endif // !USE_EXTERNAL
97 #define MB_EXIT(what, err) \
104 void *rtmbdyn_rtai_task = NULL;
107 #include <sys/stat.h>
109 #define PATH_MAX 4096
113 #define _GNU_SOURCE 1
115 #endif // HAVE_FENV_H
162 int parallel_fSilent;
163 int parallel_fPedantic;
166 #else // ! HAVE_GETPID
168 #endif // ! HAVE_GETPID
174 const debug_array da[] = {
181 {
"fnames", MYDEBUG_FNAMES },
182 #if defined(__GNUC__)
183 {
"prettyfn", MYDEBUG_FNAMES|MYDEBUG_PRETTYFN },
192 { NULL, MYDEBUG_NONE }
199 silent_cout(std::endl
200 <<
"MBDyn - MultiBody Dynamics " << VERSION << std::endl
201 <<
"configured on " << __DATE__ <<
" at " << __TIME__
207 mbdyn_usage(
const char *sShortOpts)
210 silent_cout(std::endl
211 <<
"mbdyn is a multibody simulation program." << std::endl
213 <<
"usage: mbdyn [" << sShortOpts <<
"] [input-file list] " << std::endl
215 <<
" -f, --input-file {file} reads from 'file' instead of stdin" << std::endl
216 <<
" -o, --output-file {file} writes to '{file}.<ext>'" << std::endl
217 <<
" instead of '{input-file}.<ext>'" << std::endl
218 <<
" (or 'Mbdyn.<ext>' when input from stdin)" << std::endl
222 " -d, --debug {level[:level[...]]} when using the debug version of the code," << std::endl
223 <<
" enables debug levels; available:" << std::endl
224 <<
" none" << std::endl);
225 for (
int i = 0; da[i].s != NULL; i++) {
227 " " << da[i].s << std::endl);
230 " any" << std::endl);
233 " -e, --exceptions don't trap exceptions to ease debugging" << std::endl
234 <<
" -E, --fp-mask[=...] enable some floating point checks" << std::endl
235 <<
" -h, --help prints this message" << std::endl
236 <<
" -H, --show-table print symbol table and exit" << std::endl
237 <<
" -l, --license prints the licensing terms" << std::endl
244 " -p, --parallel required when run in parallel (invoked by mpirun)" << std::endl);
247 " -P, --pedantic pedantic warning messages (more p's: noisier)" << std::endl
248 <<
" -r, --redefine" << std::endl
249 <<
" -R, --no-redefine redefine/don't redefine symbols in table" << std::endl
250 <<
" -s, --silent runs quietly (more s': quieter)" << std::endl
251 <<
" -S, --sleep [rank={n}] {time} sleep {time} (on process {n}) before" << std::endl
252 <<
" starting the analysis" << std::endl
253 <<
" -t, --same-table" << std::endl
254 <<
" -T, --no-same-table use/don't use same symbol table for multiple runs" << std::endl
255 <<
" -v, --version show version and exit" << std::endl
256 <<
" -w, --warranty prints the warranty conditions" << std::endl
257 <<
" -W, --working-dir {dir} sets the working directory" << std::endl
259 <<
"Usually mbdyn reads the input from stdin and writes messages on stdout; a log" << std::endl
260 <<
"is put in '{file}.out', and data output is sent to various '{file}.<ext>'" << std::endl
261 <<
"files ('Mbdyn.<ext>' if input from stdin)" << std::endl
270 silent_cout(std::endl
271 <<
"Copyright 1996-2017 (C) Paolo Mantegazza "
272 "and Pierangelo Masarati," << std::endl
273 <<
"Dipartimento di Ingegneria Aerospaziale "
274 "<http://www.aero.polimi.it/>" << std::endl
275 <<
"Politecnico di Milano "
276 "<http://www.polimi.it/>" << std::endl
278 <<
"MBDyn is free software, covered by the"
279 " GNU General Public License," << std::endl
280 <<
"and you are welcome to change it and/or "
281 "distribute copies of it" << std::endl
282 <<
"under certain conditions. Use 'mbdyn --license' "
283 "to see the conditions." << std::endl
284 <<
"There is absolutely no warranty for"
285 " MBDyn. Use \"mbdyn --warranty\"" << std::endl
286 <<
"for details." << std::endl
291 static char sShortOpts[] =
"d:eE::f:hHlN:o:pPrRsS:tTvwW:";
293 #ifdef HAVE_GETOPT_LONG
294 static struct option LongOpts[] = {
295 {
"debug", required_argument, NULL,
int(
'd') },
296 {
"exceptions", no_argument, NULL,
int(
'e') },
297 {
"fp-mask", optional_argument, NULL,
int(
'E') },
298 {
"input-file", required_argument, NULL,
int(
'f') },
299 {
"help", no_argument, NULL,
int(
'h') },
300 {
"show-table", no_argument, NULL,
int(
'H') },
301 {
"license", no_argument, NULL,
int(
'l') },
302 {
"threads", required_argument, NULL,
int(
'N') },
303 {
"output-file", required_argument, NULL,
int(
'o') },
304 {
"parallel", no_argument, NULL,
int(
'p') },
305 {
"pedantic", no_argument, NULL,
int(
'P') },
306 {
"redefine", no_argument, NULL,
int(
'r') },
307 {
"no-redefine", no_argument, NULL,
int(
'R') },
308 {
"silent", no_argument, NULL,
int(
's') },
309 {
"sleep", required_argument, NULL,
int(
'S') },
310 {
"same-table", no_argument, NULL,
int(
't') },
311 {
"no-same-table", no_argument, NULL,
int(
'T') },
312 {
"version", no_argument, NULL,
int(
'v') },
313 {
"warranty", no_argument, NULL,
int(
'w') },
314 {
"working-dir", required_argument, NULL,
int(
'W') },
329 parse_parallel_args(
mbdyn_proc_t& mbp,
int argc,
char *argv[])
331 for (
int i = 1; i < argc; i++) {
332 if (!mbp.
using_mpi && strncmp(argv[i],
"-p", 2) == 0) {
338 if (strncmp(argv[i],
"-s", 2) == 0) {
339 mbp.parallel_fSilent++;
341 for (
unsigned j = 2; argv[i][j] ==
's'; j++) {
342 mbp.parallel_fSilent++;
345 }
else if (strncmp(argv[i],
"-P", 2) == 0) {
346 mbp.parallel_fPedantic++;
348 for (
unsigned j = 2; argv[i][j] ==
'P'; j++) {
349 mbp.parallel_fPedantic++;
371 #ifdef HAVE_GETOPT_LONG
372 int iCurrOpt = getopt_long(argc, argv, sShortOpts,
373 LongOpts, &iIndexPtr);
375 int iCurrOpt =
getopt(argc, argv, sShortOpts);
378 if (iCurrOpt == EOF) {
385 if (get_debug_options(
optarg, da)) {
386 silent_cerr(
"Unable to interpret debug"
388 " using default" << std::endl);
389 ::debug_level = DEFAULT_DEBUG_LEVEL;
393 silent_cerr(
"Compile with '-DDEBUG'"
394 " to use debug features" << std::endl);
403 #if defined(HAVE_FENV_H) && defined(HAVE_FEENABLEEXCEPT)
404 int excepts = FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW;
407 char *start =
optarg, *next;
409 next = strchr(start,
',');
418 if (strncasecmp(start,
"invalid", len) == 0) {
419 excepts |= FE_INVALID;
420 }
else if (strncasecmp(start,
"divbyzero", len) == 0) {
421 excepts |= FE_DIVBYZERO;
422 }
else if (strncasecmp(start,
"overflow", len) == 0) {
423 excepts |= FE_OVERFLOW;
425 silent_cerr(
"option 'E': unrecognized arg \"" << std::string(start, len) <<
"\"" << std::endl);
432 pedantic_cout(
"Option 'E': exceptions=" << excepts << std::endl);
435 feenableexcept(excepts);
436 #else // ! HAVE_FENV_H
437 silent_cerr(
"Option 'E' unsupported; ignored" << std::endl);
438 #endif // ! HAVE_FENV_H
452 silent_cerr(std::endl
453 <<
"Unable to open file \""
457 silent_cerr(
" on " << mbp.ProcessorName);
460 silent_cerr(
";" << std::endl
469 mbdyn_usage(sShortOpts);
482 if (strcmp(
optarg,
"auto") == 0) {
487 long n = strtoul(
optarg, &next, 10);
488 if (next[0] !=
'\0' || next ==
optarg) {
489 silent_cerr(
"Unable to parse threads number, option \"-N " <<
optarg <<
"\"" << std::endl);
493 if (n < 1 || n >= std::numeric_limits<unsigned>::max()) {
494 silent_cerr(
"Invalid number of threads, option \"-N " << n <<
"\"" << std::endl);
506 if (getcwd(cwd,
sizeof(cwd)) == 0) {
507 silent_cerr(
"Unable to set output file: getcwd failed" << std::endl);
513 #endif // HAVE_GETCWD
523 silent_cerr(
"switch '-p' is meaningless "
524 "without MPI" << std::endl);
530 if (mbp.parallel_fPedantic > 0) {
531 mbp.parallel_fPedantic--;
549 if (mbp.parallel_fSilent > 0) {
550 mbp.parallel_fSilent--;
562 if (strncasecmp(s,
"rank=",
STRLENOF(
"rank=")) == 0) {
569 r = strtol(s, &next, 10);
570 int save_errno = errno;
571 if (next[0] !=
'\0') {
572 if (next[0] !=
',') {
573 silent_cerr(
"error in argument -S " <<
optarg << std::endl);
578 }
else if (save_errno == ERANGE) {
579 silent_cerr(
"rank=" << s <<
": overflow" << std::endl);
587 silent_cerr(
"option -S " <<
optarg <<
" valid only when --with-mpi" << std::endl);
596 int save_errno = errno;
597 if (next[0] !=
'\0') {
598 silent_cerr(
"error in argument -S " <<
optarg << std::endl);
601 }
else if (save_errno == ERANGE) {
602 silent_cerr(
"argument of -S " << s <<
" overflows" << std::endl);
634 int save_errno = errno;
635 silent_cerr(
"Error in chdir(\"" <<
optarg <<
"\") "
636 "(" << save_errno <<
": " << strerror(save_errno) <<
")"
641 silent_cerr(
"chdir() not available"
647 silent_cerr(
"Unknown option -" <<
char(
optopt) << std::endl);
648 mbdyn_usage(sShortOpts);
652 silent_cerr(std::endl
653 <<
"Unrecoverable error; aborting..."
669 std::string sNormalizedInputFileName;
670 const char *dirsep = std::strrchr(sInputFileName.c_str(),
DIR_SEP);
671 const char *dot = std::strrchr(sInputFileName.c_str(),
'.');
672 if (dot != 0 && (dirsep == 0 || dot > dirsep)) {
673 sNormalizedInputFileName = std::string(sInputFileName, 0, dot - sInputFileName.c_str());
676 sNormalizedInputFileName = sInputFileName;
680 if (sOutputFileName.empty()) {
681 if (!sInputFileName.empty()) {
682 sOutputFileName = sNormalizedInputFileName;
691 if (stat(sOutputFileName.c_str(), &s) != 0) {
692 int save_errno = errno;
695 if (save_errno != ENOENT) {
696 char *errmsg = strerror(save_errno);
698 silent_cerr(
"stat(" << sOutputFileName <<
") failed "
699 "(" << save_errno <<
": " << errmsg <<
")" << std::endl);
704 const char *
path = std::strrchr(sOutputFileName.c_str(),
DIR_SEP);
706 std::string sOutputFilePath(sOutputFileName, 0, path - sOutputFileName.c_str());
709 if (stat(sOutputFilePath.c_str(), &s) != 0) {
711 char *errmsg = strerror(save_errno);
713 silent_cerr(
"stat(" << sOutputFileName <<
") failed because "
714 "stat(" << sOutputFilePath <<
") failed "
715 "(" << save_errno <<
": " << errmsg <<
")" << std::endl);
718 }
else if (!S_ISDIR(s.st_mode)) {
719 silent_cerr(
"path to file \"" << sOutputFileName <<
"\" is invalid ("
720 "\"" << sOutputFilePath <<
"\" is not a dir)" << std::endl);
725 }
else if (S_ISDIR(s.st_mode)) {
728 if (!sInputFileName.empty()) {
733 tmpIn = sNormalizedInputFileName;
740 if (sOutputFileName[sOutputFileName.size() - 1] !=
DIR_SEP && tmpIn[0] !=
DIR_SEP) {
743 sOutputFileName += tmpIn;
750 if (getcwd(cwd,
sizeof(cwd)) == 0) {
751 silent_cerr(
"Error in getcwd()" << std::endl);
754 sOutputFileName = std::string(cwd) +
DIR_SEP + sOutputFileName;
756 #endif // HAVE_GETCWD
760 std::string sInputDir(sInputFileName.c_str(), dirsep - sInputFileName.c_str());
762 if (chdir(sInputDir.c_str())) {
763 int save_errno = errno;
764 silent_cerr(
"Error in chdir(" << sInputDir <<
") (" << save_errno <<
": " << strerror(save_errno) <<
")" << std::endl);
768 silent_cerr(
"warning: chdir(2) not available; chdir(" << sInputDir.c_str() <<
") not performed" << std::endl);
769 #endif // !HAVE_CHDIR
778 #ifndef HAVE_SYS_TIMES_H
779 const clock_t start = clock();
784 silent_cerr(
"PID=" << mbp.pid <<
" Process " << mbp.MyRank
785 <<
" (" << mbp.MyRank + 1 <<
" of " << mbp.WorldSize
786 <<
") is alive on " << mbp.ProcessorName
800 silent_cout(
"default symbol table:"
809 silent_cerr(
"sleeping " << mbp.
iSleepTime <<
"s" << std::endl);
816 if (currarg < argc) {
827 mbp.
pIn =
dynamic_cast<std::istream *
>(&std::cin);
835 silent_cout(
"reading from stdin" << std::endl);
839 silent_cout(
"reading from file \""
841 <<
"\"" << std::endl);
846 silent_cout(
"reading from file \""
848 <<
"\"" << std::endl);
851 if (++currarg == argc) {
864 silent_cerr(std::endl
865 <<
"Unable to open file "
867 " aborting..." << std::endl);
877 if (mbp.
pT == NULL) {
880 if (mbp.
pMP == NULL) {
889 #if defined(HAVE_GETCWD) && defined(HAVE_CHDIR)
891 if (getcwd(buf,
sizeof(buf)) == 0) {
892 int save_errno = errno;
893 silent_cerr(
"getcwd() failed (" << save_errno <<
": " << strerror(save_errno) <<
")" << std::endl);
896 std::string sOrigCWD(buf);
897 #endif // HAVE_GETCWD && HAVE_CHDIR
913 #if defined(HAVE_GETCWD) && defined(HAVE_CHDIR)
914 if (chdir(sOrigCWD.c_str())) {
915 int save_errno = errno;
916 silent_cerr(
"chdir(" << sOrigCWD.c_str() <<
") failed (" << save_errno <<
": " << strerror(save_errno) <<
")" << std::endl);
919 #endif // HAVE_GETCWD && HAVE_CHDIR
924 silent_cerr(
"You shouldn't be here!" << std::endl);
935 if (!mbp.
bTable || currarg == argc) {
936 if (mbp.
pMP != NULL) {
940 if (mbp.
pT != NULL) {
946 #ifdef HAVE_SYS_TIMES_H
954 ct += tmsbuf.tms_utime + tmsbuf.tms_cutime
955 + tmsbuf.tms_stime + tmsbuf.tms_cstime;
957 long clk_tck = sysconf(_SC_CLK_TCK);
959 tMils = ((ct*1000)/clk_tck)%1000;
961 char timebuf[
sizeof(
" (1000000000h 59m 59s 999ms)")];
963 size_t l =
sizeof(timebuf), n;
965 n = snprintf(s, l,
"%ld.%03ld", tSecs, tMils);
967 silent_cout(std::endl <<
"The simulation required "
968 << timebuf <<
" seconds of CPU time");
971 n = snprintf(s, l,
" (" );
976 n = snprintf(s, l,
"%ldh ", tSecs/3600);
985 "%02ldm %02lds %03ldms)",
987 (tSecs%3600)%60, tMils);
992 silent_cout(timebuf);
996 silent_cout(
" on " << mbp.ProcessorName
997 <<
" (" << mbp.MyRank + 1
998 <<
" of " << mbp.WorldSize <<
")");
1001 silent_cout(std::endl);
1004 silent_cout(std::endl <<
"Elapsed time "
1005 <<
double(clock() - start)/CLOCKS_PER_SEC <<
" seconds\n");
1014 int rc = EXIT_SUCCESS;
1033 char ProcessorName_[1024] =
"localhost";
1035 mbp.ProcessorName = ProcessorName_;
1038 mbp.parallel_fSilent = 0,
1039 mbp.parallel_fPedantic = 0;
1043 #endif // HAVE_GETPID
1054 parse_parallel_args(mbp, argc, argv);
1060 MPI::Init(argc, argv);
1061 mbp.WorldSize = MPI::COMM_WORLD.Get_size();
1062 mbp.MyRank = MPI::COMM_WORLD.Get_rank();
1064 if (mbp.MyRank > 0) {
1070 parse_parallel_args(mbp, argc, argv);
1080 int ProcessorNameLength =
sizeof(ProcessorName_);
1081 MPI::Get_processor_name(mbp.ProcessorName, ProcessorNameLength);
1083 silent_cerr(
"using MPI (explicitly required by '-p*' switch)"
1098 silent_cout(
"MBDyn terminated normally" << std::endl);
1102 silent_cout(
"MBDyn was interrupted" << std::endl);
1115 silent_cout(
"MBDyn terminated normally" << std::endl);
1118 silent_cout(
"MBDyn was interrupted" << std::endl);
1120 }
catch (std::ios::failure err) {
1121 silent_cerr(
"An IO error occurred during the execution of MBDyn (" << err.what() <<
");"
1122 " aborting... " << std::endl);
1125 silent_cerr(
"An error occurred during the execution of MBDyn;"
1126 " aborting... " << std::endl);
1143 if (::rtmbdyn_rtai_task) {
1144 (void)rtmbdyn_rt_task_delete(&::rtmbdyn_rtai_task);
1145 ::rtmbdyn_rtai_task = NULL;
1157 const std::string& sInputFileName,
1158 const std::string& sOutputFileName,
1159 unsigned int nThreads,
1173 bool bParallel(
false);
1176 const char* sKeyWords[] = {
1188 "parallel" "initial" "value",
1189 "inverse" "dynamics",
1210 PARALLEL_INITIAL_VALUE,
1232 silent_cerr(std::endl
1233 <<
"Error: <begin> expected at line "
1234 << HP.
GetLineData() <<
"; aborting..." << std::endl);
1240 silent_cerr(std::endl
1241 <<
"Error: <begin: data;> expected at line "
1242 << HP.
GetLineData() <<
"; aborting..." << std::endl);
1252 pedantic_cout(
"statement \"integrator\" is deprecated; "
1253 "use \"problem\" instead." << std::endl);
1257 pedantic_cout(
"deprecated \"multistep\" problem; "
1258 "use \"initial value\" instead" << std::endl);
1260 CurrInt = INITIAL_VALUE;
1263 case PARALLEL_INITIAL_VALUE:
1264 CurrInt = PARALLEL_INITIAL_VALUE;
1274 silent_cerr(
"compile with -DUSE_MPI to enable "
1275 "parallel solution" << std::endl);
1279 case INVERSE_DYNAMICS:
1280 CurrInt = INVERSE_DYNAMICS;
1284 silent_cerr(std::endl
1285 <<
"Unknown problem at line "
1287 <<
"; aborting..." << std::endl);
1294 silent_cerr(std::endl
1295 <<
"Error: <end: data;> expected"
1297 <<
"; aborting..." << std::endl);
1303 silent_cerr(std::endl
1304 <<
"Unknown description at line "
1306 <<
"; aborting..." << std::endl);
1318 unsigned int size = MPI::COMM_WORLD.Get_size();
1319 unsigned int Bcount = 0;
1325 MPI::COMM_WORLD.Allgather(pBuff, 1, MPI::INT,
1326 pBuff+1, 1, MPI::INT);
1327 std::vector<unsigned int> iInterfaceProc(5);
1328 unsigned int Icount = 0;
1329 for (
unsigned int i = 1; i <= size; i++) {
1330 if (pBuff[i] == pBuff[0]) {
1335 iInterfaceProc[Icount++] = i-1;
1338 iInterfaceProc.push_back(i-1);
1342 if (Bcount == size) {
1344 MBDynComm = MPI::COMM_WORLD.Dup();
1346 MBDynComm = MPI::COMM_WORLD.Split(pBuff[0], 1);
1349 for (
unsigned int ii = 0; ii < Icount; ii++) {
1350 InterfaceComms.push_back(MBDynComm.Create_intercomm(0, MPI::COMM_WORLD, iInterfaceProc[ii], INTERF_COMM_LABEL));
1355 MBDynComm = MPI::COMM_WORLD.Dup();
1358 if (MBDynComm.Get_rank()) {
1359 silent_cout(
"MBDyn will run on " << Bcount
1360 <<
" processors starting from "
1364 bParallel = (MBDynComm.Get_size() != 1);
1372 MyRank = MBDynComm.Get_rank();
1380 ASSERT(MPI::COMM_WORLD.Get_size() > 1);
1381 int iRankLength = 1 + (
int)log10(MPI::COMM_WORLD.Get_size() - 1);
1384 snprintf(buf,
sizeof(buf),
".%.*d", iRankLength, MyRank);
1385 sOutputFileName +=
buf;
1392 case PARALLEL_INITIAL_VALUE:
1395 Solver(HP, sInputFileName,
1396 sOutputFileName, nThreads, bParallel));
1399 case INVERSE_DYNAMICS:
1403 sOutputFileName, nThreads, bParallel));
1407 silent_cerr(
"Unknown integrator; aborting..." << std::endl);
std::ifstream FileStreamIn
const char sDefaultOutputFileName[]
#define MBDYN_EXCEPT_ARGS
#define DEBUGCOUTFNAME(fname)
#define MB_EXIT(what, err)
InputFormat CurrInputFormat
#define SAFEDELETEARR(pnt)
void mbdyn_warranty(void)
int is_abs_path(const char *const p)
std::string sOutputFileName
InputSource CurrInputSource
static void mbdyn_version(void)
int main(int argc, char *argv[])
virtual clock_t GetCPUTime(void) const
std::string sInputFileName
static int mbdyn_prepare_files(const std::string &sInputFileName, std::string &sOutputFileName)
#define ASSERT(expression)
#define SAFENEWWITHCONSTRUCTOR(pnt, item, constructor)
static Solver * RunMBDyn(MBDynParser &, const std::string &, const std::string &, unsigned int, bool, bool)
const std::string sDefaultInputFileName("MBDyn")
int getopt(int argc, char *const argv[], const char *opts)
virtual int GetWord(void)
#define SAFENEWARR(pnt, item, sz)
void GetEnviron(MathParser &)
void mbdyn_parse_arguments(mbdyn_proc_t &mbp, int argc, char *argv[], int &currarg)
static doublereal buf[BUFSIZE]
void mbdyn_cleanup_destroy(void)
virtual HighParser::ErrOut GetLineData(void) const
Table & GetSymbolTable(void) const
static int mbdyn_program(mbdyn_proc_t &mbp, int argc, char *argv[], int &currarg)