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