Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-09 08:41:38

0001 // Copyright 2023, Jefferson Science Associates, LLC.
0002 // Subject to the terms in the LICENSE file found in the top-level directory.
0003 
0004 #pragma once
0005 
0006 #include <JANA/Topology/JArrow.h>
0007 #include <JANA/JEventUnfolder.h>
0008 
0009 class JUnfoldArrow : public JArrow {
0010 public:
0011     enum PortIndex {PARENT_IN=0, CHILD_IN=1, CHILD_OUT=2, PARENT_OUT=3};
0012 
0013 private:
0014     JEventUnfolder* m_unfolder = nullptr;
0015     JEvent* m_parent_event = nullptr;
0016     JEvent* m_child_event = nullptr;
0017 
0018 public:
0019     JUnfoldArrow(std::string name, JEventUnfolder* unfolder) : m_unfolder(unfolder) {
0020         SetName(name);
0021         auto parent_level = unfolder->GetLevel();
0022         auto child_level = unfolder->GetChildLevel();
0023         AddPort("parent_in", parent_level, PortDirection::In);
0024         AddPort("child_in", child_level, PortDirection::In);
0025         AddPort("child_out", child_level, PortDirection::Out).SetEstablishesOrdering(true);
0026         // Just in case there's a folder that needs this.
0027         // establishes_ordering is cheap; enforces_ordering is the expensive one
0028 
0029         AddPort("parent_out", parent_level, PortDirection::Out);
0030         m_next_input_port = GetPortIndex("parent_in");
0031     }
0032 
0033     void Initialize() final {
0034         m_unfolder->DoInit();
0035         LOG_INFO(m_logger) << "Initialized JEventUnfolder '" << m_unfolder->GetTypeName() << "'" << LOG_END;
0036     }
0037 
0038     void Finalize() final {
0039         m_unfolder->DoFinish();
0040         LOG_INFO(m_logger) << "Finalized JEventUnfolder '" << m_unfolder->GetTypeName() << "'" << LOG_END;
0041     }
0042 
0043     void Fire(JEvent* event, OutputData& outputs, size_t& output_count, JArrow::FireResult& status) final {
0044 
0045         // Take whatever we were given
0046         if (this->m_next_input_port == PARENT_IN) {
0047             assert(m_parent_event == nullptr);
0048             m_parent_event = event;
0049         }
0050         else if (this->m_next_input_port == CHILD_IN) {
0051             assert(m_child_event == nullptr);
0052             m_child_event = event;
0053         }
0054         else {
0055             throw JException("Invalid input port for JEventUnfolder!");
0056         }
0057 
0058         // Check if we should exit early because we don't have a parent event
0059         if (m_parent_event == nullptr) {
0060             m_next_input_port = PARENT_IN;
0061             output_count = 0;
0062             status = JArrow::FireResult::KeepGoing;
0063             return;
0064         }
0065 
0066         // Check if we should exit early because we don't have a child event
0067         if (m_child_event == nullptr) {
0068             m_next_input_port = CHILD_IN;
0069             output_count = 0;
0070             status = JArrow::FireResult::KeepGoing;
0071             return;
0072         }
0073 
0074         // At this point we know we have both inputs, so we can run the unfolder. First we validate 
0075         // that the events we received are at the correct level for the unfolder. Hopefully the only 
0076         // way to end up here is to override the JTopologyBuilder wiring and do it wrong
0077 
0078         if (m_parent_event->GetLevel() != m_unfolder->GetLevel()) {
0079             throw JException("JUnfolder: Expected parent with level %s, got %s", toString(m_unfolder->GetLevel()).c_str(), toString(m_parent_event->GetLevel()).c_str());
0080         }
0081 
0082         if (m_child_event->GetLevel() != m_unfolder->GetChildLevel()) {
0083             throw JException("JUnfolder: Expected child with level %s, got %s", toString(m_unfolder->GetChildLevel()).c_str(), toString(m_child_event->GetLevel()).c_str());
0084         }
0085 
0086         auto result = m_unfolder->DoUnfold(*m_parent_event, *m_child_event);
0087         LOG_DEBUG(m_logger) << "Unfold succeeded: Parent event = " << m_parent_event->GetEventNumber() << ", child event = " << m_child_event->GetEventNumber() << LOG_END;
0088 
0089         if (result == JEventUnfolder::Result::KeepChildNextParent) {
0090             // KeepChildNextParent is a little more complicated because we have to handle the case of the parent having no children.
0091             // In this case the parent obviously doesn't get shared among any children, and instead it is sent to the PARENT_OUT port.
0092             int child_count = m_parent_event->GetChildCount();
0093             LOG_DEBUG(m_logger) << "Unfold finished with parent event = " << m_parent_event->GetEventNumber() << " (" << child_count << " children emitted)";
0094 
0095             if (child_count > 0) {
0096                 // Parent DOES have children even though this particular child isn't one of them
0097                 m_parent_event = nullptr;
0098                 output_count = 0;
0099                 m_next_input_port = PARENT_IN;
0100                 status = JArrow::FireResult::KeepGoing;
0101                 return;
0102             }
0103             else {
0104                 // Parent has NO children
0105                 output_count = 1;
0106                 outputs[0] = {m_parent_event, PARENT_OUT};
0107                 m_parent_event = nullptr;
0108                 m_next_input_port = PARENT_IN;
0109                 status = JArrow::FireResult::KeepGoing;
0110                 return;
0111             }
0112         }
0113         else if (result == JEventUnfolder::Result::NextChildKeepParent) {
0114             m_child_event->SetParent(m_parent_event);
0115             outputs[0] = {m_child_event, CHILD_OUT};
0116             output_count = 1;
0117             m_child_event = nullptr;
0118             m_next_input_port = CHILD_IN;
0119             status = JArrow::FireResult::KeepGoing;
0120             return;
0121         }
0122         else if (result == JEventUnfolder::Result::NextChildNextParent) {
0123             m_child_event->SetParent(m_parent_event);
0124             outputs[0] = {m_child_event, CHILD_OUT};
0125             outputs[1] = {m_parent_event, PARENT_OUT};
0126             output_count = 2;
0127             LOG_DEBUG(m_logger) << "Unfold finished with parent event = " << m_parent_event->GetEventNumber() << LOG_END;
0128             m_child_event = nullptr;
0129             m_parent_event = nullptr;
0130             m_next_input_port = PARENT_IN;
0131             status = JArrow::FireResult::KeepGoing;
0132             return;
0133         }
0134         else {
0135             throw JException("Unsupported (corrupt?) JEventUnfolder::Result");
0136         }
0137     }
0138 };
0139 
0140