Skip to content

FPGATrackSim: refactor output header tool to be more flexible

This grew out of the discussions at the recent EF tracking hackathon about splitting up the main LogicalHitsProcessAlg algorithm into multiple (at least three) algorithms. It turns out that one of the moving parts here is the "output header file" tool, which is responsible for creating the output ROOT file containing a TTree with the "input header" and "output header" C++ objects, storing the input hits and output roads and tracks. These are the files used for test vector generation.

This code was somewhat inflexible; it made a bunch of assumptions, including that there would always be two input header branches (one for the first stage, one for the second stage if turned on) and one output header branch. This was hardcoded, as were the branch names, and the interface for writing and reading files required passing around three pointers to these objects.

Since we plan to split up the main algorithm, the needs for these output files will change. We'll now have one "data prep" algorithm, which would in principle generate (at least) two input headers-- one with the pre-clustered hits and one with the post-clustered hits. (In fact, it could store additional copies of the input header to generate pre- and post- spacepoint formation test vectors as well). The second stage will then also become a separate algorithm, and so the inputs and outputs of that could be separated out as well.

This series of commits refactors this code:

  • The output header tool now has functions for creating a new input header or output header branch. (I could make this fully templated, but at that point this tool is basically just a wrapper around the TTree read/write interface, so... for now I've not done that). Algorithm code can set up as many branches as needed. This returns pointers to the input/output header objects, that can then be filled inside the algorithm code before being saved to the tree. The header objects then get reset after each write so they can be reused, and deleted when the file is closed.
  • For reading files-- something that we don't really seem to do-- the algorithm code needs to specify the names of the branches they want read via the same mechanism.
  • There were existing algorithms that read the output header file under FPGATrackSimInput, but they all seemed outdated and there doesn't appear to be any configuration for actually running them. I updated one of them, FPGATrackSimDumpOutputStatAlg, although it's not clear to me that we actually can run this at present and it doesn't do much anyway. I removed a couple of others. We arguably could get rid of FPGATrackSimDumpOutputStatAlg too but it seems useful to have at least one (placeholder?) algorithm for this. I think the idea was that the reading interface would be used for test vectors, but right now we are doing this in PyROOT instead.
  • I made the tree and branch names configurable. The tree name is a property on the output header tool; the branch names are algorithm-level properties. In principle they could be properties on the tool instead but right now the algorithm uses the property name as a "key", so it wasn't obvious to me what the best way to do this was.
  • I also changed the default branch names to just "LogicalEventInputHeader" and "LogicalEventOutputHeader" (removing the unwieldy "FPGATrackSim" from these names). The tree still has FPGATrackSim in the name.
  • And finally, I got rid of the interface class for this tool-- there is only one implementation of the tool, there's no need for an interface.

I updated LogicalHitsProcessAlg accordingly-- though this is subject to change once the algorithm is broken up. In initialize() it now does this to set up and retrieve references to the header objects:

    m_logicEventHeader_1st = m_writeOutputTool->addInputBranch(m_inputBranch.value(), true);
    
    m_logicEventOutputHeader = m_writeOutputTool->addOutputBranch(m_outputBranch.value(), true);
    if (m_runSecondStage) m_logicEventHeader_2nd = m_writeOutputTool->addInputBranch(m_inputBranch_2nd.value(), true);

And then in execute(), we fill the headers and then just call ATH_CHECK(m_writeOutputTool->writeData()). Hopefully this flexibility will make it easy to reuse this code in other algorithms.

A consequence of these changes is that we can probably get rid of the first vs second stage stuff in the output header class as well, so we no longer need e.g. getFPGATrackSimTracks_1st() and getFPGATrackSimTracks_2nd(), we can just have two copies of the class. I have yet to do that.

CC @jahreda, @tbold. I wanted to do this as a separate MR since it became somewhat involved. Happy to further adjust this interface if desired, especially the read side, which I've thought less about.

Merge request reports