LDMX Software
TrigElectronProducer.cxx
2
4// #include "SimCore/Event/SimParticle.h"
6#include "TCanvas.h"
7#include "TString.h"
8#include "Trigger/Event/TrigCaloCluster.h"
9#include "Trigger/Event/TrigParticle.h"
10
11namespace trigger {
12
14 spCollName_ = ps.getParameter<std::string>("scoringPlaneCollName");
15 clusterCollName_ = ps.getParameter<std::string>("clusterCollName");
16 eleCollName_ = ps.getParameter<std::string>("eleCollName");
17 propMapName_ = ps.getParameter<std::string>("propMapName");
18}
19
21 if (!event.exists(clusterCollName_)) return;
22 auto ecalClusters{
23 event.getObject<TrigCaloClusterCollection>(clusterCollName_)};
24
25 if (!event.exists(spCollName_)) return;
26 const std::vector<ldmx::SimTrackerHit> TargetSPHit =
27 event.getCollection<ldmx::SimTrackerHit>(spCollName_);
28 // ldmx::SimTrackerHit targetPrimary;
29 // std::map<int,int> tk_to_iTargetSPHit;
30 float xT = 0, yT = 0;
31 for (const auto& hit : TargetSPHit) {
32 if (hit.getTrackID() != 1) continue;
33 if (!(abs(hit.getPdgID()) == 11)) continue;
34 auto xyz = hit.getPosition();
35 if (xyz[2] < 0 || xyz[2] > 1) continue; // select one sp
36 xT = xyz[0];
37 yT = xyz[1];
38 // more details:
39 // https://github.com/LDMX-Software/ldmx-analysis/blob/ch/dev/src/TriggerAnalyzer.cxx
40 }
41
42 // std::vector<ldmx::SimParticle> eles;
43 TrigParticleCollection eles;
44 for (const auto& clus : ecalClusters) {
45 TrigParticle el;
46 // ldmx::SimParticle el;
47
48 // We fit for the response in an eGun sample like this:
49 // Events->Draw("Electron_e[0]/Truth_e[0]:Truth_e[0]","Truth_e[0]>500 &&
50 // Truth_e[0]<3500","prof")
51 // --> update fit to use the electron energy at the ecal face (not target)
52 // -->
53 // Events->Draw("Electron_eClus[0]/TruthEcal_e[0]:TruthEcal_e[0]","TruthEcal_e[0]>500
54 // && TruthEcal_e[0]<3500","prof") TF1* func = new
55 // TF1("func","[0]/x+[1]",500,3500); htemp->Fit(func) float calib_e =
56 // clus.e() / (98.099700/clus.e() + 0.77202700);
57 float calib_e =
58 clus.e() / (184.103 / clus.e() + 0.753756); // divide by response
59
60 // const float dX = clus.x() - xT;
61 // float R = calib_e*(11500/4000.); // convert 11.5m/4GeV (in mm/MeV)
62 // float zd = 240.; // 240mm z detector
63 // float a = dX/zd;
64 // float b = (dX*dX+zd*zd)/(2*R*zd);
65 // float pred_px = clus.e() * (-b+a*sqrt(1+a*a-b*b))/(1+a*a);
66 // float pred_py = clus.e()/4e3 * (clus.y() - yT) * 13.3; //mev/mm
67
68 // Events->Draw("TruthEcal_y-Truth_y -
69 // Electron_dy*240/Electron_zClus","TruthEcal_e>1e3")
70
71 float pred_px = clus.z() > 0
72 ? getPx(calib_e, (240. / clus.z()) * (clus.x() - xT))
73 : 0; // adjust, tracing back to ecal face
74 float pred_py =
75 clus.z() > 0 ? getPy(calib_e, (240. / clus.z()) * (clus.y() - yT)) : 0;
76
77 // std::cout << "expectX " << pred_px << " versus " << fit_px << std::endl;
78 // std::cout << "expectY " << pred_py << " versus " << fit_py << std::endl;
79 float pred_pz = sqrt(
80 std::max(pow(calib_e, 2) - (pow(pred_px, 2) + pow(pred_py, 2)), 0.));
81
82 // produce el
83 Point targ(xT, yT, 0);
84 LorentzVector p4(pred_px, pred_py, pred_pz, calib_e);
85 eles.emplace_back(p4, targ, 11);
86 Point calo(clus.x(), clus.y(),
87 clus.z()); // n.b. "Z" is not at the ECal Face!
88 eles.back().setEndPoint(
89 calo); // clus.x(), clus.y(), clus.z()); how to handle?
90 eles.back().setClusEnergy(clus.e());
91 eles.back().setClusTP(clus.nTP());
92 eles.back().setClusDepth(clus.depth());
93
94 // el.setEnergy(clus.e());
95 // el.setPdgID(11);
96 // el.setCharge(-1);
97 // el.setMass(0.000511);
98 // el.setVertex(0, xT, yT);
99 // el.setMomentum(pred_px, pred_py, pred_pz);
100 // eles.push_back(el);
101 }
102 event.add(eleCollName_, eles);
103}
104
105void TrigElectronProducer::setupMaps(bool isX) {
106 TProfile2D* prof = isX ? propMapx_ : propMapy_;
107 const int N = prof->GetXaxis()->GetNbins();
108 for (int i = 1; i <= N; i++) {
109 TF1* func = new TF1("func", "pol1", -20, 20); // going to fit for px/e
110 TProfile* proj = prof->ProfileY("h", i, i);
111 proj->Fit("func", "q", "", -1, 1);
112 bool debug = false;
113 if (debug) {
114 TCanvas c("c", "");
115 proj->Draw();
116 func->Draw("same");
117 c.SaveAs(TString::Format("debugFit_%d_%d.pdf", int(isX), i));
118 }
119 delete proj;
120 if (isX) {
121 fitsX_.push_back(func);
122 } else {
123 fitsY_.push_back(func);
124 }
125 }
126 return;
127}
128
129float TrigElectronProducer::getP(bool isX, float e, float d) {
130 if (fabs(d) > 300) return 0; // something has gone very wrong
131 const bool debug = false;
132 TProfile2D* prof = isX ? propMapx_ : propMapy_;
133 if (!prof) {
134 if (debug) std::cout << "null pointer" << std::endl;
135 return 0;
136 }
137 int bin1{-9999}, bin2{-9999};
138 bin1 = prof->GetXaxis()->FindBin(e);
139 float frac = e - prof->GetXaxis()->GetBinCenter(bin1);
140 float diff = fabs(prof->GetXaxis()->GetBinCenter(bin1) -
141 prof->GetXaxis()->GetBinCenter(bin2));
142 bin2 = diff > 0 ? bin1 + 1 : bin1 - 1;
143 bin1 = std::max(1, std::min(bin1, prof->GetXaxis()->GetNbins()));
144 bin2 = std::max(1, std::min(bin2, prof->GetXaxis()->GetNbins()));
145 float res1, res2;
146 if (isX) {
147 res1 = fitsX_[bin1 - 1]->GetX(d);
148 res2 = fitsX_[bin2 - 1]->GetX(d);
149 } else {
150 res1 = fitsY_[bin1 - 1]->GetX(d);
151 res2 = fitsY_[bin2 - 1]->GetX(d);
152 }
153
154 if (debug)
155 printf("%f %f %f %f :: %f %f %f \n", d, e,
156 prof->GetXaxis()->GetBinCenter(bin1),
157 prof->GetXaxis()->GetBinCenter(bin2), res1, res2,
158 abs(frac / diff) * res2 + (1 - abs(frac / diff)) * res1);
159 return e * (abs(frac / diff) * res2 + (1 - abs(frac / diff)) * res1);
160}
161
163 ldmx_log(debug) << "Process starts!";
164
165 TFile* f = new TFile(propMapName_.c_str(), "read");
166 propMapx_ = (TProfile2D*)f->Get("profx");
167 propMapx_->SetDirectory(0);
168 propMapy_ = (TProfile2D*)f->Get("profy");
169 propMapy_->SetDirectory(0);
170 f->Close();
171
172 setupMaps(0); // X
173 setupMaps(1); // Y
174
175 return;
176}
177
179 ldmx_log(debug) << "Process ends!";
180
181 // free maps
182 for (int i = 0; i < fitsX_.size(); i++) delete fitsX_[i];
183 for (int i = 0; i < fitsY_.size(); i++) delete fitsY_[i];
184
185 return;
186}
187
188} // namespace trigger
189
190DECLARE_PRODUCER_NS(trigger, TrigElectronProducer);
Class that translates raw positions of ECal module hits into cells in a hexagonal readout.
#define DECLARE_PRODUCER_NS(NS, CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Class which encapsulates information from a hit in a simulated tracking detector.
Trigger electron reconstruction algorithm.
Implements an event buffer system for storing event data.
Definition Event.h:41
bool exists(const std::string &name, const std::string &passName="", bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
Definition Event.cxx:92
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:27
T getParameter(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:89
Represents a simulated tracker hit in the simulation.
std::vector< float > getPosition() const
Get the XYZ position of the hit [mm].
virtual void onProcessStart()
Callback for the EventProcessor to take any necessary action when the processing of events starts,...
virtual void produce(framework::Event &event)
Process the event and put new data products into it.
virtual void onProcessEnd()
Callback for the EventProcessor to take any necessary action when the processing of events finishes,...
virtual void configure(framework::config::Parameters &ps)
Callback for the EventProcessor to configure itself from the given set of parameters.
Class for particles reconstructed by the trigger system.