Skip to content

Commit

Permalink
Merge pull request #192 from JeffersonLab/nbrei_podio
Browse files Browse the repository at this point in the history
WIP: PODIO integration
  • Loading branch information
nathanwbrei authored Feb 28, 2023
2 parents 69547f2 + a6d947d commit c3e2f1e
Show file tree
Hide file tree
Showing 32 changed files with 1,336 additions and 109 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,8 @@ docs/latex/*
*.swp
cmake-build*/
.idea/*

# PODIO generated artifacts
src/examples/PodioExample/datamodel/*
src/examples/PodioExample/src/*
src/examples/PodioExample/podio_generated_files.cmake
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ option(USE_PYTHON "Include Python dependency. This requires python-devel and pyt
option(USE_ASAN "Compile with address sanitizer" OFF)
option(USE_TSAN "Compile with thread sanitizer" OFF)
option(USE_CUDA "Compile CUDA-involved examples (Needed for examples/SubeventCUDAExample)." OFF)
option(USE_PODIO "Compile with PODIO support" OFF)
option(BUILD_SHARED_LIBS "Build into both shared and static libs." ON)


Expand Down Expand Up @@ -110,6 +111,11 @@ if (${USE_CUDA})
find_package(CUDA REQUIRED)
endif()

if (${USE_PODIO})
find_package(podio REQUIRED)
add_compile_definitions(HAVE_PODIO)
endif()

#---------
# Report back to the user what we've discovered
#---------
Expand Down Expand Up @@ -152,6 +158,11 @@ if (${USE_CUDA})
else()
message(STATUS "USE_CUDA Off")
endif()
if (${USE_PODIO})
message(STATUS "USE_PODIO On --> " ${podio_DIR})
else()
message(STATUS "USE_PODIO Off")
endif()
if (${BUILD_SHARED_LIBS})
message(STATUS "BUILD_SHARED_LIBS On")
else()
Expand Down
File renamed without changes.
39 changes: 39 additions & 0 deletions containers/Docker/podio.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

# Docker image for testing JANA/PODIO integration

FROM rootproject/root:latest
#root:6.26.10-ubuntu22.04

USER root
RUN mkdir /app
WORKDIR /app

RUN apt update -y \
&& apt install -y build-essential gdb valgrind cmake wget unzip vim libasan6 less exa bat git zlib1g-dev pip

#ENV JANA_HOME /app/JANA2/install

#RUN git clone -b nbrei_podio https://github.com/JeffersonLab/JANA2 /app/JANA2
#RUN git clone -b v00-16-02 https://github.com/AIDASoft/podio /app/podio
RUN git clone -b nbrei_jana_integration https://github.com/nathanwbrei/podio /app/podio

# RUN cd /app/JANA2 \
# && mkdir build install \
# && cmake -S . -B build \
# && cmake --build build -j 10 --target install

RUN apt install -y libyaml-dev \
&& pip install jinja2 pyyaml

# Suddenly incompatible with Catch somehow, in between v00-16-02 and tip of master: nlohmann-json3-dev \

RUN cd /app/podio \
&& mkdir build install \
&& cd build \
&& cmake -DCMAKE_INSTALL_PREFIX=../install -DUSE_EXTERNAL_CATCH2=OFF .. \
&& make -j4 install



CMD bash

1 change: 1 addition & 0 deletions src/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ add_subdirectory(BlockExample)
add_subdirectory(SubeventExample)
add_subdirectory(SubeventCUDAExample)
add_subdirectory(UnitTestingExample)
add_subdirectory(PodioExample)
34 changes: 34 additions & 0 deletions src/examples/PodioExample/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

set(PodioExample_SOURCES
PodioExample.cc
PodioExampleProcessor.cc
PodioExampleSource.cc
ExampleClusterFactory.cc
)

if (USE_PODIO)

foreach( _conf ${CMAKE_CONFIGURATION_TYPES} )
string(TOUPPER ${_conf} _conf )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${_conf} ${CMAKE_CURRENT_BINARY_DIR} )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${_conf} ${CMAKE_CURRENT_BINARY_DIR} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${_conf} ${CMAKE_CURRENT_BINARY_DIR} )
endforeach()
PODIO_GENERATE_DATAMODEL(datamodel layout.yaml DATAMODEL_HEADERS DATAMODEL_SOURCES IO_BACKEND_HANDLERS ROOT)
PODIO_ADD_DATAMODEL_CORE_LIB(DataModelLib "${DATAMODEL_HEADERS}" "${DATAMODEL_SOURCES}")
PODIO_ADD_ROOT_IO_DICT(DataModelDict DataModelLib "${DATAMODEL_HEADERS}" src/selection.xml)

find_package(podio REQUIRED)
add_executable(PodioExample ${PodioExample_SOURCES})
target_include_directories(PodioExample PUBLIC .)
target_link_libraries(PodioExample jana2 podio::podio DataModelLib DataModelDict podio::podioRootIO)
set_target_properties(PodioExample PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)

install(TARGETS PodioExample DESTINATION bin)
else()
message(STATUS "Skipping examples/PodioExample because USE_PODIO=Off")

endif()



109 changes: 109 additions & 0 deletions src/examples/PodioExample/DatamodelGlue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@

// Copyright 2023, Jefferson Science Associates, LLC.
// Subject to the terms in the LICENSE file found in the top-level directory.


#ifndef JANA2_DATAMODELGLUE_H
#define JANA2_DATAMODELGLUE_H

#include <datamodel/ExampleHit.h>
#include <datamodel/ExampleHitCollection.h>
#include <datamodel/ExampleCluster.h>
#include <datamodel/ExampleClusterCollection.h>
#include <datamodel/EventInfo.h>
#include <datamodel/EventInfoCollection.h>

template <typename T>
struct PodioCollectionMap {
};

template <>
struct PodioCollectionMap<ExampleHitCollection> {
using contents_t = ExampleHit;
};
template <>
struct PodioCollectionMap<ExampleClusterCollection> {
using contents_t = ExampleCluster;
};
template <>
struct PodioCollectionMap<EventInfoCollection> {
using contents_t = EventInfo;
};

template <typename T>
struct PodioTypeMap {
};

template <>
struct PodioTypeMap<ExampleHit> {
using mutable_t = MutableExampleHit;
using collection_t = ExampleHitCollection;
};

template <>
struct PodioTypeMap<ExampleCluster> {
using mutable_t = MutableExampleCluster;
using collection_t = ExampleClusterCollection;
};

template <>
struct PodioTypeMap<EventInfo> {
using mutable_t = MutableEventInfo;
using collection_t = EventInfoCollection;
};


template<typename ... Ts>
struct Overload : Ts ... {
using Ts::operator() ...;
};
template<class... Ts> Overload(Ts...) -> Overload<Ts...>;


template <typename F, typename... ArgsT>
void visitPodioType(const std::string& podio_typename, F& helper, ArgsT... args) {
if (podio_typename == "EventInfo") {
return helper.template operator()<EventInfo>(std::forward<ArgsT>(args)...);
}
else if (podio_typename == "ExampleHit") {
return helper.template operator()<ExampleHit>(std::forward<ArgsT>(args)...);
}
else if (podio_typename == "ExampleCluster") {
return helper.template operator()<ExampleCluster>(std::forward<ArgsT>(args)...);
}
throw std::runtime_error("Not a podio typename!");
}

// If you are using C++20, you can use templated lambdas to write your visitor completely inline like so:
/*
visitPodioType(coll->getValueTypeName(),
[&]<typename T>(const podio::CollectionBase* coll, std::string name) {
using CollT = const typename PodioTypeMap<T>::collection_t;
CollT* typed_col = static_cast<CollT*>(coll);
std::cout << name << std::endl;
for (const T& object : *typed_col) {
std::cout << coll->getValueTypeName() << std::endl;
std::cout << object << std::endl;
}
}, coll, coll_name);
*/

template <typename Visitor>
struct DatamodelCollectionVisit {
void operator()(const podio::CollectionBase &collection, Visitor& visitor) {
std::string podio_typename = collection.getTypeName();
if (podio_typename == "EventInfoCollection") {
return visitor(static_cast<const EventInfoCollection &>(collection));
} else if (podio_typename == "ExampleHitCollection") {
return visitor(static_cast<const ExampleHitCollection &>(collection));
} else if (podio_typename == "ExampleClusterCollection") {
return visitor(static_cast<const ExampleClusterCollection &>(collection));
}
throw std::runtime_error("Unrecognized podio typename!");
}
};

// TODO: Change argument to collection pointer instead of reference because that is what we do everywhere else?

#endif //JANA2_DATAMODELGLUE_H
57 changes: 57 additions & 0 deletions src/examples/PodioExample/ExampleClusterFactory.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

// Copyright 2023, Jefferson Science Associates, LLC.
// Subject to the terms in the LICENSE file found in the top-level directory.


#include "ExampleClusterFactory.h"
#include "datamodel/ExampleHit.h"
#include <JANA/JEvent.h>

ExampleClusterFactory::ExampleClusterFactory() {
SetTag("clusters");
// TODO: Need to throw an exception if you try to register a PODIO factory with an empty or non-unique tag
}

void ExampleClusterFactory::Process(const std::shared_ptr<const JEvent> &event) {

// This example groups hits according to the quadrant in which they lie on the x-y plane.

MutableExampleCluster quadrant1, quadrant2, quadrant3, quadrant4;

auto hits = event->GetCollection<ExampleHit>("hits");
for (auto hit : *hits) {
if (hit.x() > 0) {
if (hit.y() > 0) {
quadrant1.addHits(hit);
quadrant1.energy(quadrant1.energy() + hit.energy());
}
else {
quadrant4.addHits(hit);
quadrant4.energy(quadrant4.energy() + hit.energy());
}
}
else {
if (hit.y() > 0) {
quadrant2.addHits(hit);
quadrant2.energy(quadrant2.energy() + hit.energy());

}
else {
quadrant3.addHits(hit);
quadrant3.energy(quadrant3.energy() + hit.energy());
}

}
}
auto* clusters = new ExampleClusterCollection();
if (quadrant1.Hits_size() > 0) clusters->push_back(quadrant1);
if (quadrant2.Hits_size() > 0) clusters->push_back(quadrant2);
if (quadrant3.Hits_size() > 0) clusters->push_back(quadrant3);
if (quadrant4.Hits_size() > 0) clusters->push_back(quadrant4);

// If no hits were assigned to a cluster, it will self-destruct when it goes out of scope
SetCollection(clusters);
}


// TODO: Expose collections as refs, not ptrs?
20 changes: 20 additions & 0 deletions src/examples/PodioExample/ExampleClusterFactory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

// Copyright 2023, Jefferson Science Associates, LLC.
// Subject to the terms in the LICENSE file found in the top-level directory.


#ifndef JANA2_EXAMPLECLUSTERFACTORY_H
#define JANA2_EXAMPLECLUSTERFACTORY_H

#include <JANA/Podio/JFactoryPodioT.h>
#include "datamodel/ExampleCluster.h"
#include "DatamodelGlue.h"

class ExampleClusterFactory : public JFactoryPodioT<ExampleCluster> {
public:
ExampleClusterFactory();
void Process(const std::shared_ptr<const JEvent> &event) override;
};


#endif //JANA2_EXAMPLECLUSTERFACTORY_H
85 changes: 85 additions & 0 deletions src/examples/PodioExample/PodioExample.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

// Copyright 2023, Jefferson Science Associates, LLC.
// Subject to the terms in the LICENSE file found in the top-level directory.
#include <iostream>
#include <podio/CollectionBase.h>
#include <podio/Frame.h>
#include "datamodel/MutableExampleHit.h"
#include "datamodel/ExampleHitCollection.h"
#include <podio/ROOTFrameWriter.h>
#include <podio/ROOTFrameReader.h>

#include <JANA/JApplication.h>
#include <JANA/JFactoryGenerator.h>
#include <JANA/Podio/JEventProcessorPodio.h>

#include "PodioExampleSource.h"
#include "PodioExampleProcessor.h"
#include "ExampleClusterFactory.h"


void create_hits_file() {

EventInfo eventinfo1(7, 22);
EventInfoCollection eventinfos1;
eventinfos1.push_back(eventinfo1);

ExampleHitCollection hits1;
hits1.push_back({22, -1, -1, 0, 100});
hits1.push_back({49, 1, 1, 0, 15.5});
hits1.push_back({47, 1, 2, 0, 0.5});
hits1.push_back({42, 2, 1, 0, 4.0});

podio::Frame event1;
event1.put(std::move(hits1), "hits");
event1.put(std::move(eventinfos1), "eventinfos");

podio::ROOTFrameWriter writer("hits.root");
writer.writeFrame(event1, "events");

EventInfo eventinfo2(8, 22);
EventInfoCollection eventinfos2;
eventinfos2.push_back(eventinfo2);

ExampleHitCollection hits2;
hits2.push_back({42, 5, -5, 5, 7.6});
hits2.push_back({618, -3, -5, 1, 99.9});
hits2.push_back({27, -10, 10, 10, 22.2});
hits2.push_back({28, -9, 11, 10, 7.8});

podio::Frame event2;
event2.put(std::move(hits2), "hits");
event2.put(std::move(eventinfos2), "eventinfos");

writer.writeFrame(event2, "events");
writer.finish();

}

void verify_clusters_file() {
podio::ROOTFrameReader reader;
reader.openFile("podio_output.root");
auto event0 = podio::Frame(reader.readEntry("events", 0));

std::cout << "Event 0: Expected 2 clusters, got " << event0.get("clusters")->size() << std::endl;

auto event1 = podio::Frame(reader.readEntry("events", 1));
std::cout << "Event 1: Expected 3 clusters, got " << event1.get("clusters")->size() << std::endl;
}


int main() {

create_hits_file();

JApplication app;
app.Add(new PodioExampleProcessor);
app.Add(new JEventProcessorPodio);
app.Add(new JFactoryGeneratorT<ExampleClusterFactory>());
app.Add(new PodioExampleSource("hits.root"));
app.Run();

verify_clusters_file();

}

Loading

0 comments on commit c3e2f1e

Please sign in to comment.