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

Add new dEdx calibration and estimator #45016

Merged
merged 1 commit into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Configuration/PyReleaseValidation/python/relval_standard.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,10 @@
### run3-2023 (2023 HI data RawPrime with re-HLT)
workflows[142.0] = ['',['RunHIPhysicsRawPrime2023A','HLTDR3_HI2023ARawprime','RECOHIRUN3_reHLT_2023','HARVESTRUN3_HI2023A']]

### run3-2024 (2024 HI UPC data)
workflows[142.901] = ['',['RunUPC2023','RECODR3_UPC','HARVESTDPROMPTR3']]
workflows[142.902] = ['',['RunUPC2023','RECODR3_HIN','HARVESTDPROMPTR3']]

### fastsim ###
workflows[5.1] = ['TTbarFS', ['TTbarFS','HARVESTFS']]
workflows[5.2] = ['SingleMuPt10FS', ['SingleMuPt10FS','HARVESTFS']]
Expand Down
4 changes: 3 additions & 1 deletion Configuration/PyReleaseValidation/python/relval_steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2689,7 +2689,9 @@ def lhegensim2018ml(fragment,howMuch):
steps['RECODR3_reHLT_2023B']=merge([{'--conditions':'auto:run3_data_prompt_relval', '--hltProcess':'reHLT'},steps['RECODR3']])

steps['RECODR3_2023_HIN']=merge([{'--conditions':'auto:run3_data_prompt', '-s':'RAW2DIGI,L1Reco,RECO,DQM:@commonFakeHLT+@standardDQMFakeHLT', '--repacked':'', '-n':1000},steps['RECODR3_2023']])
steps['RECODR3_2023_UPC']=merge([{'--era':'Run3_2023_UPC', '--conditions':'132X_dataRun3_Prompt_HI_LowPtPhotonReg_v2'},steps['RECODR3_2023_HIN']])
steps['RECODR3_2023_UPC']=merge([{'--era':'Run3_2023_UPC'},steps['RECODR3_2023_HIN']])
steps['RECODR3_HIN']=merge([{'--conditions':'auto:run3_data_prompt', '-s':'RAW2DIGI,L1Reco,RECO,DQM:@commonFakeHLT+@standardDQMFakeHLT', '--repacked':'', '-n':1000},steps['RECODR3']])
steps['RECODR3_UPC']=merge([{'--era':'Run3_UPC'},steps['RECODR3_HIN']])

steps['RECODR3Splash']=merge([{'-n': 2,
'-s': 'RAW2DIGI,L1Reco,RECO,PAT,ALCA:SiStripCalZeroBias+SiStripCalMinBias+TkAlMinBias+EcalESAlign,DQM:@standardDQMFakeHLT+@miniAODDQM'
Expand Down
8 changes: 6 additions & 2 deletions DataFormats/TrackReco/interface/DeDxHit.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace reco {
public:
DeDxHit() {}

DeDxHit(float ch, float mom, float len, uint32_t rawDetId)
: m_charge(ch), m_momentum(mom), m_pathLength(len), m_rawDetId(rawDetId) {}
DeDxHit(float ch, float mom, float len, uint32_t rawDetId, float err = 0)
: m_charge(ch), m_momentum(mom), m_pathLength(len), m_rawDetId(rawDetId), m_error(err) {}

/// Return the angle and thick normalized, calibrated energy release
float charge() const { return m_charge; }
Expand All @@ -27,6 +27,9 @@ namespace reco {
/// Return the rawDetId
uint32_t rawDetId() const { return m_rawDetId; }

/// Return the error of the energy release
float error() const { return m_error; }

bool operator<(const DeDxHit &other) const { return m_charge < other.m_charge; }

private:
Expand All @@ -36,6 +39,7 @@ namespace reco {
float m_momentum;
float m_pathLength;
uint32_t m_rawDetId;
float m_error;
};

typedef std::vector<DeDxHit> DeDxHitCollection;
Expand Down
15 changes: 11 additions & 4 deletions DataFormats/TrackReco/interface/DeDxHitInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ namespace reco {
class DeDxHitInfoContainer {
public:
DeDxHitInfoContainer() : charge_(0.0f), pathlength_(0.0f) {}
DeDxHitInfoContainer(const float charge, const float pathlength, const DetId& detId, const LocalPoint& pos)
: charge_(charge), pathlength_(pathlength), detId_(detId), pos_(pos) {}
DeDxHitInfoContainer(
const float charge, const float pathlength, const DetId& detId, const LocalPoint& pos, const uint8_t& type)
: charge_(charge), pathlength_(pathlength), detId_(detId), pos_(pos), type_(type) {}

float charge() const { return charge_; }
float pathlength() const { return pathlength_; }
const DetId& detId() const { return detId_; }
const LocalPoint& pos() const { return pos_; }
const uint8_t& type() const { return type_; }

private:
//! total cluster charge
Expand All @@ -32,8 +34,10 @@ namespace reco {
DetId detId_;
//! hit position
LocalPoint pos_;
uint8_t type_;
};

static constexpr int Complete = 0, Compatible = 1, Calibration = 2;
typedef std::vector<DeDxHitInfo::DeDxHitInfoContainer> DeDxHitInfoContainerCollection;

public:
Expand All @@ -43,6 +47,7 @@ namespace reco {
float pathlength(size_t i) const { return infos_[i].pathlength(); }
DetId detId(size_t i) const { return infos_[i].detId(); }
const LocalPoint pos(size_t i) const { return infos_[i].pos(); }
const uint8_t type(size_t i) const { return infos_[i].type(); }
const SiPixelCluster* pixelCluster(size_t i) const {
size_t P = 0;
bool isPixel = false;
Expand Down Expand Up @@ -90,16 +95,18 @@ namespace reco {
const float pathlength,
const DetId& detId,
const LocalPoint& pos,
const uint8_t& type,
const SiStripCluster& stripCluster) {
infos_.push_back(DeDxHitInfoContainer(charge, pathlength, detId, pos));
infos_.push_back(DeDxHitInfoContainer(charge, pathlength, detId, pos, type));
stripClusters_.push_back(stripCluster);
}
void addHit(const float charge,
const float pathlength,
const DetId& detId,
const LocalPoint& pos,
const uint8_t& type,
const SiPixelCluster& pixelCluster) {
infos_.push_back(DeDxHitInfoContainer(charge, pathlength, detId, pos));
infos_.push_back(DeDxHitInfoContainer(charge, pathlength, detId, pos, type));
pixelClusters_.push_back(pixelCluster);
}

Expand Down
8 changes: 6 additions & 2 deletions DataFormats/TrackReco/src/classes_def.xml
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,13 @@
</class>


<class name="reco::DeDxHit" ClassVersion="12">
<class name="reco::DeDxHit" ClassVersion="13">
<version ClassVersion="11" checksum="2617380234"/>
<version ClassVersion="12" checksum="3747851168"/>
<version ClassVersion="13" checksum="781849298"/>
</class>
<class name="reco::DeDxHitCollection" />
<class name="std::vector<reco::DeDxHitCollection>" />

<!-- <class pattern="edm::AssociationVector<*>">
<field name="transientVector_" transient="true"/>
Expand All @@ -422,6 +424,7 @@
<class name="edm::AssociationVector<edm::RefProd<std::vector<reco::Track> >,std::vector<std::vector<reco::DeDxHit> >,edm::Ref<std::vector<reco::Track>,reco::Track,edm::refhelper::FindUsingAdvance<std::vector<reco::Track>,reco::Track> >,unsigned int,edm::helper::AssociationIdenticalKeyReference>" >
<field name="transientVector_" transient="true"/>
</class>
<class name="std::pair<edm::Ref<std::vector<reco::Track>,reco::Track,edm::refhelper::FindUsingAdvance<std::vector<reco::Track>,reco::Track> >,std::vector<reco::DeDxHit> >" />
<!-- <class name="reco::DeDxDataCollection"/> -->
<class name="reco::DeDxData" ClassVersion="10">
<version ClassVersion="10" checksum="204721063"/>
Expand Down Expand Up @@ -490,8 +493,9 @@
<class name="edm::Association<std::vector<reco::TrackExtra>>"/>
<class name="edm::Wrapper<edm::Association<std::vector<reco::TrackExtra>>>"/>

<class name="reco::DeDxHitInfo::DeDxHitInfoContainer" ClassVersion="2">
<class name="reco::DeDxHitInfo::DeDxHitInfoContainer" ClassVersion="3">
<version ClassVersion="2" checksum="3964047764"/>
<version ClassVersion="3" checksum="4148946944"/>
</class>
<class name="reco::DeDxHitInfo::DeDxHitInfoContainerCollection"/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
(pp_on_AA | run3_upc).toModify( RecoTrackerAOD.outputCommands,
func=lambda outputCommands: outputCommands.extend(['keep recoTracks_hiConformalPixelTracks_*_*'])
)
run3_upc.toModify( RecoTrackerAOD.outputCommands,
func=lambda outputCommands: outputCommands.extend([
'keep *_dedxPixelLikelihood_*_*',
'keep *_dedxStripLikelihood_*_*',
'keep *_dedxAllLikelihood_*_*'
]))
#RECO content
RecoTrackerRECO = cms.PSet(
outputCommands = cms.untracked.vstring(
Expand Down
2 changes: 2 additions & 0 deletions RecoTracker/DeDx/BuildFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<use name="CondFormats/PhysicsToolsObjects"/>
<use name="CondFormats/DataRecord"/>
<use name="TrackingTools/TrajectoryState"/>
<use name="CalibTracker/SiPixelESProducers"/>
<use name="RecoTracker/PixelLowPtUtilities"/>
<use name="rootcore"/>
<use name="root"/>
<use name="clhep"/>
Expand Down
151 changes: 151 additions & 0 deletions RecoTracker/DeDx/interface/LikelihoodFitDeDxEstimator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#ifndef RecoTracker_DeDx_LikelihoodFitDeDxEstimator_h
#define RecoTracker_DeDx_LikelihoodFitDeDxEstimator_h

#include "RecoTracker/DeDx/interface/BaseDeDxEstimator.h"
#include "DataFormats/TrackReco/interface/DeDxHit.h"

class LikelihoodFitDeDxEstimator : public BaseDeDxEstimator {
public:
LikelihoodFitDeDxEstimator(const edm::ParameterSet& iConfig){};

std::pair<float, float> dedx(const reco::DeDxHitCollection& Hits) override {
if (Hits.empty())
return {0., 0.};
// compute original
std::array<double, 2> value;
const auto& chi2 = estimate(Hits, value);
// try to remove lowest dE/dx measurement
const auto& n = Hits.size();
if (n >= 3 && (chi2 > 1.3 * n + 4 * std::sqrt(1.3 * n))) {
auto hs = Hits;
hs.erase(std::min_element(hs.begin(), hs.end()));
// if got better, accept
std::array<double, 2> v;
if (estimate(hs, v) < chi2 - 12)
value = v;
}
return {value[0], std::sqrt(value[1])};
}

private:
void calculate_wrt_epsilon(const reco::DeDxHit&, const double&, std::array<double, 3>&);
void functionEpsilon(const reco::DeDxHitCollection&, const double&, std::array<double, 3>&);
double minimizeAllSaturated(const reco::DeDxHitCollection&, std::array<double, 2>&);
double newtonMethodEpsilon(const reco::DeDxHitCollection&, std::array<double, 2>&);
double estimate(const reco::DeDxHitCollection&, std::array<double, 2>&);
};

/*****************************************************************************/
void LikelihoodFitDeDxEstimator::calculate_wrt_epsilon(const reco::DeDxHit& h,
const double& epsilon,
std::array<double, 3>& value) {
const auto& ls = h.pathLength();
const auto& sn = h.error(); // energy sigma
const auto y = h.charge() * ls; // = g * y
const auto sD = 2.E-3 + 0.095 * y;
const auto ss = sD * sD + sn * sn;
const auto s = std::sqrt(ss);
const auto delta = epsilon * ls;
const auto dy = delta - y;
constexpr double nu(0.65);

// calculate derivatives with respect to delta
std::array<double, 3> val{{0.}};
if (h.rawDetId() == 0) { // normal
if (dy < -nu * s) {
val[0] = -2. * nu * dy / s - nu * nu;
val[1] = -2. * nu / s;
val[2] = 0.;
} else {
val[0] = dy * dy / ss;
val[1] = 2. * dy / ss;
val[2] = 2. / ss;
}
} else { // saturated
if (dy < s) {
val[0] = -dy / s + 1.;
val[1] = -1. / s;
val[2] = 0.;
} else {
val[0] = 0.;
val[1] = 0.;
val[2] = 0.;
}
}

// d/d delta -> d/d epsilon
val[1] *= ls;
val[2] *= ls * ls;

// sum
for (size_t k = 0; k < value.size(); k++)
value[k] += val[k];
}

/*****************************************************************************/
void LikelihoodFitDeDxEstimator::functionEpsilon(const reco::DeDxHitCollection& Hits,
const double& epsilon,
std::array<double, 3>& val) {
val = {{0, 0, 0}};
for (const auto& h : Hits)
calculate_wrt_epsilon(h, epsilon, val);
}

/*****************************************************************************/
double LikelihoodFitDeDxEstimator::minimizeAllSaturated(const reco::DeDxHitCollection& Hits,
std::array<double, 2>& value) {
int nStep(0);
double par(3.0); // input MeV/cm

std::array<double, 3> val{{0}};
do {
functionEpsilon(Hits, par, val);
if (val[1] != 0)
par += -val[0] / val[1];
nStep++;
} while (val[0] > 1e-3 && val[1] != 0 && nStep < 10);

value[0] = par * 1.1;
value[1] = par * par * 0.01;

return val[0];
}

/*****************************************************************************/
double LikelihoodFitDeDxEstimator::newtonMethodEpsilon(const reco::DeDxHitCollection& Hits,
std::array<double, 2>& value) {
int nStep(0);
double par(3.0); // input MeV/cm
double dpar(0);

std::array<double, 3> val{{0}};
do {
functionEpsilon(Hits, par, val);
if (val[2] != 0.)
dpar = -val[1] / std::abs(val[2]);
else
dpar = 1.; // step up, for epsilon
if (par + dpar > 0)
par += dpar; // ok
else
par /= 2.; // half
nStep++;
} while (std::abs(dpar) > 1e-3 && nStep < 50);

value[0] = par;
value[1] = 2. / val[2];

return val[0];
}

/*****************************************************************************/
double LikelihoodFitDeDxEstimator::estimate(const reco::DeDxHitCollection& Hits, std::array<double, 2>& value) {
// use newton method if at least one hit is not saturated
for (const auto& h : Hits)
if (h.rawDetId() == 0)
return newtonMethodEpsilon(Hits, value);
// else use minimize all saturated
return minimizeAllSaturated(Hits, value);
}

#endif
45 changes: 33 additions & 12 deletions RecoTracker/DeDx/plugins/DeDxEstimatorProducer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ void DeDxEstimatorProducer::fillDescriptions(edm::ConfigurationDescriptions& des
edm::ParameterSetDescription desc;
desc.add<string>("estimator", "generic");
desc.add<edm::InputTag>("tracks", edm::InputTag("generalTracks"));
desc.add<bool>("UseDeDxHits", false);
desc.add<edm::InputTag>("pixelDeDxHits", {});
desc.add<edm::InputTag>("stripDeDxHits", {});
desc.add<bool>("UsePixel", false);
desc.add<bool>("UseStrip", true);
desc.add<double>("MeVperADCPixel", 3.61e-06);
Expand Down Expand Up @@ -62,6 +65,8 @@ DeDxEstimatorProducer::DeDxEstimatorProducer(const edm::ParameterSet& iConfig)
m_estimator = std::make_unique<GenericTruncatedAverageDeDxEstimator>(iConfig);
else if (estimatorName == "unbinnedFit")
m_estimator = std::make_unique<UnbinnedFitDeDxEstimator>(iConfig);
else if (estimatorName == "likelihoodFit")
m_estimator = std::make_unique<LikelihoodFitDeDxEstimator>(iConfig);
else if (estimatorName == "productDiscrim")
m_estimator = std::make_unique<ProductDeDxDiscriminator>(iConfig, cCollector);
else if (estimatorName == "btagDiscrim")
Expand All @@ -76,6 +81,10 @@ DeDxEstimatorProducer::DeDxEstimatorProducer(const edm::ParameterSet& iConfig)

m_tracksTag = consumes<reco::TrackCollection>(iConfig.getParameter<edm::InputTag>("tracks"));

useDeDxHits = iConfig.getParameter<bool>("UseDeDxHits");
m_pixelDeDxHitsTag = consumes<reco::TrackDeDxHitsCollection>(iConfig.getParameter<edm::InputTag>("pixelDeDxHits"));
m_stripDeDxHitsTag = consumes<reco::TrackDeDxHitsCollection>(iConfig.getParameter<edm::InputTag>("stripDeDxHits"));

usePixel = iConfig.getParameter<bool>("UsePixel");
useStrip = iConfig.getParameter<bool>("UseStrip");
meVperADCPixel = iConfig.getParameter<double>("MeVperADCPixel");
Expand Down Expand Up @@ -110,27 +119,39 @@ void DeDxEstimatorProducer::produce(edm::Event& iEvent, const edm::EventSetup& i

edm::Handle<reco::TrackCollection> trackCollectionHandle;
iEvent.getByToken(m_tracksTag, trackCollectionHandle);
const auto& pixelDeDxHits = iEvent.getHandle(m_pixelDeDxHitsTag);
const auto& stripDeDxHits = iEvent.getHandle(m_stripDeDxHitsTag);

std::vector<DeDxData> dedxEstimate(trackCollectionHandle->size());

for (unsigned int j = 0; j < trackCollectionHandle->size(); j++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

minor point, but I think you could probably use an iterator here instead.
I think it would be something like:

     for (it = tracks.begin(); it != tracks.end(); ++it) {
       if (it->isNonnull()) {
         const reco::TrackRef track(tracks, (*it).key());
       }
     }

Copy link
Contributor Author

@stahlleiton stahlleiton Jun 14, 2024

Choose a reason for hiding this comment

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

minor point, but I think you could probably use an iterator here instead. I think it would be something like:

     for (it = tracks.begin(); it != tracks.end(); ++it) {
       if (it->isNonnull()) {
         const reco::TrackRef track(tracks, (*it).key());
       }
     }

Just had a quick look on how implement this comment but I not sure how with current EDToken (that points to std::vector<reco::Track>). Maybe changing to a edm::View<reco::Track> could allow using iterators with edm::Ref

Ok, I think I could do what the comment suggest by using:

for (auto it = trackCollectionHandle->begin(); it != trackCollectionHandle->end(); ++it) {
const auto& j = it - trackCollectionHandle->begin();

But not sure what would be the gain compared to the existing code (since both would still rely on the index)

const reco::TrackRef track = reco::TrackRef(trackCollectionHandle.product(), j);
const reco::TrackRef track = reco::TrackRef(trackCollectionHandle, j);

int NClusterSaturating = 0;
DeDxHitCollection dedxHits;

auto const& trajParams = track->extra()->trajParams();
assert(trajParams.size() == track->recHitsSize());
auto hb = track->recHitsBegin();
dedxHits.reserve(track->recHitsSize() / 2);
for (unsigned int h = 0; h < track->recHitsSize(); h++) {
auto recHit = *(hb + h);
if (!trackerHitRTTI::isFromDet(*recHit))
continue;

auto trackDirection = trajParams[h].direction();
float cosine = trackDirection.z() / trackDirection.mag();
processHit(recHit, track->p(), cosine, dedxHits, NClusterSaturating);
if (useDeDxHits) {
if (usePixel)
dedxHits = (*pixelDeDxHits)[track];
if (useStrip) {
const auto& hits = (*stripDeDxHits)[track];
dedxHits.insert(dedxHits.end(), hits.begin(), hits.end());
}
} else {
auto const& trajParams = track->extra()->trajParams();
assert(trajParams.size() == track->recHitsSize());
auto hb = track->recHitsBegin();
dedxHits.reserve(track->recHitsSize() / 2);
for (unsigned int h = 0; h < track->recHitsSize(); h++) {
auto recHit = *(hb + h);
if (!trackerHitRTTI::isFromDet(*recHit))
continue;

auto trackDirection = trajParams[h].direction();
float cosine = trackDirection.z() / trackDirection.mag();
processHit(recHit, track->p(), cosine, dedxHits, NClusterSaturating);
}
}

sort(dedxHits.begin(), dedxHits.end(), less<DeDxHit>());
Expand Down
Loading