Flow123d  release_1.8.2-2141-g34b6400
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 #include <petsc.h>
19 
20 
21 #include "system/system.hh"
22 #include "system/sys_profiler.hh"
23 #include "system/python_loader.hh"
25 #include "input/input_type.hh"
26 #include "input/accessors.hh"
28 
29 #include <iostream>
30 #include <fstream>
31 #include <boost/regex.hpp>
32 #include <boost/program_options/parsers.hpp>
33 #include <boost/program_options/variables_map.hpp>
34 #include <boost/program_options/options_description.hpp>
35 #include <boost/filesystem.hpp>
36 
37 #include "main.h"
38 
39 #include "rev_num.h"
40 
41 /// named version of the program
42 //#define _PROGRAM_VERSION_ "0.0.0"
43 
44 //#ifndef _PROGRAM_REVISION_
45 // #define _PROGRAM_REVISION_ "(unknown revision)"
46 //#endif
47 
48 //#ifndef _PROGRAM_BRANCH_
49 // #define _PROGRAM_BRANCH_ "(unknown branch)"
50 //#endif
51 
52 #ifndef FLOW123D_COMPILER_FLAGS_
53  #define FLOW123D_COMPILER_FLAGS_ "(unknown compiler flags)"
54 #endif
55 
56 
57 namespace it = Input::Type;
58 
59 // this should be part of a system class containing all support information
61  static it::Record type = it::Record("Root", "Root record of JSON input for Flow123d.")
62  .declare_key("flow123d_version", it::String(), it::Default::obligatory(),
63  "Version of Flow123d for which the input file was created."
64  "Flow123d only warn about version incompatibility. "
65  "However, external tools may use this information to provide conversion "
66  "of the input file to the structure required by another version of Flow123d.")
68  "Simulation problem to be solved.")
69  .declare_key("pause_after_run", it::Bool(), it::Default("false"),
70  "If true, the program will wait for key press before it terminates.")
71  .close();
72 
73  return type;
74 }
75 
76 
77 
78 Application::Application( int argc, char ** argv)
79 : ApplicationBase(argc, argv),
80  main_input_filename_(""),
81  //passed_argc_(0),
82  //passed_argv_(0),
83  use_profiler(true),
84  yaml_balance_output_(false)
85 {
86  // initialize python stuff if we have
87  // nonstandard python home (release builds)
88 #ifdef FLOW123D_HAVE_PYTHON
89  PythonLoader::initialize(argv[0]);
90 #endif
91 
92 }
93 
94 
96  Input::Type::RevNumData rev_num_data;
97 
98  rev_num_data.version = string(FLOW123D_VERSION_NAME_);
99  rev_num_data.revision = string(FLOW123D_GIT_REVISION_);
100  rev_num_data.branch = string(FLOW123D_GIT_BRANCH_);
101  rev_num_data.url = string(FLOW123D_GIT_URL_);
102 
103  return rev_num_data;
104 }
105 
106 
108  // Say Hello
109  // make strings from macros in order to check type
110  Input::Type::RevNumData rev_num_data = this->get_rev_num_data();
111  string build = string(__DATE__) + ", " + string(__TIME__)
112  + " flags: " + string(FLOW123D_COMPILER_FLAGS_);
113 
114 
115  MessageOut().fmt("This is Flow123d, version {} revision: {}\n",
116  rev_num_data.version, rev_num_data.revision);
117  MessageOut().fmt("Branch: {}\nBuild: {}\nFetch URL: {}\n",
118  rev_num_data.branch, build, rev_num_data.url );
119  Profiler::instance()->set_program_info("Flow123d",
120  rev_num_data.version, rev_num_data.branch, rev_num_data.revision, build);
121 }
122 
123 
124 
126  if (main_input_filename_ == "") {
127  cout << "Usage error: The main input file has to be specified through -s parameter.\n\n";
128  cout << program_arguments_desc_ << "\n";
129  exit( exit_failure );
130  }
131 
132  // read main input file
133  FilePath fpath(main_input_filename_, FilePath::FileType::input_file);
134  try {
135  Input::ReaderToStorage json_reader(fpath, get_input_type() );
137  } catch (Input::ReaderToStorage::ExcInputError &e ) {
138  e << Input::ReaderToStorage::EI_File(fpath); throw;
139  } catch (Input::ReaderToStorage::ExcNotJSONFormat &e) {
140  e << Input::ReaderToStorage::EI_File(fpath); throw;
141  }
142  return root_record;
143 }
144 
145 
146 
147 
148 void Application::parse_cmd_line(const int argc, char ** argv) {
149  namespace po = boost::program_options;
150 
151 
152  // Declare the supported options.
153  po::options_description desc("Allowed options");
154  desc.add_options()
155  ("help", "produce help message")
156  ("solve,s", po::value< string >(), "Main input file to solve.")
157  ("input_dir,i", po::value< string >()->default_value("input"), "Directory for the ${INPUT} placeholder in the main input file.")
158  ("output_dir,o", po::value< string >()->default_value("output"), "Directory for all produced output files.")
159  ("log,l", po::value< string >()->default_value("flow123"), "Set base name for log files.")
160  ("version", "Display version and build information and exit.")
161  ("no_log", "Turn off logging.")
162  ("no_signal_handler", "Turn off signal handling. Useful for debugging with valgrind.")
163  ("no_profiler", "Turn off profiler output.")
164  ("JSON_machine", po::value< string >(), "Writes full structure of the main input file as a valid CON file into given file")
165  ("petsc_redirect", po::value<string>(), "Redirect all PETSc stdout and stderr to given file.")
166  ("yaml_balance", "Redirect balance output to YAML format too (simultaneously with the selected balance output format).");
167 
168  ;
169 
170  // parse the command line
171  po::variables_map vm;
172  po::parsed_options parsed = po::basic_command_line_parser<char>(argc, argv).options(desc).allow_unregistered().run();
173  po::store(parsed, vm);
174  po::notify(vm);
175 
176  // get unknown options
177  vector<string> to_pass_further = po::collect_unrecognized(parsed.options, po::include_positional);
178  /*
179  passed_argc_ = to_pass_further.size();
180  passed_argv_ = new char * [passed_argc_+1];
181 
182  // first copy the program executable in argv[0]
183  int arg_i=0;
184  if (argc > 0) passed_argv_[arg_i++] = xstrcpy( argv[0] );
185 
186  for(int i=0; i < passed_argc_; i++) {
187  passed_argv_[arg_i++] = xstrcpy( to_pass_further[i].c_str() );
188  }
189  passed_argc_ = arg_i;
190  */
191 
192  // if there is "help" option
193  if (vm.count("help")) {
194  cout << desc << "\n";
195  exit( exit_output );
196  }
197 
198  if (vm.count("version")) {
199  display_version();
200  exit( exit_output );
201  }
202 
203  // if there is "full_doc" option
204  /*if (vm.count("full_doc")) {
205  Input::Type::TypeBase::lazy_finish();
206  Input::Type::OutputText type_output(&get_input_type());
207  type_output.set_filter(":Field:.*");
208  cout << type_output;
209  exit( exit_output );
210  }*/
211 
212  // if there is "JSON_machine" option
213  if (vm.count("JSON_machine")) {
214  // write ist to json file
215  ofstream json_stream;
216  FilePath(vm["JSON_machine"].as<string>(), FilePath::output_file).open_stream(json_stream);
217  // create the root Record
218  it::Record root_type = get_input_type();
220  json_stream << Input::Type::OutputJSONMachine( root_type, this->get_rev_num_data() );
221  json_stream.close();
222  exit( exit_output );
223  }
224 
225  if (vm.count("petsc_redirect")) {
226  this->petsc_redirect_file_ = vm["petsc_redirect"].as<string>();
227  }
228 
229  if (vm.count("no_signal_handler")) {
230  this->signal_handler_off_ = true;
231  }
232 
233  // if there is "solve" option
234  string input_filename = ".";
235  if (vm.count("solve")) {
236  input_filename = vm["solve"].as<string>();
237  }
238 
239  // possibly turn off profilling
240  if (vm.count("no_profiler")) use_profiler=false;
241 
242  // preserves output of balance in YAML format
243  if (vm.count("yaml_balance")) yaml_balance_output_=true;
244 
245  string input_dir;
246  string output_dir;
247  if (vm.count("input_dir")) {
248  input_dir = vm["input_dir"].as<string>();
249  }
250  if (vm.count("output_dir")) {
251  output_dir = vm["output_dir"].as<string>();
252  }
253 
254  // assumes working directory "."
255  try {
256  main_input_filename_ = FilePath::set_dirs_from_input(input_filename, input_dir, output_dir );
257  } catch (FilePath::ExcMkdirFail &e) {
258  use_profiler = false; // avoid profiler output
259  throw e;
260  }
261 
262  if (vm.count("log")) {
263  this->log_filename_ = vm["log"].as<string>();
264  }
265 
266  if (vm.count("no_log")) {
267  this->log_filename_="//"; // override; do not open log files
268  }
269 
270  ostringstream tmp_stream(program_arguments_desc_);
271  tmp_stream << desc;
272  // TODO: catch specific exceptions and output usage messages
273 }
274 
275 
276 
277 
278 
280  START_TIMER("Application::run");
281  display_version();
282 
283  START_TIMER("Read Input");
284  // get main input record handle
285  Input::Record i_rec = read_input();
286  END_TIMER("Read Input");
287 
288  {
289  using namespace Input;
290  // check input file version against the version of executable
291  boost::regex version_re("([^.]*)[.]([^.]*)[.]([^.]*)");
292  boost::smatch match;
293  std::string version(FLOW123D_VERSION_NAME_);
294  vector<string> ver_fields(3);
295  if ( boost::regex_match(version, match, version_re) ) {
296  ver_fields[0]=match[1];
297  ver_fields[1]=match[2];
298  ver_fields[2]=match[3];
299  } else {
300  OLD_ASSERT(1, "Bad Flow123d version format: %s\n", version.c_str() );
301  }
302 
303  std::string input_version = i_rec.val<string>("flow123d_version");
304  vector<string> iver_fields(3);
305  if ( boost::regex_match(input_version, match, version_re) ) {
306  iver_fields[0]=match[1];
307  iver_fields[1]=match[2];
308  iver_fields[2]=match[3];
309  } else {
310  THROW( ExcVersionFormat() << EI_InputVersionStr(input_version) );
311  }
312 
313  if ( iver_fields[0] != ver_fields[0] || iver_fields[1] > ver_fields[1] ) {
314  WarningOut().fmt("Input file with version: '{}' is no compatible with the program version: '{}' \n",
315  input_version, version);
316  }
317 
318  // should flow123d wait for pressing "Enter", when simulation is completed
319  sys_info.pause_after_run = i_rec.val<bool>("pause_after_run");
320  // read record with problem configuration
321  Input::AbstractRecord i_problem = i_rec.val<AbstractRecord>("problem");
322 
323  if (i_problem.type() == HC_ExplicitSequential::get_input_type() ) {
324 
325  HC_ExplicitSequential *problem = new HC_ExplicitSequential(i_problem);
326 
327  // run simulation
328  problem->run_simulation();
329 
330  delete problem;
331  } else {
332  xprintf(UsrErr,"Problem type not implemented.");
333  }
334 
335  }
336 }
337 
338 
339 
340 
343  printf("\nPress <ENTER> for closing the window\n");
344  getchar();
345  }
346 }
347 
348 
349 
350 
352  // remove balance output files in YAML format if "yaml_balance" option is not set
353  if ( (sys_info.my_proc==0) && !yaml_balance_output_ ) {
354  boost::filesystem::path mass_file( string(FilePath("mass_balance.yaml", FilePath::output_file)) );
355  boost::filesystem::path water_file( string(FilePath("water_balance.yaml", FilePath::output_file)) );
356  boost::filesystem::path energy_file( string(FilePath("energy_balance.yaml", FilePath::output_file)) );
357 
358  if (boost::filesystem::exists(mass_file)) {
359  boost::filesystem::remove(mass_file);
360  }
361  if (boost::filesystem::exists(water_file)) {
362  boost::filesystem::remove(water_file);
363  }
364  if (boost::filesystem::exists(energy_file)) {
365  boost::filesystem::remove(energy_file);
366  }
367  }
368 
369  if (use_profiler) {
370  if (petsc_initialized) {
371  // log profiler data to this stream
372  Profiler::instance()->output (PETSC_COMM_WORLD);
373  } else {
375  }
376 
377  // call python script which transforms json file at given location
378  // Profiler::instance()->transform_profiler_data (".csv", "CSVFormatter");
379  Profiler::instance()->transform_profiler_data (".txt", "SimpleTableFormatter");
380 
381  // finally uninitialize
383  }
384 }
385 
386 
387 //=============================================================================
388 
389 /**
390  * FUNCTION "MAIN"
391  */
392 int main(int argc, char **argv) {
393  try {
394  Application app(argc, argv);
395  app.init(argc, argv);
396  } catch (std::exception & e) {
397  _LOG( Logger::MsgType::error ) << e.what();
399  } catch (...) {
400  _LOG( Logger::MsgType::error ) << "Unknown exception" << endl;
402  }
403 
404  // Say Goodbye
406 }
static Input::Type::Abstract & get_input_type()
int my_proc
Definition: system.hh:73
virtual void run()
Definition: main.cc:279
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:95
virtual void parse_cmd_line(const int argc, char **argv)
Definition: main.cc:148
Reader for (slightly) modified input files.
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:50
Class for declaration of the input of type Bool.
Definition: type_base.hh:434
#define MessageOut()
Macro defining &#39;message&#39; record of log.
Definition: logger.hh:231
string main_input_filename_
filename of main input file
Definition: main.h:91
virtual void after_run()
Definition: main.cc:341
static bool petsc_initialized
Application(int argc, char **argv)
Application constructor.
Definition: main.cc:78
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:99
Class for create JSON machine readable documentation.
Definition: type_output.hh:243
std::string branch
Actual branch of application.
Definition: type_output.hh:40
bool use_profiler
If true, we do output of profiling information.
Definition: main.h:100
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
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:286
#define OLD_ASSERT(...)
Definition: global_defs.h:131
void open_stream(Stream &stream) const
Definition: file_path.cc:205
Stores version of program and other base data of application.
Definition: type_output.hh:37
static void uninitialize()
static const int exit_failure
static void lazy_finish()
Finishes all types registered in type repositories.
Definition: type_base.cc:85
static const int exit_success
Return codes of application.
T get_root_interface() const
Returns the root accessor.
#define _LOG(type)
Internal macro defining universal record of log.
Definition: logger.hh:228
Accessor to the data with type Type::Record.
Definition: accessors.hh:277
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:87
bool yaml_balance_output_
If true, preserves output of balance in YAML format.
Definition: main.h:103
#define START_TIMER(tag)
Starts a timer with specified tag.
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:468
void display_version()
Definition: main.cc:107
void set_program_info(string program_name, string program_version, string branch, string revision, string build)
bool signal_handler_off_
Turn off signal handling useful to debug with valgrind.
static Input::Type::Record & get_input_type()
Root of the Input::Type tree. Description of whole input structure.
Definition: main.cc:60
int main(int argc, char **argv)
Definition: main.cc:392
void init(int argc, char **argv)
Accessor to the polymorphic input data of a type given by an AbstracRecord object.
Definition: accessors.hh:444
void transform_profiler_data(const string &output_file_suffix, const string &formatter)
Dedicated class for storing path to input and output files.
Definition: file_path.hh:48
Definition: system.hh:59
std::string revision
Actual revision of application.
Definition: type_output.hh:39
static const int exit_output
static Profiler * instance()
string program_arguments_desc_
Description of possible command line arguments.
Definition: main.h:97
SystemInfo sys_info
Definition: system.cc:41
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:234
#define END_TIMER(tag)
Ends a timer with specified tag.
static const Input::Type::Record & get_input_type()
Record type proxy class.
Definition: type_record.hh:171
std::string version
Actual version of application.
Definition: type_output.hh:38
Class for solution of steady or unsteady flow with sequentially coupled explicit transport.
virtual ~Application()
Destructor.
Definition: main.cc:351
#define FLOW123D_COMPILER_FLAGS_
named version of the program
Definition: main.cc:53
Input::Record root_record
root input record
Definition: main.h:106
Class for declaration of the input data that are in string format.
Definition: type_base.hh:568
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:45
void output(MPI_Comm comm, ostream &os)
int pause_after_run
Definition: system.hh:68
Input::Record read_input()
Definition: main.cc:125
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: printf.h:444
std::string url
Url of application.
Definition: type_output.hh:41