Accessing Events
Accessing from a SubRun
The example code bellow shows how to create SubRuns inside Runs, how to iterate over all the SubRuns in a Run, how to access a SubRun from a Run, and how to search for SubRuns.
main.cpp (show/hide)
#include <iostream>
#include <string>
#include <hepnos.hpp>
using namespace hepnos;
int main(int argc, char** argv) {
if(argc != 3) {
std::cerr << "Usage: " << argv[0] << "<protocol> <configfile>" << std::endl;
exit(-1);
}
DataStore datastore = DataStore::connect(argv[1], argv[2]);
// Get the root of the DataStore
DataSet root = datastore.root();
// Create a DataSet
DataSet example6 = root.createDataSet("example6");
// Create a Run 0
Run run = example6.createRun(0);
// Create a SubRun 13
SubRun subrun = run.createSubRun(13);
// Create 5 Events 42 ... 46
for(unsigned i = 0; i < 5; i++) {
subrun.createEvent(i+42);
}
// Iterate over the Events
std::cout << "Events:" << std::endl;
for(auto& event : subrun) {
std::cout << event.number() << std::endl;
}
// access a Event by its number
Event event43 = subrun[43];
// find the Event 43
SubRun::iterator it = subrun.find(43);
std::cout << it->number() << std::endl;
// lower_bound(43) will point to the Event 43
SubRun::iterator lb = subrun.lower_bound(43);
// upper_bound(43) will point to the Event 44
SubRun::iterator ub = subrun.upper_bound(43);
}
The SubRun class presents an interface very similar to that
of an std::map<EventNumber,Event>
, providing users
with begin
and end
functions to get forward
iterators, as well as find
, lower_bound
, and
upper_bound
to search for specific Events.
Events are sorted in increasing order of event number.
Accessing from a DataSet
Events are stored in SubRuns, hence they can be accessed from their parent SubRun, as shown above. They can also be accessed directly from their parent DataSet, providing a more convenient way of iterating through them without having to iterate through intermediate Run and SubRun levels.
The following example code shows how to use the
DataSet::events()
method to get an EventSet
object.
main.cpp (show/hide)
#include <iostream>
#include <string>
#include <hepnos.hpp>
using namespace hepnos;
int main(int argc, char** argv) {
if(argc != 3) {
std::cerr << "Usage: " << argv[0] << " <protocol> <configfile>" << std::endl;
exit(-1);
}
DataStore datastore = DataStore::connect(argv[1], argv[2]);
// Get the root of the DataStore
DataSet root = datastore.root();
// Create a DataSet
DataSet example7 = root.createDataSet("example7");
// Create 5 Runs with 5 SubRuns with 5 Events
std::cout << "Creating Runs, SubRuns, and Events" << std::endl;
for(unsigned i=0; i < 5; i++) {
auto run = example7.createRun(i);
for(unsigned j=0; j < 5; j++) {
auto subrun = run.createSubRun(j);
for(unsigned k=0; k < 5; k++) {
auto event = subrun.createEvent(k);
}
}
}
// Iterate over the events directly from the example7 DataSet
std::cout << "Iterating over all Events" << std::endl;
for(auto& event : example7.events()) {
SubRun subrun = event.subrun();
Run run = subrun.run();
std::cout << "Run " << run.number()
<< ", SubRun " << subrun.number()
<< ", Event " << event.number()
<< std::endl;
}
// Iterate target by target
std::cout << "Iterating over all Events target by target" << std::endl;
unsigned numTargets = datastore.numTargets(ItemType::EVENT);
for(unsigned target = 0; target < numTargets; target++) {
std::cout << "Target " << target << std::endl;
for(auto& event : example7.events(target)) {
SubRun subrun = event.subrun();
Run run = subrun.run();
std::cout << "Run " << run.number()
<< ", SubRun " << subrun.number()
<< ", Event " << event.number()
<< std::endl;
}
}
}
The EventSet object is a view of all the Events
inside a give DataSet. It provides begin
and
end
methods to iterate over the events.
The DataSet::events()
method can accept an integer
argument representing a given target number. The available
number of targets can be obtained using DataStore::numTargets()
,
passing ItemType::EVENT
to indicate that we are interested
in the number of targets that are used for storing events.
Passing such a target number to DataSet::events()
will restrict the view of the resulting EventSet to the Events
stored in that target. This feature allows parallel programs
to have distinct processes interact with distinct targets.
Note that the Events in an EventSet are not sorted lexicographically by (run number, subrun number, event number). Rather, the EventSet provides a number of guarantees on its ordering of Events:
In an EventSet restricted to a single target, the Events are sorted lexicographically by (run number, subrun number, event number).
All the Events of a given SubRun are gathered in the same target, hence an EventSet restricted to a single target will contain all the Events of a subset of SubRuns of a subset of Runs.
When iterating through an EventSet (whether it is restricted to a specific target or not), we are guaranteed to see all the Events of a SubRun before another SubRun starts.
In the above sample program, iterating over the global EventSet yields the same result as iterating over restricted EventSet by increasing target number.
This EventSet feature can be useful if one wants to have N clients iterate over all the events in a given dataset. Each client can retrieve events from a single or a subset of targets that way. However, we encourage the reader to consider using the ParallelEventProcess class in this situation, as it also provides load-balancing across clients.