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