Flow123d  release_1.8.2-1603-g0109a2b
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 
36 #include "main.h"
37 
38 #include "rev_num.h"
39 
40 /// named version of the program
41 //#define _PROGRAM_VERSION_ "0.0.0"
42 
43 //#ifndef _PROGRAM_REVISION_
44 // #define _PROGRAM_REVISION_ "(unknown revision)"
45 //#endif
46 
47 //#ifndef _PROGRAM_BRANCH_
48 // #define _PROGRAM_BRANCH_ "(unknown branch)"
49 //#endif
50 
51 #ifndef FLOW123D_COMPILER_FLAGS_
52  #define FLOW123D_COMPILER_FLAGS_ "(unknown compiler flags)"
53 #endif
54 
55 
56 namespace it = Input::Type;
57 
58 // this should be part of a system class containing all support information
60  static it::Record type = it::Record("Root", "Root record of JSON input for Flow123d.")
61  .declare_key("flow123d_version", it::String(), it::Default::obligatory(),
62  "Version of Flow123d for which the input file was created."
63  "Flow123d only warn about version incompatibility. "
64  "However, external tools may use this information to provide conversion "
65  "of the input file to the structure required by another version of Flow123d.")
67  "Simulation problem to be solved.")
68  .declare_key("pause_after_run", it::Bool(), it::Default("false"),
69  "If true, the program will wait for key press before it terminates.")
70  .close();
71 
72  return type;
73 }
74 
75 
76 
77 Application::Application( int argc, char ** argv)
78 : ApplicationBase(argc, argv),
79  main_input_dir_("."),
81  passed_argc_(0),
82  passed_argv_(0),
83  use_profiler(true)
84 {
85  // initialize python stuff if we have
86  // nonstandard python home (release builds)
87 #ifdef FLOW123D_HAVE_PYTHON
88  PythonLoader::initialize(argv[0]);
89 #endif
90 
91 }
92 
93 
94 void Application::split_path(const string& path, string& directory, string& file_name) {
95 
96  size_t delim_pos=path.find_last_of(DIR_DELIMITER);
97  if (delim_pos < string::npos) {
98 
99  // It seems, that there is some path in fname ... separate it
100  directory =path.substr(0,delim_pos);
101  file_name =path.substr(delim_pos+1); // till the end
102  } else {
103  directory = ".";
104  file_name = path;
105  }
106 }
107 
108 
110  Input::Type::RevNumData rev_num_data;
111 
112  rev_num_data.version = string(FLOW123D_VERSION_NAME_);
113  rev_num_data.revision = string(FLOW123D_GIT_REVISION_);
114  rev_num_data.branch = string(FLOW123D_GIT_BRANCH_);
115  rev_num_data.url = string(FLOW123D_GIT_URL_);
116 
117  return rev_num_data;
118 }
119 
120 
122  // Say Hello
123  // make strings from macros in order to check type
124  Input::Type::RevNumData rev_num_data = this->get_rev_num_data();
125  string build = string(__DATE__) + ", " + string(__TIME__)
126  + " flags: " + string(FLOW123D_COMPILER_FLAGS_);
127 
128 
129  xprintf(Msg, "This is Flow123d, version %s revision: %s\n",
130  rev_num_data.version.c_str(),
131  rev_num_data.revision.c_str());
132  xprintf(Msg,
133  "Branch: %s\n"
134  "Build: %s\n"
135  "Fetch URL: %s\n",
136  rev_num_data.branch.c_str(), build.c_str() , rev_num_data.url.c_str() );
137  Profiler::instance()->set_program_info("Flow123d",
138  rev_num_data.version, rev_num_data.branch, rev_num_data.revision, build);
139 }
140 
141 
142 
144  if (main_input_filename_ == "") {
145  cout << "Usage error: The main input file has to be specified through -s parameter.\n\n";
146  cout << program_arguments_desc_ << "\n";
147  exit( exit_failure );
148  }
149 
150  // read main input file
151  FilePath fpath(main_input_filename_, FilePath::FileType::input_file);
152  try {
153  Input::ReaderToStorage json_reader(fpath, get_input_type() );
155  } catch (Input::ReaderToStorage::ExcInputError &e ) {
156  e << Input::ReaderToStorage::EI_File(fpath); throw;
157  } catch (Input::ReaderToStorage::ExcNotJSONFormat &e) {
158  e << Input::ReaderToStorage::EI_File(fpath); throw;
159  }
160  return root_record;
161 }
162 
163 
164 
165 
166 void Application::parse_cmd_line(const int argc, char ** argv) {
167  namespace po = boost::program_options;
168 
169 
170  // Declare the supported options.
171  po::options_description desc("Allowed options");
172  desc.add_options()
173  ("help", "produce help message")
174  ("solve,s", po::value< string >(), "Main input file to solve.")
175  ("input_dir,i", po::value< string >()->default_value("input"), "Directory for the ${INPUT} placeholder in the main input file.")
176  ("output_dir,o", po::value< string >()->default_value("output"), "Directory for all produced output files.")
177  ("log,l", po::value< string >()->default_value("flow123"), "Set base name for log files.")
178  ("version", "Display version and build information and exit.")
179  ("no_log", "Turn off logging.")
180  ("no_profiler", "Turn off profiler output.")
181  ("JSON_machine", po::value< string >(), "Writes full structure of the main input file as a valid CON file into given file")
182  ("petsc_redirect", po::value<string>(), "Redirect all PETSc stdout and stderr to given file.");
183 
184  ;
185 
186  // parse the command line
187  po::variables_map vm;
188  po::parsed_options parsed = po::basic_command_line_parser<char>(argc, argv).options(desc).allow_unregistered().run();
189  po::store(parsed, vm);
190  po::notify(vm);
191 
192  // get unknown options
193  vector<string> to_pass_further = po::collect_unrecognized(parsed.options, po::include_positional);
194  passed_argc_ = to_pass_further.size();
195  passed_argv_ = new char * [passed_argc_+1];
196 
197  // first copy the program executable in argv[0]
198  int arg_i=0;
199  if (argc > 0) passed_argv_[arg_i++] = xstrcpy( argv[0] );
200 
201  for(int i=0; i < passed_argc_; i++) {
202  passed_argv_[arg_i++] = xstrcpy( to_pass_further[i].c_str() );
203  }
204  passed_argc_ = arg_i;
205 
206  // if there is "help" option
207  if (vm.count("help")) {
208  cout << desc << "\n";
209  exit( exit_output );
210  }
211 
212  if (vm.count("version")) {
213  display_version();
214  exit( exit_output );
215  }
216 
217  // if there is "full_doc" option
218  /*if (vm.count("full_doc")) {
219  Input::Type::TypeBase::lazy_finish();
220  Input::Type::OutputText type_output(&get_input_type());
221  type_output.set_filter(":Field:.*");
222  cout << type_output;
223  exit( exit_output );
224  }*/
225 
226  // if there is "JSON_machine" option
227  if (vm.count("JSON_machine")) {
228  // write ist to json file
229  string json_filename = vm["JSON_machine"].as<string>();
230  ofstream json_stream(json_filename);
231  // check open operation
232  if (json_stream.fail()) {
233  cerr << "Failed to open file '" << json_filename << "'" << endl;
234  } else {
235  // create the root Record
236  it::Record root_type = get_input_type();
238  json_stream << Input::Type::OutputJSONMachine( root_type, this->get_rev_num_data() );
239  json_stream.close();
240  }
241  exit( exit_output );
242  }
243 
244  if (vm.count("petsc_redirect")) {
245  this->petsc_redirect_file_ = vm["petsc_redirect"].as<string>();
246  }
247 
248  // if there is "solve" option
249  if (vm.count("solve")) {
250  string input_filename = vm["solve"].as<string>();
252  }
253 
254  // possibly turn off profilling
255  if (vm.count("no_profiler")) use_profiler=false;
256 
257  string input_dir;
258  string output_dir;
259  if (vm.count("input_dir")) {
260  input_dir = vm["input_dir"].as<string>();
261  }
262  if (vm.count("output_dir")) {
263  output_dir = vm["output_dir"].as<string>();
264  }
265 
266  // assumes working directory "."
267  FilePath::set_io_dirs(".", main_input_dir_, input_dir, output_dir );
268 
269  if (vm.count("log")) {
270  this->log_filename_ = vm["log"].as<string>();
271  }
272 
273  if (vm.count("no_log")) {
274  this->log_filename_="//"; // override; do not open log files
275  }
276 
277  ostringstream tmp_stream(program_arguments_desc_);
278  tmp_stream << desc;
279  // TODO: catch specific exceptions and output usage messages
280 }
281 
282 
283 
284 
285 
287  START_TIMER("Application::run");
288  display_version();
289 
290  START_TIMER("Read Input");
291  // get main input record handle
292  Input::Record i_rec = read_input();
293  END_TIMER("Read Input");
294 
295  {
296  using namespace Input;
297  // check input file version against the version of executable
298  boost::regex version_re("([^.]*)[.]([^.]*)[.]([^.]*)");
299  boost::smatch match;
300  std::string version(FLOW123D_VERSION_NAME_);
301  vector<string> ver_fields(3);
302  if ( boost::regex_match(version, match, version_re) ) {
303  ver_fields[0]=match[1];
304  ver_fields[1]=match[2];
305  ver_fields[2]=match[3];
306  } else {
307  OLD_ASSERT(1, "Bad Flow123d version format: %s\n", version.c_str() );
308  }
309 
310  std::string input_version = i_rec.val<string>("flow123d_version");
311  vector<string> iver_fields(3);
312  if ( boost::regex_match(input_version, match, version_re) ) {
313  iver_fields[0]=match[1];
314  iver_fields[1]=match[2];
315  iver_fields[2]=match[3];
316  } else {
317  THROW( ExcVersionFormat() << EI_InputVersionStr(input_version) );
318  }
319 
320  if ( iver_fields[0] != ver_fields[0] || iver_fields[1] > ver_fields[1] ) {
321  xprintf(Warn, "Input file with version: '%s' is no compatible with the program version: '%s' \n",
322  input_version.c_str(), version.c_str());
323  }
324 
325  // should flow123d wait for pressing "Enter", when simulation is completed
326  sys_info.pause_after_run = i_rec.val<bool>("pause_after_run");
327  // read record with problem configuration
328  Input::AbstractRecord i_problem = i_rec.val<AbstractRecord>("problem");
329 
330  if (i_problem.type() == HC_ExplicitSequential::get_input_type() ) {
331 
332  HC_ExplicitSequential *problem = new HC_ExplicitSequential(i_problem);
333 
334  // run simulation
335  problem->run_simulation();
336 
337  delete problem;
338  } else {
339  xprintf(UsrErr,"Problem type not implemented.");
340  }
341 
342  }
343 }
344 
345 
346 
347 
350  printf("\nPress <ENTER> for closing the window\n");
351  getchar();
352  }
353 }
354 
355 
356 
357 
359  if (use_profiler) {
360  if (petsc_initialized) {
361  // log profiler data to this stream
362  Profiler::instance()->output (PETSC_COMM_WORLD);
363  } else {
365  }
366 
367  // call python script which transforms json file at given location
368  // Profiler::instance()->transform_profiler_data (".csv", "CSVFormatter");
369  Profiler::instance()->transform_profiler_data (".txt", "SimpleTableFormatter");
370 
371  // finally uninitialize
373  }
374 }
375 
376 
377 //=============================================================================
378 
379 /**
380  * FUNCTION "MAIN"
381  */
382 int main(int argc, char **argv) {
383  try {
384  Application app(argc, argv);
385  app.init(argc, argv);
386  } catch (std::exception & e) {
387  std::cerr << e.what();
389  } catch (...) {
390  std::cerr << "Unknown exception" << endl;
392  }
393 
394  // Say Goodbye
396 }
static Input::Type::Abstract & get_input_type()
virtual void run()
Definition: main.cc:286
Definition: system.hh:59
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:109
virtual void parse_cmd_line(const int argc, char **argv)
Definition: main.cc:166
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:429
string main_input_filename_
filename of main input file
Definition: main.h:99
virtual void after_run()
Definition: main.cc:348
static bool petsc_initialized
Application(int argc, char **argv)
Application constructor.
Definition: main.cc:77
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
char * xstrcpy(const char *src)
MAKE BRAND NEW COPY OF STRING.
Definition: system.cc:280
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:108
#define OLD_ASSERT(...)
Definition: global_defs.h:128
Stores version of program and other base data of application.
Definition: type_output.hh:37
static void uninitialize()
static const int exit_failure
Definition: system.hh:59
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.
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
#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:459
string main_input_dir_
directory of main input file (used to resolve relative paths of other input files) ...
Definition: main.h:97
const Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:271
void display_version()
Definition: main.cc:121
void split_path(const string &path, string &directory, string &file_name)
Definition: main.cc:94
char ** passed_argv_
Definition: main.h:102
void set_program_info(string program_name, string program_version, string branch, string revision, string build)
static Input::Type::Record & get_input_type()
Root of the Input::Type tree. Description of whole input structure.
Definition: main.cc:59
int passed_argc_
Definition: main.h:101
int main(int argc, char **argv)
Definition: main.cc:382
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:42
Definition: system.hh:59
std::string revision
Actual revision of application.
Definition: type_output.hh:39
static void set_io_dirs(const string working_dir, const string root_input, const string input, const string output)
Definition: file_path.cc:60
static const int exit_output
static Profiler * instance()
string program_arguments_desc_
Description of possible command line arguments.
Definition: main.h:105
#define DIR_DELIMITER
Definition: system.hh:44
SystemInfo sys_info
Definition: system.cc:42
#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:358
#define FLOW123D_COMPILER_FLAGS_
named version of the program
Definition: main.cc:52
Input::Record root_record
root input record
Definition: main.h:111
Class for declaration of the input data that are in string format.
Definition: type_base.hh:563
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:44
void output(MPI_Comm comm, ostream &os)
int pause_after_run
Definition: system.hh:68
Input::Record read_input()
Definition: main.cc:143
std::string url
Url of application.
Definition: type_output.hh:41