File indexing completed on 2026-10-02 08:09:52
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 if( type == "Assembly" ) {
0193 continue;
0194 }
0195 Solid solid = xml::createShape(description, type, c);
0196 if( !solid.isValid() ) {
0197 except("VolumeBuilder","+++ Failed to create shape %s of type: %s",
0198 nam.c_str(), type.c_str());
0199 }
0200 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0201 "+++ Building shape from XML: %s of type: %s",
0202 nam.c_str(), solid->IsA()->GetName());
0203 shapes.emplace(nam, std::make_pair(c,solid));
0204 continue;
0205 }
0206 except("VolumeBuilder","+++ Shape %s is already known to this builder unit. "
0207 "Cannot be overridden.", nam.c_str());
0208 }
0209 return shapes.size()-len;
0210 }
0211
0212
0213 std::size_t VolumeBuilder::buildVolumes(xml_h handle) {
0214 std::size_t len = volumes.size();
0215 xml_elt_t x_comp(0);
0216 for( xml_coll_t c(handle, _U(volume)); c; ++c ) {
0217 Solid solid;
0218 xml_comp_t x = c;
0219 std::string nam = x.attr<std::string>(_U(name));
0220 xml_attr_t attr = c.attr_nothrow(_U(build));
0221
0222 if( attr ) {
0223 std::string build = c.attr<std::string>(attr);
0224 if( !buildMatch(build,buildType) ) {
0225 printout(INFO,"VolumeBuilder",
0226 "+++ Volume %s does NOT match build requirements. [Ignored]",nam.c_str());
0227 continue;
0228 }
0229 }
0230
0231
0232 bool is_volume_with_shape = x.child(_U(shape),false) != 0 || c.attr_nothrow(_U(shape)) != 0;
0233 if( !is_volume_with_shape ) {
0234 is_volume_with_shape = x.child(_U(solid),false) != 0 || c.attr_nothrow(_U(solid)) != 0;
0235 }
0236 bool is_volume_with_type = c.attr_nothrow(_U(type)) != 0;
0237 bool is_assembly = (x.child(_U(assembly),false) != 0 || c.attr_nothrow(_U(assembly)) != 0);
0238 if ( is_assembly && ( is_volume_with_shape || is_volume_with_type) ) {
0239 printout(ERROR, "VolumeBuilder",
0240 "+++ Shape defined, but ignored for ASSEMBLY volume: %s %s",
0241 nam.c_str(), "[Inconsistent description]" );
0242 }
0243
0244 if ( is_assembly || (!is_volume_with_shape && !is_volume_with_type) ) {
0245 Assembly vol(nam);
0246 Solid sol = vol.solid();
0247 xml_elt_t solid_handle(0);
0248 if( (solid_handle=x.child(_U(shape), false)) ) {
0249 shapes.emplace(nam, std::make_pair(solid_handle,sol));
0250 }
0251 placeDaughters(detector, vol, x);
0252 vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0253 volumes.emplace(nam,std::make_pair(c,vol));
0254 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder",
0255 "+++ Building assembly from XML: %-20s shape:%-24s vis:%s",
0256 nam.c_str(), vol->GetShape()->IsA()->GetName(), x.visStr().c_str());
0257 buildVolumes(c);
0258 continue;
0259 }
0260
0261 bool is_sensitive = c.attr_nothrow(_U(sensitive));
0262
0263 if( (attr=c.attr_nothrow(_U(type))) ) {
0264 std::string typ = c.attr<std::string>(attr);
0265 Volume vol = xml::createVolume(description, typ, c);
0266 vol.setAttributes(description, x.regionStr(), x.limitsStr(), x.visStr());
0267 volumes.emplace(nam,std ::make_pair(c,vol));
0268
0269 if( is_sensitive ) {
0270 vol.setSensitiveDetector(sensitive);
0271 }
0272 solid = vol.solid();
0273 printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0274 "+++ Building volume from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0275 nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0276 yes_no(is_sensitive));
0277 buildVolumes(c);
0278 continue;
0279 }
0280
0281
0282 if( (attr=c.attr_nothrow(_U(shape))) ) {
0283 std::string ref = c.attr<std::string>(attr);
0284 if( !(solid=getShape(ref)).isValid() ) continue;
0285 }
0286
0287 else if( (attr=c.attr_nothrow(_U(solid))) ) {
0288 std::string ref = c.attr<std::string>(attr);
0289 if( !(solid=getShape(ref)).isValid() ) continue;
0290 }
0291
0292 else if( (x_comp=x.child(_U(shape),false)) ) {
0293 if( !(solid=makeShape(x_comp)).isValid() ) continue;
0294 }
0295
0296 else if( (x_comp=x.child(_U(solid),false)) ) {
0297 if( !(solid=makeShape(x_comp)).isValid() ) continue;
0298 }
0299
0300
0301 if( solid.isValid() ) {
0302 Material mat = description.material(x.attr<std::string>(_U(material)));
0303 Volume vol(nam, solid, mat);
0304 placeDaughters(detector, vol, x);
0305 vol.setAttributes(description,x.regionStr(),x.limitsStr(),x.visStr());
0306 volumes.emplace(nam,std::make_pair(c,vol));
0307
0308 if( is_sensitive ) {
0309 vol.setSensitiveDetector(sensitive);
0310 }
0311 printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0312 "+++ Building volume from XML: %-20s shape:%-24s vis:%s sensitive:%s",
0313 nam.c_str(), solid->IsA()->GetName(), x.visStr().c_str(),
0314 yes_no(is_sensitive));
0315 buildVolumes(c);
0316 continue;
0317 }
0318 except("VolumeBuilder","+++ Failed to create volume %s - "
0319 "It is neither Volume nor assembly....", nam.c_str());
0320 }
0321 return volumes.size()-len;
0322 }
0323
0324
0325 void VolumeBuilder::_placeSingleVolume(DetElement parent, Volume vol, xml_h c) {
0326 xml_attr_t attr = c.attr_nothrow(_U(logvol));
0327 if( !attr ) {
0328 attr = c.attr_nothrow(_U(volume));
0329 }
0330 if( !attr ) {
0331 except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0332 }
0333 std::string nam = c.attr<std::string>(attr);
0334 if( vol_veto.find(nam) != vol_veto.end() ) {
0335 return;
0336 }
0337 auto iv = volumes.find(nam);
0338 if( iv == volumes.end() ) {
0339 except("VolumeBuilder",
0340 "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0341 nam.c_str());
0342 }
0343 PlacedVolume pv;
0344 Volume daughter = (*iv).second.second;
0345 attr = c.attr_nothrow(_U(transformation));
0346 if( attr ) {
0347 std::string tr_nam = c.attr<std::string>(attr);
0348 auto it = transformations.find(tr_nam);
0349 if( it == transformations.end() ) {
0350 except("VolumeBuilder",
0351 "+++ Failed to locate name transformation %s [typo in the XML?]",
0352 nam.c_str());
0353 }
0354 const Transform3D& tr = (*it).second.second;
0355 pv = vol.placeVolume(daughter, tr);
0356 }
0357 else {
0358 Transform3D tr = xml::createTransformation(c);
0359 pv = vol.placeVolume(daughter, tr);
0360 }
0361 xml_attr_t attr_nam = c.attr_nothrow(_U(name));
0362 if( attr_nam ) {
0363 std::string phys_nam = c.attr<std::string>(attr_nam);
0364 pv->SetName(phys_nam.c_str());
0365 }
0366 attr = c.attr_nothrow(_U(element));
0367 if( attr && !parent.isValid() ) {
0368 except("VolumeBuilder",
0369 "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0370 nam.c_str());
0371 }
0372 else if( attr ) {
0373 int elt_id = parent.id();
0374 std::string elt = c.attr<std::string>(attr);
0375 attr = c.attr_nothrow(_U(id));
0376 if( attr ) {
0377 elt_id = c.attr<int>(attr);
0378 elt += c.attr<std::string>(attr);
0379 }
0380 DetElement de(parent, elt, elt_id);
0381 de.setPlacement(pv);
0382 placeDaughters(de, daughter, c);
0383 }
0384 else {
0385 placeDaughters(parent, daughter, c);
0386 }
0387 }
0388
0389
0390 void VolumeBuilder::_placeParamVolumes(DetElement parent, Volume vol, xml_h c) {
0391 xml_attr_t attr_tr, attr_elt, attr_nam;
0392 xml_h x_phys = c.child(_U(physvol));
0393 xml_attr_t attr = x_phys.attr_nothrow(_U(logvol));
0394 if( !attr ) {
0395 attr = x_phys.attr_nothrow(_U(volume));
0396 }
0397 if( !attr ) {
0398 except("VolumeBuilder","+++ The xml volume element has no 'logvol' or 'volume' attribute!");
0399 }
0400 std::string nam = x_phys.attr<std::string>(attr);
0401 if( vol_veto.find(nam) != vol_veto.end() ) {
0402 return;
0403 }
0404 auto iv = volumes.find(nam);
0405 if( iv == volumes.end() ) {
0406 except("VolumeBuilder",
0407 "+++ Failed to locate volume %s [typo somewhere in the XML?]",
0408 nam.c_str());
0409 }
0410 attr_elt = c.attr_nothrow(_U(element));
0411 if( attr_elt && !parent.isValid() ) {
0412 except("VolumeBuilder",
0413 "+++ Failed to set DetElement placement for volume %s [Invalid parent]",
0414 nam.c_str());
0415 }
0416 Volume daughter = (*iv).second.second;
0417 attr_tr = c.attr_nothrow(_U(transformation));
0418 Transform3D tr;
0419 if( attr_tr ) {
0420 std::string tr_nam = c.attr<std::string>(attr_tr);
0421 auto it = transformations.find(tr_nam);
0422 if( it == transformations.end() ) {
0423 except("VolumeBuilder",
0424 "+++ Failed to locate name transformation %s "
0425 "[typo somewhere in the XML?]",
0426 nam.c_str());
0427 }
0428 tr = (*it).second.second;
0429 }
0430 else {
0431 tr = xml::createTransformation(c);
0432 }
0433 Transform3D transformation(Position(0,0,0));
0434 int elt_id = -1;
0435 std::string elt, phys_nam;
0436 attr_nam = x_phys.attr_nothrow(_U(name));
0437 if( attr_nam ) {
0438 phys_nam = x_phys.attr<std::string>(_U(name))+"_%d";
0439 }
0440 if( attr_elt ) {
0441 elt_id = parent.id();
0442 elt = c.attr<std::string>(attr_elt);
0443 }
0444 int number = c.attr<int>(_U(number));
0445 printout(debug ? ALWAYS : DEBUG,"VolumeBuilder","+++ Mother:%s place volume %s %d times.",
0446 vol.name(), daughter.name(), number);
0447 for(int i=0; i<number; ++i) {
0448 PlacedVolume pv = vol.placeVolume(daughter, transformation);
0449 if( attr_nam ) {
0450
0451 }
0452 if( attr_elt ) {
0453 DetElement de(parent,elt,elt_id);
0454 de.setPlacement(pv);
0455
0456 }
0457 else {
0458
0459 }
0460 transformation *= tr;
0461 }
0462 }
0463
0464
0465 std::size_t VolumeBuilder::load(xml_h element, const std::string& tag) {
0466 std::size_t count = 0;
0467 for( xml_coll_t c(element,Unicode(tag)); c; ++c ) {
0468 std::string ref = c.attr<std::string>(_U(ref));
0469 std::unique_ptr<xml::DocumentHolder> doc(new xml::DocumentHolder(xml::DocumentHandler().load(element, c.attr_value(_U(ref)))));
0470 xml_h vols = doc->root();
0471 printout(debug ? ALWAYS : DEBUG, "VolumeBuilder",
0472 "++ Processing xml document %s.", doc->uri().c_str());
0473 included_docs[ref] = std::unique_ptr<xml::DocumentHolder>(doc.release());
0474 buildShapes(vols);
0475 buildTransformations(vols);
0476 buildVolumes(vols);
0477 ++count;
0478 }
0479 return count;
0480 }
0481
0482
0483 VolumeBuilder& VolumeBuilder::placeDaughters(Volume vol, xml_h handle) {
0484 DetElement null_de;
0485 return placeDaughters(null_de, vol, handle);
0486 }
0487
0488
0489 VolumeBuilder& VolumeBuilder::placeDaughters(DetElement parent, Volume vol, xml_h handle) {
0490 for( xml_coll_t c(handle,_U(physvol)); c; ++c )
0491 _placeSingleVolume(parent, vol, c);
0492 for( xml_coll_t c(handle,_U(paramphysvol)); c; ++c )
0493 _placeParamVolumes(parent, vol, c);
0494 return *this;
0495 }
0496
0497
0498 std::size_t VolumeBuilder::buildTransformations(Handle_t handle) {
0499 std::size_t len = transformations.size();
0500 for( xml_coll_t c(handle,_U(transformation)); c; ++c ) {
0501 std::string nam = xml_comp_t(c).nameStr();
0502 transformations.emplace(nam,std::make_pair(c,xml::createTransformation(c)));
0503 }
0504 return transformations.size() - len;
0505 }
0506
0507
0508 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol) {
0509 return placeDetector(vol, x_det);
0510 }
0511
0512
0513 dd4hep::PlacedVolume VolumeBuilder::placeDetector(Volume vol, xml_h handle) {
0514 xml_comp_t x = handle;
0515 xml_dim_t x_pos = x_det.child(_U(position),false);
0516 xml_dim_t x_rot = x_det.child(_U(rotation),false);
0517 xml_dim_t x_tr = x_det.child(_U(transformation),false);
0518 Volume mother = description.pickMotherVolume(detector);
0519 PlacedVolume pv;
0520
0521 if( x_tr ) {
0522 Transform3D tr = createTransformation(x_tr);
0523 pv = mother.placeVolume(vol, tr);
0524 }
0525 else if( x_pos && x_rot ) {
0526 Transform3D tr = createTransformation(x_det);
0527 pv = mother.placeVolume(vol, tr);
0528 }
0529 else if( x_pos ) {
0530 pv = mother.placeVolume(vol, Position(x_pos.x(0),x_pos.y(0),x_pos.z(0)));
0531 }
0532 else {
0533 pv = mother.placeVolume(vol);
0534 }
0535 vol.setVisAttributes(description, x.visStr());
0536 vol.setLimitSet(description, x.limitsStr());
0537 vol.setRegion(description, x.regionStr());
0538 if( detector.isValid() ) {
0539 detector.setPlacement(pv);
0540 }
0541 return pv;
0542 }
0543
0544 #endif