Newer
Older
//==========================================================================
// AIDA Detector description implementation
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
// Author : M.Frank
//
//==========================================================================
//
// Simple program to print all the materials in a detector on
// a straight line between two given points
//
// Author : M.Frank, CERN
//
//==========================================================================
// Framework include files
#include <DDRec/MaterialScan.h>
#include <DD4hep/DD4hepUnits.h>
#include <DD4hep/Detector.h>
#include <DD4hep/Printout.h>
#include <DD4hep/Shapes.h>
/// C/C++ include files
#include <cstdio>
using namespace dd4hep;
using namespace dd4hep::rec;
/// Default constructor
MaterialScan::MaterialScan()
: m_detector(Detector::getInstance())
{
m_materialMgr.reset(new MaterialManager(m_detector.world().volume()));
}
/// Default constructor
MaterialScan::MaterialScan(Detector& description)
: m_detector(description)
{
m_materialMgr.reset(new MaterialManager(m_detector.world().volume()));
}
/// Default destructor
MaterialScan::~MaterialScan() {
}
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/// Set a specific region to limit the scan (resets the subdetector selection)
void MaterialScan::setRegion(const char* region) {
Region reg;
if ( region ) {
reg = m_detector.region(region);
}
setRegion(reg);
}
/// Set a specific region to limit the scan (resets the subdetector selection)
void MaterialScan::setRegion(Region region) {
struct PvCollector {
Region rg;
std::set<const TGeoNode*>& cont;
PvCollector(Region r, std::set<const TGeoNode*>& c) : rg(r), cont(c) {}
void collect(TGeoNode* pv) {
cont.insert(pv);
for (Int_t idau = 0, ndau = pv->GetNdaughters(); idau < ndau; ++idau)
collect(pv->GetDaughter(idau));
}
void operator()(TGeoNode* pv) {
Volume v = pv->GetVolume();
Region r = v.region();
if ( r.isValid() ) {
collect(pv);
return;
}
for (Int_t idau = 0, ndau = pv->GetNdaughters(); idau < ndau; ++idau)
(*this)(pv->GetDaughter(idau));
}
};
m_placements.clear();
if ( region.isValid() ) {
PvCollector coll(region, m_placements);
coll(m_detector.world().placement().ptr());
printout(ALWAYS,"MaterialScan","+++ Set new scanning region to: %s [%ld placements]",
region.name(), m_placements.size());
}
else {
printout(ALWAYS,"MaterialScan","+++ No region restrictions set. Back to full scanning mode.");
}
}
/// Set a specific detector volume to limit the scan
void MaterialScan::setDetector(const char* detector) {
DetElement det;
if ( detector ) {
det = m_detector.detector(detector);
}
setDetector(det);
}
/// Set a specific detector volume to limit the scan
void MaterialScan::setDetector(DetElement detector) {
struct PvCollector {
std::set<const TGeoNode*>& cont;
PvCollector(std::set<const TGeoNode*>& c) : cont(c) {}
void operator()(TGeoNode* pv) {
cont.insert(pv);
for (Int_t idau = 0, ndau = pv->GetNdaughters(); idau < ndau; ++idau) {
TGeoNode* daughter = pv->GetDaughter(idau);
(*this)(daughter);
}
}
};
if ( detector.isValid() ) {
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
PlacedVolume pv = detector.placement();
m_placements.clear();
if ( pv.isValid() ) {
PvCollector coll(m_placements);
coll(pv.ptr());
}
printout(ALWAYS,"MaterialScan","+++ Set new scanning volume to: %s [%ld placements]",
detector.path().c_str(), m_placements.size());
}
else {
printout(ALWAYS,"MaterialScan","+++ No subdetector restrictions set. Back to full scanning mode.");
m_placements.clear();
}
}
/// Set a specific volume material to limit the scan
void MaterialScan::setMaterial(const char* material) {
Material mat;
if ( material ) {
mat = m_detector.material(material);
}
setMaterial(mat);
}
/// Set a specific volume material to limit the scan
void MaterialScan::setMaterial(Material material) {
struct PvCollector {
Material material;
std::set<const TGeoNode*>& cont;
PvCollector(Material mat, std::set<const TGeoNode*>& c) : material(mat), cont(c) {}
void operator()(TGeoNode* pv) {
Volume vol = pv->GetVolume();
Material mat = vol.material();
if ( mat.ptr() == material.ptr() ) {
cont.insert(pv);
}
for (Int_t idau = 0, ndau = pv->GetNdaughters(); idau < ndau; ++idau)
(*this)(pv->GetDaughter(idau));
}
};
m_placements.clear();
if ( material.isValid() ) {
PvCollector coll(material, m_placements);
coll(m_detector.world().placement().ptr());
printout(ALWAYS,"MaterialScan","+++ Set new scanning material to: %s [%ld placements]",
material.name(), m_placements.size());
}
else {
printout(ALWAYS,"MaterialScan","+++ No material restrictions set. Back to full scanning mode.");
}
}
/// Scan along a line and store the matrials internally
const MaterialVec& MaterialScan::scan(double x0, double y0, double z0, double x1, double y1, double z1, double epsilon) const {
Vector3D p0(x0, y0, z0), p1(x1, y1, z1);
return m_materialMgr->materialsBetween(p0, p1, epsilon);
}
/// Scan along a line and print the materials traversed
void MaterialScan::print(const Vector3D& p0, const Vector3D& p1, double epsilon) const {
const auto& placements = m_materialMgr->placementsBetween(p0, p1, epsilon);
auto& matMgr = *m_materialMgr;
Vector3D end, direction;
double sum_x0 = 0;
double sum_lambda = 0;
double path_length = 0, total_length = 0;
const char* fmt1 = " | %7s %-25s %3.0f %8.3f %8.4f %11.4f %11.4f %10.3f %8.2f %11.6f %11.6f (%7.2f,%7.2f,%7.2f)\n";
const char* fmt2 = " | %7s %-25s %3.0f %8.3f %8.4f %11.6g %11.6g %10.3f %8.2f %11.6f %11.6f (%7.2f,%7.2f,%7.2f)\n";
const char* line = " +--------------------------------------------------------------------------------------------------------------------------------------------------\n";
direction = (p1-p0).unit();
::printf("%s + Material scan between: x_0 = (%7.2f,%7.2f,%7.2f) [cm] and x_1 = (%7.2f,%7.2f,%7.2f) [cm] : \n%s",
line,p0[0],p0[1],p0[2],p1[0],p1[1],p1[2],line);
::printf(" | \\ %-16s Atomic Radiation Interaction Path Integrated Integrated Material\n","Material");
::printf(" | Num. \\ %-16s Number/Z Mass/A Density Length Length Thickness Length X0 Lambda Endpoint/Startpoint\n","Name");
::printf(" | Layer \\ %-16s [g/mole] [g/cm3] [cm] [cm] [cm] [cm] [cm] [cm] ( cm, cm, cm)\n","");
::printf("%s",line);
MaterialVec materials;
std::set<Solid> tessellated_solids;
for( unsigned i=0, n=placements.size(); i<n; ++i){
TGeoNode* pv = placements[i].first.ptr();
double length = placements[i].second;
total_length += length;
end = p0 + total_length * direction;
if ( !m_placements.empty() && m_placements.find(pv) == m_placements.end() ) {
#if 0
::printf("%p %s %s %s\n",
placements[i].first.ptr(),
placements[i].first->GetName(),
placements[i].first->GetVolume()->GetName(),
placements[i].first->GetMedium()->GetName());
#endif
continue;
}
TGeoMaterial* curr_mat = placements[i].first->GetMedium()->GetMaterial();
TGeoMaterial* next_mat = (i+1)<n ? placements[i+1].first->GetMedium()->GetMaterial() : nullptr;
double nx0 = length / curr_mat->GetRadLen();
double nLambda = length / curr_mat->GetIntLen();
sum_x0 += nx0;
sum_lambda += nLambda;
path_length += length;
materials.emplace_back(placements[i].first->GetMedium(),length);
const char* fmt = curr_mat->GetRadLen() >= 1e5 ? fmt2 : fmt1;
std::string mname = curr_mat->GetName();
if ( next_mat && (i+1)<n ) {
mname += " -> ";
mname += next_mat->GetName();
}
Volume vol(placements[i].first->GetVolume());
Solid shape(vol.solid());
if ( shape->IsA() == TGeoTessellated::Class() ) {
tessellated_solids.insert(shape);
}
if ( 0 == i ) {
::printf(fmt, "(start)" , curr_mat->GetName(), curr_mat->GetZ(), curr_mat->GetA(),
curr_mat->GetDensity(), curr_mat->GetRadLen()/dd4hep::cm, curr_mat->GetIntLen()/dd4hep::cm,
0e0, 0e0, 0e0, 0e0,
p0[0]/dd4hep::cm, p0[1]/dd4hep::cm, p0[2]/dd4hep::cm);
}
// No else here!
if ( (n-1) == i ) {
::printf(fmt, "(end)", curr_mat->GetName(), curr_mat->GetZ(), curr_mat->GetA(),
curr_mat->GetDensity(), curr_mat->GetRadLen()/dd4hep::cm, curr_mat->GetIntLen()/dd4hep::cm,
0e0, 0e0, 0e0, 0e0,
p0[0]/dd4hep::cm, p0[1]/dd4hep::cm, p0[2]/dd4hep::cm);
}
else {
::printf(fmt, std::to_string(i+1).c_str(), mname.c_str(), next_mat->GetZ(), next_mat->GetA(),
next_mat->GetDensity(), next_mat->GetRadLen()/dd4hep::cm, next_mat->GetIntLen()/dd4hep::cm,
length/dd4hep::cm, path_length/dd4hep::cm, sum_x0, sum_lambda,
end[0]/dd4hep::cm, end[1]/dd4hep::cm, end[2]/dd4hep::cm);
}
::printf("%s",line);
const MaterialData& avg = matMgr.createAveragedMaterial(materials);
const char* fmt = avg.radiationLength() >= 1e5 ? fmt2 : fmt1;
::printf(fmt,"","Average Material",avg.Z(),avg.A(),avg.density(),
avg.radiationLength()/dd4hep::cm, avg.interactionLength()/dd4hep::cm,
path_length/dd4hep::cm, path_length/dd4hep::cm,
path_length/avg.radiationLength(),
path_length/avg.interactionLength(),
end[0]/dd4hep::cm, end[1]/dd4hep::cm, end[2]/dd4hep::cm);
::printf("%s",line);
if ( !tessellated_solids.empty() ) {
::printf(" | WARNING: %ld tessellated shape were encountered during the volume traversal:\n",
tessellated_solids.size());
for(auto shape : tessellated_solids )
::printf(" | \t\t %s\n", shape.name());
::printf(" | WARNING: The results of this material scan are unreliable!\n");
::printf("%s",line);
}
}
/// Scan along a line and print the materials traversed
void MaterialScan::print(double x0, double y0, double z0, double x1, double y1, double z1, double epsilon) const {
Vector3D p0(x0, y0, z0), p1(x1, y1, z1);
this->print(p0, p1, epsilon);