Flow123d  master-c754b67
main.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file main.cc
15  * @brief This file should contain only creation of Application object.
16  */
17 
18 
19 #include "system/system.hh"
20 #include "system/sys_profiler.hh"
21 #include "system/python_loader.hh"
23 #include "coupling/balance.hh"
24 #include "input/accessors.hh"
27 
28 #include <iostream>
29 #include <fstream>
30 #include <regex>
31 #include <boost/program_options/parsers.hpp>
32 #include <boost/program_options/variables_map.hpp>
33 #include <boost/program_options/options_description.hpp>
34 #include <boost/filesystem.hpp>
35 #include <thread> // std::this_thread::sleep_for
36 #include <chrono> // std::chrono::seconds
37 
38 
39 #include "main.h"
40 
41 #include "rev_num.h"
42 
43 /// named version of the program
44 //#define _PROGRAM_VERSION_ "0.0.0"
45 
46 //#ifndef _PROGRAM_REVISION_
47 // #define _PROGRAM_REVISION_ "(unknown revision)"
48 //#endif
49 
50 //#ifndef _PROGRAM_BRANCH_
51 // #define _PROGRAM_BRANCH_ "(unknown branch)"
52 //#endif
53 
54 #ifndef FLOW123D_COMPILER_FLAGS_
55  #define FLOW123D_COMPILER_FLAGS_ "(unknown compiler flags)"
56 #endif
57 
58 
59 namespace it = Input::Type;
60 
61 // this should be part of a system class containing all support information
63  static it::Record type = it::Record("Root", "Root record of JSON input for Flow123d.")
64  .declare_key("flow123d_version", it::String(), it::Default::obligatory(),
65  "Version of Flow123d for which the input file was created."
66  "Flow123d only warn about version incompatibility. "
67  "However, external tools may use this information to provide conversion "
68  "of the input file to the structure required by another version of Flow123d.")
70  "Simulation problem to be solved.")
71  .declare_key("pause_after_run", it::Bool(), it::Default("false"),
72  "If true, the program will wait for key press before it terminates.")
73  .close();
74 
75  return type;
76 }
77 
78 
79 // Note: python_path might be unused if compiling without python support
80 Application::Application(FMT_UNUSED const std::string &python_path)
81 : ApplicationBase(),
82  problem_(nullptr),
83  main_input_filename_(""),
84  //passed_argc_(0),
85  //passed_argv_(0),
86  use_profiler(true),
87  profiler_path(""),
88  yaml_balance_output_(false)
89 {
90  // initialize python stuff if we have
91  // nonstandard python home (release builds)
93 
94 }
95 
96 
98  Input::Type::RevNumData rev_num_data;
99 
100  rev_num_data.version = string(FLOW123D_VERSION_NAME_);
101  rev_num_data.revision = string(FLOW123D_GIT_REVISION_);
102  rev_num_data.branch = string(FLOW123D_GIT_BRANCH_);
103  rev_num_data.url = string(FLOW123D_GIT_URL_);
104 
105  return rev_num_data;
106 }
107 
108 
110  // Say Hello
111  // make strings from macros in order to check type
112  Input::Type::RevNumData rev_num_data = this->get_rev_num_data();
113  string build = string(__DATE__) + ", " + string(__TIME__)
114  + " flags: " + string(FLOW123D_COMPILER_FLAGS_);
115 
116 
117  MessageOut().fmt("This is Flow123d, version {} commit: {}\n",
118  rev_num_data.version, rev_num_data.revision);
119  MessageOut().fmt("Branch: {}\nBuild: {}\nFetch URL: {}\n",
120  rev_num_data.branch, build, rev_num_data.url );
121  Profiler::instance()->set_program_info("Flow123d",
122  rev_num_data.version, rev_num_data.branch, rev_num_data.revision, build);
123 }
124 
125 
126 
128  if (main_input_filename_ == "") {
129  cout << "Usage error: The main input file has to be specified through -s parameter.\n\n";
130  cout << program_arguments_desc_ << "\n";
131  exit( exit_failure );
132  }
133 
134  // read main input file
135  FilePath fpath(main_input_filename_, FilePath::FileType::input_file);
136 
137  Input::ReaderToStorage json_reader(fpath, get_input_type() );
139 
140  return root_record;
141 }
142 
143 
144 
145 void Application::parse_cmd_line(const int argc, char ** argv) {
146  namespace po = boost::program_options;
147 
148 
149  // Declare the supported options.
150  po::options_description desc("Allowed options");
151  desc.add_options()
152  ("help", "produce help message")
153  ("solve,s", po::value< string >(), "Main input file to solve.")
154  ("input_dir,i", po::value< string >()->default_value("input"), "Directory for the $INPUT_DIR$ placeholder in the main input file.")
155  ("output_dir,o", po::value< string >()->default_value("output"), "Directory for all produced output files.")
156  ("log,l", po::value< string >()->default_value("flow123"), "Set base name for log files.")
157  ("version", "Display version and build information and exit.")
158  ("no_log", "Turn off logging.")
159  ("no_signal_handler", "Turn off signal handling. Useful for debugging with valgrind.")
160  ("no_profiler,no-profiler", "Turn off profiler output.")
161  ("profiler_path,profiler-path", po::value< string >(), "Path to the profiler file")
162  ("input_format", po::value< string >(), "Writes full structure of the main input file into given file.")
163  ("petsc_redirect", po::value<string>(), "Redirect all PETSc stdout and stderr to given file.")
164  ("yaml_balance", "Redirect balance output to YAML format too (simultaneously with the selected balance output format).");
165 
166  ;
167 
168  // Can not use positional arguments together with PETSC options.
169  // Use our own solution trying to use the first unrecognized option as the main input file.
170 
171  // parse the command line
172  po::variables_map vm;
173  auto parser = po::basic_command_line_parser<char>(argc, argv)
174  .options(desc)
175  .allow_unregistered();
176  po::parsed_options parsed = parser.run();
177  po::store(parsed, vm);
178  po::notify(vm);
179 
180  // get unknown options
181  vector<string> to_pass_further = po::collect_unrecognized(parsed.options, po::include_positional);
182 
183 
184  /*
185  passed_argc_ = to_pass_further.size();
186  passed_argv_ = new char * [passed_argc_+1];
187 
188  // first copy the program executable in argv[0]
189  int arg_i=0;
190  if (argc > 0) passed_argv_[arg_i++] = xstrcpy( argv[0] );
191 
192  for(int i=0; i < passed_argc_; i++) {
193  passed_argv_[arg_i++] = xstrcpy( to_pass_further[i].c_str() );
194  }
195  passed_argc_ = arg_i;
196  */
197 
198  // possibly turn off profilling
199  if (vm.count("no_profiler")) {
200  use_profiler=false;
201  }
202 
203  if (vm.count("profiler_path")) {
204  profiler_path = vm["profiler_path"].as<string>();
205  }
206 
207  // if there is "help" option
208  if (vm.count("help")) {
209  display_version();
210  cout << endl;
211  cout << "Usage:" << endl;
212  cout << " flow123d -s <main_input>.yaml <other options> <PETSC options>" << endl;
213  cout << " flow123d <main_input>.yaml <other options> <PETSC options>" << endl;
214  cout << desc << "\n";
215  exit( exit_output );
216  }
217 
218  if (vm.count("version")) {
219  display_version();
220  exit( exit_output );
221  }
222 
223  // if there is "input_format" option
224  if (vm.count("input_format")) {
225  // write ist to json file
226  ofstream json_stream;
227  FilePath(vm["input_format"].as<string>(), FilePath::output_file).open_stream(json_stream);
228  // create the root Record
229  it::Record root_type = get_input_type();
230  root_type.finish();
232  json_stream << Input::Type::OutputJSONMachine( root_type, this->get_rev_num_data() );
233  json_stream.close();
234  exit( exit_output );
235  }
236 
237  if (vm.count("petsc_redirect")) {
238  this->petsc_redirect_file_ = vm["petsc_redirect"].as<string>();
239  }
240 
241  if (vm.count("no_signal_handler")) {
242  this->signal_handler_off_ = true;
243  }
244 
245  // if there is "solve" option
246  string input_filename = "";
247 
248  // check for positional main input file
249  if (to_pass_further.size()) {
250  string file_candidate = to_pass_further[0];
251  if (file_candidate[0] != '-') {
252  // pop the first option
253  input_filename = file_candidate;
254  to_pass_further.erase(to_pass_further.begin());
255  }
256  }
257 
258  if (vm.count("solve")) {
259  input_filename = vm["solve"].as<string>();
260  }
261 
262  if (input_filename == "")
263  THROW(ExcMessage() << EI_Message("Main input file not specified (option -s)."));
264 
265  // preserves output of balance in YAML format
266  if (vm.count("yaml_balance")) Balance::set_yaml_output();
267 
268  string input_dir;
269  string output_dir;
270  if (vm.count("input_dir")) {
271  input_dir = vm["input_dir"].as<string>();
272  }
273  if (vm.count("output_dir")) {
274  output_dir = vm["output_dir"].as<string>();
275  }
276 
277  // assumes working directory "."
278  try {
279  main_input_filename_ = FilePath::set_dirs_from_input(input_filename, input_dir, output_dir );
280  } catch (FilePath::ExcMkdirFail &e) {
281  use_profiler = false; // avoid profiler output
282  throw e;
283  }
284 
285  if (vm.count("log")) {
286  this->log_filename_ = vm["log"].as<string>();
287  }
288 
289  if (vm.count("no_log")) {
290  this->log_filename_="//"; // override; do not open log files
291  }
292 
293  ostringstream tmp_stream(program_arguments_desc_);
294  tmp_stream << desc;
295  // TODO: catch specific exceptions and output usage messages
296 }
297 
298 
299 
300 
301 
303  START_TIMER("Application::run");
304  display_version();
305 
306  START_TIMER("Read Input");
307  // get main input record handle
308  Input::Record i_rec = read_input();
309  END_TIMER("Read Input");
310 
311  {
312  using namespace Input;
313  // check input file version against the version of executable
314  std::regex version_re("([^.]*)[.]([^.]*)[.]([^.]*)");
315  std::smatch match;
316  std::string version(FLOW123D_VERSION_NAME_);
317  vector<string> ver_fields(3);
318  if ( std::regex_match(version, match, version_re) ) {
319  ver_fields[0]=match[1];
320  ver_fields[1]=match[2];
321  ver_fields[2]=match[3];
322  } else {
323  ASSERT_PERMANENT(0)(version).error("Bad Flow123d version format\n");
324  }
325 
326  std::string input_version = i_rec.val<string>("flow123d_version");
327  vector<string> iver_fields(3);
328  if ( std::regex_match(input_version, match, version_re) ) {
329  iver_fields[0]=match[1];
330  iver_fields[1]=match[2];
331  iver_fields[2]=match[3];
332  } else {
333  THROW( ExcVersionFormat() << EI_InputVersionStr(input_version) );
334  }
335 
336  if ( iver_fields[0] != ver_fields[0] || iver_fields[1] > ver_fields[1] ) {
337  WarningOut().fmt("Input file with version: '{}' is no compatible with the program version: '{}' \n",
338  input_version, version);
339  }
340 
341  // should flow123d wait for pressing "Enter", when simulation is completed
342  sys_info.pause_after_run = i_rec.val<bool>("pause_after_run");
343  // read record with problem configuration
344  Input::AbstractRecord i_problem = i_rec.val<AbstractRecord>("problem");
345 
346  if (i_problem.type() == HC_ExplicitSequential::get_input_type() ) {
347 
348  problem_ = new HC_ExplicitSequential(i_problem);
349 
350  // run simulation
352  } else {
353  THROW( ExcUnknownProblem() );
354  }
355 
356  }
357 
358  this->after_run();
359 }
360 
361 
362 
363 
366  printf("\nPress <ENTER> for closing the window\n");
367  getchar();
368  }
369 }
370 
371 
372 
373 
375  // Test if all processes are in the exception.
376  MPI_Request request;
377  MPI_Ibarrier(MPI_COMM_WORLD, &request);
378  std::this_thread::sleep_for(std::chrono::microseconds(10));
379  int done;
380  MPI_Status status;
381  MPI_Test(&request, &done, &status);
382  if (! done) {
383  // Kill all if we can not synchronize.
385  }
386  // Peacefull end.
387 }
388 
389 
390 
391 
393  if (problem_) delete problem_;
394 
395  if (use_profiler) {
396  if (petsc_initialized) {
397  // log profiler data to this stream
398  Profiler::instance()->output (PETSC_COMM_WORLD, profiler_path);
399  } else {
401  }
402 
403  // call python script which transforms json file at given location
404  // Profiler::instance()->transform_profiler_data (".csv", "CSVFormatter");
405  Profiler::instance()->transform_profiler_data (".txt", "SimpleTableFormatter2");
406 
407  // finally uninitialize
409  }
410 }
411 
412 
413 //=============================================================================
414 
415 /**
416  * FUNCTION "MAIN"
417  */
418 int main(int argc, char **argv) {
419  Application app(argv[0]);
420  try {
421  app.init(argc, argv);
422  app.run();
423  } catch (std::exception & e) {
424  _LOG( Logger::MsgType::error ).every_proc() << e.what();
425  app.terminate();
427  } catch (...) {
428  _LOG( Logger::MsgType::error ).every_proc() << "Unknown exception" << endl;
429  app.terminate();
431  }
432 
433  // Say Goodbye
435 }
Input::Type::Bool
Class for declaration of the input of type Bool.
Definition: type_base.hh:452
reader_to_storage.hh
MPI_Request
void * MPI_Request
Definition: mpi.h:142
Application::~Application
virtual ~Application()
Destructor.
Definition: main.cc:392
Profiler::instance
static Profiler * instance(bool clear=false)
Definition: sys_profiler.cc:945
Input::ReaderToStorage
Reader for (slightly) modified input files.
Definition: reader_to_storage.hh:96
python_loader.hh
Input
Abstract linear system class.
Definition: balance.hh:40
ApplicationBase::init
void init(int argc, char **argv)
Definition: application_base.cc:214
CouplingBase::get_input_type
static Input::Type::Abstract & get_input_type()
Definition: hc_explicit_sequential.cc:51
Profiler::transform_profiler_data
void transform_profiler_data(const string &, const string &)
Definition: sys_profiler.hh:900
Input::Type::RevNumData::url
std::string url
Url of application.
Definition: type_output.hh:48
Application::get_rev_num_data
Input::Type::RevNumData get_rev_num_data()
Get version of program and other base data from rev_num.h and store them to map.
Definition: main.cc:97
MPI_Abort
#define MPI_Abort
Definition: mpi.h:222
Input::Record::val
const Ret val(const string &key) const
Definition: accessors_impl.hh:31
FilePath
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
Profiler::output
void output(MPI_Comm, ostream &)
Definition: sys_profiler.hh:888
Application::profiler_path
string profiler_path
location of the profiler report file
Definition: main.h:116
Application::main_input_filename_
string main_input_filename_
filename of main input file
Definition: main.h:104
Application::after_run
void after_run()
Definition: main.cc:364
THROW
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
std::vector
Definition: doxy_dummy_defs.hh:7
system.hh
Application::problem_
HC_ExplicitSequential * problem_
Main Flow123d problem.
Definition: main.h:101
reader_internal_base.hh
FLOW123D_COMPILER_FLAGS_
#define FLOW123D_COMPILER_FLAGS_
named version of the program
Definition: main.cc:55
Application
Definition: main.h:35
Profiler::uninitialize
static void uninitialize()
Definition: sys_profiler.cc:958
Application::terminate
void terminate()
Definition: main.cc:374
FilePath::open_stream
void open_stream(Stream &stream) const
Definition: file_path.cc:211
Application::Application
Application(const std::string &python_path)
Application constructor.
Definition: main.cc:80
Profiler::set_program_info
void set_program_info(string, string, string, string, string)
Definition: sys_profiler.hh:882
Input::Type::Default
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
Application::use_profiler
bool use_profiler
If true, we do output of profiling information.
Definition: main.h:113
Input::Type::RevNumData::branch
std::string branch
Actual branch of application.
Definition: type_output.hh:47
ApplicationBase::petsc_redirect_file_
string petsc_redirect_file_
Definition: application_base.hh:149
ApplicationBase::log_filename_
string log_filename_
Definition: application_base.hh:145
Input::Record
Accessor to the data with type Type::Record.
Definition: accessors.hh:291
sys_profiler.hh
ASSERT_PERMANENT
#define ASSERT_PERMANENT(expr)
Allow use shorter versions of macro names if these names is not used with external library.
Definition: asserts.hh:348
MPI_Test
#define MPI_Test(request, flag, status)
Definition: mpi.h:366
hc_explicit_sequential.hh
Application::get_input_type
static Input::Type::Record & get_input_type()
Root of the Input::Type tree. Description of whole input structure.
Definition: main.cc:62
ApplicationBase
Definition: application_base.hh:65
accessors.hh
Input::Type::RevNumData
Stores version of program and other base data of application.
Definition: type_output.hh:44
Input::AbstractRecord
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:458
Input::Type::Default::obligatory
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
Input::Type::Record::declare_key
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:503
Input::ReaderToStorage::get_root_interface
T get_root_interface() const
Returns the root accessor.
Definition: reader_to_storage.cc:150
main
int main(int argc, char **argv)
Definition: main.cc:418
FilePath::set_dirs_from_input
static string set_dirs_from_input(const string main_yaml, const string input, const string output)
Method for set input and output directories.
Definition: file_path.cc:137
Input::Type::Record::close
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
Input::Type
Definition: balance.hh:41
Input::Type::Record
Record type proxy class.
Definition: type_record.hh:182
Application::program_arguments_desc_
string program_arguments_desc_
Description of possible command line arguments.
Definition: main.h:110
ApplicationBase::exit_output
static const int exit_output
Definition: application_base.hh:84
ApplicationBase::petsc_initialized
static bool petsc_initialized
Definition: application_base.hh:86
_LOG
#define _LOG(type)
Internal macro defining universal record of log.
Definition: logger.hh:272
HC_ExplicitSequential::run_simulation
void run_simulation()
Definition: hc_explicit_sequential.cc:215
Balance::set_yaml_output
static void set_yaml_output()
Set global variable to output balance files into YAML format (in addition to the table format).
Definition: balance.cc:66
Input::Type::String
Class for declaration of the input data that are in string format.
Definition: type_base.hh:582
fmt::printf
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: printf.h:444
main.h
MPI_Status
Definition: mpi.h:144
WarningOut
#define WarningOut()
Macro defining 'warning' record of log.
Definition: logger.hh:278
Application::display_version
void display_version()
Definition: main.cc:109
ApplicationBase::signal_handler_off_
bool signal_handler_off_
Turn off signal handling useful to debug with valgrind.
Definition: application_base.hh:155
Input::Type::Record::finish
FinishStatus finish(FinishStatus finish_type=FinishStatus::regular_) override
Finish declaration of the Record type.
Definition: type_record.cc:243
sys_info
SystemInfo sys_info
Definition: system.cc:41
SystemInfo::pause_after_run
int pause_after_run
Definition: system.hh:74
ApplicationBase::exit_failure
static const int exit_failure
Definition: application_base.hh:83
Input::Type::RevNumData::revision
std::string revision
Actual revision of application.
Definition: type_output.hh:46
MPI_COMM_WORLD
#define MPI_COMM_WORLD
Definition: mpi.h:123
Application::run
void run() override
Definition: main.cc:302
HC_ExplicitSequential
Class for solution of steady or unsteady flow with sequentially coupled explicit transport.
Definition: hc_explicit_sequential.hh:49
Input::Type::RevNumData::version
std::string version
Actual version of application.
Definition: type_output.hh:45
Input::Type::OutputJSONMachine
Class for create JSON machine readable documentation.
Definition: type_output.hh:252
HC_ExplicitSequential::get_input_type
static const Input::Type::Record & get_input_type()
Definition: hc_explicit_sequential.cc:57
PythonLoader::initialize
static void initialize()
Definition: python_loader.cc:35
Input::Type::TypeBase::delete_unfinished_types
static void delete_unfinished_types()
Finishes and marks all types registered in type repositories and unused in IST.
Definition: type_base.cc:107
FilePath::output_file
@ output_file
Definition: file_path.hh:69
Application::read_input
Input::Record read_input()
Definition: main.cc:127
balance.hh
Application::root_record
Input::Record root_record
root input record
Definition: main.h:122
START_TIMER
#define START_TIMER(tag)
Starts a timer with specified tag.
Definition: sys_profiler.hh:115
END_TIMER
#define END_TIMER(tag)
Ends a timer with specified tag.
Definition: sys_profiler.hh:149
Application::parse_cmd_line
virtual void parse_cmd_line(const int argc, char **argv)
Definition: main.cc:145
MessageOut
#define MessageOut()
Macro defining 'message' record of log.
Definition: logger.hh:275
FMT_UNUSED
#define FMT_UNUSED
Definition: posix.h:75
ApplicationBase::exit_success
static const int exit_success
Return codes of application.
Definition: application_base.hh:82