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