00001
00002 #include "Rivet/Rivet.hh"
00003 #include "Rivet/RivetAIDA.hh"
00004 #include "Rivet/AnalysisHandler.hh"
00005 #include "Rivet/AnalysisInfo.hh"
00006 #include "Rivet/Analysis.hh"
00007 #include "Rivet/Tools/Logging.hh"
00008 #include "LWH/AIManagedObject.h"
00009 using namespace AIDA;
00010
00011 namespace Rivet {
00012
00013
00014 Analysis::Analysis(const string& name)
00015 : _crossSection(-1.0),
00016 _gotCrossSection(false),
00017 _analysishandler(NULL),
00018 _madeHistoDir(false)
00019 {
00020 ProjectionApplier::_allowProjReg = false;
00021 _defaultname = name;
00022
00023 AnalysisInfo* ai = AnalysisInfo::make(name);
00024 assert(ai != 0);
00025 _info.reset(ai);
00026 assert(_info.get() != 0);
00027 }
00028
00029
00030 IAnalysisFactory& Analysis::analysisFactory() {
00031 return handler().analysisFactory();
00032 }
00033
00034
00035 ITree& Analysis::tree() {
00036 return handler().tree();
00037 }
00038
00039
00040 IHistogramFactory& Analysis::histogramFactory() {
00041 return handler().histogramFactory();
00042 }
00043
00044
00045 IDataPointSetFactory& Analysis::datapointsetFactory() {
00046 return handler().datapointsetFactory();
00047 }
00048
00049
00050 double Analysis::sqrtS() const {
00051 return handler().sqrtS();
00052 }
00053
00054 const ParticlePair& Analysis::beams() const {
00055 return handler().beams();
00056 }
00057
00058 const PdgIdPair Analysis::beamIds() const {
00059 return handler().beamIds();
00060 }
00061
00062
00063 const string Analysis::histoDir() const {
00064
00065 string path = "/" + name();
00066 if (handler().runName().length() > 0) {
00067 path = "/" + handler().runName() + path;
00068 }
00069 while (find_first(path, "//")) {
00070 replace_all(path, "//", "/");
00071 }
00072 return path;
00073 }
00074
00075
00076 const string Analysis::histoPath(const string& hname) const {
00077 const string path = histoDir() + "/" + hname;
00078 return path;
00079 }
00080
00081
00082 const string Analysis::makeAxisCode(size_t datasetId, size_t xAxisId, size_t yAxisId) const {
00083 stringstream axisCode;
00084 axisCode << "d";
00085 if (datasetId < 10) axisCode << 0;
00086 axisCode << datasetId;
00087 axisCode << "-x";
00088 if (xAxisId < 10) axisCode << 0;
00089 axisCode << xAxisId;
00090 axisCode << "-y";
00091 if (yAxisId < 10) axisCode << 0;
00092 axisCode << yAxisId;
00093 return axisCode.str();
00094 }
00095
00096
00097 Log& Analysis::getLog() const {
00098 string logname = "Rivet.Analysis." + name();
00099 return Log::getLog(logname);
00100 }
00101
00102
00103 size_t Analysis::numEvents() const {
00104 return handler().numEvents();
00105 }
00106
00107
00108 double Analysis::sumOfWeights() const {
00109 return handler().sumOfWeights();
00110 }
00111
00112
00113
00114
00115
00116 bool Analysis::isCompatible(const ParticlePair& beams) const {
00117 return isCompatible(beams.first.pdgId(), beams.second.pdgId(),
00118 beams.first.energy(), beams.second.energy());
00119 }
00120
00121
00122 bool Analysis::isCompatible(PdgId beam1, PdgId beam2, double e1, double e2) const {
00123 PdgIdPair beams(beam1, beam2);
00124 pair<double,double> energies(e1, e2);
00125 return isCompatible(beams, energies);
00126 }
00127
00128
00129 bool Analysis::isCompatible(const PdgIdPair& beams, const pair<double,double>& energies) const {
00130
00131 bool beamIdsOk = false;
00132 foreach (const PdgIdPair& bp, requiredBeams()) {
00133 if (compatible(beams, bp)) {
00134 beamIdsOk = true;
00135 break;
00136 }
00137 }
00138 if (!beamIdsOk) return false;
00139
00140
00141 bool beamEnergiesOk = requiredEnergies().size()>0 ? false : true;
00142 typedef pair<double,double> DoublePair;
00143 foreach (const DoublePair& ep, requiredEnergies()) {
00144 if ((fuzzyEquals(ep.first, energies.first, 0.01) && fuzzyEquals(ep.second, energies.second, 0.01)) ||
00145 (fuzzyEquals(ep.first, energies.second, 0.01) && fuzzyEquals(ep.second, energies.first, 0.01))) {
00146 beamEnergiesOk = true;
00147 break;
00148 }
00149 }
00150 return beamEnergiesOk;
00151
00152
00153
00154 }
00155
00156
00157
00158
00159
00160 Analysis& Analysis::setCrossSection(double xs) {
00161 _crossSection = xs;
00162 _gotCrossSection = true;
00163 return *this;
00164 }
00165
00166 double Analysis::crossSection() const {
00167 if (!_gotCrossSection || std::isnan(_crossSection)) {
00168 string errMsg = "You did not set the cross section for the analysis " + name();
00169 throw Error(errMsg);
00170 }
00171 return _crossSection;
00172 }
00173
00174 double Analysis::crossSectionPerEvent() const {
00175 const double sumW = sumOfWeights();
00176 assert(sumW != 0.0);
00177 return _crossSection / sumW;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186 void Analysis::_cacheBinEdges() const {
00187 _cacheXAxisData();
00188 if (_histBinEdges.empty()) {
00189 MSG_TRACE("Getting histo bin edges from AIDA for paper " << name());
00190 _histBinEdges = getBinEdges(_dpsData);
00191 }
00192 }
00193
00194
00195 void Analysis::_cacheXAxisData() const {
00196 if (_dpsData.empty()) {
00197 MSG_TRACE("Getting DPS x-axis data from AIDA for paper " << name());
00198 _dpsData = getDPSXValsErrs(name());
00199 }
00200 }
00201
00202
00203 const BinEdges& Analysis::binEdges(const string& hname) const {
00204 _cacheBinEdges();
00205 MSG_TRACE("Using histo bin edges for " << name() << ":" << hname);
00206 const BinEdges& edges = _histBinEdges.find(hname)->second;
00207 if (getLog().isActive(Log::TRACE)) {
00208 stringstream edges_ss;
00209 foreach (const double be, edges) {
00210 edges_ss << " " << be;
00211 }
00212 MSG_TRACE("Edges:" << edges_ss.str());
00213 }
00214 return edges;
00215 }
00216
00217
00218 const BinEdges& Analysis::binEdges(size_t datasetId, size_t xAxisId, size_t yAxisId) const {
00219 const string hname = makeAxisCode(datasetId, xAxisId, yAxisId);
00220 return binEdges(hname);
00221 }
00222
00223
00224 BinEdges Analysis::logBinEdges(size_t nbins, double lower, double upper) {
00225 assert(lower>0.0);
00226 assert(upper>lower);
00227 double loglower=log10(lower);
00228 double logupper=log10(upper);
00229 vector<double> binedges;
00230 double stepwidth=(logupper-loglower)/double(nbins);
00231 for (size_t i=0; i<=nbins; ++i) {
00232 binedges.push_back(pow(10.0, loglower+double(i)*stepwidth));
00233 }
00234 return binedges;
00235 }
00236
00237 IHistogram1D* Analysis::bookHistogram1D(size_t datasetId, size_t xAxisId,
00238 size_t yAxisId, const string& title,
00239 const string& xtitle, const string& ytitle)
00240 {
00241 const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId);
00242 return bookHistogram1D(axisCode, title, xtitle, ytitle);
00243 }
00244
00245
00246 IHistogram1D* Analysis::bookHistogram1D(const string& hname, const string& title,
00247 const string& xtitle, const string& ytitle)
00248 {
00249
00250 const BinEdges edges = binEdges(hname);
00251 _makeHistoDir();
00252 const string path = histoPath(hname);
00253 if (path.find(" ") != string::npos) {
00254 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00255 }
00256 IHistogram1D* hist = histogramFactory().createHistogram1D(path, title, edges);
00257 MSG_TRACE("Made histogram " << hname << " for " << name());
00258 hist->setXTitle(xtitle);
00259 hist->setYTitle(ytitle);
00260 return hist;
00261 }
00262
00263
00264 IHistogram1D* Analysis::bookHistogram1D(const string& hname,
00265 size_t nbins, double lower, double upper,
00266 const string& title,
00267 const string& xtitle, const string& ytitle) {
00268 _makeHistoDir();
00269 const string path = histoPath(hname);
00270 if (path.find(" ") != string::npos) {
00271 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00272 }
00273 IHistogram1D* hist = histogramFactory().createHistogram1D(path, title, nbins, lower, upper);
00274 MSG_TRACE("Made histogram " << hname << " for " << name());
00275 hist->setXTitle(xtitle);
00276 hist->setYTitle(ytitle);
00277 return hist;
00278 }
00279
00280
00281 IHistogram1D* Analysis::bookHistogram1D(const string& hname,
00282 const vector<double>& binedges,
00283 const string& title,
00284 const string& xtitle, const string& ytitle) {
00285 _makeHistoDir();
00286 const string path = histoPath(hname);
00287 if (path.find(" ") != string::npos) {
00288 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00289 }
00290 IHistogram1D* hist = histogramFactory().createHistogram1D(path, title, binedges);
00291 MSG_TRACE("Made histogram " << hname << " for " << name());
00292 hist->setXTitle(xtitle);
00293 hist->setYTitle(ytitle);
00294 return hist;
00295 }
00296
00297 IHistogram2D*
00298 Analysis::bookHistogram2D(const string& hname,
00299 size_t nxbins, double xlower, double xupper,
00300 size_t nybins, double ylower, double yupper,
00301 const string& title, const string& xtitle,
00302 const string& ytitle, const string& ztitle) {
00303 _makeHistoDir();
00304 const string path = histoPath(hname);
00305 if (path.find(" ") != string::npos) {
00306 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00307 }
00308 IHistogram2D* hist =
00309 histogramFactory().createHistogram2D(path, title, nxbins, xlower, xupper,
00310 nybins, ylower, yupper);
00311 MSG_TRACE("Made 2D histogram " << hname << " for " << name());
00312 hist->setXTitle(xtitle);
00313 hist->setYTitle(ytitle);
00314 hist->setZTitle(ztitle);
00315 return hist;
00316 }
00317
00318
00319 IHistogram2D*
00320 Analysis::bookHistogram2D(const string& hname,
00321 const vector<double>& xbinedges,
00322 const vector<double>& ybinedges,
00323 const string& title, const string& xtitle,
00324 const string& ytitle, const string& ztitle) {
00325 _makeHistoDir();
00326 const string path = histoPath(hname);
00327 if (path.find(" ") != string::npos) {
00328 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00329 }
00330 IHistogram2D* hist =
00331 histogramFactory().createHistogram2D(path, title, xbinedges, ybinedges);
00332 MSG_TRACE("Made 2D histogram " << hname << " for " << name());
00333 hist->setXTitle(xtitle);
00334 hist->setYTitle(ytitle);
00335 hist->setZTitle(ztitle);
00336 return hist;
00337 }
00338
00339
00340
00341
00342
00343 IProfile1D* Analysis::bookProfile1D(size_t datasetId, size_t xAxisId,
00344 size_t yAxisId, const string& title,
00345 const string& xtitle, const string& ytitle) {
00346 const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId);
00347 return bookProfile1D(axisCode, title, xtitle, ytitle);
00348 }
00349
00350
00351 IProfile1D* Analysis::bookProfile1D(const string& hname, const string& title,
00352 const string& xtitle, const string& ytitle)
00353 {
00354
00355 const BinEdges edges = binEdges(hname);
00356 _makeHistoDir();
00357 const string path = histoPath(hname);
00358 if (path.find(" ") != string::npos) {
00359 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00360 }
00361 IProfile1D* prof = histogramFactory().createProfile1D(path, title, edges);
00362 MSG_TRACE("Made profile histogram " << hname << " for " << name());
00363 prof->setXTitle(xtitle);
00364 prof->setYTitle(ytitle);
00365 return prof;
00366 }
00367
00368
00369 IProfile1D* Analysis::bookProfile1D(const string& hname,
00370 size_t nbins, double lower, double upper,
00371 const string& title,
00372 const string& xtitle, const string& ytitle) {
00373 _makeHistoDir();
00374 const string path = histoPath(hname);
00375 if (path.find(" ") != string::npos) {
00376 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00377 }
00378 IProfile1D* prof = histogramFactory().createProfile1D(path, title, nbins, lower, upper);
00379 MSG_TRACE("Made profile histogram " << hname << " for " << name());
00380 prof->setXTitle(xtitle);
00381 prof->setYTitle(ytitle);
00382 return prof;
00383 }
00384
00385
00386 IProfile1D* Analysis::bookProfile1D(const string& hname,
00387 const vector<double>& binedges,
00388 const string& title,
00389 const string& xtitle, const string& ytitle) {
00390 _makeHistoDir();
00391 const string path = histoPath(hname);
00392 if (path.find(" ") != string::npos) {
00393 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00394 }
00395 IProfile1D* prof = histogramFactory().createProfile1D(path, title, binedges);
00396 MSG_TRACE("Made profile histogram " << hname << " for " << name());
00397 prof->setXTitle(xtitle);
00398 prof->setYTitle(ytitle);
00399 return prof;
00400 }
00401
00402
00403
00404
00405
00406
00407 IDataPointSet* Analysis::bookDataPointSet(const string& hname, const string& title,
00408 const string& xtitle, const string& ytitle) {
00409 _makeHistoDir();
00410 const string path = histoPath(hname);
00411 if (path.find(" ") != string::npos) {
00412 throw Error("Histogram path '" + path + "' is invalid: spaces are not permitted in paths");
00413 }
00414 IDataPointSet* dps = datapointsetFactory().create(path, title, 2);
00415 MSG_TRACE("Made data point set " << hname << " for " << name());
00416 dps->setXTitle(xtitle);
00417 dps->setYTitle(ytitle);
00418 return dps;
00419 }
00420
00421
00422 IDataPointSet* Analysis::bookDataPointSet(const string& hname,
00423 size_t npts, double lower, double upper,
00424 const string& title,
00425 const string& xtitle, const string& ytitle) {
00426 IDataPointSet* dps = bookDataPointSet(hname, title, xtitle, ytitle);
00427 for (size_t pt = 0; pt < npts; ++pt) {
00428 const double binwidth = (upper-lower)/npts;
00429 const double bincentre = lower + (pt + 0.5) * binwidth;
00430 dps->addPoint();
00431 IMeasurement* meas = dps->point(pt)->coordinate(0);
00432 meas->setValue(bincentre);
00433 meas->setErrorPlus(binwidth/2.0);
00434 meas->setErrorMinus(binwidth/2.0);
00435 }
00436 return dps;
00437 }
00438
00439
00440 IDataPointSet* Analysis::bookDataPointSet(size_t datasetId, size_t xAxisId,
00441 size_t yAxisId, const string& title,
00442 const string& xtitle, const string& ytitle) {
00443
00444 _cacheXAxisData();
00445
00446 const string axisCode = makeAxisCode(datasetId, xAxisId, yAxisId);
00447
00448 MSG_TRACE("Using DPS x-positions for " << name() << ":" << axisCode);
00449 IDataPointSet* dps = bookDataPointSet(axisCode, title, xtitle, ytitle);
00450 const vector<DPSXPoint> xpts = _dpsData.find(axisCode)->second;
00451 for (size_t pt = 0; pt < xpts.size(); ++pt) {
00452 dps->addPoint();
00453 IMeasurement* meas = dps->point(pt)->coordinate(0);
00454 meas->setValue(xpts[pt].val);
00455 meas->setErrorPlus(xpts[pt].errplus);
00456 meas->setErrorMinus(xpts[pt].errminus);
00457 }
00458 MSG_TRACE("Made DPS " << axisCode << " for " << name());
00459 return dps;
00460 }
00461
00462
00463
00464
00465
00466 void Analysis::_makeHistoDir() {
00467 if (!_madeHistoDir) {
00468 if (! name().empty()) {
00469
00470
00471
00472
00473
00474
00475 tree().mkdirs(histoDir());
00476 }
00477 _madeHistoDir = true;
00478 }
00479 }
00480
00481
00482 void Analysis::normalize(AIDA::IHistogram1D*& histo, double norm) {
00483 if (!histo) {
00484 MSG_ERROR("Failed to normalize histo=NULL in analysis "
00485 << name() << " (norm=" << norm << ")");
00486 return;
00487 }
00488 const string hpath = tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00489 MSG_TRACE("Normalizing histo " << hpath << " to " << norm);
00490
00491 double oldintg = 0.0;
00492 int nBins = histo->axis().bins();
00493 for (int iBin = 0; iBin != nBins; ++iBin) {
00494
00495 oldintg += histo->binHeight(iBin);
00496 }
00497 if (oldintg == 0.0) {
00498 MSG_WARNING("Histo " << hpath << " has null integral during normalization");
00499 return;
00500 }
00501
00502
00503 scale(histo, norm/oldintg);
00504 }
00505
00506
00507 void Analysis::scale(AIDA::IHistogram1D*& histo, double scale) {
00508 if (!histo) {
00509 MSG_ERROR("Failed to scale histo=NULL in analysis "
00510 << name() << " (scale=" << scale << ")");
00511 return;
00512 }
00513 const string hpath = tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00514 MSG_TRACE("Scaling histo " << hpath);
00515
00516 vector<double> x, y, ex, ey;
00517 for (size_t i = 0, N = histo->axis().bins(); i < N; ++i) {
00518 x.push_back(0.5 * (histo->axis().binLowerEdge(i) + histo->axis().binUpperEdge(i)));
00519 ex.push_back(histo->axis().binWidth(i)*0.5);
00520
00521
00522
00523 y.push_back(histo->binHeight(i)*scale/histo->axis().binWidth(i));
00524
00525
00526
00527 ey.push_back(histo->binError(i)*scale/histo->axis().binWidth(i));
00528 }
00529
00530 string title = histo->title();
00531 string xtitle = histo->xtitle();
00532 string ytitle = histo->ytitle();
00533
00534 tree().mkdir("/tmpnormalize");
00535 tree().mv(hpath, "/tmpnormalize");
00536
00537 if (hpath.find(" ") != string::npos) {
00538 throw Error("Histogram path '" + hpath + "' is invalid: spaces are not permitted in paths");
00539 }
00540 AIDA::IDataPointSet* dps = datapointsetFactory().createXY(hpath, title, x, y, ex, ey);
00541 dps->setXTitle(xtitle);
00542 dps->setYTitle(ytitle);
00543
00544 tree().rm(tree().findPath(dynamic_cast<AIDA::IManagedObject&>(*histo)));
00545 tree().rmdir("/tmpnormalize");
00546
00547
00548 histo = 0;
00549 }
00550
00551
00552 void Analysis::normalize(AIDA::IHistogram2D*& histo, double norm) {
00553 if (!histo) {
00554 MSG_ERROR("Failed to normalize histo=NULL in analysis "
00555 << name() << " (norm=" << norm << ")");
00556 return;
00557 }
00558 const string hpath = tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00559 MSG_TRACE("Normalizing histo " << hpath << " to " << norm);
00560
00561 double oldintg = 0.0;
00562 int nxBins = histo->xAxis().bins();
00563 int nyBins = histo->yAxis().bins();
00564 for (int ixBin = 0; ixBin != nxBins; ++ixBin)
00565 for (int iyBin = 0; iyBin != nyBins; ++iyBin) {
00566
00567
00568 oldintg += histo->binHeight(ixBin, iyBin);
00569 }
00570 if (oldintg == 0.0) {
00571 MSG_WARNING("Histo " << hpath << " has null integral during normalization");
00572 return;
00573 }
00574
00575
00576 scale(histo, norm/oldintg);
00577 }
00578
00579
00580 void Analysis::scale(AIDA::IHistogram2D*& histo, double scale) {
00581 if (!histo) {
00582 MSG_ERROR("Failed to scale histo=NULL in analysis "
00583 << name() << " (scale=" << scale << ")");
00584 return;
00585 }
00586 const string hpath =
00587 tree().findPath(dynamic_cast<const AIDA::IManagedObject&>(*histo));
00588 MSG_TRACE("Scaling histo " << hpath);
00589
00590 vector<double> x, y, z, ex, ey, ez;
00591 for (size_t ix = 0, Nx = histo->xAxis().bins(); ix < Nx; ++ix)
00592 for (size_t iy = 0, Ny = histo->yAxis().bins(); iy < Ny; ++iy) {
00593 x.push_back(0.5 * (histo->xAxis().binLowerEdge(ix) +
00594 histo->xAxis().binUpperEdge(ix)));
00595 ex.push_back(histo->xAxis().binWidth(ix)*0.5);
00596 y.push_back(0.5 * (histo->yAxis().binLowerEdge(iy) +
00597 histo->yAxis().binUpperEdge(iy)));
00598 ey.push_back(histo->yAxis().binWidth(iy)*0.5);
00599
00600
00601
00602 z.push_back(histo->binHeight(ix, iy)*scale/
00603 (histo->xAxis().binWidth(ix)*histo->yAxis().binWidth(iy)));
00604
00605
00606 ez.push_back(histo->binError(ix, iy)*scale/
00607 (histo->xAxis().binWidth(ix)*histo->yAxis().binWidth(iy)));
00608 }
00609
00610 string title = histo->title();
00611 string xtitle = histo->xtitle();
00612 string ytitle = histo->ytitle();
00613 string ztitle = histo->ztitle();
00614
00615 tree().mkdir("/tmpnormalize");
00616 tree().mv(hpath, "/tmpnormalize");
00617
00618 if (hpath.find(" ") != string::npos) {
00619 throw Error("Histogram path '" + hpath + "' is invalid: spaces are not permitted in paths");
00620 }
00621 AIDA::IDataPointSet* dps =
00622 datapointsetFactory().createXYZ(hpath, title, x, y, z, ex, ey, ez);
00623 dps->setXTitle(xtitle);
00624 dps->setYTitle(ytitle);
00625 dps->setZTitle(ztitle);
00626
00627 tree().rm(tree().findPath(dynamic_cast<AIDA::IManagedObject&>(*histo)));
00628 tree().rmdir("/tmpnormalize");
00629
00630
00631 histo = 0;
00632 }
00633
00634
00635 }