20#include "libmesh/libmesh.h"
21#include "libmesh/simple_range.h"
22#include "libmesh/parallel_algebra.h"
23#include "libmesh/parallel_sync.h"
34 for (
int i = 0; i < argc; i++)
41 mooseAssert(!
hasParsed(),
"Has already parsed");
48 for (
const auto & arg : args)
61 mooseAssert(!
hasParsed(),
"Has already parsed");
62 auto it = std::find(
_argv.begin(),
_argv.end(), arg);
63 if (it ==
_argv.end())
64 mooseError(
"CommandLine::removeArgument(): The argument '", arg,
"' does not exist");
71 mooseAssert(!
hasParsed(),
"Has already parsed");
72 mooseAssert(
_entries.empty(),
"Should be empty");
75 bool has_value_accepting_entry =
false;
78 auto add_entry = [
this](
const auto & name) ->
Entry &
80 auto & entry =
_entries.emplace_back();
86 for (
const auto i : index_range(
_argv))
88 const auto & arg =
_argv[i];
90 std::string subapp_prefix, subapp_name, hit_path, hit_value;
93 if (!begins_with_dash && std::regex_search(arg, std::regex(
"^(([^\\s\n\t[\\]\\/=#&:]+):)[-]")))
95 mooseError(
"The MultiApp command line argument '",
97 "' sets a command line option.\nMultiApp command line arguments can only be "
98 "used for setting HIT parameters.");
104 else if (!begins_with_dash &&
105 pcrecpp::RE(
"(([^\\s\n\t[\\]\\/=#&:]+)?:)?((?:[^\\s\n\t[\\]=#&]+\\/"
106 ")?(?:[^\\s\n\t=#$'\"]+))=([^#]+)?")
107 .FullMatch(arg, &subapp_prefix, &subapp_name, &hit_path, &hit_value))
109 auto & entry = add_entry(hit_path);
110 if (subapp_prefix.size())
112 if (subapp_name.empty())
115 entry.subapp_name = subapp_name;
118 entry.value_separator =
"=";
119 entry.raw_args.push_back(arg);
120 entry.hit_param =
true;
121 has_value_accepting_entry =
false;
124 else if (
const auto find_equals = arg.find(
"="); find_equals != std::string::npos)
126 const auto begin = arg.substr(0, find_equals);
127 const auto end = arg.substr(find_equals + 1);
128 auto & entry = add_entry(
begin);
130 entry.value_separator =
"=";
131 entry.raw_args.push_back(arg);
132 has_value_accepting_entry =
false;
137 else if (std::regex_search(arg, std::regex(
"^\\-+[a-zA-Z]")))
139 auto & entry = add_entry(arg);
140 entry.raw_args.push_back(arg);
141 has_value_accepting_entry =
true;
149 auto & entry = add_entry(arg);
150 entry.raw_args.push_back(arg);
155 if (!has_value_accepting_entry)
157 std::stringstream err;
158 err <<
"The command line argument '" << arg
159 <<
"' is not applied to an option and is not a HIT parameter.";
164 err <<
"\n\nDid you mean to combine this argument with the previous argument, such "
167 << *
_entries.back().value <<
" " << arg <<
"'\n";
177 entry.value_separator =
" ";
178 entry.raw_args.push_back(arg);
185const std::list<CommandLine::Entry> &
188 mooseAssert(
hasParsed(),
"Has not parsed");
192std::list<CommandLine::Entry> &
195 mooseAssert(
hasParsed(),
"Has not parsed");
201std::unique_ptr<CommandLine>
203 const std::string & subapp_name,
204 const std::vector<std::string> & input_cli_args,
205 const std::set<std::string> & exclude_params)
208 "Name for the subapp should begin with the multiapp");
210 std::vector<std::string> subapp_args;
214 for (
const auto & arg : input_cli_args)
220 std::set<const Entry *> skip_entries;
221 for (
const auto & param_name : exclude_params)
225 skip_entries.insert(&*it);
232 if (entry.global || (entry.subapp_name && (*entry.subapp_name == multiapp_name ||
233 *entry.subapp_name == subapp_name)))
236 if (skip_entries.count(&entry))
242 const std::string prefix = entry.global ?
":" :
"";
244 subapp_args.push_back(prefix + entry.name + *entry.value_separator + *entry.value);
249 subapp_args.insert(subapp_args.end(), entry.raw_args.begin(), entry.raw_args.end());
252 return std::make_unique<CommandLine>(subapp_args);
255std::vector<std::string>
261 std::vector<std::string> params;
265 if (entry.hit_param && !entry.subapp_name)
267 mooseAssert(entry.value,
"Should have a value");
268 mooseAssert(entry.value_separator,
"Should have value separator");
269 mooseAssert(*entry.value_separator ==
"=",
"Should be an equals");
271 const std::string name_and_equals = entry.name + *entry.value_separator;
272 std::string arg = name_and_equals;
274 if (entry.value->empty())
283 hit::check(
"CLI_ARG", arg);
285 catch (hit::Error & err)
289 arg = name_and_equals +
"'" + *entry.value +
"'";
292 hit::check(
"CLI_ARG", arg);
295 catch (hit::Error & err)
297 mooseError(
"Failed to parse HIT in command line argument '", arg,
"'\n\n", err.what());
302 params.push_back(arg);
317 std::map<std::string, std::string> switch_param_map;
318 for (
const auto & name_value_pair : params)
320 const auto & name = name_value_pair.first;
324 auto & option = it_inserted_pair.first->second;
327 option.metadata = *metadata;
330 for (
const auto & cli_switch : option.metadata.switches)
331 if (
const auto it_inserted_pair = switch_param_map.emplace(cli_switch, name);
332 !it_inserted_pair.second)
334 it_inserted_pair.first->second,
337 "' both declare the command line switch '",
349 auto & entry = *entry_it;
350 mooseAssert(!entry.subapp_name,
"Should not be for a subapp");
353#define trySetParameter(type) \
354 if (!found && params.have_parameter<type>(name)) \
356 static_assert(InputParameters::isValidCommandLineType<type>::value, "Not a supported value"); \
357 auto & value = params.set<type>(name); \
358 setCommandLineParam(entry_it, param, entry.name, value); \
362 trySetParameter(std::string);
363 trySetParameter(std::vector<std::string>);
364 trySetParameter(Real);
365 trySetParameter(
unsigned int);
366 trySetParameter(
int);
367 trySetParameter(
bool);
369#undef trySetParameter
371 mooseAssert(found,
"Should have been found");
378 if (param.metadata.global)
385 if (entry.value_separator && *entry.value_separator ==
"=")
387 mooseAssert(entry.raw_args.size() == 1,
"Should have one value");
392 else if (param.metadata.required)
394 "Missing required command-line parameter: ", name,
"\nDoc string: ", param.description);
403 mooseAssert(
_entries.size() > 0,
"Does not have any entries");
406 const auto & command =
_entries.begin()->name;
407 return command.substr(command.find_last_of(
"/\\") + 1);
414 name = name.substr(0, name.find_last_of(
"-"));
415 if (name.find_first_of(
"/") != std::string::npos)
416 name = name.substr(name.find_first_of(
"/") + 1, std::string::npos);
425 std::size_t max_len = 0;
427 max_len = std::max(max_len, name_option_pair.second.metadata.syntax.size());
429 const auto output_options = [
this, &max_len](
const bool global)
431 Moose::out << (global ?
"Global " :
"") <<
"Options:\n" << std::left;
434 const auto & option = name_option_pair.second;
435 if (option.metadata.syntax.empty() || option.metadata.global != global)
438 Moose::out <<
" " << std::setw(max_len + 2) << option.metadata.syntax << option.description
444 output_options(
false);
445 output_options(
true);
447 Moose::out <<
"Solver Options:\n"
448 <<
" See PETSc manual for details" << std::endl;
455std::vector<std::string>
458 libmesh_parallel_only(comm);
460 std::vector<const Entry *> hit_params;
461 std::vector<std::size_t> use_count;
465 hit_params.push_back(&entry);
466 use_count.push_back(entry.used ? 1 : 0);
469 mooseAssert(comm.
verify(use_count.size()),
"Inconsistent HIT params across procs");
472 std::vector<std::string> unused;
473 for (
const auto i : index_range(use_count))
474 if (use_count[i] == 0)
475 unused.push_back(hit_params[i]->raw_args[0]);
479std::list<CommandLine::Entry>::const_iterator
484 mooseError(
"CommandLine::findCommandLineParam(): The parameter '",
486 "' is not a command line parameter");
489 const auto & param = find_param->second;
491 for (
const auto & search_switch : param.metadata.switches)
492 if (rit->name == search_switch)
493 return --(rit.base());
498std::list<CommandLine::Entry>::iterator
501 const auto it = std::as_const(*this).findCommandLineParam(name);
509 std::stringstream oss;
513 const auto q = (*entry.
value).find(
" ") != std::string::npos ?
"'" :
"";
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
bool _hit_params_built
Whether or not the HIT parameters have been built (set as used)
bool _command_line_params_populated
Whether or not command line parameters have been populated.
std::list< Entry > _entries
The parsed command line entries (arguments split into name value pairs) This is a list because it is ...
void removeArgument(const std::string &arg)
Removes an argument that must exist.
std::unique_ptr< CommandLine > initSubAppCommandLine(const std::string &multiapp_name, const std::string &subapp_name, const std::vector< std::string > &input_cli_args, const std::set< std::string > &exclude_params={})
Initializes a new CommandLine for a subapp with a MultiApp named multiapp_name and a subapp named sub...
const std::list< Entry > & getEntries() const
std::string getExecutableName() const
void populateCommandLineParams(InputParameters ¶ms)
Populates the command line input parameters from params.
void addArguments(int argc, char *argv[])
Adds arguments from raw argc and argv.
bool _has_parsed
Whether or not the Parser has parsed yet.
void addArgument(const std::string &arg)
Adds a single argument.
std::string getExecutableNameBase() const
std::list< Entry >::const_iterator findCommandLineParam(const std::string &name) const
std::string formatEntry(const Entry &entry) const
std::vector< std::string > _argv
Storage for the raw argv.
bool hasArgument(const std::string &arg) const
void parse()
Performs the parsing, which is the combining of arguments into [name, value] pairs.
void printUsage() const
Print the usage info for this command line.
std::vector< std::string > buildHitParams()
std::map< std::string, CommandLineParam > _command_line_params
The command line parameters, added by populateCommandLineParams()
std::vector< std::string > unusedHitParams(const Parallel::Communicator &comm) const
Returns the HIT command line arguments that are not used.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
timpi_pure bool verify(const T &r) const
std::string removeExtraWhitespace(const std::string &input)
bool beginsWith(const std::string &value, const std::string &begin_value)
void setSinglePetscOption(const std::string &name, const std::string &value="", FEProblemBase *const problem=nullptr)
A wrapper function for dealing with different versions of PetscOptionsSetValue.
void add_command_line_name(const std::string &name)
Stores information pertaining to a command line InputParameter.
Stores name/value pairs for each command line argument.
std::optional< std::string > value
The value, i.e. ["-foo=bar"] -> "bar" or ["-foo"] -> empty, if any.
std::optional< std::string > value_separator
The string that separates the value, if a value exists (space or =)
std::string name
The name, i.e, ["-foo=bar"] -> "-foo" or ["--foo", "bar"] -> "--foo".