diff --git a/.github/halld_recon_build.sh b/.github/halld_recon_build.sh
index e2c405132..0d4d59b7d 100644
--- a/.github/halld_recon_build.sh
+++ b/.github/halld_recon_build.sh
@@ -7,15 +7,9 @@ mkdir -p /cvmfs/oasis.opensciencegrid.org
mount -t cvmfs oasis.opensciencegrid.org /cvmfs/oasis.opensciencegrid.org
ln -s /cvmfs/oasis.opensciencegrid.org/gluex/group /group
-export BMS_OSNAME_OVERRIDE="Linux_Alma9-x86_64-gcc11.4.1-cntr"
-# The BMS_OSNAME override is needed because Alma9 retroactively switched its system gcc
-# from 11.4.1 to 11.5. We cannot create a new Alma9 container that uses gcc11.4.1, but
-# the CVMFS artifact repository hasn't been updated to reflect that.
-
source /group/halld/Software/build_scripts/gluex_env_boot_jlab.sh
-gxenv /workspace/JANA2/.github/halld_recon_build_prereqs_version.xml
+gxenv /workspace/JANA2/.github/version.xml
echo "ROOTSYS=$ROOTSYS"
cd /workspace/halld_recon/src
scons install -j12 DEBUG=1 OPTIMIZATION=0 SHOWBUILD=1
-
diff --git a/.github/halld_recon_build_prereqs_version.xml b/.github/halld_recon_build_prereqs_version.xml
deleted file mode 100644
index 9a43c1c81..000000000
--- a/.github/halld_recon_build_prereqs_version.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-Update to amptools, gluex_root_analysis, halld_recont, halld_sim, hdgeant4, hd_utilities
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.github/jana_build.sh b/.github/jana_build.sh
index 5672f6d1b..5647fcc9c 100644
--- a/.github/jana_build.sh
+++ b/.github/jana_build.sh
@@ -13,7 +13,7 @@ export JANA_HOME=$PROJECT_ROOT/JANA2
export JANA_PLUGIN_PATH=$PROJECT_ROOT/JANA2/plugins
source $BUILD_SCRIPTS/gluex_env_boot_jlab.sh --bs $BUILD_SCRIPTS
-gxenv $PROJECT_ROOT/JANA2/.github/jana_prereqs_version.xml
+gxenv $PROJECT_ROOT/JANA2/.github/version.xml
echo "jana_home value: $JANA_HOME"
diff --git a/.github/jana_prereqs_version.xml b/.github/jana_prereqs_version.xml
deleted file mode 100644
index f40682d12..000000000
--- a/.github/jana_prereqs_version.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-Update to amptools, gluex_root_analysis, halld_recont, halld_sim, hdgeant4, hd_utilities
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.github/version.xml b/.github/version.xml
new file mode 100644
index 000000000..922c2eeca
--- /dev/null
+++ b/.github/version.xml
@@ -0,0 +1,28 @@
+
+
+
+Bugfix in halld_recon, based on root6.32.08 and compiled with c++20.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/workflows/halld_recon.yml b/.github/workflows/halld_recon.yml
index 0fccf8988..19b3aaffd 100644
--- a/.github/workflows/halld_recon.yml
+++ b/.github/workflows/halld_recon.yml
@@ -28,7 +28,7 @@ jobs:
--platform linux/amd64 \
--privileged \
--mount type=bind,source=${{ github.workspace }},target=/workspace \
- raiqarasool/gluex_build:cvmfs /bin/bash -c "source /workspace/JANA2/.github/jana_build.sh"
+ codecr.jlab.org/nbrei/jana2-ci/jana2_devenv_alma9:latest /bin/bash -c "source /workspace/JANA2/.github/jana_build.sh"
- name: Git Clone Halld_recon
run: |
@@ -42,7 +42,7 @@ jobs:
--platform linux/amd64 \
--privileged \
--mount type=bind,source=${{ github.workspace }},target=/workspace \
- raiqarasool/gluex_build:cvmfs /bin/bash -c "source /workspace/JANA2/.github/halld_recon_build.sh"
+ codecr.jlab.org/nbrei/jana2-ci/jana2_devenv_alma9:latest /bin/bash -c "source /workspace/JANA2/.github/halld_recon_build.sh"
- name: Cleaning up created folders
if: always()
diff --git a/src/libraries/JANA/CMakeLists.txt b/src/libraries/JANA/CMakeLists.txt
index e423cda2e..14457ea11 100644
--- a/src/libraries/JANA/CMakeLists.txt
+++ b/src/libraries/JANA/CMakeLists.txt
@@ -32,6 +32,7 @@ set(JANA2_SOURCES
Components/JComponentSummary.cc
Components/JDatabundle.cc
Components/JHasInputs.cc
+ Components/JHasOutputs.cc
Utils/JCpuInfo.cc
Utils/JProcessorMapping.cc
diff --git a/src/libraries/JANA/Components/JHasInputs.cc b/src/libraries/JANA/Components/JHasInputs.cc
index ef65ba015..92bd8d60c 100644
--- a/src/libraries/JANA/Components/JHasInputs.cc
+++ b/src/libraries/JANA/Components/JHasInputs.cc
@@ -57,7 +57,7 @@ void JHasInputs::VariadicInputBase::TriggerFactoryCreate(const JEvent& event) {
}
throw JException("Could not find parent at level=" + toString(m_level));
}
- if (!m_realized_databundle_names.empty()) {
+ if (!m_requested_databundle_names.empty()) {
for (auto& tag : m_requested_databundle_names) {
auto coll = facset->GetDatabundle(m_type_index, tag);
if (coll == nullptr && !m_is_optional) {
diff --git a/src/libraries/JANA/Components/JHasInputs.h b/src/libraries/JANA/Components/JHasInputs.h
index 0bce3c4bf..64918fd2b 100644
--- a/src/libraries/JANA/Components/JHasInputs.h
+++ b/src/libraries/JANA/Components/JHasInputs.h
@@ -139,6 +139,9 @@ struct JHasInputs {
void SetRequestedDatabundleNames(std::vector names) {
m_requested_databundle_names = names;
m_realized_databundle_names = names;
+ // If options.names are empty, m_realized_databundle_names will be filled later
+ // Otherwise, m_realized_databundle_names always matches m_requested_databundle_names
+ // This weirdness is an optimization to avoid having to repopulate m_realized_databundle_names for every event
}
void SetEmptyInputPolicy(EmptyInputPolicy policy) {
@@ -163,6 +166,10 @@ struct JHasInputs {
void Configure(const VariadicInputOptions& options) {
m_requested_databundle_names = options.names;
+ m_realized_databundle_names = options.names;
+ // If options.names are empty, m_realized_databundle_names will be filled later
+ // Otherwise, m_realized_databundle_names always matches m_requested_databundle_names
+ // This weirdness is an optimization to avoid having to repopulate m_realized_databundle_names for every event
m_level = options.level;
m_is_optional = options.is_optional;
}
@@ -339,6 +346,7 @@ struct JHasInputs {
void SetTags(std::vector tags) {
m_requested_databundle_names = tags;
+ m_realized_databundle_names = tags;
}
const std::vector>& operator()() { return m_datas; }
@@ -526,37 +534,44 @@ struct JHasInputs {
return;
}
- // Validate that we have the correct number of input databundle names
- if (single_input_databundle_names.size() != m_inputs.size()) {
- throw JException("Wrong number of (nonvariadic) input databundle names! Expected %d, found %d", m_inputs.size(), single_input_databundle_names.size());
- }
-
- if (variadic_input_databundle_names.size() != m_variadic_inputs.size()) {
- throw JException("Wrong number of variadic input databundle names! Expected %d, found %d", m_variadic_inputs.size(), variadic_input_databundle_names.size());
- }
+ if (!single_input_databundle_names.empty()) {
- size_t i = 0;
- for (auto* input : m_inputs) {
- input->SetDatabundleName(single_input_databundle_names.at(i));
- if (single_input_levels.empty()) {
- input->SetLevel(component_level);
+ // Validate that we have the correct number of input databundle names
+ if (single_input_databundle_names.size() != m_inputs.size()) {
+ throw JException("Wrong number of (nonvariadic) input databundle names! Expected %d, found %d", m_inputs.size(), single_input_databundle_names.size());
}
- else {
- input->SetLevel(single_input_levels.at(i));
+
+ size_t i = 0;
+ for (auto* input : m_inputs) {
+ input->SetDatabundleName(single_input_databundle_names.at(i));
+ if (single_input_levels.empty()) {
+ input->SetLevel(component_level);
+ }
+ else {
+ input->SetLevel(single_input_levels.at(i));
+ }
+ i += 1;
}
- i += 1;
}
- i = 0;
- for (auto* variadic_input : m_variadic_inputs) {
- variadic_input->SetRequestedDatabundleNames(variadic_input_databundle_names.at(i));
- if (variadic_input_levels.empty()) {
- variadic_input->SetLevel(component_level);
+ if (!variadic_input_databundle_names.empty()) {
+
+ // Validate that we have the correct number of variadic input databundle names
+ if (variadic_input_databundle_names.size() != m_variadic_inputs.size()) {
+ throw JException("Wrong number of lists of variadic input databundle names! Expected %d, found %d", m_variadic_inputs.size(), variadic_input_databundle_names.size());
}
- else {
- variadic_input->SetLevel(variadic_input_levels.at(i));
+
+ size_t i = 0;
+ for (auto* variadic_input : m_variadic_inputs) {
+ variadic_input->SetRequestedDatabundleNames(variadic_input_databundle_names.at(i));
+ if (variadic_input_levels.empty()) {
+ variadic_input->SetLevel(component_level);
+ }
+ else {
+ variadic_input->SetLevel(variadic_input_levels.at(i));
+ }
+ i += 1;
}
- i += 1;
}
}
diff --git a/src/libraries/JANA/Components/JHasOutputs.cc b/src/libraries/JANA/Components/JHasOutputs.cc
new file mode 100644
index 000000000..e430f0c45
--- /dev/null
+++ b/src/libraries/JANA/Components/JHasOutputs.cc
@@ -0,0 +1,15 @@
+#include "JHasOutputs.h"
+#include
+
+void jana::components::UpdateFactoryStatusOnEulerianStore(JFactory* fac) {
+ // We need to set the factory status separately from the databundle status so
+ // that the factory doesn't accidentally get re-run.
+ // We do this inside a weird little free function because we need to avoid creating
+ // a circular definition of JFactory in our templates.
+ // Eventually we will need to refactor JFactory::Status and CreationStatus.
+
+ fac->SetStatus(JFactory::Status::Inserted);
+ fac->SetCreationStatus(JFactory::CreationStatus::Inserted);
+}
+
+
diff --git a/src/libraries/JANA/Components/JHasOutputs.h b/src/libraries/JANA/Components/JHasOutputs.h
index 724bfbdcd..c9d88e611 100644
--- a/src/libraries/JANA/Components/JHasOutputs.h
+++ b/src/libraries/JANA/Components/JHasOutputs.h
@@ -8,6 +8,7 @@ class JFactorySet;
namespace jana::components {
+void UpdateFactoryStatusOnEulerianStore(JFactory* fac);
class JHasOutputs {
public:
@@ -39,7 +40,7 @@ class JHasOutputs {
class VariadicOutputBase {
private:
std::vector m_databundles;
- JEventLevel m_level = JEventLevel::PhysicsEvent;
+ JEventLevel m_level = JEventLevel::None;
public:
virtual ~VariadicOutputBase() {
@@ -167,27 +168,39 @@ class JHasOutputs {
}
else {
// Do the obvious, sensible thing instead
- size_t i = 0;
- for (auto* output : m_outputs) {
- output->SetLevel(component_level);
- if (use_short_names) {
- output->SetShortName(single_output_databundle_names.at(i));
+ if (!single_output_databundle_names.empty()) {
+ if (single_output_databundle_names.size() != m_outputs.size()) {
+ throw JException("Wrong number of (nonvariadic) output databundle names! Expected %d, found %d", m_outputs.size(), single_output_databundle_names.size());
}
- else {
- output->SetUniqueName(single_output_databundle_names.at(i));
+
+ size_t i = 0;
+ for (auto* output : m_outputs) {
+ output->SetLevel(component_level);
+ if (use_short_names) {
+ output->SetShortName(single_output_databundle_names.at(i));
+ }
+ else {
+ output->SetUniqueName(single_output_databundle_names.at(i));
+ }
+ i += 1;
}
- i += 1;
}
- i = 0;
- for (auto* variadic_output : m_variadic_outputs) {
- variadic_output->SetLevel(component_level);
- if (use_short_names) {
- variadic_output->SetShortNames(variadic_output_databundle_names.at(i));
+
+ if (!variadic_output_databundle_names.empty()) {
+ if (variadic_output_databundle_names.size() != m_variadic_outputs.size()) {
+ throw JException("Wrong number of lists of variadic output databundle names! Expected %d, found %d", m_variadic_outputs.size(), variadic_output_databundle_names.size());
}
- else {
- variadic_output->SetUniqueNames(variadic_output_databundle_names.at(i));
+ size_t i = 0;
+ for (auto* variadic_output : m_variadic_outputs) {
+ variadic_output->SetLevel(component_level);
+ if (use_short_names) {
+ variadic_output->SetShortNames(variadic_output_databundle_names.at(i));
+ }
+ else {
+ variadic_output->SetUniqueNames(variadic_output_databundle_names.at(i));
+ }
+ i += 1;
}
- i += 1;
}
}
}
diff --git a/src/libraries/JANA/Components/JLightweightOutput.h b/src/libraries/JANA/Components/JLightweightOutput.h
index 733b9d07d..78dbe6393 100644
--- a/src/libraries/JANA/Components/JLightweightOutput.h
+++ b/src/libraries/JANA/Components/JLightweightOutput.h
@@ -74,6 +74,10 @@ class Output : public JHasOutputs::OutputBase {
typed_bundle->GetData() = std::move(*m_external_data);
}
typed_bundle->SetStatus(JDatabundle::Status::Inserted);
+ auto fac = typed_bundle->GetFactory();
+ if (fac != nullptr) {
+ UpdateFactoryStatusOnEulerianStore(fac);
+ }
}
};
@@ -179,6 +183,11 @@ class VariadicOutput : public JHasOutputs::VariadicOutputBase {
}
typed_databundle->GetData() = std::move(m_transient_datas.at(i));
typed_databundle->SetStatus(JDatabundle::Status::Inserted);
+
+ auto fac = typed_databundle->GetFactory();
+ if (fac != nullptr) {
+ UpdateFactoryStatusOnEulerianStore(fac);
+ }
i += 1;
}
}
diff --git a/src/libraries/JANA/Components/JPodioOutput.h b/src/libraries/JANA/Components/JPodioOutput.h
index 7e4717408..b9a7ef3b4 100644
--- a/src/libraries/JANA/Components/JPodioOutput.h
+++ b/src/libraries/JANA/Components/JPodioOutput.h
@@ -25,7 +25,7 @@ class PodioOutput : public JHasOutputs::OutputBase {
this->m_podio_databundle = new JPodioDatabundle;
SetDatabundle(m_podio_databundle);
- m_podio_databundle->SetShortName(collection_name);
+ m_podio_databundle->SetUniqueName(collection_name);
m_podio_databundle->SetTypeName(JTypeInfo::demangle());
m_podio_databundle->SetTypeIndex(std::type_index(typeid(PodioT)));
@@ -130,6 +130,12 @@ class PodioOutput : public JHasOutputs::OutputBase {
}
typed_collection_bundle->SetCollection(published);
typed_collection_bundle->SetStatus(JDatabundle::Status::Inserted);
+
+ auto fac = typed_collection_bundle->GetFactory();
+ if (fac != nullptr) {
+ UpdateFactoryStatusOnEulerianStore(fac);
+ }
+
m_transient_collection = std::make_unique();
m_transient_collection->setSubsetCollection(m_is_subset);
}
@@ -140,7 +146,7 @@ template
class VariadicPodioOutput : public JHasOutputs::VariadicOutputBase {
private:
std::vector> m_transient_collections;
- std::vector m_databundles;
+ bool m_is_subset = false;
public:
VariadicPodioOutput(JHasOutputs* owner, std::vector default_collection_names={}) {
@@ -151,13 +157,15 @@ class VariadicPodioOutput : public JHasOutputs::VariadicOutputBase {
databundle->SetTypeName(JTypeInfo::demangle());
databundle->SetTypeIndex(std::type_index(typeid(PodioT)));
GetDatabundles().push_back(databundle);
- m_databundles.push_back(databundle);
m_transient_collections.push_back(std::make_unique());
}
}
void SetShortNames(std::vector short_names) override {
- m_databundles.clear();
+ for (auto* db : GetDatabundles()) {
+ delete db;
+ }
+ GetDatabundles().clear();
m_transient_collections.clear();
for (const std::string& name : short_names) {
auto databundle = new JPodioDatabundle;
@@ -165,27 +173,41 @@ class VariadicPodioOutput : public JHasOutputs::VariadicOutputBase {
databundle->SetTypeName(JTypeInfo::demangle());
databundle->SetTypeIndex(std::type_index(typeid(PodioT)));
GetDatabundles().push_back(databundle);
- m_databundles.push_back(databundle);
m_transient_collections.push_back(std::make_unique());
+ m_transient_collections.back()->setSubsetCollection(m_is_subset);
}
}
void SetUniqueNames(std::vector unique_names) override {
- m_databundles.clear();
+ for (auto* db : GetDatabundles()) {
+ delete db;
+ }
+ GetDatabundles().clear();
m_transient_collections.clear();
for (const std::string& name : unique_names) {
auto databundle = new JPodioDatabundle;
+ LOG << "SetUniqueNames: Adding databundle with unique_name " << name;
databundle->SetUniqueName(name);
databundle->SetTypeName(JTypeInfo::demangle());
databundle->SetTypeIndex(std::type_index(typeid(PodioT)));
GetDatabundles().push_back(databundle);
- m_databundles.push_back(databundle);
m_transient_collections.push_back(std::make_unique());
+ m_transient_collections.back()->setSubsetCollection(m_is_subset);
}
}
std::vector>& operator()() { return m_transient_collections; }
+ void SetSubsetCollection(bool is_subset) {
+ m_is_subset = is_subset;
+ for (auto& coll : m_transient_collections) {
+ coll->setSubsetCollection(is_subset);
+ }
+ }
+
+ bool IsSubsetCollection() const { return m_is_subset; }
+
+
void LagrangianStore(JFactorySet& facset, JDatabundle::Status status) override {
if (m_transient_collections.size() != GetDatabundles().size()) {
throw JException("VariadicPodioOutput::LagrangianStore() failed: Declared %d collections, but provided %d.", GetDatabundles().size(), m_transient_collections.size());
@@ -208,13 +230,14 @@ class VariadicPodioOutput : public JHasOutputs::VariadicOutputBase {
size_t i = 0;
for (auto& collection : m_transient_collections) {
- frame->put(std::move(collection), m_databundles[i]->GetUniqueName());
- const auto* moved = &frame->template get(m_databundles[i]->GetUniqueName());
- const auto &databundle = dynamic_cast(m_databundles[i]);
+ frame->put(std::move(collection), GetDatabundles()[i]->GetUniqueName());
+ const auto* moved = &frame->template get(GetDatabundles()[i]->GetUniqueName());
+ const auto &databundle = dynamic_cast(GetDatabundles()[i]);
databundle->SetCollection(moved);
databundle->SetStatus(status);
i += 1;
collection = std::make_unique();
+ collection->setSubsetCollection(m_is_subset);
}
}
@@ -246,31 +269,40 @@ class VariadicPodioOutput : public JHasOutputs::VariadicOutputBase {
int i=0;
for (auto& collection : m_transient_collections) {
- frame->put(std::move(collection), m_databundles[i]->GetUniqueName());
- const auto* moved = &frame->template get(m_databundles[i]->GetUniqueName());
+ frame->put(std::move(collection), GetDatabundles()[i]->GetUniqueName());
+ const auto* moved = &frame->template get(GetDatabundles()[i]->GetUniqueName());
JPodioDatabundle* typed_collection_bundle = nullptr;
- auto collection_bundle = facset.GetDatabundle(m_databundles[i]->GetTypeIndex(), m_databundles[i]->GetUniqueName());
+ auto collection_bundle = facset.GetDatabundle(GetDatabundles()[i]->GetTypeIndex(), GetDatabundles()[i]->GetUniqueName());
if (collection_bundle == nullptr) {
// No databundle present. In this case we create it, using m_databundles[i] as a template
- typed_collection_bundle = new JPodioDatabundle(*m_databundles[i]);
+ auto typed_prototype = static_cast(GetDatabundles()[i]);
+ typed_collection_bundle = new JPodioDatabundle(*typed_prototype);
facset.Add(typed_collection_bundle);
}
else {
typed_collection_bundle = dynamic_cast(collection_bundle);
if (typed_collection_bundle == nullptr) {
// Wrong databundle present
- throw JException("Databundle with unique_name '%s' is not a JPodioDatabundle", m_databundles[i]->GetUniqueName().c_str());
+ throw JException("Databundle with unique_name '%s' is not a JPodioDatabundle", GetDatabundles()[i]->GetUniqueName().c_str());
}
}
// Then we store the collection itself
typed_collection_bundle->SetCollection(moved);
typed_collection_bundle->SetStatus(JDatabundle::Status::Inserted);
+
+ auto fac = typed_collection_bundle->GetFactory();
+ if (fac != nullptr) {
+ UpdateFactoryStatusOnEulerianStore(fac);
+ }
+
+ // Replace the transient collection
+ collection = std::make_unique();
+ collection->setSubsetCollection(m_is_subset);
i += 1;
}
- m_transient_collections.clear();
}
};
diff --git a/src/libraries/JANA/Services/JWiringService.h b/src/libraries/JANA/Services/JWiringService.h
index 47a0ad691..64b456ece 100644
--- a/src/libraries/JANA/Services/JWiringService.h
+++ b/src/libraries/JANA/Services/JWiringService.h
@@ -43,7 +43,7 @@ class JWiringService : public JService {
};
private:
- Parameter m_wirings_input_file {this, "jana:wiring_file", "",
+ Parameter m_wirings_input_file {this, "wiring_file", "",
"Path to TOML file containing wiring definitions"};
WiringSet m_wiring_set;
diff --git a/src/libraries/JANA/Topology/JEventMapArrow.cc b/src/libraries/JANA/Topology/JEventMapArrow.cc
index ac54ea115..72d43317d 100644
--- a/src/libraries/JANA/Topology/JEventMapArrow.cc
+++ b/src/libraries/JANA/Topology/JEventMapArrow.cc
@@ -38,7 +38,7 @@ void JEventMapArrow::fire(JEvent* event, OutputData& outputs, size_t& output_cou
}
for (JEventUnfolder* unfolder : m_unfolders) {
JCallGraphEntryMaker cg_entry(*event->GetJCallGraphRecorder(), unfolder->GetTypeName()); // times execution until this goes out of scope
- unfolder->Preprocess(*event);
+ unfolder->DoPreprocess(*event);
}
for (JEventProcessor* processor : m_procs) {
JCallGraphEntryMaker cg_entry(*event->GetJCallGraphRecorder(), processor->GetTypeName()); // times execution until this goes out of scope
diff --git a/src/programs/unit_tests/Components/UnfoldTests.cc b/src/programs/unit_tests/Components/UnfoldTests.cc
index 38038ae15..ef7736ac2 100644
--- a/src/programs/unit_tests/Components/UnfoldTests.cc
+++ b/src/programs/unit_tests/Components/UnfoldTests.cc
@@ -1,11 +1,15 @@
+#include "JANA/JEventUnfolder.h"
+#include
#include
#include
#include
#include
+#include
#if JANA2_HAVE_PODIO
#include
+#include
#endif
namespace jana {
@@ -258,7 +262,257 @@ TEST_CASE("NoOpUnfolder_Tests") {
}
-} // namespace arrowtests
+#if JANA2_HAVE_PODIO
+
+/*
+* This test case hopefully finds issues that the ePIC timeframe splitter will eventually encounter
+*/
+
+struct ePICSource : public JEventSource {
+ std::vector>> datastream;
+ size_t next_idx = 0;
+
+ PodioOutput info_out {this, "info"};
+ VariadicPodioOutput hits_out {this, {"adet_hits", "bdet_hits"}};
+
+ ePICSource() {
+ SetTypeName("ePICSource");
+ SetLevel(JEventLevel::Timeslice);
+ SetCallbackStyle(CallbackStyle::ExpertMode);
+ }
+
+ Result Emit(JEvent&) override {
+ if (next_idx == datastream.size()) {
+ return Result::FailureFinished;
+ }
+
+ MutableEventInfo info;
+ info.TimesliceNumber(next_idx);
+ info_out()->push_back(info);
+
+ const auto& timeslice = datastream.at(next_idx);
+ for (auto& hit_data: timeslice) {
+ MutableExampleHit hit;
+ int det = std::get<0>(hit_data);
+ int time = std::get<1>(hit_data);
+ double energy = std::get<2>(hit_data);
+ hit.time(time);
+ hit.energy(energy);
+ hits_out().at(det)->push_back(hit);
+ }
+ LOG << "Emitting timeslice " << next_idx << " containing " << timeslice.size() << " hits";
+ next_idx += 1;
+
+ return Result::Success;
+ }
+};
+
+struct TimeAdjustment : public JFactory {
+ VariadicPodioInput hits_in {this, VariadicInputOptions{.names={"adet_hits", "bdet_hits"}}};
+ VariadicPodioOutput hits_out {this, {"adet_hits_adjusted", "bdet_hits_adjusted"}};
+
+ TimeAdjustment() {
+ SetLevel(JEventLevel::Timeslice);
+ }
+
+ void Process(const JEvent&) {
+ size_t i=0;
+ for (const auto& hit_coll : hits_in()) {
+ for (const auto& raw_hit : *hit_coll) {
+ auto adjusted_hit = raw_hit.clone();
+ adjusted_hit.time(adjusted_hit.time() + 1);
+ hits_out().at(i)->push_back(adjusted_hit);
+ }
+ i += 1;
+ }
+ }
+};
+
+
+struct Splitter : public JEventUnfolder {
+ PodioInput info_in {this, {.name="info"}};
+ PodioOutput info_out {this, "info"};
+ VariadicPodioInput hits_in {this, VariadicInputOptions{.names={"adet_hits_adjusted", "bdet_hits_adjusted"}}};
+ VariadicPodioOutput hits_out {this, {"adet_hits", "bdet_hits"}};
+
+ uint64_t current_t = 0;
+ uint64_t current_evt_nr = 0;
+
+ Splitter() {
+ info_out.SetSubsetCollection(true);
+ hits_out.SetSubsetCollection(true);
+ SetParentLevel(JEventLevel::Timeslice);
+ SetChildLevel(JEventLevel::PhysicsEvent);
+ }
+
+ JEventUnfolder::Result Unfold(const JEvent&, JEvent& child, int) {
+
+ REQUIRE(info_in()->size() == 1);
+
+ LOG << "Unfolding timeslice " << info_in()->at(0).TimesliceNumber() << " into physics event " << current_evt_nr;
+
+ for (; current_t < 10; current_t += 1) {
+
+ bool hits_found = false;
+ size_t current_coll_idx=0;
+ for (const auto& hit_coll : hits_in()) {
+ for (const auto& hit : *hit_coll) {
+ if (hit.time() == current_t) {
+ hits_found = true;
+ hits_out().at(current_coll_idx)->push_back(hit);
+ }
+ }
+ current_coll_idx += 1;
+ }
+
+ if (hits_found) {
+ if (current_t == 9) {
+ // We've reached the last timestep in this timeslice
+ current_t = 0;
+ LOG << "Splitter: NextChildNextParent";
+ info_out()->push_back(info_in()->at(0));
+ child.SetEventNumber(current_evt_nr++);
+ return Result::NextChildNextParent;
+ }
+ else {
+ // Next call to Unfold() starts with the subsequent timestep
+ current_t += 1;
+ LOG << "Splitter: NextChildKeepParent";
+ info_out()->push_back(info_in()->at(0));
+ child.SetEventNumber(current_evt_nr++);
+ return Result::NextChildKeepParent;
+ }
+ }
+ }
+ // No (remaining) hits found in this timeslice for any timestep
+ current_t = 0;
+ LOG << "Splitter: KeepChildNextParent";
+ return Result::KeepChildNextParent;
+ }
+};
+
+
+struct Checker : public JEventProcessor {
+ PodioInput info_in {this, {.name="info"}};
+ VariadicPodioInput hits_in {this, VariadicInputOptions{.names={"adet_hits", "bdet_hits"}}};
+
+ std::vector expected_timeslice_nrs;
+ std::vector>> expected_hits;
+ size_t current_idx = 0;
+
+ Checker() {
+ SetCallbackStyle(CallbackStyle::ExpertMode);
+ EnableOrdering();
+ }
+ void ProcessSequential(const JEvent& event) override {
+
+ int ts_nr = info_in->at(0).TimesliceNumber();
+ LOG << "Checking event " << event.GetEventNumber() << " from timeslice " << ts_nr;
+
+ std::vector> hits_found;
+
+ size_t det_id = 0;
+ for (const auto& coll : hits_in()) {
+ for (const auto& hit : *coll) {
+ hits_found.push_back({ det_id, hit.time(), hit.energy()});
+ }
+ det_id += 1;
+ }
+
+ REQUIRE(expected_timeslice_nrs.at(current_idx) == ts_nr);
+ REQUIRE(expected_hits.at(current_idx).size() == hits_found.size());
+ for (size_t i=0; i(expected_hits.at(current_idx).at(i)) == std::get<0>(hits_found.at(i)));
+ REQUIRE(std::get<1>(expected_hits.at(current_idx).at(i)) == std::get<1>(hits_found.at(i)));
+ REQUIRE(std::get<2>(expected_hits.at(current_idx).at(i)) == std::get<2>(hits_found.at(i)));
+ }
+
+ current_idx += 1;
+ }
+};
+
+
+TEST_CASE("ePIC_Timeframe_Splitting") {
+ JApplication app;
+ auto src = new ePICSource;
+ auto checker = new Checker();
+
+ app.Add(src);
+ app.Add(new JFactoryGeneratorT);
+ app.Add(new Splitter);
+ app.Add(checker);
+
+ const int DetA = 0;
+ const int DetB = 1;
+
+ SECTION("JustOne") {
+ src->datastream = {
+ {{DetA, 0, 22.2}},
+ {{DetA, 0, 33.3}},
+ {{DetA, 0, 44.4}}
+ };
+ checker->expected_timeslice_nrs = {0, 1, 2};
+ checker->expected_hits = {
+ {{DetA, 1, 22.2}},
+ {{DetA, 1, 33.3}},
+ {{DetA, 1, 44.4}}
+ };
+ app.Run();
+ }
+ SECTION("OneOrZero") {
+ src->datastream = {
+ {{DetA, 0, 22.2}},
+ {},
+ {{DetA, 0, 33.3}},
+ {{DetA, 0, 44.4}}
+ };
+ checker->expected_timeslice_nrs = {0, 2, 3};
+ checker->expected_hits = {
+ {{DetA, 1, 22.2}},
+ {{DetA, 1, 33.3}},
+ {{DetA, 1, 44.4}}
+ };
+ app.Run();
+ }
+ SECTION("FlatMap") {
+ src->datastream = {
+ {{DetA, 0, 22.2}, {DetA, 1, 33.3}},
+ {{DetA, 0, 44.4}, {DetA, 1, 55.5}, {DetB, 2, 66.6}},
+ {{DetA, 0, 77.7}}
+ };
+ checker->expected_timeslice_nrs = {0,0,1,1,1,2};
+ checker->expected_hits = {
+ {{DetA, 1, 22.2}},
+ {{DetA, 2, 33.3}},
+ {{DetA, 1, 44.4}},
+ {{DetA, 2, 55.5}},
+ {{DetB, 3, 66.6}},
+ {{DetA, 1, 77.7}}
+ };
+ app.Run();
+ }
+ SECTION("UnFlatMap") {
+ src->datastream = {
+ {{DetA, 0, 22.2}, {DetA, 1, 33.3}, {DetA, 1, 19}, {DetB, 1, 22}},
+ {{DetA, 0, 44.4}, {DetA, 1, 55.5}, {DetB, 2, 66.6}},
+ {{DetA, 0, 77.7}, {DetA, 0, 88.8}, {DetA, 0, 99.9}}
+ };
+ checker->expected_timeslice_nrs = {0,0,1,1,1,2};
+ checker->expected_hits = {
+ {{DetA, 1, 22.2}},
+ {{DetA, 2, 33.3}, {DetA, 2, 19}, {DetB, 2, 22}},
+ {{DetA, 1, 44.4}},
+ {{DetA, 2, 55.5}},
+ {{DetB, 3, 66.6}},
+ {{DetA, 1, 77.7}, {DetA, 1, 88.8}, {DetA, 1, 99.9}}
+ };
+ app.Run();
+ }
+}
+
+#endif // JANA2_HAVE_PODIO
+
+} // namespace unfoldtests
} // namespace jana
diff --git a/src/programs/unit_tests/Services/JWiringServiceTests.cc b/src/programs/unit_tests/Services/JWiringServiceTests.cc
index b07b3bc92..d700470cb 100644
--- a/src/programs/unit_tests/Services/JWiringServiceTests.cc
+++ b/src/programs/unit_tests/Services/JWiringServiceTests.cc
@@ -433,6 +433,8 @@ struct WiredFac : public JFactory {
WiredFac() {
SetPrefix("wiredfac");
+ m_protoclusters_in.SetDatabundleName("default_protos");
+ m_clusters_out.SetUniqueName("default_clusters");
}
void Process(const JEvent&) {
for (auto protocluster : *m_protoclusters_in) {
@@ -525,4 +527,64 @@ TEST_CASE("WiringTests_FacGenShortnames") {
}
+static constexpr std::string_view facgen_partial_input_names_only = R"(
+ [[wiring]]
+ action = "update"
+ type_name = "WiredFac"
+ prefix = "wiredfac"
+ input_names = ["overridden_input"]
+)";
+
+TEST_CASE("WiringTests_Partial_InputNamesOnly") {
+
+ JApplication app;
+
+ auto wiring_svc = app.GetService();
+ toml::table table = toml::parse(facgen_partial_input_names_only);
+ wiring_svc->ApplyWiringSet(wiring_svc->ParseWiringSet(table));
+
+ auto gen = new JFactoryGeneratorT;
+ app.Add(gen);
+ app.Initialize();
+
+ auto event = std::make_shared(&app);
+ std::vector test_data;
+ test_data.push_back(new Cluster{0, 0, 22.2});
+ event->Insert(test_data, "overridden_input");
+
+ auto results = event->Get("default_clusters");
+ REQUIRE(results.size() == 1);
+ REQUIRE(results.at(0)->E == 23.2);
+
+}
+static constexpr std::string_view facgen_partial_output_names_only = R"(
+ [[wiring]]
+ action = "update"
+ type_name = "WiredFac"
+ prefix = "wiredfac"
+ output_names = ["overridden_output"]
+)";
+
+TEST_CASE("WiringTests_Partial_OutputNamesOnly") {
+
+ JApplication app;
+
+ auto wiring_svc = app.GetService();
+ toml::table table = toml::parse(facgen_partial_output_names_only);
+ wiring_svc->ApplyWiringSet(wiring_svc->ParseWiringSet(table));
+
+ auto gen = new JFactoryGeneratorT;
+ app.Add(gen);
+ app.Initialize();
+
+ auto event = std::make_shared(&app);
+ std::vector test_data;
+ test_data.push_back(new Cluster{0, 0, 22.2});
+ event->Insert(test_data, "default_protos");
+
+ auto results = event->Get("overridden_output");
+ REQUIRE(results.size() == 1);
+ REQUIRE(results.at(0)->E == 23.2);
+
+}