Belle II Software  release-08-01-10
relations_internal.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include <framework/datastore/RelationIndex.h>
9 #include <framework/dataobjects/EventMetaData.h>
10 #include <framework/dataobjects/ProfileInfo.h>
11 #include <framework/datastore/RelationsObject.h>
12 #include <framework/utilities/TestHelpers.h>
13 
14 #include <gtest/gtest.h>
15 
16 using namespace std;
17 using namespace Belle2;
18 
19 namespace {
21  class RelationsInternal : public ::testing::Test {
22  protected:
24  void SetUp() override
25  {
26  DataStore::Instance().setInitializeActive(true);
27  evtData.registerInDataStore();
28  profileData.registerInDataStore();
29  relObjData.registerInDataStore();
30  DataStore::Instance().setInitializeActive(false);
31 
32  for (int i = 0; i < 10; ++i) {
33  evtData.appendNew();
34  profileData.appendNew();
35  relObjData.appendNew();
36  }
37  }
38 
40  void TearDown() override
41  {
42  DataStore::Instance().reset();
43  }
44 
45  void findRelationsCheckContents();
46 
48  StoreArray<ProfileInfo> profileData;
49  StoreArray<RelationsObject> relObjData;
50  };
51 
53  TEST_F(RelationsInternal, RelationCreate)
54  {
55  DataStore::Instance().setInitializeActive(true);
56  evtData.registerRelationTo(profileData);
57  DataStore::Instance().setInitializeActive(false);
58 
59  RelationArray relation(evtData, profileData);
60  EXPECT_FALSE(relation); //creation only happens on write access or explicitly
61  //since we provided arguments to constructor, these should be available even before create()
62  EXPECT_TRUE(relation.getFromAccessorParams() == evtData.getAccessorParams());
63  EXPECT_TRUE(relation.getToAccessorParams() == profileData.getAccessorParams());
64 
65  relation.create();
66  EXPECT_TRUE(relation);
67  EXPECT_TRUE(relation.getFromAccessorParams() == evtData.getAccessorParams());
68  EXPECT_TRUE(relation.getToAccessorParams() == profileData.getAccessorParams());
69  }
70 
72  TEST_F(RelationsInternal, RelationFind)
73  {
74  DataStore::Instance().setInitializeActive(true);
75  EXPECT_FALSE(evtData.optionalRelationTo(profileData));
76  EXPECT_FALSE(evtData.requireRelationTo(profileData));
77 
79  evtData.registerRelationTo(profileData);
80  evtData2.registerInDataStore("OwnName");
81  evtData2.registerRelationTo(profileData);
82  DataStore::Instance().setInitializeActive(false);
83 
84  RelationArray relation(evtData, profileData);
85  EXPECT_FALSE(RelationArray(DataStore::relationName(evtData.getName(), profileData.getName()), DataStore::c_Event));
86  relation.create();
87  EXPECT_TRUE(RelationArray(evtData, profileData, "", DataStore::c_Event));
88  string name = relation.getName();
89 
90  EXPECT_EQ("OwnName", evtData2.getName());
91 
92 
93  RelationArray relationAttachedUsingName(name, DataStore::c_Event);
94  //trying to get the accessor params should cause the array to attach (and thus get the appropriate data)
95  EXPECT_TRUE(relationAttachedUsingName.getFromAccessorParams() == evtData.getAccessorParams());
96  EXPECT_TRUE(relationAttachedUsingName.getToAccessorParams() == profileData.getAccessorParams());
97  EXPECT_TRUE(relationAttachedUsingName);
98 
99  //check for OwnNameToProfileInfos
100  EXPECT_FALSE(RelationArray(DataStore::relationName(evtData2.getName(), profileData.getName()), DataStore::c_Event));
101  EXPECT_FALSE(RelationArray("OwnNameToProfileInfos", DataStore::c_Event));
102  RelationArray relation2(evtData2, profileData);
103  relation2.create();
104  EXPECT_TRUE(relation2.getName() == "OwnNameToProfileInfos");
105  EXPECT_TRUE(RelationArray(evtData2, profileData));
106 
107  //outside of initialize() this should fail
108  EXPECT_B2FATAL(evtData.requireRelationTo(profileData));
109  }
110 
112  TEST_F(RelationsInternal, RelationWrongDeathTest)
113  {
114  DataStore::Instance().setInitializeActive(true);
115  RelationArray relation1(evtData, profileData, "test");
116  relation1.registerInDataStore();
117  DataStore::Instance().setInitializeActive(false);
118 
119  relation1.create();
120  EXPECT_B2FATAL(RelationArray(profileData, evtData, "test").isValid());
121  EXPECT_B2FATAL(RelationArray(profileData, evtData, "test").add(0, 0, 1.0));
122  EXPECT_B2FATAL(RelationArray(profileData, evtData, "test")[0]);
123  EXPECT_B2FATAL(RelationArray(profileData, evtData, "test").getModified());
124  }
125 
127  TEST_F(RelationsInternal, RegistrationWithDefaultNames)
128  {
129  //not registered yet
130  EXPECT_B2FATAL(relObjData[0]->addRelationTo(profileData[3]));
131  EXPECT_B2FATAL(DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[1], 2.0));
132 
133  DataStore::Instance().setInitializeActive(true);
134  relObjData.registerRelationTo(profileData);
135  evtData.registerRelationTo(profileData);
136  DataStore::Instance().setInitializeActive(false);
137 
138  //profileData has default name, so this should be ok now
139  relObjData[0]->addRelationTo(profileData[4]);
140  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[3], 2.0);
141  }
142 
147  TEST_F(RelationsInternal, RelationDefaultConstructed)
148  {
149  DataStore::Instance().setInitializeActive(true);
150  RelationArray array(evtData, profileData);
151  array.registerInDataStore();
152  DataStore::Instance().setInitializeActive(false);
153 
154  auto* rel = new RelationContainer(); //default constructed object, as written to file
155  ASSERT_TRUE(DataStore::Instance().createObject(rel, false, array));
156 
157  EXPECT_FALSE(array.isValid());
158 
159  //shouldn't die here
160  RelationIndex<EventMetaData, ProfileInfo> index(evtData, profileData);
161  }
162 
164  TEST_F(RelationsInternal, BuildIndex)
165  {
166  DataStore::Instance().setInitializeActive(true);
167  evtData.registerRelationTo(profileData);
168  DataStore::Instance().setInitializeActive(false);
169 
170  RelationArray relation(evtData, profileData);
171  relation.add(0, 0, 1.0);
172  relation.add(0, 1, 2.0);
173  relation.add(0, 2, 3.0);
174  relation.consolidate();
175  EXPECT_EQ(relation.getEntries(), 1);
176 
178  EXPECT_EQ(relIndex.size(), 3u);
179 
180  relation.add(1, 0, 1.0);
182  EXPECT_EQ(relIndex2.size(), 4u);
183  //Rebuilding index will affect old index. Should we copy index?
184  //Copy could be expensive and this should be a corner-case anyway
185  EXPECT_EQ(relIndex.size(), 4u);
186 
187  //check elements of last relation (both from objects point to to_obj)
188  const EventMetaData* first_from_obj = (evtData)[0];
189  const EventMetaData* from_obj = (evtData)[1];
190  const ProfileInfo* to_obj = (profileData)[0];
191  EXPECT_TRUE(first_from_obj == relIndex.getFirstElementTo(to_obj)->from);
192  EXPECT_TRUE(to_obj == relIndex.getFirstElementTo(to_obj)->to);
193  EXPECT_FLOAT_EQ(1.0, relIndex.getFirstElementTo(to_obj)->weight);
194  EXPECT_TRUE(first_from_obj == relIndex.getFirstElementTo(*to_obj)->from);
195  EXPECT_TRUE(to_obj == relIndex.getFirstElementFrom(from_obj)->to);
196  EXPECT_TRUE(to_obj == relIndex.getFirstElementFrom(*from_obj)->to);
197  EXPECT_TRUE(to_obj == relIndex.getFirstElementFrom(first_from_obj)->to);
198 
199  //check search for non-existing relations
200  EXPECT_TRUE(relIndex.getFirstElementTo(nullptr) == nullptr);
201  EXPECT_TRUE(relIndex.getFirstElementFrom(nullptr) == nullptr);
202  EXPECT_TRUE(relIndex.getFirstElementFrom(nullptr) == nullptr);
203  EXPECT_TRUE(relIndex.getFirstElementFrom((evtData)[4]) == nullptr);
204  EXPECT_TRUE(relIndex.getFirstElementTo((profileData)[3]) == nullptr);
205 
206  //check size of found element lists
207  {
208  int size(0);
209  double allweights(0);
210  for (auto& e : relIndex.getElementsFrom((evtData)[0])) {
211  ++size;
212  allweights += e.weight;
213  }
214  EXPECT_EQ(size, 3);
215  EXPECT_DOUBLE_EQ(allweights, 6.0);
216  }
217  {
218  int size(0);
219  double allweights(0);
220  for (auto& e : relIndex.getElementsTo((profileData)[0])) {
221  ++size;
222  allweights += e.weight;
223  }
224  EXPECT_EQ(size, 2);
225  EXPECT_DOUBLE_EQ(allweights, 2.0);
226  }
227  {
228  int size(0);
229  double allweights(0);
230  for (const auto& e : relIndex.getElementsTo((profileData)[4])) {
231  ++size;
232  allweights += e.weight;
233  }
234  EXPECT_EQ(size, 0);
235  EXPECT_DOUBLE_EQ(allweights, 0.0);
236  }
237  }
238 
240  TEST_F(RelationsInternal, InconsistentIndexDeathTest)
241  {
242  DataStore::Instance().setInitializeActive(true);
243  evtData.registerRelationTo(profileData);
244  DataStore::Instance().setInitializeActive(false);
245 
246  RelationArray relation(evtData, profileData);
247  relation.add(0, 10, 1.0);
249  EXPECT_B2FATAL(rel_t relIndex);
250  relation.clear();
251  relation.add(10, 0, 1.0);
252  EXPECT_B2FATAL(rel_t relIndex);
253  }
254 
255 
257  TEST_F(RelationsInternal, EmptyIndex)
258  {
259  DataStore::Instance().setInitializeActive(true);
260  evtData.registerRelationTo(profileData);
261  DataStore::Instance().setInitializeActive(false);
262 
264  EXPECT_FALSE(index);
265  EXPECT_EQ(index.size(), 0u);
266  EXPECT_EQ(index.getFromAccessorParams().first, "");
267  EXPECT_EQ(index.getToAccessorParams().first, "");
268  }
269 
271  TEST_F(RelationsInternal, WrongRelationIndexDeathTest)
272  {
273  StoreArray<EventMetaData> eventData("evts");
274 
275  DataStore::Instance().setInitializeActive(true);
276  RelationArray relation(profileData, evtData, "test");
277  relation.registerInDataStore();
278  RelationArray(evtData, profileData).registerInDataStore();
279  eventData.registerInDataStore();
280  RelationArray relation2(evtData, profileData, "test2");
281  relation2.registerInDataStore();
282  DataStore::Instance().setInitializeActive(false);
283 
284  relation.create();
286  EXPECT_B2FATAL(rel_t(evtData, profileData, "test"));
287  EXPECT_B2FATAL(rel_t("test"));
288 
289  relation2.create();
290  EXPECT_B2FATAL(rel_t(eventData, profileData, "test2"));
291 
292  //This relation works and points to evtData, not eventData.
293  //no check is performed, user is responsible to check
294  //using getFromAccessorParams and getToAccessorParams
295  EXPECT_TRUE(rel_t("test2"));
296  }
297 
299  void RelationsInternal::findRelationsCheckContents()
300  {
301  const EventMetaData* fromObj = (evtData)[0];
302  RelationVector<ProfileInfo> toRels = DataStore::getRelationsWithObj<ProfileInfo>(fromObj);
303  EXPECT_EQ(toRels.size(), 3u);
304  //this is assuming stable order, correct?
305  EXPECT_DOUBLE_EQ(toRels.weight(0), 1.0);
306  EXPECT_DOUBLE_EQ(toRels.weight(1), 2.0);
307  EXPECT_DOUBLE_EQ(toRels.weight(2), -3.0);
308 
309  EXPECT_TRUE(toRels.object(0) == (profileData)[0]);
310  EXPECT_TRUE(toRels.object(1) == (profileData)[1]);
311  EXPECT_TRUE(toRels.object(2) == (profileData)[2]);
312 
313  //test range-based for over RelationVector
314  int i = 0;
315  for (const ProfileInfo& prof : toRels) {
316  (void)prof; //variable unused
317  i++;
318  }
319  EXPECT_EQ(i, 3);
320 
321  const ProfileInfo* toObj = (profileData)[2];
322  RelationVector<EventMetaData> fromRels = DataStore::getRelationsWithObj<EventMetaData>(toObj);
323  EXPECT_EQ(fromRels.size(), 1u);
324  EXPECT_DOUBLE_EQ(fromRels.weight(0), -3.0);
325  EXPECT_TRUE(fromRels.object(0) == fromObj);
326  EXPECT_TRUE(fromRels[0] == fromObj);
327 
328  //some things that shouldn't return anything
329  EXPECT_EQ(DataStore::getRelationsWithObj<EventMetaData>(fromObj).size(), 0u);
330  }
331 
333  TEST_F(RelationsInternal, FindRelations)
334  {
335  DataStore::Instance().setInitializeActive(true);
336  evtData.registerRelationTo(profileData);
337  DataStore::Instance().setInitializeActive(false);
338 
339  //check non-existing relations (registered)
340  const EventMetaData* fromObj = (evtData)[0];
341  RelationVector<ProfileInfo> toRels = DataStore::getRelationsWithObj<ProfileInfo>(fromObj);
342  EXPECT_EQ(toRels.size(), 0u);
343  const ProfileInfo* toObj = (profileData)[2];
344  RelationVector<EventMetaData> fromRels = DataStore::getRelationsWithObj<EventMetaData>(toObj);
345  EXPECT_EQ(fromRels.size(), 0u);
346 
347  //check non-existing relations (unregistered)
348  RelationVector<EventMetaData> toRels2 = DataStore::getRelationsWithObj<EventMetaData>(fromObj);
349  EXPECT_EQ(toRels2.size(), 0u);
350  RelationVector<ProfileInfo> fromRels2 = DataStore::getRelationsWithObj<ProfileInfo>(toObj);
351  EXPECT_EQ(fromRels2.size(), 0u);
352 
353  RelationArray relation(evtData, profileData);
354  relation.add(0, 0, 1.0);
355  relation.add(0, 1, 2.0);
356  relation.add(0, 2, -3.0);
357 
358  findRelationsCheckContents();
359 
360 
361  //check that results don't change after consolidation
362  relation.consolidate();
363  findRelationsCheckContents();
364  }
365 
367  TEST_F(RelationsInternal, AddRelations)
368  {
369  DataStore::Instance().setInitializeActive(true);
370  evtData.registerRelationTo(profileData);
371  DataStore::Instance().setInitializeActive(false);
372 
373  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[0], 1.0);
374  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[1], 2.0);
375  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[2], -3.0);
376 
377  findRelationsCheckContents();
378  }
379 
381  TEST_F(RelationsInternal, GetRelationsWith)
382  {
383  DataStore::Instance().setInitializeActive(true);
384  evtData.registerRelationTo(profileData);
385  DataStore::Instance().setInitializeActive(false);
386 
387  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[0], 1.0);
388  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[1], 2.0);
389  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[2], 3.0);
390 
391  //some objects with no relations to given type
392  EXPECT_EQ(DataStore::getRelationsWithObj<EventMetaData>((evtData)[0]).size(), 0u);
393  EXPECT_EQ(DataStore::getRelationsWithObj<EventMetaData>((profileData)[3]).size(), 0u);
394 
395  RelationVector<ProfileInfo> profRels = DataStore::getRelationsWithObj<ProfileInfo>((evtData)[0]);
396  EXPECT_EQ(profRels.size(), 3u);
397  EXPECT_EQ(profRels.weight(0), 1.0); //should be positive
398 
399  RelationVector<EventMetaData> eventRels = DataStore::getRelationsWithObj<EventMetaData>((profileData)[0]);
400  EXPECT_EQ(eventRels.size(), 1u);
401  EXPECT_EQ(eventRels.weight(0), 1.0); //points to given object, same weight
402  }
403 
405  TEST_F(RelationsInternal, SearchAll)
406  {
407  //2nd array of this type
408  StoreArray<ProfileInfo> profileData2("ProfileInfos2");
409 
410  DataStore::Instance().setInitializeActive(true);
411  profileData2.registerInDataStore();
412  evtData.registerRelationTo(profileData);
413  evtData.registerRelationTo(profileData2);
414  DataStore::Instance().setInitializeActive(false);
415 
416  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[0], 1.0);
417  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[1], 2.0);
418  DataStore::Instance().addRelationFromTo((evtData)[0], (profileData)[2], -3.0);
419 
420  //add one object (plus relation) to the other array
421  profileData2.appendNew();
422  DataStore::Instance().addRelationFromTo((evtData)[0], profileData2[0], 42.0);
423 
424  //profileData2 shouldn't be searched by default when searching or EventMetaData objects
425  findRelationsCheckContents();
426 
427  //actually test "ALL" option
428  const EventMetaData* fromObj = (evtData)[0];
429  RelationVector<ProfileInfo> toRels = DataStore::getRelationsWithObj<ProfileInfo>(fromObj, "ALL");
430  EXPECT_EQ(toRels.size(), 4u);
431  //order might be anything, check sum of weights
432  double sum = 0.0;
433  for (int i = 0; i < (int)toRels.size(); i++) {
434  sum += toRels.weight(i);
435  }
436  EXPECT_DOUBLE_EQ(sum, 42.0 + 1 + 2 - 3);
437 
438  //finding with default TO name
439  EXPECT_EQ(DataStore::getRelationsWithObj<ProfileInfo>(fromObj, profileData.getName()).size(), 3u);
440  //finding with TO name of 2nd array
441  EXPECT_EQ(DataStore::getRelationsWithObj<ProfileInfo>(fromObj, profileData2.getName()).size(), 1u);
442  //and something that doesn't exist
443  EXPECT_EQ(DataStore::getRelationsWithObj<ProfileInfo>(fromObj, "DoesntExist").size(), 0u);
444 
445  const ProfileInfo* toObj = profileData2[0];
446  //object should also be found without specifying the name
447  EXPECT_EQ(DataStore::getRelationsWithObj<EventMetaData>(toObj).size(), 1u);
448  //or with 'ALL"
449  EXPECT_EQ(DataStore::getRelationsWithObj<EventMetaData>(toObj, "ALL").size(), 1u);
450  //and using a base class
451  EXPECT_EQ(DataStore::getRelationsWithObj<TObject>(toObj, "ALL").size(), 1u);
452 
453  //no relations to this type
454  EXPECT_EQ(DataStore::getRelationsWithObj<EventMetaData>(fromObj, "ALL").size(), 0u);
455  //should work again
456  EXPECT_EQ(DataStore::getRelationsWithObj<TObject>(fromObj, "ALL").size(), 4u);
457 
458  }
459 
460 
461  TEST_F(RelationsInternal, ListOfRelatedArrays)
462  {
463  //2nd array of this type
464  StoreArray<ProfileInfo> profileData2("ProfileInfos2");
465 
466  //nothing
467  EXPECT_EQ(0u, DataStore::Instance().getListOfRelatedArrays(profileData2).size());
468  EXPECT_EQ(0u, DataStore::Instance().getListOfRelatedArrays(profileData).size());
469  EXPECT_EQ(0u, DataStore::Instance().getListOfRelatedArrays(evtData).size());
470 
471  DataStore::Instance().setInitializeActive(true);
472  profileData2.registerInDataStore();
473  evtData.registerRelationTo(profileData);
474  evtData.registerRelationTo(profileData2);
475  DataStore::Instance().setInitializeActive(false);
476 
477  EXPECT_EQ(1u, DataStore::Instance().getListOfRelatedArrays(profileData2).size());
478  EXPECT_EQ(1u, DataStore::Instance().getListOfRelatedArrays(profileData).size());
479  EXPECT_EQ(2u, DataStore::Instance().getListOfRelatedArrays(evtData).size());
480 
481  EXPECT_EQ(evtData.getName(), DataStore::Instance().getListOfRelatedArrays(profileData2).at(0));
482  EXPECT_EQ(evtData.getName(), DataStore::Instance().getListOfRelatedArrays(profileData).at(0));
483  }
484 
485  TEST_F(RelationsInternal, StoreArray_clear_cleans_relations)
486  {
487  DataStore::Instance().setInitializeActive(true);
488  evtData.registerRelationTo(relObjData);
489  relObjData.registerRelationTo(profileData);
490  evtData.registerRelationTo(profileData);
491  DataStore::Instance().setInitializeActive(false);
492 
493  DataStore::Instance().addRelationFromTo((evtData)[0], (relObjData)[0], 1.0);
494  DataStore::Instance().addRelationFromTo((relObjData)[1], (profileData)[9], 1.0);
495  DataStore::Instance().addRelationFromTo((evtData)[1], (profileData)[1], 2.0);
496 
497  evtData.clear();
498  profileData.clear();
499 
500  EXPECT_EQ(DataStore::getRelationsWithObj<ProfileInfo>(relObjData[1]).size(), 0u);
501  EXPECT_EQ(DataStore::getRelationsWithObj<EventMetaData>(relObjData[0]).size(), 0u);
502  }
503 } // namespace
Store event, run, and experiment numbers.
Definition: EventMetaData.h:33
Store execution time and memory usage.
Definition: ProfileInfo.h:22
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:62
Class to store relations between StoreArrays in the DataStore.
Provides access to fast ( O(log n) ) bi-directional lookups on a specified relation.
Definition: RelationIndex.h:76
size_t size() const
Get the size of the index.
const Element * getFirstElementFrom(const FROM &from) const
Return a pointer to the first relation Element of the given object.
range_from getElementsFrom(const FROM *from) const
Return a range of all elements pointing from the given object.
const Element * getFirstElementTo(const TO &to) const
Return a pointer to the first relation Element of the given object.
range_to getElementsTo(const TO *to) const
Return a range of all elements pointing to the given object.
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
T * object(int index) const
Get object with index.
float weight(int index) const
Get weight with index.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
Definition: globalLabel.cc:72
bool isValid(EForwardBackward eForwardBackward)
Check whether the given enum instance is one of the valid values.
Abstract base class for different kinds of events.
const FROM * from
pointer of the element from which the relation points.
const TO * to
pointer of the element to which the relation points.
RelationElement::weight_type weight
weight of the relation.