File indexing completed on 2025-01-30 09:16:46
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef DD4HEP_DETELEMENTVOLUMEIDS_H
0014 #define DD4HEP_DETELEMENTVOLUMEIDS_H
0015
0016
0017 #include <DD4hep/DetElement.h>
0018 #include <DD4hep/Volumes.h>
0019
0020
0021
0022
0023 namespace dd4hep {
0024
0025
0026 class Detector;
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 class DetElementVolumeIDs {
0037 private:
0038
0039 const Detector& m_detDesc;
0040
0041 public:
0042
0043 std::size_t numberOfNodes { 0 };
0044
0045 struct Encoding {
0046 VolumeID identifier;
0047 VolumeID mask;
0048 };
0049
0050 std::map<DetElement, std::vector<Encoding> > entries;
0051
0052 private:
0053 using PlacementPath = std::vector<PlacedVolume>;
0054
0055
0056 std::size_t scanPhysicalVolume(DetElement& parent,
0057 DetElement e,
0058 PlacedVolume pv,
0059 Encoding parent_encoding,
0060 SensitiveDetector& sd,
0061 PlacementPath& chain);
0062 public:
0063
0064 DetElementVolumeIDs(const Detector& description);
0065
0066 std::size_t populate(DetElement e);
0067 };
0068 }
0069 #endif
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 #include <DD4hep/Printout.h>
0085 #include <DD4hep/Factories.h>
0086 #include <DD4hep/Detector.h>
0087 #include <DD4hep/DetectorTools.h>
0088 #include <DD4hep/detail/DetectorInterna.h>
0089
0090
0091 using namespace dd4hep;
0092
0093 namespace {
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 long assign_de_volumeIDs(Detector& description, int argc, char** argv) {
0104 std::string detector = "/world";
0105 for(int i = 0; i < argc && argv[i]; ++i) {
0106 if ( 0 == ::strncmp("-detector",argv[i],4) )
0107 detector = argv[++i];
0108 else {
0109 std::cout <<
0110 "Usage: -plugin DD4hep_DetElementVolumeIDs -arg [-arg] \n\n"
0111 " -detector <string> Top level DetElement path. Default: '/world' \n"
0112 " -help Print this help output \n"
0113 " Arguments given: " << arguments(argc,argv) << std::endl << std::flush;
0114 ::exit(EINVAL);
0115 }
0116 }
0117 DetElement element = description.world();
0118 if ( detector != "/world" ) {
0119 element = detail::tools::findElement(description,detector);
0120 if ( !element.isValid() ) {
0121 except("DD4hep_DetElementVolumeIDs","+++ Invalid DetElement path: %s",detector.c_str());
0122 }
0123 }
0124 DetElementVolumeIDs mgr(description);
0125 auto count = mgr.populate(element);
0126 if ( count == 0 ) {
0127 except("DD4hep_DetElementVolumeIDs",
0128 "+++ NO volume identifiers assigned to DetElement %s. %s",
0129 "Something went wrong!",detector.c_str());
0130 }
0131 return count > 0 ? 1 : 0;
0132 }
0133 }
0134 DECLARE_APPLY(DD4hep_DetElementVolumeIDs,assign_de_volumeIDs)
0135
0136 using Encoding = DetElementVolumeIDs::Encoding;
0137 using VolIDs = PlacedVolume::VolIDs;
0138
0139 namespace {
0140
0141
0142 Encoding update_encoding(const IDDescriptor iddesc, const VolIDs& ids, const Encoding& initial) {
0143 VolumeID volume_id = initial.identifier, mask = initial.mask;
0144 for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
0145 const auto& id = (*i);
0146 const BitFieldElement* f = iddesc.field(id.first);
0147 VolumeID msk = f->mask();
0148 int off = f->offset();
0149 VolumeID val = id.second;
0150 volume_id |= ((f->value(val << off) << off)&msk);
0151 mask |= msk;
0152 }
0153 return { volume_id, mask };
0154 }
0155 }
0156
0157
0158 DetElementVolumeIDs::DetElementVolumeIDs(const Detector& description)
0159 : m_detDesc(description)
0160 {
0161 }
0162
0163
0164 std::size_t DetElementVolumeIDs::populate(DetElement det) {
0165 std::size_t count = 0UL;
0166 Encoding encoding { 0, 0 };
0167 PlacedVolume pv = det.placement();
0168
0169 entries.clear();
0170 if ( !pv.isValid() ) {
0171 except("DetElementVolumeIDs",
0172 "+++ Top level DetElement %s has no valid placement. %s",
0173 "[Something awfully wrong]", det.path().c_str());
0174 }
0175 if ( det == m_detDesc.world() ) {
0176 for (const auto& i : det.children() ) {
0177 DetElement de = i.second;
0178 pv = de.placement();
0179 if (pv.isValid()) {
0180 PlacementPath chain;
0181 Encoding coding { 0, 0 };
0182 SensitiveDetector sd (0);
0183 count += scanPhysicalVolume(de, de, pv, coding, sd, chain);
0184 continue;
0185 }
0186 printout(WARNING, "DetElementVolumeIDs", "++ Detector element %s of type %s has no placement.",
0187 de.name(), de.type().c_str());
0188 }
0189 printout(INFO, "DetElementVolumeIDs", "++ Assigned %ld volume identifiers to DetElements.", count);
0190 return count;
0191 }
0192 SensitiveDetector sd = m_detDesc.sensitiveDetector(det.name());
0193 if ( !pv.volIDs().empty() && !sd.isValid() ) {
0194 except("DetElementVolumeIDs",
0195 "+++ No sensitive detector available for top level DetElement %s.",
0196 det.path().c_str());
0197 }
0198 PlacementPath chain;
0199 count += scanPhysicalVolume(det, det, pv, encoding, sd, chain);
0200 printout(INFO, "DetElementVolumeIDs", "++ Assigned %ld volume identifiers to DetElements.", count);
0201 return count;
0202 }
0203
0204
0205 std::size_t
0206 DetElementVolumeIDs::scanPhysicalVolume(DetElement& parent,
0207 DetElement e,
0208 PlacedVolume pv,
0209 Encoding parent_encoding,
0210 SensitiveDetector& sd,
0211 PlacementPath& chain)
0212 {
0213 TGeoNode* node = pv.ptr();
0214 std::size_t count = 0;
0215 if (node) {
0216 Volume vol = pv.volume();
0217 const VolIDs& pv_ids = pv.volIDs();
0218 Encoding vol_encoding = parent_encoding;
0219 bool is_sensitive = vol.isSensitive();
0220 bool have_encoding = pv_ids.empty();
0221 bool compound = e.type() == "compound";
0222
0223 if ( compound ) {
0224 sd = SensitiveDetector(0);
0225 vol_encoding = Encoding();
0226 }
0227 else if ( !sd.isValid() ) {
0228 if ( is_sensitive )
0229 sd = vol.sensitiveDetector();
0230 else if ( (parent->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
0231 sd = m_detDesc.sensitiveDetector(parent.name());
0232 else if ( (e->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
0233 sd = m_detDesc.sensitiveDetector(e.name());
0234 }
0235 chain.emplace_back(node);
0236 if ( sd.isValid() && !pv_ids.empty() ) {
0237 Readout ro = sd.readout();
0238 if ( ro.isValid() ) {
0239 vol_encoding = update_encoding(ro.idSpec(), pv_ids, parent_encoding);
0240 have_encoding = true;
0241 }
0242 else {
0243 printout(WARNING, "DetElementVolumeIDs",
0244 "%s: Strange constellation volume %s is sensitive, but has no readout! sd:%p",
0245 parent.name(), pv.volume().name(), sd.ptr());
0246 }
0247 }
0248 for (int idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
0249 TGeoNode* daughter = node->GetDaughter(idau);
0250 PlacedVolume place_dau(daughter);
0251 if ( place_dau.data() ) {
0252 DetElement de_dau;
0253
0254
0255
0256 for( const auto& de : e.children() ) {
0257 if ( de.second.placement().ptr() == daughter ) {
0258 de_dau = de.second;
0259 break;
0260 }
0261 }
0262 if ( de_dau.isValid() ) {
0263 PlacementPath dau_chain;
0264 count += scanPhysicalVolume(parent, de_dau, place_dau, vol_encoding, sd, dau_chain);
0265 }
0266 else {
0267 count += scanPhysicalVolume(parent, e, place_dau, vol_encoding, sd, chain);
0268 }
0269 }
0270 else {
0271 except("DetElementVolumeIDs",
0272 "Invalid not instrumented placement: %s %s", daughter->GetName(),
0273 " [Internal error -- bad detector constructor]");
0274 }
0275
0276
0277 if ( compound ) {
0278 sd = SensitiveDetector(0);
0279 }
0280 }
0281 if ( sd.isValid() ) {
0282 if ( !have_encoding && !compound ) {
0283 printout(ERROR, "DetElementVolumeIDs",
0284 "Element %s: Missing SD encoding. Volume manager won't work!",
0285 e.path().c_str());
0286 }
0287 if ( is_sensitive || count > 0 ) {
0288
0289 if ( node == e.placement().ptr() ) {
0290
0291
0292
0293
0294
0295
0296 e.object<DetElement::Object>().volumeID = vol_encoding.identifier;
0297 }
0298
0299 if ( entries.find(e) == entries.end()) {
0300 entries[e].emplace_back(vol_encoding);
0301 ++numberOfNodes;
0302 }
0303 ++count;
0304 }
0305 }
0306 chain.pop_back();
0307 }
0308 return count;
0309 }