Skip to content
Configuration.cpp 3.28 KiB
Newer Older
#include "Configuration.hpp"

#include <algorithm>
#include <array>
#include <iostream>
#include <stdexcept>
#include <tuple>

#include "MpiEnvironment.hpp"
#include <boost/format.hpp>
#include <boost/program_options.hpp>

// BEGIN helper functions to parse Communication Mode cmd args
namespace {
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;
}
// END helper functions
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") //
Thomas Steinreiter's avatar
Thomas Steinreiter committed
	    ("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);
	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(static_cast<int>(env.worldSize()), // nnodes
		                2,                                 // ndims
		                dims.data());                      // dims
		cfg.Procs.Cols = static_cast<std::size_t>(dims[0]);
		cfg.Procs.Rows = static_cast<std::size_t>(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));