--- a/bin/Makefile.am Mon Apr 03 13:52:15 2017 +0200 +++ b/bin/Makefile.am Mon May 01 13:49:26 2017 +0200 @@ -27,7 +27,7 @@ endif ## No-Python Rivet program -noinst_PROGRAMS = rivet-nopy +bin_PROGRAMS = rivet-nopy rivet_nopy_SOURCES = rivet-nopy.cc rivet_nopy_CPPFLAGS = -I$(top_srcdir)/include $(AM_CPPFLAGS) rivet_nopy_LDFLAGS = -L$(HEPMCLIBPATH) --- a/bin/rivet-nopy.cc Mon Apr 03 13:52:15 2017 +0200 +++ b/bin/rivet-nopy.cc Mon May 01 13:49:26 2017 +0200 @@ -1,36 +1,320 @@ #include "Rivet/AnalysisHandler.hh" #include "Rivet/AnalysisLoader.hh" +#include "Rivet/Analysis.hh" +#include "Rivet/Run.hh" +#include "Rivet/Tools/RivetPaths.hh" #include "HepMC/IO_GenEvent.h" using namespace std; -int main(int argc, char** argv) { - if (argc < 2) { - cerr << "Usage: " << argv[0] << " [ ...]" << endl; +/** + * Make friendly help message + * + * @param prog Program name + */ +void usage(const char* prog) +{ + std::cout << "Usage: " << prog << "[ARGUMENTS] INPUT\n\n" + << "Options:\n" + << " -a NAME Add analysis NAME\n" + << " -n NUMBER Number of events to analyse\n" + << " -s NUMBER Skip this many events\n" + << " -p Add current directory to searhc path\n" + << " -o FILENAME Output file name\n" + << " -A List all known analyses\n" + << " -U List used analyses\n" + << " -l COMPONENT=LEVEL Set logging level for COMPONENT\n" + << " -r NAME Set run name\n" + << " -i Ignore beams\n" + << " -x X-SECTION Set cross-section (in pb)\n" + << std::endl; +} + +// Using declaration for getLog +using Rivet::Log; + +/** + * Make sure we can get a logger here + */ +Rivet::Log& getLog() +{ + return Log::getLog("Rivet.main"); +} + +/** + * Set log level on component from argument string + */ +void setLogLevel(const std::string& arg) +{ + size_t eq = arg.find('='); + if (eq == std::string::npos) return; + + std::string comp = arg.substr(0,eq); + std::string lvl = arg.substr(eq+1,std::string::npos); + std::transform(lvl.begin(), lvl.end(), lvl.begin(), ::toupper); + Rivet::Log::setLevel(comp, Rivet::Log::getLevelFromName(lvl)); +} + +/** + * Progress meter + */ +struct Progress +{ + clock_t _start; + clock_t _mark; + clock_t _now; + long _freq; + /** + * Constructor + * + * @param f Update frequency + */ + Progress(long f) : + _start(clock()), _mark(_start), _now(_start), _freq(f) + { } + /** + * Store current time + */ + void split() { _now = clock(); } + void mark() { _mark = clock(); } + /** + * Calculate how much time as elapsed + * + * @return Time elapsd in seconds + */ + int elapsed() const { return (_now - _start) / CLOCKS_PER_SEC; } + /** + * Calculate how much time remains + * + * @param current event number + * @param end Maximum event number + * + * @return seconds remaning, or -1 if not possible to calculate + */ + int remain(long cur, long end) + { + if (end <= 0) return (_now-_mark)/CLOCKS_PER_SEC; + if (_now == _mark) return -1; + double per = double(cur) / (_now - _mark); + int rem = end - cur; + return rem / per / CLOCKS_PER_SEC; + } + /** + * Format a time string + * + * @param sec Seconds + */ + std::string format(int sec) + { + std::stringstream s; + if (sec < 0) s << "?"; + else + s << (sec / 3600) << ":" << std::setfill('0') + << std::setw(2) << ((sec / 60) % 60) << ":" + << std::setw(2) << (sec % 60); + return s.str(); + } + /** + * Print current progress + */ + void print(long cur, long end, const char* pre="Processed") + { + split(); + int rem = remain(cur, end); + int spe = remain(cur, 0); + int ela = elapsed(); + std::stringstream s; + s.precision(3); + s << std::left << std::setw(9) << pre << std::right + << std::setw(9) << cur; + if (end > 0) s << " of " << std::setw(9) << end; + s << " elapsed: " << format(ela) << " (" << std::setw(6); + if (ela > 0) s << double(cur)/spe; + else s << "?"; + s << "/s)"; + if (end > 0) s << " ETA: " << format(rem); + if (cur % _freq == 0) MSG_INFO(s.str()); + else MSG_DEBUG(s.str()); + } +}; + + +int main(int argc, char** argv) +{ + std::vector anaNames; + std::vector inputs; + std::string output("Rivet.yoda"); + std::string runName(""); + long nEvents = 0; + long nSkip = 0; + long freq = 100; + bool listAll = false; + bool listUsed = false; + bool ignoreBeams = false; + bool store = true; + double xSection = -1; + for (int i = 1; i < argc; i++) { + std::string arg(argv[i]); + if (arg[0] != '-' || arg[1] == '\0') { + inputs.push_back(arg); + continue; + } + if (arg[1] == '-') { + if (arg=="--help") { usage(argv[0]); exit(0); } + else if (arg=="--analysis") anaNames.push_back(argv[++i]); + else if (arg=="--nevts") nEvents = atoll(argv[++i]); + else if (arg=="--nskip") nSkip = atoll(argv[++i]); + else if (arg=="--pwd") Rivet::addAnalysisLibPath("."); + else if (arg=="--histo-file") output = argv[++i]; + else if (arg=="--list" || arg=="--list-analyses") listAll = true; + else if (arg=="--list-used-analyses") listUsed = true; + else if (arg=="--runname") runName = argv[++i]; + else if (arg=="--ignore-beams") ignoreBeams = true; + else if (arg=="--cross-section") xSection = atof(argv[++i]); + else if (arg=="--verbose") setLogLevel("Rivet.main=DEBUG"); + else if (arg=="--quiet") setLogLevel("Rivet.main=TRACE"); + else if (arg=="--no-histo-file") store = false; + else { + MSG_ERROR("Unknown option: " << arg); + exit(1); + } + continue; + } + switch (arg[1]) { + case 'h': usage(argv[0]); exit(0); break; + case 'a': anaNames.push_back(argv[++i]); break; + case 'n': nEvents = atoll(argv[++i]); break; + case 's': nSkip = atoll(argv[++i]); break; + case 'p': Rivet::addAnalysisLibPath("."); break; + case 'I': // Fall-through + case 'L': Rivet::addAnalysisLibPath(arg.substr(2,std::string::npos)); break; + case 'H': // Fall-through + case 'o': output = argv[++i]; break; + case 'A': listAll = true; break; + case 'U': listUsed = true; break; + case 'l': setLogLevel(argv[++i]); break; + case 'r': runName = argv[++i]; break; + case 'i': ignoreBeams = true; break; + case 'x': xSection = atof(argv[++i]); break; + case 'v': setLogLevel("Rivet.main=DEBUG"); break; + case 'q': setLogLevel("Rivet.main=TRACE"); break; + case 'N': store = false; break; + case 'f': freq = atoll(argv[++i]); break; + default: + MSG_ERROR("Unknown option " << arg); + return 1; + } + } + // Possibly list all known analysis + if (listAll) { + typedef std::unique_ptr AnaPtr; + typedef std::vector Analyses; + Analyses all = Rivet::AnalysisLoader::getAllAnalyses(); + for (Analyses::const_iterator i = all.begin(); i != all.end(); ++i) { + // AnaPtr a = *i; + std::stringstream s; + s << std::left << std::setw(25) << (*i)->name() << " " + << std::setw(12) << (*i)->status() << " " + << (*i)->summary(); + std::cout << s.str() << std::endl; + } + return 0; + } + // Sanity checks + if (nEvents < 0) nEvents = 0; + if (nSkip < 0) nSkip = 0; + if (inputs.size() <= 0) { + MSG_ERROR("No inputs specified"); return 1; } - - foreach (const string& a, Rivet::AnalysisLoader::analysisNames()) - cout << a << endl; - - Rivet::AnalysisHandler ah; - for (int i = 2; i < argc; ++i) { - ah.addAnalysis(argv[i]); + if (anaNames.size() <= 0) { + MSG_ERROR("No analyses specified"); + return 1; } + // Print some information on what we're about to do + std::stringstream s; + s << "Setting:\n" + << " Run name: " << runName << "\n" + << " Number of events: " << nEvents << "\n" + << " Number of events to skip: " << nSkip << "\n" + << " Output file: " << output << "\n" + << " X-section: " << xSection << "\n" + << " Analyses: "; + std::copy(anaNames.begin(), anaNames.end(), + std::ostream_iterator(s, " ")); + s << "\n Inputs: "; + std::copy(inputs.begin(), inputs.end(), + std::ostream_iterator(s, " ")); + MSG_INFO(s.str()); - std::ifstream file(argv[1]); - HepMC::IO_GenEvent hepmcio(file); - HepMC::GenEvent* evt = hepmcio.read_next_event(); - while (evt) { - ah.analyze(*evt); - delete evt; evt = 0; - hepmcio >> evt; + // Create analysis handler and add analyses + Rivet::AnalysisHandler ah(runName); + ah.setIgnoreBeams(ignoreBeams); + for (auto n : anaNames) ah.addAnalysis(n); + + // Create runner, set parameters, and initialize from first event + Rivet::Run run(ah); + run.setListAnalyses(listUsed); + if (xSection > 0) run.setCrossSection(xSection); + run.init(inputs[0], 1); + + // Create progress meter and initialize some states + Progress p(freq); + bool first = true; + long ev = 0; + long sk = 0; + + // Loop over all inputs + for (auto i : inputs) { + // Open file - not done on first iteration because already done in + // init + if (!first) run.openFile(i, 1); + first = false; + + // Read in event + if (!run.readEvent()) { + MSG_ERROR("Failed to read event from '" << i << "'"); + continue; + } + + // Loop over number of events or all events + while (nEvents <= 0 || ev-nSkip < nEvents) { + ev++; + + // Possible skip over events + if (ev < nSkip) { + sk++; + p.print(sk, nSkip, "Skipped"); + run.skipEvent(); + continue; + } + // When done skipping, update our mark time + if (ev == nSkip) p.mark(); + + // Process event + if (!run.processEvent()) { + MSG_WARNING("Processing of event " << ev << " failed"); + break; + } + p.print(ev-nSkip, nEvents); + + // Read the next event + if (!run.readEvent()) break; + } } - file.close(); + // End the job and possibly write output + run.finalize(); + if (store) { + MSG_INFO("Writing output to " << output); + std::stringstream s; + for (auto d : ah.getData()) + s << " " << std::left << std::setw(25) << d->path() + << " " << d->title() << "\n"; + MSG_INFO(s.str()); + ah.writeData(output); + } + MSG_INFO("All done"); - ah.setCrossSection(1.0); - ah.finalize(); - ah.writeData("Rivet.yoda"); - + // _exit(0); return 0; } --- a/include/Rivet/AnalysisHandler.hh Mon Apr 03 13:52:15 2017 +0200 +++ b/include/Rivet/AnalysisHandler.hh Mon May 01 13:49:26 2017 +0200 @@ -28,6 +28,7 @@ /// for handling the final writing-out of histograms. class AnalysisHandler { public: + typedef list Analyses; /// @name Constructors and destructors. */ //@{ @@ -118,7 +119,7 @@ std::vector analysisNames() const; /// Get the collection of currently registered analyses. - const std::set& analyses() const { + const Analyses& analyses() const { return _analyses; } @@ -192,9 +193,10 @@ private: - + /// The collection of Analysis objects to be used. - set _analyses; + // set _analyses; + Analyses _analyses; /// @name Run properties --- a/src/Core/AnalysisHandler.cc Mon Apr 03 13:52:15 2017 +0200 +++ b/src/Core/AnalysisHandler.cc Mon May 01 13:49:26 2017 +0200 @@ -185,7 +185,8 @@ if (analysis.get() != 0) { // < Check for null analysis. MSG_DEBUG("Adding analysis '" << analysisname << "'"); analysis->_analysishandler = this; - _analyses.insert(analysis); + // _analyses.insert(analysis); + _analyses.push_back(analysis); } else { MSG_WARNING("Analysis '" << analysisname << "' not found."); } @@ -205,7 +206,8 @@ } if (toremove.get() != 0) { MSG_DEBUG("Removing analysis '" << analysisname << "'"); - _analyses.erase(toremove); + // _analyses.erase(toremove); + _analyses.remove(toremove); } return *this; } @@ -311,7 +313,8 @@ AnalysisHandler& AnalysisHandler::addAnalysis(Analysis* analysis) { analysis->_analysishandler = this; - _analyses.insert(AnaHandle(analysis)); + // _analyses.insert(AnaHandle(analysis)); + _analyses.push_back(AnaHandle(analysis)); return *this; }