#include "QFramework/TQStringUtils.h"
#include "QFramework/TQSample.h"
#include "QFramework/TQUtils.h"
#include "QFramework/TQIterator.h"
#include "QFramework/TQToken.h"
#include "TFile.h"
#include "definitions.h"
#include "QFramework/TQLibrary.h"
#ifdef HAS_XAOD
#define XAOD_STANDALONE 1
#include "TChain.h"
#include "xAODRootAccessInterfaces/TActiveEvent.h"
#include "xAODRootAccess/TEvent.h"
#include "xAODRootAccessInterfaces/TVirtualEvent.h"
#include "xAODRootAccess/MakeTransientTree.h"
bool TQSample::gUseTransientTree(true);
#else
bool TQSample::gUseTransientTree(false);
#endif
bool TQSample::gUseAthenaAccessMode(false);
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
ClassImp(TQSample)
TList * TQSample::splitTreeLocations(TString treeLocations) {
TList * list = 0;
while (!treeLocations.IsNull()) {
TString location;
TQStringUtils::readUpTo(treeLocations, location, "<");
TQStringUtils::readBlanks(treeLocations);
if (TQStringUtils::removeLeading(treeLocations, "<", 2) != 1) {
if (!list) {
list = new TList();
list->SetOwner(true);
}
list->Add(new TObjString(TQStringUtils::trim(location).Data()));
} else {
if (list)
delete list;
return 0;
}
}
return list;
}
TQFolder * TQSample::newInstance(const TString& name) {
TQSample* newSample = new TQSample(name.IsNull() ? this->GetName() : name.Data());
newSample->fTreeLocation = this->fTreeLocation;
newSample->fNormalisation = this->fNormalisation;
return newSample;
}
TString TQSample::extractFilename(const TString& treeLocation) {
int pos = treeLocation.Last(':');
if (pos != kNPOS) {
return treeLocation(0, pos);
} else {
return TString("");
}
}
TString TQSample::extractTreename(const TString& treeLocation) {
int pos = treeLocation.Last(':');
if (pos != kNPOS) {
return treeLocation(pos + 1, treeLocation.Length());
} else {
return treeLocation;
}
}
TQSample::TQSample() : TQSampleFolder() {
}
TQSample::TQSample(const TString& name) : TQSampleFolder(name) {
}
void TQSample::setNormalisation(double normalisation_) {
if (this->fProxySample) {
this->fProxySample->setNormalisation(normalisation_);
return;
}
fNormalisation = normalisation_;
}
double TQSample::getNormalisation() {
if (this->fProxySample) {
return this->fProxySample->getNormalisation();
}
return fNormalisation;
}
void TQSample::setTree(TFile* f, const TString& treename){
DEBUGclass("checking status of file");
if(!f || f->IsZombie() || !f->IsOpen()){
INFO("Encountered possible zombie file in sample '%s'!",this->getPath().Data());
this->fTree = NULL;
return;
}
DEBUGclass("attempting to retrieve tree");
TTree* tree = dynamic_cast<TTree*>(fFile->Get(treename.Data()));
DEBUGclass("function called on file '%s' for tree '%s'",f->GetName(),treename.Data());
#ifdef HAS_XAOD
bool isxAOD = false;
TTree* testTree = tree;
if (!testTree || testTree->GetEntriesFast()<1) {
testTree = dynamic_cast<TTree*>(fFile->Get("MetaData"));
}
if (!testTree) return;
TQIterator itr(testTree->GetListOfBranches());
while(itr.hasNext()){
TBranch* obj = (TBranch*)(itr.readNext());
if(TQStringUtils::find(obj->GetClassName(),"xAOD") != kNPOS){
isxAOD = true;
break;
}
}
if(isxAOD){
DEBUGclass("identified tree of sample '%s' as xAOD, making transient",this->getPath().Data());
DEBUGclass("creating new xAOD::TEvent");
xAOD::TVirtualEvent* evt = xAOD::TActiveEvent::event();
if(evt){
DEBUGclass("re-using existing instance of xAOD::TEvent");
this->fEvent = dynamic_cast<xAOD::TEvent*>(evt);
if(!this->fEvent) throw std::runtime_error("active instance of TVirtualEvent is not of type TEvent!");
} else {
DEBUGclass("creating new instance of xAOD::TEvent");
this->fEvent = new xAOD::TEvent(gUseAthenaAccessMode? xAOD::TEvent::kAthenaAccess : xAOD::TEvent::kClassAccess);
this->fEvent->setActive();
}
bool ok = (this->fEvent->readFrom( this->fFile, kTRUE, treename ).isSuccess());
DEBUGclass("calling xAOD::MakeTransientTree on event %x with treename '%s'",this->fEvent,treename.Data());
if(ok){
if(tree && TQSample::gUseTransientTree){
int oldErrorIgnoreLevel = gErrorIgnoreLevel;
gErrorIgnoreLevel = 2000;
this->fTree = xAOD::MakeTransientTree( *this->fEvent, treename );
gErrorIgnoreLevel = oldErrorIgnoreLevel;
DEBUGclass("retrieved transient tree %x",this->fTree);
this->fTreeIsTransient = true;
} else {
this->fTree = tree;
this->fTreeIsTransient = false;
}
} else {
WARNclass("TEvent failed to read from input file!");
this->fEvent = 0;
}
return;
}
#else
#endif
DEBUGclass("identified tree of sample '%s' as plain ROOT, setting data member",this->getPath().Data());
this->fTree = tree;
fTreeIsTransient = false;
}
void TQSample::clearTree(){
if(fFile){
this->retractTreeFromFriends();
if (fFile->IsOpen()){
DEBUGclass("closing file");
fFile->Close();
}
DEBUGclass("deleting file pointer");
delete fFile;
}
#ifdef HAS_XAOD
fEvent = NULL;
#endif
fFile = NULL;
fTree = NULL;
}
bool TQSample::getTree(){
DEBUGclass("trying to retrieve tree");
#ifdef DUMMYSAMPLE
TList * treeLocations = splitTreeLocations(DUMMYSAMPLE);
#else
TList * treeLocations = splitTreeLocations(getTreeLocation());
#endif
if (!treeLocations) {
WARN("Failed to obtain tree location for sample %s",this->GetName());
return false;
}
TString defFilename;
TString defTreename;
int nTreeLocations = treeLocations->GetEntries();
for (int i = 0; i < nTreeLocations && (fTree || i == 0); i++) {
TString location = treeLocations->At(i)->GetName();
TString filename = extractFilename(location);
TString treename = extractTreename(location);
if (filename.IsNull() && !defFilename.IsNull())
filename = defFilename;
else if (!filename.IsNull() && defFilename.IsNull())
defFilename = filename;
if (treename.IsNull() && !defTreename.IsNull())
treename = defTreename;
else if (!treename.IsNull() && defTreename.IsNull())
defTreename = treename;
if (!filename.IsNull()) {
TFile* myOpenFile = TQUtils::openFile(filename);
if (myOpenFile) {
if (i == 0) {
fFile = myOpenFile;
DEBUGclass("setting tree");
this->setTree(fFile, treename);
DEBUGclass("got tree %x",this->fTree);
if (!fTree) {
INFOclass("Failed to retrieve tree from file %s", filename.Data());
}
} else {
if (fTree) fTree->AddFriend(treename.Data(), myOpenFile);
else ERRORclass("Cannot add tree from file '%s' as a friend tree as no valid tree could be obtained from the first file '%s'",myOpenFile->GetPath(),fFile->GetPath());
}
} else {
ERRORclass("Failed to open file while retrieving tree!");
return false;
}
} else {
TTree* tree = dynamic_cast<TTree*>(getObject(treename.Data()));
if (tree){
this->fTree = tree;
this->fTreeIsTransient = false;
} else {
fTree = NULL;
return false;
}
}
}
delete treeLocations;
DEBUGclass("successfully completed function");
return true;
}
void TQSample::promoteTreeToFriends(){
if (this->fFriends == nullptr) return;
for (auto myFriendSF : (*this->fFriends)) {
if (! myFriendSF->InheritsFrom(TQSample::Class()) ) { throw std::runtime_error("Attempt to promote tree to friend which is not of type TQSample. A SampleFolder within a Sample should never happen, check your analysis setup!"); return; }
TQSample* myFriend = static_cast<TQSample*>(myFriendSF);
DEBUG("promoting tree from sample '%s' to sample '%s'",this->getPath().Data(),myFriend->getPath().Data());
if(!myFriend->getFile()){
myFriend->fTree = this->fTree;
#ifdef HAS_XAOD
myFriend->fEvent = this->fEvent;
#endif
}
}
}
void TQSample::retractTreeFromFriends(){
if (this->fFriends == nullptr) return;
for (auto myFriendSF : (*this->fFriends)) {
if (! myFriendSF->InheritsFrom(TQSample::Class()) ) { throw std::runtime_error("Attempt to retract tree from friend which is not of type TQSample. A SampleFolder within a Sample should never happen, check your analysis setup!"); return; }
TQSample* myFriend = static_cast<TQSample*>(myFriendSF);
if (myFriend==this) continue;
DEBUG("retracting tree of sample '%s' from sample '%s'",this->getPath().Data(),myFriend->getPath().Data());
if(!myFriend->getFile()){
myFriend->fTree = NULL;
#ifdef HAS_XAOD
myFriend->fEvent = NULL;
#endif
}
}
}
TQToken * TQSample::getTreeToken() {
DEBUGclass("entering function");
if (this->fProxySample) {
return this->fProxySample->getTreeToken();
}
bool createdFile = !(this->fFile);
if (!fTree) {
if(this->getTree()){
this->promoteTreeToFriends();
}
}
if (fTree) {
DEBUGclass("creating tree token");
TQToken * treeToken = new TQToken();
treeToken->setContent(fTree);
if (!fTokens) {
fTokens = new TList();
fTokens->SetOwner(true);
}
fTokens->Add(treeToken);
DEBUGclass("returning tree token");
return treeToken;
}
if (createdFile && this->fFile) {
this->clearTree();
}
return NULL;
}
TQToken * TQSample::getFileToken() {
DEBUGclass("entering function");
if (this->fProxySample) {
return this->fProxySample->getFileToken();
}
bool createdFile = !(this->fFile);
if (!fFile) {
if(this->getTree()){
this->promoteTreeToFriends();
}
}
if (fFile) {
DEBUGclass("returning file");
TQToken * fileToken = new TQToken();
fileToken->setContent(fFile);
if (!fTokens) {
fTokens = new TList();
fTokens->SetOwner(true);
}
fTokens->Add(fileToken);
return fileToken;
}
if (createdFile && this->fFile) {
this->clearTree();
}
return NULL;
}
TQToken * TQSample::getEventToken() {
#ifdef HAS_XAOD
DEBUGclass("entering function");
if (this->fProxySample) {
return this->fProxySample->getEventToken();
}
bool createdFile = !(this->fFile);
if (!fEvent) {
if(this->getTree()){
this->promoteTreeToFriends();
}
}
if (fEvent) {
DEBUGclass("returning TEvent");
TQToken * eventToken = new TQToken();
eventToken->setContent(fEvent);
if (!fTokens) {
fTokens = new TList();
fTokens->SetOwner(true);
}
fTokens->Add(eventToken);
return eventToken;
}
if (createdFile && this->fFile) {
this->clearTree();
}
return NULL;
#else
ERRORclass("event token was requested, but TEvent class unavailable in standalone release!");
return NULL;
#endif
}
bool TQSample::returnTreeToken(TQToken * &token_) {
if (this->fProxySample) {
return this->fProxySample->returnTreeToken(token_);
}
return this->returnToken(token_);
}
bool TQSample::returnToken(TQToken * &token_) {
if (this->fProxySample) {
return this->fProxySample->returnToken(token_);
}
if (fTokens && fTokens->FindObject(token_)) {
fTokens->Remove(token_);
token_ = 0;
if (getNTreeTokens() == 0) {
DEBUGclass("returning tree token - no tokens left, clearing tree");
this->clearTree();
} else {
DEBUGclass("returning tree token - there are still other active tokens");
}
return true;
} else {
return false;
}
}
bool TQSample::setTreeLocation(TString treeLocation_) {
if (this->fProxySample) {
return this->fProxySample->setTreeLocation(treeLocation_);
}
if (getNTreeTokens() == 0) {
fTreeLocation = treeLocation_;
return true;
} else {
return false;
}
}
int TQSample::getNTreeTokens() {
if (this->fProxySample) {
return this->fProxySample->getNTreeTokens();
}
if (fTokens)
return fTokens->GetEntries();
else
return 0;
}
void TQSample::printTreeTokens() {
if (this->fProxySample) {
this->fProxySample->printTreeTokens();
return;
}
TQIterator itr(fTokens);
while (itr.hasNext()) {
TQToken * token = dynamic_cast<TQToken*>(itr.readNext());
if (token) {
token->print();
}
}
}
bool TQSample::checkTreeAccessibility() {
if (this->fProxySample) {
return this->fProxySample->checkTreeAccessibility();
}
bool isAccessible = false;
TQToken * token = getTreeToken();
if (token) {
isAccessible = true;
returnTreeToken(token);
}
return isAccessible;
}
bool TQSample::updateTreeLocation() {
if (this->fProxySample) {
return this->fProxySample->updateTreeLocation();
}
TString filepath,treename;
if( ( this->getTagString(".xsp.filepath",filepath) && this->getTagString(".xsp.treename",treename) ) ||
( this->getTagString(".init.filepath",filepath) && this->getTagString(".init.treename",treename) ) ){
this->fTreeLocation = filepath + ":" + treename;
}
return true;
}
TString TQSample::getTreeLocation() {
if (this->fProxySample) {
return this->fProxySample->getTreeLocation();
}
if(this->fTreeLocation.IsNull()){
this->updateTreeLocation();
}
if (TQStringUtils::hasWildcards(fTreeLocation)) {
throw std::runtime_error(TString::Format("TreeLocation of sample '%s' is not fully resolved but contains wildcards. The tree might not be retrieved correctly!",this->GetName()).Data());
}
return fTreeLocation;
}
const TString& TQSample::getTreeLocationRef() {
if (this->fProxySample) {
return this->fProxySample->getTreeLocationRef();
}
if (this->fTreeLocation.IsNull()) {
this->updateTreeLocation();
}
return this->fTreeLocation;
}
TString TQSample::getFilename() {
if (this->fProxySample) {
return this->fProxySample->getFilename();
}
TList * treeLocations = splitTreeLocations(fTreeLocation);
TString treeLocation;
if (treeLocations) {
if (treeLocations->GetEntries() > 0)
treeLocation = TString(treeLocations->First()->GetName());
delete treeLocations;
}
return extractFilename(treeLocation);
}
TString TQSample::getTreename() {
if (this->fProxySample) {
return this->fProxySample->getTreename();
}
TList * treeLocations = splitTreeLocations(fTreeLocation);
TString treeLocation;
if (treeLocations) {
if (treeLocations->GetEntries() > 0)
treeLocation = TString(treeLocations->First()->GetName());
delete treeLocations;
}
return extractTreename(treeLocation);
}
bool TQSample::addSubSample(TQSample * subSample) {
if(this->isSubSample()){
return false;
}
if (!subSample) {
return false;
}
if(!this->addFolder(subSample)) {
return false;
}
return true;
}
TQSample* TQSample::addSelfAsSubSample(const TString& name) {
if(name.IsNull()) return NULL;
TQSample* subSample = new TQSample(name);
if(!this->addSubSample(subSample)){
delete subSample;
return NULL;
}
subSample->importTags(this);
return subSample;
}
TQSample * TQSample::getSubSample(const TString& path) {
TQSampleFolder * sampleFolder = getSampleFolder(path);
if (sampleFolder && sampleFolder->InheritsFrom(TQSample::Class()))
return static_cast<TQSample*>(sampleFolder);
else
return 0;
}
bool TQSample::isSubSample(){
return this->getBaseSample();
}
TQSample * TQSample::getBaseSample() {
return dynamic_cast<TQSample*>(this->getBase());
}
TFile* TQSample::getFile(){
if (this->fProxySample) {
return this->fProxySample->getFile();
}
return this->fFile;
}
TQSample::~TQSample() {
if (fTokens) {
delete fTokens;
fTokens = nullptr;
}
}
bool TQSample::hasSubSamples() {
TCollection * contents = this->GetListOfFolders();
if (!contents) return false;
TIterator * itr = contents->MakeIterator();
if (!itr) return false;
bool retval = false;
TObject * obj = nullptr;
while ( (obj = itr->Next() ) ) {
if (obj->InheritsFrom(TQSample::Class())) {
retval = true;
break;
}
}
delete itr;
return retval;
}
bool TQSample::createFriendLinksForSamplesWithTreeLocation(TQSampleFolder* otherSF, std::shared_ptr<TList> otherSFContents) {
if (!otherSF) otherSF = this;
bool isIncluded = false;
if (!otherSFContents) otherSFContents = std::shared_ptr<TList>( otherSF->getListOfSampleFolders("*", TQSample::Class()) );
TQSampleIterator itr(otherSFContents.get());
std::map<int,std::map<TString,TQSample*>> locationMap;
while(itr.hasNext()) {
TQSample* thisSample = itr.readNext();
if (!thisSample) continue;
if (thisSample == this) isIncluded = true;
if (thisSample->hasFriends()) continue;
TString location = thisSample->getTreeLocation();
if (location.Length() > 0 || !thisSample->hasSubSamples()) {
int distToRoot = thisSample->getDistToRoot();
if (location.Length() == 0) {
location = TString("<noFile>");
}
TQSample* existing = locationMap[distToRoot][location];
if (existing) {
existing->befriend(thisSample);
} else {
thisSample->befriend(thisSample);
locationMap[distToRoot][location] = thisSample;
}
}
}
return isIncluded;
}
void TQSample::findFriendsInternal(TQSampleFolder* otherSF, bool forceUpdateSubsamples, std::shared_ptr<TList> otherSFContents){
bool isLinked = this->hasFriends() || this->createFriendLinksForSamplesWithTreeLocation(otherSF, otherSFContents);
bool hasSubSamples = this->hasSubSamples();
const int thisDistToRoot = this->getDistToRoot();
if (!isLinked || hasSubSamples) {
if (!otherSFContents) otherSFContents = std::shared_ptr<TList>( otherSF->getListOfSampleFolders("*", TQSample::Class()) );
TQSampleIterator itr(otherSFContents.get());
if (!isLinked) {
const TString myTreeLocation = this->getTreeLocation();
if (myTreeLocation.Length()>0 || !hasSubSamples) {
while(itr.hasNext()){
TQSample* s = itr.readNext();
if (!s || s->hasFriends()) continue;
if (thisDistToRoot != s->getDistToRoot()) continue;
const TString treelocation = s->getTreeLocation();
DEBUGclass("looking at friend candidate '%s'",s->getPath().Data());
if(TQStringUtils::equal(treelocation,myTreeLocation) ){
DEBUGclass("found friend '%s'",s->getPath().Data());
this->befriend(s);
break;
}
}
}
}
if (hasSubSamples) {
itr.reset();
TQSampleIterator subitr(this->getListOfSamples("?"));
while(itr.hasNext()){
TQSample* other = itr.readNext();
if (!other || thisDistToRoot != other->getDistToRoot() || other->hasFriends() || !other->hasSubSamples() || this->getNSamples() != other->getNSamples() ) continue;
bool befriend = true;
while(subitr.hasNext() && befriend) {
TQSample* thisSub = subitr.readNext();
if (!thisSub) continue;
TQSample* otherSub = other->getSubSample(thisSub->GetName());
if (!otherSub) {befriend = false; break;}
if (forceUpdateSubsamples || (!thisSub->hasFriends()) ) thisSub->findFriends(otherSF, forceUpdateSubsamples);
if (forceUpdateSubsamples || (!otherSub->hasFriends()) ) otherSub->findFriends(otherSF, forceUpdateSubsamples);
befriend = befriend && thisSub->isFriend(otherSub);
}
subitr.reset();
if (befriend) {
this->befriend(other);
}
}
}
}
}
int TQSample::getOwnSize() const {
return sizeof(*this);
}