Fluid structure interaction suite
runner.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2022 by Luca Heltai
4 //
5 // This file is part of the FSI-suite platform, based on the deal.II library.
6 //
7 // The FSI-suite platform is free software; you can use it, redistribute it,
8 // and/or modify it under the terms of the GNU Lesser General Public License as
9 // published by the Free Software Foundation; either version 3.0 of the License,
10 // or (at your option) any later version. The full text of the license can be
11 // found in the file LICENSE at the top level of the FSI-suite platform
12 // distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include "runner.h"
17 
18 #include <deal.II/base/logstream.h>
19 #include <deal.II/base/mpi.h>
22 #include <deal.II/base/utilities.h>
23 
24 #include "argh.hpp"
25 #include "text_flow.hpp"
26 
27 using namespace dealii;
28 
29 namespace Runner
30 {
45  std::pair<unsigned int, unsigned int>
46  get_dimension_and_spacedimension(const std::string &prm_file,
47  const unsigned int default_dim = 2,
48  const unsigned int default_spacedim = 2)
49  {
51  std::to_string(default_dim),
52  Patterns::Integer(1, 3));
54  std::to_string(default_spacedim),
55  Patterns::Integer(1, 3));
56  try
57  {
58  ParameterAcceptor::prm.parse_input(prm_file, "", true);
59  auto dim = ParameterAcceptor::prm.get_integer("dim");
60  auto spacedim = ParameterAcceptor::prm.get_integer("spacedim");
61  return {dim, spacedim};
62  }
63  catch (std::exception &exc)
64  {
65  return {default_dim, default_spacedim};
66  throw;
67  }
68  }
69 
70 
88  std::tuple<int, int, std::string, std::string>
90  {
91  argh::parser cli(argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
92  unsigned int dim = 2;
93  unsigned int spacedim = 2;
94  std::string input_parameter_file = "";
95  std::string output_parameter_file = "";
96 
97  const std::string exename =
98  cli(0).str().substr(cli(0).str().find_last_of("/") + 1);
99 
100 
101  // Either as -i prm_file or as first positional argument after all options
102  cli({"i", "input_prm_file"}, input_parameter_file) >> input_parameter_file;
103  cli(1, input_parameter_file) >> input_parameter_file;
104 
105  const bool has_dim_or_spacedim =
106  cli[{"d", "dim"}] || cli[{"s", "spacedim"}];
107  // Now read from command line the dimension and space dimension
108  cli({"d", "dim"}) >> dim;
109  // Make sure the default is to set spacedim = dim
110  cli({"s", "spacedim"}, dim) >> spacedim;
111 
112  // And do the same from the parameter file
113  const auto [prm_dim, prm_spacedim] =
114  get_dimension_and_spacedimension(input_parameter_file, dim, spacedim);
115 
116  // Throw an exception if the inputer parameter file and the command line do
117  // not agree. Notice that, if the file doees not exist, they will agree,
118  // since the default values are the same.
119  AssertThrow(
120  !has_dim_or_spacedim || (dim == prm_dim) && (spacedim == prm_spacedim),
122  "You have specified a parameter file that contains a specification "
123  "of the dimension and of the space dimension, as <" +
124  std::to_string(prm_dim) + ", " + std::to_string(prm_spacedim) +
125  ">, but you also indicated a -d (--dim) = " + std::to_string(dim) +
126  " or -s (--spacedim) = " + std::to_string(spacedim) +
127  " argument on the command line that do not match the content of the parameter file. "
128  "Use only one of the two ways to select the dimension and the "
129  "space dimension, or make sure that what you specify in the parameter file "
130  "matches what you specify on the command line."));
131 
132  // Now the logic to deduce the output parameter file name. Make sure we
133  // output in the current directory, even if the file is specified with a
134  // full path
135  if (input_parameter_file != "")
136  {
137  auto rel_name = input_parameter_file.substr(
138  input_parameter_file.find_last_of("/") + 1);
139  output_parameter_file = "used_" + rel_name;
140  }
141  else
142  {
143  output_parameter_file = "used_" + exename + ".prm";
144  }
145 
146  // If you want to overwrite the output parameter file, use the -o option
147  cli({"o", "output_prm_file"}, output_parameter_file) >>
148  output_parameter_file;
149 
150  deallog << "Will run in dimension " << dim << " and spacedimension "
151  << spacedim << std::endl
152  << "Input parameter file: " << input_parameter_file << std::endl
153  << "Output parameter file: " << output_parameter_file << std::endl;
154 
155  return std::make_tuple(prm_dim,
156  prm_spacedim,
157  input_parameter_file,
158  output_parameter_file);
159  }
160 
161 
182  int
184  const std::string &input_parameter_file,
185  const std::string &output_parameter_file)
186  {
187  argh::parser cli(argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
188  ParameterAcceptor::initialize(input_parameter_file, output_parameter_file);
189 
190  if (cli[{"h", "help"}])
191  {
192  auto format = [](const auto &a, const auto &b) {
193  return TextFlow::Column(a).width(34) + TextFlow::Column(b).width(46);
194  };
195 
196 
197  const std::string exename =
198  cli(0).str().substr(cli(0).str().find_last_of("/") + 1);
199 
200  std::cout
201  << "Usage: " << cli(0).str() << " [OPTIONS] [PRM FILE]" << std::endl
202  << "Options:" << std::endl
203  << format("-h, --help", "Print this help message") << std::endl
204  << format(
205  "-i, --input_prm_file <filename>",
206  "Input parameter file. Defaults"
207  " to the empty string (meaning: use the default values, or the "
208  "values specified on the command line). Notice that you can "
209  "specify the input paramter file also as the first positional arguement to the program.")
210  << std::endl
211  << format(
212  "-o, --output_prm_file <filename>",
213  "Where to write the file containing the actual parameters "
214  "used in this run of the program. It defaults to the string `used_" +
215  exename +
216  "' if the input parameter file is not specified, "
217  "otherwise it defaults to the string `used_' followed by the "
218  "name of the input parameter file.")
219  << std::endl
220  << format(
221  "-d, --dim <value>",
222  "Dimension at which this program should be run. Defaults to 2.")
223  << std::endl
224  << format(
225  "-s, --spacedim <value>",
226  "Space dimension at which this program should run. Defaults to 2.")
227  << std::endl
228  << format(
229  "-\"Section/option name\"=<value>",
230  "Any of the options that you can specify in the parameter file. "
231  "The format here is the following: "
232  "-\"Section/Subsection/option\"=\"value,another value\", "
233  "where the quotes are required only if an otpion contains spaces, "
234  "or if a value contains separators, like commas, columns, etc.")
235  << std::endl
236  << format("-pause", "Wait for a keypress to attach a debugger.")
237  << std::endl
238  << std::endl;
241  return -1;
242  }
243 
244  std::set<std::string> non_prm{"h",
245  "help",
246  "i",
247  "input_prm_file",
248  "o",
249  "output_prm_file",
250  "d",
251  "dim",
252  "s",
253  "spacedim",
254  "pause"};
255  for (auto &p : cli.params())
256  if (non_prm.find(p.first) == non_prm.end())
257  {
258  auto path = Utilities::split_string_list(p.first, "/");
259  const std::string entry = path.back();
260  path.pop_back();
261 
262  for (const auto &sec : path)
264 
265  ParameterAcceptor::prm.set(entry, p.second);
266 
267  for (const auto &sec : path)
268  {
269  (void)sec;
271  }
272  }
273  int ret = 0;
274  for (auto &p : cli.pos_args())
275  if (p != argv[0] && p != input_parameter_file)
276  {
277  deallog << "WARNING -- ignoring positional argument: " << p
278  << std::endl;
279  ret = 1;
280  }
281 
283  output_parameter_file,
286  // Check if we need to wait for input
287  if (cli["pause"] && Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
288  {
289  std::cout << "============================================" << std::endl
290  << "PID: " << getpid() << std::endl
291  << "============================================" << std::endl
292  << "Press any key to continue..." << std::endl
293  << "============================================"
294  << std::endl;
295  std::cin.get();
296  }
297 
298  // Everything went fine, so return 0 or 1
299  return ret;
300  }
301 } // namespace Runner
static void initialize(const std::string &filename="", const std::string &output_filename="", const ParameterHandler::OutputStyle output_style_for_output_filename=ParameterHandler::Short, ParameterHandler &prm=ParameterAcceptor::prm, const ParameterHandler::OutputStyle output_style_for_filename=ParameterHandler::DefaultStyle)
static ParameterHandler prm
virtual void parse_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="", const bool skip_undefined=false)
void enter_subsection(const std::string &subsection, const bool create_path_if_needed=true)
std::ostream & print_parameters(std::ostream &out, const OutputStyle style) const
void leave_subsection()
long int get_integer(const std::string &entry_string) const
void declare_entry(const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation="", const bool has_to_be_set=false)
void set(const std::string &entry_name, const std::string &new_value)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
LogStream deallog
Expression sec(const Expression &x)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
std::vector< std::string > split_string_list(const std::string &s, const std::string &delimiter=",")
Gather some functions and classes typically used in the main() of the FSI-suite applications.
Definition: runner.h:26
int setup_parameters_from_cli(char **argv, const std::string &input_parameter_file, const std::string &output_parameter_file)
Setup the ParameterAcceptor::prm according to the parameters specified in the parameter file,...
Definition: runner.cc:183
std::pair< unsigned int, unsigned int > get_dimension_and_spacedimension(const std::string &prm_file, const unsigned int default_dim=2, const unsigned int default_spacedim=2)
Retrieves the dimension and space dimension from a parameter file.
Definition: runner.cc:46
std::tuple< int, int, std::string, std::string > get_dimensions_and_parameter_files(char **argv)
Parse from the command line the parameter file names (both input and output) and the running dimensio...
Definition: runner.cc:89