Skip to content

Commit

Permalink
Use Gaudi::Functional, add examples and adapt PodioInput to use Gaudi…
Browse files Browse the repository at this point in the history
…::Functional (#129)
  • Loading branch information
jmcarcell committed Oct 4, 2023
1 parent 5376f4f commit 4eb5cd8
Show file tree
Hide file tree
Showing 25 changed files with 1,299 additions and 70 deletions.
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
### File copied from https://github.com/key4hep/key4hep-dev-utils
### DO NOT EDIT, CHANGES WILL BE OVERWRITTEN

### C++ ###
# Prerequisites
*.d
Expand Down Expand Up @@ -241,7 +238,7 @@ podio_generated_files.cmake
/python/edm4hep/__version__.py
edm4hep/edm4hep/
edm4hep/src/
## k4FWCore
# k4FWCore
test/k4FWCoreTest/**/*.root
## k4MarlinWrapper
test/inputFiles/*.slcio
Expand Down
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,35 @@ print(my_opts[0].foo)

k4FWCore is a CMake project. After setting up the dependencies (use for example `source /cvmfs/sw.hsf.org/key4hep/setup.sh`)


```
mkdir build install
cd build;
``` bash
mkdir build
cd build
cmake ..
make install
```


## Implementing algorithms
k4FWCore uses `Gaudi::Functional` for executing algorithms. There are several
types of algorithms, depending on your use case:
- The `Consumer` takes inputs but no outputs; can be used for reading
- The `Producer` takes outputs but no inputs; can be used for generating
collections or events
- The `Transformer` is the more general one (both the `Consumer` and the
`Producer` are a particular case of this one) and takes both inputs and
outputs

A more complete list of algorithms can be found in
https://lhcb.github.io/DevelopKit/03a-gaudi/, in the `Gaudi::Functional`
section.

In all cases the implementation process is the same: we'll create a new class
that will inherit from one of the previous algorithms. Then, we implement
`operator()`, where our algorithm will be. This `operator()` will return either
a single type (including `void`) or a tuple with multiple types. It will take
one parameter per input. Simple examples can be found in the test folder for
each one of the above-mentioned algorithms. In addition, there are tests that
have either multiple inputs and / or multiple outputs (like
`ExampleFunctionalProducerMultiple`) that can be used as a template for the more
typical case when working with multiple inputs or outputs.

**`GaudiAlg` is deprecated and will be removed in future versions of Gaudi.**
186 changes: 159 additions & 27 deletions k4FWCore/components/PodioInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,181 @@
* limitations under the License.
*/
#include "PodioInput.h"
#include "GaudiAlg/Consumer.h"

#include "TFile.h"
#include "TROOT.h"

#include "k4FWCore/DataWrapper.h"
#include "k4FWCore/PodioDataSvc.h"

#include "edm4hep/CaloHitContributionCollection.h"
#include "edm4hep/CalorimeterHitCollection.h"
#include "edm4hep/ClusterCollection.h"
#include "edm4hep/MCParticleCollection.h"
#include "edm4hep/MCRecoCaloAssociationCollection.h"
#include "edm4hep/MCRecoClusterParticleAssociationCollection.h"
#include "edm4hep/MCRecoParticleAssociationCollection.h"
#include "edm4hep/MCRecoTrackParticleAssociationCollection.h"
#include "edm4hep/MCRecoTrackerAssociationCollection.h"
#include "edm4hep/MCRecoTrackerHitPlaneAssociationCollection.h"
#include "edm4hep/ParticleIDCollection.h"
#include "edm4hep/RawCalorimeterHitCollection.h"
#include "edm4hep/RawTimeSeriesCollection.h"
#include "edm4hep/RecDqdxCollection.h"
#include "edm4hep/RecIonizationClusterCollection.h"
#include "edm4hep/RecoParticleVertexAssociationCollection.h"
#include "edm4hep/ReconstructedParticleCollection.h"
#include "edm4hep/SimCalorimeterHitCollection.h"
#include "edm4hep/SimPrimaryIonizationClusterCollection.h"
#include "edm4hep/SimTrackerHitCollection.h"
#include "edm4hep/TimeSeriesCollection.h"
#include "edm4hep/TrackCollection.h"
#include "edm4hep/TrackerHitCollection.h"
#include "edm4hep/TrackerHitPlaneCollection.h"
#include "edm4hep/TrackerPulseCollection.h"
#include "edm4hep/VertexCollection.h"

#include "podio/UserDataCollection.h"

DECLARE_COMPONENT(PodioInput)

PodioInput::PodioInput(const std::string& name, ISvcLocator* svcLoc) : GaudiAlgorithm(name, svcLoc) {}
template <typename T> inline void PodioInput::maybeRead(std::string_view collName) const {
if (m_podioDataSvc->readCollection<T>(std::string(collName)).isFailure()) {
error() << "Failed to register collection " << collName << endmsg;
}
}

StatusCode PodioInput::initialize() {
if (GaudiAlgorithm::initialize().isFailure())
return StatusCode::FAILURE;
void PodioInput::fillReaders() {
m_readers["edm4hep::MCParticleCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::MCParticleCollection>(collName);
};
m_readers["edm4hep::SimTrackerHitCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::SimTrackerHitCollection>(collName);
};
m_readers["edm4hep::CaloHitContributionCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::CaloHitContributionCollection>(collName);
};
m_readers["edm4hep::SimCalorimeterHitCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::SimCalorimeterHitCollection>(collName);
};
m_readers["edm4hep::RawCalorimeterHitCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::RawCalorimeterHitCollection>(collName);
};
m_readers["edm4hep::CalorimeterHitCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::CalorimeterHitCollection>(collName);
};
m_readers["edm4hep::ParticleIDCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::ParticleIDCollection>(collName);
};
m_readers["edm4hep::ClusterCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::ClusterCollection>(collName);
};
m_readers["edm4hep::TrackerHitCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::TrackerHitCollection>(collName);
};
m_readers["edm4hep::TrackerHitPlaneCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::TrackerHitPlaneCollection>(collName);
};
m_readers["edm4hep::RawTimeSeriesCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::RawTimeSeriesCollection>(collName);
};
m_readers["edm4hep::TrackCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::TrackCollection>(collName);
};
m_readers["edm4hep::VertexCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::VertexCollection>(collName);
};
m_readers["edm4hep::ReconstructedParticleCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::ReconstructedParticleCollection>(collName);
};
m_readers["edm4hep::MCRecoParticleAssociationCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::MCRecoParticleAssociationCollection>(collName);
};
m_readers["edm4hep::MCRecoCaloAssociationCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::MCRecoCaloAssociationCollection>(collName);
};
m_readers["edm4hep::MCRecoTrackerAssociationCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::MCRecoTrackerAssociationCollection>(collName);
};
m_readers["edm4hep::MCRecoTrackerHitPlaneAssociationCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::MCRecoTrackerHitPlaneAssociationCollection>(collName);
};
m_readers["edm4hep::MCRecoClusterParticleAssociationCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::MCRecoClusterParticleAssociationCollection>(collName);
};
m_readers["edm4hep::MCRecoTrackParticleAssociationCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::MCRecoTrackParticleAssociationCollection>(collName);
};
m_readers["edm4hep::RecoParticleVertexAssociationCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::RecoParticleVertexAssociationCollection>(collName);
};
m_readers["edm4hep::SimPrimaryIonizationClusterCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::SimPrimaryIonizationClusterCollection>(collName);
};
m_readers["edm4hep::TrackerPulseCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::TrackerPulseCollection>(collName);
};
m_readers["edm4hep::RecIonizationClusterCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::RecIonizationClusterCollection>(collName);
};
m_readers["edm4hep::TimeSeriesCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::TimeSeriesCollection>(collName);
};
m_readers["edm4hep::RecDqdxCollection"] = [&](std::string_view collName) {
maybeRead<edm4hep::RecDqdxCollection>(collName);
};
m_readers["podio::UserDataCollection<int>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<int>>(collName);
};
m_readers["podio::UserDataCollection<float>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<float>>(collName);
};
m_readers["podio::UserDataCollection<double>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<double>>(collName);
};
m_readers["podio::UserDataCollection<int8_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<int8_t>>(collName);
};
m_readers["podio::UserDataCollection<int16_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<int16_t>>(collName);
};
m_readers["podio::UserDataCollection<int32_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<int32_t>>(collName);
};
m_readers["podio::UserDataCollection<int64_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<int64_t>>(collName);
};
m_readers["podio::UserDataCollection<uint8_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<uint8_t>>(collName);
};
m_readers["podio::UserDataCollection<uint16_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<uint16_t>>(collName);
};
m_readers["podio::UserDataCollection<uint32_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<uint32_t>>(collName);
};
m_readers["podio::UserDataCollection<uint64_t>"] = [&](std::string_view collName) {
maybeRead<podio::UserDataCollection<uint64_t>>(collName);
};
}

PodioInput::PodioInput(const std::string& name, ISvcLocator* svcLoc) : Consumer(name, svcLoc) {
// check whether we have the PodioEvtSvc active
m_podioDataSvc = dynamic_cast<PodioDataSvc*>(evtSvc().get());
if (nullptr == m_podioDataSvc)
return StatusCode::FAILURE;

// TODO: add an upfront check for existence of data products

return StatusCode::SUCCESS;
if (!m_podioDataSvc) {
error() << "Could not get PodioDataSvc" << endmsg;
}
fillReaders();
}

StatusCode PodioInput::execute() {
size_t cntr = 0;
// Re-create the collections from ROOT file

void PodioInput::operator()() const {
for (auto& collName : m_collectionNames) {
debug() << "Registering collection to read " << collName << endmsg;
if (m_podioDataSvc->readCollection(collName).isFailure()) {
return StatusCode::FAILURE;
auto type = m_podioDataSvc->getCollectionType(collName);
if (m_readers.find(type) != m_readers.end()) {
m_readers[type](collName);
} else {
maybeRead<podio::CollectionBase>(collName);
}
}

// Tell data service that we are done with requested collections
m_podioDataSvc->endOfRead();
return StatusCode::SUCCESS;
}

StatusCode PodioInput::finalize() {
if (GaudiAlgorithm::finalize().isFailure())
return StatusCode::FAILURE;
return StatusCode::SUCCESS;
}
28 changes: 13 additions & 15 deletions k4FWCore/components/PodioInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@
*/
#ifndef FWCORE_PODIOINPUT_H
#define FWCORE_PODIOINPUT_H
// Gaaudi
#include "GaudiAlg/GaudiAlgorithm.h"
// Gaudi
#include "Gaudi/Property.h"
#include "GaudiAlg/Consumer.h"

// STL
#include <string>
#include <vector>

// forward declarations
// from k4FWCore:
class PodioDataSvc;

/** @class PodioInput
Expand All @@ -36,22 +35,21 @@ class PodioDataSvc;
* @author J. Lingemann
*/

class PodioInput : public GaudiAlgorithm {
using BaseClass_t = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>;

class PodioInput final : public Gaudi::Functional::Consumer<void(), BaseClass_t> {
public:
/// Constructor.
PodioInput(const std::string& name, ISvcLocator* svcLoc);
/// Initialization of PodioInput. Acquires the data service, opens root file and creates trees.
virtual StatusCode initialize();
/// Execute. Re-creates collections that are specified to be read and sets references.
virtual StatusCode execute();
/// Finalize. Closes ROOT file.
virtual StatusCode finalize();
void operator()() const override;

private:
/// Name of collections to read. Set by option collections (this is temporary)
template <typename T> void maybeRead(std::string_view collName) const;
void fillReaders();
// Name of collections to read. Set by option collections (this is temporary)
Gaudi::Property<std::vector<std::string>> m_collectionNames{this, "collections", {}, "Places of collections to read"};
/// Data service: needed to register objects and get collection IDs. Just an observing pointer.
PodioDataSvc* m_podioDataSvc;
// Data service: needed to register objects and get collection IDs. Just an observing pointer.
PodioDataSvc* m_podioDataSvc;
mutable std::map<std::string_view, std::function<void(std::string_view)>> m_readers;
};

#endif
36 changes: 36 additions & 0 deletions k4FWCore/include/k4FWCore/BaseClass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2014-2023 Key4hep-Project.
*
* This file is part of Key4hep.
* See https://key4hep.github.io/key4hep-doc/ for further info.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef K4FWCORE_FUNCTIONALUTILS_H
#define K4FWCORE_FUNCTIONALUTILS_H

#include "GaudiAlg/GaudiAlgorithm.h"
#include "GaudiKernel/DataObjectHandle.h"
#include "k4FWCore/DataWrapper.h"

// Base class used for the Traits template argument of the
// Gaudi::Functional algorithms
struct BaseClass_t {
template <typename T> using InputHandle = DataObjectReadHandle<DataWrapper<T>>;
template <typename T> using OutputHandle = DataObjectWriteHandle<DataWrapper<T>>;

using BaseClass = Gaudi::Algorithm;
};

#endif
15 changes: 13 additions & 2 deletions k4FWCore/include/k4FWCore/DataWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,33 @@ template <class T> class GAUDI_API DataWrapper : public DataWrapperBase {

public:
DataWrapper() : m_data(nullptr){};
DataWrapper(T&& coll) {
m_data = new T(std::move(coll));
is_owner = true;
}
DataWrapper(std::unique_ptr<T> uptr) : m_data(uptr.get()) {
uptr.release();
is_owner = false;
};
virtual ~DataWrapper();

const T* getData() { return m_data; }
const T* getData() const { return m_data; }
void setData(const T* data) { m_data = data; }
virtual void resetData() { m_data = nullptr; }

operator const T&() const& { return *m_data; }

private:
/// try to cast to collectionBase; may return nullptr;
virtual podio::CollectionBase* collectionBase();

private:
const T* m_data;
bool is_owner{true};
};

template <class T> DataWrapper<T>::~DataWrapper() {
if (m_data != nullptr)
if (is_owner && !m_data)
delete m_data;
}

Expand Down
Loading

0 comments on commit 4eb5cd8

Please sign in to comment.