Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-22 22:37:09

0001 #include "FWCore/Framework/interface/global/EDAnalyzer.h"
0002 #include "FWCore/Framework/interface/Event.h"
0003 #include "FWCore/Framework/interface/EventSetup.h"
0004 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0005 #include "FWCore/Utilities/interface/EDGetToken.h"
0006 #include "FWCore/Utilities/interface/Exception.h"
0007 #include "FWCore/Utilities/interface/InputTag.h"
0008 #include "FWCore/Framework/interface/MakerMacros.h"
0009 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0010 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0011 #include "DataFormats/Common/interface/ThinnedAssociation.h"
0012 #include "DataFormats/TestObjects/interface/Thing.h"
0013 #include "DataFormats/TestObjects/interface/ThingCollection.h"
0014 #include "DataFormats/TestObjects/interface/TrackOfThings.h"
0015 #include "DataFormats/Provenance/interface/ProductID.h"
0016 
0017 #include <vector>
0018 
0019 namespace edmtest {
0020 
0021   class ThinningTestAnalyzer : public edm::global::EDAnalyzer<> {
0022   public:
0023     explicit ThinningTestAnalyzer(edm::ParameterSet const& pset);
0024 
0025     static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0026 
0027     void analyze(edm::StreamID, edm::Event const& e, edm::EventSetup const& c) const override;
0028 
0029   private:
0030     edm::Handle<ThingCollection> getParent(edm::Event const& event) const;
0031     std::tuple<edm::Handle<ThingCollection>, edm::RefProd<ThingCollection>> getThinned(edm::Event const& event) const;
0032     edm::Handle<edm::ThinnedAssociation> getAssociation(edm::Event const& event) const;
0033     edm::Handle<TrackOfThingsCollection> getTrackCollection(edm::Event const& event) const;
0034 
0035     template <typename RefT>
0036     void testRefToParent(RefT const& ref,
0037                          std::string_view refName,
0038                          int const expectedValue,
0039                          int const eventOffset) const;
0040 
0041     template <typename RefT>
0042     void testRefToThinned(RefT const& ref,
0043                           std::string_view refName,
0044                           int const expectedValue,
0045                           int const eventOffset,
0046                           edm::ProductID const thinnedCollectionID) const;
0047 
0048     void testVectors(TrackOfThings const& track,
0049                      edm::RefProd<ThingCollection> const& thinnedRefProd,
0050                      edm::EDProductGetter const& productGetter,
0051                      int const eventOffset) const;
0052 
0053     void incrementExpectedValue(std::vector<int>::const_iterator& iter) const;
0054 
0055     edm::EDGetTokenT<ThingCollection> parentToken_;
0056     edm::EDGetTokenT<ThingCollection> thinnedToken_;
0057     edm::EDGetTokenT<edm::ThinnedAssociation> associationToken_;
0058     edm::EDGetTokenT<TrackOfThingsCollection> trackToken_;
0059 
0060     bool parentWasDropped_;
0061     std::vector<int> expectedParentContent_;
0062     bool thinnedWasDropped_;
0063     bool thinnedIsAlias_;
0064     bool refToParentIsAvailable_;
0065     std::vector<int> expectedThinnedContent_;
0066     std::vector<unsigned int> expectedIndexesIntoParent_;
0067     bool associationShouldBeDropped_;
0068     std::vector<int> expectedValues_;
0069     int parentSlimmedValueFactor_;
0070     int thinnedSlimmedValueFactor_;
0071     int refSlimmedValueFactor_;
0072   };
0073 
0074   ThinningTestAnalyzer::ThinningTestAnalyzer(edm::ParameterSet const& pset) {
0075     parentToken_ = consumes<ThingCollection>(pset.getParameter<edm::InputTag>("parentTag"));
0076     thinnedToken_ = mayConsume<ThingCollection>(pset.getParameter<edm::InputTag>("thinnedTag"));
0077     associationToken_ = mayConsume<edm::ThinnedAssociation>(pset.getParameter<edm::InputTag>("associationTag"));
0078     trackToken_ = consumes<TrackOfThingsCollection>(pset.getParameter<edm::InputTag>("trackTag"));
0079     parentWasDropped_ = pset.getParameter<bool>("parentWasDropped");
0080     if (!parentWasDropped_) {
0081       expectedParentContent_ = pset.getParameter<std::vector<int>>("expectedParentContent");
0082     }
0083     thinnedWasDropped_ = pset.getParameter<bool>("thinnedWasDropped");
0084     thinnedIsAlias_ = pset.getParameter<bool>("thinnedIsAlias");
0085     if (!thinnedWasDropped_) {
0086       expectedThinnedContent_ = pset.getParameter<std::vector<int>>("expectedThinnedContent");
0087     }
0088     refToParentIsAvailable_ = pset.getParameter<bool>("refToParentIsAvailable");
0089     associationShouldBeDropped_ = pset.getParameter<bool>("associationShouldBeDropped");
0090     if (!associationShouldBeDropped_) {
0091       expectedIndexesIntoParent_ = pset.getParameter<std::vector<unsigned int>>("expectedIndexesIntoParent");
0092     }
0093     expectedValues_ = pset.getParameter<std::vector<int>>("expectedValues");
0094 
0095     auto slimmedFactor = [](int count, int factor) {
0096       int ret = 1;
0097       for (int i = 0; i < count; ++i) {
0098         ret *= factor;
0099       }
0100       return ret;
0101     };
0102     int const slimmedValueFactor = pset.getParameter<int>("slimmedValueFactor");
0103     parentSlimmedValueFactor_ = slimmedFactor(pset.getParameter<int>("parentSlimmedCount"), slimmedValueFactor);
0104     thinnedSlimmedValueFactor_ = slimmedFactor(pset.getParameter<int>("thinnedSlimmedCount"), slimmedValueFactor);
0105     refSlimmedValueFactor_ = slimmedFactor(pset.getParameter<int>("refSlimmedCount"), slimmedValueFactor);
0106   }
0107 
0108   void ThinningTestAnalyzer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0109     edm::ParameterSetDescription desc;
0110     desc.add<edm::InputTag>("parentTag");
0111     desc.add<edm::InputTag>("thinnedTag");
0112     desc.add<edm::InputTag>("associationTag");
0113     desc.add<edm::InputTag>("trackTag");
0114     desc.add<bool>("parentWasDropped", false);
0115     desc.add<bool>("thinnedWasDropped", false);
0116     desc.add<bool>("thinnedIsAlias", false);
0117     desc.add<bool>("refToParentIsAvailable", true)
0118         ->setComment(
0119             "If Ref-to-parent is generally available. With thinnedRefFrom it may happen that the Ref-to-parent is not "
0120             "available, but the Ref-to-thinned is. In such case this parameter should be set to 'False', and the "
0121             "'expectedValues' should be set to correspond the values via Ref-to-thinned.");
0122     std::vector<int> defaultV;
0123     std::vector<unsigned int> defaultVU;
0124     desc.add<std::vector<int>>("expectedParentContent", defaultV);
0125     desc.add<std::vector<int>>("expectedThinnedContent", defaultV);
0126     desc.add<std::vector<unsigned int>>("expectedIndexesIntoParent", defaultVU);
0127     desc.add<bool>("associationShouldBeDropped", false);
0128     desc.add<std::vector<int>>("expectedValues");
0129     desc.add<int>("parentSlimmedCount", 0);
0130     desc.add<int>("thinnedSlimmedCount", 0);
0131     desc.add<int>("refSlimmedCount", 0);
0132     desc.add<int>("slimmedValueFactor", 10);
0133     descriptions.addDefault(desc);
0134   }
0135 
0136   void ThinningTestAnalyzer::analyze(edm::StreamID, edm::Event const& event, edm::EventSetup const&) const {
0137     auto parentCollection = getParent(event);
0138     auto [thinnedCollection, thinnedRefProd] = getThinned(event);
0139     auto associationCollection = getAssociation(event);
0140     auto trackCollection = getTrackCollection(event);
0141 
0142     if (!parentWasDropped_ && !associationShouldBeDropped_) {
0143       if (associationCollection->parentCollectionID() != parentCollection.id()) {
0144         throw cms::Exception("TestFailure") << "analyze parent ProductID is not correct";
0145       }
0146     }
0147 
0148     if (!thinnedWasDropped_ && !associationShouldBeDropped_) {
0149       if (associationCollection->thinnedCollectionID() != thinnedCollection.id()) {
0150         throw cms::Exception("TestFailure") << "analyze thinned ProductID is not correct";
0151       }
0152     }
0153 
0154     int const eventOffset = static_cast<int>(event.eventAuxiliary().event() * 100 + 100);
0155 
0156     std::vector<int>::const_iterator expectedValue = expectedValues_.begin();
0157     for (auto const& track : *trackCollection) {
0158       testRefToParent(track.ref1, "ref1", *expectedValue, eventOffset);
0159       if (not thinnedWasDropped_) {
0160         testRefToThinned(edm::thinnedRefFrom(track.ref1, thinnedRefProd, event.productGetter()),
0161                          "ref1",
0162                          *expectedValue,
0163                          eventOffset,
0164                          thinnedCollection.id());
0165       }
0166       testRefToParent(track.refToBase1, "refToBase1", *expectedValue, eventOffset);
0167       incrementExpectedValue(expectedValue);
0168 
0169       testRefToParent(track.ref2, "ref2", *expectedValue, eventOffset);
0170       if (not thinnedWasDropped_) {
0171         testRefToThinned(edm::thinnedRefFrom(track.ref2, thinnedRefProd, event.productGetter()),
0172                          "ref2",
0173                          *expectedValue,
0174                          eventOffset,
0175                          thinnedCollection.id());
0176       }
0177       incrementExpectedValue(expectedValue);
0178 
0179       testRefToParent(track.ptr1, "ptr1", *expectedValue, eventOffset);
0180       incrementExpectedValue(expectedValue);
0181 
0182       testRefToParent(track.ptr2, "ptr2", *expectedValue, eventOffset);
0183       incrementExpectedValue(expectedValue);
0184 
0185       testVectors(track, thinnedRefProd, event.productGetter(), eventOffset);
0186     }
0187   }
0188 
0189   edm::Handle<ThingCollection> ThinningTestAnalyzer::getParent(edm::Event const& event) const {
0190     auto parentCollection = event.getHandle(parentToken_);
0191 
0192     unsigned int i = 0;
0193     if (parentWasDropped_) {
0194       if (parentCollection.isValid()) {
0195         throw cms::Exception("TestFailure") << "parent collection present, should have been dropped";
0196       }
0197     } else if (!expectedParentContent_.empty()) {
0198       if (parentCollection->size() != expectedParentContent_.size()) {
0199         throw cms::Exception("TestFailure") << "parent collection has unexpected size, got " << parentCollection->size()
0200                                             << " expected " << expectedParentContent_.size();
0201       }
0202       for (auto const& thing : *parentCollection) {
0203         // Just some numbers that match the somewhat arbitrary values put in
0204         // by the ThingProducer.
0205         int expected = static_cast<int>(expectedParentContent_.at(i) + event.eventAuxiliary().event() * 100 + 100) *
0206                        parentSlimmedValueFactor_;
0207         if (thing.a != expected) {
0208           throw cms::Exception("TestFailure")
0209               << "parent collection has unexpected content, got " << thing.a << " expected " << expected;
0210         }
0211         ++i;
0212       }
0213     }
0214 
0215     return parentCollection;
0216   }
0217 
0218   std::tuple<edm::Handle<ThingCollection>, edm::RefProd<ThingCollection>> ThinningTestAnalyzer::getThinned(
0219       edm::Event const& event) const {
0220     auto thinnedCollection = event.getHandle(thinnedToken_);
0221 
0222     // Check to see the content is what we expect based on what was written
0223     // by ThingProducer and TrackOfThingsProducer. The values are somewhat
0224     // arbitrary and meaningless.
0225     edm::RefProd<ThingCollection> thinnedRefProd;
0226     if (thinnedWasDropped_) {
0227       if (thinnedCollection.isValid()) {
0228         throw cms::Exception("TestFailure") << "thinned collection present, should have been dropped";
0229       }
0230     } else {
0231       thinnedRefProd = edm::RefProd<ThingCollection>{thinnedCollection};
0232       unsigned expectedIndex = 0;
0233       if (thinnedCollection->size() != expectedThinnedContent_.size()) {
0234         throw cms::Exception("TestFailure")
0235             << "thinned collection has unexpected size, got " << thinnedCollection->size() << " expected "
0236             << expectedThinnedContent_.size();
0237       }
0238       for (auto const& thing : *thinnedCollection) {
0239         const int expected = (expectedThinnedContent_.at(expectedIndex) + event.eventAuxiliary().event() * 100 + 100) *
0240                              thinnedSlimmedValueFactor_;
0241         if (thing.a != expected) {
0242           throw cms::Exception("TestFailure")
0243               << "thinned collection has unexpected content, got " << thing.a << " expected " << expected;
0244         }
0245         ++expectedIndex;
0246       }
0247     }
0248     return std::tuple(thinnedCollection, thinnedRefProd);
0249   }
0250 
0251   edm::Handle<edm::ThinnedAssociation> ThinningTestAnalyzer::getAssociation(edm::Event const& event) const {
0252     auto associationCollection = event.getHandle(associationToken_);
0253     if (associationShouldBeDropped_ && associationCollection.isValid()) {
0254       throw cms::Exception("TestFailure") << "association collection should have been dropped but was not";
0255     }
0256     if (!associationShouldBeDropped_) {
0257       unsigned int expectedIndex = 0;
0258       if (associationCollection->indexesIntoParent().size() != expectedIndexesIntoParent_.size()) {
0259         throw cms::Exception("TestFailure") << "association collection has unexpected size";
0260       }
0261       for (auto const& association : associationCollection->indexesIntoParent()) {
0262         if (association != expectedIndexesIntoParent_.at(expectedIndex)) {
0263           throw cms::Exception("TestFailure")
0264               << "association collection has unexpected content, for index " << expectedIndex << " got " << association
0265               << " expected " << expectedIndexesIntoParent_.at(expectedIndex);
0266         }
0267         ++expectedIndex;
0268       }
0269     }
0270     return associationCollection;
0271   }
0272 
0273   edm::Handle<TrackOfThingsCollection> ThinningTestAnalyzer::getTrackCollection(edm::Event const& event) const {
0274     auto trackCollection = event.getHandle(trackToken_);
0275     if (trackCollection->size() != 5u) {
0276       throw cms::Exception("TestFailure") << "unexpected Track size";
0277     }
0278     return trackCollection;
0279   }
0280 
0281   template <typename RefT>
0282   void ThinningTestAnalyzer::testRefToParent(RefT const& ref,
0283                                              std::string_view refName,
0284                                              int const expectedValue,
0285                                              int const eventOffset) const {
0286     if (not refToParentIsAvailable_ or expectedValue == -1) {
0287       if (ref.isAvailable()) {
0288         throw cms::Exception("TestFailure")
0289             << refName << " is available when it should not be, refers to " << ref.id() << " key " << ref.key();
0290       }
0291     } else {
0292       if (!ref.isAvailable()) {
0293         throw cms::Exception("TestFailure") << refName << " is not available when it should be";
0294       }
0295       // Check twice to test some possible caching problems.
0296       const int expected = (expectedValue + eventOffset) * refSlimmedValueFactor_;
0297       if (ref->a != expected) {
0298         throw cms::Exception("TestFailure")
0299             << "Unexpected values from " << refName << ", got " << ref->a << " expected " << expected;
0300       }
0301       if (ref->a != expected) {
0302         throw cms::Exception("TestFailure")
0303             << "Unexpected values from " << refName << "  (2nd try), got " << ref->a << " expected " << expected;
0304       }
0305     }
0306   }
0307 
0308   template <typename RefT>
0309   void ThinningTestAnalyzer::testRefToThinned(RefT const& refToThinned,
0310                                               std::string_view refName,
0311                                               int const expectedValue,
0312                                               int const eventOffset,
0313                                               edm::ProductID const thinnedCollectionID) const {
0314     if (expectedValue == -1) {
0315       if (refToThinned.isNonnull()) {
0316         throw cms::Exception("TestFailure") << "thinnedRefFrom(" << refName << ") is non-null when it should be null";
0317       }
0318       if (refToThinned.isAvailable()) {
0319         throw cms::Exception("TestFailure") << "thinnedRefFrom(" << refName << ") is available when it should not be";
0320       }
0321     } else {
0322       if (refToThinned.isNull()) {
0323         throw cms::Exception("TestFailure") << "thinnedRefFrom(" << refName << ") is null when it should not be";
0324       }
0325       if (refToThinned.id() != thinnedCollectionID) {
0326         throw cms::Exception("TestFailure") << "thinnedRefFrom(" << refName << ").id() " << refToThinned.id()
0327                                             << " differs from expectation " << thinnedCollectionID;
0328       }
0329       if (not refToThinned.isAvailable()) {
0330         throw cms::Exception("TestFailure") << "thinnedRefFrom(" << refName << ") is not available when it should be";
0331       }
0332       // Check twice to test some possible caching problems.
0333       // need to account for slimming because going through an explicit ref-to-slimmed
0334       const int expected = (expectedValue + eventOffset) * thinnedSlimmedValueFactor_;
0335       if (refToThinned->a != expected) {
0336         throw cms::Exception("TestFailure") << "Unexpected values from thinnedRefFrom(" << refName << "), got "
0337                                             << refToThinned->a << " expected " << expected;
0338       }
0339       if (refToThinned->a != expected) {
0340         throw cms::Exception("TestFailure") << "Unexpected values from thinnedRefFrom(" << refName << ") (2nd try) "
0341                                             << refToThinned->a << " expected " << expected;
0342       }
0343     }
0344   }
0345 
0346   void ThinningTestAnalyzer::testVectors(TrackOfThings const& track,
0347                                          edm::RefProd<ThingCollection> const& thinnedRefProd,
0348                                          edm::EDProductGetter const& productGetter,
0349                                          int const eventOffset) const {
0350     // Test RefVector, PtrVector, and RefToBaseVector
0351     unsigned int k = 0;
0352     bool allPresent = true;
0353     for (auto iExpectedValue : expectedValues_) {
0354       if (iExpectedValue != -1) {
0355         if (not thinnedWasDropped_) {
0356           auto refToThinned = edm::thinnedRefFrom(track.refVector1[k], thinnedRefProd, productGetter);
0357           // need to account for slimming because going through an explicit ref-to-slimmed
0358           const int expected = (iExpectedValue + eventOffset) * thinnedSlimmedValueFactor_;
0359           if (refToThinned->a != expected) {
0360             throw cms::Exception("TestFailure") << "unexpected values from thinnedRefFrom(refVector1), got "
0361                                                 << refToThinned->a << " expected " << expected;
0362           }
0363         }
0364         if (refToParentIsAvailable_) {
0365           const int expected = (iExpectedValue + eventOffset) * refSlimmedValueFactor_;
0366           if (track.refVector1[k]->a != expected) {
0367             throw cms::Exception("TestFailure")
0368                 << "unexpected values from refVector1, got " << track.refVector1[k]->a << " expected " << expected;
0369           }
0370           if (track.ptrVector1[k]->a != expected) {
0371             throw cms::Exception("TestFailure") << "unexpected values from ptrVector1";
0372           }
0373           if (track.refToBaseVector1[k]->a != expected) {
0374             throw cms::Exception("TestFailure") << "unexpected values from refToBaseVector1";
0375           }
0376         }
0377       } else {
0378         allPresent = false;
0379       }
0380       ++k;
0381     }
0382 
0383     if (refToParentIsAvailable_ and allPresent) {
0384       if (!track.refVector1.isAvailable()) {
0385         throw cms::Exception("TestFailure") << "unexpected value (false) from refVector::isAvailable";
0386       }
0387       if (!track.ptrVector1.isAvailable()) {
0388         throw cms::Exception("TestFailure") << "unexpected value (false) from ptrVector::isAvailable";
0389       }
0390       if (!track.refToBaseVector1.isAvailable()) {
0391         throw cms::Exception("TestFailure") << "unexpected value (false) from refToBaseVector::isAvailable";
0392       }
0393     } else {
0394       if (track.refVector1.isAvailable()) {
0395         throw cms::Exception("TestFailure") << "unexpected value (true) from refVector::isAvailable";
0396       }
0397       if (track.ptrVector1.isAvailable()) {
0398         throw cms::Exception("TestFailure") << "unexpected value (true) from ptrVector::isAvailable";
0399       }
0400       if (track.refToBaseVector1.isAvailable()) {
0401         throw cms::Exception("TestFailure") << "unexpected value (true) from refToBaseVector::isAvailable";
0402       }
0403     }
0404   }
0405 
0406   void ThinningTestAnalyzer::incrementExpectedValue(std::vector<int>::const_iterator& iter) const {
0407     ++iter;
0408     if (iter == expectedValues_.end())
0409       iter = expectedValues_.begin();
0410   }
0411 }  // namespace edmtest
0412 using edmtest::ThinningTestAnalyzer;
0413 DEFINE_FWK_MODULE(ThinningTestAnalyzer);