Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross-correlation algorithm for the ECAL timing reconstruction #33119

Merged
merged 47 commits into from Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
7ba20c8
Rebasing kucc for 11_3
nminafra Feb 12, 2021
38506d2
Simplified inclusion of kucc
nminafra Feb 12, 2021
a93f1a2
Implemented thomreis suggestions iteration 1
nminafra Feb 13, 2021
c0bdba3
scram build code-format
nminafra Feb 13, 2021
a7b115f
kansasMethodCC renamed as crossCorrelationMethod
nminafra Feb 15, 2021
857a61c
added comment for magic constants from EcalUncalibRecHitTimeWeightsAl…
nminafra Feb 15, 2021
4d1c340
kansasMethodCC renamed as crossCorrelationMethod complete
nminafra Feb 17, 2021
13690d6
Second round of thomreis comments
nminafra Feb 17, 2021
465da15
Code cleanup and small performance optimization (EcalUncalibRecHitTim…
nminafra Feb 17, 2021
514e38d
Added parameters in python files
nminafra Feb 17, 2021
d183be0
Added parameters to ParameterSetDescription
nminafra Feb 17, 2021
a74b1fc
Adding test file dedicated to CC method
nminafra Feb 17, 2021
75833b8
working test file
nminafra Feb 17, 2021
21901ad
LogWarning to LogInfo when too many CC iterations
nminafra Feb 19, 2021
3be47f2
slightly more efficient
nminafra Feb 19, 2021
a916b16
Cleanup
nminafra Feb 19, 2021
1e4a5df
Cleanup of test
nminafra Feb 19, 2021
252a9e4
code-checks and code-format
nminafra Feb 19, 2021
45c5972
Further cleanup
nminafra Feb 19, 2021
ad7d742
Fixeing clang warnings
nminafra Mar 10, 2021
ba9e43b
Removing destructor
nminafra Mar 12, 2021
0179ab0
Passing float by value
nminafra Mar 12, 2021
e770087
Constexpr
nminafra Mar 12, 2021
4904d82
More efficient access to vector elements
nminafra Mar 12, 2021
ddf38c2
C++ style cast
nminafra Mar 12, 2021
f5743f8
Using range loop
nminafra Mar 12, 2021
5d248d8
Efficiency improvement
nminafra Mar 12, 2021
c7f9e7d
Efficiency improvement
nminafra Mar 12, 2021
062cc95
Efficiency improvement
nminafra Mar 13, 2021
81c6ce9
const added
nminafra Mar 13, 2021
b81a2a7
const added
nminafra Mar 13, 2021
421fe2f
Const added
nminafra Mar 13, 2021
6af8364
rule 2.12
nminafra Mar 13, 2021
03a441f
Avoid repeated computation inside the loop
nminafra Mar 13, 2021
d29bd1b
rule 2.12
nminafra Mar 13, 2021
f21df41
Constexpr
nminafra Mar 13, 2021
4f60d30
Efficiency improvement
nminafra Mar 13, 2021
3d10143
Reordered public/private
nminafra Mar 13, 2021
ad0c604
Using fac,facM1orP2,facP1
nminafra Mar 13, 2021
44df65f
Using fac,facM1orP2,facP1
nminafra Mar 13, 2021
21cd746
Cleaner test file
nminafra Mar 13, 2021
cf995bc
Using unique_ptr for EcalUncalibRecHitTimingCCAlgo
nminafra Mar 13, 2021
3f74b66
Using single precision float
nminafra Mar 13, 2021
cb78d71
Removed log
nminafra Mar 13, 2021
8442f0b
code-format
nminafra Mar 13, 2021
e47da18
Minor fixes
nminafra Mar 16, 2021
e10760c
errOnTime fix
nminafra Mar 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,43 @@
#ifndef RecoLocalCalo_EcalRecAlgos_EcalUncalibRecHitTimingCCAlgo_HH
#define RecoLocalCalo_EcalRecAlgos_EcalUncalibRecHitTimingCCAlgo_HH

/** \class EcalUncalibRecHitTimingCCAlgo
* CrossCorrelation algorithm for timing reconstruction
*
* \author N. Minafra, J. King, C. Rogan
*/

#include "RecoLocalCalo/EcalRecAlgos/interface/EcalUncalibRecHitRecAbsAlgo.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"

#include "CondFormats/EcalObjects/interface/EcalPedestals.h"
#include "CondFormats/EcalObjects/interface/EcalGainRatios.h"
#include "DataFormats/EcalDigi/interface/EcalConstants.h"
#include "RecoLocalCalo/EcalRecAlgos/interface/EigenMatrixTypes.h"

class EcalUncalibRecHitTimingCCAlgo {
public:
EcalUncalibRecHitTimingCCAlgo(const float startTime, const float stopTime, const float targetTimePrecision);
double computeTimeCC(const EcalDataFrame& dataFrame,
const std::vector<double>& amplitudes,
const EcalPedestals::Item* aped,
const EcalMGPAGainRatio* aGain,
const FullSampleVector& fullpulse,
EcalUncalibratedRecHit& uncalibRecHit,
float errOnTime) const;
Copy link
Contributor

@slava77 slava77 Mar 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
float errOnTime) const;
float& errOnTime) const;

I noticed only now thanks to the static analyzer https://cmssdt.cern.ch/SDT/jenkins-artifacts/pull-request-integration/PR-74f75c/13543/llvm-analysis/report-9ba007.html#EndPath.


private:
const float startTime_;
const float stopTime_;
const float targetTimePrecision_;

static constexpr int TIME_WHEN_NOT_CONVERGING = 100;
static constexpr int MAX_NUM_OF_ITERATIONS = 30;
static constexpr int MIN_NUM_OF_ITERATIONS = 2;
static constexpr float GLOBAL_TIME_SHIFT = 100;

FullSampleVector interpolatePulse(const FullSampleVector& fullpulse, const float t = 0) const;
float computeCC(const std::vector<float>& samples, const FullSampleVector& sigmalTemplate, const float t) const;
};

#endif
157 changes: 157 additions & 0 deletions RecoLocalCalo/EcalRecAlgos/src/EcalUncalibRecHitTimingCCAlgo.cc
@@ -0,0 +1,157 @@
#include "RecoLocalCalo/EcalRecAlgos/interface/EcalUncalibRecHitTimingCCAlgo.h"

EcalUncalibRecHitTimingCCAlgo::EcalUncalibRecHitTimingCCAlgo(const float startTime,
const float stopTime,
const float targetTimePrecision)
: startTime_(startTime), stopTime_(stopTime), targetTimePrecision_(targetTimePrecision) {}

double EcalUncalibRecHitTimingCCAlgo::computeTimeCC(const EcalDataFrame& dataFrame,
const std::vector<double>& amplitudes,
const EcalPedestals::Item* aped,
const EcalMGPAGainRatio* aGain,
const FullSampleVector& fullpulse,
EcalUncalibratedRecHit& uncalibRecHit,
float errOnTime) const {
constexpr unsigned int nsample = EcalDataFrame::MAXSAMPLES;

double maxamplitude = -std::numeric_limits<double>::max();
float pulsenorm = 0.;

std::vector<float> pedSubSamples(nsample);
for (unsigned int iSample = 0; iSample < nsample; iSample++) {
const EcalMGPASample& sample = dataFrame.sample(iSample);

float amplitude = 0.;
int gainId = sample.gainId();

double pedestal = 0.;
double gainratio = 1.;

if (gainId == 0 || gainId == 3) {
pedestal = aped->mean_x1;
gainratio = aGain->gain6Over1() * aGain->gain12Over6();
} else if (gainId == 1) {
pedestal = aped->mean_x12;
gainratio = 1.;
} else if (gainId == 2) {
pedestal = aped->mean_x6;
gainratio = aGain->gain12Over6();
}

amplitude = (static_cast<float>(sample.adc()) - pedestal) * gainratio;

if (gainId == 0) {
//saturation
amplitude = (4095. - pedestal) * gainratio;
}

pedSubSamples[iSample] = amplitude;

if (amplitude > maxamplitude) {
maxamplitude = amplitude;
}
pulsenorm += fullpulse(iSample);
}

int ipulse = -1;
for (auto const& amplit : amplitudes) {
ipulse++;
int bxp3 = ipulse - 2;
int firstsamplet = std::max(0, bxp3);
int offset = 7 - bxp3;

for (unsigned int isample = firstsamplet; isample < nsample; ++isample) {
auto const pulse = fullpulse(isample + offset);
pedSubSamples[isample] = std::max(0., pedSubSamples[isample] - amplit * pulse / pulsenorm);
}
}

// Start of time computation
float tStart = startTime_ + GLOBAL_TIME_SHIFT;
float tStop = stopTime_ + GLOBAL_TIME_SHIFT;
float tM = (tStart + tStop) / 2;

float distStart, distStop;
int counter = 0;

do {
++counter;
distStart = computeCC(pedSubSamples, fullpulse, tStart);
distStop = computeCC(pedSubSamples, fullpulse, tStop);

if (distStart > distStop) {
tStop = tM;
} else {
tStart = tM;
}
tM = (tStart + tStop) / 2;

} while (tStop - tStart > targetTimePrecision_ && counter < MAX_NUM_OF_ITERATIONS);

tM -= GLOBAL_TIME_SHIFT;

if (counter < MIN_NUM_OF_ITERATIONS || counter > MAX_NUM_OF_ITERATIONS - 1) {
tM = TIME_WHEN_NOT_CONVERGING * ecalPh1::Samp_Period;
//Negative error means that there was a problem with the CC
errOnTime = -targetTimePrecision_ / ecalPh1::Samp_Period;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I do not see a value assigned to errOnTime for normal conditions.
Is it intentional?

}

return -tM / ecalPh1::Samp_Period;
}

FullSampleVector EcalUncalibRecHitTimingCCAlgo::interpolatePulse(const FullSampleVector& fullpulse,
const float time) const {
// t is in ns
int shift = time / ecalPh1::Samp_Period;
if (time < 0)
shift -= 1;
float tt = time / ecalPh1::Samp_Period - shift;

FullSampleVector interpPulse;
// 2nd poly with avg
unsigned int numberOfSamples = fullpulse.size();
auto facM1orP2 = 0.25 * tt * (tt - 1);
auto fac = (0.25 * (tt - 2) - 0.5 * (tt + 1)) * (tt - 1);
auto facP1 = (0.25 * (tt + 1) - 0.5 * (tt - 2)) * tt;
for (unsigned int i = 1; i < numberOfSamples - 2; ++i) {
float a =
facM1orP2 * fullpulse[i - 1] + fac * fullpulse[i] + facP1 * fullpulse[i + 1] + facM1orP2 * fullpulse[i + 2];
if (a > 0)
interpPulse[i] = a;
else
interpPulse[i] = 0;
}
interpPulse[0] = facM1orP2 * fullpulse[0] + facP1 * fullpulse[1] + facM1orP2 * fullpulse[2];
interpPulse[numberOfSamples - 2] = facM1orP2 * fullpulse[numberOfSamples - 3] + fac * fullpulse[numberOfSamples - 2] +
facP1 * fullpulse[numberOfSamples - 1];
interpPulse[numberOfSamples - 1] = 2 * facM1orP2 * fullpulse[numberOfSamples - 2] -
4 * facM1orP2 * fullpulse[numberOfSamples - 1] +
facP1 * fullpulse[numberOfSamples - 1];

FullSampleVector interpPulseShifted;
for (int i = 0; i < interpPulseShifted.size(); ++i) {
if (i + shift >= 0 && i + shift < interpPulse.size())
interpPulseShifted[i] = interpPulse[i + shift];
else
interpPulseShifted[i] = 0;
}
return interpPulseShifted;
}

float EcalUncalibRecHitTimingCCAlgo::computeCC(const std::vector<float>& samples,
const FullSampleVector& signalTemplate,
const float time) const {
constexpr int exclude = 1;
float powerSamples = 0.;
float powerTemplate = 0.;
float cc = 0.;
auto interpolated = interpolatePulse(signalTemplate, time);
for (int i = exclude; i < int(samples.size() - exclude); ++i) {
powerSamples += std::pow(samples[i], 2);
powerTemplate += std::pow(interpolated[i], 2);
cc += interpolated[i] * samples[i];
}

float denominator = std::sqrt(powerTemplate * powerSamples);
return cc / denominator;
}
Expand Up @@ -65,7 +65,13 @@ EcalUncalibRecHitWorkerMultiFit::EcalUncalibRecHitWorkerMultiFit(const edm::Para
timealgo_ = ratioMethod;
else if (timeAlgoName == "WeightsMethod")
timealgo_ = weightsMethod;
else if (timeAlgoName != "None")
else if (timeAlgoName == "crossCorrelationMethod") {
timealgo_ = crossCorrelationMethod;
double startTime = ps.getParameter<double>("crossCorrelationStartTime");
double stopTime = ps.getParameter<double>("crossCorrelationStopTime");
double targetTimePrecision = ps.getParameter<double>("crossCorrelationTargetTimePrecision");
computeCC_ = std::make_unique<EcalUncalibRecHitTimingCCAlgo>(startTime, stopTime, targetTimePrecision);
} else if (timeAlgoName != "None")
edm::LogError("EcalUncalibRecHitError") << "No time estimation algorithm defined";

// ratio method parameters
Expand Down Expand Up @@ -472,7 +478,21 @@ void EcalUncalibRecHitWorkerMultiFit::run(const edm::Event& evt,
}
uncalibRecHit.setJitter(timerh);
uncalibRecHit.setJitterError(0.); // not computed with weights
} else { // no time method;

} else if (timealgo_ == crossCorrelationMethod) {
uncalibRecHit.setJitterError(0.);

std::vector<double> amplitudes(activeBX.size());
for (unsigned int ibx = 0; ibx < activeBX.size(); ++ibx)
amplitudes[ibx] = uncalibRecHit.outOfTimeAmplitude(ibx);

float jitterError = 0.;
float jitter = computeCC_->computeTimeCC(*itdg, amplitudes, aped, aGain, fullpulse, uncalibRecHit, jitterError);

uncalibRecHit.setJitter(jitter);
uncalibRecHit.setJitterError(jitterError);

} else { // no time method;
uncalibRecHit.setJitter(0.);
uncalibRecHit.setJitterError(0.);
}
Expand Down Expand Up @@ -661,6 +681,9 @@ edm::ParameterSetDescription EcalUncalibRecHitWorkerMultiFit::getAlgoDescription
edm::ParameterDescription<bool>("kPoorRecoFlagEE", false, true) and
edm::ParameterDescription<double>("chi2ThreshEB_", 65.0, true) and
edm::ParameterDescription<double>("chi2ThreshEE_", 50.0, true) and
edm::ParameterDescription<double>("crossCorrelationStartTime", -25.0, true) and
edm::ParameterDescription<double>("crossCorrelationStopTime", 25.0, true) and
edm::ParameterDescription<double>("crossCorrelationTargetTimePrecision", 0.01, true) and
edm::ParameterDescription<edm::ParameterSetDescription>("EcalPulseShapeParameters", psd0, true));

return psd;
Expand Down
Expand Up @@ -40,6 +40,7 @@
#include "CondFormats/DataRecord/interface/EcalSamplesCorrelationRcd.h"
#include "CondFormats/DataRecord/interface/EcalPulseShapesRcd.h"
#include "CondFormats/DataRecord/interface/EcalPulseCovariancesRcd.h"
#include "RecoLocalCalo/EcalRecAlgos/interface/EcalUncalibRecHitTimingCCAlgo.h"

namespace edm {
class Event;
Expand Down Expand Up @@ -94,7 +95,7 @@ class EcalUncalibRecHitWorkerMultiFit final : public EcalUncalibRecHitWorkerBase
edm::ESGetToken<EcalSampleMask, EcalSampleMaskRcd> sampleMaskToken_;

// time algorithm to be used to set the jitter and its uncertainty
enum TimeAlgo { noMethod, ratioMethod, weightsMethod };
enum TimeAlgo { noMethod, ratioMethod, weightsMethod, crossCorrelationMethod };
TimeAlgo timealgo_ = noMethod;

// time weights method
Expand Down Expand Up @@ -163,6 +164,9 @@ class EcalUncalibRecHitWorkerMultiFit final : public EcalUncalibRecHitWorkerBase
bool kPoorRecoFlagEE_;
double chi2ThreshEB_;
double chi2ThreshEE_;

//Timing Cross Correlation Algo
std::unique_ptr<EcalUncalibRecHitTimingCCAlgo> computeCC_;
};

#endif
Expand Up @@ -73,5 +73,10 @@
kPoorRecoFlagEE = cms.bool(False),
chi2ThreshEB_ = cms.double(65.0),
chi2ThreshEE_ = cms.double(50.0),

# for crossCorrelationMethod
crossCorrelationStartTime = cms.double(-25),
crossCorrelationStopTime = cms.double(25),
crossCorrelationTargetTimePrecision = cms.double(0.01),
)
)
@@ -0,0 +1,97 @@
import FWCore.ParameterSet.Config as cms

from Configuration.StandardSequences.Eras import eras

process = cms.Process('RECO', eras.Run2_2018)

# import of standard configurations
process.load('Configuration.StandardSequences.Services_cff')
process.load('FWCore.MessageService.MessageLogger_cfi')
process.load('Configuration.StandardSequences.GeometryRecoDB_cff')
process.load('Configuration.StandardSequences.MagneticField_AutoFromDBCurrent_cff')
process.load('Configuration.StandardSequences.FrontierConditions_GlobalTag_cff')
process.load('Configuration.StandardSequences.Reconstruction_cff')



process.source = cms.Source('PoolSource',
fileNames = cms.untracked.vstring(
'/store/data/Run2018D/EGamma/RAW/v1/000/323/414/00000/042D6023-E0A2-8649-8D86-445F752A8F6B.root',
),
)


# Other statements
from Configuration.AlCa.GlobalTag import GlobalTag
process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:run2_data', '')


process.maxEvents = cms.untracked.PSet(
input = cms.untracked.int32(1000)
)

#-----------------------------------------
# CMSSW/Hcal non-DQM Related Module import
#-----------------------------------------
process.load('Configuration.StandardSequences.GeometryRecoDB_cff')
process.load("RecoLocalCalo.Configuration.hcalLocalReco_cff")
process.load("RecoLocalCalo.Configuration.ecalLocalRecoSequence_cff")
process.load("EventFilter.HcalRawToDigi.HcalRawToDigi_cfi")
process.load("EventFilter.EcalRawToDigi.EcalUnpackerData_cfi")
process.load("RecoLuminosity.LumiProducer.bunchSpacingProducer_cfi")

# load both cpu plugins
process.load("RecoLocalCalo.EcalRecProducers.ecalMultiFitUncalibRecHit_cfi")
nminafra marked this conversation as resolved.
Show resolved Hide resolved

##
## force HLT configuration for ecalMultiFitUncalibRecHit
##

process.ecalMultiFitUncalibRecHit.algoPSet = cms.PSet(
# for crossCorrelationMethod
timealgo = cms.string( "crossCorrelationMethod" ),
crossCorrelationStartTime = cms.double(-25),
crossCorrelationStopTime = cms.double(25),
crossCorrelationTargetTimePrecision = cms.double(0.01),
)
nminafra marked this conversation as resolved.
Show resolved Hide resolved

##

process.ecalDigis = process.ecalEBunpacker.clone()
process.ecalDigis.InputLabel = cms.InputTag('rawDataCollector')

process.out = cms.OutputModule(
"PoolOutputModule",
fileName = cms.untracked.string("test_uncalib.root")
)

process.finalize = cms.EndPath(process.out)

process.bunchSpacing = cms.Path(
process.bunchSpacingProducer
)

process.digiPath = cms.Path(
process.ecalDigis
)

process.recoPath = cms.Path(
process.ecalMultiFitUncalibRecHit
*process.ecalRecHit
)

process.schedule = cms.Schedule(
process.bunchSpacing,
process.digiPath,
process.recoPath,
process.finalize
)

process.options = cms.untracked.PSet(
numberOfThreads = cms.untracked.uint32(8),
numberOfStreams = cms.untracked.uint32(8),
SkipEvent = cms.untracked.vstring('ProductNotFound'),
wantSummary = cms.untracked.bool(True)
)