21#include "ResultEvent.hh"
22#include "ResultEventTree.hh"
23#include "ResultHistogram.hh"
24#include "ResultHistogram2D.hh"
25#include "ResultSampler.hh"
26#include "ResultTree.hh"
28#include "analysis/Event.hh"
29#include "analysis/Model.hh"
30#include "analysis/Options.hh"
33#include "BDSOutputROOTEventOptions.hh"
34#include "BDSOutputROOTEventSampler.hh"
35#include "BDSVersionData.hh"
47#include "TDirectory.h"
55 std::vector<Result*> results;
63 std::vector<Result*>& results)
66 TDirectory* originalDirectory = TDirectory::CurrentDirectory();
71 TList* d1k = d1->GetListOfKeys();
72 for (
int i = 0; i < d1k->GetEntries(); ++i)
74 TObject* keyObject = d1k->At(i);
75 TObject* d1o = d1->Get(keyObject->GetName());
77 std::string objectName = std::string(keyObject->GetName());
78 std::string className = std::string(d1o->ClassName());
81 if (objectName ==
"Options" && className ==
"TTree")
83 std::vector<const char*> names;
84 TTree* options = (TTree*) d1->Get(objectName.c_str());
92 if (className ==
"TDirectory" || className ==
"TDirectoryFile")
94 TDirectory* subD1 = (TDirectory*)d1->Get(objectName.c_str());
95 TDirectory* subD2 = (TDirectory*)d2->Get(objectName.c_str());
103 else if(className ==
"TH1D")
105 TH1* d1h = (TH1*)d1->Get(objectName.c_str());
106 TH1* d2h = (TH1*)d2->Get(objectName.c_str());
114 else if(className ==
"TTree")
116 TTree* d1t = (TTree*)d1->Get(objectName.c_str());
117 TTree* d2t = (TTree*)d2->Get(objectName.c_str());
127 std::cout <<
"No comparison written for object named " << objectName
128 <<
" of type " << className << std::endl;
131 originalDirectory->cd();
138 c->
name = h1->GetName();
139 c->tolerance = Compare::Chi2Tolerance;
141 c->h1Entries = h1->GetEntries();
142 c->h2Entries = h2->GetEntries();
143 c->h1NXBins = h1->GetNbinsX();
144 c->h2NXBins = h2->GetNbinsX();
145 c->h1XMean = h1->GetMean();
146 c->h2XMean = h2->GetMean();
147 c->h1XRms = h1->GetRMS();
148 c->h2XRms = h2->GetRMS();
149 c->h1Integral= h1->Integral();
150 c->h2Integral= h2->Integral();
153 if (c->h1NXBins != c->h2NXBins)
156 results.push_back(c);
162 for (
int i=0;i < h1->GetNbinsX(); i++)
165 if (h1->GetBinError(i) > 0)
167 c->chi2 += std::pow(h1->GetBinContent(i)-h2->GetBinContent(i),2)/(std::pow(h1->GetBinError(i),2)+std::pow(h2->GetBinError(i),2));
172 if (!std::isnormal(ndof))
177 if(c->chi2 > Compare::Chi2Tolerance)
180 results.push_back(c);
185 std::vector<std::string> treesToIgnore = {
"Header",
"Model",
"Options",
"Run",
"Beam",
"ParticleData"};
188 std::string treeName = t1->GetName();
189 if (std::find(treesToIgnore.begin(), treesToIgnore.end(), treeName) != treesToIgnore.end())
191 else if (!strcmp(treeName.c_str(),
"Optics"))
196 else if (!strcmp(treeName.c_str(),
"Event"))
200 TDirectory* dir = t1->GetDirectory();
202 std::vector<std::string> samplerNames;
203 std::vector<std::string> samplerCNames;
204 std::vector<std::string> samplerSNames;
206 TTree* modTree =
dynamic_cast<TTree*
>(dir->Get(
"Model"));
210 else if (modTree->GetEntries() == 0)
216 modTree->GetEntry(0);
218 samplerCNames = mod->SamplerCNames();
219 samplerSNames = mod->SamplerSNames();
223 {std::cout <<
"Model not stored so can't compare sampler branches." << std::endl;}
224 Compare::EventTree(t1, t2, results, samplerNames, samplerCNames, samplerSNames);
231 c->t1NEntries = (int)t1->GetEntries();
232 c->t2NEntries = (int)t2->GetEntries();
234 TObjArray* oa1 = t1->GetListOfBranches();
235 TObjArray* oa2 = t2->GetListOfBranches();
237 for(
int j = 0; j<oa1->GetSize(); ++j)
239 bool branchFailed =
false;
240 TBranch* b1 = (TBranch*)((*oa1)[j]);
241 TBranch* b2 = (TBranch*)((*oa2)[j]);
244 b1->SetAddress(&t1v);
245 b2->SetAddress(&t2v);
246 for(
int i = 0; i<t1->GetEntries(); ++i)
251 if(std::abs((t1v - t2v )/t1v) > Compare::TreeTolerance)
260 {c->offendingBranches.emplace_back(std::string(b2->GetName()));}
262 results.push_back(c);
268 c->
name = t1->GetName();
271 c->t1NEntries = (int)t1->GetEntries();
272 c->t2NEntries = (int)t2->GetEntries();
275 std::map<std::string, bool> positiveValues = {
299 std::vector<std::string> errorBranches = {
300 "Sigma_Emitt_x",
"Sigma_Emitt_y",
301 "Sigma_Alpha_x",
"Sigma_Alpha_y",
302 "Sigma_Beta_x",
"Sigma_Beta_y",
303 "Sigma_Gamma_x",
"Sigma_Gamma_y",
304 "Sigma_Disp_x",
"Sigma_Disp_y",
305 "Sigma_Disp_xp",
"Sigma_Disp_yp",
306 "Sigma_Mean_x",
"Sigma_Mean_y",
307 "Sigma_Sigma_x",
"Sigma_Sigma_y",
308 "Sigma_Sigma_xp",
"Sigma_Sigma_yp",
309 "Sigma_Mean_E",
"Sigma_Sigma_E",
310 "Sigma_Mean_t",
"Sigma_Sigma_t"
313 TObjArray *oa1 = t1->GetListOfBranches();
317 for (
int j = 0; j< oa1->GetSize(); ++j)
319 TBranch* b1 = (TBranch*)(*oa1)[j];
320 std::string branchName = std::string(b1->GetName());
322 bool branchFailed =
false;
323 bool shouldBeGTEZero =
false;
330 if (Compare::IsInVector(branchName, errorBranches))
333 b1->SetAddress(&t1v);
334 for(
int i = 0; i<t1->GetEntries(); ++i)
338 if (LTZero(t1v) || NanOrInf(t1v))
348 shouldBeGTEZero = positiveValues[branchName];
350 std::string errBranchName =
"Sigma_" + branchName;
352 TBranch* b1err = t1->GetBranch(errBranchName.c_str());
353 TBranch* b2err = t2->GetBranch(errBranchName.c_str());
354 if (!b1err || !b2err)
357 TBranch* b2 = t2->GetBranch(branchName.c_str());
364 b1->SetAddress(&t1v);
365 b1err->SetAddress(&t1e);
366 b2->SetAddress(&t2v);
367 b2err->SetAddress(&t2e);
370 for(
int i = 0; i<t1->GetEntries(); ++i)
375 if (!std::isnormal(t1e) || !std::isnormal(t2e))
380 bool valueIsGood =
true;
383 if (!GTEZero(t1v) || !GTEZero(t2v))
384 {valueIsGood =
false;}
386 if (NanOrInf(t1v) || NanOrInf(t2v) || !valueIsGood)
389 std::cout <<
"Invalid value found for branch \"" << branchName <<
"\"" << G4endl;
390 std::cout << t1v <<
" " << t2v <<
" " << t1e <<
" " << t2e <<
" " << std::endl;
395 double chi2 = std::pow(t1v - t2v, 2) / (std::pow(t1e,2) + std::pow(t2e,2));
397 branchFailed = chi2 > Compare::OpticsSimgaTolerance;
401 std::cout << t1v <<
" " << t2v <<
" " << t1e <<
" "
402 << t2e <<
" " << chi2 << std::endl;
411 std::cout <<
"Branch was " << branchName << std::endl << std::endl;
412 c->offendingBranches.push_back(branchName);
416 results.push_back(c);
419void Compare::EventTree(TTree* t1, TTree* t2, std::vector<Result*>& results,
420 const std::vector<std::string>& samplerNames,
421 const std::vector<std::string>& samplerCNames,
422 const std::vector<std::string>& samplerSNames)
425 ret->
name = t1->GetName();
428 ret->t1NEntries = (int)t1->GetEntries();
429 ret->t2NEntries = (int)t2->GetEntries();
433 if (ret->t1NEntries != ret->t2NEntries)
436 results.push_back(ret);
441 G4bool processSamplers = !samplerNames.empty();
442 Event* evtLocal1 =
new Event(
false, processSamplers, BDSIM_DATA_VERSION);
443 Event* evtLocal2 =
new Event(
false, processSamplers, BDSIM_DATA_VERSION);
444 evtLocal1->
SetBranchAddress(t1, &samplerNames,
false,
nullptr,
nullptr, &samplerCNames, &samplerSNames);
445 evtLocal2->
SetBranchAddress(t2, &samplerNames,
false,
nullptr,
nullptr, &samplerCNames, &samplerSNames);
447 for (
long int i = 0; i < (
long int)t1->GetEntries(); i++)
450 re.
name = std::to_string(i);
452 re.
objtype =
"Event of Event Tree";
455 Int_t bytesLoaded1 = t1->GetEntry(i);
456 Int_t bytesLoaded2 = t2->GetEntry(i);
457 std::cout <<
"Bytes loaded (1) " << bytesLoaded1 << std::endl;
458 std::cout <<
"Bytes loaded (2) " << bytesLoaded2 << std::endl;
461 std::cout << evtLocal1 <<
" " << evtLocal2 << std::endl;
470 for (
auto j = 0; j < (int)evtLocal1->
Samplers.size(); j++)
475 ret->eventResults.push_back(re);
482 results.push_back(ret);
498 std::string samplerName = e1->samplerName;
499 if (samplerName ==
"sampler")
500 {samplerName = e2->samplerName;}
504 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"n");}
508 if (
Diff(e1->z, e2->z))
509 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"z");}
510 if (
Diff(e1->S, e2->S))
511 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"S");}
513 for (
int i = 0; i < e1->n; i++)
515 if (
Diff(e1->energy, e2->energy, i))
516 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"energy");}
517 if (
Diff(e1->x, e2->x, i))
518 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"x");}
519 if (
Diff(e1->y, e2->y, i))
520 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"y");}
521 if (
Diff(e1->xp, e2->xp, i))
522 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"xp");}
523 if (
Diff(e1->yp, e2->yp, i))
524 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"yp");}
525 if (
Diff(e1->zp, e2->zp, i))
526 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"zp");}
527 if (
Diff(e1->p, e2->p, i))
528 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"p");}
529 if (
Diff(e1->T, e2->T, i))
530 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"T");}
531 if (
Diff(e1->partID, e2->partID, i))
532 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"partID");}
534 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"charge");}
536 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"isIon");}
538 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"ionA");}
540 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"ionZ");}
542 {rs.passed =
false; rs.offendingLeaves.emplace_back(
"nElectrons");}
548 {re->
passed =
false; re->offendingBranches.push_back(samplerName);}
549 re->samplerResults.push_back(rs);
554 bool allPassed =
true;
555 const int titleWidth = 20;
556 const int fullWidth = titleWidth + 22;
557 std::cout << std::endl;
558 std::cout <<
"N results: " << results.size() << std::endl;
559 std::cout <<
"Comparison: " << std::setw(titleWidth) <<
"Object Name" <<
" "
560 <<
"Result" << std::endl;
561 std::cout << std::setfill(
'-') << std::setw(fullWidth) <<
" " << std::endl;
562 std::cout << std::setfill(
' ');
563 for (
const auto& result : results)
565 if (!(result->passed))
568 std::cout << *result << std::endl;
571 {std::cout <<
"Comparison: " << std::setw(20) << result->name <<
" : Passed" << std::endl;}
578 std::cout <<
"Comparison file has no " << className <<
" called " << objectName <<
". Skipping" << std::endl;
585 if (aString.compare(0, prefix.length(), prefix) == 0)
590 catch(
const std::out_of_range&)
595bool Compare::IsInVector(std::string key,
const std::vector<std::string>& vec)
597 return std::find(vec.begin(), vec.end(), key) != vec.end();
Information stored per sampler per event.
std::vector< bool > isIon
These are not filled by default.
std::vector< int > nElectrons
These are not filled by default.
std::vector< int > ionA
These are not filled by default.
std::vector< int > charge
These are not filled by default.
std::vector< int > ionZ
These are not filled by default.
BDSOutputROOTEventSampler< double > * GetPrimaries()
Accessor.
std::vector< BDSOutputROOTEventSampler< double > * > Samplers
Local variable ROOT data is mapped to.
void SetBranchAddress(TTree *t, const RBDS::VectorString *samplerNames=nullptr, bool allBranchesOn=false, const RBDS::VectorString *branchesToTurnOn=nullptr, const RBDS::VectorString *collimatorNamesIn=nullptr, const RBDS::VectorString *samplerCNamesIn=nullptr, const RBDS::VectorString *samplerSNamesIn=nullptr)
void SetBranchAddress(TTree *t, bool allBranchesOn=true, const RBDS::VectorString *branchesToTurnOn=nullptr)
Set the branch addresses to address the contents of the file.
std::vector< std::string > SamplerNames() const
Access all the unique sampler names from the model.
void SetBranchAddress(TTree *t, bool allBranchesOn=true, const RBDS::VectorString *branchesToTurnOn=nullptr)
Set the branch addresses to address the contents of the file.
BDSOutputROOTEventOptions * options
Member that ROOT can map file data to locally.
Result of comparison of all entries in an Event tree in BDSIM output.
Result of comparison of single entry of an Event tree in BDSIM output.
Result of comparing 2 histograms.
Result of comparison of a sampler branch.
Result of comparing 2 TTrees.
std::string name
Name of object being compared in files.
bool passed
Whether it passed or not.
std::string objtype
Name of class of object being compared in files.
std::vector< Result * > Files(TFile *f1, TFile *f2)
Compare two files.
void Trees(TTree *t1, TTree *t2, std::vector< Result * > &results)
Compare two TTrees.
bool Summarise(const std::vector< Result * > &results)
Loop over results and print any failed ones. Returns true if all passed.
bool Diff(const std::vector< T > &v1, std::vector< T > &v2, int i)
Return true if they're different.
bool hasPrimaries
Bool for checking if primaries were written to file.
void PrintNoMatching(std::string className, std::string objectName)
void Histograms(TH1 *h1, TH1 *h2, std::vector< Result * > &results)
Compare two histogams.
void Directories(TDirectory *d1, TDirectory *d2, std::vector< Result * > &results)
void Optics(TTree *t1, TTree *t2, std::vector< Result * > &results)
bool StringStartsWith(std::string aString, std::string prefix)
Check whether a string is prefixed with another string.