This chapter builds on the examples so far to show how to process events that have come from an event builder. We specifically build this on the framework in the example: Peforming type independent processing.
The only differences between event built and non-event-built data are how the PHYSICS_EVENT ring item bodies are constructed. For event built data, these bodies consist of a size followed by a sequence of fragments. Each fragment has a header and a body. The body of each fragment is, itself, just another PHYSICS_EVENT ring item.
NSCLDAQ supplies the FragmentIndex
class.
This class is able to unravel event built data for you. In this
chapter, we're going to look at the changes to the
processor.cpp file needed to make
processEvent
capable of dealing with
an event that has been glued together from fragments by the
event builder.
The full code for this example is installed in $DAQROOT/share/recipes/eventbuilt
Here are the additions we needed to make to the top part of processor.cpp
FragmentIndex.h defines the
FragmentIndex
class we'll use to pick apart
the raw physics items. Once we've done that,
we'll use a CRingItemFactory
(defined in CRingItemFactory.h) to
construct a CPHysicsEventItem
from a pointer to
the ring item in each fragment.
Let's now look at the processEvent
code.
void CRingItemProcessor::processEvent(CPhysicsEventItem& item) { std::cout << "Event:\n"; std::cout << "Time stamp: " << item.getEventTimestamp() << " Output SourceId: " << item.getSourceId() << std::endl; FragmentIndex indexer( static_cast<uint16_t*>(item.getBodyPointer()) ); std::cout << "Event has " << indexer.getNumberFragments() << " fragments\n"; CRingItemFactory itemFactory; for (size_t i = 0; i < indexer.getNumberFragments(); i++) { FragmentInfo fragment(indexer.getFragment(i)); std::cout << "Fragment: " << i << " source id : " << fragment.s_sourceId << " timestamp: " << fragment.s_timestamp << std::endl; // Each item is a ring item. The itemhdr points to the ring item. // s_itembody points to the item body. uint8_t* pRawFrag = reinterpret_cast<uint8_t*>(fragment.s_itemhdr); CRingItem* pRawItem = itemFactory.createRingItem(pRawFrag); std::unique_ptr<CPhysicsEventItem> fragItem(dynamic_cast<CPhysicsEventItem*>(pRawItem)); std::cout << "Fragment: \n" << fragItem->toString() << std::endl; uint16_t* pBody = fragment.s_itembody; } }
FragmentIndex
object is to pass
it a pointer to the body of the ring item. The
FragmentIndex
class allows you
to iterate over the fragments either using STL like
iteration or by getting the size and indexing each fragment.
FragmentInfo
structure.
This has the following fields:
s_timestamp
The timestamp of the fragment. All of the fragment timestamps will be within the Glom coincidence window of the first fragment.
s_sourceId
The id of the sourcea that produced this fragment. Note the event builder allows fragments from the same sourcea to appear more than once in the event. This is an intentional feature.
s_size
The size of the fragment payload. This should match the size field of the embedded ring item.
s_barrier
The barrier type of the fragment. This should always be zero as physics events are not barrier events.
s_itemhdr
Points to the items header. This is the ring item header of the ring item that is the fragment payload.
s_itemBody
Pointer to the body of the ring item. This is correctly computed for items with and without body headers.
CPhysicsEvent
).
Since that ring item is dynamically allocated, we wrap it in
a std::unique_ptr
to ensure it is
destroyed when the block exits.
s_itembody
in the fragment description struct points to it. The
CRingItem
base class method
getBodyPointer
also returns a
pointer to the body.
Both are correct even if the event has no body header