Skip to content

Commit 88ee799

Browse files
authored
Merge pull request #47124 from Jakub-Gajownik/ecal-phase2-reco-gpu-alpaka-integration-150x
Ecal Phase2 Weights-based Reconstruction, Alpaka integration
2 parents ea03b42 + e8bf0bd commit 88ee799

10 files changed

+400
-44
lines changed

Configuration/PyReleaseValidation/python/relval_gpu.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
# mc Run4
3737
# no PU
3838
# Alpaka pixel-only: TTbar: quadruplets any backend, any backend vs cpu validation, profiling, triplets
39+
# Alpaka ECAL-only development: TTbar: any backend
3940
# Alpaka pixel-only: Single Nu E10: any backend
4041
# Alpaka LST-only: TTbar: TRK-only w/ 2 iterations and LST building on any backend
4142
# with PU
@@ -70,6 +71,7 @@
7071

7172
# Run4, Alpaka-based noPU
7273
29634.402, 29634.403, 29634.404, 29634.406, 29634.704,
74+
29634.612,
7375
29661.402,
7476

7577
# Run4, Alpaka-based PU

Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,10 +2118,13 @@ def condition(self, fragment, stepList, key, hasHarvest):
21182118
offset = 0.61,
21192119
)
21202120

2121-
# ECAL Phase 2 workflow running on CPU or GPU (if available)
2122-
upgradeWFs['ecalDevelGPU'] = UpgradeWorkflow_ecalDevel(
2123-
reco = {'--procModifiers': 'gpu'},
2124-
suffix = '_ecalDevelGPU',
2121+
# ECAL Phase 2 workflow running on CPU or GPU with Alpaka code
2122+
upgradeWFs['ecalDevelAlpaka'] = UpgradeWorkflow_ecalDevel(
2123+
reco = {
2124+
'--procModifiers': 'alpaka',
2125+
'--customise' : 'HeterogeneousCore/AlpakaServices/customiseAlpakaServiceMemoryFilling.customiseAlpakaServiceMemoryFilling'
2126+
},
2127+
suffix = '_ecalDevelAlpaka',
21252128
offset = 0.612,
21262129
)
21272130

RecoLocalCalo/EcalRecProducers/plugins/EcalUncalibRecHitSoAToLegacy.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,21 @@ class EcalUncalibRecHitSoAToLegacy : public edm::global::EDProducer<> {
3232
void EcalUncalibRecHitSoAToLegacy::fillDescriptions(edm::ConfigurationDescriptions &confDesc) {
3333
edm::ParameterSetDescription desc;
3434

35-
desc.add<edm::InputTag>("inputCollectionEB",
36-
edm::InputTag("ecalMultiFitUncalibRecHitPortable", "EcalUncalibRecHitsEB"));
3735
desc.add<std::string>("outputLabelEB", "EcalUncalibRecHitsEB");
3836
desc.ifValue(edm::ParameterDescription<bool>("isPhase2", false, true),
3937
false >> (edm::ParameterDescription<edm::InputTag>(
38+
"inputCollectionEB",
39+
edm::InputTag("ecalMultiFitUncalibRecHitPortable", "EcalUncalibRecHitsEB"),
40+
true) and
41+
edm::ParameterDescription<edm::InputTag>(
4042
"inputCollectionEE",
4143
edm::InputTag("ecalMultiFitUncalibRecHitPortable", "EcalUncalibRecHitsEE"),
4244
true) and
4345
edm::ParameterDescription<std::string>("outputLabelEE", "EcalUncalibRecHitsEE", true)) or
44-
true >> edm::EmptyGroupDescription());
46+
true >> (edm::ParameterDescription<edm::InputTag>(
47+
"inputCollectionEB",
48+
edm::InputTag("ecalUncalibRecHitPhase2Portable", "EcalUncalibRecHitsEB"),
49+
true)));
4550
confDesc.add("ecalUncalibRecHitSoAToLegacy", desc);
4651
}
4752

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include "DataFormats/EcalDigi/interface/EcalDigiCollections.h"
2+
#include "DataFormats/EcalDigi/interface/EcalDigiPhase2HostCollection.h"
3+
#include "DataFormats/EcalDigi/interface/alpaka/EcalDigiPhase2DeviceCollection.h"
4+
#include "FWCore/MessageLogger/interface/MessageLogger.h"
5+
#include "FWCore/Utilities/interface/EDGetToken.h"
6+
#include "FWCore/Utilities/interface/EDPutToken.h"
7+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/global/EDProducer.h"
8+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/Event.h"
9+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/EventSetup.h"
10+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/MakerMacros.h"
11+
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
12+
13+
namespace ALPAKA_ACCELERATOR_NAMESPACE {
14+
15+
class EcalPhase2DigiToPortableProducer : public global::EDProducer<> {
16+
public:
17+
explicit EcalPhase2DigiToPortableProducer(edm::ParameterSet const &ps);
18+
~EcalPhase2DigiToPortableProducer() override = default;
19+
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);
20+
21+
void produce(edm::StreamID sid, device::Event &event, device::EventSetup const &setup) const override;
22+
23+
private:
24+
const edm::EDGetTokenT<EBDigiCollectionPh2> inputDigiToken_;
25+
const edm::EDPutTokenT<EcalDigiPhase2HostCollection> outputDigiHostToken_;
26+
};
27+
28+
void EcalPhase2DigiToPortableProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
29+
edm::ParameterSetDescription desc;
30+
31+
desc.add<edm::InputTag>("BarrelDigis", edm::InputTag("simEcalUnsuppressedDigis", ""));
32+
desc.add<std::string>("digisLabelEB", "ebDigis");
33+
34+
descriptions.addWithDefaultLabel(desc);
35+
}
36+
37+
EcalPhase2DigiToPortableProducer::EcalPhase2DigiToPortableProducer(edm::ParameterSet const &ps)
38+
: EDProducer(ps),
39+
inputDigiToken_{consumes(ps.getParameter<edm::InputTag>("BarrelDigis"))},
40+
outputDigiHostToken_{produces(ps.getParameter<std::string>("digisLabelEB"))} {}
41+
42+
void EcalPhase2DigiToPortableProducer::produce(edm::StreamID sid,
43+
device::Event &event,
44+
device::EventSetup const &setup) const {
45+
//input data from event
46+
const auto &inputDigis = event.get(inputDigiToken_);
47+
48+
const uint32_t size = inputDigis.size();
49+
50+
//create host and device Digi collections of required size
51+
EcalDigiPhase2HostCollection digisHostColl{static_cast<int32_t>(size), event.queue()};
52+
auto digisHostCollView = digisHostColl.view();
53+
54+
//iterate over digis
55+
uint32_t i = 0;
56+
for (const auto &inputDigi : inputDigis) {
57+
const unsigned int nSamples = inputDigi.size();
58+
//assign id to host collection
59+
digisHostCollView.id()[i] = inputDigi.id();
60+
if (nSamples > ecalPh2::sampleSize) {
61+
edm::LogError("size_mismatch") << "Number of input samples (" << nSamples
62+
<< ") larger than the maximum sample size (" << ecalPh2::sampleSize
63+
<< "). Ignoring the excess samples.";
64+
}
65+
//iterate over sample in digi, make sure the size of the input is not larger than the max sample size in Phase 2, if smaller set to 0
66+
for (unsigned int sample = 0; sample < ecalPh2::sampleSize; ++sample) {
67+
if (sample < nSamples) {
68+
//get samples from input digi
69+
EcalLiteDTUSample thisSample = inputDigi[sample];
70+
//assign adc data to host collection
71+
digisHostCollView.data()[i][sample] = thisSample.raw();
72+
} else {
73+
digisHostCollView.data()[i][sample] = 0;
74+
}
75+
}
76+
++i;
77+
}
78+
digisHostCollView.size() = i;
79+
80+
//emplace device collection in the event
81+
event.emplace(outputDigiHostToken_, std::move(digisHostColl));
82+
}
83+
} // namespace ALPAKA_ACCELERATOR_NAMESPACE
84+
85+
DEFINE_FWK_ALPAKA_MODULE(EcalPhase2DigiToPortableProducer);
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <alpaka/alpaka.hpp>
2+
3+
#include "DataFormats/EcalDigi/interface/alpaka/EcalDigiPhase2DeviceCollection.h"
4+
#include "DataFormats/EcalDigi/interface/EcalDataFrame_Ph2.h"
5+
#include "DataFormats/EcalDigi/interface/EcalDigiCollections.h"
6+
#include "DataFormats/EcalRecHit/interface/alpaka/EcalUncalibratedRecHitDeviceCollection.h"
7+
#include "DataFormats/EcalRecHit/interface/EcalUncalibratedRecHit.h"
8+
9+
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
10+
#include "HeterogeneousCore/AlpakaInterface/interface/traits.h"
11+
#include "HeterogeneousCore/AlpakaInterface/interface/workdivision.h"
12+
13+
#include "EcalUncalibRecHitPhase2WeightsAlgoPortable.h"
14+
#include "EcalUncalibRecHitPhase2WeightsStruct.h"
15+
16+
namespace ALPAKA_ACCELERATOR_NAMESPACE::ecal::weights {
17+
using namespace cms::alpakatools;
18+
19+
class Phase2WeightsKernel {
20+
public:
21+
ALPAKA_FN_ACC void operator()(Acc1D const& acc,
22+
EcalUncalibRecHitPhase2Weights const* weightsObj,
23+
EcalDigiPhase2DeviceCollection::ConstView digisDev,
24+
EcalUncalibratedRecHitDeviceCollection::View uncalibratedRecHitsDev) const {
25+
constexpr int nsamples = ecalPh2::sampleSize;
26+
auto const nchannels = digisDev.size();
27+
// one thread sets the output collection size scalar
28+
if (once_per_grid(acc)) {
29+
uncalibratedRecHitsDev.size() = digisDev.size();
30+
}
31+
32+
auto const* weightsdata = weightsObj->weights.data();
33+
auto const* timeWeightsdata = weightsObj->timeWeights.data();
34+
//divide the grid into uniform elements
35+
for (auto tx : uniform_elements(acc, nchannels)) {
36+
bool g1 = false;
37+
const auto& digi = digisDev[tx].data();
38+
auto recHit = uncalibratedRecHitsDev[tx];
39+
recHit.amplitude() = 0;
40+
recHit.jitter() = 0;
41+
for (int s = 0; s < nsamples; ++s) {
42+
const auto sample = digi[s];
43+
const auto trace =
44+
(static_cast<float>(ecalLiteDTU::adc(sample))) * ecalPh2::gains[ecalLiteDTU::gainId(sample)];
45+
recHit.amplitude() += (trace * weightsdata[s]);
46+
recHit.jitter() += (trace * timeWeightsdata[s]);
47+
if (ecalLiteDTU::gainId(sample) == 1)
48+
g1 = true;
49+
recHit.outOfTimeAmplitudes()[s] = 0.;
50+
}
51+
recHit.amplitudeError() = 1.0f;
52+
recHit.id() = digisDev.id()[tx];
53+
recHit.flags() = 0;
54+
recHit.pedestal() = 0.;
55+
recHit.jitterError() = 0.;
56+
recHit.chi2() = 0.;
57+
recHit.aux() = 0;
58+
if (g1) {
59+
recHit.flags() = 0x1 << EcalUncalibratedRecHit::kHasSwitchToGain1;
60+
}
61+
} //if within nchannels
62+
} //kernel}
63+
};
64+
65+
void phase2Weights(EcalDigiPhase2DeviceCollection const& digis,
66+
EcalUncalibratedRecHitDeviceCollection& uncalibratedRecHits,
67+
EcalUncalibRecHitPhase2Weights const* weightsObj,
68+
Queue& queue) {
69+
// use 64 items per group (arbitrary value, a reasonable starting point)
70+
uint32_t items = 64;
71+
// use as many groups as needed to cover the whole problem
72+
uint32_t groups = divide_up_by(digis->metadata().size(), items);
73+
//create the work division
74+
auto workDiv = make_workdiv<Acc1D>(groups, items);
75+
//launch the kernel
76+
alpaka::exec<Acc1D>(
77+
queue, workDiv, Phase2WeightsKernel{}, weightsObj, digis.const_view(), uncalibratedRecHits.view());
78+
}
79+
80+
} // namespace ALPAKA_ACCELERATOR_NAMESPACE::ecal::weights
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef RecoLocalCalo_EcalRecProducers_plugins_alpaka_EcalUncalibRecHitPhase2WeightsAlgoPortable_h
2+
#define RecoLocalCalo_EcalRecProducers_plugins_alpaka_EcalUncalibRecHitPhase2WeightsAlgoPortable_h
3+
4+
#include "DataFormats/EcalDigi/interface/alpaka/EcalDigiPhase2DeviceCollection.h"
5+
#include "DataFormats/EcalRecHit/interface/alpaka/EcalUncalibratedRecHitDeviceCollection.h"
6+
7+
#include "DataFormats/EcalDigi/interface/EcalDataFrame_Ph2.h"
8+
#include "EcalUncalibRecHitPhase2WeightsStruct.h"
9+
10+
namespace ALPAKA_ACCELERATOR_NAMESPACE::ecal::weights {
11+
12+
void phase2Weights(EcalDigiPhase2DeviceCollection const &digis,
13+
EcalUncalibratedRecHitDeviceCollection &uncalibratedRecHits,
14+
EcalUncalibRecHitPhase2Weights const *weightsObj,
15+
Queue &queue);
16+
17+
} //namespace ALPAKA_ACCELERATOR_NAMESPACE::ecal::weights
18+
19+
#endif // RecoLocalCalo_EcalRecProducers_plugins_EcalUncalibRecHitPhase2WeightsAlgoPortable_h
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#include <array>
2+
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
3+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
4+
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
5+
#include "FWCore/Framework/interface/Frameworkfwd.h"
6+
#include "FWCore/Utilities/interface/StreamID.h"
7+
#include "FWCore/Utilities/interface/InputTag.h"
8+
9+
#include "HeterogeneousCore/AlpakaInterface/interface/config.h"
10+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/Event.h"
11+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/EventSetup.h"
12+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/EDPutToken.h"
13+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/global/EDProducer.h"
14+
#include "HeterogeneousCore/AlpakaCore/interface/alpaka/MakerMacros.h"
15+
#include "HeterogeneousCore/AlpakaCore/interface/MoveToDeviceCache.h"
16+
17+
#include "DataFormats/EcalDigi/interface/EcalDataFrame_Ph2.h"
18+
#include "DataFormats/EcalDigi/interface/EcalConstants.h"
19+
#include "DataFormats/EcalDigi/interface/alpaka/EcalDigiPhase2DeviceCollection.h"
20+
#include "DataFormats/EcalDigi/interface/EcalDigiPhase2HostCollection.h"
21+
#include "DataFormats/EcalRecHit/interface/EcalUncalibratedRecHitHostCollection.h"
22+
#include "DataFormats/EcalRecHit/interface/alpaka/EcalUncalibratedRecHitDeviceCollection.h"
23+
#include "DataFormats/Portable/interface/PortableObject.h"
24+
25+
#include "EcalUncalibRecHitPhase2WeightsAlgoPortable.h"
26+
#include "EcalUncalibRecHitPhase2WeightsStruct.h"
27+
28+
namespace ALPAKA_ACCELERATOR_NAMESPACE {
29+
class EcalUncalibRecHitPhase2WeightsProducerPortable : public global::EDProducer<> {
30+
public:
31+
explicit EcalUncalibRecHitPhase2WeightsProducerPortable(edm::ParameterSet const &ps);
32+
~EcalUncalibRecHitPhase2WeightsProducerPortable() override = default;
33+
static void fillDescriptions(edm::ConfigurationDescriptions &);
34+
35+
void produce(edm::StreamID sid, device::Event &, device::EventSetup const &) const override;
36+
37+
private:
38+
using InputProduct = EcalDigiPhase2DeviceCollection;
39+
const device::EDGetToken<InputProduct> digisToken_; //both tokens stored on the device
40+
using OutputProduct = EcalUncalibratedRecHitDeviceCollection;
41+
const device::EDPutToken<OutputProduct> uncalibratedRecHitsToken_;
42+
43+
// class data member
44+
cms::alpakatools::MoveToDeviceCache<Device, PortableHostObject<EcalUncalibRecHitPhase2Weights>> weightsCache_;
45+
};
46+
47+
// constructor with initialisation of elements
48+
EcalUncalibRecHitPhase2WeightsProducerPortable::EcalUncalibRecHitPhase2WeightsProducerPortable(
49+
const edm::ParameterSet &ps)
50+
: EDProducer(ps),
51+
digisToken_{consumes(ps.getParameter<edm::InputTag>("digisLabelEB"))},
52+
uncalibratedRecHitsToken_{produces(ps.getParameter<std::string>("uncalibratedRecHitsLabelEB"))},
53+
weightsCache_(PortableHostObject<EcalUncalibRecHitPhase2Weights>(
54+
cms::alpakatools::host(), [](const edm::ParameterSet &ps) {
55+
EcalUncalibRecHitPhase2Weights weights;
56+
const auto amp_weights = ps.getParameter<std::vector<double>>("weights");
57+
const auto timeWeights = ps.getParameter<std::vector<double>>("timeWeights");
58+
for (unsigned int i = 0; i < ecalPh2::sampleSize; ++i) {
59+
if (i < amp_weights.size()) {
60+
weights.weights[i] = static_cast<float>(amp_weights[i]);
61+
} else {
62+
weights.weights[i] = 0;
63+
}
64+
if (i < timeWeights.size()) {
65+
weights.timeWeights[i] = static_cast<float>(timeWeights[i]);
66+
} else {
67+
weights.timeWeights[i] = 0;
68+
}
69+
}
70+
return weights;
71+
}(ps))) {}
72+
73+
void EcalUncalibRecHitPhase2WeightsProducerPortable::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
74+
edm::ParameterSetDescription desc;
75+
76+
desc.add<std::string>("uncalibratedRecHitsLabelEB", "EcalUncalibRecHitsEB");
77+
//The weights values below should be kept up to date with those on the CPU version of this module
78+
//stored in RecoLocalCalo/EcalRecProducers/plugins/EcalUncalibRecHitPhase2WeightsProducer.cc
79+
desc.add<std::vector<double>>("weights",
80+
{-0.121016,
81+
-0.119899,
82+
-0.120923,
83+
-0.0848959,
84+
0.261041,
85+
0.509881,
86+
0.373591,
87+
0.134899,
88+
-0.0233605,
89+
-0.0913195,
90+
-0.112452,
91+
-0.118596,
92+
-0.121737,
93+
-0.121737,
94+
-0.121737,
95+
-0.121737});
96+
desc.add<std::vector<double>>("timeWeights",
97+
{0.429452,
98+
0.442762,
99+
0.413327,
100+
0.858327,
101+
4.42324,
102+
2.04369,
103+
-3.42426,
104+
-4.16258,
105+
-2.36061,
106+
-0.725371,
107+
0.0727267,
108+
0.326005,
109+
0.402035,
110+
0.404287,
111+
0.434207,
112+
0.422775});
113+
114+
desc.add<edm::InputTag>("digisLabelEB", edm::InputTag("ecalPhase2DigiToPortableProducer", "ebDigis"));
115+
116+
descriptions.addWithDefaultLabel(desc);
117+
}
118+
119+
void EcalUncalibRecHitPhase2WeightsProducerPortable::produce(edm::StreamID sid,
120+
device::Event &event,
121+
const device::EventSetup &setup) const {
122+
//get the device collection of digis
123+
auto const &digis = event.get(digisToken_);
124+
125+
//get size of digis
126+
const uint32_t size = digis->metadata().size();
127+
128+
//allocate output product on the device
129+
OutputProduct uncalibratedRecHits{static_cast<int32_t>(size), event.queue()};
130+
131+
//do not run the algo if there are no digis
132+
if (size > 0) {
133+
auto const &weightsObj = weightsCache_.get(event.queue());
134+
//launch the asynchronous work
135+
ecal::weights::phase2Weights(digis, uncalibratedRecHits, weightsObj.const_data(), event.queue());
136+
}
137+
//put the output collection into the event
138+
event.emplace(uncalibratedRecHitsToken_, std::move(uncalibratedRecHits));
139+
}
140+
141+
} //namespace ALPAKA_ACCELERATOR_NAMESPACE
142+
DEFINE_FWK_ALPAKA_MODULE(EcalUncalibRecHitPhase2WeightsProducerPortable);

0 commit comments

Comments
 (0)