Refactor Event ownership, event level processing and add LoLXTTreeWriter
Description
Event Ownership
Each processor now takes an Event in the constructor instead of passing the Event to the processEvent()
method. The Event is a shared_ptr in order to properly manage shared ownership and deleting of the Event to avoid memory leaks. Each processor (derived from IEventProcessor
or for readers, DataFile
) stores the shared_ptr as mEvent
. The base class (IEventProcessor
) does not contain the mEvent
variable in order to allow different event types to be stored based on the specific requirements for the each case.
Event Types
Specialized Event types such as LoLXEvent
can be created by inheriting from the Event
class. The reader that uses this event type must take it as a parameter. Initialize event
to the correct type such as event = std::make_shared<LoLXEvent>();
in RunManager::createReader
and cast the event to the desired type before creating the DataFile using std::dynamic_pointer_cast
such as in V1740Factory.cxx
.
Event Level Processing
Event level processing can take place on any type of Event
. If the processing requires specific variables, it should take the correct event type that contains these variables such as LoLXEventProcessor
takes a LoLXEvent
. In RunManager::createEventLevelProcessor
, cast event
to the desired type using std::dynamic_pointer_cast
and check that the cast was successful (if not successful, the result will be nullptr/0). If a user selects LOLX
for the event processor strategy in the config file, but has not used V1740
as the device/reader, it will fail because the event was not created as a LoLXEvent
. Pass the result of the cast to the processor constructor if it was successful.
TTreeWriter
When using an Event Level Processor or an event type that has more variables than the base Event
class, create a new TTreeWriter derived class. For example, the LoLXTTreeWriter
. Add a branch for each variable in the constructor and set the branch variables in pushEventVariables()
. The specific writer should be constructed with a shared pointer of the correct event type as a parameter and store it as mEvent
to be used in pushEventVariables()
. In the PulseWriteProcessor
constructor, specify the correct TTreeWriter to use based on the EventLevelProcessor selected. For the LoLXTTreeWriter example, if channelCfg.eventStrategy == "LOLX"
, then the writing strategy should be forced to be LoLXTTreeWriter
. Since this writers takes std::shared_ptr<LoLXEvent>
, the event must be cast to the correct type before creating the writer.
Testing
Testing LoLX specific functionality:
- Use a config file that uses the V1740 reader(Device)
- Make sure
"EventProcessor": "LOLX",
is in theChannelConfigs
and it is usingTTreeWriter
- Run
./bin/vanwftk <path to config file>
- It should run without errors
- The outputted TTree should contain
multiplicity
andfirstPulseTime
(if run without"EventProcessor": "LOLX",
the TTree should not contain these variables)
Testing dynamic casting fails correctly:
- Use a config file that uses a reader(Device) other than V1740 (e.g. experiments/example.json)
- Add
"EventProcessor": "LOLX",
to theChannelConfigs
- Run
./bin/vanwftk <path to config file>
- It should fail and output
Cannot use LOLX event processor for this Event. Must use LoLXEvent (V1740).