Skip to content
Snippets Groups Projects
Options.cxx 7.41 KiB
/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Felix Weiglhofer [committer] */
#include "Options.h"

#include "util/StlUtils.h"

#include <boost/program_options.hpp>

#include <iostream>
#include <iterator>
#include <unordered_map>

using namespace cbm::algo;
namespace po = boost::program_options;

using fles::Subsystem;


namespace std
{
  template<class T>
  std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
  {
    copy(v.begin(), v.end(), std::ostream_iterator<T>(os, " "));
    return os;
  }
}  // namespace std

#ifndef CBM_ONLINE_USE_FAIRLOGGER
void validate(boost::any& v, const std::vector<std::string>& values, severity_level*, int)
{

  static const std::unordered_map<std::string, severity_level> levels{
    {"trace", severity_level::trace}, {"debug", severity_level::debug},     {"status", severity_level::status},
    {"info", severity_level::info},   {"warning", severity_level::warning}, {"error", severity_level::error},
    {"fatal", severity_level::fatal}};

  po::validators::check_first_occurrence(v);

  const std::string& s = po::validators::get_single_string(values);

  auto it = levels.find(s);

  if (it == levels.end()) throw po::validation_error(po::validation_error::invalid_option_value);

  v = it->second;
}
#endif  // Not CBM_ONLINE_USE_FAIRLOGGER

Options::Options(int argc, char** argv)
{

  po::options_description required("Required options");
  // clang-format off
  required.add_options()
    ("param-dir,p", po::value(&fParamsDir)->value_name("<folder>")->required(),
      "read program options from this folder")
    ("input-locator,i", po::value(&fInputLocator)->value_name("<locator>")->required(),
      "URI specifying input timeslice source")
  ;
  // clang-format on

  po::options_description generic("Other options");
  // clang-format off
  generic.add_options()
    ("output,o", po::value(&fOutputFile)->default_value("")->value_name("<file>"),
      "write results to file")
    ("device,d", po::value(&fDevice)->default_value("cpu")->value_name("<device>"),
      "select device (cpu, cuda0, cuda1, hip0, ...)")
#ifndef CBM_ONLINE_USE_FAIRLOGGER
    ("log-level,l", po::value(&fLogLevel)->default_value(info)->value_name("<level>"),
      "set log level (debug, info, warning, error, fatal)")
#endif  // Not CBM_ONLINE_USE_FAIRLOGGER
    ("monitor,m", po::value(&fMonitorUri)->value_name("<uri>")->implicit_value("file:cout"),
      "URI specifying monitor output (e.g. file:/tmp/monitor.txt, influx1:login:8086:cbmreco_status). Prints to cout when no argument is given. Monitor is disabled when flag is not set.")
    ("histogram", po::value(&fHistogramUri)->value_name("<uri>"), "URI to specify histogram server")
    ("histoshwm", po::value(&fHistogramHwm)->default_value(1)->value_name("<num>"),
     "High-Water Mark for ZMQ socket to histogram server in messages:\n"
     " 0 = no buffering, num = nb updates kept in buffer if not pulled by server \n"
     " Tune to avoid too high memory usage but also adapt to server load!")
    ("aux-data", po::value(&fCollectAuxData)->implicit_value(true), "Enables collecting of auxiliary data from algorithms")
    ("qa", po::value(&fQaSteps)->multitoken()->default_value({QaStep::UnpackSts, QaStep::EventBuilding, QaStep::Tracking})->value_name("<qa steps>"),
      "space separated list of QA Steps to enable (BeamBmon, UnpackSts, EventBuilding, Tracking, ...)")
#ifdef BOOST_IOS_HAS_ZSTD
    ("hist-compr", po::bool_switch(&fCompressHistograms)->default_value(false),
      "enables ZSTD compression of the outgoing histograms stream (decompression needed in target server!)")
#endif
    ("log-file,L", po::value(&fLogFile)->value_name("<file>"),
      "write log messages to file")
    ("output-types,O", po::value(&fOutputTypes)->multitoken()->value_name("<types>"),
      "space separated list of reconstruction output types (Hit, Tracks, DigiTimeslice, DigiEvent, ...)")
    ("compress-archive", po::bool_switch(&fCompressArchive)->default_value(false), "Enable compression for output archives")
    ("steps", po::value(&fRecoSteps)->multitoken()->default_value({Step::Unpack, Step::DigiTrigger, Step::LocalReco, Step::Tracking})->value_name("<steps>"),
      "space separated list of reconstruction steps (unpack, digitrigger, localreco, ...)")
    ("event-reco", po::bool_switch(&fReconstructDigiEvents)->default_value(false), "runs digi event reconstruction (local reco, tracking, trigger)")
    ("systems,s", po::value(&fDetectors)->multitoken()->default_value({Subsystem::STS, Subsystem::TOF, Subsystem::BMON, Subsystem::MUCH, Subsystem::RICH, Subsystem::TRD, Subsystem::TRD2D})->value_name("<detectors>"),
      "space separated list of detectors to process (sts, mvd, ...)")
    ("child-id,c", po::value(&fChildId)->default_value("00")->value_name("<id>"), "online process id on node")
    ("run-id,r", po::value(&fRunId)->default_value(2391)->value_name("<RunId>"), "Run ID, for now flesctl run index, later run start time")
    ("run-start", po::value(&fRunStartTime)->default_value(0)->value_name("<RunStart >"), "Run start time in ns, can be fles start or online start")
    ("num-ts,n", po::value(&fNumTimeslices)->default_value(-1)->value_name("<num>"),
      "Stop after <num> timeslices (-1 = all)")
    ("skip-ts", po::value(&fSkipTimeslices)->default_value(0)->value_name("<num>"),
      "Skip first <num> timeslices")
    ("omp", po::value(&fNumOMPThreads)->default_value(-1)->value_name("<num>"),
      "Set number of OpenMP threads (-1 = use OMP_NUM_THREADS environment variable)")
    ("times,t", po::value(&fProfilingLevel)->default_value(ProfilingNone)->implicit_value(ProfilingPerTS),
      "Print kernel times (Can opt. be given a value: Use none to disable or summary to only print aggregated times.)")
    ("timings-file", po::value(&fTimingsFile)->value_name("<file>"),
      "Write profiling times to yaml file (only when '-t' is set)")
    ("dump-archive", po::bool_switch(&fDumpArchive)->default_value(false),
      "Dump archive content to stdout and exit. Provide archive with '-i'. (This is a hack to quick check archive content until we have proper tooling.)")
    ("release-mode,R",po::value<bool>(&fReleaseMode)->implicit_value(true),
      "Copy and release each timeslice immediately after receiving it")
    ("help,h",
      "produce help message")
  ;
  // clang-format on

  po::options_description cmdline_options;
  cmdline_options.add(required).add(generic);

  po::variables_map vm;
  po::command_line_parser parser{argc, argv};
  parser.options(cmdline_options);
  try {
    auto result = parser.run();
    po::store(result, vm);
  }
  catch (const std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl;
    std::cerr << "Use '-h' to display all valid options." << std::endl;
    std::exit(EXIT_FAILURE);
  }

  if (vm.count("help") > 0) {
    std::cout << cmdline_options << std::endl;
    std::exit(EXIT_SUCCESS);
  }

  try {
    po::notify(vm);
  }
  catch (const po::required_option& e) {
    std::cerr << "Error: " << e.what() << std::endl;
    std::cerr << "Use '-h' to display all valid options." << std::endl;
    std::exit(EXIT_FAILURE);
  }
}

bool Options::HasOutput(RecoData recoData) const { return Contains(fOutputTypes, recoData); }

bool Options::Has(fles::Subsystem detector) const { return Contains(fDetectors, detector); }

bool Options::Has(Step step) const { return Contains(fRecoSteps, step); }

bool Options::Has(QaStep qastep) const { return Contains(fQaSteps, qastep); }