Newer
Older
#include "Configuration.hpp"
#include <iostream>
#include <stdexcept>
#include "MpiEnvironment.hpp"
#include <boost/format.hpp>
#include <boost/program_options.hpp>
// BEGIN helper functions to parse Communication Mode cmd args
using namespace std::string_literals;
std::array<std::pair<std::string, CommunicationMode>, 2>
StringToCommunicationMode{
std::make_pair("Collective"s, CommunicationMode::Collective), //
std::make_pair("P2P"s, CommunicationMode::P2P) //
};
std::istream& operator>>(std::istream& in, CommunicationMode& comm) {
std::string buf;
in >> buf;
auto r = std::find_if(std::begin(StringToCommunicationMode),
std::end(StringToCommunicationMode),
[&](auto& t) { return t.first == buf; });
if (r == std::end(StringToCommunicationMode))
throw boost::program_options::validation_error(
boost::program_options::validation_error::invalid_option_value);
comm = r->second;
return in;
}
auto Configuration::parseArgs(int argc, char* argv[], const MpiEnvironment& env)
-> Configuration {
namespace po = boost::program_options;
Configuration cfg;
po::options_description desc{"Allowed options"};
desc.add_options()("help,h", "produce help message") //
("nprocs-x,x", po::value<std::size_t>(&cfg.Procs.Cols),
"number of processes in x-direction") //
("nprocs-y,y", po::value<std::size_t>(&cfg.Procs.Rows),
"number of processes in y-direction") //
("generations,g", po::value<std::size_t>(&cfg.Generations),
"number of generations simulated") //
("commmode,m", po::value<CommunicationMode>(&cfg.CommMode),
"Communication Mode. Collective or P2P") //
("inputfile,f", po::value<std::string>(&cfg.InputFilePath)->required(),
"path to wireworld file") //
("outputfile,o", po::value<std::string>(&cfg.OutputFilePath),
"path to output file"); //
po::positional_options_description poDesc;
poDesc.add("inputfile", 1);
po::variables_map vm;
try {
po::store(po::command_line_parser(argc, argv)
.options(desc) //
.positional(poDesc) //
.run(),
vm);
if (vm.count("help") > 0 && env.isMaster()) {
std::cout << desc << "\n";
}
po::notify(vm);
} catch (const po::error& err) { MpiReportErrorAbort(err.what()); }
// if no dimensions given, use MPI_Dims_create
if (cfg.Procs.Cols < 1 || cfg.Procs.Rows < 1) {
std::array<int, 2> dims{static_cast<int>(cfg.Procs.Cols),
static_cast<int>(cfg.Procs.Rows)};
MPI_Dims_create(env.worldSize(), // nnodes
2, // ndims
cfg.Procs.Cols = dims[0];
cfg.Procs.Rows = dims[1];
const auto& totalCellCount = cfg.Procs.Cols * cfg.Procs.Rows;
const auto& worldSize = env.worldSize();
if (totalCellCount != static_cast<std::size_t>(worldSize)) {
MpiReportErrorAbort(boost::str(
boost::format("Total number of cells (%d) does not match "
"the MPI World size (%d)") %
totalCellCount % worldSize));
}
return cfg;
}