20#include <FairRootManager.h>
21#include <FairVolume.h>
22#include <fairlogger/Logger.h>
24#include <TGeoManager.h>
25#include <TGeoMatrix.h>
26#include <TGeoMedium.h>
28#include <TGeoVolume.h>
29#include <TVirtualMC.h>
32#include <rapidjson/document.h>
33#include <rapidjson/error/en.h>
34#include <rapidjson/istreamwrapper.h>
64 mOptions(rhs.mOptions),
65 mSensitiveVolumeNames(rhs.mSensitiveVolumeNames),
66 mSensitiveVolIDs(rhs.mSensitiveVolIDs),
67 mVolID2SensorID(rhs.mVolID2SensorID),
82 if (!vol || visited.count(vol)) {
87 bool sensitive =
false;
89 const std::string volname = vol->GetName();
91 if (!token.empty() && volname.find(token) != std::string::npos) {
98 if (
auto medium = vol->GetMedium()) {
99 const std::string medname = medium->GetName();
101 if (!token.empty() && medname.find(token) != std::string::npos) {
112 const int nd = vol->GetNdaughters();
113 for (
int i = 0;
i < nd; ++
i) {
114 if (
auto node = vol->GetNode(
i)) {
125 LOG(error) <<
"No geometry could be built for external detector " << GetName();
134 std::set<TGeoVolume*> visited;
137 LOG(warning) <<
"External detector " << GetName() <<
": no volume matched the configured sensitive media; "
138 <<
"no hits will be produced";
141 <<
" sensitive volume(s) selected";
166 LOG(info) <<
"External detector " << GetName() <<
": registered sensitive volume '" <<
name
167 <<
"' (MC volID " << volID <<
", sensor " <<
mVolID2SensorID[volID] <<
")";
175 const auto unique = std::string(
"o2ext_sensitive_action_") + GetName();
176 mSensitiveAction = o2::conf::GetFromMacro<SensitiveFcn>(file,
func,
"o2::ext::ExternalDetector::SensitiveFcn", unique);
178 LOG(info) <<
"External detector " << GetName() <<
": using sensitive action '" <<
func
179 <<
"' from macro '" << file <<
"'";
181 LOG(fatal) <<
"External detector " << GetName() <<
": could not load sensitive action '" <<
func
182 <<
"' from macro '" << file <<
"'";
202 if (!(fMC->TrackCharge())) {
211 bool startHit =
false, stopHit =
false;
212 unsigned char status = 0;
213 if (fMC->IsTrackEntering()) {
216 if (fMC->IsTrackInside()) {
219 if (fMC->IsTrackExiting()) {
222 if (fMC->IsTrackOut()) {
225 if (fMC->IsTrackStop()) {
228 if (fMC->IsTrackAlive()) {
243 if (!(startHit | stopHit)) {
255 TLorentzVector positionStop;
256 fMC->TrackPosition(positionStop);
274 return static_cast<o2::data::Stack*
>(fMC->GetStack())->GetCurrentTrackNumber();
278 const TVector3& startMom,
double startE,
double endTime,
double eLoss,
279 unsigned char startStatus,
unsigned char endStatus,
int pdg,
float length)
281 mHits->emplace_back(trackID, sensorID, startPos, endPos, startMom, startE, endTime, eLoss,
282 startStatus, endStatus, pdg,
length);
285 return &(
mHits->back());
291 if (FairRootManager::Instance()) {
306 LOG(info) <<
"External detector " << GetName() <<
" EndOfEvent: " <<
mStepCount
307 <<
" sensitive step(s) -> " << (
mHits ?
mHits->size() : 0) <<
" hit(s)";
316TGeoMatrix* makePlacementFromJSON(
const rapidjson::Value& placement)
318 auto combi =
new TGeoCombiTrans();
319 if (placement.HasMember(
"rotation_deg") && placement[
"rotation_deg"].IsArray()) {
320 const auto&
r = placement[
"rotation_deg"];
322 combi->RotateX(
r[0].GetDouble());
323 combi->RotateY(
r[1].GetDouble());
324 combi->RotateZ(
r[2].GetDouble());
326 LOG(warning) <<
"ExternalDetector placement 'rotation_deg' must have 3 entries; ignoring";
329 if (placement.HasMember(
"translation") && placement[
"translation"].IsArray()) {
330 const auto& t = placement[
"translation"];
332 combi->SetDx(t[0].GetDouble());
333 combi->SetDy(t[1].GetDouble());
334 combi->SetDz(t[2].GetDouble());
336 LOG(warning) <<
"ExternalDetector placement 'translation' must have 3 entries; ignoring";
345 std::vector<ExternalDetector*>
result;
348 std::ifstream fileStream(expanded, std::ios::in);
349 if (!fileStream.is_open()) {
350 LOG(error) <<
"Cannot open external geometry config file '" << expanded <<
"'";
354 rapidjson::IStreamWrapper isw(fileStream);
355 rapidjson::Document doc;
356 doc.ParseStream(isw);
357 if (doc.HasParseError()) {
358 LOG(error) <<
"Error parsing external geometry JSON '" << expanded <<
"': "
359 << rapidjson::GetParseError_En(doc.GetParseError())
360 <<
" (offset " << doc.GetErrorOffset() <<
")";
365 if (!doc.HasMember(
"externalDetectors")) {
368 if (!doc[
"externalDetectors"].IsArray()) {
369 LOG(error) <<
"External geometry JSON '" << expanded <<
"': 'externalDetectors' must be an array";
373 auto getString = [](
const rapidjson::Value&
v,
const char*
key) -> std::string {
374 if (
v.HasMember(
key) &&
v[
key].IsString()) {
375 return v[
key].GetString();
377 return std::string();
380 for (
const auto&
entry : doc[
"externalDetectors"].GetArray()) {
381 if (!
entry.IsObject()) {
382 LOG(error) <<
"Skipping non-object entry in 'externalDetectors'";
385 const auto name = getString(
entry,
"name");
387 LOG(error) <<
"Skipping external detector entry without 'name'";
394 LOG(error) <<
"External detector '" <<
name <<
"' requires both 'macro' and 'anchor'; skipping";
398 if (
entry.HasMember(
"sensitiveMedia") &&
entry[
"sensitiveMedia"].IsArray()) {
399 for (
const auto&
m :
entry[
"sensitiveMedia"].GetArray()) {
405 if (
entry.HasMember(
"sensitiveVolumes") &&
entry[
"sensitiveVolumes"].IsArray()) {
406 for (
const auto&
v :
entry[
"sensitiveVolumes"].GetArray()) {
413 LOG(error) <<
"External detector '" <<
name
414 <<
"' requires a non-empty 'sensitiveMedia' or 'sensitiveVolumes' array; skipping";
418 const auto detIDName = getString(
entry,
"detID");
419 if (!detIDName.empty()) {
422 LOG(error) <<
"External detector '" <<
name <<
"': unknown detID '" << detIDName <<
"'; skipping";
428 if (
entry.HasMember(
"placement") &&
entry[
"placement"].IsObject()) {
437 auto title = getString(
entry,
"title");
442 <<
"' anchored to '" << options.
anchor_volume <<
"', tied to DetID '"
Helpers to inject CAD-derived (TGeo) geometry into O2 simulation.
Definition of the Stack class.
std::unique_ptr< expressions::Node > node
Sensitive detector built from an externally provided (CAD-derived) geometry.
int registerSensitiveVolumeAndGetVolID(std::string const &name)
std::string addNameTo(const char *ext) const
static constexpr const char * getName(ID id)
names of defined detectors
static constexpr int nDetectors
number of defined detectors
static constexpr int nameToID(char const *name, int id=First)
int currentTrackID() const
MCTrack number of the track currently being stepped.
static std::vector< ExternalDetector * > createFromJSON(const std::string &jsonfile)
std::vector< o2::ext::Hit > * mHits
void InitializeO2Detector() override
Resolve the Monte Carlo volume IDs of the sensitive volumes.
int mStepCount
volume currently passed to ProcessHits (for the action helpers)
std::unordered_map< int, int > mVolID2SensorID
MC volume IDs of the sensitive volumes.
o2::ext::Hit * addHit(int trackID, int sensorID, const TVector3 &startPos, const TVector3 &endPos, const TVector3 &startMom, double startE, double endTime, double eLoss, unsigned char startStatus, unsigned char endStatus, int pdg=0, float length=0.f)
int currentSensorID() const
ExternalDetectorOptions mOptions
void Register() override
Register the hit collection with the FairRootManager.
SensitiveFcn mSensitiveAction
container for produced hits
FairVolume * mCurrentVolume
optional user-provided sensitive action (loaded from a macro)
void collectSensitiveVolumeNames(TGeoVolume *vol, std::set< TGeoVolume * > &visited)
recursively collect names of volumes whose medium matches the configured sensitive media
Bool_t ProcessHits(FairVolume *v=nullptr) override
Called for each tracking step; produces hits in the sensitive volumes.
void ConstructGeometry() override
Build the CAD geometry, remap its media and register the sensitive volumes.
std::vector< std::string > mSensitiveVolumeNames
Bool_t defaultProcessHits()
the built-in sensitive action used when no macro is configured (generic entrance/exit hit)
struct o2::ext::ExternalDetector::TrackData mTrackData
~ExternalDetector() override
std::set< int > mSensitiveVolIDs
names of the volumes to be made sensitive (filled at geometry build)
void EndOfEvent() override
static ShmManager & Instance()
GLuint const GLchar * name
GLuint GLsizei GLsizei * length
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
TGeoVolume * buildCADVolumeFromMacro(const std::string ¯oFile, const std::string &instanceTag)
void remapCADMedia(TGeoVolume *top, const char *modulename)
void freeSimVector(std::vector< T > *ptr)
std::string expandShellVarsInFileName(std::string const &input)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Common utility functions.
Configuration of a single sensitive external detector.
TGeoMatrix const * placement
std::string sensitiveMacro
std::string sensitiveFunction
std::string root_macro_file
std::vector< std::string > sensitiveMedia
std::string anchor_volume
std::vector< std::string > sensitiveVolumes
TLorentzVector mPositionStart
track status flag at entrance
double mEnergyLoss
momentum at entrance
unsigned char mTrkStatusStart
hit creation started
TLorentzVector mMomentumStart
position at entrance
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"