ARTEMIS-CRIB
 
Loading...
Searching...
No Matches
TReconstProcessor.cc
Go to the documentation of this file.
1/**
2 * @file TReconstProcessor.cc
3 * @brief for solid target reconstruction
4 * @author Kodai Okawa <okawa@cns.s.u-tokyo.ac.jp>
5 * @date 2024-09-03 14:33:39
6 * @note last modified: 2024-09-03 17:05:31
7 * @details
8 */
9
10#include "TReconstProcessor.h"
11
13#include "TReactionInfo.h"
14#include <Mass.h> // TSrim library
15#include <TFile.h>
16#include <TGraph.h>
17#include <TKey.h>
18#include <TLorentzVector.h>
19#include <TRandom.h>
20
22
24
25////////////////////////////////////////////////////////////////////////////////
26/// From telescope object and beam (tracking) object, it calculate the
27/// Ecm assuming reaction position is z = 0 for solid target.
28///
29/// Need variables in the steering file:
30/// - InputCollection: telescope object, inherit from art::TTelescopeData
31/// - InputTrackCollection: tracking object, inherit from art::TTrack
32/// - OutputCollection: name of output branch, inherit from art::TReactionInfo
33/// - ParticleZArray: [Z1, Z2, Z3, Z4]
34/// - ParticleAArray: [A1, A2, A3, A4]
35/// - assuming two body reaction (NEED size 4 aray)
36/// - [beam, target, fragment, residual]
37/// - example: A(a,b)B reaction,
38/// - the order is [a, A, b, B]
39/// - this is "inverse kinematics", so we assume the detected particle is "B"
40///
41/// Option:
42/// - ExcitedEnergy: if you want to treat excited state transition, input the
43/// excited energy (MeV) of Z3 particles
44/// - UseCenterPosition: use center position at the detector.
45/// - if DSSSD is not working, this flag is used.
46
47TReconstProcessor::TReconstProcessor() : fInData(nullptr), fInTrackData(nullptr), fOutData(nullptr) {
48 RegisterInputCollection("InputCollection", "telescope data inherit from TTelescopeData", fInputColName,
49 TString("tel"));
50 RegisterInputCollection("InputTrackCollection", "tracking data inherit from TTrack", fInputTrackColName,
51 TString("track"));
52 RegisterOutputCollection("OutputCollection", "reconstracted reaction information using TGTIK method", fOutputColName,
53 TString("result"));
54
55 IntVec_t init_i_vec;
56 RegisterProcessorParameter("ParticleZArray", "particle atomic numbers of the reaction", fParticleZArray, init_i_vec);
57 RegisterProcessorParameter("ParticleAArray", "particle mass numbers of the reaction", fParticleAArray, init_i_vec);
58
59 // custom function
60 RegisterProcessorParameter("ExcitedEnergy", "excited energy", fExcitedEnergy, -1.0);
61
62 RegisterOptionalInputInfo("DetectorParameter", "name of telescope parameter", fDetectorParameterName,
63 TString("prm_detectors"), &fDetectorPrm, "TClonesArray", "art::crib::TDetectorParameter");
64 RegisterOptionalInputInfo("TargetParameter", "name of target parameter", fTargetParameterName,
65 TString("prm_targets"), &fTargetPrm, "TClonesArray", "art::crib::TTargetParameter");
66 RegisterProcessorParameter("UseCenterPosition", "custom, use center position at the detecgtor", fDoCenterPos, false);
67}
68
69////////////////////////////////////////////////////////////////////////////////
70/// free the memory
71
76
77////////////////////////////////////////////////////////////////////////////////
78/// in this process, it prepares some variables
79
80void TReconstProcessor::Init(TEventCollection *col) {
81 Info("Init", "%s, %s => %s", fInputColName.Data(), fInputTrackColName.Data(), fOutputColName.Data());
82
83 fInData = reinterpret_cast<TClonesArray **>(col->GetObjectRef(fInputColName.Data()));
84 if (!fInData) {
85 SetStateError(Form("input not found: %s", fInputColName.Data()));
86 return;
87 }
88
89 fInTrackData = reinterpret_cast<TClonesArray **>(col->GetObjectRef(fInputTrackColName.Data()));
90 if (!fInTrackData) {
91 SetStateError(Form("input not found: %s", fInputTrackColName.Data()));
92 return;
93 }
94
95 const TClass *const cl1 = (*fInData)->GetClass();
96 const TClass *const cl2 = (*fInTrackData)->GetClass();
97 if (!(cl1->InheritsFrom(art::crib::TTelescopeData::Class()))) {
98 SetStateError(Form("%s need to inherit from TTelescopeData", fInputColName.Data()));
99 return;
100 }
101 if (!(cl2->InheritsFrom(art::TTrack::Class()))) {
102 SetStateError(Form("%s need to inherit from TTrack", fInputTrackColName.Data()));
103 return;
104 }
105
106 if (!fDetectorPrm) {
107 SetStateError(Form("input not found: %s", fDetectorParameterName.Data()));
108 return;
109 }
110
111 if (!fTargetPrm) {
112 SetStateError(Form("input not found: %s", fTargetParameterName.Data()));
113 return;
114 }
115
116 if (fParticleZArray.size() != 4 || fParticleAArray.size() != 4) {
117 SetStateError("Particle array size should be 4 in the steering file");
118 return;
119 }
120
121 // unit = mass (MeV)
122 M1 = amdc::Mass(fParticleZArray[0], fParticleAArray[0]) * amdc::amu;
123 M2 = amdc::Mass(fParticleZArray[1], fParticleAArray[1]) * amdc::amu;
124 M3_default = amdc::Mass(fParticleZArray[2], fParticleAArray[2]) * amdc::amu;
125 M4 = amdc::Mass(fParticleZArray[3], fParticleAArray[3]) * amdc::amu;
126
127 if (fExcitedEnergy > 0)
129 else
130 M3 = M3_default;
131
132 Info("Init", "reconstract the reaction: %d%s + %d%s -> %d%s + %d%s <- detect",
133 fParticleAArray[0], amdc::GetEl(fParticleZArray[0]).c_str(),
134 fParticleAArray[1], amdc::GetEl(fParticleZArray[1]).c_str(),
135 fParticleAArray[2], amdc::GetEl(fParticleZArray[2]).c_str(),
136 fParticleAArray[3], amdc::GetEl(fParticleZArray[3]).c_str());
137
138 Info("Init", "\tQ-value: %lf MeV", (M1 + M2) - (M3 + M4));
139
140 // prepare output collection
141 fOutData = new TClonesArray("art::crib::TReactionInfo");
142 fOutData->SetName(fOutputColName);
143 col->Add(fOutputColName, fOutData, fOutputIsTransparent);
144
145 gRandom->SetSeed(time(nullptr));
146}
147
148////////////////////////////////////////////////////////////////////////////////
149/// Main process
150
152 fOutData->Clear("C");
153
154 Int_t nData = (*fInData)->GetEntriesFast();
155 if (nData == 0)
156 return;
157 else if (nData != 1) {
158 std::cerr << "warning: the input " << fInputColName << " entry number is not 1, but " << nData << std::endl;
159 }
160
161 Int_t nTrackData = (*fInTrackData)->GetEntriesFast();
162 if (nTrackData == 0)
163 return;
164 if (nTrackData != 1) {
165 std::cerr << "warning: the input " << fInputTrackColName << " entry number is not 1, but " << nTrackData
166 << std::endl;
167 }
168
169 const TDataObject *const inData = static_cast<TDataObject *>((*fInData)->At(0));
170 const TTelescopeData *const Data = dynamic_cast<const TTelescopeData *>(inData);
171 const TDataObject *const inTrackData = static_cast<TDataObject *>((*fInTrackData)->At(0));
172 const TTrack *const TrackData = dynamic_cast<const TTrack *>(inTrackData);
173
174 if (!IsValid(Data->GetTelID()))
175 return;
176
177 // energy threshold
178 if (Data->GetEtotal() < 0.01)
179 return;
180
181 // excited energy process
182 Double_t excited_energy = 0.0;
183 if (fExcitedEnergy > 0)
184 excited_energy = fExcitedEnergy;
185
186 // reaction position
187 Double_t z = 0.0;
188 Double_t Ecm = GetEcmFromDetectParticle(z, TrackData, Data);
189
190 if (!IsValid(Ecm))
191 return;
192
193 TReactionInfo *outData = static_cast<TReactionInfo *>(fOutData->ConstructedAt(0));
194 outData->SetID(0);
195 outData->SetXYZ(TrackData->GetX(z), TrackData->GetY(z), z);
196
197 outData->SetEnergy(Ecm);
198 outData->SetBeamEnergy(Ecm * ((M1 + M2) / M2));
199
200 auto [ELab, ALab] = GetELabALabPair(z, TrackData, Data);
201 outData->SetThetaL((180.0 / TMath::Pi()) * ALab);
202 outData->SetTheta(180.0 - (180.0 / TMath::Pi()) * GetCMAngle(ELab, Ecm, ALab)); // inverse kinematics
203 outData->SetExEnergy(excited_energy);
204}
205
206////////////////////////////////////////////////////////////////////////////////
207/// From <b>assuming Z position (reaction position) = 0</b>,
208/// calculate the Ecm from detected particle information.
209/// Currently it uses classsic kinematics.
210
211Double_t TReconstProcessor::GetEcmFromDetectParticle(Double_t z, const TTrack *track, const TTelescopeData *data) {
212 auto [energy, theta] = GetELabALabPair(z, track, data);
213 if (!IsValid(energy))
214 return kInvalidD;
215
216 // kinematics (using bisection method) detected particle id=3
217 // return GetEcm_kinematics(energy, theta, 0.01, 1.0e+4);
218
219 // classic kinematics
220 return GetEcm_classic_kinematics(energy, theta);
221}
222
223////////////////////////////////////////////////////////////////////////////////
224/// From <b>assuming Z position (reaction position)</b>,
225/// calculate the ELab and ALab of Z4 from detected particle information.
226/// It uses TSrim library.
227
228std::pair<Double_t, Double_t> TReconstProcessor::GetELabALabPair(Double_t z, const TTrack *track, const TTelescopeData *data) {
229 Int_t tel_id = data->GetTelID();
230 const TParameterObject *const inPrm = static_cast<TParameterObject *>((*fDetectorPrm)->At(tel_id - 1));
231 const TDetectorParameter *Prm = dynamic_cast<const TDetectorParameter *>(inPrm);
232 if (!Prm) {
233 std::cerr << "parameter is not found" << std::endl;
234 return {kInvalidD, kInvalidD};
235 }
236
237 Int_t stripNum[2] = {Prm->GetStripNum(0), Prm->GetStripNum(1)};
238 Int_t stripID[2] = {data->GetXID(), data->GetYID()};
239 Double_t stripSize[2] = {Prm->GetSize(0) / (Double_t)stripNum[0], Prm->GetSize(1) / (Double_t)stripNum[1]};
240
241 Double_t det_x, det_y;
242 if (fDoCenterPos)
243 det_x = -Prm->GetSize(0) / 2.0 + Prm->GetSize(0);
244 else if (stripID[0] >= 0 && stripID[0] < stripNum[0])
245 det_x = -Prm->GetSize(0) / 2.0 + stripSize[0] * (Double_t)stripID[0];
246 else
247 det_x = -Prm->GetSize(0) / 2.0 + Prm->GetSize(0);
248
249 if (fDoCenterPos)
250 det_y = -Prm->GetSize(1) / 2.0 + Prm->GetSize(1);
251 else if (stripID[1] >= 0 && stripID[1] < stripNum[1])
252 det_y = -Prm->GetSize(1) / 2.0 + stripSize[1] * (Double_t)stripID[1];
253 else
254 det_y = -Prm->GetSize(1) / 2.0 + Prm->GetSize(1);
255
256 TVector3 detect_position(det_x, det_y, Prm->GetDistance());
257 detect_position.RotateY(Prm->GetAngle()); // rad
258 detect_position += TVector3(Prm->GetCenterRotPos(0), Prm->GetCenterRotPos(1), Prm->GetCenterRotPos(2));
259
260 TVector3 reaction_position(track->GetX(z), track->GetY(z), z);
261 TVector3 track_direction(track->GetX(1.) - track->GetX(0.), track->GetY(1.) - track->GetY(0.), 1.0);
262
263 Double_t theta = track_direction.Angle(detect_position - reaction_position); // LAB, rad
264 Double_t energy = data->GetEtotal();
265
266 return {energy, theta};
267}
268
269////////////////////////////////////////////////////////////////////////////////
270/// From detected energy and angle, calculate kinematics using relativity.
271/// This is used in GetEcmFromDetectPartice method.
272/// currently not avalable.
273
274Double_t TReconstProcessor::GetEcm_kinematics(Double_t, Double_t, Double_t, Double_t) {
275 return kInvalidD;
276}
277
278////////////////////////////////////////////////////////////////////////////////
279/// From detected energy and angle, calculate kinematics using classic.
280/// This is used in GetEcmFromDetectPartice method.
281/// Please refer from okawa's master thesis for an detail.
282
283Double_t TReconstProcessor::GetEcm_classic_kinematics(Double_t energy, Double_t theta) {
284 Double_t alpha = (M2 * (M1 + M2)) / (2.0 * M1);
285 Double_t beta = (M4 * (M3 + M4)) / (2.0 * M3);
286 Double_t qvalue = (M1 + M2) - (M3 + M4);
287
288 Double_t v4 = TMath::Sqrt(2.0 * energy / M4);
289 // elastic scattering
290 if (TMath::Abs(alpha - beta) < 1.0e-5) {
291 Double_t vcm_elastic = -(qvalue - beta * v4 * v4) / (2.0 * beta * v4 * TMath::Cos(theta));
292 if (vcm_elastic < 0) {
293 std::cerr << "vcm < 0! : vcm = " << vcm_elastic
294 << ", det_energy : " << energy << ", theta : " << theta << std::endl;
295 return kInvalidD;
296 }
297 return alpha * vcm_elastic * vcm_elastic;
298 }
299 Double_t b = (beta * v4 * TMath::Cos(theta)) / (alpha - beta);
300 Double_t c = (qvalue - beta * v4 * v4) / (alpha - beta);
301 Double_t D = b * b - c;
302 if (D < 0) {
303 if (TMath::Abs(D) < 1.0e-5) {
304 D = 0.0;
305 } else {
306 std::cerr << "b^2 - c = " << D << " < 0, det_energy : " << energy << ", theta : " << theta << std::endl;
307 return kInvalidD;
308 }
309 }
310
311 Double_t vcm = -b + TMath::Sqrt(D);
312 if (vcm < 0) {
313 std::cerr << "vcm < 0! : vcm = " << -b << " + " << TMath::Sqrt(D) << ", det_energy : " << energy
314 << ", theta : " << theta << std::endl;
315 return kInvalidD;
316 }
317
318 return alpha * vcm * vcm;
319}
320
321////////////////////////////////////////////////////////////////////////////////
322/// Assuming Ecm and detected energy, calculate CM angle.
323/// This is also used classic kinematics
324
325Double_t TReconstProcessor::GetCMAngle(Double_t ELab, Double_t Ecm, Double_t ALab) {
326 Double_t alpha = (M2 * (M1 + M2)) / (2.0 * M1);
327 Double_t beta = (M4 * (M3 + M4)) / (2.0 * M3);
328 Double_t qvalue = (M1 + M2) - (M3 + M4);
329
330 Double_t v4 = TMath::Sqrt(2.0 * ELab / M4);
331 Double_t vcm = TMath::Sqrt(Ecm / alpha);
332 Double_t v4cm = TMath::Sqrt((Ecm + qvalue) / beta);
333
334 Double_t theta_cm = TMath::ACos((v4 * TMath::Cos(ALab) - vcm) / v4cm);
335 return theta_cm;
336}
ClassImp(TReconstProcessor)
for solid target reconstruction
Double_t GetCenterRotPos(Int_t id) const
Int_t GetStripNum(Int_t id) const
Double_t GetSize(Int_t id) const
void SetEnergy(Double_t arg)
void SetExEnergy(Double_t arg)
void SetThetaL(Double_t arg)
void SetTheta(Double_t arg)
void SetBeamEnergy(Double_t arg)
void SetXYZ(Double_t x, Double_t y, Double_t z)
Double_t GetEcm_classic_kinematics(Double_t energy, Double_t theta)
Get Ecm from detected particle information (classic kinematics)
TClonesArray * fOutData
output object (TClonesArray(art::TReactionInfo))
Double_t GetCMAngle(Double_t ELab, Double_t Ecm, Double_t ALab)
Get Lab Angle after reconstruction.
IntVec_t fParticleZArray
reaction particles Atomic num array
IntVec_t fParticleAArray
reaction particles Mass num array
std::pair< Double_t, Double_t > GetELabALabPair(Double_t z, const TTrack *track, const TTelescopeData *data)
Get LAB energy and angle from detected particle information.
TString fInputTrackColName
input tracking collection name (art::TTrack)
TReconstProcessor()
Default constructor.
Double_t GetEcmFromDetectParticle(Double_t z, const TTrack *track, const TTelescopeData *data)
Get Ecm from detected particle information.
void Init(TEventCollection *col) override
Initialization.
TString fInputColName
input telescope collection name (art::TTelescopeData)
void Process() override
Main process.
TString fDetectorParameterName
detector parameter name (art::TDetectorParameter)
TClonesArray ** fInTrackData
tracking input object (TClonesArray(art::TTrack))
TString fOutputColName
output collection name (art::TReactionInfo)
~TReconstProcessor() override
Default destructor.
Double_t GetEcm_kinematics(Double_t energy, Double_t theta, Double_t low_e, Double_t high_e)
Get Ecm from detected particle information (relativity kinematics)
TClonesArray ** fTargetPrm
target parameter obejct (TClonesArray(art::TTargetParameter))
Double_t fExcitedEnergy
Excited Energy.
TClonesArray ** fInData
telescope input object (TClonesArray(art::TTelescopeData))
TClonesArray ** fDetectorPrm
detector parameter object (TClonesArray(art::TDetectorParameter))
TString fTargetParameterName
target parameter name (art::TTargetParameter)
Bool_t fDoCenterPos
Flag of custom processor.
Double_t GetEtotal() const
return to the guide