R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeuland.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
14#include "R3BNeuland.h"
15#include "FairRun.h"
16#include "FairRuntimeDb.h"
17#include "R3BMCStack.h"
18#include "R3BNeulandGeoPar.h"
19#include "TClonesArray.h"
20#include "TGeoManager.h"
21#include "TVirtualMC.h"
22#include <FairRootManager.h>
23#include <FairVolume.h>
24#include <R3BLogger.h>
25
26// Initialize variables from Birk' s Law
27constexpr auto seconds_to_nanoseconds = 1e9;
28constexpr auto BirkdP = 1.032;
29constexpr auto BirkC1 = 0.013 / BirkdP;
30constexpr auto BirkC2 = 9.6e-6 / (BirkdP * BirkdP);
31
32namespace
33{
34 inline auto GetLightYield(const int charge, const double length, const double edep) -> double
35 {
36 // Apply Birk's law ( Adapted from G3BIRK/Geant3)
37 if (charge != 0 && length > 0)
38 {
39 auto birkC1Mod = BirkC1;
40
41 // Apply correction for higher charge states
42 if (TMath::Abs(charge) >= 2)
43 {
44 birkC1Mod *= 7.2 / 12.6; // NOLINT
45 }
46
47 const double dedxcm = 1000. * edep / length;
48 const double lightYield = edep / (1. + birkC1Mod * dedxcm + BirkC2 * dedxcm * dedxcm);
49 return lightYield;
50 }
51 return edep; // Rarely very small energy depositions have no length?
52 }
53} // namespace
54
59
60R3BNeuland::R3BNeuland(const TString& geoFile, const TGeoTranslation& trans, const TGeoRotation& rot)
61 : R3BNeuland(geoFile, { trans, rot })
62{
63}
64
65R3BNeuland::R3BNeuland(const TString& geoFile, const TGeoCombiTrans& combi)
66 : FairDetector{ "R3BNeuland", true, kNEULAND }
67 , rot_trans_{ combi }
68 , geo_file_{ geoFile.Data() }
69{
70}
71
72R3BNeuland::R3BNeuland(int nDP, const TGeoTranslation& trans, const TGeoRotation& rot)
73 : R3BNeuland(nDP, { trans, rot })
74{
75}
76
77R3BNeuland::R3BNeuland(const int nDP, const TGeoCombiTrans& combi)
78 : R3BNeuland(fmt::format("neuland_v3_{}dp.geo.root", nDP), combi)
79{
80 num_of_planes_ = 2 * nDP;
81}
82
84{
85 LOG(info) << "R3BNeuland initialization ...";
86
87 FairDetector::Initialize();
88
89 write_parameter_file();
90 reset_values();
91}
92
93auto R3BNeuland::ProcessHits(FairVolume* /*v*/) -> bool
94{
95 // New hit in detector
96 if (gMC->IsTrackEntering())
97 {
98 if (!is_last_hit_done_)
99 {
100 LOG(warn) << "R3BNeuland: Incomplete hit discarded";
101 reset_values();
102 }
103
104 is_last_hit_done_ = kFALSE;
105 energy_loss_ = 0.;
106 light_yield_ = 0.;
107 time_ = gMC->TrackTime() * seconds_to_nanoseconds;
108 length_ = gMC->TrackLength();
109 gMC->TrackPosition(pos_in_);
110 gMC->TrackMomentum(mom_in_);
111 gMC->CurrentVolOffID(1, fPaddleId);
112
113 particle_id_ = gMC->TrackPid();
114 track_pid_map_.emplace(gMC->GetStack()->GetCurrentTrackNumber(), gMC->TrackPid());
115 if (auto search = track_pid_map_.find(gMC->GetStack()->GetCurrentParentTrackNumber());
116 search != track_pid_map_.end())
117 {
118 parent_particle_id_ = search->first;
119 }
120 }
121
122 // Sum energy loss for all steps in the active volume
123 energy_loss_ += gMC->Edep();
124 light_yield_ += GetLightYield(gMC->TrackCharge(), gMC->TrackStep(), gMC->Edep());
125
126 // Set additional parameters at exit of active volume. Create R3BNeulandPoint.
127 if (gMC->IsTrackExiting() || gMC->IsTrackStop() || gMC->IsTrackDisappeared())
128 {
129 // Do not save a hit if no energy deposited
130 constexpr auto minimum_energy_cutoff = 1e-20;
131 if (energy_loss_ < minimum_energy_cutoff || light_yield_ < minimum_energy_cutoff)
132 {
133 reset_values();
134 return kTRUE;
135 }
136
137 fTrackId = gMC->GetStack()->GetCurrentTrackNumber();
138 gMC->TrackPosition(pos_out_);
139 gMC->TrackMomentum(mom_out_);
140
141 // Add Point
142 LOG(debug) << "R3BNeuland: Adding Point at (" << pos_in_.X() << ", " << pos_in_.Y() << ", " << pos_in_.Z()
143 << ") cm, paddle " << fPaddleId << ", track " << fTrackId << ", energy loss " << energy_loss_
144 << " GeV " << gMC->GetStack()->GetCurrentParentTrackNumber();
145 auto* neuland_point =
146 dynamic_cast<R3BNeulandPoint*>(tca_points_buffer_->ConstructedAt(tca_points_buffer_->GetEntriesFast()));
147 neuland_point->SetTrackID(fTrackId);
148 neuland_point->SetDetectorID(fPaddleId);
149 neuland_point->SetPosition(pos_in_.Vect());
150 neuland_point->SetMomentum(mom_in_.Vect());
151 neuland_point->SetTime(time_);
152 neuland_point->SetLength(length_);
153 neuland_point->SetEnergyLoss(energy_loss_);
154 neuland_point->SetEventID(gMC->CurrentEvent());
155 neuland_point->SetLightYield(light_yield_);
156 neuland_point->SetParticleId(particle_id_);
157 neuland_point->SetParentParticleId(parent_particle_id_);
158 // fNeulandPoints.get().emplace_back(fTrackId,
159 // fPaddleId,
160 // fPosIn.Vect(),
161 // fMomIn.Vect(),
162 // fTime,
163 // fLength,
164 // fEnergyLoss,
165 // gMC->CurrentEvent(),
166 // fLightYield,
167 // fParticleId,
168 // fParentParticleId);
169
170 // Increment number of LandPoints for this track
171 auto* stack = dynamic_cast<R3BStack*>(gMC->GetStack());
172 stack->AddPoint(kNEULAND);
173 reset_values();
174 }
175
176 return kTRUE;
177}
178
179auto R3BNeuland::CheckIfSensitive(std::string name) -> bool { return name == "volBC408"; }
180
182{
183 if (fVerboseLevel != 0)
184 {
185 Print();
186 }
187 Reset();
188}
189
191{
192 auto& points = neuland_points_.get();
193 points.reserve(tca_points_buffer_->GetEntriesFast());
194 for (auto* point : TRangeDynCast<R3BNeulandPoint>(tca_points_buffer_.get()))
195 {
196 points.push_back(*point);
197 }
198}
199
200void R3BNeuland::Print(Option_t* /*unused*/) const
201{
202 LOG(info) << "R3BNeuland: " << neuland_points_.get_constref().size() << " Neuland Points registered in this event";
203}
204
206{
207 neuland_points_.clear();
208 tca_points_buffer_->Clear();
209 reset_values();
210 track_pid_map_.clear();
211}
212
213void R3BNeuland::reset_values()
214{
215 is_last_hit_done_ = kTRUE;
216 fTrackId = 0;
217 fPaddleId = -1;
218 time_ = 0;
219 length_ = 0.;
220 energy_loss_ = 0.;
221 light_yield_ = 0.;
222 pos_in_.Clear();
223 pos_out_.Clear();
224 mom_in_.Clear();
225 mom_out_.Clear();
226}
227
228void R3BNeuland::write_parameter_file()
229{
230 FairRuntimeDb* rtdb = FairRun::Instance()->GetRuntimeDb();
231 neuland_geo_par_ = dynamic_cast<R3BNeulandGeoPar*>(rtdb->getContainer("R3BNeulandGeoPar"));
232
233 // Really bad way to find the Neuland *node* (not the volume!)
234 TGeoNode* geoNodeNeuland = nullptr;
235 for (int i{}; i < gGeoManager->GetTopNode()->GetNdaughters(); i++)
236 {
237 if (TString(gGeoManager->GetTopNode()->GetDaughter(i)->GetVolume()->GetName()) == "volNeuland")
238 {
239 geoNodeNeuland = gGeoManager->GetTopNode()->GetDaughter(i);
240 break;
241 }
242 }
243
244 if (geoNodeNeuland == nullptr)
245 {
246 LOG(fatal) << "volNeuland not found";
247 }
248
249 neuland_geo_par_->SetNeulandGeoNode(geoNodeNeuland);
250 neuland_geo_par_->setChanged();
251}
252
253auto R3BNeuland::GetCollection(int iColl) const -> TClonesArray*
254{
255 if (iColl == 0)
256 {
257 return tca_points_buffer_.get();
258 }
259 return nullptr;
260}
261
262void R3BNeuland::Register() { neuland_points_.init(); }
263
265{
266 if (is_geo_auto_built)
267 {
268 create_geo();
269 }
270 else
271 {
272 create_geo_from_root_file();
273 }
274}
275
276void R3BNeuland::create_geo()
277{
278
279 auto* geo_loader = FairGeoLoader::Instance();
280 if (geo_loader == nullptr)
281 {
282 geo_loader = std::make_unique<FairGeoLoader>("TGeo", "FairGeoLoader").release();
283 }
284 auto* neuland_geo = geo_creator_.construct_volume(num_of_planes_, geo_loader);
285 if (auto* top_volume = gGeoManager->GetTopVolume(); top_volume != nullptr)
286 {
287 // Use copy_id 0 since only one neuland is needed
288 auto* neuland_node = top_volume->AddNode(neuland_geo, 0, rot_trans_.MakeClone());
289
290 // This will set each bar as a sensitive volume
291 ExpandNode(neuland_node);
292 }
293 else
294 {
295 throw R3B::runtime_error("Top volume from gGeoManager is nullptr!");
296 }
297}
298
299void R3BNeuland::create_geo_from_root_file()
300{
301 SetGeometryFileName(geo_file_.c_str());
302 if (!GetGeometryFileName().EndsWith(".root"))
303 {
304 R3BLOG(fatal, GetName() << " (which is a " << ClassName() << ") geometry file is not specified");
305 }
306 R3BLOG(info,
307 fmt::format("Constructing {} (which is a {}) geometry from ROOT file {} ...",
308 GetName(),
309 ClassName(),
310 GetGeometryFileName().Data()));
311 ConstructRootGeometry();
312 if (not rot_trans_.IsIdentity())
313 {
314 if (auto* top_node = gGeoManager->GetTopNode(); top_node != nullptr)
315 {
316 auto* neuland_node = top_node->GetDaughter(gGeoManager->GetTopNode()->GetNdaughters() - 1);
317 dynamic_cast<TGeoNodeMatrix*>(neuland_node)->SetMatrix(rot_trans_.MakeClone());
318 }
319 else
320 {
321 throw R3B::runtime_error("Top node from gGeoManager is nullptr!");
322 }
323 }
324}
325
@ kNEULAND
#define R3BLOG(severity, x)
Definition R3BLogger.h:35
constexpr auto BirkdP
constexpr auto seconds_to_nanoseconds
constexpr auto BirkC2
ClassImp(R3BNeuland)
constexpr auto BirkC1
NeuLAND detector simulation class.
Definition R3BNeuland.h:43
auto CheckIfSensitive(std::string name) -> bool override
auto ProcessHits(FairVolume *=nullptr) -> bool override
void Register() override
void FinishEvent() override
void EndOfEvent() override
R3BNeuland()
Default constructor.
void ConstructGeometry() override
auto GetCollection(int iColl) const -> TClonesArray *override
void Reset() override
void Print(Option_t *="") const override
void Initialize() override
void SetLightYield(double light_yield)
R3BStack.h.
Definition R3BMCStack.h:55
void AddPoint(DetectorId iDet)
Increment number of points for the current track in a given detector.