EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SmearCore_0_1.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SmearCore_0_1.cxx
1 // Based on
2 // https://indico.bnl.gov/event/7913/contributions/41704/attachments/30564/47972/200924_Parametrizations.pdf
3 // https://indico.bnl.gov/event/11053/contributions/46969/attachments/33324/53540/core.pdf
4 
5 // From March 29, 2021
6 //
7 // By default, use 3T field
8 // Command line argument allows any other one, but be aware that
9 // it's purely a linear (affine; pol1) inter-/extrapolation
10 // between the parameters at 1.4 and 3T
11 //
12 // Important Notes:
13 // - Where ranges are given, the more conservative number is chosen.
14 // - Without available specifications, angular resolution is assumed to be perfect.
15 // - Momentum and energy acceptance specifications are NOT implemented
16 // -- It is not a priori clear whether cuts should apply to truth or smeared value
17 // -- A "looper" may not reach the detector.
18 // -- On the other hand, a calorimetry deposit may fluctuate above threshold
19 // - PID for pi/K/p is implemented with perfect PID in the acceptance (and momentum range)
20 // - Electron PID is not implemented. Very high purity is important and not handled well with the above approach
21 
24 #include "eicsmear/smear/Device.h"
26 #include "eicsmear/smear/Smearer.h"
29 #include <eicsmear/smear/Smear.h>
31 #include "Math/Vector4D.h"
32 
33 // using valarray instead of vector because entry-wise arithmetic is built-in
34 #include <valarray>
35 
36 // declare static --> local to this file, won't clash with others
37 static double ThetaFromEta( const double eta );
38 
39 // FIXME: Comments
40 static void AssembleCoreTracker ( Smear::Detector& det,
41  const std::valarray<double>& eta_min, const std::valarray<double>& eta_max,
42  const std::valarray<double>& A, const std::valarray<double>& B );
43 
44 
50 static std::valarray<double> CalcA ( const double Bfield,
51  const double x1, const std::valarray<double> A1,
52  const double x2, const std::valarray<double> A2 );
53 
59 static std::valarray<double> CalcB ( const double Bfield,
60  const double x1, const std::valarray<double> B1,
61  const double x2, const std::valarray<double> B2 );
62 
63 Smear::Detector BuildCore_0_1( const double Bfield ) {
64  gSystem->Load("libeicsmear");
65 
66  // Create the detector object to hold all devices
67  Smear::Detector det;
68 
69  // The framework provides implementations of three kinematic calculation methods
70  // from smeared values
71  // NM - "Null method" uses the scattered lepton.
72  // DA - Double Angle method
73  // JB - Jacquet-Blondel method
74  // Users should be mindful of the limitations and assumptions in
75  // the calculation of smeared kinematics. Sophisticated calculations are best redone in user code
76  // from the smeared particles directly.
77  det.SetEventKinematicsCalculator("NM DA JB");
78 
79  // Perfect phi and theta for all particles
80  // ---------------------------------------
81  // total coverage for tracker, ecal, and hcal is -4.0 < eta < 4.0
82  Smear::Acceptance::Zone AngleZoneCommon(ThetaFromEta ( 4.0 ),ThetaFromEta ( -4.0 ));
83  Smear::Device SmearThetaCommon(Smear::kTheta, "0.0");
84  SmearThetaCommon.Accept.AddZone(AngleZoneCommon);
85  SmearThetaCommon.Accept.SetGenre(Smear::kAll);
86  det.AddDevice(SmearThetaCommon);
87 
88  Smear::Device SmearPhiCommon(Smear::kPhi, "0.0");
89  SmearPhiCommon.Accept.AddZone(AngleZoneCommon);
90  SmearPhiCommon.Accept.SetGenre(Smear::kAll);
91  det.AddDevice(SmearPhiCommon);
92 
93  // Tracking (B = 3 T)
94  // --------
95  // Note: Smear::kCharged checks pdg charge, so includes muons (good)
96 
97  // |eta|
98  const std::valarray<double> eta_min = { 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5 };
99  const std::valarray<double> eta_max = { 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4 };
100  // sigma_p/p ~ A% * p + B%
101  const std::valarray<double> A3T = { 0.018, 0.016, 0.016, 0.012, 0.018, 0.039, 0.103, 0.295 };
102  const std::valarray<double> B3T = { 0.369, 0.428, 0.427, 0.462, 0.719, 1.336, 2.428, 4.552 };
103  const std::valarray<double> A1p4T = { 0.038, 0.035, 0.035, 0.026, 0.041, 0.088, 0.217, 0.610 };
104  const std::valarray<double> B1p4T = { 0.816, 0.898, 0.921, 0.997, 1.548, 2.830, 5.234, 9.797 };
105 
106  const std::valarray<double> A = CalcA ( Bfield, 1.4, A1p4T, 3.0, A3T );
107  const std::valarray<double> B = CalcB ( Bfield, 1.4, B1p4T, 3.0, B3T );
108  AssembleCoreTracker ( det, eta_min, eta_max, A, B );
109 
110  // PID
111  // ---
112  // Perfect pi/K/P PID everywhere for now
113  // Make sure to not cover more than is covered by the other detectors.
114  // No minimum momentum is used.
115  // Accept charged hadrons (excludes e, mu)
116 
117  // p < 10 GeV
119  0., TMath::TwoPi(), // phi
120  0., TMath::Infinity(), // E
121  0., 10 ); // p
122  Smear::PerfectID Pid;
123  Pid.Accept.AddZone(PidZone);
126  det.AddDevice( Pid );
127 
128  // EM Calorimeters
129  // ---------------
130  // Note: Smear::kElectromagnetic == gamma + e. Does not include muons (good)
131  // Calorimeter resolution usually given as sigma_E/E = A% / E + B%/Sqrt{E} + C%
132  // EIC Smear needs absolute sigma: sigma_E = Sqrt{A*A + B*B*E + C*C*E*E}
133 
134  // E> 20 (50) MeV not used because it suppresses smeared-up particles
135 
136  // Inner Back
137  // eta = -3.5 -- -2.0
138  // 1%/E + 2.5%/sqrtE + 1%
139  // A B C
140  Smear::Acceptance::Zone EmcalInnerBackZone(ThetaFromEta ( -2.0 ),ThetaFromEta ( -3.5 ));
141  Smear::Device EmcalInnerBack(Smear::kE, "sqrt( pow ( 0.01,2 ) + pow( 0.025,2)*E + pow ( 0.01*E,2 ) )");
142  EmcalInnerBack.Accept.AddZone(EmcalInnerBackZone);
143  EmcalInnerBack.Accept.SetGenre(Smear::kElectromagnetic);
144  det.AddDevice(EmcalInnerBack);
145 
146  // Outer Back / Barrel
147  // eta = -2.0 -- 0.0
148  // 2%/E + 4%/sqrtE + 2%
149  // A B C
150  Smear::Acceptance::Zone EmcalOuterBackZone(ThetaFromEta ( 0.0 ),ThetaFromEta ( -2.0 ));
151  Smear::Device EmcalOuterBack(Smear::kE, "sqrt( pow ( 0.02,2 ) + pow( 0.04,2)*E + pow ( 0.02*E,2 ) )");
152  EmcalOuterBack.Accept.AddZone(EmcalOuterBackZone);
153  EmcalOuterBack.Accept.SetGenre(Smear::kElectromagnetic);
154  det.AddDevice(EmcalOuterBack);
155 
156 
157  // Forward barrel - assume Matrix specs (waiting for Craig Woody's talk)
158  // eta = 0 -- 1
159  // E > 100 MeV (50 MeV if higher resolution)
160  // not used because it suppresses smeared-up particles
161  // 2%/EāŠ•(12-14)%/āˆšEāŠ•(2-3)% for 30 cm space
162  // choosing
163  // 2%/E + 14%/sqrtE + 3%
164  // A B C
165  Smear::Acceptance::Zone EmcalForwardBarrelZone(ThetaFromEta ( 1 ),ThetaFromEta ( 0 ));
166  Smear::Device EmcalForwardBarrel(Smear::kE, "sqrt( pow ( 0.02,2 ) + pow( 0.14,2)*E + pow ( 0.03*E,2 ) )");
167  EmcalForwardBarrel.Accept.AddZone(EmcalForwardBarrelZone);
168  EmcalForwardBarrel.Accept.SetGenre(Smear::kElectromagnetic);
169  det.AddDevice(EmcalForwardBarrel);
170 
171  // Forward outer - assume Matrix specs (waiting for Craig Woody's talk)
172  // eta = 1 -- 2
173  // E > 50 MeV not used because it suppresses smeared-up particles
174  // "2%/E + (4*-12)%/sqrtE + 2% Upper limit achievable with 40cm space
175  // *Better resolution requires ~65 cm space allocated"
176  // choosing
177  // 2%/E + 12%/sqrtE + 2%
178  // A B C
179  Smear::Acceptance::Zone EmcalFwdOuterZone(ThetaFromEta ( 2 ),ThetaFromEta ( 1 )); // E
180  Smear::Device EmcalFwdOuter(Smear::kE, "sqrt( pow ( 0.02,2 ) + pow( 0.12,2)*E + pow ( 0.02*E,2 ) )");
181  EmcalFwdOuter.Accept.AddZone(EmcalFwdOuterZone);
182  EmcalFwdOuter.Accept.SetGenre(Smear::kElectromagnetic);
183  det.AddDevice(EmcalFwdOuter);
184 
185  // > Shashlyk, Pb/Sc 5.5 x5.5, 8% stochastic, 2% constant.
186 
187  // Forward inner - Shashlyk guess
188  // eta = 2 -- 3.5
189  // E > 50 MeV not used because it suppresses smeared-up particles
190  // Optimistic Shashlyk
191  // 2%/E + 8%/sqrtE + 2%
192  // A B C
193  Smear::Acceptance::Zone EmcalFwdInnerZone(ThetaFromEta ( 3.5 ),ThetaFromEta ( 2 )); // E
194  Smear::Device EmcalFwdInner(Smear::kE, "sqrt( pow ( 0.02,2 ) + pow( 0.8,2)*E + pow ( 0.02*E,2 ) )");
195  EmcalFwdInner.Accept.AddZone(EmcalFwdInnerZone);
196  EmcalFwdInner.Accept.SetGenre(Smear::kElectromagnetic);
197  det.AddDevice(EmcalFwdInner);
198 
199 
200  // Hadronic Calorimeters
201  // Assume marix specs (waiting for Oleg Tsai's talk)
202  // Except, aspire to 35 % / sqrt(E) + 2% forward
203  // ----------------------
204  // Note: kHadronic == |pdg|>110.
205 
206  // Back
207  // eta = -3.5 -- -1
208  // E>500 MeV not used because it suppresses smeared-up particles
209  // (Better resolution required more space and R&D)
210  // stoch. = 50%, const = 10%
211  Smear::Acceptance::Zone HcalBackZone(ThetaFromEta ( -1 ),ThetaFromEta ( -3.5 ) );
212  Smear::Device HcalBack(Smear::kE, "sqrt(pow( 0.1*E, 2) + pow ( 0.5,2) *E)");
213  HcalBack.Accept.AddZone(HcalBackZone);
214  HcalBack.Accept.SetGenre(Smear::kHadronic);
215  det.AddDevice(HcalBack);
216 
217  // Barrel
218  // eta = -1 -- 1
219  // E>500 MeV not used because it suppresses smeared-up particles
220  // stoch. = 100%, const = 10%
221  Smear::Acceptance::Zone HcalBarrelZone(ThetaFromEta ( 1 ),ThetaFromEta ( -1 ) ); // E
222  Smear::Device HcalBarrel(Smear::kE, "sqrt( pow( 0.1*E, 2) + pow( 1.0, 2)*E)");
223  HcalBarrel.Accept.AddZone(HcalBarrelZone);
224  HcalBarrel.Accept.SetGenre(Smear::kHadronic);
225  det.AddDevice(HcalBarrel);
226 
227  // Forward
228  // eta = 1 -- 3.5
229  // E>500 MeV not used because it suppresses smeared-up particles
230  // stoch. = 35%, const = 2% (aspirational goal)
231  Smear::Acceptance::Zone HcalFwdZone(ThetaFromEta ( 3.5 ),ThetaFromEta ( 1 ));
232  Smear::Device HcalFwd(Smear::kE, "sqrt(pow( 0.02*E, 2) + pow ( 0.35,2) *E)");
233  HcalFwd.Accept.AddZone(HcalFwdZone);
235  det.AddDevice(HcalFwd);
236 
237  return det;
238 }
239 
240 // -------------------------------------------------------------------
241 double ThetaFromEta( const double eta ) {
242  if ( !std::isnan(eta) && !std::isinf(eta) ) {
243  return 2.0 * atan( exp( -eta ));
244  }
245  throw std::runtime_error("ThetaFromEta called with NaN or Inf");
246  return -1;
247 }
248 
249 // -------------------------------------------------------------------
250 std::valarray<double> CalcA ( const double Bfield,
251  const double x1, const std::valarray<double> A1,
252  const double x2, const std::valarray<double> A2 ){
253  // TODO: Add tests:
254  // - vectors have the same length
255  // - B>=0
256  // - x1<x2
257  // - Result is exact at x1 and x2
258  // - all vector components are >=0
259 
260  // Basic linear interpolation
261  // f ( x ) = f(x1) + ( x-x1 ) * ( f(x2) - f(x1) ) / (x2 - x1 )
262  return A1 + (Bfield - x1 ) * (A2 - A1) / (x2 - x1 );
263 }
264 // -------------------------------------------------------------------
265 std::valarray<double> CalcB ( const double Bfield,
266  const double x1, const std::valarray<double> B1,
267  const double x2, const std::valarray<double> B2 ){
268  // TODO: Add tests:
269  // - vectors have the same length
270  // - B>=0
271  // - x1<x2
272  // - Result is exact at x1 and x2
273  // - all vector components are >=0
274 
275  // Basic linear interpolation
276  // f ( x ) = f(x1) + ( x-x1 ) * ( f(x2) - f(x1) ) / (x2 - x1 )
277  return B1 + (Bfield - x1 ) * (B2 - B1) / (x2 - x1 );
278 }
279 
280 // -------------------------------------------------------------------
282  const std::valarray<double>& eta_min, const std::valarray<double>& eta_max,
283  const std::valarray<double>& A, const std::valarray<double>& B ){
284 
285  // sigma_p/p ~ A% * p + B %
286  const TString SmearString = "sqrt( pow ( AAA *P*P, 2) + pow ( BBB * P, 2) )";
287 
288  for( auto i = 0; i< A.size(); ++i) {
289  auto CurrentString = SmearString;
290  TString AAA = ""; AAA += 0.01*A[i];
291  TString BBB = ""; BBB += 0.01*B[i];
292  CurrentString.ReplaceAll ( "AAA", AAA );
293  CurrentString.ReplaceAll ( "BBB", BBB );
294 
295  Smear::Device TrackPos(Smear::kP, CurrentString);
296  TrackPos.Accept.SetCharge(Smear::kCharged);
297  Smear::Device TrackNeg = TrackPos;
298 
299  // Two zones, acceptance is symmetrical in eta
300  Smear::Acceptance::Zone TrackZonePos( ThetaFromEta ( eta_max[i] ), ThetaFromEta ( eta_min[i] ));
301  Smear::Acceptance::Zone TrackZoneNeg( ThetaFromEta ( -eta_min[i] ), ThetaFromEta ( -eta_max[i] ));
302 
303  TrackPos.Accept.AddZone(TrackZonePos);
304  TrackNeg.Accept.AddZone(TrackZoneNeg);
305  det.AddDevice(TrackPos);
306  det.AddDevice(TrackNeg);
307 
308  // std::cout << i << " " << CurrentString << std::endl;
309  }
310 
311  return;
312 }
313