rivet is hosted by Hepforge, IPPP Durham
AnalysisInfo.cc
Go to the documentation of this file.
00001 #include "Rivet/Rivet.hh"
00002 #include "Rivet/AnalysisInfo.hh"
00003 #include "Rivet/Tools/RivetBoost.hh"
00004 #include "Rivet/Tools/RivetPaths.hh"
00005 #include "Rivet/Tools/Utils.hh"
00006 #include "Rivet/Tools/Logging.hh"
00007 #include "yaml-cpp/yaml.h"
00008 #include <iostream>
00009 #include <fstream>
00010 #include <unistd.h>
00011 
00012 namespace Rivet {
00013 
00014 
00015   namespace {
00016     Log& getLog() {
00017       return Log::getLog("Rivet.AnalysisInfo");
00018     }
00019   }
00020 
00021 
00022   /// Static factory method
00023   AnalysisInfo* AnalysisInfo::make(const std::string& ananame) {
00024     // Returned AI, in semi-null state
00025     AnalysisInfo* ai = new AnalysisInfo();
00026     ai->_beams += make_pair(PID::ANY, PID::ANY);
00027     ai->_name = ananame;
00028 
00029     /// If no ana data file found, return null AI
00030     const string datapath = findAnalysisInfoFile(ananame + ".info");
00031     if (datapath.empty()) {
00032       MSG_DEBUG("No datafile " << ananame + ".info found");
00033       return ai;
00034     }
00035 
00036     // Read data from YAML document
00037     MSG_DEBUG("Reading analysis data from " << datapath);
00038     YAML::Node doc;
00039     try {
00040       #if YAMLCPP_API_VERSION == 3
00041       std::ifstream file(datapath.c_str());
00042       YAML::Parser parser(file);
00043       parser.GetNextDocument(doc);
00044       #elif YAMLCPP_API_VERSION == 5
00045       doc = YAML::LoadFile(datapath);
00046       #endif
00047     } catch (const YAML::ParserException& ex) {
00048       MSG_ERROR("Parse error when reading analysis data from " << datapath << " (" << ex.what() << ")");
00049       return ai;
00050     }
00051 
00052     #define THROW_INFOERR(KEY) throw InfoError("Problem in info parsing while accessing key " + string(KEY) + " in file " + datapath)
00053 
00054     // Simple scalars (test for nullness before casting)
00055     #if YAMLCPP_API_VERSION == 3
00056     /// @todo Fix
00057     #define TRY_GETINFO(KEY, VAR) try { if (doc.FindValue(KEY)) { string val; doc[KEY] >> val; ai->_ ## VAR = val; } } catch (...) { THROW_INFOERR(KEY); }
00058     #elif YAMLCPP_API_VERSION == 5
00059     #define TRY_GETINFO(KEY, VAR) try { if (doc[KEY] && !doc[KEY].IsNull()) ai->_ ## VAR = doc[KEY].as<string>(); } catch (...) { THROW_INFOERR(KEY); }
00060     #endif
00061     TRY_GETINFO("Name", name);
00062     TRY_GETINFO("Summary", summary);
00063     TRY_GETINFO("Status", status);
00064     TRY_GETINFO("RunInfo", runInfo);
00065     TRY_GETINFO("Description", description);
00066     TRY_GETINFO("Experiment", experiment);
00067     TRY_GETINFO("Collider", collider);
00068     TRY_GETINFO("Year", year);
00069     TRY_GETINFO("SpiresID", spiresId);
00070     TRY_GETINFO("InspireID", inspireId);
00071     TRY_GETINFO("BibKey", bibKey);
00072     TRY_GETINFO("BibTeX", bibTeX);
00073     #undef TRY_GETINFO
00074 
00075     // Sequences (test the seq *and* each entry for nullness before casting)
00076     #if YAMLCPP_API_VERSION == 3
00077     /// @todo Fix
00078     #define TRY_GETINFO_SEQ(KEY, VAR) try { \
00079         if (const YAML::Node* VAR = doc.FindValue(KEY)) {               \
00080           for (size_t i = 0; i < VAR->size(); ++i) {                     \
00081             string val; (*VAR)[i] >> val; ai->_ ## VAR += val;          \
00082           } } } catch (...) { THROW_INFOERR(KEY); }
00083     #elif YAMLCPP_API_VERSION == 5
00084     #define TRY_GETINFO_SEQ(KEY, VAR) try { \
00085         if (doc[KEY] && !doc[KEY].IsNull()) {                           \
00086           const YAML::Node& VAR = doc[KEY];                             \
00087           for (size_t i = 0; i < VAR.size(); ++i)                       \
00088             if (!VAR[i].IsNull()) ai->_ ## VAR += VAR[i].as<string>();  \
00089         } } catch (...) { THROW_INFOERR(KEY); }
00090     #endif
00091     TRY_GETINFO_SEQ("Authors", authors);
00092     TRY_GETINFO_SEQ("References", references);
00093     TRY_GETINFO_SEQ("ToDo", todos);
00094     #undef TRY_GETINFO_SEQ
00095 
00096 
00097     // A boolean with some name flexibility
00098     try {
00099       #if YAMLCPP_API_VERSION == 3
00100       bool val;
00101       if (const YAML::Node* n = doc.FindValue("NeedsCrossSection")) { *n >> val; ai->_needsCrossSection = val; }
00102       if (const YAML::Node* n = doc.FindValue("NeedCrossSection")) { *n >> val; ai->_needsCrossSection = val; }
00103       #elif YAMLCPP_API_VERSION == 5
00104       if (doc["NeedsCrossSection"]) ai->_needsCrossSection = doc["NeedsCrossSection"].as<bool>();
00105       else if (doc["NeedCrossSection"]) ai->_needsCrossSection = doc["NeedCrossSection"].as<bool>();
00106       #endif
00107     } catch (...) {
00108       THROW_INFOERR("NeedsCrossSection|NeedCrossSection");
00109     }
00110 
00111 
00112     // Beam particle identities
00113     try {
00114       #if YAMLCPP_API_VERSION == 3
00115 
00116       if (const YAML::Node* pbeampairs = doc.FindValue("Beams")) {
00117         const YAML::Node& beampairs = *pbeampairs;
00118         vector<PdgIdPair> beam_pairs;
00119         if (beampairs.size() == 2 &&
00120             beampairs[0].Type() == YAML::NodeType::Scalar &&
00121             beampairs[1].Type() == YAML::NodeType::Scalar) {
00122           string bstr0, bstr1;
00123           beampairs[0] >> bstr0;
00124           beampairs[1] >> bstr1;
00125           beam_pairs += PID::make_pdgid_pair(bstr0, bstr1);
00126         } else {
00127           for (YAML::Iterator bpi = beampairs.begin(); bpi != beampairs.end(); ++bpi) {
00128             const YAML::Node& bp = *bpi;
00129             if (bp.size() == 2 &&
00130                 bp[0].Type() == YAML::NodeType::Scalar &&
00131                 bp[1].Type() == YAML::NodeType::Scalar) {
00132               string bstr0, bstr1;
00133               bp[0] >> bstr0;
00134               bp[1] >> bstr1;
00135               beam_pairs += PID::make_pdgid_pair(bstr0, bstr1);
00136             } else {
00137               throw InfoError("Beam ID pairs have to be either a 2-tuple or a list of 2-tuples of particle names");
00138             }
00139           }
00140         }
00141         ai->_beams = beam_pairs;
00142       }
00143 
00144       #elif YAMLCPP_API_VERSION == 5
00145 
00146       if (doc["Beams"]) {
00147         const YAML::Node& beams = doc["Beams"];
00148         vector<PdgIdPair> beam_pairs;
00149         if (beams.size() == 2 && beams[0].IsScalar() && beams[0].IsScalar()) {
00150           beam_pairs += PID::make_pdgid_pair(beams[0].as<string>(), beams[1].as<string>());
00151         } else {
00152           for (size_t i = 0; i < beams.size(); ++i) {
00153             const YAML::Node& bp = beams[i];
00154             if (bp.size() != 2 || !bp[0].IsScalar() || !bp[0].IsScalar())
00155               throw InfoError("Beam ID pairs have to be either a 2-tuple or a list of 2-tuples of particle names");
00156             beam_pairs += PID::make_pdgid_pair(bp[0].as<string>(), bp[1].as<string>());
00157           }
00158         }
00159         ai->_beams = beam_pairs;
00160       }
00161 
00162       #endif
00163     } catch (...) { THROW_INFOERR("Beams"); }
00164 
00165 
00166     // Beam energies
00167     try {
00168       #if YAMLCPP_API_VERSION == 3
00169 
00170       if (const YAML::Node* penergies = doc.FindValue("Energies")) {
00171         const YAML::Node& energies = *penergies;
00172         vector<pair<double,double> > beam_energy_pairs;
00173         for (YAML::Iterator be = energies.begin(); be != energies.end(); ++be) {
00174           if (be->Type() == YAML::NodeType::Scalar) {
00175             // If beam energy is a scalar, then assume symmetric beams each with half that energy
00176             double sqrts;
00177             *be >> sqrts;
00178             beam_energy_pairs += make_pair(sqrts/2.0, sqrts/2.0);
00179           } else if (be->Type() == YAML::NodeType::Sequence) {
00180             const YAML::Node& beseq = *be;
00181             // If the sub-sequence is of length 1, then it's another scalar sqrt(s)!
00182             if (beseq.size() == 1) {
00183               double sqrts;
00184               (*be)[0] >> sqrts;
00185               beam_energy_pairs += make_pair(sqrts/2.0, sqrts/2.0);
00186             } else if (beseq.size() == 2) {
00187               vector<double> beamenergies;
00188               double beamenergy0, beamenergy1;
00189               beseq[0] >> beamenergy0;
00190               beseq[1] >> beamenergy1;
00191               beam_energy_pairs += make_pair(beamenergy0, beamenergy1);
00192             } else {
00193               throw InfoError("Beam energies have to be a list of either numbers or pairs of numbers");
00194             }
00195           } else {
00196             throw InfoError("Beam energies have to be a list of either numbers or pairs of numbers");
00197           }
00198         }
00199         ai->_energies = beam_energy_pairs;
00200       }
00201 
00202       #elif YAMLCPP_API_VERSION == 5
00203 
00204       if (doc["Energies"]) {
00205         vector< pair<double,double> > beam_energy_pairs;
00206         for (size_t i = 0; i < doc["Energies"].size(); ++i) {
00207           const YAML::Node& be = doc["Energies"][i];
00208           if (be.IsScalar()) {
00209             // If beam energy is a scalar, then assume symmetric beams each with half that energy
00210             beam_energy_pairs += make_pair(be.as<double>()/2.0, be.as<double>()/2.0);
00211           } else if (be.IsSequence()) {
00212             if (be.size() != 2)
00213               throw InfoError("Beam energies have to be a list of either numbers or pairs of numbers");
00214             beam_energy_pairs += make_pair(be[0].as<double>(), be[1].as<double>());
00215           } else {
00216             throw InfoError("Beam energies have to be a list of either numbers or pairs of numbers");
00217           }
00218         }
00219         ai->_energies = beam_energy_pairs;
00220       }
00221 
00222       #endif
00223 
00224     } catch (...) { THROW_INFOERR("Energies"); }
00225 
00226     #undef THROW_INFOERR
00227 
00228 
00229     MSG_TRACE("AnalysisInfo pointer = " << ai);
00230     return ai;
00231   }
00232 
00233 
00234   string toString(const AnalysisInfo& ai) {
00235     stringstream ss;
00236     ss << ai.name();
00237     ss << " - " << ai.summary();
00238     // ss << " - " << ai.beams();
00239     // ss << " - " << ai.energies();
00240     ss << " (" << ai.status() << ")";
00241     return ss.str();
00242   }
00243 
00244 
00245 }