Skip to content

Commit

Permalink
Polishing, improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
siramok committed Aug 2, 2024
1 parent bb61ae2 commit 11197e0
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ Steering::verify_params(const conduit::Node &params,
conduit::Node &info)
{
bool res = true;
// This optional parameter exists for automated testing purposes
if(params.has_child("explicit_command"))
{
// This parameter exists for automated testing purposes
if(!params["explicit_command"].dtype().is_string())
{
info["errors"].append() = "optional entry 'explicit_command' must"
Expand All @@ -98,51 +98,51 @@ Steering::verify_params(const conduit::Node &params,
void
Steering::execute()
{
// Commands
m_commands["exit"] = [this]()
{ this->exit_shell(); };
m_commands["help"] = [this]()
{ this->print_help(); };
m_commands["list"] = [this]()
{ this->list_callbacks(); };
m_commands["param"] = [this]()
{ this->print_params(); };
m_commands["run"] = [this]()
{ this->empty_run(); };

// Descriptions
// Map of commands to function pointers
m_commands["exit"] = [this](){this->exit_shell();};
m_commands["help"] = [this](){this->print_help();};
m_commands["list"] = [this](){this->list_callbacks();};
m_commands["param"] = [this](){this->print_params();};
m_commands["run"] = [this](){this->empty_run();};

// Descriptions for each command
m_descriptions["exit"] = "Exit the steering interface.";
m_descriptions["help"] = "Print this help message.";
m_descriptions["list"] = "List all registered Ascent callbacks.";
m_descriptions["param"] = "Modify current params.\n\t\
- Print: param\n\t\
- Add: param <key> <value>\n\t\
- Delete: param delete <key>\n\t\
- Reset: param reset";
m_descriptions["run"] = "Run an Ascent callback.\n\t\
- Example: run <callback_name>";

#ifdef ASCENT_MPI_ENABLED
// Grab the MPI communicator we're supposed to use
m_mpi_comm = MPI_Comm_f2c(flow::Workspace::default_mpi_comm());
MPI_Comm_rank(m_mpi_comm, &m_rank);
m_params["mpi_comm"] = MPI_Comm_c2f(m_mpi_comm);
#else
m_rank = 0;
#endif
m_params["mpi_rank"] = m_rank;

m_running = true;
m_empty_params = true;

// Print header
if (m_rank == 0)
{
std::cout << std::endl << "-------------Entering interactive steering";
std::cout << " mode for Ascent--------------" << std::endl;
std::cout << std::endl << "-------------Entering interactive";
std::cout << " steering mode for Ascent--------------" << std::endl;
std::cout << "Type 'help' to see available commands" << std::endl;
std::cout << std::endl;
}

std::string input;
int input_size = 0;
// Setup variables
m_running = true;
while (m_running)
{
std::string input = "";
int input_size = input.size();

if(params().has_path("explicit_command"))
{
// This path exists for automated testing purposes
Expand All @@ -157,12 +157,17 @@ Steering::execute()
}
else if (m_rank == 0)
{
// Blocks forever waiting for user input
// TODO: it would be cool to eventually implement a timeout here
std::cout << "steering>" << std::endl;
std::getline(std::cin, input);
input_size = input.size();
}

#ifdef ASCENT_MPI_ENABLED
// The input string gets broadcast, parsed, and executed by all MPI
// ranks. This enables us to 1) maintain param parity and 2)
// execute callbacks that make use of MPI.
MPI_Bcast(&input_size, 1, MPI_INT, 0, m_mpi_comm);
if (m_rank > 0)
{
Expand All @@ -175,12 +180,11 @@ Steering::execute()
m_mpi_comm);
#endif

// Parse and execute user input
// Parse and execute user input. Users can't naturally enter
// multi-line commands, but we support it here for automated
// testing purposes
std::istringstream iss(input);
std::string line;

// Users can't naturally enter multi-line commands, but
// we support it here for automated testing purposes
while (std::getline(iss, line))
{
std::istringstream lineStream(line);
Expand All @@ -189,14 +193,16 @@ Steering::execute()

std::vector<std::string> tokens;
std::string token;
while (lineStream >> token) {
while (lineStream >> token)
{
tokens.push_back(token);
}

parse_input(cmd, tokens);
}
}

// Print footer
if (m_rank == 0)
{
std::cout << "-------------Exiting interactive steering mode for";
Expand Down Expand Up @@ -231,6 +237,7 @@ Steering::exit_shell()
void
Steering::list_callbacks()
{
// Let users see which callbacks were registered with Ascent
if (m_rank == 0)
{
std::cout << std::endl << "[Available Callbacks]" << std::endl;
Expand All @@ -257,6 +264,9 @@ Steering::list_callbacks()
}
else
{
// We currently don't let users execute bool callbacks via this
// interface, but we may as well list them here for debug
// purposes
std::cout << "bool: ";
for (const auto &callback : bool_callback_names)
{
Expand Down Expand Up @@ -289,106 +299,121 @@ Steering::print_params()
if (m_rank == 0)
{
std::cout << std::endl << "[Current Params]";
if (m_empty_params)
if (m_params.number_of_children() > 0)
{
std::cout << std::endl << "None" << std::endl << std::endl;
m_params.print();
}
else
{
m_params.print();
std::cout << std::endl << "None" << std::endl << std::endl;
}
}
}

//-----------------------------------------------------------------------------
void
Steering::run_callback(const std::vector<std::string> &args)
Steering::run_callback(const std::string &callback_name)
{
try
bool has_callback = false;

// Void callback name iterator
std::vector<std::string> void_callback_names;
ascent::get_void_callbacks(void_callback_names);
auto void_it = std::find(void_callback_names.begin(),
void_callback_names.end(),
callback_name);

// Bool callback name iterator
std::vector<std::string> bool_callback_names;
ascent::get_bool_callbacks(bool_callback_names);
auto bool_it = std::find(bool_callback_names.begin(),
bool_callback_names.end(),
callback_name);

// Make sure that the callback actually exists before executing it. This
// lets us print a friendlier error in case it doesn't
if (void_it != void_callback_names.end())
{
std::string callback = args[0];
bool has_callback = false;

// Void
std::vector<std::string> void_callback_names;
ascent::get_void_callbacks(void_callback_names);
auto void_it = std::find(void_callback_names.begin(),
void_callback_names.end(),
callback);

// Bool
std::vector<std::string> bool_callback_names;
ascent::get_bool_callbacks(bool_callback_names);
auto bool_it = std::find(bool_callback_names.begin(),
bool_callback_names.end(),
callback);

if (void_it != void_callback_names.end()) {
has_callback = true;
if (m_rank == 0)
{
std::cout << std::endl << "Running callback: " << callback;
std::cout << std::endl;
}
}
else if (bool_it != bool_callback_names.end()) {
if (m_rank == 0)
{
std::cout << std::endl << "[Error]" << std::endl;
std::cout << "Directly executing bool callbacks is not";
std::cout << " supported." << std::endl << std::endl;
}
}
else
has_callback = true;
if (m_rank == 0)
{
if (m_rank == 0)
{
std::cout << std::endl << "[Error]" << std::endl;
std::cout << "There is no registered callback named '";
std::cout << callback << "'" << std::endl << std::endl;
}
std::cout << std::endl << "Running callback: " << callback_name;
std::cout << std::endl;
}
}
else if (bool_it != bool_callback_names.end() && m_rank == 0)
{
// TODO: would it make sense to let users execute bool callbacks?
std::cout << std::endl << "[Error]" << std::endl;
std::cout << "Directly executing bool callbacks is not";
std::cout << " supported from this interface." << std::endl;
std::cout << std::endl;
}
else if (m_rank == 0)
{
std::cout << std::endl << "[Error]" << std::endl;
std::cout << "There is no registered callback named '";
std::cout << callback_name << "'" << std::endl << std::endl;
}

if (!has_callback)
{
return;
}
if (!has_callback)
{
return;
}

ascent::execute_callback(callback, m_params, m_output);
// Reset any output from a previous callback
m_output = conduit::Node();

// This might not be necessary?
// It's not a great experience if the interface crashes due to an exception
// getting thrown within a callback
try
{
ascent::execute_callback(callback_name, m_params, m_output);
}
catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
}

// TODO: reevaluate if an MPI barrier is necessary here
#ifdef ASCENT_MPI_ENABLED
MPI_Barrier(m_mpi_comm);
MPI_Barrier(m_mpi_comm);
#endif

if (m_rank == 0)

if (m_rank == 0)
{
std::cout << std::endl << "[Output]";
if (m_output.number_of_children() > 0)
{
std::cout << std::endl << "[Output]";
m_output.print();
std::cout << std::endl;
}
}
catch (const std::exception &e)
{
// TODO: emit an Ascent error instead?
std::cerr << e.what() << std::endl;
else
{
std::cout << std::endl << "None" << std::endl << std::endl;
}
}
}

//-----------------------------------------------------------------------------
void
Steering::modify_params(const std::vector<std::string> &args)
Steering::modify_params(const std::vector<std::string> &tokens)
{
std::string cmd = args.size() > 0 ? args[0] : "";
std::string arg = args.size() > 1 ? args[1] : "";
std::string cmd = tokens.size() > 0 ? tokens[0] : "";
std::string arg = tokens.size() > 1 ? tokens[1] : "";

if (cmd == "reset")
{
// Start fresh with a new Conduit node
m_params = conduit::Node();
#ifdef ASCENT_MPI_ENABLED
m_params["mpi_comm"] = MPI_Comm_c2f(m_mpi_comm);
#endif
m_params["mpi_rank"] = m_rank;
}
else if (cmd == "delete" && !arg.empty())
{
if(m_params.has_child(arg))
// Remove a specific param
if(arg != "mpi_comm" && arg != "mpi_rank" && m_params.has_child(arg))
{
m_params.remove(arg);
}
Expand All @@ -405,7 +430,6 @@ Steering::modify_params(const std::vector<std::string> &args)
// The side effect of this is that integers are also
double possible_number = std::stod(arg);
m_params[cmd] = possible_number;
m_empty_params = false;
assigned = true;
}
catch (const std::invalid_argument&)
Expand All @@ -416,11 +440,10 @@ Steering::modify_params(const std::vector<std::string> &args)
}
}

// It wasn't numeric, treat it as a string
// The input wasn't numeric, so we treat it as a string
if (!assigned)
{
m_params[cmd] = arg;
m_empty_params = false;
}
}

Expand All @@ -445,7 +468,8 @@ Steering::parse_input(const std::string &cmd,

if (cmd == "run" && !args.empty())
{
run_callback(args);
std::string callback_name = args[0];
run_callback(callback_name);
}
else if (cmd == "param" && !args.empty())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,14 @@ class ASCENT_API Steering : public ::flow::Filter
#endif
int m_rank;
bool m_running;
bool m_empty_params;

void empty_run();
void exit_shell();
void list_callbacks();
void print_help();
void print_params();
void run_callback(const std::vector<std::string> &args);
void modify_params(const std::vector<std::string> &args);
void run_callback(const std::string &callback_name);
void modify_params(const std::vector<std::string> &tokens);
void parse_input(const std::string &cmd,
const std::vector<std::string> &args);
};
Expand Down
Loading

0 comments on commit 11197e0

Please sign in to comment.