Skip to content

Commit

Permalink
Add the ability for multiapps to take CLI params
Browse files Browse the repository at this point in the history
  • Loading branch information
permcody committed Jul 31, 2015
1 parent 1d13028 commit a8a56e4
Show file tree
Hide file tree
Showing 38 changed files with 615 additions and 28 deletions.
1 change: 1 addition & 0 deletions framework/include/base/FEProblem.h
Expand Up @@ -526,6 +526,7 @@ class FEProblem :
* Returns whether or not the current simulation has any multiapps
*/
bool hasMultiApps() const { return _has_multiapps; }
bool hasMultiApp(const std::string & name);

/**
* Check existence of the VectorPostprocessor.
Expand Down
29 changes: 26 additions & 3 deletions framework/include/parser/CommandLine.h
Expand Up @@ -48,7 +48,6 @@ class CommandLine
std::vector<std::string> cli_switch;
};


CommandLine(int argc, char * argv[]);
virtual ~CommandLine();

Expand Down Expand Up @@ -90,12 +89,29 @@ class CommandLine
GetPot * getPot() { return _get_pot; }

/**
* Check if we have a variable on the command line
* Check if we have a variable on the command line. Note that a call to this
* method can modify the prefix unless the optional Boolean is set to false.
*
* @param name The name of the variable
* @return True if the variable was defined on the command line
*/
bool haveVariable(const std::string & name);
bool haveVariable(const std::string & name, bool allow_prefix_change=true);

/**
* Sets the prefix for the CommandLine object. This is used for passing
* parameters to Multiapps
*/
void setPrefix(const std::string & name, const std::string & num="");

/**
* Resets the prefix to the value set with the last call to setPrefix.
* Generally you do not need to call this method unless you wish
* to reset the prefix after calling haveVariable before retrieving a
* raw pointer to the GetPot object.
*/
void resetPrefix();

// Dump the contents of the GetPot object
void print(const char * prefix, std::ostream & out_stream, unsigned int skip_count);

protected:
Expand All @@ -105,6 +121,13 @@ class CommandLine
std::map<std::string, Option> _cli_options;
/// This is a set of all "extra" options on the command line
std::set<std::string> _command_line_vars;

/// The base prefix for this CommandLine object
std::string _base_prefix;
/// The number added to the prefix to point it at a specific Multiapp
std::string _prefix_num;
/// Boolean indicating whether we have prefixes set on this CommandLine Object
bool _has_prefix;
};

template <typename T>
Expand Down
11 changes: 11 additions & 0 deletions framework/src/base/FEProblem.C
Expand Up @@ -2659,6 +2659,17 @@ FEProblem::addMultiApp(const std::string & multi_app_name, const std::string & n
// multi_app->init();
}

bool
FEProblem::hasMultiApp(const std::string & multi_app_name)
{
for (unsigned int i = 0; i < Moose::exec_types.size(); i++)
if (_multi_apps(Moose::exec_types[i])[0].hasMultiApp(multi_app_name))
return true;

return false;
}


MultiApp *
FEProblem::getMultiApp(const std::string & multi_app_name)
{
Expand Down
67 changes: 60 additions & 7 deletions framework/src/base/MooseApp.C
Expand Up @@ -24,6 +24,7 @@
#include "Conversion.h"
#include "CommandLine.h"
#include "InfixIterator.h"
#include "MultiApp.h"

// Regular expression includes
#include "pcrecpp.h"
Expand Down Expand Up @@ -357,14 +358,66 @@ MooseApp::runInputFile()
std::vector<std::string> all_vars = _parser.getPotHandle()->get_variable_names();
_parser.checkUnidentifiedParams(all_vars, error_unused, true);

// Only check CLI parameters on the main application
// TODO: Add support for SubApp overrides and checks #4119
if (_name == "main")
// Check the CLI parameters
all_vars = _command_line->getPot()->get_variable_names();
// Remove flags, they aren't "input" parameters
all_vars.erase( std::remove_if(all_vars.begin(), all_vars.end(), isFlag), all_vars.end() );

MooseSharedPointer<FEProblem> fe_problem= _action_warehouse.problem();
if (fe_problem.get() && name() == "main")
{
// Check the CLI parameters
all_vars = _command_line->getPot()->get_variable_names();
// Remove flags, they aren't "input" parameters
all_vars.erase( std::remove_if(all_vars.begin(), all_vars.end(), isFlag), all_vars.end() );
// Make sure that multiapp overrides were processed properly
int last = all_vars.size() - 1; // last is allowed to go negative
for (int i = 0; i <= last; /* no increment */) // i is an int because last is an int
{
std::string multi_app, variable;
int app_num;

/**
* Command line parameters that contain a colon are assumed to apply to MultiApps
* (e.g. MultiApp_name[num]:fully_qualified_parameter)
*
* Note: Two separate regexs are used since the digit part is optional. Attempting
* to have an optional capture into a non-string type will cause pcrecpp to report
* false. Capturing into a string an converting is more work than just using two
* regexs to begin with.
*/
if (pcrecpp::RE("(.*?)" // Match the MultiApp name
"(\\d+)" // MultiApp number (leave off to apply to all MultiApps with this name)
":" // the colon delimiter
"(.*)" // the variable override that applies to the MultiApp
).FullMatch(all_vars[i], &multi_app, &app_num, &variable) &&
fe_problem->hasMultiApp(multi_app) && // Make sure the MultiApp exists
// Finally make sure the number is in range (if provided)
static_cast<unsigned int>(app_num) < fe_problem->getMultiApp(multi_app)->numGlobalApps())


// delete the current item by copying the last item to this position and decrementing the vector end position
all_vars[i] = all_vars[last--];

else if (pcrecpp::RE("(.*?)" // Same as above without the MultiApp number
":"
"(.*)"
).FullMatch(all_vars[i], &multi_app, &variable) &&
fe_problem->hasMultiApp(multi_app)) // Make sure the MultiApp exists but no need to check numbers

// delete (see comment above)
all_vars[i] = all_vars[last--];


// TODO: check to see if globals are unused
else if (all_vars[i].find(":") == 0)
all_vars[i] = all_vars[last--];

else
// only increment if we didn't "delete", otherwise we'll need to revisit the current index due to copy
++i;
}

mooseAssert(last + 1 >= 0, "index \"last\" is negative");

// Remove the deleted items
all_vars.resize(last+1);

_parser.checkUnidentifiedParams(all_vars, error_unused, false);
}
Expand Down
16 changes: 13 additions & 3 deletions framework/src/multiapps/MultiApp.C
Expand Up @@ -95,7 +95,12 @@ MultiApp::MultiApp(const InputParameters & parameters):
_fe_problem(getParam<FEProblem *>("_fe_problem")),
_app_type(getParam<MooseEnum>("app_type")),
_input_files(getParam<std::vector<std::string> >("input_files")),
_total_num_apps(0),
_my_num_apps(0),
_first_local_app(0),
_orig_comm(getParam<MPI_Comm>("_mpi_comm")),
_my_comm(MPI_COMM_SELF),
_my_rank(0),
_inflation(getParam<Real>("bounding_box_inflation")),
_max_procs_per_app(getParam<unsigned int>("max_procs_per_app")),
_output_in_position(getParam<bool>("output_in_position")),
Expand All @@ -109,6 +114,14 @@ MultiApp::MultiApp(const InputParameters & parameters):
_has_an_app(true),
_backups(declareRestartableDataWithContext<SubAppBackups>("backups", this))
{
if (_move_apps.size() != _move_positions.size())
mooseError("The number of apps to move and the positions to move them to must be the same for MultiApp "<<_name);

// Fill in the _positions vector
fillPositions();

_total_num_apps = _positions.size();
mooseAssert(_input_files.size() == 1 || _positions.size() == _input_files.size(), "Number of positions and input files are not the same!");
}

MultiApp::~MultiApp()
Expand All @@ -133,9 +146,6 @@ MultiApp::initialSetup()
if (_move_apps.size() != _move_positions.size())
mooseError("The number of apps to move and the positions to move them to must be the same for MultiApp " << name());

_total_num_apps = _positions.size();
mooseAssert(_input_files.size() == 1 || _positions.size() == _input_files.size(), "Number of positions and input files are not the same!");

/// Set up our Comm and set the number of apps we're going to be working on
buildComm();

Expand Down
69 changes: 66 additions & 3 deletions framework/src/parser/CommandLine.C
Expand Up @@ -20,7 +20,8 @@
#include "InputParameters.h"

CommandLine::CommandLine(int argc, char *argv[]) :
_get_pot(new GetPot(argc, argv))
_get_pot(new GetPot(argc, argv)),
_has_prefix(false)
{
}

Expand Down Expand Up @@ -181,9 +182,71 @@ CommandLine::isVariableOnCommandLine(const std::string &name) const
}

bool
CommandLine::haveVariable(const std::string & name)
CommandLine::haveVariable(const std::string & name, bool allow_prefix_change)
{
return _get_pot->have_variable(name);
// Make sure the CommandLine object is in the right state with the right prefix
resetPrefix();
if (_get_pot->have_variable(name))
return true;

if (allow_prefix_change)
{
/**
* Try falling back to the base prefix before giving up. Note that this
* will modify the behavior of invocations to GetPot after this method
* completes. This is desired and intended behavior. After allowing
* the prefix to fall back, one should call resetPrefix() to restore
* normal behavior.
*/
if (_has_prefix)
{
_get_pot->set_prefix((_base_prefix + ":").c_str());
if (_get_pot->have_variable(name))
return true;
}

/**
* As a final attempt we'll see if the user has passed a global command line parameter
* in the form ":name=value". Similarly to the normal subapp prefix, this will also
* modify subsequent invocations to GetPot until resetPrefix() has been called.
*/
_get_pot->set_prefix(":");
if (_get_pot->have_variable(name))
return true;
else
/**
* We failed to find the parameter with the subapp prefix (if applicable) or
* in the global section so we need to reset the prefix now back to nothing.
*/
_get_pot->set_prefix("");
}

return false;
}

void
CommandLine::setPrefix(const std::string & name, const std::string & num)
{
_base_prefix = name;
_prefix_num = num;
_has_prefix = true;

/**
* By default we'll append the name and num together and delimit with a colon for the GetPot parser.
* However, we may need to fall back and check only the base prefix if a user wants to apply a parameter
* override to all Multiapps with a given name.
*/
_get_pot->set_prefix((name + num + ":").c_str());
}

void
CommandLine::resetPrefix()
{
// If this CommandLine instance doesn't have a prefix, do nothing
if (!_has_prefix)
return;

_get_pot->set_prefix((_base_prefix + _prefix_num + ":").c_str());
}

void
Expand Down

0 comments on commit a8a56e4

Please sign in to comment.