Skip to content

Commit 66e3773

Browse files
authored
Inclination angle effects in MCH digitizer (#13038)
* first prototype for inclination and impact on resolution
1 parent 8062b96 commit 66e3773

File tree

8 files changed

+120
-27
lines changed

8 files changed

+120
-27
lines changed

Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,25 @@ class Hit : public ::o2::BasicXYZEHit<float>
2525

2626
public:
2727
Hit(int trackId = 0, short detElemId = 0, math_utils::Point3D<float> entrancePoint = {}, const math_utils::Point3D<float> exitPoint = {},
28-
float eloss = 0.0, float length = 0.0, float tof = 0.0)
29-
: ::o2::BasicXYZEHit<float>(entrancePoint.x(), entrancePoint.y(), entrancePoint.z(), tof, eloss, trackId, detElemId), mLength{length}, mExitPoint(exitPoint)
28+
float eloss = 0.0, float length = 0.0, float entranceTof = 0.0, float eTot = 0.0)
29+
: ::o2::BasicXYZEHit<float>(entrancePoint.x(), entrancePoint.y(), entrancePoint.z(), entranceTof, eloss, trackId, detElemId), mLength{length}, mExitPoint(exitPoint), mEtot{eTot}
3030
{
3131
}
3232

3333
math_utils::Point3D<float> entrancePoint() const { return GetPos(); }
3434
math_utils::Point3D<float> exitPoint() const { return mExitPoint; }
3535

36+
// time in s
37+
float entranceTof() const { return GetTime(); }
38+
// particle energy in GeV
39+
float eTot() const { return mEtot; }
40+
3641
short detElemId() const { return GetDetectorID(); }
3742

3843
private:
3944
float mLength = {};
4045
math_utils::Point3D<float> mExitPoint = {};
46+
float mEtot = {};
4147
ClassDefNV(Hit, 1);
4248
};
4349

Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ class Response
3232
public:
3333
Response(Station station);
3434
~Response() = default;
35-
3635
float getChargeSpread() const { return mChargeSpread; }
3736
float getPitch() const { return mPitch; }
3837
float getSigmaIntegration() const { return mSigmaIntegration; }
3938
bool isAboveThreshold(float charge) const { return charge > mChargeThreshold; }
39+
bool isAngleEffect() const { return mAngleEffect; }
40+
bool isMagnetEffect() const { return mMagnetEffect; }
4041

4142
/** Converts energy deposition into a charge.
4243
*
@@ -65,6 +66,20 @@ class Response
6566
/// compute the number of samples corresponding to the charge in ADC units
6667
uint32_t nSamples(float charge) const;
6768

69+
/// compute deteriation of y-resolution due to track inclination and B-field
70+
float inclandbfield(float thetawire, float betagamma, float bx) const;
71+
72+
private:
73+
MathiesonOriginal mMathieson{}; ///< Mathieson function
74+
float mPitch = 0.f; ///< anode-cathode pitch (cm)
75+
float mChargeSlope = 0.f; ///< charge slope used in E to charge conversion
76+
float mChargeSpread = 0.f; ///< width of the charge distribution (cm)
77+
float mSigmaIntegration = 0.f; ///< number of sigmas used for charge distribution
78+
float mChargeCorr = 0.f; ///< amplitude of charge correlation between cathodes
79+
float mChargeThreshold = 0.f; ///< minimum fraction of charge considered
80+
bool mAngleEffect = true; ///< switch for angle effect influencing charge deposition
81+
bool mMagnetEffect = true; ///< switch for magnetic field influencing charge deposition
82+
6883
/// Ratio of particle mean eloss with respect MIP's Khalil Boudjemline, sep 2003, PhD.Thesis and Particle Data Book
6984
float eLossRatio(float logbetagamma) const;
7085
/// ToDo: check Aliroot formula vs PDG, if really log_10 and not ln or bug in Aliroot
@@ -74,22 +89,11 @@ class Response
7489

7590
/// Angle effect: Normalisation form theta=10 degres to theta between 0 and 10 (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis)
7691
/// Angle with respect to the wires assuming that chambers are perpendicular to the z axis.
77-
float angleEffectNorma(float elossratio) const;
92+
float angleEffectNorma(float angle) const;
7893

7994
/// Magnetic field effect: Normalisation form theta=16 degres (eq. 10 degrees B=0) to theta between -20 and 20 (Lamia Benhabib jun 2006 )
8095
/// Angle with respect to the wires assuming that chambers are perpendicular to the z axis.
8196
float magAngleEffectNorma(float angle, float bfield) const;
82-
83-
private:
84-
MathiesonOriginal mMathieson{}; ///< Mathieson function
85-
float mPitch = 0.f; ///< anode-cathode pitch (cm)
86-
float mChargeSlope = 0.f; ///< charge slope used in E to charge conversion
87-
float mChargeSpread = 0.f; ///< width of the charge distribution (cm)
88-
float mSigmaIntegration = 0.f; ///< number of sigmas used for charge distribution
89-
float mChargeCorr = 0.f; ///< amplitude of charge correlation between cathodes
90-
float mChargeThreshold = 0.f; ///< minimum fraction of charge considered
91-
bool mAngleEffect = true; ///< switch for angle effect influencing charge deposition
92-
bool mMagnetEffect = true; ///< switch for magnetic field influencing charge deposition
9397
};
9498
} // namespace mch
9599
} // namespace o2

Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include "DetectorsRaw/HBFUtils.h"
1919
#include "MCHSimulation/DigitizerParam.h"
20+
#include <TGeoGlobalMagField.h>
21+
#include "Field/MagneticField.h"
2022

2123
/// Convert collision time to ROF time (ROF duration = 4 BC)
2224
std::pair<o2::InteractionRecord, uint8_t> time2ROFtime(const o2::InteractionRecord& time)
@@ -25,9 +27,11 @@ std::pair<o2::InteractionRecord, uint8_t> time2ROFtime(const o2::InteractionReco
2527
return std::make_pair(o2::InteractionRecord(time.bc - bc, time.orbit), bc);
2628
}
2729

30+
//_________________________________________________________________________________________________
31+
2832
namespace o2::mch
2933
{
30-
34+
//_________________________________________________________________________________________________
3135
DEDigitizer::DEDigitizer(int deId, math_utils::Transform3D transformation, std::mt19937& random)
3236
: mDeId{deId},
3337
mResponse{deId < 300 ? Station::Type1 : Station::Type2345},
@@ -78,6 +82,26 @@ void DEDigitizer::processHit(const Hit& hit, const InteractionRecord& collisionT
7882
auto localX = mResponse.getAnod(lpos.X());
7983
auto localY = lpos.Y();
8084

85+
// calculate angle between track and wire assuming wire perpendicular to z-axis
86+
// take global coordinates to avoid issues with rotations of detection elements
87+
// neglect rotation of chambers w.r.t. beam
88+
auto thetawire = atan((exitPoint.Y() - entrancePoint.Y()) / (entrancePoint.Z() - exitPoint.Z()));
89+
90+
// local b-field
91+
double b[3] = {0., 0., 0.};
92+
double x[3] = {entrancePoint.X(), entrancePoint.Y(), entrancePoint.Z()};
93+
if (TGeoGlobalMagField::Instance()->GetField()) {
94+
TGeoGlobalMagField::Instance()->Field(x, b);
95+
} else {
96+
LOG(fatal) << "no b field in MCH DEDigitizer";
97+
}
98+
99+
// calculate track betagamma
100+
// assume beta = 1 and mass of charged muon to calculate track betagamma from particle energy
101+
auto betagamma = hit.eTot() / 0.1056583745;
102+
auto yAngleEffect = mResponse.inclandbfield(thetawire, betagamma, b[0]);
103+
localY += yAngleEffect;
104+
81105
// borders of charge integration area
82106
auto dxy = mResponse.getSigmaIntegration() * mResponse.getChargeSpread();
83107
auto xMin = localX - dxy;

Detectors/MUON/MCH/Simulation/src/Response.cxx

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ Response::Response(Station station)
4747
mChargeCorr = ResponseParam::Instance().chargeCorrelation;
4848
mChargeThreshold = ResponseParam::Instance().chargeThreshold;
4949
}
50-
5150
//_____________________________________________________________________
5251
float Response::etocharge(float edepos) const
5352
{
@@ -90,29 +89,66 @@ uint32_t Response::nSamples(float charge) const
9089
return std::round(std::pow(charge / signalParam[1], 1. / signalParam[2]) + signalParam[0]);
9190
}
9291
//_____________________________________________________________________
92+
float Response::inclandbfield(float thetawire, float betagamma, float bx) const
93+
{
94+
float yAngleEffect = 0;
95+
// auxiliary variables for b-field and inclination angle effect
96+
float eLossParticleElossMip = 0.0;
97+
float sigmaEffect10degrees = 0.0;
98+
float sigmaEffectThetadegrees = 0.0;
99+
100+
if (isAngleEffect()) {
101+
if (!isMagnetEffect()) {
102+
thetawire = abs(thetawire);
103+
if ((betagamma > 3.2) && (thetawire * TMath::RadToDeg() <= 15.)) {
104+
betagamma = log(betagamma); // check if ln or log10
105+
eLossParticleElossMip = eLossRatio(betagamma);
106+
sigmaEffect10degrees = angleEffect10(eLossParticleElossMip);
107+
sigmaEffectThetadegrees = sigmaEffect10degrees / angleEffectNorma(thetawire * TMath::RadToDeg());
108+
if (o2::mch::Station() == o2::mch::Station::Type1) {
109+
sigmaEffectThetadegrees /= 1.09833 + 0.017 * (thetawire * TMath::RadToDeg());
110+
}
111+
yAngleEffect = 0.0001 * gRandom->Gaus(0, sigmaEffectThetadegrees); // error due to the angle effect in cm
112+
}
113+
} else {
114+
if ((betagamma > 3.2) && (abs(thetawire * TMath::RadToDeg()) <= 15.)) {
115+
betagamma = log(betagamma);
116+
eLossParticleElossMip = eLossRatio(betagamma);
117+
sigmaEffect10degrees = angleEffect10(eLossParticleElossMip);
118+
sigmaEffectThetadegrees = sigmaEffect10degrees / magAngleEffectNorma(thetawire * TMath::RadToDeg(), bx / 10.); // check b-field unit in aliroot and O2
119+
if (o2::mch::Station() == o2::mch::Station::Type1) {
120+
sigmaEffectThetadegrees /= 1.09833 + 0.017 * (thetawire * TMath::RadToDeg());
121+
}
122+
yAngleEffect = 0.0001 * gRandom->Gaus(0, sigmaEffectThetadegrees);
123+
}
124+
}
125+
}
126+
return yAngleEffect;
127+
}
128+
//_____________________________________________________________________
93129
float Response::eLossRatio(float logbetagamma) const
94130
{
95131
// Ratio of particle mean eloss with respect MIP's Khalil Boudjemline, sep 2003, PhD.Thesis and Particle Data Book
96132
/// copied from aliroot AliMUONv1.cxx
97133
float eLossRatioParam[5] = {1.02138, -9.54149e-02, +7.83433e-02, -9.98208e-03, +3.83279e-04};
98-
return eLossRatioParam[0] + eLossRatioParam[1] * logbetagamma + eLossRatioParam[2] * std::pow(logbetagamma, 2) + eLossRatioParam[3] * std::pow(logbetagamma, 3) + eLossRatioParam[4] * std::pow(logbetagamma, 4);
134+
return eLossRatioParam[0] + eLossRatioParam[1] * logbetagamma + eLossRatioParam[2] * logbetagamma * logbetagamma + eLossRatioParam[3] * logbetagamma * logbetagamma * logbetagamma + eLossRatioParam[4] * logbetagamma * logbetagamma * logbetagamma * logbetagamma;
99135
}
100136
//_____________________________________________________________________
101137
float Response::angleEffect10(float elossratio) const
102138
{
103139
/// Angle effect in tracking chambers at theta =10 degres as a function of ElossRatio (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) (in micrometers)
104140
/// copied from aliroot AliMUONv1.cxx
105141
float angleEffectParam[3] = {1.90691e+02, -6.62258e+01, 1.28247e+01};
106-
return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * std::pow(elossratio, 2);
142+
return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * elossratio * elossratio;
107143
}
108144
//_____________________________________________________________________
109-
float Response::angleEffectNorma(float elossratio) const
145+
float Response::angleEffectNorma(float angle) const
110146
{
111147
/// Angle effect: Normalisation form theta=10 degres to theta between 0 and 10 (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis)
112148
/// Angle with respect to the wires assuming that chambers are perpendicular to the z axis.
113149
/// copied from aliroot AliMUONv1.cxx
114150
float angleEffectParam[4] = {4.148, -6.809e-01, 5.151e-02, -1.490e-03};
115-
return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * std::pow(elossratio, 2) + angleEffectParam[3] * std::pow(elossratio, 3);
151+
return angleEffectParam[0] + angleEffectParam[1] * angle + angleEffectParam[2] * angle * angle + angleEffectParam[3] * angle * angle * angle;
116152
}
117153
//_____________________________________________________________________
118154
float Response::magAngleEffectNorma(float angle, float bfield) const
@@ -122,5 +158,5 @@ float Response::magAngleEffectNorma(float angle, float bfield) const
122158
/// copied from aliroot AliMUONv1.cxx
123159
float angleEffectParam[7] = {8.6995, 25.4022, 13.8822, 2.4717, 1.1551, -0.0624, 0.0012};
124160
float aux = std::abs(angle - angleEffectParam[0] * bfield);
125-
return 121.24 / ((angleEffectParam[1] + angleEffectParam[2] * std::abs(bfield)) + angleEffectParam[3] * aux + angleEffectParam[4] * std::pow(aux, 2) + angleEffectParam[5] * std::pow(aux, 3) + angleEffectParam[6] * std::pow(aux, 4));
161+
return 121.24 / ((angleEffectParam[1] + angleEffectParam[2] * std::abs(bfield)) + angleEffectParam[3] * aux + angleEffectParam[4] * aux * aux + angleEffectParam[5] * aux * aux * aux + angleEffectParam[6] * aux * aux * aux * aux);
126162
}

Detectors/MUON/MCH/Simulation/src/Stepper.cxx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ void Stepper::process(const TVirtualMC& vmc)
5959
if (t.isEntering()) {
6060
float x, y, z;
6161
vmc.TrackPosition(x, y, z);
62+
mTof = (float)vmc.TrackTime();
6263
mEntrancePoint.SetXYZ(x, y, z);
6364
resetStep();
6465
}
@@ -68,9 +69,11 @@ void Stepper::process(const TVirtualMC& vmc)
6869

6970
if (t.isExiting() || t.isStopped()) {
7071
float x, y, z;
72+
float etot;
7173
vmc.TrackPosition(x, y, z);
74+
etot = (float)vmc.Etot();
7275
mHits->emplace_back(stack->GetCurrentTrackNumber(), detElemId, mEntrancePoint,
73-
math_utils::Point3D<float>{x, y, z}, mTrackEloss, mTrackLength);
76+
math_utils::Point3D<float>{x, y, z}, mTrackEloss, mTrackLength, mTof, etot);
7477
resetStep();
7578
}
7679
}

Detectors/MUON/MCH/Simulation/src/Stepper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class Stepper
4343
private:
4444
float mTrackEloss{0.0};
4545
float mTrackLength{0.0};
46+
float mTof{0.0};
4647
std::vector<o2::mch::Hit>* mHits{nullptr};
4748
math_utils::Point3D<float> mEntrancePoint;
4849
};

Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
#include "MCHSimulation/Hit.h"
2929
#include "SimulationDataFormat/MCCompLabel.h"
3030
#include "SimulationDataFormat/MCTruthContainer.h"
31+
#include "Field/MagneticField.h"
3132
#include "TGeoManager.h"
33+
#include "TGeoGlobalMagField.h"
3234
#include "boost/format.hpp"
3335
#include <boost/test/data/test_case.hpp>
3436
#include <boost/property_tree/ptree.hpp>
@@ -50,6 +52,20 @@ struct GEOMETRY {
5052
}
5153
};
5254

55+
void initField(float l3Current, float dipoleCurrent)
56+
{
57+
/// Create the magnetic field map if not already done
58+
if (TGeoGlobalMagField::Instance()->GetField()) {
59+
return;
60+
}
61+
62+
auto field =
63+
o2::field::MagneticField::createFieldMap(l3Current, dipoleCurrent, o2::field::MagneticField::kConvLHC, false, 3500.,
64+
"A-A", "$(O2_ROOT)/share/Common/maps/mfchebKGI_sym.root");
65+
TGeoGlobalMagField::Instance()->SetField(field);
66+
TGeoGlobalMagField::Instance()->Lock();
67+
}
68+
5369
namespace
5470
{
5571
short detElemId1 = 101;
@@ -100,6 +116,8 @@ BOOST_AUTO_TEST_CASE(DigitizerTest)
100116
o2::conf::ConfigurableParam::setValue("MCHDigitizer", "seed", 123);
101117
o2::mch::Digitizer digitizer(transformation);
102118

119+
initField(-30000.0, -6000.0);
120+
103121
int trackId1 = 0;
104122
int trackId2 = 1;
105123
int trackId3 = 2;
@@ -108,13 +126,14 @@ BOOST_AUTO_TEST_CASE(DigitizerTest)
108126
float eloss = 1.e-6;
109127
float length = 0.f;
110128
float tof = 0.f;
129+
float energ = 10.0;
111130

112131
std::vector<o2::mch::Hit> hits1(2);
113-
hits1.at(0) = o2::mch::Hit(trackId1, detElemId1, entrancePoint1, exitPoint1, eloss, length, tof);
114-
hits1.at(1) = o2::mch::Hit(trackId2, detElemId2, entrancePoint2, exitPoint2, eloss, length, tof);
132+
hits1.at(0) = o2::mch::Hit(trackId1, detElemId1, entrancePoint1, exitPoint1, eloss, length, tof, energ);
133+
hits1.at(1) = o2::mch::Hit(trackId2, detElemId2, entrancePoint2, exitPoint2, eloss, length, tof, energ);
115134

116135
std::vector<o2::mch::Hit> hits2(1);
117-
hits2.at(0) = o2::mch::Hit(trackId3, detElemId3, entrancePoint3, exitPoint3, eloss, length, tof);
136+
hits2.at(0) = o2::mch::Hit(trackId3, detElemId3, entrancePoint3, exitPoint3, eloss, length, tof, energ);
118137

119138
digitizer.processHits(hits1, collisionTime1, 0, 0);
120139
digitizer.processHits(hits2, collisionTime2, 0, 0);

Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace mch
4545
class MCHDPLDigitizerTask : public o2::base::BaseDPLDigitizer
4646
{
4747
public:
48-
MCHDPLDigitizerTask() : o2::base::BaseDPLDigitizer(o2::base::InitServices::GEOM) {}
48+
MCHDPLDigitizerTask() : o2::base::BaseDPLDigitizer(o2::base::InitServices::FIELD | o2::base::InitServices::GEOM) {}
4949

5050
void initDigitizerTask(framework::InitContext& ic) override
5151
{

0 commit comments

Comments
 (0)