Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:53:25

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   internal::Data& DataGetterHelper::getBranchDataFor(std::type_info const& iInfo,
0151                                                      char const* iModuleLabel,
0152                                                      char const* iProductInstanceLabel,
0153                                                      char const* iProcessLabel) const {
0154     edm::TypeID type(iInfo);
0155     internal::DataKey key(type, iModuleLabel, iProductInstanceLabel, iProcessLabel);
0156 
0157     KeyToDataMap::iterator itFind = data_.find(key);
0158     if (itFind == data_.end()) {
0159       //see if such a branch actually exists
0160       std::string const sep("_");
0161       //CHANGE: If this fails, need to lookup the the friendly name which was used to write the file
0162       std::string name(type.friendlyClassName());
0163       name += sep + std::string(key.module());
0164       name += sep + std::string(key.product()) + sep;
0165 
0166       //if we have to lookup the process label, remember it and register the product again
0167       std::string foundProcessLabel;
0168       TBranch* branch = nullptr;
0169       std::shared_ptr<internal::Data> theData;
0170 
0171       if (nullptr == iProcessLabel || iProcessLabel == key.kEmpty() || strlen(iProcessLabel) == 0) {
0172         std::string const* lastLabel = nullptr;
0173         //have to search in reverse order since newest are on the bottom
0174         const edm::ProcessHistory& h = DataGetterHelper::history();
0175         for (edm::ProcessHistory::const_reverse_iterator iproc = h.rbegin(), eproc = h.rend(); iproc != eproc;
0176              ++iproc) {
0177           lastLabel = &(iproc->processName());
0178           branch = findBranch(tree_, name, iproc->processName());
0179           if (nullptr != branch) {
0180             break;
0181           }
0182         }
0183         if (nullptr == branch) {
0184           return branchNotFound;
0185         }
0186         //do we already have this one?
0187         if (nullptr != lastLabel) {
0188           internal::DataKey fullKey(type, iModuleLabel, iProductInstanceLabel, lastLabel->c_str());
0189           itFind = data_.find(fullKey);
0190           if (itFind != data_.end()) {
0191             //remember the data we've found
0192             theData = itFind->second;
0193           } else {
0194             //only set this if we don't already have it since it this string is not empty we re-register
0195             foundProcessLabel = *lastLabel;
0196           }
0197         }
0198       } else {
0199         //we have all the pieces
0200         branch = findBranch(tree_, name, key.process());
0201         if (nullptr == branch) {
0202           return branchNotFound;
0203         }
0204       }
0205 
0206       //cache the info
0207       size_t moduleLabelLen = strlen(iModuleLabel) + 1;
0208       char* newModule = new char[moduleLabelLen];
0209       std::strncpy(newModule, iModuleLabel, moduleLabelLen);
0210       labels_.push_back(newModule);
0211 
0212       char const* newProduct = kEmptyString;
0213       if (key.product()[0] != 0) {
0214         size_t newProductLen = strlen(key.product()) + 1;
0215         auto newProductTmp = new char[newProductLen];
0216         std::strncpy(newProductTmp, key.product(), newProductLen);
0217         newProduct = newProductTmp;
0218         labels_.push_back(newProduct);
0219       }
0220       char const* newProcess = kEmptyString;
0221       if (key.process()[0] != 0) {
0222         size_t newProcessLen = strlen(key.process()) + 1;
0223         auto newProcessTmp = new char[newProcessLen];
0224         std::strncpy(newProcessTmp, key.process(), newProcessLen);
0225         newProcess = newProcessTmp;
0226         labels_.push_back(newProcess);
0227       }
0228       internal::DataKey newKey(edm::TypeID(iInfo), newModule, newProduct, newProcess);
0229 
0230       if (nullptr == theData.get()) {
0231         //We do not already have this data as another key
0232 
0233         //create an instance of the object to be used as a buffer
0234         edm::TypeWithDict typeWithDict(iInfo);
0235         if (!bool(typeWithDict)) {
0236           throw cms::Exception("UnknownType") << "No dictionary exists for type " << iInfo.name();
0237         }
0238 
0239         edm::ObjectWithDict obj = edm::ObjectWithDict::byType(typeWithDict);
0240 
0241         if (obj.address() == nullptr) {
0242           throw cms::Exception("ConstructionFailed") << "failed to construct an instance of " << typeWithDict.name();
0243         }
0244         auto newData = std::make_shared<internal::Data>();
0245         newData->branch_ = branch;
0246         newData->obj_ = obj;
0247         newData->lastProduct_ = -1;
0248         newData->pObj_ = obj.address();
0249         newData->pProd_ = nullptr;
0250         branch->SetAddress(&(newData->pObj_));
0251         theData = newData;
0252       }
0253       itFind = data_.insert(std::make_pair(newKey, theData)).first;
0254 
0255       if (!foundProcessLabel.empty()) {
0256         //also remember it with the process label
0257         auto newProcessTmp = new char[foundProcessLabel.size() + 1];
0258         std::strcpy(newProcessTmp, foundProcessLabel.c_str());
0259         newProcess = newProcessTmp;
0260         labels_.push_back(newProcess);
0261         internal::DataKey newKeyWithProcess(edm::TypeID(iInfo), newModule, newProduct, newProcess);
0262 
0263         data_.insert(std::make_pair(newKeyWithProcess, theData));
0264       }
0265     }
0266     return *(itFind->second);
0267   }
0268 
0269   std::string const DataGetterHelper::getBranchNameFor(std::type_info const& iInfo,
0270                                                        char const* iModuleLabel,
0271                                                        char const* iProductInstanceLabel,
0272                                                        char const* iProcessLabel) const {
0273     internal::Data& theData =
0274         DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
0275 
0276     if (nullptr != theData.branch_) {
0277       return std::string(theData.branch_->GetName());
0278     }
0279     return std::string("");
0280   }
0281 
0282   bool DataGetterHelper::getByLabel(std::type_info const& iInfo,
0283                                     char const* iModuleLabel,
0284                                     char const* iProductInstanceLabel,
0285                                     char const* iProcessLabel,
0286                                     void* oData,
0287                                     Long_t eventEntry) const {
0288     // Maintain atEnd() check in parent classes
0289     void** pOData = reinterpret_cast<void**>(oData);
0290     *pOData = nullptr;
0291 
0292     internal::Data& theData =
0293         DataGetterHelper::getBranchDataFor(iInfo, iModuleLabel, iProductInstanceLabel, iProcessLabel);
0294 
0295     if (nullptr != theData.branch_) {
0296       if (eventEntry != theData.lastProduct_) {
0297         //haven't gotten the data for this event
0298         getBranchData(getter_.get(), eventEntry, theData);
0299       }
0300       *pOData = theData.obj_.address();
0301     }
0302 
0303     if (nullptr == *pOData)
0304       return false;
0305     else
0306       return true;
0307   }
0308 
0309   bool DataGetterHelper::getByBranchDescription(edm::BranchDescription const& bDesc,
0310                                                 Long_t eventEntry,
0311                                                 KeyToDataMap::iterator& itData) const {
0312     if (!bDesc.branchID().isValid()) {
0313       return false;
0314     }
0315 
0316     //Calculate the key from the branch description
0317     edm::TypeWithDict typeWD(edm::TypeWithDict::byName(edm::wrappedClassName(bDesc.fullClassName())));
0318     edm::TypeID type(typeWD.typeInfo());
0319     assert(bool(type));
0320 
0321     //Only the product instance label may be empty
0322     char const* pIL = bDesc.productInstanceName().c_str();
0323     if (pIL[0] == 0) {
0324       pIL = nullptr;
0325     }
0326     internal::DataKey k(type, bDesc.moduleLabel().c_str(), pIL, bDesc.processName().c_str());
0327 
0328     //has this already been gotten?
0329     itData = data_.find(k);
0330     if (data_.end() == itData) {
0331       //ask for the data
0332       edm::WrapperBase const* dummy = nullptr;
0333       getByLabel(type.typeInfo(), k.module(), k.product(), k.process(), &dummy, eventEntry);
0334       if (nullptr == dummy) {
0335         return false;
0336       }
0337       itData = data_.find(k);
0338       assert(itData != data_.end());
0339       assert(dummy == itData->second->obj_.address());
0340     }
0341     return true;
0342   }
0343 
0344   edm::WrapperBase const* DataGetterHelper::getByProductID(edm::ProductID const& iID, Long_t eventEntry) const {
0345     typedef std::pair<edm::ProductID, edm::BranchListIndex> IDPair;
0346     IDPair theID = std::make_pair(iID, branchMap_->branchListIndexes()[iID.processIndex() - 1]);
0347     std::map<IDPair, std::shared_ptr<internal::Data>>::const_iterator itFound = idToData_.find(theID);
0348 
0349     if (itFound == idToData_.end()) {
0350       edm::BranchDescription const& bDesc = branchMap_->productToBranch(iID);
0351       KeyToDataMap::iterator itData;
0352 
0353       if (!getByBranchDescription(bDesc, eventEntry, itData)) {
0354         return nullptr;
0355       }
0356       itFound = idToData_.insert(std::make_pair(theID, itData->second)).first;
0357     }
0358     if (eventEntry != itFound->second->lastProduct_) {
0359       //haven't gotten the data for this event
0360       getBranchData(getter_.get(), eventEntry, *(itFound->second));
0361     }
0362     if (nullptr == itFound->second->pProd_) {
0363       itFound->second->pProd_ = wrapperBasePtr(itFound->second->obj_);
0364       if (nullptr == itFound->second->pProd_) {
0365         return nullptr;
0366       }
0367     }
0368     return itFound->second->pProd_;
0369   }
0370 
0371   edm::WrapperBase const* DataGetterHelper::getByBranchID(edm::BranchID const& bid, Long_t eventEntry) const {
0372     auto itFound = bidToData_.find(bid);
0373 
0374     if (itFound == bidToData_.end()) {
0375       edm::BranchDescription const& bDesc = branchMap_->branchIDToBranch(bid);
0376       KeyToDataMap::iterator itData;
0377 
0378       if (!getByBranchDescription(bDesc, eventEntry, itData)) {
0379         return nullptr;
0380       }
0381       itFound = bidToData_.insert(std::make_pair(bid, itData->second)).first;
0382     }
0383     if (eventEntry != itFound->second->lastProduct_) {
0384       //haven't gotten the data for this event
0385       getBranchData(getter_.get(), eventEntry, *(itFound->second));
0386     }
0387     if (nullptr == itFound->second->pProd_) {
0388       itFound->second->pProd_ = wrapperBasePtr(itFound->second->obj_);
0389       if (nullptr == itFound->second->pProd_) {
0390         return nullptr;
0391       }
0392     }
0393     return itFound->second->pProd_;
0394   }
0395 
0396   edm::WrapperBase const* DataGetterHelper::wrapperBasePtr(edm::ObjectWithDict const& objectWithDict) const {
0397     // This converts a void* that points at a Wrapper<T>* into a WrapperBase*
0398     edm::TypeWithDict wrapperBaseTypeWithDict(typeid(edm::WrapperBase));
0399     return static_cast<edm::WrapperBase const*>(
0400         wrapperBaseTypeWithDict.pointerToBaseType(objectWithDict.address(), objectWithDict.typeOf()));
0401   }
0402 
0403   std::optional<std::tuple<edm::WrapperBase const*, unsigned int>> DataGetterHelper::getThinnedProduct(
0404       edm::ProductID const& pid, unsigned int key, Long_t eventEntry) const {
0405     return edm::detail::getThinnedProduct(
0406         pid,
0407         key,
0408         branchMap_->thinnedAssociationsHelper(),
0409         [this](edm::ProductID const& p) { return branchMap_->productToBranchID(p); },
0410         [this, eventEntry](edm::BranchID const& b) { return getThinnedAssociation(b, eventEntry); },
0411         [this, eventEntry](edm::ProductID const& p) { return getByProductID(p, eventEntry); });
0412   }
0413 
0414   void DataGetterHelper::getThinnedProducts(edm::ProductID const& pid,
0415                                             std::vector<edm::WrapperBase const*>& foundContainers,
0416                                             std::vector<unsigned int>& keys,
0417                                             Long_t eventEntry) const {
0418     edm::detail::getThinnedProducts(
0419         pid,
0420         branchMap_->thinnedAssociationsHelper(),
0421         [this](edm::ProductID const& p) { return branchMap_->productToBranchID(p); },
0422         [this, eventEntry](edm::BranchID const& b) { return getThinnedAssociation(b, eventEntry); },
0423         [this, eventEntry](edm::ProductID const& p) { return getByProductID(p, eventEntry); },
0424         foundContainers,
0425         keys);
0426   }
0427 
0428   edm::OptionalThinnedKey DataGetterHelper::getThinnedKeyFrom(edm::ProductID const& parentID,
0429                                                               unsigned int key,
0430                                                               edm::ProductID const& thinnedID,
0431                                                               Long_t eventEntry) const {
0432     edm::BranchID parent = branchMap_->productToBranchID(parentID);
0433     if (!parent.isValid())
0434       return std::monostate{};
0435     edm::BranchID thinned = branchMap_->productToBranchID(thinnedID);
0436     if (!thinned.isValid())
0437       return std::monostate{};
0438 
0439     try {
0440       auto ret = edm::detail::getThinnedKeyFrom_implementation(
0441           parentID,
0442           parent,
0443           key,
0444           thinnedID,
0445           thinned,
0446           branchMap_->thinnedAssociationsHelper(),
0447           [this, eventEntry](edm::BranchID const& branchID) { return getThinnedAssociation(branchID, eventEntry); });
0448       if (auto factory = std::get_if<edm::detail::GetThinnedKeyFromExceptionFactory>(&ret)) {
0449         return [func = *factory]() {
0450           auto ex = func();
0451           ex.addContext("Calling DataGetterHelper::getThinnedKeyFrom()");
0452           return ex;
0453         };
0454       } else {
0455         return ret;
0456       }
0457     } catch (edm::Exception& ex) {
0458       ex.addContext("Calling DataGetterHelper::getThinnedKeyFrom()");
0459       throw ex;
0460     }
0461   }
0462 
0463   edm::ThinnedAssociation const* DataGetterHelper::getThinnedAssociation(edm::BranchID const& branchID,
0464                                                                          Long_t eventEntry) const {
0465     edm::WrapperBase const* wrapperBase = getByBranchID(branchID, eventEntry);
0466     if (wrapperBase == nullptr) {
0467       throw edm::Exception(edm::errors::LogicError)
0468           << "DataGetterHelper::getThinnedAssociation, product ThinnedAssociation not found.\n";
0469     }
0470     if (!(typeid(edm::ThinnedAssociation) == wrapperBase->dynamicTypeInfo())) {
0471       throw edm::Exception(edm::errors::LogicError)
0472           << "DataGetterHelper::getThinnedAssociation, product has wrong type, not a ThinnedAssociation.\n";
0473     }
0474     edm::Wrapper<edm::ThinnedAssociation> const* wrapper =
0475         static_cast<edm::Wrapper<edm::ThinnedAssociation> const*>(wrapperBase);
0476 
0477     edm::ThinnedAssociation const* thinnedAssociation = wrapper->product();
0478     return thinnedAssociation;
0479   }
0480 
0481   const edm::ProcessHistory& DataGetterHelper::history() const { return historyGetter_->history(); }
0482 
0483   //
0484   // static member functions
0485   //
0486 }  // namespace fwlite