Skip to content

Commit c48bce1

Browse files
committed
Added first example algorithm, ready for testing
1 parent d8f1077 commit c48bce1

File tree

8 files changed

+160
-69
lines changed

8 files changed

+160
-69
lines changed

JugAlgo/JugAlgo/Algorithm.h

+19-13
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,19 @@
1313

1414
namespace Jug::Algo {
1515

16-
namespace detail {} // namespace detail
17-
1816
template <class AlgoImpl> class Algorithm : public GaudiAlgorithm {
1917
public:
20-
using AlgoType = AlgoImpl;
21-
using InputType = typename AlgoType::InputType;
22-
using OutputType = typename AlgoType::OutputType;
18+
using algo_type = AlgoImpl;
19+
using input_type = typename algo_type::input_type;
20+
using output_type = typename algo_type::output_type;
21+
using Input = typename algo_type::Input;
22+
using Output = typename algo_type::Output;
2323

2424
Algorithm(const std::string& name, ISvcLocator* svcLoc)
2525
: GaudiAlgorithm(name, svcLoc)
26-
, m_input{this, m_algo.inputNames()}
27-
, m_output{this, m_algo.outputNames()} {}
26+
, m_algo{name}
27+
, m_output{this, m_algo.outputNames()}
28+
, m_input{this, m_algo.inputNames()} {}
2829

2930
StatusCode initialize() override {
3031
debug() << "Initializing " << name() << endmsg;
@@ -33,7 +34,12 @@ template <class AlgoImpl> class Algorithm : public GaudiAlgorithm {
3334
const algorithms::LogLevel level{
3435
static_cast<algorithms::LogLevel>(msgLevel() > 0 ? msgLevel() - 1 : 0)};
3536
debug() << "Setting the logger level to " << algorithms::logLevelName(level) << endmsg;
36-
m_algo->level(level);
37+
m_algo.level(level);
38+
39+
// Init our data structures
40+
debug() << "Initializing data structures" << endmsg;
41+
m_input.init();
42+
m_output.init();
3743

3844
// call configure function that passes properties
3945
debug() << "Configuring properties" << endmsg;
@@ -56,18 +62,18 @@ template <class AlgoImpl> class Algorithm : public GaudiAlgorithm {
5662
virtual StatusCode configure() = 0;
5763

5864
protected:
59-
template <typename T, typename U> void setAlgoProp(std::string_view name, U&& value) {
60-
m_algo.template setProperty<T>(name, value);
65+
template <typename T> void setAlgoProp(std::string_view name, T&& value) {
66+
m_algo.template setProperty(name, value);
6167
}
6268
template <typename T> T getAlgoProp(std::string name) const {
6369
return m_algo.template getProperty<T>(name);
6470
}
6571
bool hasAlgoProp(std::string_view name) const { return m_algo.hasProperty(name); }
6672

6773
private:
68-
AlgoType m_algo;
69-
detail::DataProxy<InputType> m_input;
70-
detail::DataProxy<OutputType> m_output;
74+
algo_type m_algo;
75+
detail::DataProxy<output_type> m_output;
76+
detail::DataProxy<input_type> m_input;
7177
};
7278

7379
} // namespace Jug::Algo

JugAlgo/JugAlgo/detail/DataProxy.h

+57-40
Original file line numberDiff line numberDiff line change
@@ -12,61 +12,79 @@
1212

1313
namespace Jug::Algo::detail {
1414

15+
enum class DataMode : unsigned { kInput, kOutput };
16+
1517
// Generate properties for each of the data arguments
16-
template <class T, bool kIsInput> class DataElement {
18+
template <class T, DataMode kMode> class DataElement {
19+
1720
public:
18-
using value_type = std::conditional_t<algorithms::is_input_v<T>, algorithms::input_type_t<T>,
21+
using value_type = std::conditional_t<kMode == DataMode::kInput, algorithms::input_type_t<T>,
1922
algorithms::output_type_t<T>>;
2023
using data_type = algorithms::data_type_t<T>;
24+
constexpr static const bool kIsOptional = algorithms::is_optional_v<T>;
2125

22-
DataElement(gsl::not_null<GaudiAlgorithm*> owner, std::string_view name)
23-
: m_owner{owner}, m_data_name(m_owner, name, "") {}
26+
template <class Owner>
27+
DataElement(Owner* owner, std::string_view name)
28+
: m_data_name{std::make_unique<Gaudi::Property<std::string>>(owner, std::string(name), "")}
29+
, m_owner{owner} {}
2430
void init() {
2531
if (m_handle) {
2632
// treat error: already initialized
2733
}
28-
if (!m_data_name.empty()) {
34+
if (!m_data_name->empty()) {
2935
m_handle = std::make_unique<DataHandle<data_type>>(
30-
m_data_name, (kIsInput ? Gaudi::DataHandle::Reader : Gaudi::DataHandle::Writer), m_owner);
36+
*m_data_name,
37+
((kMode == DataMode::kInput) ? Gaudi::DataHandle::Reader : Gaudi::DataHandle::Writer),
38+
m_owner);
3139
} else if (!algorithms::is_optional_v<T>) {
3240
// treat error: member not optional but no collection name given
3341
}
3442
}
3543
value_type get() const {
36-
if (!m_handle) {
37-
return nullptr;
44+
if constexpr (kIsOptional) {
45+
if (!m_handle) {
46+
return nullptr;
47+
}
3848
}
39-
if constexpr (kIsInput) {
49+
if constexpr (kMode == DataMode::kInput) {
4050
return m_handle->get();
4151
} else {
4252
return m_handle->createAndPut();
4353
}
4454
}
4555

4656
private:
47-
GaudiAlgorithm* m_owner;
48-
Gaudi::Property<std::string> m_data_name;
49-
std::unique_ptr<DataHandle<T>> m_handle;
57+
std::unique_ptr<Gaudi::Property<std::string>>
58+
m_data_name; // This needs to be a pointer, else things go wrong once we go through
59+
// createElements - probably something about passing the Property through an
60+
// rvalue (or copy) constructor
61+
std::unique_ptr<DataHandle<data_type>> m_handle;
62+
gsl::not_null<Gaudi::Algorithm*> m_owner;
5063
};
5164

5265
// Specialization for vectors
53-
template <class T, class A, bool kIsInput> class DataElement<std::vector<T, A>, kIsInput> {
66+
template <class T, class A, DataMode kMode> class DataElement<std::vector<T, A>, kMode> {
5467
public:
55-
using value_type = std::conditional_t<algorithms::is_input_v<T>, algorithms::input_type_t<T>,
68+
using value_type = std::conditional_t<kMode == DataMode::kInput, algorithms::input_type_t<T>,
5669
algorithms::output_type_t<T>>;
5770
using data_type = algorithms::data_type_t<T>;
5871

59-
DataElement(gsl::not_null<GaudiAlgorithm*> owner, std::string_view name)
60-
: m_owner{owner}, m_data_names(m_owner, name, "") {}
72+
template <class Owner>
73+
DataElement(Owner* owner, std::string_view name)
74+
: m_data_names{std::make_unique<Gaudi::Property<std::vector<std::string>>>(
75+
owner, std::string(name), {})}
76+
, m_owner{owner} {}
6177
void init() {
6278
if (!m_handles.empty()) {
6379
// treat error: already initialized
6480
}
65-
if (!m_data_names.empty()) {
66-
for (const auto& name : m_data_names) {
81+
if (!m_data_names->empty()) {
82+
for (const auto& name : *m_data_names) {
6783
if (!name.empty()) {
6884
m_handles.emplace_back(std::make_unique<DataHandle<data_type>>(
69-
name, (kIsInput ? Gaudi::DataHandle::Reader : Gaudi::DataHandle::Writer), m_owner));
85+
name,
86+
(kMode == DataMode::kInput ? Gaudi::DataHandle::Reader : Gaudi::DataHandle::Writer),
87+
m_owner));
7088
} else {
7189
// treat error: empty name
7290
}
@@ -78,7 +96,7 @@ template <class T, class A, bool kIsInput> class DataElement<std::vector<T, A>,
7896
std::vector<value_type> get() const {
7997
std::vector<value_type> ret;
8098
for (auto& handle : m_handles) {
81-
if constexpr (kIsInput) {
99+
if constexpr (kMode == DataMode::kInput) {
82100
ret.emplace_back(handle->get());
83101
} else {
84102
ret.emplace_back(handle->createAndPut());
@@ -88,16 +106,15 @@ template <class T, class A, bool kIsInput> class DataElement<std::vector<T, A>,
88106
}
89107

90108
private:
91-
GaudiAlgorithm* m_owner;
92-
Gaudi::Property<std::vector<std::string>> m_data_names;
109+
std::unique_ptr<Gaudi::Property<std::vector<std::string>>> m_data_names;
93110
std::vector<std::unique_ptr<DataHandle<T>>> m_handles;
111+
gsl::not_null<Gaudi::Algorithm*> m_owner;
94112
};
95113

96-
template <bool kIsInput, class NamesArray, class Tuple, size_t... I>
97-
auto createElements(GaudiAlgorithm* owner, const NamesArray& names, const Tuple&,
98-
std::index_sequence<I...>)
99-
-> std::tuple<DataElement<std::tuple_element_t<I, Tuple>, kIsInput>...> {
100-
return {{owner, std::get<I>(names)}...};
114+
template <DataMode kMode, class Owner, class NamesArray, class Tuple, size_t... I>
115+
auto createElements(Owner* owner, const NamesArray& names, const Tuple&, std::index_sequence<I...>)
116+
-> std::tuple<DataElement<std::tuple_element_t<I, Tuple>, kMode>...> {
117+
return {DataElement<std::tuple_element_t<I, Tuple>, kMode>(owner, std::get<I>(names))...};
101118
}
102119

103120
// Call ::get() on each element of the HandleTuple, and return the result in the format of
@@ -111,28 +128,28 @@ ReturnTuple getElements(HandleTuple& handles, std::index_sequence<I...>) {
111128

112129
template <class Data> class DataProxy {
113130
public:
114-
static constexpr bool kIsInput = algorithms::is_input_v<Data>;
115-
using value_type = Data;
116-
using data_type = typename Data::data_type;
117-
constexpr static size_t kSize = Data::kSize;
118-
using names_type = typename Data::DataNames;
131+
static constexpr DataMode kMode =
132+
(algorithms::is_input_v<Data> ? DataMode::kInput : DataMode::kOutput);
133+
using value_type = typename Data::value_type;
134+
using data_type = typename Data::data_type;
135+
constexpr static size_t kSize = Data::kSize;
136+
using names_type = typename Data::key_type;
119137
using elements_type =
120-
decltype(createElements<kIsInput>(std::declval<GaudiAlgorithm*>(), names_type(), data_type(),
121-
std::make_index_sequence<kSize>()));
138+
decltype(createElements<kMode>(std::declval<GaudiAlgorithm*>(), names_type(), data_type(),
139+
std::make_index_sequence<kSize>()));
122140

123-
DataProxy(gsl::not_null<GaudiAlgorithm*> owner, const names_type& names)
124-
: m_owner{owner}
125-
, m_elements{createElements<kIsInput>(m_owner, names, data_type(),
126-
std::make_index_sequence<kSize>())} {}
141+
template <class Owner>
142+
DataProxy(Owner* owner, const names_type& names)
143+
: m_elements{
144+
createElements<kMode>(owner, names, data_type(), std::make_index_sequence<kSize>())} {}
127145
void init() {
128-
std::apply([](auto el) { el.init(); }, m_elements);
146+
std::apply([](auto&&... el) { (el.init(), ...); }, m_elements);
129147
}
130148
value_type get() const {
131149
return getElements<value_type>(m_elements, std::make_index_sequence<kSize>());
132150
}
133151

134152
private:
135-
GaudiAlgorithm* m_owner;
136153
elements_type m_elements;
137154
};
138155

JugAlgo/src/dummy.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <JugAlgo/IAlgoServiceSvc.h>
2-
#include <JugAlgo/Algorithm.h>
2+
//#include <JugAlgo/Algorithm.h>
33

44
namespace {
55
constexpr int doNothing() { return 1; }

JugReco/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ gaudi_add_module(JugRecoPlugins
1111
${JugRecoPlugins_sources}
1212
LINK
1313
Gaudi::GaudiAlgLib Gaudi::GaudiKernel
14-
JugBase
14+
JugBase JugAlgo
15+
algocore algocalorimetry
1516
ROOT::Core ROOT::RIO ROOT::Tree
1617
EDM4HEP::edm4hep
1718
EDM4EIC::edm4eic
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright (C) 2022 Sylvester Joosten, Chao, Chao Peng, Whitney Armstrong
3+
4+
/*
5+
* Reconstruct the cluster with Center of Gravity method
6+
* Logarithmic weighting is used for mimicing energy deposit in transverse direction
7+
*
8+
* Author: Sylvester Joosten, Chao Peng (ANL), 09/20/2022
9+
*/
10+
11+
#include <JugAlgo/Algorithm.h>
12+
#include <algorithms/calorimetry/ClusterRecoCoG.h>
13+
14+
#include "Gaudi/Property.h"
15+
16+
namespace Jug::Reco {
17+
18+
namespace {
19+
using AlgoBase = Jug::Algo::Algorithm<algorithms::calorimetry::ClusterRecoCoG>;
20+
}
21+
22+
class ClusterRecoCoG : public AlgoBase {
23+
24+
public:
25+
ClusterRecoCoG(const std::string& name, ISvcLocator* svcLoc) : AlgoBase(name, svcLoc) {}
26+
27+
virtual StatusCode configure() {
28+
setAlgoProp("samplingFraction", m_sampFrac.value());
29+
setAlgoProp("logWeightBase", m_logWeightBase.value());
30+
setAlgoProp("energyWeight", m_energyWeight.value());
31+
setAlgoProp("moduleDimZName", m_moduleDimZName.value());
32+
setAlgoProp("enableEtaBounds", m_enableEtaBounds.value());
33+
return StatusCode::SUCCESS;
34+
}
35+
36+
private:
37+
Gaudi::Property<double> m_sampFrac{this, "samplingFraction", 1.0};
38+
Gaudi::Property<double> m_logWeightBase{this, "logWeightBase", 3.6};
39+
Gaudi::Property<std::string> m_energyWeight{this, "energyWeight", "log"};
40+
Gaudi::Property<std::string> m_moduleDimZName{this, "moduleDimZName", ""};
41+
Gaudi::Property<bool> m_enableEtaBounds{this, "enableEtaBounds", false};
42+
};
43+
44+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
45+
DECLARE_COMPONENT(ClusterRecoCoG)
46+
47+
} // namespace Jug::Reco
48+

external/algorithms/core/include/algorithms/algorithm.h

+14-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <vector>
88

99
#include <algorithms/logger.h>
10+
#include <algorithms/name.h>
1011
#include <algorithms/property.h>
1112
#include <algorithms/type_traits.h>
1213

@@ -18,26 +19,31 @@ template <class... T> struct Input : std::tuple<input_type_t<T>...> {
1819
constexpr static const size_t kSize = sizeof...(T);
1920
using value_type = std::tuple<input_type_t<T>...>;
2021
using data_type = std::tuple<T...>;
21-
using index_type = std::array<const std::string, kSize>;
22+
using key_type = std::array<const std::string, kSize>;
2223
};
2324
template <class... T> struct Output : std::tuple<output_type_t<T>...> {
2425
constexpr static const size_t kSize = sizeof...(T);
2526
using value_type = std::tuple<output_type_t<T>...>;
2627
using data_type = std::tuple<T...>;
27-
using index_type = std::array<const std::string, kSize>;
28+
using key_type = std::array<const std::string, kSize>;
2829
};
2930

3031
// TODO: C++20 Concepts version for better error handling
3132
template <class InputType, class OutputType>
32-
class Algorithm : public PropertyMixin, public LoggerMixin {
33+
class Algorithm : public PropertyMixin, public LoggerMixin, public NameMixin {
3334
public:
34-
using Input = typename InputType::value_type;
35-
using Output = typename OutputType::value_type;
36-
using InputNames = typename InputType::index_type;
37-
using OutputNames = typename OutputType::index_type;
35+
using input_type = InputType;
36+
using output_type = OutputType;
37+
using Input = typename input_type::value_type;
38+
using Output = typename output_type::value_type;
39+
using InputNames = typename input_type::key_type;
40+
using OutputNames = typename output_type::key_type;
3841

3942
Algorithm(std::string_view name, const InputNames& input_names, const OutputNames& output_names)
40-
: LoggerMixin(name), m_input_names{input_names}, m_output_names{output_names} {}
43+
: LoggerMixin(name)
44+
, NameMixin(name)
45+
, m_input_names{input_names}
46+
, m_output_names{output_names} {}
4147

4248
void init();
4349
void process(const Input& input, const Output& output);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
namespace algorithms {
4+
5+
// Simple name Mixin providing consistent name API
6+
class NameMixin {
7+
public:
8+
NameMixin(std::string_view name) : m_name{name} {}
9+
std::string_view name() const { return m_name; }
10+
11+
private:
12+
const std::string m_name;
13+
};
14+
15+
} // namespace algorithms
16+

external/algorithms/core/include/algorithms/service.h

+3-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <map>
44
#include <string>
55

6+
#include <algorithms/name.h>
67
#include <algorithms/property.h>
78

89
// Add boilerplate to service class definitions
@@ -55,7 +56,7 @@ class ServiceSvc {
5556
// CRTP base class to add the instance method
5657
// This could have been part of DEFINE_SERVICE macro, but I think it is better
5758
// to keep the macro magic to a minimum to maximize transparency
58-
template <class SvcType> class Service : public PropertyMixin {
59+
template <class SvcType> class Service : public PropertyMixin, public NameMixin {
5960
public:
6061
static SvcType& instance() {
6162
// This is guaranteed to be thread-safe from C++11 onwards.
@@ -64,11 +65,7 @@ template <class SvcType> class Service : public PropertyMixin {
6465
}
6566
// constructor for the service base class registers the service, except
6667
// for the ServiceSvc which is its own thing (avoid circularity)
67-
Service(std::string_view name) : m_name{name} { ServiceSvc::instance().add(name, this); }
68-
std::string_view name() const { return m_name; }
69-
70-
private:
71-
const std::string m_name;
68+
Service(std::string_view name) : NameMixin{name} { ServiceSvc::instance().add(name, this); }
7269
};
7370

7471
} // namespace algorithms

0 commit comments

Comments
 (0)