diff --git a/CMakeLists.txt b/CMakeLists.txt index 854bd0b25a6a9cfa03f0f857d44930a55be3aabc..6d868e192eae5fd1a32e5a9c75476f314b913f5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ dd4hep_configure_output() dd4hep_add_plugin(${a_lib_name} SOURCES src/BackwardGEMTracker_geo.cpp + src/BarrelBarDetectorWithSideFrame_geo.cpp src/BarrelCalorimeter_geo.cpp src/BarrelCalorimeterHybrid_geo.cpp src/BarrelCalorimeterInterlayers_geo.cpp diff --git a/athena.xml b/athena.xml index 9edd47480f6fcf30746c47ee7e54c0573e5fecee..a0d887d3cf2dc89b4046b8018a4380dab6511171 100644 --- a/athena.xml +++ b/athena.xml @@ -165,17 +165,14 @@ ## Central tracking detectors </documentation> - <include ref="compact/tracking_config_accadia.xml"/> + <include ref="compact/tracking_config_acadia.xml"/> <!--include ref="compact/tracking_config_mgpds.xml"/--> <documentation level="10"> ### PID detectors </documentation> - <!--include ref="compact/dirc.xml"/--> - <include ref="compact/mrich.xml"/> - <!--include ref="compact/forward_trd.xml"/--> - <include ref="compact/drich.xml"/> + <include ref="compact/pid_config_acadia.xml" /> <documentation level="10"> ## Central calorimetry diff --git a/compact/definitions.xml b/compact/definitions.xml index cc2e41d49efcd44cd9f54ae1c9aae16c68c8036a..f7beba445901afd30f687bb743b7aeffe5819994 100644 --- a/compact/definitions.xml +++ b/compact/definitions.xml @@ -335,7 +335,7 @@ Examples: <constant name="BackwardTOF_length" value="0.0*cm"/> <comment> Note: PID has space for DIRC and optional uRWEL layers</comment> - <constant name="BarrelPIDThickness" value="10.0 * cm"/> + <constant name="BarrelPIDThickness" value="15.0 * cm"/> <documentation> @@ -454,7 +454,7 @@ end of the solenoid coils. <constant name="SolenoidYokeEndcapP_zmin" value="Solenoid_length/2.0 + Solenoid_offset + EndcapPExtra_length"/> <constant name="SolenoidYokeEndcapN_zmin" value="Solenoid_length/2.0 - Solenoid_offset + EndcapNExtra_length"/> - <constant name="EcalBarrel_rmin" value="BarrelTrackingAndPID_rmax + 35.0 * mm"/> + <constant name="EcalBarrel_rmin" value="BarrelTrackingAndPID_rmax + 10.0 * mm"/> <constant name="Barrel_rmax" value="Solenoid_rmin - 1.0 *cm "/> <constant name="Barrel_TotalCalThickness" value="Barrel_rmax - EcalBarrel_rmin"/> @@ -614,7 +614,7 @@ The logic goes like this: <constant name="HcalEndcapN_thickness" value="HcalEndcapNLayer_NRepeat * HcalSingleLayerThickness"/> <comment> Special DIRC parameters </comment> - <constant name="DIRCFull_length" value="max(CentralTracking_length + BackwardInnerEndcap_length + EcalEndcapN_length, EcalBarrel_length) + 50*cm"/> + <constant name="DIRCFull_length" value="max(CentralTracking_length + BackwardInnerEndcap_length + EcalEndcapN_length, EcalBarrel_length) + 10*cm"/> <constant name="DIRCExtra_offset" value="-5*cm"/> diff --git a/compact/display.xml b/compact/display.xml index ad508f310f2af1e8de489fc6efb4e194c70d2ac0..16cac3b3b14dfea28ac6a18b5480f32c1c781d01 100644 --- a/compact/display.xml +++ b/compact/display.xml @@ -57,7 +57,14 @@ <comment> PID Detectors </comment> - <vis name="RICHVis" ref="AnlViolet" showDaughters="true"/> + <vis name="RICHVis" ref="AnlViolet" showDaughters="true"/> + + <vis name="DIRCVis" ref="AnlTeal" showDaughters="true" visible="false"/> + <vis name="DIRCLayerVis" ref="AnlTeal" showDaughters="true" visible="false"/> + <vis name="DIRCModuleVis" ref="AnlBlue" showDaughters="true" visible="false"/> + <vis name="DIRCSupportVis" ref="VertexSupportVis" showDaughters="true" visible="true"/> + <vis name="DIRCFrameVis" ref="AnlOrange" showDaughters="true" visible="true"/> + <vis name="DIRCBarVis" ref="AnlTeal" showDaughters="true" visible="true"/> <comment> Beam line diff --git a/compact/fake_dirc.xml b/compact/fake_dirc.xml new file mode 100644 index 0000000000000000000000000000000000000000..4c7fe67497fdd945188c7e63f58367132a8644da --- /dev/null +++ b/compact/fake_dirc.xml @@ -0,0 +1,114 @@ +<lccdd> + + <comment> + DIRC consists of 16 (default) identical modules making a barrel. + </comment> + + <define> + <constant name="DIRC_rmin" value="BarrelTracking_rmax"/> + <constant name="DIRC_rmax" value="DIRC_rmin + BarrelPIDThickness"/> + <constant name="DIRC_length" value="DIRCFull_length"/> + <constant name="DIRC_offset" value="(CentralTracking_length - DIRC_length)/2.0 - DIRCExtra_offset"/> + + <constant name="DIRCModule_count" value="16" comment="Number of DIRC boxes per... DIRC. 16 - default"/> + + <constant name="DIRCBar_thickness" value="17*mm" /> + <constant name="DIRCBar_length" value="DIRC_length-8*cm" /> + + <constant name="DIRCSkinFront_thickness" value="2.5*mm" /> + <constant name="DIRCSkinBack_thickness" value="2.5*mm" /> + + <constant name="DIRCFrame_width" value="20*mm"/> + <constant name="DIRCFrame_length" value="DIRC_length"/> + <constant name="DIRCFrame_thickness" value="40*mm"/> + + <constant name="DIRCModule_rmax" value="DIRC_rmin + DIRCBar_thickness + DIRCSkinFront_thickness + DIRCSkinBack_thickness"/> + <constant name="DIRCModule_thickness" value="DIRCModule_rmax - DIRC_rmin" /> + <constant name="DIRCFrame_rmax" value="DIRC_rmin + DIRCFrame_thickness" /> + + <constant name="DIRCModule_halfangle" value="180*degree/DIRCModule_count" /> + <constant name="DIRCModule_width" value="2*DIRC_rmin * tan(DIRCModule_halfangle)"/> + + <constant name="DIRCModule_rmin" value="DIRC_rmin + 1*cm"/> + + </define> + + + <materials> + </materials> + + <limits> + </limits> + + <regions> + </regions> + + <display> + </display> + + <detectors> + <detector id="BarrelDIRC_ID" name="FakeDIRC" type="athena_FakeDIRC" readout="DIRCBarHits" vis="DIRCVis"> + <dimensions rmin="DIRC_rmin" rmax="DIRC_rmax" length="DIRC_length" /> + <position x="0" y="0" z="DIRC_offset" /> + <comment> Fake DIRC modules </comment> + <module name="DIRCModule" vis="DIRCModuleVis"> + <module_component name="FrontSkin" + material="CarbonFiber" + sensitive="false" + width="DIRCModule_width" + thickness="DIRCSkinFront_thickness" + vis="VertexSupportVis" + length="DIRCBar_length" /> + <module_component name="QuartzBar" + material="Quartz" + sensitive="true" + width="DIRCModule_width" + thickness="DIRCBar_thickness" + vis="DIRCBarVis" + length="DIRCBar_length" /> + <module_component name="BackSkin" + material="CarbonFiber" + sensitive="false" + width="DIRCModule_width" + thickness="DIRCSkinBack_thickness" + vis="DIRCSupportVis" + length="DIRCBar_length" /> + <frame material="StainlessSteel" + width="DIRCFrame_width" + length="DIRCFrame_length" + vis="DIRCFrameVis" + thickness="DIRCFrame_thickness" /> + </module> + <comment> Fake DIRC layers </comment> + <layer module="DIRCModule" id="1" vis="DIRCLayerVis"> + <barrel_envelope + inner_r="DIRC_rmin" + outer_r="DIRC_rmax" + z_length="DIRC_length" /> + <rphi_layout + phi_tilt="0" + nphi="DIRCModule_count" + phi0="0" + rc="0.5*(DIRCModule_rmin+DIRCModule_rmax)" + dr="0" /> + <z_layout + dr="0.0*mm" + z0="0.0*mm" + nz="1" /> + </layer> + </detector> + </detectors> + + <readouts> + <readout name="DIRCBarHits"> + <segmentation type="CartesianGridXY" grid_size_x="3.0*mm" grid_size_y="3.0*mm" /> + <id>system:8,barrel:2,layer:4,module:8,section:4,x:32:-16,y:-16</id> + </readout> + </readouts> + + <plugins> + </plugins> + + <fields> + </fields> +</lccdd> diff --git a/compact/pid_config_acadia.xml b/compact/pid_config_acadia.xml new file mode 100644 index 0000000000000000000000000000000000000000..9c9e5072fb1bc45b4aff3d060112bbd85193f4c9 --- /dev/null +++ b/compact/pid_config_acadia.xml @@ -0,0 +1,8 @@ +<lccdd> + +<include ref="fake_dirc.xml"/> +<include ref="mrich.xml"/> +<include ref="drich.xml"/> + +</lccdd> + diff --git a/compact/subsystem_views/README.mds b/compact/subsystem_views/README.mds new file mode 100644 index 0000000000000000000000000000000000000000..fd530e16924bf0a43c9bc2a876bd254e6b590c29 --- /dev/null +++ b/compact/subsystem_views/README.mds @@ -0,0 +1,11 @@ +# subsytem_views + +These compact detector files are copies of the main `athena.xml` compact description file, modified to only show certain subsystems. + +To add or update a subsystem: + +1. Copy `athena.xml` to this directory (`compact/subsystem_views`) with the appropriate name. +2. Remove all the undesired detectors from this xml file. **Do not modify any of the included xml files** -- only modify the top level xml file here. +3. Check that that you have the desired color scheme (eg. `colors.xml`) and display attributes (eg. `display_detailed.xml`) included. + +These compact detector files should not be used for any real simulations or studies. diff --git a/compact/subsystem_views/inner_detector.xml b/compact/subsystem_views/inner_detector.xml index ab73075d27ff1136e6e1bfb465bca59ad9e9b757..df19d69ae2f43d149664652a237ed0c0c32933d1 100644 --- a/compact/subsystem_views/inner_detector.xml +++ b/compact/subsystem_views/inner_detector.xml @@ -162,17 +162,14 @@ ## Central tracking detectors </documentation> - <include ref="compact/tracking_config_accadia.xml"/> + <include ref="compact/tracking_config_acadia.xml"/> <!--include ref="compact/tracking_config_mgpds.xml"/--> <documentation level="10"> ### PID detectors </documentation> - <!--include ref="compact/dirc.xml"/--> - <include ref="compact/mrich.xml"/> - <!--include ref="compact/forward_trd.xml"/--> - <include ref="compact/drich.xml"/> + <include ref="compact/pid_config_acadia.xml"/> <documentation level="10"> ## Central calorimetry diff --git a/compact/subsystem_views/pid_only.xml b/compact/subsystem_views/pid_only.xml index 8917782d142bc8dc7d555b7818d7e09075d76c1d..07d265938edd6a80b9c216c81e174257e59ca918 100644 --- a/compact/subsystem_views/pid_only.xml +++ b/compact/subsystem_views/pid_only.xml @@ -163,9 +163,7 @@ PID detectors ------------- </comment> - <include ref="compact/dirc.xml"/> - <include ref="compact/mrich.xml"/> - <include ref="compact/drich.xml"/> + <include ref="compact/pid_config_acadia.xml"/> <comment> diff --git a/compact/subsystem_views/tracking_only.xml b/compact/subsystem_views/tracking_only.xml index 0996c864b219e8a0697e12c93ce7bdbfbd3e2fdc..0f4825046f506c906f383cfc5e2b9b0199c8ff5b 100644 --- a/compact/subsystem_views/tracking_only.xml +++ b/compact/subsystem_views/tracking_only.xml @@ -162,7 +162,7 @@ Central tracking detectors -------------------------- </comment> - <include ref="compact/tracking_config_accadia.xml"/> + <include ref="compact/tracking_config_acadia.xml"/> <comment> PID detectors diff --git a/compact/tracking_config_accadia.xml b/compact/tracking_config_acadia.xml similarity index 100% rename from compact/tracking_config_accadia.xml rename to compact/tracking_config_acadia.xml diff --git a/src/BarrelBarDetectorWithSideFrame_geo.cpp b/src/BarrelBarDetectorWithSideFrame_geo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eda8daae25f3b60b4aa28515d382a5aad42635c4 --- /dev/null +++ b/src/BarrelBarDetectorWithSideFrame_geo.cpp @@ -0,0 +1,252 @@ +/** \addtogroup PID + * \brief Type: **Barrel bar detector (think DIRC) with longitudinal frame**. + * \author S. Joosten + * + * \ingroup PID + * + * + * \code + * \endcode + * + * @{ + */ +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "DD4hep/Shapes.h" +#include "DDRec/DetectorData.h" +#include "DDRec/Surface.h" +#include "XML/Layering.h" + +using namespace std; +using namespace dd4hep; + +/** Barrel Bar detector with optional framek + * + * - Optional "frame" tag within the module element (frame eats part of the module width + * and is longitudinal at both sides) + * - Detector is setup as a "tracker" so we can use the hits to perform fast MC + * for e.g. the DIRC + * + */ +static Ref_t create_BarrelBarDetectorWithSideFrame(Detector& description, xml_h e, SensitiveDetector sens) +{ + typedef vector<PlacedVolume> Placements; + xml_det_t x_det = e; + Material air = description.air(); + int det_id = x_det.id(); + string det_name = x_det.nameStr(); + DetElement sdet(det_name, det_id); + map<string, Volume> volumes; + map<string, Placements> sensitives; + map<string, std::vector<rec::VolPlane>> volplane_surfaces; + PlacedVolume pv; + dd4hep::xml::Dimension dimensions(x_det.dimensions()); + xml_dim_t dirc_pos = x_det.position(); + + map<string, std::array<double, 2>> module_thicknesses; + + Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.length() * 0.5); + Volume assembly(det_name, topVolumeShape, air); + + sens.setType("tracker"); + + // loop over the modules + for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) { + xml_comp_t x_mod = mi; + string m_nam = x_mod.nameStr(); + + if (volumes.find(m_nam) != volumes.end()) { + printout(ERROR, "BarrelBarDetectorWithSideFrame", + string((string("Module with named ") + m_nam + string(" already exists."))).c_str()); + throw runtime_error("Logics error in building modules."); + } + + int ncomponents = 0; + int sensor_number = 1; + double total_thickness = 0; + + // Compute module total thickness from components + xml_coll_t ci(x_mod, _U(module_component)); + for (ci.reset(), total_thickness = 0.0; ci; ++ci) { + total_thickness += xml_comp_t(ci).thickness(); + } + // the module assembly volume + Assembly m_vol(m_nam); + volumes[m_nam] = m_vol; + m_vol.setVisAttributes(description, x_mod.visStr()); + + // Optional module frame. + // frame is 2 longitudinal bars at the side of the module + // + // |___| <-- example module cross section (x-y plane), frame is flush with the + // bottom of the module and protrudes on the top if needed + // + + // Get frame width, as it impacts the main module for being built. We + // construct the actual frame structure later (once we know the module width) + double frame_width = 0; + if (x_mod.hasChild("frame")) { + xml_comp_t m_frame = x_mod.child(_U(frame)); + frame_width = m_frame.width(); + } + + double thickness_so_far = 0.0; + double thickness_sum = -total_thickness / 2.0; + double max_component_width = 0; + for (xml_coll_t ci(x_mod, _U(module_component)); ci; ++ci, ++ncomponents) { + xml_comp_t x_comp = ci; + xml_comp_t x_pos = x_comp.position(false); + string c_nam = _toString(ncomponents, "component%d"); + + double box_width = x_comp.width() - 2 * frame_width; + max_component_width = fmax(max_component_width, box_width); + + Box c_box{box_width / 2, x_comp.length() / 2, x_comp.thickness() / 2}; + Volume c_vol{c_nam, c_box, description.material(x_comp.materialStr())}; + + pv = m_vol.placeVolume(c_vol, Position(0, 0, thickness_sum + x_comp.thickness() / 2.0)); + + c_vol.setRegion(description, x_comp.regionStr()); + c_vol.setLimitSet(description, x_comp.limitsStr()); + c_vol.setVisAttributes(description, x_comp.visStr()); + if (x_comp.isSensitive()) { + c_vol.setSensitiveDetector(sens); + sensitives[m_nam].push_back(pv); + module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0, + total_thickness - thickness_so_far - x_comp.thickness() / 2.0}; + // -------- create a measurement plane for the tracking surface attched to the sensitive volume ----- + rec::Vector3D u(0., 1., 0.); + rec::Vector3D v(0., 0., 1.); + rec::Vector3D n(1., 0., 0.); + + // compute the inner and outer thicknesses that need to be assigned to the tracking surface + // depending on wether the support is above or below the sensor + double inner_thickness = module_thicknesses[m_nam][0]; + double outer_thickness = module_thicknesses[m_nam][1]; + + rec::SurfaceType type(rec::SurfaceType::Sensitive); + + rec::VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ; + volplane_surfaces[m_nam].push_back(surf); + } + thickness_sum += x_comp.thickness(); + thickness_so_far += x_comp.thickness(); + } + // Now add-on the frame + if (x_mod.hasChild("frame")) { + xml_comp_t m_frame = x_mod.child(_U(frame)); + double frame_thickness = getAttrOrDefault<double>(m_frame, _U(thickness), total_thickness); + + Box lframe_box{m_frame.width() / 2., m_frame.length() / 2., frame_thickness / 2.}; + Box rframe_box{m_frame.width() / 2., m_frame.length() / 2., frame_thickness / 2.}; + + // Keep track of frame with so we can adjust the module bars appropriately + + Volume lframe_vol{"left_frame", lframe_box, description.material(m_frame.materialStr())}; + Volume rframe_vol{"right_frame", rframe_box, description.material(m_frame.materialStr())}; + lframe_vol.setVisAttributes(description, m_frame.visStr()); + rframe_vol.setVisAttributes(description, m_frame.visStr()); + + m_vol.placeVolume(lframe_vol, Position(frame_width / 2. + max_component_width / 2, 0., + frame_thickness / 2. - total_thickness / 2.0)); + m_vol.placeVolume(rframe_vol, Position(-frame_width / 2. - max_component_width / 2, 0., + frame_thickness / 2. - total_thickness / 2.0)); + } + } + + // now build the layers + for (xml_coll_t li(x_det, _U(layer)); li; ++li) { + xml_comp_t x_layer = li; + xml_comp_t x_barrel = x_layer.child(_U(barrel_envelope)); + xml_comp_t x_layout = x_layer.child(_U(rphi_layout)); + xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the <z_layout> element. + int lay_id = x_layer.id(); + string m_nam = x_layer.moduleStr(); + string lay_nam = _toString(x_layer.id(), "layer%d"); + Tube lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), x_barrel.z_length() / 2.0); + Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume. + lay_vol.setVisAttributes(description, x_layer.visStr()); + + double phi0 = x_layout.phi0(); // Starting phi of first module. + double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a module. + double rc = x_layout.rc(); // Radius of the module center. + int nphi = x_layout.nphi(); // Number of modules in phi. + double rphi_dr = x_layout.dr(); // The delta radius of every other module. + double phi_incr = (M_PI * 2) / nphi; // Phi increment for one module. + double phic = phi0; // Phi of the module center. + double z0 = z_layout.z0(); // Z position of first module in phi. + double nz = z_layout.nz(); // Number of modules to place in z. + double z_dr = z_layout.dr(); // Radial displacement parameter, of every other module. + + Volume module_env = volumes[m_nam]; + DetElement lay_elt(sdet, _toString(x_layer.id(), "layer%d"), lay_id); + Placements& sensVols = sensitives[m_nam]; + + // Z increment for module placement along Z axis. + // Adjust for z0 at center of module rather than + // the end of cylindrical envelope. + double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0; + // Starting z for module placement along Z axis. + double module_z = -z0; + int module = 1; + + // Loop over the number of modules in phi. + for (int ii = 0; ii < nphi; ii++) { + double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of module position. + double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of module position. + double x = rc * std::cos(phic); // Basic x module position. + double y = rc * std::sin(phic); // Basic y module position. + + // Loop over the number of modules in z. + for (int j = 0; j < nz; j++) { + string module_name = _toString(module, "module%d"); + DetElement mod_elt(lay_elt, module_name, module); + + Transform3D tr(RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2), Position(x, y, module_z)); + + pv = lay_vol.placeVolume(module_env, tr); + pv.addPhysVolID("module", module); + pv.addPhysVolID("section", j); + mod_elt.setPlacement(pv); + for (size_t ic = 0; ic < sensVols.size(); ++ic) { + PlacedVolume sens_pv = sensVols[ic]; + DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module); + comp_de.setPlacement(sens_pv); + rec::volSurfaceList(comp_de)->push_back(volplane_surfaces[m_nam][ic]); + } + + /// Increase counters etc. + module++; + // Adjust the x and y coordinates of the module. + x += dx; + y += dy; + // Flip sign of x and y adjustments. + dx *= -1; + dy *= -1; + // Add z increment to get next z placement pos. + module_z += z_incr; + } + phic += phi_incr; // Increment the phi placement of module. + rc += rphi_dr; // Increment the center radius according to dr parameter. + rphi_dr *= -1; // Flip sign of dr parameter. + module_z = -z0; // Reset the Z placement parameter for module. + } + // Create the PhysicalVolume for the layer. + pv = assembly.placeVolume(lay_vol); // Place layer in mother + pv.addPhysVolID("layer", lay_id); // Set the layer ID. + lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr()); + lay_elt.setPlacement(pv); + } + sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr()); + assembly.setVisAttributes(description.invisible()); + pv = description.pickMotherVolume(sdet).placeVolume(assembly, Position(0, 0, dirc_pos.z())); + pv.addPhysVolID("system", det_id); // Set the subdetector system ID. + pv.addPhysVolID("barrel", 1); // Flag this as a barrel subdetector. + sdet.setPlacement(pv); + return sdet; +} + +//@} +// clang-format off +DECLARE_DETELEMENT(BarrelBarDetectorWithSideFrame, create_BarrelBarDetectorWithSideFrame) +DECLARE_DETELEMENT(athena_FakeDIRC, create_BarrelBarDetectorWithSideFrame)