-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add compare macro #1419
base: dev
Are you sure you want to change the base?
Add compare macro #1419
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First round of comments.
Could we please get a test for this tooling somehow?
Maybe we could integrate it in some other test by running the simulation with two seeds and then compare the results? (which should hopefully be quite the same?)
The test will be the next step. First I want to get the macro and the script in which are the prerequisites for the test. |
examples/scripts/checkfiles.sh
Outdated
simulation/Tutorial1/macros/tutorial1_TGeant4_pions.mc_p2.000_t0_n1.root | ||
simulation/Tutorial1/macros/tutorial1_TGeant4_pions.mc_p2.000_t0_n10.root | ||
simulation/Tutorial1/macros/tutorial1_pythia8_TGeant4_pions.mc_p2.000_t0_n10.root | ||
simulation/Tutorial1/macros/tutorial1_pythia6_TGeant4_pions.mc_p2.000_t0_n10.root | ||
simulation/Tutorial1/macros/tutorial1_urqmd_TGeant4.mc.root | ||
|
||
simulation/Tutorial2/macros/tutorial2_pions.mc_p2.000_t0_n10.root | ||
simulation/Tutorial2/macros/tutorial2_pions.mc_p2.000_t0_n10.sg1.root | ||
simulation/Tutorial2/macros/tutorial2_pions.mc_p2.000_t0_n20.sg2.root | ||
simulation/Tutorial2/macros/tutorial2_pions.mc_p2.000_t0_n130.bg.root | ||
#simulation/Tutorial2/macros/digis.mc.root | ||
#simulation/Tutorial2/macros/digis.mix.mc.root | ||
|
||
simulation/Tutorial4/macros/data/testrun_align_TGeant4.root | ||
simulation/Tutorial4/macros/data/testreco_align_TGeant4.root | ||
#simulation/Tutorial4/macros/data/test.ana.root | ||
|
||
simulation/rutherford/macros/data/test_TGeant4.mc.root | ||
simulation/rutherford/macros/data/test1_TGeant4.mc.root | ||
|
||
advanced/propagator/macros/prop.mc.root | ||
#advanced/propagator/macros/prop.rk.cal.root | ||
|
||
advanced/Tutorial3/macro/data/testrun_TGeant4.root | ||
advanced/Tutorial3/macro/data/testdigi_TGeant4.root | ||
advanced/Tutorial3/macro/data/testreco_TGeant4.root | ||
advanced/Tutorial3/macro/data/testDiRePr_TGeant4.root | ||
#advanced/Tutorial3/macro/data/testrecotimebased_TGeant4.root | ||
|
||
#MQ/serialization/data_io/testinput1.root | ||
#MQ/serialization/data_io/outputEx1Test.root | ||
#MQ/serialization/data_io/testinput2.root | ||
#MQ/serialization/data_io/outputEx2Test.root | ||
#MQ/pixelDetector/macros/pixel_TGeant4.mc.root | ||
#MQ/pixelDetector/macros/pixel_TGeant4.digi.root | ||
#MQ/pixelDetector/macros/pixel_TGeant4.digiToBin.root | ||
#MQ/pixelDetector/macros/MQ.pixel_TGeant4.hits.root | ||
#MQ/pixelSimSplit/run/MQ.simulation_TGeant4.data.root |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should generate this list somehow, having it hardcoded like this will be a nightmare to maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree but I am not sure if this will be so easy. For the time being it would be good if we could keep the hard coded list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An idea would be to glob for ${dir1}/**/*.root
and then iterate this list of files, if such a root file also exists in $dir2
. We may have to add then another sanity check to the TreeCompareAuto.C
macro that it will skip non-FairRoot root files, if there were any.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that not all ROOT files should be tested. Not all off them contain the tree. That means that we have to filter the list afterwards to get only the list of files we want. In my opinion this isn't better than having a fixed list.
One solution would be to provide some benchmark files you want to compare and loop over these files and compare them with the newly produced ones. The downside of this is that we have to provide the benchmark files somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another approach would be:
- Add a CMake list variable
FAIRROOT_SIMTREE_FILES_FOR_INTEGRITY_TESTING
- Append file names to it in each of the local
CMakeLists.txt
files from each example/test the file belongs to - Then
configure_file()
thischeckfiles.sh
script in a way that the contents of the CMake variable is added
Then the "authority" of naming relevant root files stays local to the individual example/test/lib. What do you think?
The macro compares the cbmsim trees of two ROOT files whose names are passed as arguments. If any difference is found the script fails. The script simply calls the macro for all relevant ROOT files which are produced when running the test suite. This allows to compare results before and after a change.
@ChristianTackeGSI, @dennisklein, thanks for all the suggestions. I hope I addressed them now all. |
4d8743c
to
86a3f4b
Compare
examples/scripts/TreeCompareAuto.C
Outdated
return 0; | ||
} | ||
|
||
TCanvas c1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TCanvas c1; |
and see following comment further down
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed to suppress a warning/info from ROOT. I add a comment and renamed the variable.
TString command1 = leafName + ">>htemp"; | ||
tree1->Draw(command1); | ||
int entries{0}; | ||
float low{0.}; | ||
float high{0.}; | ||
int nBins{0}; | ||
auto htemp = static_cast<TH1F*>(gPad->GetPrimitive("htemp")); | ||
if (htemp) { | ||
entries = htemp->GetEntries(); | ||
nBins = htemp->GetNbinsX(); | ||
low = htemp->GetXaxis()->GetXmin(); | ||
high = htemp->GetXaxis()->GetXmax(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TString command1 = leafName + ">>htemp"; | |
tree1->Draw(command1); | |
int entries{0}; | |
float low{0.}; | |
float high{0.}; | |
int nBins{0}; | |
auto htemp = static_cast<TH1F*>(gPad->GetPrimitive("htemp")); | |
if (htemp) { | |
entries = htemp->GetEntries(); | |
nBins = htemp->GetNbinsX(); | |
low = htemp->GetXaxis()->GetXmin(); | |
high = htemp->GetXaxis()->GetXmax(); | |
} | |
TH1F htemp; | |
long long entries = tree1->GetEntries(); | |
float value = 0; | |
tree1->SetBranchAddress(leafName, &value); | |
for (long long i = 0; i < entries; ++i) { | |
tree1->GetEntry(i); | |
htemp->Fill(value); | |
} | |
float low = htemp.GetXaxis()->GetXmin(); | |
float high = htemp.GetXaxis()->GetXmax(); | |
int nBins = htemp.GetNbinsX(); |
Why not something simple like this (have not tested the above code, but there should be some code similar to the above)?
What is the benefit to go through all this Draw()
logic and global referencing via gPad
?
We could also get rid of the htemp->Clear();
etc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the hist
case a bit further down, one could use a TFormula
, but since it is just a subtraction, not even needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will not work since the value can be anything and must not be a float.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then why do you cast it to a TH1F*
where the F
stands for float
? (Also, how are low
and high
then supposed to work if it is not a float?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, how are low and high then supposed to work if it is not a float?)
Btw, TAxis::GetXmax()
returns a double
?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In our case, it should rather depend on the data in the root file, should it not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can pass any number to TH1F::Fill() which will find the proper bin to increase. The type of the histogram only defines the maximum value which can be stored per bin. TH1C can only store values less than 128 per bin. TH1F stores the bin content in a float value.
These are the values you have to pass to the constructor which is the same for all types of one dimensional histograms
[in] | name | name of histogram (avoid blanks) | const char*
[in] | title | histogram title. | const char*
[in] | nbins | number of bins | int
[in] | xlow | low edge of first bin | double
[in] | xup | upper edge of last bin (not included in last bin) | double
TAxis::GetMax returns the value value of the upper edge of the last bin which is a double.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, thx, this I misunderstood. But then the common type to fill the histogram with is just double
? So, read the tree content into doubles (instead of float as I did in my suggestion)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or as a question: Which H1F
API is used by TTree::Draw
to add its stored values to the histogram?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And whatever the code looks like, my points are:
- Why do we need to involve a
TCanvas
object, aTPad
object and a function calledDraw
- all clearly graphics related entities - in a script that does not want to produce any graphics? Especially, if we have to create a randomTCanvas
object in the middle which is not used and just for some side effect? Don't you agree that this is a terrible program to write, read and maintain (source code readability AND computational complexity)? - Can we produce the histogram object without the indirection through the global object
gPad
?
Rewrite function GetLeafNames Use solution proposed by @dennisklein in FairRootGroup#1419 Fix variable names. Remove C-style casts. Use uniqe_ptr where possible. Remove fixed tree name. Use standard types instaed of ROOT types. Use references instead of pointers where possible. Remove unneeded functions. General code improvements.
86a3f4b
to
070d938
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't follow all the discussions. So please excuse, if I duplicate anything! (In that case, just write a short "dupe" and press the resolve button!)
TString command = leafName + "-" + leafName1 + ">>hist(20, -10.,10.)"; | ||
tree1->Draw(command); | ||
auto hist = static_cast<TH1F*>(gPad->GetPrimitive("hist")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we please call this histogram hdifferences
or something like that?
TKey* key; | ||
TIter keyIterator(keylist); | ||
TString treeName; | ||
int numTreeInFile{0}; | ||
while ((key = static_cast<TKey*>(keyIterator()))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be replaced by a TRangeDynCast?
Something like this maybe?
for (auto key : TRangeDynCast<TKey const>(keylist)) {
if (!key) {
continue;
}
…
}
|
||
bool operator==(TH1 const&, TH1 const&); | ||
|
||
int TreeCompareAuto(TString fileName1 = "", TString fileName2 = "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int TreeCompareAuto(TString fileName1 = "", TString fileName2 = "") | |
int TreeCompareAuto(TString fileName1, TString fileName2) |
We anyways expect non-empty arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I recently learned, ReadObj
returns an owning pointer.
if (key->ReadObj()->InheritsFrom("TTree")) { | ||
treeName = key->GetName(); | ||
std::cout << "Found TTree with name " << treeName << std::endl; | ||
numTreeInFile++; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TKey::ReadObj
returns an owning pointer (see #1461).
Maybe move this in front of the loop?
std::unique_ptr<TTree> tree1;
And then:
if (key->ReadObj()->InheritsFrom("TTree")) { | |
treeName = key->GetName(); | |
std::cout << "Found TTree with name " << treeName << std::endl; | |
numTreeInFile++; | |
} | |
tree1.reset(key->ReadObject<TTree>()); | |
if (tree1) { | |
treeName = key->GetName(); | |
std::cout << "Found TTree with name " << treeName << std::endl; | |
numTreeInFile++; | |
} |
Add a macro which allows to compare the cbmsim tree of two different ROOT macros. The added script does this comparison for all relevant ROOT files produced by the test suite. This allows to easily compare the results before and after a change of FairRoot to see if there are unexpected changes.
Checklist: