diff --git a/DDCore/src/plugins/DetectorCheck.cpp b/DDCore/src/plugins/DetectorCheck.cpp index 21421a8a18f98270c476fcbe24e0ba6d5bc87fa9..2add900955f4eb47a87d874151cd1d51c1a5e46b 100644 --- a/DDCore/src/plugins/DetectorCheck.cpp +++ b/DDCore/src/plugins/DetectorCheck.cpp @@ -97,6 +97,7 @@ namespace { bool check_placements { false }; bool check_volmgr { false }; bool check_sensitive { false }; + bool ignore_detector { false }; SensitiveDetector get_current_sensitive_detector(); @@ -449,7 +450,7 @@ void DetectorCheck::checkManagerSingleVolume(DetElement detector, PlacedVolume p if ( pv.volume().isSensitive() ) { PlacedVolume det_place = m_volMgr.lookupDetElementPlacement(vid); ++m_sens_counters.elements; - if ( pv.ptr() != det_place.ptr() ) { + if ( !ignore_detector && pv.ptr() != det_place.ptr() ) { err << "VolumeMgrTest: Wrong placement " << " got " << det_place.name() << " (" << (void*)det_place.ptr() << ")" << " instead of " << pv.name() << " (" << (void*)pv.ptr() << ") " @@ -551,33 +552,35 @@ void DetectorCheck::checkManagerSingleVolume(DetElement detector, PlacedVolume p printout(ERROR, m_det.name(), "DETELEMENT_PERSISTENCY FAILED: World transformation have DIFFERET pointer!"); ++m_place_counters.errors; } - - if ( pv.ptr() == det_elem.placement().ptr() ) { - // The computed transformation 'trafo' MUST be equal to: - // m_volMgr.worldTransformation(vid) AND det_elem.nominal().worldTransformation() - int res1 = detail::matrix::_matrixEqual(trafo, det_elem.nominal().worldTransformation()); - int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid)); - if ( res1 != detail::matrix::MATRICES_EQUAL || res2 != detail::matrix::MATRICES_EQUAL ) { - printout(ERROR, m_det.name(), "DETELEMENT_PLACEMENT FAILED: World transformation DIFFER."); - ++m_place_counters.errors; - } - else { - printout(INFO, m_det.name(), "DETELEMENT_PLACEMENT: PASSED. All matrices equal: %s", - volumeID(vid).c_str()); - } - } - else { - // The computed transformation 'trafo' MUST be equal to: - // m_volMgr.worldTransformation(vid) - // The det_elem.nominal().worldTransformation() however is DIFFERENT! - int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid)); - if ( res2 != detail::matrix::MATRICES_EQUAL ) { - printout(ERROR, m_det.name(), "VOLUME_PLACEMENT FAILED: World transformation DIFFER."); - ++m_place_counters.errors; + + if ( !ignore_detector ) { + if ( pv.ptr() == det_elem.placement().ptr() ) { + // The computed transformation 'trafo' MUST be equal to: + // m_volMgr.worldTransformation(vid) AND det_elem.nominal().worldTransformation() + int res1 = detail::matrix::_matrixEqual(trafo, det_elem.nominal().worldTransformation()); + int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid)); + if ( res1 != detail::matrix::MATRICES_EQUAL || res2 != detail::matrix::MATRICES_EQUAL ) { + printout(ERROR, m_det.name(), "DETELEMENT_PLACEMENT FAILED: World transformation DIFFER."); + ++m_place_counters.errors; + } + else { + printout(INFO, m_det.name(), "DETELEMENT_PLACEMENT: PASSED. All matrices equal: %s", + volumeID(vid).c_str()); + } } else { - printout(INFO, m_det.name(), "VOLUME_PLACEMENT: PASSED. All matrices equal: %s", - volumeID(vid).c_str()); + // The computed transformation 'trafo' MUST be equal to: + // m_volMgr.worldTransformation(vid) + // The det_elem.nominal().worldTransformation() however is DIFFERENT! + int res2 = detail::matrix::_matrixEqual(trafo, m_volMgr.worldTransformation(m_mapping,vid)); + if ( res2 != detail::matrix::MATRICES_EQUAL ) { + printout(ERROR, m_det.name(), "VOLUME_PLACEMENT FAILED: World transformation DIFFER."); + ++m_place_counters.errors; + } + else { + printout(INFO, m_det.name(), "VOLUME_PLACEMENT: PASSED. All matrices equal: %s", + volumeID(vid).c_str()); + } } } } @@ -643,6 +646,7 @@ void DetectorCheck::help(int argc,char** argv) { " sensitive volume placements. \n\n" " NOTE: Option requires proper PhysVolID setup \n" " of the sensitive volume placements ! \n" + " -ignore_detector Ignore DetElement placement check for -volmgr \n" << std::endl; std::cout << "Arguments: " << std::endl; for(int iarg=0; iarg<argc;++iarg) { @@ -659,6 +663,7 @@ long DetectorCheck::run(Detector& description,int argc,char** argv) { bool structure = false; bool sensitive = false; bool placements = false; + bool ignore_de = false; printout(ALWAYS, "DetectorCheck", "++ Processing plugin..."); for(int iarg=0; iarg<argc;++iarg) { if ( argv[iarg] == 0 ) break; @@ -674,6 +679,8 @@ long DetectorCheck::run(Detector& description,int argc,char** argv) { geometry = true; else if ( ::strncasecmp(argv[iarg], "-sensitive",4) == 0 ) sensitive = true; + else if ( ::strncasecmp(argv[iarg], "-ignore_detelement",4) == 0 ) + ignore_de = true; else if ( ::strncasecmp(argv[iarg], "-help",4) == 0 ) help(argc, argv); else @@ -685,12 +692,13 @@ long DetectorCheck::run(Detector& description,int argc,char** argv) { if ( name == "all" || name == "All" || name == "ALL" ) { for (const auto& det : description.detectors() ) { printout(INFO, "DetectorCheck", "++ Processing subdetector: %s", det.second.name()); - test.check_structure = structure; - test.check_placements = placements; - test.check_volmgr = volmgr; - test.check_geometry = geometry; - test.check_sensitive = sensitive; - test.execute(det.second, 9999); + test.check_structure = structure; + test.check_placements = placements; + test.check_volmgr = volmgr; + test.check_geometry = geometry; + test.check_sensitive = sensitive; + test.ignore_detector = ignore_de; + test.execute(det.second, 9999); } return 1; } @@ -702,6 +710,7 @@ long DetectorCheck::run(Detector& description,int argc,char** argv) { test.check_volmgr = volmgr; test.check_geometry = geometry; test.check_sensitive = sensitive; + test.ignore_detector = ignore_de; test.execute(det, 9999); } return 1; diff --git a/examples/ClientTests/compact/FiberTubeCalorimeter.xml b/examples/ClientTests/compact/FiberTubeCalorimeter.xml new file mode 100644 index 0000000000000000000000000000000000000000..44cf6321e00f38a61dba020190ff8d97debff57b --- /dev/null +++ b/examples/ClientTests/compact/FiberTubeCalorimeter.xml @@ -0,0 +1,110 @@ +<lccdd> + <info name="SCEPCAL with IDEA" + title="SCEPCAL with IDEA" + author="Sarah Eno" + url="https://twiki.cern.ch/twiki/bin/view/CLIC/xxx" + status="development" + version="1.0"> + <comment>The compact format for the SCEPCAL IDEA from Sarah Eno</comment> + </info> + + <includes> + <gdmlFile ref="${DD4hepINSTALL}/DDDetectors/compact/elements.xml"/> + <gdmlFile ref="${DD4hepINSTALL}/DDDetectors/compact/materials.xml"/> + </includes> + + <materials> + <material name="Brass"> + <D value="8.73" unit="g/cm3" /> + <fraction n="0.75" ref="Cu"/> + <fraction n="0.25" ref="Zn"/> + </material> + </materials> + + <define> + <!-- constants for dual readout crystal calorimeter --> + <constant name="DRcrystalwidth" value="1.0*cm"/> <!-- should be 1 --> + <constant name="DRcrystallength" value="20.0*cm"/> <!-- should be 20 normally, 400 for 20 interacion length test--> + <constant name="DRcrystalNsize" value="45"/> <!-- should be 45 --> + <!-- gap between ecal and hcal --> + <constant name="EcalHcalgap" value="0.1*cm"/> <!-- should be small 0.1 mm --> + <!-- constants for dual readout spagetti fiber hcal calorimeter in SCEPCAL --> + <!-- these are radii (or half widths) --> + <constant name="DRFiberAbswidthSCE" value="1.0*mm"/> <!-- should be 1.0 mm --> + <constant name="DRFiberFibwidthSCE" value=".5025*mm"/> <!-- should be 0.5025 mm --> + <constant name="holeoverSCE" value="0.025*mm"/> + <constant name="gapSCE" value="0.0001*mm"/> + <constant name="DRFiberlengthSCE" value="2.*cm"/> <!-- should be 200 cm --> + <constant name="DRFiberNsizeSCE" value="5"/> <!-- should be 136 --> + <!-- 200 crash 190 no crash 195 no crash 197 no crash 199 no crash--> + <!-- crashes when make fiber size smaller --> + + <!-- constants for dual readout spagetti fiber hcal calorimeter in IDEA --> + <constant name="DRFiberAbswidthIDEA" value="1.0*mm"/> <!-- should be 1.0 mm --> + <constant name="DRFiberFibwidthIDEA" value="0.5025*mm"/> <!-- should be 0.5025 mm --> + <constant name="holeoverIDEA" value="0.025*mm"/> + <constant name="gapIDEA" value="0.0001*mm"/> + <constant name="DRFiberlengthIDEA" value="400.*cm"/> <!-- should be 200 cm --> + <constant name="DRFiberNsizeIDEA" value="199"/> <!-- should be 150 --> + + +<!-- constants for dual readout sampling hcal calorimeter --> + <constant name="DRSampAthick" value="4.*mm"/> <!-- should be 20 --> + <constant name="DRSampSthick" value="4.*mm"/> <!-- should be 5 --> + <constant name="DRSampQthick" value="4.*mm"/> <!-- should be 5 --> + <constant name="DRSampxy" value="20.*mm"/> <!-- should be 20 --> + <constant name="DRSampNsize" value="10"/> <!-- should be 5 --> + <constant name="DRSampNlayer" value="200"/> <!-- should be 40 --> + <!-- detector numbering scheme --> + <constant name="Ecal_ID" value="5"/> + <constant name="Hcal_ID" value="6"/> + <constant name="EdgeDet_ID" value="4"/> + + <constant name="killthick" value="0.01*cm"/> + <constant name="edgeoffset" value="50*cm"/> + + <constant name="world_side" value="DRcrystallength+2*DRFiberlengthIDEA+EcalHcalgap+edgeoffset+10."/> + <constant name="world_x" value="world_side/1.5"/> <!-- should be /4 --> + <constant name="world_y" value="world_side/1.5"/> <!-- should be /4 --> + <constant name="world_z" value="world_side"/> + </define> + + <display> + <vis name="AbsVis" alpha="1.0" r="0.0" g="1.0" b="0.0" showDaughters="true" visible="true"/> + <vis name="CerenVis" alpha="0.5" r="0.0" g="0.0" b="1.0" showDaughters="true" visible="true"/> + <vis name="ScintVis" alpha="0.5" r="1.0" g="0.0" b="0.0" showDaughters="true" visible="true"/> + <vis name="phdetVis" alpha="1.0" r="1.0" g="1.0" b="1.0" showDaughters="true" visible="true"/> + <vis name="towerVis" alpha="0.1" r="0.3" g="0.3" b="0.3" showDaughters="true" visible="true"/> + </display> + + <readouts> + <readout name="DRFNoSegment"> + <segmentation type="NoSegmentation"/> + <id>system:8,layer:12,tube:12,hole:3,type:3</id> + </readout> + </readouts> + + <detectors> + <detector id="Hcal_ID" name="FiberTubeCalorimeter" type="DD4hep_FiberTubeCalorimeter" readout="DRFNoSegment" vis="towerVis"> + <!-- here z_length is the absorber length, thickness is length of an end side + z1 is the photodetector length gap is the distance between modules, and dz is how far the fiber sticks out of the absorber. + Nsize is the number of cells to make + zmin is where the dtector goes + --> + <dimensions numsides="DRFiberNsizeSCE" + thickness="DRFiberAbswidthSCE" + z_length="DRFiberlengthSCE" + gap="gapSCE" + zmin="-world_side/2.+2*killthick+edgeoffset+DRcrystallength+EcalHcalgap" + z1="killthick"/> + <structure> + <core1 name="core1" rmax="DRFiberFibwidthSCE" rmin="0.0" material="Polystyrene" vis="ScintVis" sensitive="yes"/> + <core2 name="core2" rmax="DRFiberFibwidthSCE" rmin="0.0" material="Quartz" vis="CerenVis" sensitive="yes"/> + <hole name="hole" rmax="(DRFiberFibwidthSCE+holeoverSCE)" rmin="0.0" material="Air" vis="holeVis" sensitive="yes"/> + <absorb material="Brass" vis="AbsVis" sensitive="yes"/> + <phdet1 name="phdet1" rmax="DRFiberFibwidthSCE" rmin="0.0" material="killMedia2" vis="phdetVis" sensitive="yes"/> + <phdet2 name="phdet2" rmax="DRFiberFibwidthSCE" rmin="0.0" material="killMedia3" vis="phdetVis" sensitive="yes"/> + </structure> + </detector> + </detectors> +</lccdd> diff --git a/examples/ClientTests/src/FiberTubeCalorimeter_geo.cpp b/examples/ClientTests/src/FiberTubeCalorimeter_geo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed2251b2bdaab7b9a16dba4e1a81e478d067c0b4 --- /dev/null +++ b/examples/ClientTests/src/FiberTubeCalorimeter_geo.cpp @@ -0,0 +1,177 @@ +//========================================================================== +// 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 +// +//========================================================================== +// +// Specialized generic detector constructor for fiber tube calorimeter. +// See https://github.com/AIDASoft/DD4hep/issues/1173 for details +// +// Detector geometry structure +// <system> <layer> <tube> <hole> <type> +// /world_volume/FiberCalo/rowtube_1/brass_1/hole_1/quartz_1 +// /brass_2/hole_1/scintillator_1 brass_1 == brass_2 == brass....n +// /brass_3/hole_1/quartz_1 +// /brass_4/hole_1/scintillator_1 +// /brass_5/hole_1/quartz_1 +// brass_1/quartz_1 Volume(brass) / hole +// Volume(hole) / quartz +// alt: Volume(hole) / scintillator +// +// /world_volume/FiberCalo/rowtube_1/brass/quartz +// +// Dump using: +// geoPluginRun -input examples/ClientTests/compact/FiberTubeCalorimeter.xml \ +// -volmgr -print 3 -plugin DD4hep_DetectorCheck \ +// -name FiberTubeCalorimeter -geometry -structure -sensitive -volmgr -ignore +// +//========================================================================== +#include "DD4hep/DetFactoryHelper.h" + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::detail; + +static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) { + constexpr double tol = 0.0; + xml_det_t x_det = e; + + // for volume tags in detector + int det_id = x_det.id(); + string det_name = x_det.nameStr(); + Material air = description.air(); + + // pointer to finding dimensins text in xml file + // look in DDCore/include/Parsers/detail/Dimension.h for arguments + xml_comp_t x_dim = x_det.dimensions(); + double hthick = x_dim.thickness(); + double hzlength = x_dim.z_length()/2.; + double hzph = x_dim.z1(); + int Ncount = x_dim.numsides(); + double agap = x_dim.gap(); + double azmin = x_dim.zmin(); + + // these refer to different fields in the xml file for this detector + xml_comp_t fX_struct( x_det.child( _Unicode(structure) ) ); + xml_comp_t fX_absorb( fX_struct.child( _Unicode(absorb) ) ); + xml_comp_t fX_core1( fX_struct.child( _Unicode(core1) ) ); + xml_comp_t fX_core2( fX_struct.child( _Unicode(core2) ) ); + xml_comp_t fX_hole( fX_struct.child( _Unicode(hole) ) ); + xml_comp_t fX_phdet1( fX_struct.child( _Unicode(phdet1) ) ); + xml_comp_t fX_phdet2( fX_struct.child( _Unicode(phdet2) ) ); + + // detector element for entire detector. + DetElement sdet (det_name, det_id); + Volume motherVol = description.pickMotherVolume(sdet); + Box env_box ((2*Ncount+1)*(hthick+agap+tol),(2*Ncount+1)*(hthick+agap+tol), (hzlength+hzph+tol)); + Volume envelopeVol (det_name, env_box, air); + envelopeVol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); + + Material mat; + Transform3D trafo; + PlacedVolume pv; + + pv = motherVol.placeVolume(envelopeVol, Position(0.,0.,azmin+hzlength+hzph+tol)); + pv.addPhysVolID("system", det_id); + sdet.setPlacement(pv); // associate the placed volume to the detector element + sens.setType("calorimeter"); + + // scint fiber + mat = description.material(fX_core1.materialStr()); + Volume fiber_scint_vol("fiber1", Tube(0.,fX_core1.rmax(), hzlength), mat); + fiber_scint_vol.setAttributes(description,fX_core1.regionStr(),fX_core1.limitsStr(),fX_core1.visStr()); + if ( fX_core1.isSensitive() ) { + fiber_scint_vol.setSensitiveDetector(sens); + } + + // quartz fiber + Tube fiber_quartz_tub(0.,fX_core2.rmax(), hzlength); + Volume fiber_quartz_vol("fiber_quartz", fiber_quartz_tub, description.material(fX_core2.materialStr())); + fiber_quartz_vol.setAttributes(description,fX_core2.regionStr(),fX_core2.limitsStr(),fX_core2.visStr()); + cout<<"fiber_quartz vis is "<<fX_core2.visStr()<<endl; + if ( fX_core2.isSensitive() ) { + cout<<"setting DRFtubeFiber fiber_quartz sensitive "<<endl; + fiber_quartz_vol.setSensitiveDetector(sens); + } + + // absorberhole with a scintillating fiber inside + Tube hole_tube(0.,fX_hole.rmax(),hzlength); + Volume scint_hole_vol( "scintAbsorberHole", hole_tube, air); + scint_hole_vol.setAttributes(description,fX_hole.regionStr(),fX_hole.limitsStr(),fX_hole.visStr()); + trafo = Transform3D(RotationZYX(0.,0.,0.),Position(0.,0.,0.)); + pv = scint_hole_vol.placeVolume(fiber_scint_vol, trafo); + pv.addPhysVolID("type",1); + if ( fX_hole.isSensitive() ) { + cout<<"setting DRFtubeFiber absorber hole sensitive "<<endl; + scint_hole_vol.setSensitiveDetector(sens); + } + + // absorberhole with a quartz inside + Volume quartz_hole_vol( "quartzAbsorberHole", hole_tube, air); + quartz_hole_vol.setAttributes(description,fX_hole.regionStr(),fX_hole.limitsStr(),fX_hole.visStr()); + pv = quartz_hole_vol.placeVolume(fiber_quartz_vol); + pv.addPhysVolID("type",2); + if ( fX_hole.isSensitive() ) { + cout<<"setting DRFtubeFiber absorber hole sensitive "<<endl; + quartz_hole_vol.setSensitiveDetector(sens); + } + + // absorber with scintillator inside + mat = description.material(fX_absorb.materialStr()); + Tube brass_tube(0.,hthick,hzlength); + Volume scint_abs_vol( "scintAbsorber", brass_tube, mat); + scint_abs_vol.setAttributes(description,fX_absorb.regionStr(),fX_absorb.limitsStr(),fX_absorb.visStr()); + pv = scint_abs_vol.placeVolume(scint_hole_vol); + pv.addPhysVolID("hole",1); + if ( fX_absorb.isSensitive() ) { + cout<<"setting DRFtubeFiber absorber sensitive "<<endl; + scint_abs_vol.setSensitiveDetector(sens); + } + + // absorber with quartz inside + mat = description.material(fX_absorb.materialStr()); + Volume quartz_abs_vol( "quartzAbsorber", brass_tube, mat); + quartz_abs_vol.setAttributes(description,fX_absorb.regionStr(),fX_absorb.limitsStr(),fX_absorb.visStr()); + pv = quartz_abs_vol.placeVolume(quartz_hole_vol, trafo); + pv.addPhysVolID("hole",2); + if ( fX_absorb.isSensitive() ) { + cout<<"setting DRFtubeFiber absorber sensitive "<<endl; + quartz_abs_vol.setSensitiveDetector(sens); + } + + // setup the volumes with the shapes and properties in one horixontal layer + Volume tube_row_vol("layer", Box(hthick,hthick,hzlength+hzph), air); + tube_row_vol.setVisAttributes(description, x_det.visStr()); + //tube_row_vol.setSensitiveDetector(sens); + + for (int ijk=-Ncount; ijk<Ncount+1; ijk++) { + cout<<"making row ijk "<<ijk<<endl; + double mod_x_off = (ijk)*2*(hthick+agap); + Transform3D tr(RotationZYX(0.,0.,0.), Position(mod_x_off,0.,0.)); + int towernum = Ncount + ijk + 1; + pv = tube_row_vol.placeVolume((towernum%2 == 0) ? quartz_abs_vol : scint_abs_vol, tr); + pv.addPhysVolID("tube", towernum); + } + // Now stack multiple horizontal layers to form the final box + for (int ijk=-Ncount; ijk<Ncount+1; ijk++) { + cout << "making row ijk " << ijk << endl; + double mod_y_off = (ijk)*2*(hthick+agap); + Transform3D tr(RotationZYX(0.,0.,0.), Position(0.,mod_y_off,0.)); + pv = envelopeVol.placeVolume(tube_row_vol, tr); + pv.addPhysVolID("layer", Ncount+ijk+1); + + DetElement de_layer(_toString(Ncount+ijk, "layer_%d"), det_id); + de_layer.setPlacement(pv); + sdet.add(de_layer); + } + return sdet; +} + +DECLARE_DETELEMENT(DD4hep_FiberTubeCalorimeter,create_detector)