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
0204
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
0223
0224
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
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
0333
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
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
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 }
0412 using edmtest::ThinningTestAnalyzer;
0413 DEFINE_FWK_MODULE(ThinningTestAnalyzer);