16#include "FairRuntimeDb.h"
19#include "TClonesArray.h"
20#include "TGeoManager.h"
21#include "TVirtualMC.h"
22#include <FairRootManager.h>
23#include <FairVolume.h>
34 inline auto GetLightYield(
const int charge,
const double length,
const double edep) ->
double
37 if (charge != 0 && length > 0)
42 if (TMath::Abs(charge) >= 2)
44 birkC1Mod *= 7.2 / 12.6;
47 const double dedxcm = 1000. * edep / length;
48 const double lightYield = edep / (1. + birkC1Mod * dedxcm +
BirkC2 * dedxcm * dedxcm);
66 : FairDetector{
"R3BNeuland", true,
kNEULAND }
68 , geo_file_{ geoFile.Data() }
78 :
R3BNeuland(fmt::format(
"neuland_v3_{}dp.geo.root", nDP), combi)
80 num_of_planes_ = 2 * nDP;
85 LOG(info) <<
"R3BNeuland initialization ...";
87 FairDetector::Initialize();
89 write_parameter_file();
96 if (gMC->IsTrackEntering())
98 if (!is_last_hit_done_)
100 LOG(warn) <<
"R3BNeuland: Incomplete hit discarded";
104 is_last_hit_done_ = kFALSE;
108 length_ = gMC->TrackLength();
109 gMC->TrackPosition(pos_in_);
110 gMC->TrackMomentum(mom_in_);
111 gMC->CurrentVolOffID(1, fPaddleId);
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())
118 parent_particle_id_ = search->first;
123 energy_loss_ += gMC->Edep();
124 light_yield_ += GetLightYield(gMC->TrackCharge(), gMC->TrackStep(), gMC->Edep());
127 if (gMC->IsTrackExiting() || gMC->IsTrackStop() || gMC->IsTrackDisappeared())
130 constexpr auto minimum_energy_cutoff = 1e-20;
131 if (energy_loss_ < minimum_energy_cutoff || light_yield_ < minimum_energy_cutoff)
137 fTrackId = gMC->GetStack()->GetCurrentTrackNumber();
138 gMC->TrackPosition(pos_out_);
139 gMC->TrackMomentum(mom_out_);
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());
156 neuland_point->SetParticleId(particle_id_);
157 neuland_point->SetParentParticleId(parent_particle_id_);
171 auto* stack =
dynamic_cast<R3BStack*
>(gMC->GetStack());
183 if (fVerboseLevel != 0)
192 auto& points = neuland_points_.get();
193 points.reserve(tca_points_buffer_->GetEntriesFast());
194 for (
auto* point : TRangeDynCast<R3BNeulandPoint>(tca_points_buffer_.get()))
196 points.push_back(*point);
202 LOG(info) <<
"R3BNeuland: " << neuland_points_.get_constref().size() <<
" Neuland Points registered in this event";
207 neuland_points_.clear();
208 tca_points_buffer_->Clear();
210 track_pid_map_.clear();
213void R3BNeuland::reset_values()
215 is_last_hit_done_ = kTRUE;
228void R3BNeuland::write_parameter_file()
230 FairRuntimeDb* rtdb = FairRun::Instance()->GetRuntimeDb();
231 neuland_geo_par_ =
dynamic_cast<R3BNeulandGeoPar*
>(rtdb->getContainer(
"R3BNeulandGeoPar"));
234 TGeoNode* geoNodeNeuland =
nullptr;
235 for (
int i{}; i < gGeoManager->GetTopNode()->GetNdaughters(); i++)
237 if (TString(gGeoManager->GetTopNode()->GetDaughter(i)->GetVolume()->GetName()) ==
"volNeuland")
239 geoNodeNeuland = gGeoManager->GetTopNode()->GetDaughter(i);
244 if (geoNodeNeuland ==
nullptr)
246 LOG(fatal) <<
"volNeuland not found";
249 neuland_geo_par_->SetNeulandGeoNode(geoNodeNeuland);
250 neuland_geo_par_->setChanged();
257 return tca_points_buffer_.get();
266 if (is_geo_auto_built)
272 create_geo_from_root_file();
276void R3BNeuland::create_geo()
279 auto* geo_loader = FairGeoLoader::Instance();
280 if (geo_loader ==
nullptr)
282 geo_loader = std::make_unique<FairGeoLoader>(
"TGeo",
"FairGeoLoader").release();
284 auto* neuland_geo = geo_creator_.construct_volume(num_of_planes_, geo_loader);
285 if (
auto* top_volume = gGeoManager->GetTopVolume(); top_volume !=
nullptr)
288 auto* neuland_node = top_volume->AddNode(neuland_geo, 0, rot_trans_.MakeClone());
291 ExpandNode(neuland_node);
295 throw R3B::runtime_error(
"Top volume from gGeoManager is nullptr!");
299void R3BNeuland::create_geo_from_root_file()
301 SetGeometryFileName(geo_file_.c_str());
302 if (!GetGeometryFileName().EndsWith(
".root"))
304 R3BLOG(fatal, GetName() <<
" (which is a " << ClassName() <<
") geometry file is not specified");
307 fmt::format(
"Constructing {} (which is a {}) geometry from ROOT file {} ...",
310 GetGeometryFileName().Data()));
311 ConstructRootGeometry();
312 if (not rot_trans_.IsIdentity())
314 if (
auto* top_node = gGeoManager->GetTopNode(); top_node !=
nullptr)
316 auto* neuland_node = top_node->GetDaughter(gGeoManager->GetTopNode()->GetNdaughters() - 1);
317 dynamic_cast<TGeoNodeMatrix*
>(neuland_node)->SetMatrix(rot_trans_.MakeClone());
321 throw R3B::runtime_error(
"Top node from gGeoManager is nullptr!");
#define R3BLOG(severity, x)
constexpr auto seconds_to_nanoseconds
NeuLAND detector simulation class.
auto CheckIfSensitive(std::string name) -> bool override
auto ProcessHits(FairVolume *=nullptr) -> bool override
void FinishEvent() override
void EndOfEvent() override
R3BNeuland()
Default constructor.
void ConstructGeometry() override
auto GetCollection(int iColl) const -> TClonesArray *override
void Print(Option_t *="") const override
void Initialize() override
void SetLightYield(double light_yield)
void AddPoint(DetectorId iDet)
Increment number of points for the current track in a given detector.