File indexing completed on 2025-03-14 08:15:02
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef DD4HEP_NONE
0014
0015
0016 #include <XML/VolumeBuilder.h>
0017 #include <XML/Utilities.h>
0018 #include <DD4hep/Printout.h>
0019 #include <DD4hep/Plugins.h>
0020 #include <DD4hep/Detector.h>
0021 #include <DD4hep/DetFactoryHelper.h>
0022 #include <Math/Polar2D.h>
0023
0024 #include <TClass.h>
0025
0026 using dd4hep::xml::tools::VolumeBuilder;
0027
0028
0029 VolumeBuilder::VolumeBuilder(Detector& dsc, xml_h x_parent, SensitiveDetector sd)
0030 : description(dsc), x_det(x_parent), sensitive(sd)
0031 {
0032 if ( x_det ) {
0033 name = x_det.nameStr();
0034 id = x_det.id();
0035 detector = DetElement(name, id);
0036 }
0037 buildType = description.buildType();
0038 }
0039
0040
0041 std::size_t VolumeBuilder::collectMaterials(xml_h element) {
0042 std::size_t len = materials.size();
0043 for( xml_coll_t c(element,_U(material)); c; ++c ) {
0044 xml_comp_t x_c = c;
0045 std::string nam = x_c.nameStr();
0046 std::string val = x_c.valueStr();
0047 Material mat = description.material(val);
0048 materials[nam] = mat;
0049 }
0050 return materials.size()-len;
0051 }
0052
0053
0054 void VolumeBuilder::registerShape(const std::string& nam, Solid shape) {
0055 auto is = shapes.find(nam);
0056 if ( is == shapes.end() ) {
0057 shapes[nam] = std::make_pair(xml_h(0), shape);
0058 return;
0059 }
0060 except("VolumeBuilder","+++ Shape %s is already known to this builder unit. ",nam.c_str());
0061 }
0062
0063
0064 void VolumeBuilder::registerVolume(const std::string& nam, Volume volume) {
0065 auto is = volumes.find(nam);
0066 if ( is == volumes.end() ) {
0067 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0068 "+++ Register volume: %-20s shape:%-24s vis:%s sensitive:%s",
0069 nam.c_str(),
0070 volume.solid()->IsA()->GetName(),
0071 volume.visAttributes().name(),
0072 yes_no(volume.isSensitive()));
0073 volumes[nam] = std::make_pair(xml_h(0), volume);
0074 return;
0075 }
0076 except("VolumeBuilder","+++ Volume %s is already known to this builder unit. ",nam.c_str());
0077 }
0078
0079
0080 dd4hep::Volume VolumeBuilder::volume(const std::string& nam) const {
0081 auto iv = volumes.find(nam);
0082 if ( iv == volumes.end() ) {
0083 auto ib = vol_veto.find(nam);
0084 if ( ib != vol_veto.end() ) {
0085
0086 return Volume();
0087 }
0088 except("VolumeBuilder","+++ Volume %s is not known to this builder unit. ",nam.c_str());
0089 }
0090 Volume vol = (*iv).second.second;
0091 if ( !vol.isValid() ) {
0092 except("VolumeBuilder","+++ Failed to access volume %s from the local cache.",nam.c_str());
0093 }
0094 return vol;
0095 }
0096
0097
0098 dd4hep::Transform3D VolumeBuilder::getTransform(const std::string& nam) const {
0099 auto it = transformations.find(nam);
0100 if ( it == transformations.end() ) {
0101 except("VolumeBuilder","+++ Tranformation %s is not known to this builder unit. ",nam.c_str());
0102 }
0103 return (*it).second.second;
0104 }
0105
0106
0107 dd4hep::Solid VolumeBuilder::getShape(const std::string& nam) const {
0108 auto is = shapes.find(nam);
0109 if ( is == shapes.end() ) {
0110 auto ib = shape_veto.find(nam);
0111 if ( ib != shape_veto.end() ) {
0112
0113 return Solid();
0114 }
0115 except("VolumeBuilder","+++ Shape %s is not known to this builder unit. ",nam.c_str());
0116 }
0117 Solid solid = (*is).second.second;
0118 if ( !solid.isValid() ) {
0119 except("VolumeBuilder","+++ Failed to access shape %s from the local cache.",nam.c_str());
0120 }
0121 return solid;
0122 }
0123
0124
0125 dd4hep::Solid VolumeBuilder::makeShape(xml_h handle) {
0126 xml_comp_t x = handle;
0127 xml_attr_t a = handle.attr_nothrow(_U(name));
0128 std::string nam;
0129 if ( a ) {
0130 nam = handle.attr<std::string>(a);
0131 auto is = shapes.find(nam);
0132 if ( is != shapes.end() ) {
0133 except("VolumeBuilder","+++ The named shape %s is already known to this builder unit. "
0134 "Cannot be overridden.",nam.c_str());
0135 }
0136 }
0137
0138 if ( !nam.empty() ) {
0139 auto iv = shape_veto.find(nam);
0140 if ( iv != shape_veto.end() ) {
0141 return Solid();
0142 }
0143 }
0144
0145 a = handle.attr_nothrow(_U(build));
0146 if ( a ) {
0147 std::string build = handle.attr<std::string>(a);
0148 if ( !buildMatch(build,buildType) ) {
0149 printout(INFO,"VolumeBuilder",
0150 "+++ Shape %s does NOT match build requirements. [Ignored]",nam.c_str());
0151 if ( !nam.empty() ) shape_veto.emplace(nam);
0152 return Solid();
0153 }
0154 }
0155
0156 std::string type = x.attr<std::string>(_U(type));
0157 Solid solid = xml::createShape(description, type, x);
0158 if ( !solid.isValid() ) {
0159 except("VolumeBuilder","+++ Failed to create shape %s of type: %s",
0160 nam.c_str(), type.c_str());
0161 }
0162
0163 if ( !nam.empty() ) {
0164 solid.setName(nam);
0165 shapes.emplace(nam,std::make_pair(handle,solid));
0166 }
0167 printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0168 "+++ Created shape of type: %s name: %s",type.c_str(), nam.c_str());
0169 return solid;
0170 }
0171
0172
0173 std::size_t VolumeBuilder::buildShapes(xml_h handle) {
0174 std::size_t len = shapes.size();
0175 for( xml_coll_t c(handle,_U(shape)); c; ++c ) {
0176 xml_elt_t x = c;
0177 std::string nam = x.attr<std::string>(_U(name));
0178 auto is = shapes.find(nam);
0179 if ( is == shapes.end() ) {
0180
0181 xml_attr_t x_build = c.attr_nothrow(_U(build));
0182 if ( x_build ) {
0183 std::string build = c.attr<std::string>(x_build);
0184 if ( !buildMatch(build,buildType) ) {
0185 printout(INFO,"VolumeBuilder",
0186 "+++ Shape %s does NOT match build requirements. [Ignored]",nam.c_str());
0187 shape_veto.emplace(nam);
0188 continue;
0189 }
0190 }
0191 std::string type = x.attr<std::string>(_U(type));
0192 Solid solid = xml::createShape(description, type, c);
0193 if ( !solid.isValid() ) {
0194 except("VolumeBuilder","+++ Failed to create shape %s of type: %s",
0195 nam.c_str(), type.c_str());
0196 }
0197 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0198 "+++ Building shape from XML: %s of type: %s",
0199 nam.c_str(), solid->IsA()->GetName());
0200 shapes.emplace(nam,std::make_pair(c,solid));
0201 continue;
0202 }
0203 except("VolumeBuilder","+++ Shape %s is already known to this builder unit. "
0204 "Cannot be overridden.",nam.c_str());
0205 }
0206 return shapes.size()-len;
0207 }
0208
0209
0210 std::size_t VolumeBuilder::buildVolumes(xml_h handle) {
0211 std::size_t len = volumes.size();
0212 xml_elt_t x_comp(0);
0213 for( xml_coll_t c(handle,_U(volume)); c; ++c ) {
0214 Solid solid;
0215 xml_comp_t x = c;
0216 std::string nam = x.attr<std::string>(_U(name));
0217 xml_attr_t attr = c.attr_nothrow(_U(build));
0218
0219 if ( attr ) {
0220 std::string build = c.attr<std::string>(attr);
0221 if ( !buildMatch(build,buildType) ) {
0222 printout(INFO,"VolumeBuilder",
0223 "+++ Volume %s does NOT match build requirements. [Ignored]",nam.c_str());
0224 continue;
0225 }
0226 }
0227 bool is_sensitive = c.attr_nothrow(_U(sensitive));
0228
0229 if ( (attr=c.attr_nothrow(_U(type))) ) {
0230 std::string typ = c.attr<std::string>(attr);
0231 Volume vol = xml::createVolume(description, typ, c);
0232 vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0233 volumes.emplace(nam,std::make_pair(c,vol));
0234
0235 if ( is_sensitive ) {
0236 vol.setSensitiveDetector(sensitive);
0237 }
0238 solid = vol.solid();
0239 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0240 "+++ Building volume from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0241 nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0242 yes_no(is_sensitive));
0243 buildVolumes(c);
0244 continue;
0245 }
0246
0247
0248 if ( (attr=c.attr_nothrow(_U(shape))) ) {
0249 std::string ref = c.attr<std::string>(attr);
0250 if ( !(solid=getShape(ref)).isValid() ) continue;
0251 }
0252
0253 else if ( (x_comp=x.child(_U(shape),false)) ) {
0254 if ( !(solid=makeShape(x_comp)).isValid() ) continue;
0255 }
0256
0257
0258 if ( solid.isValid() ) {
0259 Material mat = description.material(x.attr<std::string>(_U(material)));
0260 Volume vol(nam, solid, mat);
0261 placeDaughters(detector, vol, x);
0262 vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0263 volumes.emplace(nam,std::make_pair(c,vol));
0264
0265 if ( is_sensitive ) {
0266 vol.setSensitiveDetector(sensitive);
0267 }
0268 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0269 "+++ Building volume from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0270 nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0271 yes_no(is_sensitive));
0272 buildVolumes(c);
0273 continue;
0274 }
0275 bool is_assembly = true;
0276 is_assembly |= x.child(_U(assembly),false) != 0;
0277 is_assembly |= c.attr_nothrow(_U(assembly)) != 0;
0278 if ( is_assembly ) {
0279 Assembly vol(nam);
0280 placeDaughters(detector, vol, x);
0281 vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0282 volumes.emplace(nam,std::make_pair(c,vol));
0283 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0284 "+++ Building assembly from XML: %-20s shape:%-24s vis:%s",
0285 nam.c_str(), vol->GetShape()->IsA()->GetName(), x.visStr().c_str());
0286 buildVolumes(c);
0287 continue;
0288 }
0289 except("VolumeBuilder","+++ Failed to create volume %s - "
0290 "It is neither Volume nor assembly....", nam.c_str());
0291 }
0292 return volumes.size()-len;
0293 }
0294
0295
0296 void VolumeBuilder::_placeSingleVolume(DetElement parent, Volume vol, xml_h c) {
0297 xml_attr_t attr = c.attr_nothrow(_U(logvol));
0298 if ( !attr ) {
0299 attr = c.attr_nothrow(_U(volume));
0300 }
0301 if ( !attr ) {
0302 except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0303 }
0304 std::string nam = c.attr<std::string>(attr);
0305 if ( vol_veto.find(nam) != vol_veto.end() ) {
0306 return;
0307 }
0308 auto iv = volumes.find(nam);
0309 if ( iv == volumes.end() ) {
0310 except("VolumeBuilder",
0311 "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0312 nam.c_str());
0313 }
0314 PlacedVolume pv;
0315 Volume daughter = (*iv).second.second;
0316 attr = c.attr_nothrow(_U(transformation));
0317 if ( attr ) {
0318 std::string tr_nam = c.attr<std::string>(attr);
0319 auto it = transformations.find(tr_nam);
0320 if ( it == transformations.end() ) {
0321 except("VolumeBuilder",
0322 "+++ Failed to locate name transformation %s [typo in the XML?]",
0323 nam.c_str());
0324 }
0325 const Transform3D& tr = (*it).second.second;
0326 pv = vol.placeVolume(daughter, tr);
0327 }
0328 else {
0329 Transform3D tr = xml::createTransformation(c);
0330 pv = vol.placeVolume(daughter, tr);
0331 }
0332 xml_attr_t attr_nam = c.attr_nothrow(_U(name));
0333 if ( attr_nam ) {
0334 std::string phys_nam = c.attr<std::string>(attr_nam);
0335 pv->SetName(phys_nam.c_str());
0336 }
0337 attr = c.attr_nothrow(_U(element));
0338 if ( attr && !parent.isValid() ) {
0339 except("VolumeBuilder",
0340 "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0341 nam.c_str());
0342 }
0343 else if ( attr ) {
0344 int elt_id = parent.id();
0345 std::string elt = c.attr<std::string>(attr);
0346 attr = c.attr_nothrow(_U(id));
0347 if ( attr ) {
0348 elt_id = c.attr<int>(attr);
0349 elt += c.attr<std::string>(attr);
0350 }
0351 DetElement de(parent, elt, elt_id);
0352 de.setPlacement(pv);
0353 placeDaughters(de, daughter, c);
0354 }
0355 else {
0356 placeDaughters(parent, daughter, c);
0357 }
0358 }
0359
0360
0361 void VolumeBuilder::_placeParamVolumes(DetElement parent, Volume vol, xml_h c) {
0362 xml_attr_t attr_tr, attr_elt, attr_nam;
0363 xml_h x_phys = c.child(_U(physvol));
0364 xml_attr_t attr = x_phys.attr_nothrow(_U(logvol));
0365 if ( !attr ) {
0366 attr = x_phys.attr_nothrow(_U(volume));
0367 }
0368 if ( !attr ) {
0369 except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0370 }
0371 std::string nam = x_phys.attr<std::string>(attr);
0372 if ( vol_veto.find(nam) != vol_veto.end() ) {
0373 return;
0374 }
0375 auto iv = volumes.find(nam);
0376 if ( iv == volumes.end() ) {
0377 except("VolumeBuilder",
0378 "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0379 nam.c_str());
0380 }
0381 attr_elt = c.attr_nothrow(_U(element));
0382 if ( attr_elt && !parent.isValid() ) {
0383 except("VolumeBuilder",
0384 "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0385 nam.c_str());
0386 }
0387 Volume daughter = (*iv).second.second;
0388 attr_tr = c.attr_nothrow(_U(transformation));
0389 Transform3D tr;
0390 if ( attr_tr ) {
0391 std::string tr_nam = c.attr<std::string>(attr_tr);
0392 auto it = transformations.find(tr_nam);
0393 if ( it == transformations.end() ) {
0394 except("VolumeBuilder",
0395 "+++ Failed to locate name transformation %s "
0396 "[typo somewhere in the XML?]",
0397 nam.c_str());
0398 }
0399 tr = (*it).second.second;
0400 }
0401 else {
0402 tr = xml::createTransformation(c);
0403 }
0404 Transform3D transformation(Position(0,0,0));
0405 int elt_id = -1;
0406 std::string elt, phys_nam;
0407 attr_nam = x_phys.attr_nothrow(_U(name));
0408 if ( attr_nam ) {
0409 phys_nam = x_phys.attr<std::string>(_U(name))+"_%d";
0410 }
0411 if ( attr_elt ) {
0412 elt_id = parent.id();
0413 elt = c.attr<std::string>(attr_elt);
0414 }
0415 int number = c.attr<int>(_U(number));
0416 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder","+++ Mother:%s place volume %s %d times.",
0417 vol.name(), daughter.name(), number);
0418 for(int i=0; i<number; ++i) {
0419 PlacedVolume pv = vol.placeVolume(daughter, transformation);
0420 if ( attr_nam ) {
0421
0422 }
0423 if ( attr_elt ) {
0424 DetElement de(parent,elt,elt_id);
0425 de.setPlacement(pv);
0426
0427 }
0428 else {
0429
0430 }
0431 transformation *= tr;
0432 }
0433 }
0434
0435
0436 std::size_t VolumeBuilder::load(xml_h element, const std::string& tag) {
0437 std::size_t count = 0;
0438 for( xml_coll_t c(element,Unicode(tag)); c; ++c ) {
0439 std::string ref = c.attr<std::string>(_U(ref));
0440 std::unique_ptr<xml::DocumentHolder> doc(new xml::DocumentHolder(xml::DocumentHandler().load(element, c.attr_value(_U(ref)))));
0441 xml_h vols = doc->root();
0442 printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0443 "++ Processing xml document %s.", doc->uri().c_str());
0444 included_docs[ref] = std::unique_ptr<xml::DocumentHolder>(doc.release());
0445 buildShapes(vols);
0446 buildTransformations(vols);
0447 buildVolumes(vols);
0448 ++count;
0449 }
0450 return count;
0451 }
0452
0453
0454 VolumeBuilder& VolumeBuilder::placeDaughters(Volume vol, xml_h handle) {
0455 DetElement null_de;
0456 return placeDaughters(null_de, vol, handle);
0457 }
0458
0459
0460 VolumeBuilder& VolumeBuilder::placeDaughters(DetElement parent, Volume vol, xml_h handle) {
0461 for( xml_coll_t c(handle,_U(physvol)); c; ++c )
0462 _placeSingleVolume(parent, vol, c);
0463 for( xml_coll_t c(handle,_U(paramphysvol)); c; ++c )
0464 _placeParamVolumes(parent, vol, c);
0465 return *this;
0466 }
0467
0468
0469 std::size_t VolumeBuilder::buildTransformations(Handle_t handle) {
0470 std::size_t len = transformations.size();
0471 for( xml_coll_t c(handle,_U(transformation)); c; ++c ) {
0472 std::string nam = xml_comp_t(c).nameStr();
0473 transformations.emplace(nam,std::make_pair(c,xml::createTransformation(c)));
0474 }
0475 return transformations.size() - len;
0476 }
0477
0478
0479 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol) {
0480 return placeDetector(vol, x_det);
0481 }
0482
0483
0484 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol, xml_h handle) {
0485 xml_comp_t x = handle;
0486 xml_dim_t x_pos = x_det.child(_U(position),false);
0487 xml_dim_t x_rot = x_det.child(_U(rotation),false);
0488 xml_dim_t x_tr = x_det.child(_U(transformation),false);
0489 Volume mother = description.pickMotherVolume(detector);
0490 PlacedVolume pv;
0491
0492 if ( x_tr ) {
0493 Transform3D tr = createTransformation(x_tr);
0494 pv = mother.placeVolume(vol, tr);
0495 }
0496 else if ( x_pos && x_rot ) {
0497 Transform3D tr = createTransformation(x_det);
0498 pv = mother.placeVolume(vol, tr);
0499 }
0500 else if ( x_pos ) {
0501 pv = mother.placeVolume(vol, Position(x_pos.x(0),x_pos.y(0),x_pos.z(0)));
0502 }
0503 else {
0504 pv = mother.placeVolume(vol);
0505 }
0506 vol.setVisAttributes(description, x.visStr());
0507 vol.setLimitSet(description, x.limitsStr());
0508 vol.setRegion(description, x.regionStr());
0509 if ( detector.isValid() ) {
0510 detector.setPlacement(pv);
0511 }
0512 return pv;
0513 }
0514
0515 #endif