Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:04:10

0001 // -*- C++ -*-
0002 //
0003 // Package:     DataFormats/FWLite
0004 // Class  :     DataGetterHelper
0005 //
0006 // Implementation:
0007 //     [Notes on implementation]
0008 //
0009 // Original Author: Eric Vaandering
0010 //         Created:  Fri Jan 29 11:58:01 CST 2010
0011 //
0012 
0013 // system include files
0014 #include <cassert>
0015 #include <iostream>
0016 
0017 // user include files
0018 #include "DataFormats/FWLite/interface/DataGetterHelper.h"
0019 #include "TFile.h"
0020 #include "TTree.h"
0021 #include "TTreeCache.h"
0022 
0023 #include "DataFormats/Common/interface/ThinnedAssociation.h"
0024 #include "DataFormats/Common/interface/Wrapper.h"
0025 #include "DataFormats/Common/interface/WrapperBase.h"
0026 #include "DataFormats/Common/interface/getThinned_implementation.h"
0027 #include "DataFormats/Provenance/interface/ThinnedAssociationsHelper.h"
0028 
0029 #include "FWCore/FWLite/interface/setRefStreamer.h"
0030 
0031 #include "FWCore/Utilities/interface/EDMException.h"
0032 #include "FWCore/Utilities/interface/Exception.h"
0033 #include "FWCore/Reflection/interface/FunctionWithDict.h"
0034 #include "FWCore/Utilities/interface/TypeID.h"
0035 #include "FWCore/Reflection/interface/TypeWithDict.h"
0036 #include "FWCore/Utilities/interface/WrappedClassName.h"
0037 
0038 namespace fwlite {
0039   //
0040   // constants, enums and typedefs
0041   //
0042 
0043   //
0044   // static data member definitions
0045   //
0046   // empty object used to signal that the branch requested was not found
0047   static internal::Data branchNotFound{};
0048   static const char kEmptyString[1] = {0};
0049 
0050   //
0051   // constructors and destructor
0052   //
0053   DataGetterHelper::DataGetterHelper(TTree* tree,
0054                                      std::shared_ptr<HistoryGetterBase> historyGetter,
0055                                      std::shared_ptr<BranchMapReader> branchMap,
0056                                      std::shared_ptr<edm::EDProductGetter> getter,
0057                                      bool useCache,
0058                                      std::function<void(TBranch const&)> baFunc)
0059       : branchMap_(branchMap),
0060         historyGetter_(historyGetter),
0061         getter_(getter),
0062         tcTrained_(false),
0063         tcUse_(useCache),
0064         branchAccessFunc_(baFunc) {
0065     if (nullptr == tree) {
0066       throw cms::Exception("NoTree") << "The TTree pointer passed to the constructor was null";
0067     }
0068     tree_ = tree;
0069     if (tcUse_) {
0070       tree_->SetCacheSize();
0071     }
0072   }
0073 
0074   // DataGetterHelper::DataGetterHelper(const DataGetterHelper& rhs)
0075   // {
0076   //    // do actual copying here;
0077   // }
0078 
0079   DataGetterHelper::~DataGetterHelper() {}
0080 
0081   //
0082   // assignment operators
0083   //
0084   // const DataGetterHelper& DataGetterHelper::operator=(const DataGetterHelper& rhs)
0085   // {
0086   //   //An exception safe implementation is
0087   //   DataGetterHelper temp(rhs);
0088   //   swap(rhs);
0089   //
0090   //   return *this;
0091   // }
0092 
0093   //
0094   // member functions
0095   //
0096 
0097   //
0098   // const member functions
0099   //
0100 
0101   //
0102   // static member functions
0103   //
0104 
0105   static TBranch* findBranch(TTree* iTree, std::string const& iMainLabels, std::string const& iProcess) {
0106     std::string branchName(iMainLabels);
0107     branchName += iProcess;
0108     //branchName+=".obj";
0109     branchName += ".";
0110     return iTree->GetBranch(branchName.c_str());
0111   }
0112 
0113   void DataGetterHelper::getBranchData(edm::EDProductGetter const* iGetter,
0114                                        Long64_t eventEntry,
0115                                        internal::Data& iData) const {
0116     GetterOperate op(iGetter);
0117 
0118     ////WORK AROUND FOR ROOT!!
0119     ////Create a new instance so that we can clear any cache the object uses
0120     ////this slows the code down
0121     //edm::ObjectWithDict obj = iData.obj_;
0122     //iData.obj_ = iData.obj_.construct();
0123     //iData.pObj_ = iData.obj_.address();
0124     //iData.branch_->SetAddress(&(iData.pObj_));
0125     ////If a REF to this was requested in the past, we might as well do the work now
0126     //if(nullptr != iData.pProd_) {
0127     //    iData.pProd_ = iData.obj_.address();
0128     //}
0129     //obj.destruct();
0130     ////END OF WORK AROUND
0131 
0132     if (tcUse_) {
0133       TTreeCache* tcache = dynamic_cast<TTreeCache*>(branchMap_->getFile()->GetCacheRead());
0134 
0135       if (nullptr != tcache) {
0136         if (!tcTrained_) {
0137           tcache->SetLearnEntries(100);
0138           tcache->SetEntryRange(0, tree_->GetEntries());
0139           tcTrained_ = true;
0140         }
0141         tree_->LoadTree(eventEntry);
0142       }
0143     }
0144     branchAccessFunc_(*iData.branch_);
0145     iData.branch_->GetEntry(eventEntry);
0146 
0147     iData.lastProduct_ = eventEntry;
0148   }
0149 
0150   std::optional<edm::BranchID> DataGetterHelper::getBranchIDFor(std::type_info const& iInfo,
0151                                                                 char const* iModuleLabel,
0152                                                                 char const* iProductInstanceLabel,
0153                                                                 char const* iProcessLabel) const {
0154     auto branchFor = [this](edm::TypeID const& iInfo,
0155                             char const* iModuleLabel,
0156                             char const* iProductInstanceLabel,
0157                             char const* iProcessLabel) -> std::optional<edm::BranchID> {
0158       for (auto const& bd : branchMap_->getBranchDescriptions()) {
0159         if (bd.unwrappedTypeID() == iInfo and bd.moduleLabel() == iModuleLabel and
0160             bd.productInstanceName() == iProductInstanceLabel and bd.processName() == iProcessLabel) {
0161           return bd.branchID();
0162         }
0163       }
0164       return std::nullopt;
0165     };
0166     if (nullptr == iProcessLabel || strlen(iProcessLabel) == 0) {
0167       //have to search in reverse order since newest are on the bottom
0168       const edm::ProcessHistory& h = DataGetterHelper::history();
0169       edm::TypeID typeID(iInfo);
0170       for (edm::ProcessHistory::const_reverse_iterator iproc = h.rbegin(), eproc = h.rend(); iproc != eproc; ++iproc) {
0171         auto v = branchFor(typeID, iModuleLabel, iProductInstanceLabel, iproc->processName().c_str());
0172         if (v) {
0173           return v;
0174         }
0175       }
0176       return std::nullopt;
0177     }
0178     return branchFor(edm::TypeID(iInfo), iModuleLabel, iProductInstanceLabel, iProcessLabel);
0179   }
0180 
0181   internal::Data& DataGetterHelper::getBranchDataFor(std::type_info const& iInfo,
0182                                                      char const* iModuleLabel,
0183                                                      char const* iProductInstanceLabel,
0184                                                      char const* iProcessLabel) const {
0185     edm::TypeID type(iInfo);
0186     internal::DataKey key(type, iModuleLabel, iProductInstanceLabel, iProcessLabel);
0187 
0188     KeyToDataMap::iterator itFind = data_.find(key);
0189     if (itFind == data_.end()) {
0190       //see if such a branch actually exists
0191       std::string const sep("_");
0192       //CHANGE: If this fails, need to lookup the the friendly name which was used to write the file
0193       std::string name(type.friendlyClassName());
0194       name += sep + std::string(key.module());
0195       name += sep + std::string(key.product()) + sep;
0196 
0197       //if we have to lookup the process label, remember it and register the product again
0198       std::string foundProcessLabel;
0199       TBranch* branch = nullptr;
0200       std::shared_ptr<internal::Data> theData;
0201 
0202       if (nullptr == iProcessLabel || iProcessLabel == key.kEmpty() || strlen(iProcessLabel) == 0) {
0203         std::string const* lastLabel = nullptr;
0204         //have to search in reverse order since newest are on the bottom
0205         const edm::ProcessHistory& h = DataGetterHelper::history();
0206         for (edm::ProcessHistory::const_reverse_iterator iproc = h.rbegin(), eproc = h.rend(); iproc != eproc;
0207              ++iproc) {
0208           lastLabel = &(iproc->processName());
0209           branch = findBranch(tree_, name, iproc->processName());
0210           if (nullptr != branch) {
0211             break;
0212           }
0213         }
0214         if (nullptr == branch) {
0215           return branchNotFound;
0216         }
0217         //do we already have this one?
0218         if (nullptr != lastLabel) {
0219           internal::DataKey fullKey(type, iModuleLabel, iProductInstanceLabel, lastLabel->c_str());
0220           itFind = data_.find(fullKey);
0221           if (itFind != data_.end()) {
0222             //remember the data we've found
0223             theData = itFind->second;
0224           } else {
0225             //only set this if we don't already have it since it this string is not empty we re-register
0226             foundProcessLabel = *lastLabel;
0227           }
0228         }
0229       } else {
0230         //we have all the pieces
0231         branch = findBranch(tree_, name, key.process());
0232         if (nullptr == branch) {
0233           return branchNotFound;
0234         }
0235       }
0236 
0237       //cache the info
0238       size_t moduleLabelLen = strlen(iModuleLabel) + 1;
0239       char* newModule = new char[moduleLabelLen];
0240       std::strncpy(newModule, iModuleLabel, moduleLabelLen);
0241       labels_.push_back(newModule);
0242 
0243       char const* newProduct = kEmptyString;
0244       if (key.product()[0] != 0) {
0245         size_t newProductLen = strlen(key.product()) + 1;
0246         auto newProductTmp = new char[newProductLen];
0247         std::strncpy(newProductTmp, key.product(), newProductLen);
0248         newProduct = newProductTmp;
0249         labels_.push_back(newProduct);
0250       }
0251       char const* newProcess = kEmptyString;
0252       if (key.process()[0] != 0) {
0253         size_t newProcessLen = strlen(key.process()) + 1;
0254         auto newProcessTmp = new char[newProcessLen];
0255         std::strncpy(newProcessTmp, key.process(), newProcessLen);
0256         newProcess = newProcessTmp;
0257         labels_.push_back(newProcess);
0258       }
0259       internal::DataKey newKey(edm::TypeID(iInfo), newModule, newProduct, newProcess);
0260 
0261       if (nullptr == theData.get()) {
0262         //We do not already have this data as another key
0263 
0264         //create an instance of the object to be used as a buffer
0265         edm::TypeWithDict typeWithDict(iInfo);
0266         if (!bool(typeWithDict)) {
0267           throw cms::Exception("UnknownType") << "No dictionary exists for type " << iInfo.name();
0268         }
0269 
0270         edm::ObjectWithDict obj = edm::ObjectWithDict::byType(typeWithDict);
0271 
0272         if (obj.address() == nullptr) {
0273           throw cms::Exception("ConstructionFailed") << "failed to construct an instance of " << typeWithDict.name();
0274         }
0275         auto newData = std::make_shared<internal::Data>();
0276         newData->branch_ = branch;
0277         newData->obj_ = obj;
0278         newData->lastProduct_ = -1;
0279         newData->pObj_ = obj.address();
0280         newData->pProd_ = nullptr;
0281         branch->SetAddress(&(newData->pObj_));
0282         theData = newData;
0283       }
0284       itFind = data_.insert(std::make_pair(newKey, theData)).first;
0285 
0286       if (!foundProcessLabel.empty()) {
0287         //also remember it with the process label
0288         auto newProcessTmp = new char[foundProcessLabel.size() + 1];
0289         std::strcpy(newProcessTmp, foundProcessLabel.c_str());
0290         newProcess = newProcessTmp;
0291         labels_.push_back(newProcess);
0292         internal::DataKey newKeyWithProcess(edm::TypeID(iInfo), newModule, newProduct, newProcess);
0293 
0294         data_.insert(std::make_pair(newKeyWithProcess, theData));
0295       }
0296     }
0297     return *(itFind->second);
0298   }
0299 
0300   std::string const DataGetterHelper::getBranchNameFor(std::type_info const& iInfo,
0301                                                        char const* iModuleLabel,
0302                                                        char const* iProductInstanceLabel,
0303                                                        char const* iProcessLabel) const {
0304     internal::Data& theData =
0305         DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
0306 
0307     if (nullptr != theData.branch_) {
0308       return std::string(theData.branch_->GetName());
0309     }
0310     return std::string("");
0311   }
0312 
0313   bool DataGetterHelper::getByLabel(std::type_info const& iInfo,
0314                                     char const* iModuleLabel,
0315                                     char const* iProductInstanceLabel,
0316                                     char const* iProcessLabel,
0317                                     void* oData,
0318                                     Long_t eventEntry) const {
0319     // Maintain atEnd() check in parent classes
0320     void** pOData = reinterpret_cast<void**>(oData);
0321     *pOData = nullptr;
0322 
0323     internal::Data& theData =
0324         DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
0325 
0326     if (nullptr != theData.branch_) {
0327       if (eventEntry != theData.lastProduct_) {
0328         //haven't gotten the data for this event
0329         getBranchData(getter_.get(), eventEntry, theData);
0330       }
0331       *pOData = theData.obj_.address();
0332     }
0333 
0334     if (nullptr == *pOData)
0335       return false;
0336     else
0337       return true;
0338   }
0339 
0340   bool DataGetterHelper::getByBranchDescription(edm::BranchDescription const& bDesc,
0341                                                 Long_t eventEntry,
0342                                                 KeyToDataMap::iterator& itData) const {
0343     if (!bDesc.branchID().isValid()) {
0344       return false;
0345     }
0346 
0347     //Calculate the key from the branch description
0348     edm::TypeWithDict typeWD(edm::TypeWithDict::byName(edm::wrappedClassName(bDesc.fullClassName())));
0349     edm::TypeID type(typeWD.typeInfo());
0350     assert(bool(type));
0351 
0352     //Only the product instance label may be empty
0353     char const* pIL = bDesc.productInstanceName().c_str();
0354     if (pIL[0] == 0) {
0355       pIL = nullptr;
0356     }
0357     internal::DataKey k(type, bDesc.moduleLabel().c_str(), pIL, bDesc.processName().c_str());
0358 
0359     //has this already been gotten?
0360     itData = data_.find(k);
0361     if (data_.end() == itData) {
0362       //ask for the data
0363       edm::WrapperBase const* dummy = nullptr;
0364       getByLabel(type.typeInfo(), k.module(), k.product(), k.process(), &dummy, eventEntry);
0365       if (nullptr == dummy) {
0366         return false;
0367       }
0368       itData = data_.find(k);
0369       assert(itData != data_.end());
0370       assert(dummy == itData->second->obj_.address());
0371     }
0372     return true;
0373   }
0374 
0375   edm::WrapperBase const* DataGetterHelper::getByProductID(edm::ProductID const& iID, Long_t eventEntry) const {
0376     typedef std::pair<edm::ProductID, edm::BranchListIndex> IDPair;
0377     IDPair theID = std::make_pair(iID, branchMap_->branchListIndexes()[iID.processIndex() - 1]);
0378     std::map<IDPair, std::shared_ptr<internal::Data>>::const_iterator itFound = idToData_.find(theID);
0379 
0380     if (itFound == idToData_.end()) {
0381       edm::BranchDescription const& bDesc = branchMap_->productToBranch(iID);
0382       KeyToDataMap::iterator itData;
0383 
0384       if (!getByBranchDescription(bDesc, eventEntry, itData)) {
0385         return nullptr;
0386       }
0387       itFound = idToData_.insert(std::make_pair(theID, itData->second)).first;
0388     }
0389     if (eventEntry != itFound->second->lastProduct_) {
0390       //haven't gotten the data for this event
0391       getBranchData(getter_.get(), eventEntry, *(itFound->second));
0392     }
0393     if (nullptr == itFound->second->pProd_) {
0394       itFound->second->pProd_ = wrapperBasePtr(itFound->second->obj_);
0395       if (nullptr == itFound->second->pProd_) {
0396         return nullptr;
0397       }
0398     }
0399     return itFound->second->pProd_;
0400   }
0401 
0402   edm::WrapperBase const* DataGetterHelper::getByBranchID(edm::BranchID const& bid, Long_t eventEntry) const {
0403     auto itFound = bidToData_.find(bid);
0404 
0405     if (itFound == bidToData_.end()) {
0406       edm::BranchDescription const& bDesc = branchMap_->branchIDToBranch(bid);
0407       KeyToDataMap::iterator itData;
0408 
0409       if (!getByBranchDescription(bDesc, eventEntry, itData)) {
0410         return nullptr;
0411       }
0412       itFound = bidToData_.insert(std::make_pair(bid, itData->second)).first;
0413     }
0414     if (eventEntry != itFound->second->lastProduct_) {
0415       //haven't gotten the data for this event
0416       getBranchData(getter_.get(), eventEntry, *(itFound->second));
0417     }
0418     if (nullptr == itFound->second->pProd_) {
0419       itFound->second->pProd_ = wrapperBasePtr(itFound->second->obj_);
0420       if (nullptr == itFound->second->pProd_) {
0421         return nullptr;
0422       }
0423     }
0424     return itFound->second->pProd_;
0425   }
0426 
0427   edm::WrapperBase const* DataGetterHelper::wrapperBasePtr(edm::ObjectWithDict const& objectWithDict) const {
0428     // This converts a void* that points at a Wrapper<T>* into a WrapperBase*
0429     edm::TypeWithDict wrapperBaseTypeWithDict(typeid(edm::WrapperBase));
0430     return static_cast<edm::WrapperBase const*>(
0431         wrapperBaseTypeWithDict.pointerToBaseType(objectWithDict.address(), objectWithDict.typeOf()));
0432   }
0433 
0434   std::optional<std::tuple<edm::WrapperBase const*, unsigned int>> DataGetterHelper::getThinnedProduct(
0435       edm::ProductID const& pid, unsigned int key, Long_t eventEntry) const {
0436     return edm::detail::getThinnedProduct(
0437         pid,
0438         key,
0439         branchMap_->thinnedAssociationsHelper(),
0440         [this](edm::ProductID const& p) { return branchMap_->productToBranchID(p); },
0441         [this, eventEntry](edm::BranchID const& b) { return getThinnedAssociation(b, eventEntry); },
0442         [this, eventEntry](edm::ProductID const& p) { return getByProductID(p, eventEntry); });
0443   }
0444 
0445   void DataGetterHelper::getThinnedProducts(edm::ProductID const& pid,
0446                                             std::vector<edm::WrapperBase const*>& foundContainers,
0447                                             std::vector<unsigned int>& keys,
0448                                             Long_t eventEntry) const {
0449     edm::detail::getThinnedProducts(
0450         pid,
0451         branchMap_->thinnedAssociationsHelper(),
0452         [this](edm::ProductID const& p) { return branchMap_->productToBranchID(p); },
0453         [this, eventEntry](edm::BranchID const& b) { return getThinnedAssociation(b, eventEntry); },
0454         [this, eventEntry](edm::ProductID const& p) { return getByProductID(p, eventEntry); },
0455         foundContainers,
0456         keys);
0457   }
0458 
0459   edm::OptionalThinnedKey DataGetterHelper::getThinnedKeyFrom(edm::ProductID const& parentID,
0460                                                               unsigned int key,
0461                                                               edm::ProductID const& thinnedID,
0462                                                               Long_t eventEntry) const {
0463     edm::BranchID parent = branchMap_->productToBranchID(parentID);
0464     if (!parent.isValid())
0465       return std::monostate{};
0466     edm::BranchID thinned = branchMap_->productToBranchID(thinnedID);
0467     if (!thinned.isValid())
0468       return std::monostate{};
0469 
0470     try {
0471       auto ret = edm::detail::getThinnedKeyFrom_implementation(
0472           parentID,
0473           parent,
0474           key,
0475           thinnedID,
0476           thinned,
0477           branchMap_->thinnedAssociationsHelper(),
0478           [this, eventEntry](edm::BranchID const& branchID) { return getThinnedAssociation(branchID, eventEntry); });
0479       if (auto factory = std::get_if<edm::detail::GetThinnedKeyFromExceptionFactory>(&ret)) {
0480         return [func = *factory]() {
0481           auto ex = func();
0482           ex.addContext("Calling DataGetterHelper::getThinnedKeyFrom()");
0483           return ex;
0484         };
0485       } else {
0486         return ret;
0487       }
0488     } catch (edm::Exception& ex) {
0489       ex.addContext("Calling DataGetterHelper::getThinnedKeyFrom()");
0490       throw ex;
0491     }
0492   }
0493 
0494   edm::ThinnedAssociation const* DataGetterHelper::getThinnedAssociation(edm::BranchID const& branchID,
0495                                                                          Long_t eventEntry) const {
0496     edm::WrapperBase const* wrapperBase = getByBranchID(branchID, eventEntry);
0497     if (wrapperBase == nullptr) {
0498       throw edm::Exception(edm::errors::LogicError)
0499           << "DataGetterHelper::getThinnedAssociation, product ThinnedAssociation not found.\n";
0500     }
0501     if (!(typeid(edm::ThinnedAssociation) == wrapperBase->dynamicTypeInfo())) {
0502       throw edm::Exception(edm::errors::LogicError)
0503           << "DataGetterHelper::getThinnedAssociation, product has wrong type, not a ThinnedAssociation.\n";
0504     }
0505     edm::Wrapper<edm::ThinnedAssociation> const* wrapper =
0506         static_cast<edm::Wrapper<edm::ThinnedAssociation> const*>(wrapperBase);
0507 
0508     edm::ThinnedAssociation const* thinnedAssociation = wrapper->product();
0509     return thinnedAssociation;
0510   }
0511 
0512   const edm::ProcessHistory& DataGetterHelper::history() const { return historyGetter_->history(); }
0513 
0514   //
0515   // static member functions
0516   //
0517 }  // namespace fwlite