R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandNeutronReconstructionMon.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2025 Members of R3B Collaboration *
4 * *
5 * This software is distributed under the terms of the *
6 * GNU General Public Licence (GPL) version 3, *
7 * copied verbatim in the file "LICENSE". *
8 * *
9 * In applying this license GSI does not waive the privileges and immunities *
10 * granted to it by virtue of its status as an Intergovernmental Organization *
11 * or submit itself to any jurisdiction. *
12 ******************************************************************************/
13
15
16#include <algorithm>
17#include <cmath>
18#include <functional>
19#include <iostream>
20#include <numeric>
21#include <utility>
22
23#include "TClonesArray.h"
24#include "TDirectory.h"
25#include "TH1D.h"
26#include "TH2D.h"
27#include <TFile.h>
28
29#include "FairLogger.h"
30#include "FairMCPoint.h"
31#include "FairRootManager.h"
32#include "FairRtdbRun.h"
33#include "FairRuntimeDb.h"
34
35#include "R3BMCTrack.h"
36#include "R3BNeulandNeutron.h"
37#include "R3BNeulandPoint.h"
38
39static const Double_t c2 = 898.75517873681758374; // cm²/ns²
40static const Double_t massNeutron = 939.565379; // MeV/c²
41
42Double_t Distance(const R3BNeulandNeutron& nn, const FairMCPoint& mc)
43{
44 TVector3 v;
45 mc.Position(v);
46 v -= nn.GetPosition();
47 return std::sqrt(v.Dot(v));
48}
49
50Double_t Score(const std::vector<std::pair<R3BNeulandNeutron, FairMCPoint>>& combination)
51{
52 return std::accumulate(combination.begin(),
53 combination.end(),
54 0.,
55 [](const Double_t sum, const std::pair<R3BNeulandNeutron, FairMCPoint>& pair)
56 { return sum + Distance(pair.first, pair.second); });
57}
58
59template <typename T, typename U>
60std::vector<std::vector<std::pair<T, U>>> GetAllCombinations(std::vector<T> ts /* Copy! */,
61 std::vector<U> us /* Copy! */,
62 std::function<bool(const U&, const U&)> comparator)
63{
64 std::vector<std::vector<std::pair<T, U>>> out;
65
66 // Bring both inputs up to the same length
67 if (ts.size() < us.size())
68 {
69 ts.resize(us.size());
70 }
71 if (us.size() < ts.size())
72 {
73 us.resize(ts.size());
74 }
75
76 std::sort(us.begin(), us.end(), comparator);
77 do
78 {
79 std::vector<std::pair<T, U>> tmp;
80 for (size_t i = 0; i < ts.size(); i++)
81 {
82 tmp.push_back({ ts.at(i), us.at(i) });
83 }
84 out.push_back(std::move(tmp));
85 } while (std::next_permutation(us.begin(), us.end(), comparator));
86
87 return out;
88}
89
91 : FairTask("R3B Neuland Neutron Reconstruction Evaluation")
92 , fInput(input)
93 , fOutput(output)
94{
95 LOG(info) << "Using R3B Neuland Neutron Reconstruction Evaluation";
96}
97
99
101{
102 FairRootManager* ioman = FairRootManager::Instance();
103 if (!ioman)
104 {
105 LOG(fatal) << "R3BNeulandNeutronReconstructionMon::Init: No FairRootManager";
106 return kFATAL;
107 }
108
109 // Set Input: TClonesArray of R3BNeulandNeutrons
110 if (dynamic_cast<TClonesArray*>(ioman->GetObject(fInput)) == nullptr)
111 {
112 LOG(fatal) << "R3BNeulandNeutronReconstructionMon::Init No " << fInput << "!";
113 return kFATAL;
114 }
115 if (!TString((dynamic_cast<TClonesArray*>(ioman->GetObject(fInput)))->GetClass()->GetName())
116 .EqualTo("R3BNeulandNeutron"))
117 {
118 LOG(fatal) << "R3BNeulandNeutronReconstructionMon::Init Branch " << fInput
119 << " does not contain "
120 "R3BNeulandNeutrons!";
121 return kFATAL;
122 }
123 fReconstructedNeutrons = dynamic_cast<TClonesArray*>(ioman->GetObject(fInput));
124
125 // Set Input: TClonesArray of FairMCPoints
126 if (dynamic_cast<TClonesArray*>(ioman->GetObject("NeulandPrimaryPoints")) == nullptr)
127 {
128 LOG(fatal) << "R3BNeulandNeutronReconstructionMon::Init No NeulandPrimaryPoints!";
129 return kFATAL;
130 }
131 if (!TString((dynamic_cast<TClonesArray*>(ioman->GetObject("NeulandPrimaryPoints")))->GetClass()->GetName())
132 .EqualTo("R3BNeulandPoint"))
133 {
134 LOG(fatal) << "R3BNeulandNeutronReconstructionMon::Init Branch NeulandPrimaryPoints "
135 "does not contain R3BNeulandPoint!";
136 return kFATAL;
137 }
138 fPrimaryNeutronInteractionPoints = dynamic_cast<TClonesArray*>(ioman->GetObject("NeulandPrimaryPoints"));
139
140 // Set Input: TClonesArray of R3BMCTrack
141 if (dynamic_cast<TClonesArray*>(ioman->GetObject("MCTrack")) == nullptr)
142 {
143 LOG(fatal) << "R3BNeulandNeutronReconstructionMon::Init No MCTrack!";
144 return kFATAL;
145 }
146 if (!TString((dynamic_cast<TClonesArray*>(ioman->GetObject("MCTrack")))->GetClass()->GetName())
147 .EqualTo("R3BMCTrack"))
148 {
149 LOG(fatal) << "R3BNeulandNeutronReconstructionMon::Init Branch MCTrack "
150 "does not contain FairMCPoints!";
151 return kFATAL;
152 }
153 fMCTracks = dynamic_cast<TClonesArray*>(ioman->GetObject("MCTrack"));
154
155 TH1::AddDirectory(kFALSE);
156
157 fhScore = new TH1D("fhScore", "Neuland Neutron Reconstruction Score (lower is better)", 5000, 0, 5000);
158 fhCountN = new TH1D("fhCountN", "Number of reconstructed Neutrons", 11, -0.5, 10.5);
159 fhCountNdiff =
160 new TH1D("fhCountNdiff", "Number of reacted primary Neutrons - Number of reconstructed Neutrons", 11, -5, 5);
161 fhEdiff = new TH1D("fhEdiff", "Energy of primary Neutron - Energy of reconstructed Neutron", 2001, -1000, 1000);
162
163 fhErel = new TH1D("fhErel", "fhErel", 5000, 0, 5000);
164 fhErelMC = new TH1D("fhErelMC", "fhErelMC", 5000, 0, 5000);
165 fhErelVSnNreco = new TH2D("fhErelVSnNreco", "fhErelVSnNreco", 5000, 0, 5000, 11, -0.5, 10.5);
166
167 fhErelVSnNrecoNPNIPs = new TH2D("fhErelVSnNrecoNPNIPs", "fhErelVSnNrecoNPNIPs", 5000, 0, 5000, 11, -0.5, 10.5);
168
169 fhNreacNreco = new TH2D("fhNreacNreco", "fhNreacNreco", 11, -0.5, 10.5, 11, -0.5, 10.5);
170 fhNreacNreco->GetXaxis()->SetTitle("nReac");
171 fhNreacNreco->GetYaxis()->SetTitle("nReco");
172
173 return kSUCCESS;
174}
175
177{
178 const Int_t nReconstructedNeutrons = fReconstructedNeutrons->GetEntries();
179 std::vector<R3BNeulandNeutron> neutrons;
180 neutrons.reserve(nReconstructedNeutrons);
181 for (Int_t i = 0; i < nReconstructedNeutrons; i++)
182 {
183 neutrons.push_back(*(dynamic_cast<R3BNeulandNeutron*>(fReconstructedNeutrons->At(i))));
184 }
185
186 const Int_t nNPNIPS = fPrimaryNeutronInteractionPoints->GetEntries();
187 std::vector<R3BNeulandPoint> npnips;
188 npnips.reserve(nReconstructedNeutrons);
189 for (Int_t i = 0; i < nNPNIPS; i++)
190 {
191 npnips.push_back(*(dynamic_cast<R3BNeulandPoint*>(fPrimaryNeutronInteractionPoints->At(i))));
192 }
193 fhCountN->Fill(nReconstructedNeutrons);
194 fhCountNdiff->Fill((Int_t)nNPNIPS - (Int_t)nReconstructedNeutrons);
195 fhNreacNreco->Fill(nNPNIPS, nReconstructedNeutrons);
196
197 // Find the lowes score by brute force creating all combinations of MC-known and reconstructed neutron hits.
198 // Score is the sum of distances. Note that detecting a wrong amount of neutrons will create a huge score
199 // WiP. Slow because of all the copying
200 /*const auto allCombinations =
201 GetAllCombinations<R3BNeulandNeutron, FairMCPoint>(neutrons,
202 npnips,
203 [](const FairMCPoint& a, const FairMCPoint& b)
204 {
205 return a.GetTime() < b.GetTime();
206 });
207
208 const auto bestCombination = *std::min_element(allCombinations.begin(),
209 allCombinations.end(),
210 [](const std::vector<std::pair<R3BNeulandNeutron, FairMCPoint>>& a,
211 const std::vector<std::pair<R3BNeulandNeutron, FairMCPoint>>& b)
212 {
213 return Score(a) < Score(b);
214 });
215
216 const Double_t minScore = Score(bestCombination);
217 fhScore->Fill(minScore);
218
219 for (const auto& pair : bestCombination)
220 {
221 if (pair.second.GetEnergyLoss() > 0 || pair.first.GetEkin() > 0)
222 {
223 // TODO: Only for massNeutron
224 if (pair.second.GetEnergyLoss() > 0)
225 {
226 fhEdiff->Fill(pair.second.GetEnergyLoss() * 1000. - massNeutron - pair.first.GetEkin());
227 }
228 else
229 {
230 fhEdiff->Fill(-pair.first.GetEkin());
231 }
232 }
233 }*/
234
235 // Erel
236 // if (nReconstructedNeutrons == 0)
237 {
238 TLorentzVector p4_reco;
239 Double_t m0_reco = 0;
240
241 TLorentzVector p4_mc;
242 Double_t m0_mc = 0;
243
244 TLorentzVector p4_npnips;
245 Double_t m0_npnips = 0;
246
247 for (const auto& neutron : neutrons)
248 {
249 p4_reco += TLorentzVector(neutron.GetP(), neutron.GetEtot());
250 m0_reco += massNeutron;
251 }
252
253 for (const auto& npnip : npnips)
254 {
255 // Workaround mom = 0
256 R3BMCTrack* MCTrack = dynamic_cast<R3BMCTrack*>(fMCTracks->At(npnip.GetTrackID()));
257 p4_npnips += TLorentzVector(MCTrack->GetPx() * 1000.,
258 MCTrack->GetPy() * 1000.,
259 MCTrack->GetPz() * 1000.,
260 MCTrack->GetEnergy() * 1000.);
261 m0_npnips += MCTrack->GetMass() * 1000.;
262 }
263
264 R3BMCTrack* MCTrack;
265 const Int_t nMCTracks = fMCTracks->GetEntries();
266 for (Int_t i = 0; i < nMCTracks; i++)
267 {
268 MCTrack = dynamic_cast<R3BMCTrack*>(fMCTracks->At(i));
269 // We are only interested in primary particles, these should come first,
270 // thus we can stop once the Mother Id != -1
271 if (MCTrack->GetMotherId() != -1)
272 {
273 // break;
274 continue;
275 }
276
277 // For E_rel with reconstructed neutrons, only sum up non-neutron primary particles
278 // This information has to come from the other detectors later.
279 if (MCTrack->GetPdgCode() != 2112)
280 {
281 p4_reco += TLorentzVector(MCTrack->GetPx() * 1000.,
282 MCTrack->GetPy() * 1000.,
283 MCTrack->GetPz() * 1000.,
284 MCTrack->GetEnergy() * 1000.);
285 m0_reco += MCTrack->GetMass() * 1000.;
286
287 p4_npnips += TLorentzVector(MCTrack->GetPx() * 1000.,
288 MCTrack->GetPy() * 1000.,
289 MCTrack->GetPz() * 1000.,
290 MCTrack->GetEnergy() * 1000.);
291 m0_npnips += MCTrack->GetMass() * 1000.;
292 }
293
294 // For comparison, calculate E_rel for all primary particles from MC
295 p4_mc += TLorentzVector(MCTrack->GetPx() * 1000.,
296 MCTrack->GetPy() * 1000.,
297 MCTrack->GetPz() * 1000.,
298 MCTrack->GetEnergy() * 1000.);
299 m0_mc += MCTrack->GetMass() * 1000.;
300 }
301
302 const Double_t minv = p4_reco.Mag() - m0_reco;
303 fhErel->Fill(minv * 1000.);
304 fhErelVSnNreco->Fill(minv * 1000., nReconstructedNeutrons);
305
306 if (fhmErelnReco[nReconstructedNeutrons] == nullptr)
307 {
308 fhmErelnReco[nReconstructedNeutrons] = new TH1D("fhErel" + TString::Itoa(nReconstructedNeutrons, 10),
309 "fhErel" + TString::Itoa(nReconstructedNeutrons, 10),
310 5000,
311 0,
312 5000);
313 }
314 fhmErelnReco.at(nReconstructedNeutrons)->Fill(minv * 1000.);
315
316 const Double_t minv_mc = p4_mc.Mag() - m0_mc;
317 fhErelMC->Fill(minv_mc * 1000.);
318
319 const Double_t minv_npnips = p4_npnips.Mag() - m0_npnips;
320 fhErelVSnNrecoNPNIPs->Fill(minv_npnips * 1000., nNPNIPS);
321 }
322}
323
325{
326 TDirectory* tmp = gDirectory;
327 FairRootManager::Instance()->GetOutFile()->cd();
328
329 gDirectory->mkdir(fOutput);
330 gDirectory->cd(fOutput);
331
332 fhCountN->Write();
333 fhCountNdiff->Write();
334 fhScore->Write();
335 fhEdiff->Write();
336 fhErel->Write();
337 fhErelMC->Write();
338 fhErelVSnNreco->Write();
339 fhErelVSnNrecoNPNIPs->Write();
340 fhNreacNreco->Write();
341
342 for (auto& nh : fhmErelnReco)
343 {
344 nh.second->Write();
345 }
346
347 gDirectory = tmp;
348}
349
ClassImp(R3B::Neuland::Cal2HitPar)
Double_t Distance(const R3BNeulandNeutron &nn, const FairMCPoint &mc)
static const Double_t c2
Double_t Score(const std::vector< std::pair< R3BNeulandNeutron, FairMCPoint > > &combination)
static const Double_t massNeutron
std::vector< std::vector< std::pair< T, U > > > GetAllCombinations(std::vector< T > ts, std::vector< U > us, std::function< bool(const U &, const U &)> comparator)
int GetPdgCode() const
Accessors.
Definition R3BMCTrack.h:48
double GetEnergy() const
Definition R3BMCTrack.h:63
double GetPz() const
Definition R3BMCTrack.h:59
double GetPy() const
Definition R3BMCTrack.h:58
double GetMass() const
Definition R3BMCTrack.h:60
double GetPx() const
Definition R3BMCTrack.h:57
int GetMotherId() const
Definition R3BMCTrack.h:49
TVector3 GetPosition() const
R3BNeulandNeutronReconstructionMon(const TString input="NeulandNeutrons", const TString output="NeulandNeutronReconstructionMon")
STL class.