1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5
6 #include "GmshConfig.h"
7
8 #if defined(HAVE_MPI)
9 #include <mpi.h>
10 #endif
11
12 #if !defined(WIN32) || defined(__CYGWIN__)
13 #include <unistd.h>
14 #endif
15
16 #include <clocale>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <math.h>
20 #include <string.h>
21 #include <time.h>
22 #include <sys/stat.h>
23 #include "GmshMessage.h"
24 #include "GmshSocket.h"
25 #include "GmshGlobal.h"
26 #include "GModel.h"
27 #include "Options.h"
28 #include "Context.h"
29 #include "OpenFile.h"
30 #include "StringUtils.h"
31 #include "OS.h"
32
33 #if defined(HAVE_ONELAB)
34 #include "onelab.h"
35 #include "onelabUtils.h"
36 #endif
37
38 #include "gmshLocalNetworkClient.h"
39
40 #if defined(HAVE_PETSC)
41 #include <petsc.h>
42 #endif
43
44 #if defined(HAVE_SLEPC)
45 #include <slepc.h>
46 #endif
47
48 #if defined(HAVE_FLTK)
49 #include <FL/fl_ask.H>
50 #include "FlGui.h"
51 #include "extraDialogs.h"
52 #endif
53
54 #if defined(_OPENMP)
55 #include <omp.h>
56 #endif
57
58 int Msg::_commRank = 0;
59 int Msg::_commSize = 1;
60 int Msg::_verbosity = 5;
61 int Msg::_progressMeterStep = 10;
62 std::atomic<int> Msg::_progressMeterCurrent(-1);
63 int Msg::_progressMeterTotal = 0;
64 std::map<std::string, double> Msg::_timers;
65 bool Msg::_infoCpu = false;
66 bool Msg::_infoMem = false;
67 double Msg::_startTime = 0.;
68 int Msg::_startMaxThreads = 0;
69 int Msg::_warningCount = 0;
70 int Msg::_errorCount = 0;
71 int Msg::_atLeastOneErrorInRun = 0;
72 std::string Msg::_firstWarning;
73 std::string Msg::_firstError;
74 std::string Msg::_lastError;
75 GmshMessage *Msg::_callback = nullptr;
76 std::vector<std::string> Msg::_commandLineArgs;
77 std::string Msg::_launchDate;
78 std::map<std::string, std::vector<double> > Msg::_commandLineNumbers;
79 std::map<std::string, std::string> Msg::_commandLineStrings;
80 GmshClient *Msg::_client = nullptr;
81 std::string Msg::_execName;
82 #if defined(HAVE_ONELAB)
83 onelab::client *Msg::_onelabClient = nullptr;
84 onelab::server *onelab::server::_server = nullptr;
85 #endif
86 std::string Msg::_logFileName;
87 FILE *Msg::_logFile = nullptr;
88
89 #if defined(_MSC_VER) && (_MSC_VER >= 1310) //NET 2003
90 #define vsnprintf _vsnprintf
91 #else
92 #if defined(HAVE_NO_VSNPRINTF)
vsnprintf(char * str,size_t size,const char * fmt,va_list ap)93 static int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
94 {
95 if (strlen(fmt) > size - 1) { // just copy the format
96 strncpy(str, fmt, size - 1);
97 str[size - 1] = '\0';
98 return size;
99 }
100 return vsprintf(str, fmt, ap);
101 }
102 #endif
103 #endif
104
addGmshPathToEnvironmentVar(const std::string & name)105 static void addGmshPathToEnvironmentVar(const std::string &name)
106 {
107 std::string gmshPath = SplitFileName(CTX::instance()->exeFileName)[0];
108 if(gmshPath.size()){
109 std::string tmp = GetEnvironmentVar(name);
110 if(tmp.find(gmshPath) != std::string::npos) return; // already there
111 std::string path;
112 if(tmp.empty()) {
113 path = gmshPath;
114 }
115 else {
116 #if defined(WIN32)
117 path = tmp + ";" + gmshPath;
118 #else
119 path = tmp + ":" + gmshPath;
120 #endif
121 }
122 SetEnvironmentVar(name, path);
123 }
124 }
125
Initialize(int argc,char ** argv)126 void Msg::Initialize(int argc, char **argv)
127 {
128 _startTime = TimeOfDay();
129 _startMaxThreads = GetMaxThreads();
130 #if defined(HAVE_MPI)
131 int flag;
132 MPI_Initialized(&flag);
133 if(!flag) MPI_Init(&argc, &argv);
134 MPI_Comm_rank(MPI_COMM_WORLD, &_commRank);
135 MPI_Comm_size(MPI_COMM_WORLD, &_commSize);
136 MPI_Comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
137 #endif
138 #if defined(HAVE_PETSC)
139 int sargc = 0;
140 char **sargv = new char*[argc + 1];
141 // prune argv from gmsh-specific options that make PETSc verbose
142 for(int i = 0; i < argc; i++){
143 std::string val(argv[i]);
144 if(val != "-info" && val != "-help" && val != "-version" && val != "-v")
145 sargv[sargc++] = argv[i];
146 }
147 sargv[sargc] = nullptr;
148 PetscInitialize(&sargc, &sargv, PETSC_NULL, PETSC_NULL);
149 PetscPopSignalHandler();
150 #if defined(HAVE_SLEPC)
151 SlepcInitialize(&sargc, &sargv, PETSC_NULL, PETSC_NULL);
152 #endif
153 delete [] sargv;
154 #endif
155 time_t now;
156 time(&now);
157 _launchDate = ctime(&now);
158 _launchDate.resize(_launchDate.size() - 1);
159
160 bool _env = true, _locale = true;
161 _commandLineArgs.resize(argc);
162 for(int i = 0; i < argc; i++) {
163 _commandLineArgs[i] = argv[i];
164 if(_commandLineArgs[i] == "-noenv")
165 _env = false;
166 else if(_commandLineArgs[i] == "-nolocale")
167 _locale = false;
168 }
169
170 CTX::instance()->exeFileName = GetExecutableFileName();
171 if(CTX::instance()->exeFileName.empty() && _commandLineArgs.size())
172 CTX::instance()->exeFileName = _commandLineArgs[0];
173
174 if(_env) {
175 // add the directory where the binary is installed to the path where Python
176 // looks for modules, and to the path for executables (this allows us to
177 // find the onelab.py module or subclients automatically)
178 addGmshPathToEnvironmentVar("PYTHONPATH");
179 addGmshPathToEnvironmentVar("PATH");
180 }
181
182 if(_locale) {
183 // make sure to use the "C" locale; in particular this ensures that we will
184 // use a dot for for the decimal separator when writing ASCII mesh files
185 std::setlocale(LC_ALL, "C.UTF-8");
186 std::setlocale(LC_NUMERIC, "C");
187 }
188
189 InitializeOnelab("Gmsh");
190
191 #if defined(_OPENMP)
192 // this is deprecated
193 //omp_set_nested(true);
194 #endif
195 }
196
Finalize()197 void Msg::Finalize()
198 {
199 // close log file
200 if(_logFile){
201 fclose(_logFile);
202 _logFile = nullptr;
203 }
204
205 #if defined(HAVE_SLEPC)
206 SlepcFinalize();
207 #endif
208 #if defined(HAVE_PETSC)
209 // this often crashes when called multiple times
210 //PetscFinalize();
211 #endif
212 #if defined(HAVE_MPI)
213 int finalized; // Some PETSc versions call MPI_FINALIZE
214 MPI_Finalized(&finalized);
215 if (!finalized)
216 MPI_Finalize();
217 #endif
218 FinalizeOnelab();
219 if(GetMaxThreads() != _startMaxThreads)
220 SetNumThreads(_startMaxThreads);
221 }
222
GetCommRank()223 int Msg::GetCommRank()
224 {
225 return _commRank;
226 }
227
GetCommSize()228 int Msg::GetCommSize()
229 {
230 return _commSize;
231 }
232
SetCommRank(int val)233 void Msg::SetCommRank(int val)
234 {
235 _commRank = val;
236 }
237
SetCommSize(int val)238 void Msg::SetCommSize(int val)
239 {
240 _commSize = val;
241 }
242
SetCallback(GmshMessage * callback)243 void Msg::SetCallback(GmshMessage *callback)
244 {
245 _callback = callback;
246 }
247
GetCallback()248 GmshMessage *Msg::GetCallback()
249 {
250 return _callback;
251 }
252
SetVerbosity(int val)253 void Msg::SetVerbosity(int val)
254 {
255 _verbosity = val;
256 }
257
GetVerbosity()258 int Msg::GetVerbosity()
259 {
260 return _verbosity;
261 }
262
SetLogFile(const std::string & name)263 void Msg::SetLogFile(const std::string &name)
264 {
265 _logFileName = name;
266 if(_logFile) fclose(_logFile);
267 if(name.size()){
268 _logFile = Fopen(name.c_str(), "w");
269 if(!_logFile)
270 Msg::Error("Could not open file '%s'", name.c_str());
271 }
272 else
273 _logFile = nullptr;
274 }
275
GetLaunchDate()276 std::string Msg::GetLaunchDate()
277 {
278 return _launchDate;
279 }
280
GetCommandLineArgs()281 std::vector<std::string> &Msg::GetCommandLineArgs()
282 {
283 return _commandLineArgs;
284 }
285
GetCommandLineFull()286 std::string Msg::GetCommandLineFull()
287 {
288 std::string tmp;
289 for(std::size_t i = 0; i < _commandLineArgs.size(); i++){
290 if(i) tmp += " ";
291 tmp += _commandLineArgs[i];
292 }
293 return tmp;
294 }
295
GetCommandLineNumbers()296 std::map<std::string, std::vector<double> > &Msg::GetCommandLineNumbers()
297 {
298 return _commandLineNumbers;
299 }
300
GetCommandLineStrings()301 std::map<std::string, std::string> &Msg::GetCommandLineStrings()
302 {
303 return _commandLineStrings;
304 }
305
SetProgressMeterStep(int step)306 void Msg::SetProgressMeterStep(int step)
307 {
308 _progressMeterStep = step;
309 }
310
GetProgressMeterStep()311 int Msg::GetProgressMeterStep()
312 {
313 return _progressMeterStep;
314 }
315
StartProgressMeter(int ntotal)316 void Msg::StartProgressMeter(int ntotal)
317 {
318 _progressMeterCurrent = 0;
319 _progressMeterTotal = ntotal;
320 }
321
StopProgressMeter()322 void Msg::StopProgressMeter()
323 {
324 _progressMeterCurrent = -1;
325 _progressMeterTotal = 0;
326 #if defined(HAVE_FLTK)
327 if(FlGui::available()){
328 FlGui::instance()->setProgress("", 0, 0, 1);
329 FlGui::check(true);
330 }
331 #endif
332 }
333
SetInfoCpu(bool val)334 void Msg::SetInfoCpu(bool val)
335 {
336 _infoCpu = val;
337 }
338
SetInfoMem(bool val)339 void Msg::SetInfoMem(bool val)
340 {
341 _infoMem = val;
342 }
343
Timer(const std::string & str)344 double &Msg::Timer(const std::string &str) { return _timers[str]; }
345
GetWarningCount()346 int Msg::GetWarningCount()
347 {
348 return _warningCount;
349 }
350
GetErrorCount()351 int Msg::GetErrorCount()
352 {
353 return _errorCount;
354 }
355
GetFirstWarning()356 std::string Msg::GetFirstWarning()
357 {
358 return _firstWarning;
359 }
360
GetFirstError()361 std::string Msg::GetFirstError()
362 {
363 return _firstError;
364 }
365
GetLastError()366 std::string Msg::GetLastError()
367 {
368 return _lastError;
369 }
370
SetExecutableName(const std::string & name)371 void Msg::SetExecutableName(const std::string &name)
372 {
373 _execName.assign(name);
374 }
375
GetExecutableName()376 std::string Msg::GetExecutableName()
377 {
378 return _execName;
379 }
380
381 #if defined(HAVE_ONELAB)
GetOnelabClient()382 onelab::client *Msg::GetOnelabClient()
383 {
384 return _onelabClient;
385 }
386 #endif
387
Exit(int level)388 void Msg::Exit(int level)
389 {
390 Finalize();
391 #if defined(HAVE_MPI)
392 if(level) MPI_Abort(MPI_COMM_WORLD, level);
393 #endif
394 exit(level ? level : _atLeastOneErrorInRun);
395 }
396
streamIsFile(FILE * stream)397 static int streamIsFile(FILE *stream)
398 {
399 // the given stream is definitely not interactive if it is a regular file
400 struct stat stream_stat;
401 if(fstat(fileno(stream), &stream_stat) == 0){
402 if(stream_stat.st_mode & S_IFREG) return 1;
403 }
404 return 0;
405 }
406
streamIsVT100(FILE * stream)407 static int streamIsVT100(FILE *stream)
408 {
409 // on unix directly check if the file descriptor refers to a terminal
410 #if !defined(WIN32) || defined(__CYGWIN__)
411 return isatty(fileno(stream));
412 #endif
413
414 // otherwise try to detect some known cases:
415
416 // if running inside emacs the terminal is not VT100
417 const char* emacs = getenv("EMACS");
418 if(emacs && *emacs == 't') return 0;
419
420 // list of known terminal names (from cmake)
421 static const char* names[] =
422 {"Eterm", "ansi", "color-xterm", "con132x25", "con132x30", "con132x43",
423 "con132x60", "con80x25", "con80x28", "con80x30", "con80x43", "con80x50",
424 "con80x60", "cons25", "console", "cygwin", "dtterm", "eterm-color", "gnome",
425 "gnome-256color", "konsole", "konsole-256color", "kterm", "linux", "msys",
426 "linux-c", "mach-color", "mlterm", "putty", "rxvt", "rxvt-256color",
427 "rxvt-cygwin", "rxvt-cygwin-native", "rxvt-unicode", "rxvt-unicode-256color",
428 "screen", "screen-256color", "screen-256color-bce", "screen-bce", "screen-w",
429 "screen.linux", "vt100", "xterm", "xterm-16color", "xterm-256color",
430 "xterm-88color", "xterm-color", "xterm-debian", nullptr};
431 const char** t = nullptr;
432 const char* term = getenv("TERM");
433 if(term){
434 for(t = names; *t && strcmp(term, *t) != 0; ++t) {}
435 }
436 if(!(t && *t)) return 0;
437 return 1;
438 }
439
PrintResources(bool printDate,bool printWallTime,bool printCpu,bool printMem)440 std::string Msg::PrintResources(bool printDate, bool printWallTime,
441 bool printCpu, bool printMem)
442 {
443 long mem = GetMemoryUsage();
444
445 std::string pdate = "";
446 if(printDate){
447 time_t now;
448 time(&now);
449 pdate = ctime(&now);
450 pdate.resize(pdate.size() - 1);
451 if(printWallTime || printCpu || (printMem && mem))
452 pdate += ", ";
453 }
454
455 std::string pwall = "";
456 if(printWallTime){
457 char tmp[128];
458 sprintf(tmp, "Wall %gs", TimeOfDay() - _startTime);
459 pwall = tmp;
460 if(printCpu || (printMem && mem))
461 pwall += ", ";
462 }
463
464 std::string pcpu = "";
465 if(printCpu){
466 char tmp[128];
467 sprintf(tmp, "CPU %gs", Cpu());
468 pcpu = tmp;
469 if(printMem && mem)
470 pcpu += ", ";
471 }
472
473 std::string pmem = "";
474 if(mem && printMem){
475 char tmp[128];
476 sprintf(tmp, "Mem %gMb", (double)mem / 1024. / 1024.);
477 pmem = tmp;
478 }
479
480 std::string str;
481 if(pdate.size() || pwall.size() || pcpu.size() || pmem.size())
482 str += " (From start: " + pdate + pwall + pcpu + pmem + ")";
483 return str;
484 }
485
Error(const char * fmt,...)486 void Msg::Error(const char *fmt, ...)
487 {
488 _errorCount++;
489 _atLeastOneErrorInRun = 1;
490
491 char str[5000];
492 va_list args;
493 va_start(args, fmt);
494 vsnprintf(str, sizeof(str), fmt, args);
495 va_end(args);
496 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
497
498 if(_firstError.empty()) _firstError = str;
499 _lastError = str;
500
501 if(GetVerbosity() >= 1) {
502 if(_logFile) fprintf(_logFile, "Error: %s\n", str);
503 if(_callback) (*_callback)("Error", str);
504 if(_client) _client->Error(str);
505 #if defined(HAVE_FLTK)
506 if(FlGui::available()){
507 std::string tmp = std::string(CTX::instance()->guiColorScheme ? "@B72@." : "@C1@.")
508 + "Error : " + str;
509 FlGui::instance()->addMessage(tmp.c_str());
510 FlGui::instance()->setLastStatus
511 (CTX::instance()->guiColorScheme ? FL_DARK_RED : FL_RED);
512 FlGui::check(true);
513 }
514 #endif
515 if(CTX::instance()->terminal){
516 const char *c0 = "", *c1 = "";
517 if(!streamIsFile(stderr) && streamIsVT100(stderr)){
518 c0 = "\33[1m\33[31m"; c1 = "\33[0m"; // bold red
519 }
520 if(_commSize > 1)
521 fprintf(stderr, "%sError : [rank %3d] %s%s\n", c0, GetCommRank(), str, c1);
522 else
523 fprintf(stderr, "%sError : %s%s\n", c0, str, c1);
524 fflush(stderr);
525 }
526 }
527
528 if(CTX::instance()->abortOnError == 2) {
529 #if defined(HAVE_FLTK)
530 if(FlGui::available()) return; // don't throw if GUI is running
531 #endif
532 throw _lastError;
533 }
534 else if(CTX::instance()->abortOnError == 3) {
535 throw _lastError;
536 }
537 else if(CTX::instance()->abortOnError == 4) {
538 Exit(1);
539 }
540 }
541
Warning(const char * fmt,...)542 void Msg::Warning(const char *fmt, ...)
543 {
544 _warningCount++;
545
546 if(GetVerbosity() < 2) return;
547
548 char str[5000];
549 va_list args;
550 va_start(args, fmt);
551 vsnprintf(str, sizeof(str), fmt, args);
552 va_end(args);
553 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
554
555 if(_logFile) fprintf(_logFile, "Warning: %s\n", str);
556 if(_callback) (*_callback)("Warning", str);
557 if(_client) _client->Warning(str);
558
559 #if defined(HAVE_FLTK)
560 if(FlGui::available()){
561 std::string tmp = std::string(CTX::instance()->guiColorScheme ? "@B152@." : "@C5@.")
562 + "Warning : " + str;
563 FlGui::instance()->addMessage(tmp.c_str());
564 if(_firstWarning.empty()) _firstWarning = str;
565 FlGui::instance()->setLastStatus();
566 FlGui::check(true);
567 }
568 #endif
569
570 if(CTX::instance()->terminal){
571 const char *c0 = "", *c1 = "";
572 if(!streamIsFile(stderr) && streamIsVT100(stderr)){
573 c0 = "\33[35m"; c1 = "\33[0m"; // magenta
574 }
575 if(_commSize > 1)
576 fprintf(stderr, "%sWarning : [rank %3d] %s%s\n", c0, GetCommRank(), str, c1);
577 else
578 fprintf(stderr, "%sWarning : %s%s\n", c0, str, c1);
579 fflush(stderr);
580 }
581 }
582
Info(const char * fmt,...)583 void Msg::Info(const char *fmt, ...)
584 {
585 if(GetVerbosity() < 4) return;
586
587 char str[5000];
588 va_list args;
589 va_start(args, fmt);
590 vsnprintf(str, sizeof(str), fmt, args);
591 va_end(args);
592 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
593
594 if(_infoCpu || _infoMem){
595 std::string res = PrintResources(false, _infoCpu, _infoCpu, _infoMem);
596 strcat(str, res.c_str());
597 }
598
599 if(_logFile) fprintf(_logFile, "Info: %s\n", str);
600 if(_callback) (*_callback)("Info", str);
601 if(_client) _client->Info(str);
602
603 #if defined(HAVE_FLTK)
604 if(FlGui::available()){
605 std::string tmp = std::string("Info : ") + str;
606 FlGui::instance()->addMessage(tmp.c_str());
607 FlGui::check(true);
608 }
609 #endif
610
611 if(CTX::instance()->terminal){
612 if(_progressMeterCurrent >= 0 && _progressMeterTotal > 1 &&
613 _commSize == 1) {
614 int p = _progressMeterCurrent;
615 fprintf(stdout, "Info : [%3d%%] %s\n", p, str);
616 }
617 else if(_commSize > 1)
618 fprintf(stdout, "Info : [rank %3d] %s\n", GetCommRank(), str);
619 else
620 fprintf(stdout, "Info : %s\n", str);
621 fflush(stdout);
622 }
623 }
624
RequestRender()625 void Msg::RequestRender()
626 {
627 if(_callback) (*_callback)("RequestRender", "");
628 }
629
Direct(const char * fmt,...)630 void Msg::Direct(const char *fmt, ...)
631 {
632 if(GetVerbosity() < 3) return;
633
634 char str[5000];
635 va_list args;
636 va_start(args, fmt);
637 vsnprintf(str, sizeof(str), fmt, args);
638 va_end(args);
639 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
640
641 if(_logFile) fprintf(_logFile, "Direct: %s\n", str);
642 if(_callback) (*_callback)("Direct", str);
643 if(_client) _client->Info(str);
644
645 #if defined(HAVE_FLTK)
646 if(FlGui::available()){
647 std::string tmp = std::string(CTX::instance()->guiColorScheme ? "@B136@." : "@C4@.")
648 + str;
649 FlGui::instance()->addMessage(tmp.c_str());
650 FlGui::check(true);
651 }
652 #endif
653
654 if(CTX::instance()->terminal){
655 const char *c0 = "", *c1 = "";
656 if(!streamIsFile(stdout) && streamIsVT100(stdout)){
657 c0 = "\33[34m"; c1 = "\33[0m"; // blue
658 }
659 if(_commSize > 1)
660 fprintf(stdout, "%s[rank %3d] %s%s\n", c0, GetCommRank(), str, c1);
661 else
662 fprintf(stdout, "%s%s%s\n", c0, str, c1);
663 fflush(stdout);
664 }
665 }
666
Auto(const char * fmt,...)667 void Msg::Auto(const char *fmt, ...)
668 {
669 char str[5000];
670 va_list args;
671 va_start(args, fmt);
672 vsnprintf(str, sizeof(str), fmt, args);
673 va_end(args);
674 if(strstr(str, "Error") || strstr(str, "error") || strstr(str, "ERROR"))
675 Msg::Error("%s", str);
676 else if(strstr(str, "Warning") || strstr(str, "warning") || strstr(str, "WARNING"))
677 Msg::Warning("%s", str);
678 else
679 Msg::Info("%s", str);
680 }
681
StatusBar(bool log,const char * fmt,...)682 void Msg::StatusBar(bool log, const char *fmt, ...)
683 {
684 if(GetVerbosity() < 4) return;
685
686 char str[5000];
687 va_list args;
688 va_start(args, fmt);
689 vsnprintf(str, sizeof(str), fmt, args);
690 va_end(args);
691 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
692
693 if(_infoCpu || _infoMem){
694 std::string res = PrintResources(false, _infoCpu, _infoCpu, _infoMem);
695 strcat(str, res.c_str());
696 }
697
698 if(_logFile) fprintf(_logFile, "Info: %s\n", str);
699 if(_callback && log) (*_callback)("Info", str);
700 if(_client && log) _client->Info(str);
701
702 #if defined(HAVE_FLTK)
703 if(FlGui::available()){
704 if(!log || GetVerbosity() > 4)
705 FlGui::instance()->setStatus(str);
706 if(log){
707 std::string tmp = std::string("Info : ") + str;
708 FlGui::instance()->addMessage(tmp.c_str());
709 FlGui::check(true);
710 }
711 }
712 #endif
713
714 if(log && CTX::instance()->terminal){
715 if(_commSize > 1)
716 fprintf(stdout, "Info : [rank %3d] %s\n", GetCommRank(), str);
717 else
718 fprintf(stdout, "Info : %s\n", str);
719 fflush(stdout);
720 }
721 }
722
StatusGl(const char * fmt,...)723 void Msg::StatusGl(const char *fmt, ...)
724 {
725 #if defined(HAVE_FLTK)
726 if(GetCommRank()) return;
727 char str[5000];
728 va_list args;
729 va_start(args, fmt);
730 vsnprintf(str, sizeof(str), fmt, args);
731 va_end(args);
732 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
733
734 if(FlGui::available())
735 FlGui::instance()->setStatus(str, true);
736 #endif
737 }
738
SetWindowTitle(const std::string & title)739 void Msg::SetWindowTitle(const std::string &title)
740 {
741 #if defined(HAVE_FLTK)
742 if(FlGui::available()){
743 FlGui::instance()->setGraphicTitle(title);
744 }
745 #endif
746 }
747
Debug(const char * fmt,...)748 void Msg::Debug(const char *fmt, ...)
749 {
750 if(GetVerbosity() < 99) return;
751
752 char str[5000];
753 va_list args;
754 va_start(args, fmt);
755 vsnprintf(str, sizeof(str), fmt, args);
756 va_end(args);
757 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
758
759 if(_logFile) fprintf(_logFile, "Debug: %s\n", str);
760 if(_callback) (*_callback)("Debug", str);
761 if(_client) _client->Info(str);
762
763 #if defined(HAVE_FLTK)
764 if(FlGui::available()){
765 std::string tmp = std::string("Debug : ") + str;
766 FlGui::instance()->addMessage(tmp.c_str());
767 }
768 #endif
769
770 if(CTX::instance()->terminal){
771 if(_commSize > 1)
772 fprintf(stdout, "Debug : [rank %3d] %s\n", GetCommRank(), str);
773 else
774 fprintf(stdout, "Debug : %s\n", str);
775 fflush(stdout);
776 }
777 }
778
ProgressMeter(int n,bool log,const char * fmt,...)779 void Msg::ProgressMeter(int n, bool log, const char *fmt, ...)
780 {
781 if(GetCommRank() || GetVerbosity() < 4) return;
782 if(_progressMeterStep <= 0 || _progressMeterStep >= 100) return;
783 if(_progressMeterTotal <= 0) return;
784
785 int N = _progressMeterTotal;
786 double percent = 100. * (double)n / (double)N;
787
788 if(percent >= _progressMeterCurrent || n > N - 1){
789 int p = _progressMeterCurrent;
790 while(p < percent) p += _progressMeterStep;
791 if(p >= 100) p = 100;
792
793 _progressMeterCurrent = p;
794
795 // TODO With C++11 use std::string (contiguous layout) and avoid all these C
796 // problems
797 // str2 needs to have at least 5018 bytes or buffer overflow will occur
798 char str[5000], str2[5100];
799 va_list args;
800 va_start(args, fmt);
801 vsnprintf(str, sizeof(str), fmt, args);
802 va_end(args);
803 int l = strlen(str); if(str[l - 1] == '\n') str[l - 1] = '\0';
804 sprintf(str2, "Info : [%3d%%] %s", p, str);
805
806 if(_client) _client->Progress(str2);
807
808 #if defined(HAVE_FLTK)
809 if(FlGui::available() && GetVerbosity() > 4){
810 FlGui::instance()->setProgress(str, (n > N - 1) ? 0 : n, 0, N);
811 FlGui::check(true);
812 }
813 #endif
814 if(_logFile) fprintf(_logFile, "Progress: %s\n", str);
815 if(_callback) (*_callback)("Progress", str);
816 if(!streamIsFile(stdout) && log && CTX::instance()->terminal){
817 fprintf(stdout, "%s \r",
818 (n > N - 1) ? "" : str2);
819 fflush(stdout);
820 }
821 }
822 }
823
PrintTimers()824 void Msg::PrintTimers()
825 {
826 // do a single stdio call!
827 std::string str;
828 for(auto it = _timers.begin();
829 it != _timers.end(); it++){
830 if(it != _timers.begin()) str += ", ";
831 char tmp[256];
832 sprintf(tmp, "%s = %gs ", it->first.c_str(), it->second);
833 str += std::string(tmp);
834 }
835 if(!str.size()) return;
836
837 if(CTX::instance()->terminal){
838 if(_commSize > 1)
839 fprintf(stdout, "Timers : [rank %3d] %s\n", GetCommRank(), str.c_str());
840 else
841 fprintf(stdout, "Timers : %s\n", str.c_str());
842 fflush(stdout);
843 }
844 }
845
ResetErrorCounter()846 void Msg::ResetErrorCounter()
847 {
848 _warningCount = 0; _errorCount = 0;
849 _firstWarning.clear(); _firstError.clear(); _lastError.clear();
850 #if defined(HAVE_FLTK)
851 if(FlGui::available()) FlGui::instance()->setLastStatus();
852 #endif
853 }
854
PrintErrorCounter(const char * title)855 void Msg::PrintErrorCounter(const char *title)
856 {
857 if(GetCommRank() || GetVerbosity() < 1) return;
858 if(!GetWarningCount() && !GetErrorCount()) return;
859
860 std::string prefix = GetErrorCount() ? "Error : " : "Warning : ";
861 std::string help("Check the full log for details");
862 std::string line(std::max(strlen(title), help.size()), '-');
863 char warn[128], err[128];
864 sprintf(warn, "%5d warning%s", GetWarningCount(), GetWarningCount() == 1 ? "" : "s");
865 sprintf(err, "%5d error%s", GetErrorCount(), GetErrorCount() == 1 ? "" : "s");
866
867 #if defined(HAVE_FLTK)
868 if(FlGui::available()){
869 std::string col = GetErrorCount() ?
870 std::string(CTX::instance()->guiColorScheme ? "@B72@." : "@C1@.") :
871 std::string(CTX::instance()->guiColorScheme ? "@B152@." : "@C5@.");
872 FlGui::instance()->addMessage((col + prefix + line).c_str());
873 FlGui::instance()->addMessage((col + prefix + title).c_str());
874 FlGui::instance()->addMessage((col + prefix + warn).c_str());
875 FlGui::instance()->addMessage((col + prefix + err).c_str());
876 FlGui::instance()->addMessage((col + prefix + help).c_str());
877 FlGui::instance()->addMessage((col + prefix + line).c_str());
878 if(GetErrorCount()) fl_beep();
879 }
880 #endif
881
882 if(CTX::instance()->terminal){
883 const char *c0 = "", *c1 = "";
884 if(!streamIsFile(stderr) && streamIsVT100(stderr)){
885 c0 = GetErrorCount() ? "\33[1m\33[31m" : "\33[35m"; // bold red or magenta
886 c1 = "\33[0m";
887 }
888 fprintf(stderr, "%s%s\n%s\n%s\n%s\n%s\n%s%s\n", c0, (prefix + line).c_str(),
889 (prefix + title).c_str(), (prefix + warn).c_str(),
890 (prefix + err).c_str(), (prefix + help).c_str(),
891 (prefix + line).c_str(), c1);
892 fflush(stderr);
893 }
894 }
895
GetValue(const char * text,double defaultval)896 double Msg::GetValue(const char *text, double defaultval)
897 {
898 // if a callback is given let's assume we don't want to be bothered
899 // with interactive stuff
900 if(CTX::instance()->noPopup || _callback) return defaultval;
901
902 #if defined(HAVE_FLTK)
903 if(FlGui::available()){
904 char defaultstr[256];
905 sprintf(defaultstr, "%.16g", defaultval);
906 const char *ret = fl_input(text, defaultstr, "");
907 if(!ret)
908 return defaultval;
909 else
910 return atof(ret);
911 }
912 #endif
913
914 printf("%s (default=%.16g): ", text, defaultval);
915 char str[256];
916 char *ret = fgets(str, sizeof(str), stdin);
917 if(!ret || !strlen(str) || !strcmp(str, "\n"))
918 return defaultval;
919 else
920 return atof(str);
921 }
922
GetString(const char * text,const std::string & defaultval)923 std::string Msg::GetString(const char *text, const std::string &defaultval)
924 {
925 // if a callback is given let's assume we don't want to be bothered
926 // with interactive stuff
927 if(CTX::instance()->noPopup || _callback) return defaultval;
928
929 #if defined(HAVE_FLTK)
930 if(FlGui::available()){
931 const char *ret = fl_input(text, defaultval.c_str(), "");
932 if(!ret)
933 return defaultval;
934 else
935 return std::string(ret);
936 }
937 #endif
938
939 printf("%s (default=%s): ", text, defaultval.c_str());
940 char str[256];
941 char *ret = fgets(str, sizeof(str), stdin);
942 if(!ret || !strlen(str) || !strcmp(str, "\n"))
943 return defaultval;
944 else
945 return std::string(str);
946 }
947
GetAnswer(const char * question,int defaultval,const char * zero,const char * one,const char * two)948 int Msg::GetAnswer(const char *question, int defaultval, const char *zero,
949 const char *one, const char *two)
950 {
951 // if a callback is given let's assume we don't want to be bothered
952 // with interactive stuff
953 if(CTX::instance()->noPopup || _callback) return defaultval;
954
955 #if defined(HAVE_FLTK)
956 if(FlGui::available())
957 return fl_choice(question, zero, one, two, "");
958 #endif
959
960 if(two)
961 printf("%s\n\n0=[%s] 1=[%s] 2=[%s] (default=%d): ", question,
962 zero, one, two, defaultval);
963 else
964 printf("%s\n\n0=[%s] 1=[%s] (default=%d): ", question,
965 zero, one, defaultval);
966 char str[256];
967 char *ret = fgets(str, sizeof(str), stdin);
968 if(!ret || !strlen(str) || !strcmp(str, "\n"))
969 return defaultval;
970 else
971 return atoi(ret);
972 }
973
UseOnelab()974 bool Msg::UseOnelab()
975 {
976 #if defined(HAVE_ONELAB)
977 return _onelabClient ? true : false;
978 #else
979 return false;
980 #endif
981 }
982
SetOnelabNumber(const std::string & name,double val,bool visible,bool persistent,bool readOnly,int changedValue)983 void Msg::SetOnelabNumber(const std::string &name, double val, bool visible,
984 bool persistent, bool readOnly, int changedValue)
985 {
986 #if defined(HAVE_ONELAB)
987 if(_onelabClient){
988 // get if first so we can keep its options
989 std::vector<onelab::number> numbers;
990 _onelabClient->get(numbers, name);
991 if(numbers.empty()){
992 numbers.resize(1);
993 numbers[0].setName(name);
994 }
995 numbers[0].setValue(val);
996 if(!visible) numbers[0].setVisible(false);
997 if(persistent) numbers[0].setAttribute("Persistent", "1");
998 numbers[0].setReadOnly(readOnly);
999 numbers[0].setChangedValue(changedValue);
1000 _onelabClient->set(numbers[0]);
1001 }
1002 #endif
1003 }
1004
SetOnelabNumber(const std::string & name,const std::vector<double> & val,bool visible)1005 void Msg::SetOnelabNumber(const std::string &name, const std::vector<double> &val,
1006 bool visible)
1007 {
1008 #if defined(HAVE_ONELAB)
1009 if(_onelabClient){
1010 onelab::number n(name, val);
1011 if(!visible) n.setVisible(false);
1012 _onelabClient->set(n);
1013 }
1014 #endif
1015 }
1016
SetOnelabString(const std::string & name,const std::string & val,bool visible,bool persistent,bool readOnly,int changedValue,const std::string & kind)1017 void Msg::SetOnelabString(const std::string &name, const std::string &val,
1018 bool visible, bool persistent, bool readOnly,
1019 int changedValue, const std::string &kind)
1020 {
1021 #if defined(HAVE_ONELAB)
1022 if(_onelabClient){
1023 // get if first so we can keep its options
1024 std::vector<onelab::string> strings;
1025 _onelabClient->get(strings, name);
1026 if(strings.empty()){
1027 strings.resize(1);
1028 strings[0].setName(name);
1029 }
1030 strings[0].setValue(val);
1031 if(!visible) strings[0].setVisible(false);
1032 if(persistent) strings[0].setAttribute("Persistent", "1");
1033 strings[0].setReadOnly(readOnly);
1034 strings[0].setChangedValue(changedValue);
1035 if(kind.size()) strings[0].setKind(kind);
1036 _onelabClient->set(strings[0]);
1037 }
1038 #endif
1039 }
1040
AddOnelabStringChoice(const std::string & name,const std::string & kind,const std::string & value,bool updateValue,bool readOnly,bool visible)1041 void Msg::AddOnelabStringChoice(const std::string &name,
1042 const std::string &kind,
1043 const std::string &value, bool updateValue,
1044 bool readOnly, bool visible)
1045 {
1046 #if defined(HAVE_ONELAB)
1047 if(_onelabClient){
1048 std::vector<std::string> choices;
1049 std::vector<onelab::string> ps;
1050 _onelabClient->get(ps, name);
1051 if(ps.size()){
1052 choices = ps[0].getChoices();
1053 if(std::find(choices.begin(), choices.end(), value) == choices.end())
1054 choices.push_back(value);
1055 if(updateValue)
1056 ps[0].setValue(value);
1057 }
1058 else{
1059 ps.resize(1);
1060 ps[0].setName(name);
1061 ps[0].setKind(kind);
1062 ps[0].setValue(value);
1063 choices.push_back(value);
1064 }
1065 ps[0].setChoices(choices);
1066 if(readOnly){
1067 ps[0].setReadOnly(true);
1068 ps[0].setAttribute("AutoCheck", "0");
1069 }
1070 else{
1071 ps[0].setReadOnly(false);
1072 ps[0].setAttribute("AutoCheck", "1");
1073 }
1074 ps[0].setVisible(visible);
1075 _onelabClient->set(ps[0]);
1076 }
1077 #endif
1078 }
1079
GetOnelabNumber(const std::string & name,double defaultValue,bool errorIfMissing)1080 double Msg::GetOnelabNumber(const std::string &name, double defaultValue,
1081 bool errorIfMissing)
1082 {
1083 #if defined(HAVE_ONELAB)
1084 if(_onelabClient){
1085 std::vector<onelab::number> numbers;
1086 _onelabClient->get(numbers, name);
1087 if(numbers.empty()){
1088 if(errorIfMissing)
1089 Msg::Error("Unknown ONELAB number parameter '%s'", name.c_str());
1090 return defaultValue;
1091 }
1092 else
1093 return numbers[0].getValue();
1094 }
1095 #endif
1096 if(errorIfMissing)
1097 Msg::Error("GetNumber requires a ONELAB client");
1098 return defaultValue;
1099 }
1100
GetOnelabString(const std::string & name,const std::string & defaultValue,bool errorIfMissing)1101 std::string Msg::GetOnelabString(const std::string &name,
1102 const std::string &defaultValue,
1103 bool errorIfMissing)
1104 {
1105 #if defined(HAVE_ONELAB)
1106 if(_onelabClient){
1107 std::vector<onelab::string> strings;
1108 _onelabClient->get(strings, name);
1109 if(strings.empty()){
1110 if(errorIfMissing)
1111 Msg::Error("Unknown ONELAB string parameter '%s'", name.c_str());
1112 return defaultValue;
1113 }
1114 else
1115 return strings[0].getValue();
1116 }
1117 #endif
1118 if(errorIfMissing)
1119 Msg::Error("GetString requires a ONELAB client");
1120 return defaultValue;
1121 }
1122
1123 #if defined(HAVE_ONELAB)
1124 class localGmsh : public onelab::localClient {
1125 public:
localGmsh()1126 localGmsh() : onelab::localClient("Gmsh") {}
1127 // redefinition of virtual onelab_client::sendMergeFileRequest
sendMergeFileRequest(const std::string & name)1128 void sendMergeFileRequest(const std::string &name)
1129 {
1130 if(name.find(".geo") != std::string::npos){
1131 MergePostProcessingFile(name, CTX::instance()->solver.autoShowViews,
1132 CTX::instance()->solver.autoShowLastStep, true);
1133 GModel::current()->setFileName(name);
1134 }
1135 else if((name.find(".opt") != std::string::npos)){
1136 MergeFile(name);
1137 }
1138 else if((name.find(".macro") != std::string::npos)){
1139 MergeFile(name);
1140 }
1141 else
1142 MergePostProcessingFile(name, CTX::instance()->solver.autoShowViews,
1143 CTX::instance()->solver.autoShowLastStep, true);
1144 }
sendInfo(const std::string & msg)1145 void sendInfo(const std::string &msg){ Msg::Info("%s", msg.c_str()); }
sendWarning(const std::string & msg)1146 void sendWarning(const std::string &msg){ Msg::Warning("%s", msg.c_str()); }
sendError(const std::string & msg)1147 void sendError(const std::string &msg){ Msg::Error("%s", msg.c_str()); }
1148 };
1149 #endif
1150
InitializeOnelab(const std::string & name,const std::string & sockname)1151 void Msg::InitializeOnelab(const std::string &name, const std::string &sockname)
1152 {
1153 #if defined(HAVE_ONELAB)
1154 if(_onelabClient) delete _onelabClient;
1155 if(sockname.empty()){
1156 _onelabClient = new localGmsh();
1157 if(name != "Gmsh"){ // load db from file:
1158 FILE *fp = Fopen(name.c_str(), "rb");
1159 if(fp){
1160 Msg::Info("Reading ONELAB database '%s'", name.c_str());
1161 _onelabClient->fromFile(fp);
1162 fclose(fp);
1163 }
1164 else
1165 Error("Error loading onelab database '%s'", name.c_str());
1166 }
1167 }
1168 else{
1169 onelab::remoteNetworkClient *c = new onelab::remoteNetworkClient(name, sockname);
1170 _onelabClient = c;
1171 _client = c->getGmshClient();
1172
1173 SetOnelabNumber(name + "/Use command line", 1, false);
1174 SetOnelabString(name + "/File extension", ".geo", false);
1175 SetOnelabString(name + "/9CheckCommand", "-", false);
1176 SetOnelabString(name + "/9ComputeCommand", "-3", false);
1177
1178 std::vector<onelab::string> ps;
1179 _onelabClient->get(ps, name + "/Action");
1180 if(ps.size()){
1181 //removed message, as terminal is set to 1 when we get here
1182 //Info("Performing ONELAB '%s'", ps[0].getValue().c_str());
1183 if(ps[0].getValue() == "initialize") Exit(0);
1184 }
1185 }
1186
1187 // default onelab button mode
1188 SetOnelabString("ONELAB/Button", "", false, true);
1189 #endif
1190 }
1191
FinalizeOnelab()1192 void Msg::FinalizeOnelab()
1193 {
1194 #if defined(HAVE_ONELAB)
1195 // kill any running clients
1196 for(auto it = onelab::server::instance()->firstClient();
1197 it != onelab::server::instance()->lastClient(); it++){
1198 (*it)->kill();
1199 }
1200 // delete local client
1201 if(_onelabClient){
1202 delete _onelabClient;
1203 _onelabClient = nullptr;
1204 _client = nullptr;
1205 }
1206 #endif
1207 }
1208
SetOnelabAction(const std::string & action)1209 void Msg::SetOnelabAction(const std::string &action)
1210 {
1211 #if defined(HAVE_ONELAB)
1212 if(_onelabClient){
1213 onelab::string o(_onelabClient->getName() + "/Action", action);
1214 o.setVisible(false);
1215 o.setChangedValue(0);
1216 _onelabClient->set(o);
1217 }
1218 #endif
1219 }
1220
GetOnelabAction()1221 std::string Msg::GetOnelabAction()
1222 {
1223 #if defined(HAVE_ONELAB)
1224 if(_onelabClient){
1225 std::vector<onelab::string> ps;
1226 _onelabClient->get(ps, _onelabClient->getName() + "/Action");
1227 if(ps.size()) return ps[0].getValue();
1228 }
1229 #endif
1230 return "";
1231 }
1232
LoadOnelabClient(const std::string & clientName,const std::string & sockName)1233 void Msg::LoadOnelabClient(const std::string &clientName, const std::string &sockName)
1234 {
1235 #if defined(HAVE_ONELAB)
1236 onelab::remoteNetworkClient *client = nullptr;
1237 client = new onelab::remoteNetworkClient(clientName, sockName);
1238 if(client){
1239 std::string action, cmd;
1240 std::vector<onelab::string> ps;
1241 client->get(ps, clientName + "/Action");
1242 if(ps.size() && ps[0].getValue().size())
1243 action.assign(ps[0].getValue());
1244 //cmd.assign("");
1245 if(!action.compare("compute")){
1246 std::vector<onelab::string> ps;
1247 client->get(ps,clientName+"/FullCmdLine");
1248 if(ps.size() && ps[0].getValue().size())
1249 cmd.assign(ps[0].getValue());
1250
1251 if(cmd.size()){
1252 Msg::Info("Loader calls <%s>", cmd.c_str());
1253 //client->sendInfo(strcat("Loader calls",cmd.c_str()));
1254 std::cout << "Loader calls " << cmd << std::endl;
1255 SystemCall(cmd.c_str(), true); //true->blocking
1256 }
1257 else
1258 Msg::Info("No full command line found for <%s>",
1259 clientName.c_str());
1260 }
1261 Msg::Info("Stopping client <%s>", clientName.c_str());
1262 delete client;
1263 }
1264 exit(1);
1265 #endif
1266 }
1267
GetGmshClient()1268 GmshClient *Msg::GetGmshClient()
1269 {
1270 return _client;
1271 }
1272
GetNumOnelabClients()1273 int Msg::GetNumOnelabClients()
1274 {
1275 #if defined(HAVE_ONELAB)
1276 return onelab::server::instance()->getNumClients();
1277 #endif
1278 return 0;
1279 }
1280
1281 #if defined(HAVE_ONELAB)
_setStandardOptions(onelab::parameter * p,std::map<std::string,std::vector<double>> & fopt,std::map<std::string,std::vector<std::string>> & copt)1282 static void _setStandardOptions(onelab::parameter *p,
1283 std::map<std::string, std::vector<double> > &fopt,
1284 std::map<std::string, std::vector<std::string> > &copt)
1285 {
1286 // strings
1287 if(copt.count("Label")) p->setLabel(copt["Label"][0]);
1288 if(copt.count("ShortHelp")) // for backward compatibility
1289 p->setLabel(copt["ShortHelp"][0]);
1290 if(copt.count("Help")) p->setHelp(copt["Help"][0]);
1291 if(copt.count("Highlight")) p->setAttribute("Highlight", copt["Highlight"][0]);
1292 if(copt.count("Macro")) p->setAttribute("Macro", copt["Macro"][0]);
1293 if(copt.count("GmshOption")) p->setAttribute("GmshOption", copt["GmshOption"][0]);
1294 if(copt.count("ServerAction")) p->setAttribute("ServerAction", copt["ServerAction"][0]);
1295 if(copt.count("Units")) p->setAttribute("Units", copt["Units"][0]);
1296 if(copt.count("AutoCheck")) // for backward compatibility
1297 p->setAttribute("AutoCheck", copt["AutoCheck"][0]);
1298
1299 // numbers
1300 if(fopt.count("Visible")) p->setVisible(fopt["Visible"][0] ? true : false);
1301 if(fopt.count("ReadOnly")) p->setReadOnly(fopt["ReadOnly"][0] ? true : false);
1302 if(fopt.count("NeverChanged")) p->setNeverChanged(fopt["NeverChanged"][0] ? true : false);
1303 if(fopt.count("ChangedValue")) p->setChangedValue(fopt["ChangedValue"][0]);
1304 if(fopt.count("ReadOnlyRange"))
1305 p->setAttribute("ReadOnlyRange", fopt["ReadOnlyRange"][0] ? "1" : "0");
1306 if(fopt.count("AutoCheck"))
1307 p->setAttribute("AutoCheck", fopt["AutoCheck"][0] ? "1" : "0");
1308 }
1309
_setOtherAttributes(onelab::parameter * p,std::map<std::string,std::vector<std::string>> & copt)1310 static void _setOtherAttributes(onelab::parameter *p,
1311 std::map<std::string, std::vector<std::string> > &copt)
1312 {
1313 for(auto it = copt.begin(); it != copt.end(); it++)
1314 if(p->getAttribute(it->first).empty() &&
1315 it->first.compare("Name") &&
1316 it->first.compare("Label") &&
1317 it->first.compare("ShortHelp") &&
1318 it->first.compare("Help") &&
1319 it->first.compare("Visible") &&
1320 it->first.compare("ReadOnly") &&
1321 it->first.compare("NeverChanged") &&
1322 it->first.compare("ChangedValue")) // Attribute 'it' was not already set
1323 p->setAttribute(it->first, it->second[0]);
1324 }
1325
_getParameterName(const std::string & key,std::map<std::string,std::vector<std::string>> & copt)1326 static std::string _getParameterName(const std::string &key,
1327 std::map<std::string, std::vector<std::string> > &copt)
1328 {
1329 std::string name(key);
1330 if(copt.count("Path")){
1331 std::string path = copt["Path"][0];
1332 // if path ends with a number, assume it's for ordering purposes
1333 if(path.size() && path[path.size() - 1] >= '0' && path[path.size() - 1] <= '9')
1334 name = path + name;
1335 else if(path.size() && path[path.size() - 1] == '/')
1336 name = path + name;
1337 else
1338 name = path + "/" + name;
1339 }
1340 return name;
1341 }
1342 #endif
1343
ExchangeOnelabParameter(const std::string & key,std::vector<double> & val,std::map<std::string,std::vector<double>> & fopt,std::map<std::string,std::vector<std::string>> & copt)1344 void Msg::ExchangeOnelabParameter(const std::string &key,
1345 std::vector<double> &val,
1346 std::map<std::string, std::vector<double> > &fopt,
1347 std::map<std::string, std::vector<std::string> > &copt)
1348 {
1349 #if defined(HAVE_ONELAB)
1350 if(!_onelabClient) return;
1351
1352 std::string name;
1353 if(copt.count("Name"))
1354 name = copt["Name"][0];
1355
1356 if(name.empty()){
1357 if(copt.size() || fopt.size())
1358 Msg::Error("From now on you need to use the `Name' attribute to create a "
1359 "ONELAB parameter: `Name \"%s\"'",
1360 _getParameterName(key, copt).c_str());
1361 return;
1362 }
1363
1364 std::vector<onelab::number> ps;
1365 _onelabClient->get(ps, name);
1366 bool noRange = true, noChoices = true, noLoop = true;
1367 bool noGraph = true, noClosed = true;
1368 if(ps.size()){
1369 bool useLocalValue = ps[0].getReadOnly();
1370 if(fopt.count("ReadOnly")) useLocalValue = fopt["ReadOnly"][0];
1371 if(useLocalValue)
1372 ps[0].setValues(val);
1373 else
1374 val = ps[0].getValues(); // use value from server
1375 // keep track of these attributes, which can be changed server-side (unless
1376 // they are not visible or, for the range/choices, when explicitly setting
1377 // these attributes as ReadOnly)
1378 if(ps[0].getVisible()){
1379 if(!(fopt.count("ReadOnlyRange") && fopt["ReadOnlyRange"][0])){
1380 if(ps[0].getMin() != -onelab::parameter::maxNumber() ||
1381 ps[0].getMax() != onelab::parameter::maxNumber() ||
1382 ps[0].getStep() != 0.) noRange = false;
1383 if(ps[0].getChoices().size()) noChoices = false;
1384 }
1385 if(ps[0].getAttribute("Loop").size()) noLoop = false;
1386 if(ps[0].getAttribute("Graph").size()) noGraph = false;
1387 if(ps[0].getAttribute("Closed").size()) noClosed = false;
1388 }
1389 }
1390 else{
1391 ps.resize(1);
1392 ps[0].setName(name);
1393 ps[0].setValues(val);
1394 }
1395 // send updated parameter to server
1396 if(noRange && fopt.count("Range") && fopt["Range"].size() == 2){
1397 ps[0].setMin(fopt["Range"][0]); ps[0].setMax(fopt["Range"][1]);
1398 }
1399 else if(noRange && fopt.count("Min") && fopt.count("Max")){
1400 ps[0].setMin(fopt["Min"][0]); ps[0].setMax(fopt["Max"][0]);
1401 }
1402 else if(noRange && fopt.count("Min")){
1403 ps[0].setMin(fopt["Min"][0]); ps[0].setMax(onelab::parameter::maxNumber());
1404 }
1405 else if(noRange && fopt.count("Max")){
1406 ps[0].setMax(fopt["Max"][0]); ps[0].setMin(-onelab::parameter::maxNumber());
1407 }
1408 if(noRange && fopt.count("Step")) ps[0].setStep(fopt["Step"][0]);
1409 // if no range/min/max/step info is provided, try to compute a reasonnable
1410 // range and step (this makes the gui much nicer to use)
1411 if(val.size() && noRange && !fopt.count("Range") && !fopt.count("Step") &&
1412 !fopt.count("Min") && !fopt.count("Max")){
1413 bool isInteger = (floor(val[0]) == val[0]);
1414 double fact = isInteger ? 5. : 20.;
1415 if(val[0] > 0){
1416 ps[0].setMin(val[0] / fact);
1417 ps[0].setMax(val[0] * fact);
1418 ps[0].setStep((ps[0].getMax() - ps[0].getMin()) / 100.);
1419 }
1420 else if(val[0] < 0){
1421 ps[0].setMin(val[0] * fact);
1422 ps[0].setMax(val[0] / fact);
1423 ps[0].setStep((ps[0].getMax() - ps[0].getMin()) / 100.);
1424 }
1425 if(val[0] && isInteger){
1426 ps[0].setMin((int)ps[0].getMin());
1427 ps[0].setMax((int)ps[0].getMax());
1428 ps[0].setStep((int)ps[0].getStep());
1429 }
1430 }
1431 if(noChoices && fopt.count("Choices")){
1432 ps[0].setChoices(fopt["Choices"]);
1433 if(copt.count("Choices")) ps[0].setChoiceLabels(copt["Choices"]);
1434 }
1435 if(noLoop && copt.count("Loop")) // for backward compatibity
1436 ps[0].setAttribute("Loop", copt["Loop"][0]);
1437 if(noLoop && fopt.count("Loop"))
1438 ps[0].setAttribute("Loop", (fopt["Loop"][0] == 3.) ? "3" :
1439 (fopt["Loop"][0] == 2.) ? "2" :
1440 (fopt["Loop"][0] == 1.) ? "1" : "");
1441 if(noGraph && copt.count("Graph")) ps[0].setAttribute("Graph", copt["Graph"][0]);
1442 if(noClosed && copt.count("Closed")) // for backward compatibility
1443 ps[0].setAttribute("Closed", copt["Closed"][0]);
1444 if(noClosed && fopt.count("Closed"))
1445 ps[0].setAttribute("Closed", fopt["Closed"][0] ? "1" : "0");
1446 if(copt.count("NumberFormat"))
1447 ps[0].setAttribute("NumberFormat", copt["NumberFormat"][0]);
1448 _setStandardOptions(&ps[0], fopt, copt);
1449 _setOtherAttributes(&ps[0], copt);
1450 _onelabClient->set(ps[0]);
1451 #endif
1452 }
1453
ExchangeOnelabParameter(const std::string & key,std::string & val,std::map<std::string,std::vector<double>> & fopt,std::map<std::string,std::vector<std::string>> & copt)1454 void Msg::ExchangeOnelabParameter(const std::string &key,
1455 std::string &val,
1456 std::map<std::string, std::vector<double> > &fopt,
1457 std::map<std::string, std::vector<std::string> > &copt)
1458 {
1459 #if defined(HAVE_ONELAB)
1460 if(!_onelabClient) return;
1461
1462 std::string name;
1463 if(copt.count("Name"))
1464 name = copt["Name"][0];
1465
1466 if(name.empty()){
1467 if(copt.size() || fopt.size())
1468 Msg::Error("From now on you need to use the `Name' attribute to create a "
1469 "ONELAB parameter: `Name \"%s\"'",
1470 _getParameterName(key, copt).c_str());
1471 return;
1472 }
1473
1474 std::vector<onelab::string> ps;
1475 _onelabClient->get(ps, name);
1476 bool noChoices = true, noClosed = true, noMultipleSelection = true;
1477 if(ps.size()){
1478 bool useLocalValue = ps[0].getReadOnly();
1479 if(fopt.count("ReadOnly")) useLocalValue = fopt["ReadOnly"][0];
1480 if(useLocalValue)
1481 ps[0].setValue(val); // use local value
1482 else
1483 val = ps[0].getValue(); // use value from server
1484 // keep track of these attributes, which can be changed server-side (unless
1485 // they are not visible)
1486 if(ps[0].getVisible()){
1487 if(ps[0].getChoices().size()) noChoices = false;
1488 if(ps[0].getAttribute("Closed").size()) noClosed = false;
1489 if(ps[0].getAttribute("MultipleSelection").size()) noMultipleSelection = false;
1490 }
1491 }
1492 else{
1493 ps.resize(1);
1494 ps[0].setName(name);
1495 ps[0].setValue(val);
1496 }
1497 if(copt.count("Kind")) ps[0].setKind(copt["Kind"][0]);
1498 if(noChoices && copt.count("Choices")) ps[0].setChoices(copt["Choices"]);
1499 if(noClosed && copt.count("Closed")) // for backward compatibility
1500 ps[0].setAttribute("Closed", copt["Closed"][0]);
1501 if(noClosed && fopt.count("Closed"))
1502 ps[0].setAttribute("Closed", fopt["Closed"][0] ? "1" : "0");
1503 if(noMultipleSelection && copt.count("MultipleSelection"))
1504 ps[0].setAttribute("MultipleSelection", copt["MultipleSelection"][0]);
1505 _setStandardOptions(&ps[0], fopt, copt);
1506 _setOtherAttributes(&ps[0], copt);
1507 _onelabClient->set(ps[0]);
1508 #endif
1509 }
1510
UndefineOnelabParameter(const std::string & name)1511 void Msg::UndefineOnelabParameter(const std::string &name)
1512 {
1513 #if defined(HAVE_ONELAB)
1514 if(!_onelabClient) return;
1515 _onelabClient->clear(name);
1516 #endif
1517 }
1518
ImportPhysicalGroupsInOnelab()1519 void Msg::ImportPhysicalGroupsInOnelab()
1520 {
1521 #if defined(HAVE_ONELAB)
1522 if(_onelabClient){
1523 std::vector<onelab::number> oldn;
1524 _onelabClient->get(oldn, "Gmsh/Number of physical groups");
1525 int oldsize = 0;
1526 if(oldn.size()) oldsize = (int)oldn[0].getValue();
1527
1528 std::map<int, std::vector<GEntity*> > groups[4];
1529 GModel::current()->getPhysicalGroups(groups);
1530 int size = 0;
1531 for(int dim = 0; dim <= 3; dim++)
1532 size += groups[dim].size();
1533 onelab::number n("Gmsh/Number of physical groups", size);
1534 n.setReadOnly(true);
1535 n.setChangedValue(1);
1536 n.setVisible(false);
1537 n.setAttribute("Closed", "1");
1538 _onelabClient->set(n);
1539
1540 onelab::number nd("Gmsh/Model dimension", GModel::current()->getDim());
1541 nd.setReadOnly(true);
1542 nd.setChangedValue(1);
1543 nd.setVisible(false);
1544 nd.setAttribute("Closed", "1");
1545 _onelabClient->set(nd);
1546
1547 int index = 1;
1548 for(int dim = 0; dim <= 3; dim++){
1549 for(auto it = groups[dim].begin();
1550 it != groups[dim].end(); it++){
1551 int num = it->first;
1552 std::string name = GModel::current()->getPhysicalName(dim, it->first);
1553 char tmp[256];
1554 if(name.empty()){
1555 sprintf(tmp, "Physical %s %d", (dim == 3) ? "Volume" : (dim == 2) ? "Surface" :
1556 (dim == 1) ? "Curve" : "Point", num);
1557 name = tmp;
1558 }
1559 sprintf(tmp, "Gmsh/Physical group %d/", index);
1560 std::string str = tmp;
1561 onelab::number n1(str + "Dimension", dim);
1562 n1.setReadOnly(true);
1563 n1.setChangedValue(1);
1564 n1.setVisible(false);
1565 _onelabClient->set(n1);
1566 onelab::number n2(str + "Number", num);
1567 n2.setReadOnly(true);
1568 n2.setChangedValue(1);
1569 n2.setVisible(false);
1570 _onelabClient->set(n2);
1571 onelab::string s(str + "Name", name);
1572 s.setReadOnly(true);
1573 s.setChangedValue(1);
1574 s.setVisible(false);
1575 _onelabClient->set(s);
1576 index++;
1577 }
1578 }
1579
1580 // remove old ones
1581 for(int index = size + 1; index < oldsize + 1; index++){
1582 char tmp[256];
1583 sprintf(tmp, "Gmsh/Physical group %d/Dimension", index);
1584 _onelabClient->clear(tmp);
1585 sprintf(tmp, "Gmsh/Physical group %d/Number", index);
1586 _onelabClient->clear(tmp);
1587 sprintf(tmp, "Gmsh/Physical group %d/Name", index);
1588 _onelabClient->clear(tmp);
1589 }
1590
1591 #if defined(HAVE_FLTK)
1592 if(FlGui::available()){
1593 FlGui::instance()->resetVisibility();
1594 FlGui::instance()->rebuildTree(false);
1595 }
1596 #endif
1597 }
1598 #endif
1599 }
1600
RunOnelabClient(const std::string & name,const std::string & command)1601 void Msg::RunOnelabClient(const std::string &name, const std::string &command)
1602 {
1603 #if defined(HAVE_ONELAB)
1604 onelabUtils::runClient(name, command);
1605 #endif
1606 }
1607
SetOnelabChanged(int value,const std::string & client)1608 void Msg::SetOnelabChanged(int value, const std::string &client)
1609 {
1610 #if defined(HAVE_ONELAB)
1611 onelab::server::instance()->setChanged(value, client);
1612 #endif
1613 }
1614
Barrier()1615 void Msg::Barrier()
1616 {
1617 #if defined(HAVE_MPI)
1618 MPI_Barrier(MPI_COMM_WORLD);
1619 #endif
1620 }
1621
1622 #if defined(_OPENMP)
1623
GetNumThreads()1624 int Msg::GetNumThreads(){ return omp_get_num_threads(); }
SetNumThreads(int num)1625 void Msg::SetNumThreads(int num){ omp_set_num_threads(num); }
GetMaxThreads()1626 int Msg::GetMaxThreads(){ return omp_get_max_threads(); }
GetThreadNum()1627 int Msg::GetThreadNum(){ return omp_get_thread_num(); }
1628
1629 #else
1630
GetNumThreads()1631 int Msg::GetNumThreads(){ return 1; }
SetNumThreads(int num)1632 void Msg::SetNumThreads(int num)
1633 {
1634 if(num > 1)
1635 Msg::Warning("Setting number of threads to %d requires OpenMP", num);
1636 }
GetMaxThreads()1637 int Msg::GetMaxThreads(){ return 1; }
GetThreadNum()1638 int Msg::GetThreadNum(){ return 0; }
1639
1640 #endif
1641
MsgProgressStatus(int num)1642 MsgProgressStatus::MsgProgressStatus(int num)
1643 : _totalElementToTreat(num), _currentI(0), _nextIToCheck(0),
1644 _initialTime(Cpu()), _lastTime(_initialTime), _lastPercentage(0),
1645 _progressMeterStep(Msg::GetProgressMeterStep())
1646 {
1647 Msg::SetProgressMeterStep(1);
1648 Msg::StartProgressMeter(_totalElementToTreat);
1649 }
1650
~MsgProgressStatus()1651 MsgProgressStatus::~MsgProgressStatus()
1652 {
1653 Msg::ProgressMeter(_totalElementToTreat, true, "done");
1654 Msg::SetProgressMeterStep(_progressMeterStep);
1655 Msg::StopProgressMeter();
1656 }
1657
next()1658 void MsgProgressStatus::next()
1659 {
1660 if(Msg::GetCommRank() || Msg::GetNumThreads() > 1) return;
1661
1662 ++_currentI;
1663 if (_currentI < _nextIToCheck) return;
1664
1665 int currentPercentage = _currentI * 100 / _totalElementToTreat;
1666 // check every percentage only
1667 _nextIToCheck = (currentPercentage + 1) * _totalElementToTreat / 100 + 1;
1668
1669 double currentTime = Cpu();
1670 if ((currentPercentage < 5 && currentTime - _lastTime > 15.) ||
1671 (currentPercentage > _lastPercentage + 4 && currentTime - _lastTime > 10.)) {
1672 _lastPercentage = currentPercentage;
1673 _lastTime = currentTime;
1674 const double remaining = (currentTime - _initialTime) / (_currentI + 1) *
1675 (_totalElementToTreat - _currentI - 1);
1676 if (remaining < 60*2)
1677 Msg::ProgressMeter(_currentI - 1, true,
1678 "%d%% (remaining time ~%g seconds)",
1679 currentPercentage, remaining);
1680 else if (remaining < 60*60*2)
1681 Msg::ProgressMeter(_currentI - 1, true,
1682 "%d%% (remaining time ~%g minutes)",
1683 currentPercentage, remaining / 60);
1684 else
1685 Msg::ProgressMeter(_currentI - 1, true,
1686 "%d%% (remaining time ~%g hours)",
1687 currentPercentage, remaining / 3600);
1688 }
1689 }
1690