File indexing completed on 2025-12-17 09:19:51
0001
0002
0003
0004 #include "PHNodeIOManager.h"
0005 #include "PHCompositeNode.h"
0006 #include "PHIODataNode.h"
0007 #include "PHNodeIterator.h"
0008 #include "phooldefs.h"
0009
0010 #include <TBranch.h> // for TBranch
0011 #include <TBranchElement.h>
0012 #include <TBranchObject.h>
0013 #include <TClass.h>
0014 #include <TDirectory.h> // for TDirectory
0015 #include <TFile.h>
0016 #include <TLeafObject.h>
0017 #include <TObjArray.h> // for TObjArray
0018 #include <TObject.h>
0019 #include <TROOT.h>
0020 #include <TSystem.h>
0021 #include <TTree.h>
0022 #include <TTreeCache.h>
0023
0024 #include <boost/algorithm/string.hpp>
0025
0026 #include <cassert>
0027 #include <cstdlib>
0028 #include <iostream>
0029 #include <sstream>
0030 #include <string>
0031 #include <utility>
0032 #include <vector>
0033
0034 PHNodeIOManager::PHNodeIOManager(const std::string& f,
0035 const PHAccessType a)
0036 {
0037 isFunctionalFlag = setFile(f, "titled by PHOOL", a) ? 1 : 0;
0038 }
0039
0040 PHNodeIOManager::PHNodeIOManager(const std::string& f, const std::string& title,
0041 const PHAccessType a)
0042 : isFunctionalFlag(setFile(f, title, a) ? 1 : 0)
0043 {
0044 }
0045
0046 PHNodeIOManager::PHNodeIOManager(const std::string& f, const PHAccessType a,
0047 const PHTreeType treeindex)
0048 {
0049 if (treeindex != PHEventTree)
0050 {
0051 std::ostringstream temp;
0052 temp << TreeName << treeindex;
0053 TreeName = temp.str();
0054 }
0055 isFunctionalFlag = setFile(f, "titled by PHOOL", a) ? 1 : 0;
0056 }
0057
0058 PHNodeIOManager::~PHNodeIOManager()
0059 {
0060 closeFile();
0061 delete file;
0062 }
0063
0064 void PHNodeIOManager::closeFile()
0065 {
0066 if (file)
0067 {
0068 if (accessMode == PHWrite || accessMode == PHUpdate)
0069 {
0070 file->Write();
0071 }
0072 file->Close();
0073 }
0074 }
0075
0076 bool PHNodeIOManager::setFile(const std::string& f, const std::string& title,
0077 const PHAccessType a)
0078 {
0079 filename = f;
0080 accessMode = a;
0081 if (file)
0082 {
0083 if (file->IsOpen())
0084 {
0085 closeFile();
0086 }
0087 delete file;
0088 file = nullptr;
0089 }
0090 std::string currdir = gDirectory->GetPath();
0091 gROOT->cd();
0092 switch (accessMode)
0093 {
0094 case PHWrite:
0095 file = TFile::Open(filename.c_str(), "RECREATE", title.c_str());
0096 if (!file)
0097 {
0098 return false;
0099 }
0100 file->SetCompressionSettings(m_CompressionSetting);
0101 tree = new TTree(TreeName.c_str(), title.c_str());
0102 TTree::SetMaxTreeSize(900000000000LL);
0103
0104 gROOT->cd(currdir.c_str());
0105 return true;
0106 break;
0107 case PHReadOnly:
0108 file = TFile::Open(filename.c_str());
0109 tree = nullptr;
0110 if (!file)
0111 {
0112 return false;
0113 }
0114 selectObjectToRead("*", true);
0115 gROOT->cd(currdir.c_str());
0116 return true;
0117 break;
0118 case PHUpdate:
0119 file = TFile::Open(filename.c_str(), "UPDATE", title.c_str());
0120 if (!file)
0121 {
0122 return false;
0123 }
0124 file->SetCompressionSettings(m_CompressionSetting);
0125 tree = new TTree(TreeName.c_str(), title.c_str());
0126 gROOT->cd(currdir.c_str());
0127 return true;
0128 break;
0129 default:
0130 std::cout << PHWHERE << "Invalid Access mode " << accessMode << std::endl;
0131 break;
0132 }
0133
0134 return false;
0135 }
0136
0137 bool PHNodeIOManager::write(PHCompositeNode* topNode)
0138 {
0139
0140
0141
0142
0143 topNode->write(this);
0144
0145
0146
0147
0148 if (file && tree)
0149 {
0150 tree->Fill();
0151 eventNumber++;
0152 return true;
0153 }
0154
0155 return false;
0156 }
0157
0158 bool PHNodeIOManager::write(TObject** data, const std::string& path, int nodebuffersize, int nodesplitlevel)
0159 {
0160 if (file && tree)
0161 {
0162 TBranch* thisBranch = tree->GetBranch(path.c_str());
0163 if (!thisBranch)
0164 {
0165 int use_splitlevel = splitlevel;
0166 int use_buffersize = buffersize;
0167
0168
0169
0170 if (splitlevel == std::numeric_limits<int>::min())
0171 {
0172 use_splitlevel = nodesplitlevel;
0173 }
0174 if (buffersize == std::numeric_limits<int>::min())
0175 {
0176 use_buffersize = nodebuffersize;
0177 }
0178 tree->Branch(path.c_str(), (*data)->ClassName(),
0179 data, use_buffersize, use_splitlevel);
0180 }
0181 else
0182 {
0183 thisBranch->SetAddress(data);
0184 }
0185 return true;
0186 }
0187
0188 return false;
0189 }
0190
0191 bool PHNodeIOManager::read(size_t requestedEvent)
0192 {
0193 return readEventFromFile(requestedEvent);
0194 }
0195
0196 PHCompositeNode*
0197 PHNodeIOManager::read(PHCompositeNode* topNode, size_t requestedEvent)
0198 {
0199
0200
0201 if (!tree)
0202 {
0203 topNode = reconstructNodeTree(topNode);
0204 }
0205
0206
0207 if (tree && readEventFromFile(requestedEvent))
0208 {
0209 return topNode;
0210 }
0211
0212 return nullptr;
0213 }
0214
0215 void PHNodeIOManager::print() const
0216 {
0217 if (file)
0218 {
0219 if (accessMode == PHReadOnly)
0220 {
0221 std::cout << "PHNodeIOManager reading " << filename << std::endl;
0222 }
0223 else
0224 {
0225 std::cout << "PHNodeIOManager writing " << filename << std::endl;
0226 }
0227 }
0228 if (file && tree)
0229 {
0230 tree->Print();
0231 }
0232 std::cout << "\n\nList of selected objects to read:" << std::endl;
0233 std::map<std::string, bool>::const_iterator classiter;
0234 for (classiter = objectToRead.begin(); classiter != objectToRead.end(); ++classiter)
0235 {
0236 std::cout << classiter->first << " is set to " << classiter->second << std::endl;
0237 }
0238 }
0239
0240 std::string
0241 PHNodeIOManager::getBranchClassName(TBranch* branch)
0242 {
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 #if ROOT_VERSION_CODE >= ROOT_VERSION(3, 01, 5)
0253 TBranchElement* be = dynamic_cast<TBranchElement*>(branch);
0254
0255 if (be)
0256 {
0257
0258 return be->GetClassName();
0259 }
0260 #endif
0261
0262 TBranchObject* bo = dynamic_cast<TBranchObject*>(branch);
0263 if (bo)
0264 {
0265
0266
0267
0268 TLeafObject* leaf = static_cast<TLeafObject*>(branch->GetLeaf(branch->GetName()));
0269 assert(leaf != nullptr);
0270 return leaf->GetTypeName();
0271 }
0272 std::cout << PHWHERE << "Fatal error, dynamic cast of TBranchObject failed" << std::endl;
0273 gSystem->Exit(1);
0274 exit(1);
0275 }
0276
0277 bool PHNodeIOManager::readEventFromFile(size_t requestedEvent)
0278 {
0279
0280
0281 if (!tree)
0282 {
0283 std::cout << PHWHERE << " Tree not initialized" << std::endl;
0284 return false;
0285 }
0286
0287 int bytesRead;
0288
0289
0290
0291
0292
0293 std::string currdir = gDirectory->GetPath();
0294 TFile* file_ptr = gFile;
0295 file->cd();
0296
0297 if (m_cacheSize != std::numeric_limits<uint64_t>::max())
0298 {
0299 tree->SetCacheSize(m_cacheSize);
0300 }
0301
0302 if (requestedEvent)
0303 {
0304 bytesRead = tree->GetEvent(requestedEvent);
0305 if (bytesRead)
0306 {
0307 eventNumber = requestedEvent + 1;
0308 }
0309 }
0310 else
0311 {
0312 bytesRead = tree->GetEvent(eventNumber++);
0313 }
0314
0315 gFile = file_ptr;
0316 gROOT->cd(currdir.c_str());
0317
0318 if (!bytesRead)
0319 {
0320 return false;
0321 }
0322 if (bytesRead == -1)
0323 {
0324 std::cout << PHWHERE << "Error: Input TTree corrupt, exiting now" << std::endl;
0325 exit(1);
0326 }
0327 return true;
0328 }
0329
0330 int PHNodeIOManager::readSpecific(size_t requestedEvent, const std::string& objectName)
0331 {
0332
0333
0334
0335 std::map<std::string, TBranch*>::const_iterator p = fBranches.find(objectName);
0336
0337 if (p != fBranches.end())
0338 {
0339 TBranch* branch = p->second;
0340 if (branch)
0341 {
0342 return branch->GetEvent(requestedEvent);
0343 }
0344 }
0345 else
0346 {
0347 std::cout << PHWHERE << "Cannot find "
0348 << objectName << " in TBranch" << std::endl;
0349 }
0350 return 0;
0351 }
0352
0353 PHCompositeNode*
0354 PHNodeIOManager::reconstructNodeTree(PHCompositeNode* topNode)
0355 {
0356 if (!file)
0357 {
0358 if (filename.empty())
0359 {
0360 std::cout << PHWHERE << "filename was never set" << std::endl;
0361 }
0362 else
0363 {
0364 std::cout << PHWHERE << "TFile " << filename << " NULL pointer" << std::endl;
0365 }
0366 return nullptr;
0367 }
0368
0369 file->GetObject(TreeName.c_str(),tree);
0370
0371 if (!tree)
0372 {
0373 std::cout << PHWHERE << "PHNodeIOManager::reconstructNodeTree : Root Tree "
0374 << TreeName << " not found in file " << file->GetName() << std::endl;
0375 return nullptr;
0376 }
0377
0378
0379
0380 std::ostringstream nname;
0381 nname << TreeName << file;
0382
0383 tree->SetName(nname.str().c_str());
0384
0385
0386 std::map<std::string, bool>::const_iterator it;
0387
0388 if (tree->GetNbranches() > 0)
0389 {
0390 for (it = objectToRead.begin(); it != objectToRead.end(); ++it)
0391 {
0392 tree->SetBranchStatus((it->first).c_str(),
0393 static_cast<bool>(it->second));
0394 }
0395 }
0396
0397
0398 TObjArray* branchArray = tree->GetListOfBranches();
0399
0400
0401 size_t i;
0402 size_t j;
0403
0404
0405 if (!topNode)
0406 {
0407 topNode = new PHCompositeNode("TOP");
0408 }
0409 PHNodeIterator nodeIter(topNode);
0410
0411
0412
0413
0414 std::string delimeters = phooldefs::branchpathdelim + phooldefs::legacypathdelims;
0415 for (i = 0; i < (size_t) (branchArray->GetEntriesFast()); i++)
0416 {
0417 std::string branchname = (*branchArray)[i]->GetName();
0418 std::vector<std::string> splitvec;
0419 boost::split(splitvec, branchname, boost::is_any_of(delimeters));
0420 for (size_t ia = 1; ia < splitvec.size() - 1; ia++)
0421 {
0422 if (!nodeIter.cd(splitvec[ia]))
0423 {
0424 nodeIter.addNode(new PHCompositeNode(splitvec[ia]));
0425 nodeIter.cd(splitvec[ia]);
0426 }
0427 }
0428 TBranch* thisBranch = (TBranch*) ((*branchArray)[i]);
0429
0430
0431 if (thisBranch->TestBit(kDoNotProcess))
0432 {
0433
0434 for (j = 1; j < splitvec.size() - 1; j++)
0435 {
0436 nodeIter.cd("..");
0437 }
0438 continue;
0439 }
0440
0441 std::string branchClassName = getBranchClassName(thisBranch);
0442 std::string branchName = thisBranch->GetName();
0443 fBranches[branchName] = thisBranch;
0444
0445 assert(gROOT != nullptr);
0446 TClass* thisClass = gROOT->GetClass(branchClassName.c_str());
0447
0448 if (!thisClass)
0449 {
0450 std::cout << PHWHERE << std::endl;
0451 std::cout << "Missing Class: " << branchClassName << std::endl;
0452 std::cout << "Did you forget to load the shared library which contains "
0453 << branchClassName << "?" << std::endl;
0454 }
0455
0456
0457 assert(thisClass != nullptr);
0458
0459 PHIODataNode<TObject>* newIODataNode = static_cast<PHIODataNode<TObject>*>(nodeIter.findFirst("PHIODataNode", *splitvec.rbegin()));
0460 if (!newIODataNode)
0461 {
0462 TObject* newTObject = static_cast<TObject*>(thisClass->New());
0463 newIODataNode = new PHIODataNode<TObject>(newTObject, *splitvec.rbegin());
0464 nodeIter.addNode(newIODataNode);
0465 }
0466 else
0467 {
0468 TObject* oldobject = newIODataNode->getData();
0469 std::string oldclass = oldobject->ClassName();
0470 if (oldclass != branchClassName)
0471 {
0472 std::cout << "You only have to worry if you get this message when reading parallel files"
0473 << std::endl
0474 << "if you get this when opening the 2nd, 3rd,... file" << std::endl
0475 << "It looks like your objects are not of the same version in these files" << std::endl;
0476 std::cout << PHWHERE << "Found object " << oldobject->ClassName()
0477 << " in node tree but the file "
0478 << filename << " contains a " << branchClassName
0479 << " object. The object will be replaced without harming you" << std::endl;
0480 std::cout << "CAVEAT: If you use local copies of pointers to data nodes" << std::endl
0481 << "instead of searching the node tree you are in trouble now" << std::endl;
0482 delete newIODataNode;
0483 TObject* newTObject = static_cast<TObject*>(thisClass->New());
0484 newIODataNode = new PHIODataNode<TObject>(newTObject, *splitvec.rbegin());
0485 nodeIter.addNode(newIODataNode);
0486 }
0487 }
0488
0489 if (thisClass->InheritsFrom("PHObject"))
0490 {
0491 newIODataNode->setObjectType("PHObject");
0492 }
0493 else
0494 {
0495 std::cout << PHWHERE << branchClassName.c_str()
0496 << " inherits neither from PHTable nor from PHObject"
0497 << " setting type to PHObject" << std::endl;
0498 newIODataNode->setObjectType("PHObject");
0499 }
0500 thisBranch->SetAddress(&(newIODataNode->data));
0501 for (j = 1; j < splitvec.size() - 1; j++)
0502 {
0503 nodeIter.cd("..");
0504 }
0505 }
0506 return topNode;
0507 }
0508
0509 void PHNodeIOManager::selectObjectToRead(const std::string& objectName, bool readit)
0510 {
0511 objectToRead[objectName] = readit;
0512
0513
0514 if (tree)
0515 {
0516 std::map<std::string, bool>::const_iterator it;
0517
0518 for (it = objectToRead.begin(); it != objectToRead.end(); ++it)
0519 {
0520 tree->SetBranchStatus((it->first).c_str(),
0521 static_cast<bool>(it->second));
0522 }
0523 }
0524 return;
0525 }
0526
0527 bool PHNodeIOManager::isSelected(const std::string& objectName)
0528 {
0529 std::map<std::string, TBranch*>::const_iterator p = fBranches.find(objectName);
0530
0531 return p != fBranches.end();
0532 }
0533
0534 bool PHNodeIOManager::SetCompressionSetting(const int level)
0535 {
0536 if (level < 0)
0537 {
0538 return false;
0539 }
0540 m_CompressionSetting = level;
0541 if (file)
0542 {
0543 file->SetCompressionSettings(m_CompressionSetting);
0544 }
0545
0546 return true;
0547 }
0548
0549 uint64_t
0550 PHNodeIOManager::GetBytesWritten()
0551 {
0552 if (file)
0553 {
0554 return file->GetBytesWritten();
0555 }
0556 return 0.;
0557 }
0558
0559 uint64_t
0560 PHNodeIOManager::GetFileSize()
0561 {
0562 if (file)
0563 {
0564 return file->GetSize();
0565 }
0566 return 0.;
0567 }
0568
0569 std::map<std::string, TBranch*>*
0570 PHNodeIOManager::GetBranchMap()
0571 {
0572 FillBranchMap();
0573 return &fBranches;
0574 }
0575
0576 int PHNodeIOManager::FillBranchMap()
0577 {
0578 if (fBranches.empty())
0579 {
0580 TTree* treetmp = nullptr;
0581 file->GetObject(TreeName.c_str(),treetmp);
0582 if (treetmp)
0583 {
0584 TObjArray* branchArray = treetmp->GetListOfBranches();
0585 for (size_t i = 0; i < (size_t) (branchArray->GetEntriesFast()); i++)
0586 {
0587 TBranch* thisBranch = (TBranch*) ((*branchArray)[i]);
0588 std::string branchName = (*branchArray)[i]->GetName();
0589 fBranches[branchName] = thisBranch;
0590 }
0591 }
0592 else
0593 {
0594 std::cout << PHWHERE << " No Root Tree " << TreeName
0595 << " on file " << filename << std::endl;
0596 return -1;
0597 }
0598 }
0599 return 0;
0600 }
0601
0602 bool PHNodeIOManager::NodeExist(const std::string& nodename)
0603 {
0604 if (fBranches.empty())
0605 {
0606 FillBranchMap();
0607 }
0608 std::string delimeters = phooldefs::branchpathdelim + phooldefs::legacypathdelims;
0609 for (auto& fBranche : fBranches)
0610 {
0611 std::vector<std::string> splitvec;
0612 boost::split(splitvec, fBranche.first, boost::is_any_of(delimeters));
0613 if (splitvec.back() == nodename)
0614 {
0615 return true;
0616 }
0617 }
0618 return false;
0619 }
0620
0621 void PHNodeIOManager::DisableReadCache()
0622 {
0623 if (file)
0624 {
0625 file->SetCacheRead(nullptr);
0626 }
0627 return;
0628 }