File indexing completed on 2025-09-18 09:41:12
0001 #pragma once
0002 #include <JANA/JApplication.h>
0003 #include <JANA/JObject.h>
0004 #include <JANA/JEventSource.h>
0005 #include <JANA/JEventUnfolder.h>
0006 #include <JANA/JEventProcessor.h>
0007 #include <catch.hpp>
0008
0009 namespace jana {
0010 namespace timeslice_tests {
0011
0012
0013 struct MyHit : public JObject {
0014 int hit_id;
0015 int energy, x, y;
0016 };
0017
0018 struct MyCluster : public JObject {
0019 int cluster_id;
0020 int energy, x, y;
0021 std::vector<int> hits;
0022 };
0023
0024
0025 struct MyTimesliceSource : public JEventSource {
0026
0027 MyTimesliceSource() {
0028 SetLevel(JEventLevel::Timeslice);
0029 }
0030
0031 void Open() override { }
0032
0033 void GetEvent(std::shared_ptr<JEvent> event) override {
0034
0035 LOG_INFO(GetLogger()) << "MyTimesliceSource: Emitting " << event->GetEventNumber() << LOG_END;
0036 }
0037 };
0038
0039
0040 struct MyTimesliceUnfolder : public JEventUnfolder {
0041
0042 std::atomic_int init_called_count {0};
0043 mutable std::atomic_int preprocess_called_count {0};
0044 std::atomic_int unfold_called_count {0};
0045 std::atomic_int finish_called_count {0};
0046
0047 MyTimesliceUnfolder() {
0048 SetParentLevel(JEventLevel::Timeslice);
0049 SetChildLevel(JEventLevel::PhysicsEvent);
0050 }
0051
0052 virtual void Init() {
0053 init_called_count++;
0054 };
0055
0056 virtual void Preprocess(const JEvent& ) const {
0057 preprocess_called_count++;
0058
0059
0060 };
0061
0062 virtual Result Unfold(const JEvent& parent, JEvent& child, int item) {
0063 child.SetEventNumber(parent.GetEventNumber()*10 + item);
0064 LOG << "Unfolding parent=" << parent.GetEventNumber() << ", child=" << child.GetEventNumber() << ", item=" << item << LOG_END;
0065 unfold_called_count++;
0066
0067
0068 if (item == 3) {
0069 LOG_INFO(GetLogger()) << "Unfold found item 3, finishing join" << LOG_END;
0070
0071 return Result::NextChildNextParent;
0072 }
0073 return Result::NextChildKeepParent;
0074 }
0075
0076 virtual void Finish() {
0077 finish_called_count++;
0078 };
0079
0080 };
0081
0082 struct MyEventProcessor : public JEventProcessor {
0083
0084 std::atomic_int init_called_count {0};
0085 std::atomic_int process_called_count {0};
0086 std::atomic_int finish_called_count {0};
0087
0088 MyEventProcessor() {
0089 SetCallbackStyle(CallbackStyle::ExpertMode);
0090 }
0091
0092 void Init() override {
0093 init_called_count++;
0094 }
0095
0096 void ProcessSequential(const JEvent& event) override {
0097 process_called_count++;
0098 LOG_INFO(GetLogger()) << "MyEventProcessor: Processing " << event.GetEventNumber() << LOG_END;
0099 auto clusters = event.Get<MyCluster>("evt");
0100
0101 REQUIRE(init_called_count == 1);
0102 REQUIRE(finish_called_count == 0);
0103 }
0104
0105 void Finish() override {
0106 finish_called_count += 1;
0107 }
0108
0109 };
0110
0111
0112 struct MyProtoClusterFactory : public JFactoryT<MyCluster> {
0113
0114 int init_call_count = 0;
0115 int change_run_call_count = 0;
0116 int process_call_count = 0;
0117
0118 MyProtoClusterFactory() {
0119 SetLevel(JEventLevel::Timeslice);
0120 SetTag("ts");
0121 }
0122
0123 void Init() override {
0124 ++init_call_count;
0125 }
0126
0127 void ChangeRun(const std::shared_ptr<const JEvent>&) override {
0128 ++change_run_call_count;
0129 }
0130
0131 void Process(const std::shared_ptr<const JEvent>&) override {
0132 ++process_call_count;
0133 Insert(new MyCluster);
0134
0135 }
0136 };
0137
0138
0139 struct MyClusterFactory : public JFactoryT<MyCluster> {
0140
0141 int init_call_count = 0;
0142 int change_run_call_count = 0;
0143 int process_call_count = 0;
0144
0145 MyClusterFactory() {
0146 SetLevel(JEventLevel::PhysicsEvent);
0147 SetTag("evt");
0148 }
0149
0150 void Init() override {
0151 ++init_call_count;
0152 }
0153
0154 void ChangeRun(const std::shared_ptr<const JEvent>&) override {
0155 ++change_run_call_count;
0156 }
0157
0158 void Process(const std::shared_ptr<const JEvent>&) override {
0159 ++process_call_count;
0160 Insert(new MyCluster);
0161
0162 }
0163 };
0164
0165 }
0166
0167 namespace multilevel_source_tests {
0168
0169 struct MyCalibs {int x=0; };
0170 struct MyControls {int x=0; };
0171 struct MyHits {int x=0; };
0172
0173 struct MyMultilevelSource : public JEventSource {
0174
0175 std::vector<std::pair<JEventLevel, int>> data_stream;
0176 size_t data_stream_index = 0;
0177
0178 Output<MyCalibs> m_calibs_out {this};
0179 Output<MyControls> m_controls_out {this};
0180 Output<MyHits> m_hits_out {this};
0181
0182 MyMultilevelSource() {
0183 SetCallbackStyle(CallbackStyle::ExpertMode);
0184 SetEventLevels({JEventLevel::Run, JEventLevel::SlowControls, JEventLevel::PhysicsEvent});
0185
0186 m_calibs_out.SetLevel(JEventLevel::Run);
0187 m_controls_out.SetLevel(JEventLevel::SlowControls);
0188 m_hits_out.SetLevel(JEventLevel::PhysicsEvent);
0189 }
0190
0191 Result Emit(JEvent& event) override {
0192
0193 if (data_stream_index >= data_stream.size()) {
0194 return Result::FailureFinished;
0195 }
0196
0197 auto container_level = event.GetLevel();
0198 auto data_level = data_stream[data_stream_index].first;
0199
0200 if (container_level != data_level) {
0201 SetNextEventLevel(data_level);
0202 return JEventSource::Result::FailureLevelChange;
0203 }
0204
0205 if (data_level == JEventLevel::PhysicsEvent) {
0206 m_hits_out().push_back(new MyHits {data_stream[data_stream_index].second});
0207 }
0208 else if (data_level == JEventLevel::SlowControls) {
0209 m_controls_out().push_back(new MyControls {data_stream[data_stream_index].second});
0210 }
0211 else if (data_level == JEventLevel::Run) {
0212 m_calibs_out().push_back(new MyCalibs {data_stream[data_stream_index].second});
0213 }
0214
0215 data_stream_index += 1;
0216 return Result::Success;
0217 }
0218 };
0219
0220 struct MyMultilevelProcessor : public JEventProcessor {
0221
0222 std::vector<std::tuple<int, int, int>> expected_data_stream;
0223 std::vector<std::tuple<int, int, int>> actual_data_stream;
0224
0225 Input<MyCalibs> m_calibs_in {this};
0226 Input<MyControls> m_controls_in {this};
0227 Input<MyHits> m_hits_in {this};
0228
0229 MyMultilevelProcessor() {
0230 SetCallbackStyle(CallbackStyle::ExpertMode);
0231 m_calibs_in.SetLevel(JEventLevel::Run);
0232 m_calibs_in.SetOptional(true);
0233
0234 m_controls_in.SetLevel(JEventLevel::SlowControls);
0235 m_controls_in.SetOptional(true);
0236
0237 m_hits_in.SetLevel(JEventLevel::PhysicsEvent);
0238 m_hits_in.SetOptional(true);
0239 }
0240
0241 void ProcessSequential(const JEvent&) override {
0242
0243 int calib = m_calibs_in->size() == 0 ? -1 : m_calibs_in->at(0)->x;
0244 int control = m_controls_in->size() == 0 ? -1 : m_controls_in->at(0)->x;
0245 int hit = m_hits_in->size() == 0 ? -1 : m_hits_in->at(0)->x;
0246
0247 actual_data_stream.push_back({calib, control, hit});
0248 }
0249
0250 void Finish() override {
0251 REQUIRE(expected_data_stream == actual_data_stream);
0252 }
0253
0254 };
0255
0256
0257 }
0258 }