EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SmearHandBook_1_2.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SmearHandBook_1_2.cxx
1 // Based on
2 // Electron-Ion Collider Detector Requirements and R&D Handbook
3 // Version 1.2 February 25, 2020
4 // Page 26
5 // Retrieved from
6 // http://www.eicug.org/web/content/detector-rd
7 // http://www.eicug.org/web/sites/default/files/EIC_HANDBOOK_v1.2.pdf
8 
9 // Additional details from discussions within the calorimetry working group:
10 //
11 // > These are two configuration for hadron endcap we talked today to consider.
12 // > Base configuration:
13 // > EM - W/ScFi, granularity 2.5 cm x 2.5 cm, 12% stochastic, 2% constant terms
14 // > HCal- Fe/Sc, granularity 10 x 10 cm, 50% stochastic, 10% constant
15 
16 // > Configuration 2:
17 // > EM is the same as above.
18 // > HCal -Pb/Sc, 10 x 10 cm, 45% stochastic, 6% constant terms.
19 
20 // > Alternative ECAL
21 // > Shashlyk, Pb/Sc 5.5 x5.5, 8% stochastic, 2% constant.
22 
23 // > Thanks,
24 // > Oleg [Tsai]
25 
26 
29 #include "eicsmear/smear/Device.h"
31 #include "eicsmear/smear/Smearer.h"
34 #include <eicsmear/smear/Smear.h>
36 #include "Math/Vector4D.h"
37 
38 // declare static --> local to this file, won't clash with others
39 static double ThetaFromEta( const double eta );
40 
42 
43  gSystem->Load("libeicsmear");
44 
45  // Create the detector object to hold all devices
46  Smear::Detector det;
47 
48  // The framework provides implementations of three kinematic calculation methods
49  // from smeared values
50  // NM - "Null method" uses the scattered lepton.
51  // DA - Double Angle method
52  // JB - Jacquet-Blondel method
53  // Important Notes:
54  // - All methods rely on measured energy and momentum components (lepton for NM, hadrons for DA, JB).
55  // In order to rely on these methods, you therefore _need_ to cover the relevant
56  // regions with smearers for momentum, angles and energy.
57  // - This is exacerbated by the fact that in the current implementation a smearing of e.g. P
58  // may fool the framework into assuming theta is measured to be the initialization value 0,
59  // leading to nan or inf or otherwise wrong calculations.
60  // NM catches P=0 and replaces it in calculations with E,
61  // but JB and DA either don't work at all or report nonsenical values.
62  // - It may be advantageous to use a P measurement in place of E in a more general case.
63  // In the future, we plan to change to a weighted mean approach.
64  // The summary of the above is that the user should be mindful of the limitations and assumptions in
65  // the calculation of smeared kinematics. Sophisticated calculations are best redone in user code
66  // from the smeared particles directly.
67  det.SetEventKinematicsCalculator("NM DA JB");
68 
69 
70  // IMPORTANT: There are two traps (will be addressed in future releases):
71  // 1) If you smear E but don't provide phi, theta smearers, those values will be
72  // set to 0, not to a fault value and not to the truth level
73  // 2) If you do provide such a smearer, pt and pz will be changed
74  // by a consistency enforcer in Detector::Smear()
75 
76 
77  // As detailed above, we always need phi and theta smearers.
78  // In the absence of handbook values, assume 0.001 radians throughout the acceptance
79  // That's a reasonably conservative guesstimate for tracking,
80  // and probably a bit too good for most calorimeters.
81  // In reality, you would have granularity and clustering assumptions
82  // which are best handled in an afterburner (like tracking efficiency).
83 
84  // Phi and theta smearing for all particles
85  // ----------------------------------------
86  // total coverage of the handbook for tracker and hcal is -3.5 < eta < 3.5
87  Smear::Acceptance::Zone AngleZoneHadronic(ThetaFromEta ( 3.5 ),ThetaFromEta ( -3.5 ));
88  Smear::Device SmearThetaHadronic(Smear::kTheta, "0.001");
89  SmearThetaHadronic.Accept.AddZone(AngleZoneHadronic);
90  SmearThetaHadronic.Accept.SetGenre(Smear::kHadronic);
91  det.AddDevice(SmearThetaHadronic);
92 
93  Smear::Device SmearPhiHadronic(Smear::kPhi, "0.001");
94  SmearPhiHadronic.Accept.AddZone(AngleZoneHadronic);
95  SmearPhiHadronic.Accept.SetGenre(Smear::kHadronic);
96  det.AddDevice(SmearPhiHadronic);
97 
98  // muons are neither hadrons nor electromgnetic
99  Smear::Acceptance::Zone AngleZoneMuon(ThetaFromEta ( 3.5 ),ThetaFromEta ( -3.5 ));
100  Smear::Device SmearThetaMuon(Smear::kTheta, "0.0");
101  SmearThetaMuon.Accept.AddZone(AngleZoneMuon);
102  SmearThetaMuon.Accept.AddParticle(13);
103  SmearThetaMuon.Accept.AddParticle(-13);
104  det.AddDevice(SmearThetaMuon);
105 
106  Smear::Device SmearPhiMuon(Smear::kPhi, "0.0");
107  SmearPhiMuon.Accept.AddZone(AngleZoneMuon);
108  SmearPhiMuon.Accept.AddParticle(13);
109  SmearPhiMuon.Accept.AddParticle(-13);
110  det.AddDevice(SmearPhiMuon);
111 
112  // emcal stretches to -4.5 < eta < 4.5
113  Smear::Acceptance::Zone AngleZoneEmcal(ThetaFromEta ( 4.5 ),ThetaFromEta ( -4.5 ));
114  Smear::Device SmearThetaEmcal(Smear::kTheta, "0.001");
115  SmearThetaEmcal.Accept.AddZone(AngleZoneEmcal);
116  SmearThetaEmcal.Accept.SetGenre(Smear::kElectromagnetic);
117  det.AddDevice(SmearThetaEmcal);
118 
119  Smear::Device SmearPhiEmcal(Smear::kPhi, "0.001");
120  SmearPhiEmcal.Accept.AddZone(AngleZoneEmcal);
121  SmearPhiEmcal.Accept.SetGenre(Smear::kElectromagnetic);
122  det.AddDevice(SmearPhiEmcal);
123 
124  // Tracking
125  // --------
126  // Note: Smear::kCharged checks pdg charge, so includes muons (good)
127  // eta = -3.5 -- -2.5
128  // sigma_p/p ~ 0.1% p+2.0%
129  Smear::Acceptance::Zone TrackBack1Zone(ThetaFromEta ( -2.5 ),ThetaFromEta ( -3.5 ));
130  Smear::Device TrackBack1P(Smear::kP, "sqrt( pow ( 0.001*P*P, 2) + pow ( 0.02*P, 2) )");
131  TrackBack1P.Accept.AddZone(TrackBack1Zone);
132  TrackBack1P.Accept.SetCharge(Smear::kCharged);
133  // TrackBack1P.Accept.SetGenre(Smear::kHadronic);
134  det.AddDevice(TrackBack1P);
135 
136  // eta = -2.5 -- -1
137  // sigma_p/p ~ 0.05% p+1.0%
138  Smear::Acceptance::Zone TrackBack2Zone(ThetaFromEta ( -1 ),ThetaFromEta ( -2.5 ));
139  Smear::Device TrackBack2P(Smear::kP, "sqrt( pow ( 0.0005*P*P, 2) + pow ( 0.01*P, 2) )");
140  TrackBack2P.Accept.AddZone(TrackBack2Zone);
141  TrackBack2P.Accept.SetCharge(Smear::kCharged);
142  // TrackBack2P.Accept.SetGenre(Smear::kHadronic);
143  det.AddDevice(TrackBack2P);
144 
145  // eta = -1 -- +1
146  // sigma_p/p ~ 0.05% p+0.5%
147  Smear::Acceptance::Zone TrackBarrelZone(ThetaFromEta ( 1 ),ThetaFromEta ( -1 ));
148  Smear::Device TrackBarrelP(Smear::kP, "sqrt( pow ( 0.0005*P*P, 2) + pow ( 0.005*P, 2) )");
149  TrackBarrelP.Accept.AddZone(TrackBarrelZone);
150  TrackBarrelP.Accept.SetCharge(Smear::kCharged);
151  // TrackBarrelP.Accept.SetGenre(Smear::kHadronic);
152  det.AddDevice(TrackBarrelP);
153 
154  // eta = 1 -- 2.5
155  // sigma_p/p ~ 0.05% p+1.0%
156  Smear::Acceptance::Zone TrackFwd2Zone(ThetaFromEta ( 2.5 ),ThetaFromEta ( 1 ));
157  Smear::Device TrackFwd2P(Smear::kP, "sqrt( pow ( 0.0005*P*P, 2) + pow ( 0.01*P, 2) )");
158  TrackFwd2P.Accept.AddZone(TrackFwd2Zone);
159  TrackFwd2P.Accept.SetCharge(Smear::kCharged);
160  // TrackFwd2P.Accept.SetGenre(Smear::kHadronic);
161  det.AddDevice(TrackFwd2P);
162 
163  // eta = 2.5 -- 3.5
164  // sigma_p/p ~ 0.1% p+2.0%
165  Smear::Acceptance::Zone TrackFwd1Zone(ThetaFromEta ( 3.5 ),ThetaFromEta ( 2.5 ));
166  Smear::Device TrackFwd1P(Smear::kP, "sqrt( pow ( 0.001*P*P, 2) + pow ( 0.02*P, 2) )");
167  TrackFwd1P.Accept.AddZone(TrackFwd1Zone);
168  TrackFwd1P.Accept.SetCharge(Smear::kCharged);
169  // TrackFwd1P.Accept.SetGenre(Smear::kHadronic);
170  det.AddDevice(TrackFwd1P);
171 
172  // TODO: Add low-Q^2 tagger: -6.9<eta<-5.8: Delta_theta/theta < 1.5%; 10^-6 < Q2 < 10^-2 GeV2
173  // TODO: Add proton spectrometer: eta>6.2: sigma_intrinsic(|t|)/|t| < 1%; Acceptance: 0.2 < pT < 1.2 GeV/c
174  // TODO: Add material budget X/X0 <~5%
175  // TODO: Add vertexing: sigma_xyz ~ 20 microns, d0(z) ~ d0(r phi) ~ (20 microns)/(pT [GeV]) + 5 microns
176 
177  // EM Calorimeters
178  // ---------------
179  // Note: Smear::kElectromagnetic == gamma + e. Does not include muons (good)
180 
181  // Calorimeter resolution usually given as sigma_E/E = const% + stocastic%/Sqrt{E}
182  // EIC Smear needs absolute sigma: sigma_E = Sqrt{const*const*E*E + stoc*stoc*E}
183 
184  // IMPORTANT: The Handbook table 2 does not provide constant terms,
185  // which may be important for some measurements.
186  // We adapted the handbook here to values provided by the calo DWG where available
187 
188  // Back
189  // eta = -4.5 -- -2
190  // stoch. = 2%
191  // Using const. = 1% (PANDA-ish)
192  // Note: p. 41f calls for stoch = 1--1.5%, const <~ 0.5%
193  Smear::Acceptance::Zone EmcalBackZone(ThetaFromEta ( -2 ),ThetaFromEta ( -4.5 ));
194  Smear::Device EmcalBack(Smear::kE, "sqrt( pow ( 0.01*E,2 ) + pow( 0.01,2)*E)");
195  EmcalBack.Accept.AddZone(EmcalBackZone);
197  det.AddDevice(EmcalBack);
198 
199  // MidBack
200  // eta = -2 -- -1
201  // stoch. = 7%
202  // Could use const. = 1% (bit worse than KLOE)
203  // but using the Calo group's alternative instead, Shashlyk, Pb/Sc 8% stochastic, 2% constant.
204  Smear::Acceptance::Zone EmcalMidBackZone(ThetaFromEta ( -1 ),ThetaFromEta ( -2 ));
205  // Smear::Device EmcalMidBack(Smear::kE, "sqrt( pow ( 0.01*E,2 ) + pow( 0.07,2)*E)");
206  Smear::Device EmcalMidBack(Smear::kE, "sqrt( pow ( 0.02*E,2 ) + pow( 0.08,2)*E)");
207  EmcalMidBack.Accept.AddZone(EmcalMidBackZone);
209  det.AddDevice(EmcalMidBack);
210 
211  // Forward
212  // eta = -1 -- 4.5
213  // stoch. = 10-12%.
214  // From calo group: using 12% and const.=2% (W/SciFi)
215  Smear::Acceptance::Zone EmcalFwdZone(ThetaFromEta ( 4.5 ),ThetaFromEta ( -1 ));
216  Smear::Device EmcalFwd(Smear::kE, "sqrt( pow ( 0.02*E,2 ) + pow( 0.12,2)*E)");
217  EmcalFwd.Accept.AddZone(EmcalFwdZone);
219  det.AddDevice(EmcalFwd);
220 
221  // TODO: Add PID
222  // Could turn on perfect PID
223  // Make sure to not cover more than is covered by the other detectors.
224  // Using the smallest region here, but we could add a second one for
225  // the extended EmCal range
226  // Smear::Acceptance::Zone acceptpid(ThetaFromEta(3.5),ThetaFromEta(-3.5));
227  // Smear::PerfectID pid;
228  // pid.Accept.AddZone(acceptpid);
229  // det.AddDevice( pid );
230 
231  // Hadronic Calorimeters
232  // ----------------------
233  // IMPORTANT: The Handbook table 2 does not provide constant terms,
234  // which may be important for some measurements.
235  // The barrel options modeled after existing instruments will have one,
236  // leaving it at 0 otherwise
237  // Note: kHadronic == |pdg|>110.
238 
239  // Back
240  // eta = -3.5 -- -1
241  // stoch. = 50%
242  // Using configuration 2 from calo group, Pb/Sc 45% stochastic, 6% constant terms.
243  Smear::Acceptance::Zone HcalBackZone(ThetaFromEta ( -1 ),ThetaFromEta ( -3.5 ));
244  Smear::Device HcalBack(Smear::kE, "sqrt(pow( 0.06*E, 2) + pow ( 0.45,2) *E)");
245  HcalBack.Accept.AddZone(HcalBackZone);
246  HcalBack.Accept.SetGenre(Smear::kHadronic);
247  det.AddDevice(HcalBack);
248 
249  // Barrel
250  // Handbook: TBD
251  // Providing two options
252  // ~CMS
253  Smear::Device HcalBarrel(Smear::kE, "sqrt( pow( 0.07*E, 2) + pow( 0.85, 2)*E)");
254  // Zeus
255  // Smear::Device HcalBarrel(Smear::kE, "sqrt( pow( 0.02*E, 2) + pow( 0.35,2) *E)");
256 
257  // eta = -1 -- 1
258  Smear::Acceptance::Zone HcalBarrelZone(ThetaFromEta ( 1 ),ThetaFromEta ( -1 ));
259  HcalBarrel.Accept.AddZone(HcalBarrelZone);
260  HcalBarrel.Accept.SetGenre(Smear::kHadronic);
261  det.AddDevice(HcalBarrel);
262 
263  // Forward
264  // eta = 1 -- 3.5
265  // stoch. = 50%
266  // Using configuration 2 from calo group, Pb/Sc 45% stochastic, 6% constant terms.
267  Smear::Acceptance::Zone HcalFwdZone(ThetaFromEta ( 3.5 ),ThetaFromEta ( 1 ));
268  Smear::Device HcalFwd(Smear::kE, "sqrt(pow( 0.06*E, 2) + pow ( 0.45,2) *E)");
269  HcalFwd.Accept.AddZone(HcalFwdZone);
271  det.AddDevice(HcalFwd);
272 
273  return det;
274 }
275 
276 // -------------------------------------------------------------------
277 double ThetaFromEta( const double eta ) {
278  if ( !std::isnan(eta) && !std::isinf(eta) ) {
279  return 2.0 * atan( exp( -eta ));
280  }
281  throw std::runtime_error("ThetaFromEta called with NaN or Inf");
282  return -1;
283 }