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