From 042b30b2381a5f8ee776f40f76edd6c5aa2c83b4 Mon Sep 17 00:00:00 2001 From: varnes <150390087+varnes@users.noreply.github.com> Date: Sat, 22 Feb 2025 01:54:37 -0700 Subject: [PATCH] ECal endcap turbine version 3 (#426) * Add v02 of turbine endcal ecal * Fix up some printouts * Fix printouts * Fix printouts * Fix printouts * Fix printouts * Fix printout * IDEA with DRC dedicated test added * fix IDEA with DRC test * apply other SD action to DRC * still not working... * replace absolute path by cmake variables in ctest * IDEA+DRC test is now working * copy TrackerBarrel_o1_v06 * copy CLD_o2_v06 to CLD_o2_v07 * update version * Use new TrackerBarrel * TrackerBarrel_o1_v06 remove using namespace std * move NeighbourSurfacesData population into a function * Move LayerLayout population out of the sensor loop * TrackerBarrel_o1_v06 add assembly stave * addExtensionsToHCalAllegro * implemented suggestions from discussion * implement comments and improve code readibility * fix failing test and remove unused phi segmentation * fix endcap bitfields and improve readibility * keep ALLEGRO v03 xml file unchanged * adding version nr also for the barrel xml * update READMEs * add HCalTileBarrel_o1_v02_geo.cpp * CLD_o2_v07: start with new lumical to fix overlaps * CLD_o2_v07: remove old lumical xml * Updates for v2 of turbine geometry * Updates for v2 of turbine geometry * Updates for v2 of turbine geometry * Fix bugs in LAr bath placement and in placement of passive elements when split into layers * Calibration layers in z as well as rho * Update to use z calibration layers * Add v03 of the turbine geometry * Updates for topological clustering * Updates for topological clustering * Updates for topological clustering * Fix a few typos * Fix compiler warnings * Update nominal detector model for turbing ecal endcap * remove cout's * Change NL to LAr * Update with description of v03 * Add some new accessor function * Proper calibration xml * Remove unintentional changes * Remove unintentional changes * Remove unintentional changes * Remove commented code * Fix subtype numbering and remove commented code * Remove unintentional changes * Remove duplicated lines * Remove unintentional changes * Remove unintentional changes * Fix remaining bugs in subtype numbering, add separate xmls for v02 and v03 * Fix remaining bugs in subtype numbering, add separate xmls for v02 and v03 * Fix remaining bugs in subtype numbering, add separate xmls for v02 and v03 * Remove commented code * Remove comments * Modify as suggested in the PR * Remove some outdated xmls * Rename xmls to comply with versioning recommendation * Use new name for turbine ECal * Use new name for turbine ECal * Add updated turbine xmls to ALLEGRO_o1_v04 area * Bring into sync with main * Sync with main * Revert "Sync with main" This reverts commit d246857a20f84eed9a7cfa29684a40b44c359e6a. Undoing bad commit * Revert "Bring into sync with main" This reverts commit 9587c0a93a03689aa0deae121677d92beaa79f15. Undoing bad commit * Add a bit more information about the updates to the endcap turbine calorimeter * Revise CI tests to avoid timeout, and make ALLEGRO v04 test the same as ALLEGRO v03 --------- Co-authored-by: Erich Varnes Co-authored-by: Alvaro Tolosa Delgado Co-authored-by: Leonhard Reichenbach Co-authored-by: michaela mlynarikova Co-authored-by: Andre Sailer --- .../compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml | 2 +- ...ine.xml => ECalEndcaps_Turbine_o1_v03.xml} | 93 ++- ...CalEndcaps_Turbine_o1_v03_calibration.xml} | 97 ++- .../ECalEndcaps_Turbine_o1_v03_upstream.xml | 148 ++++ .../compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml | 2 +- .../ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml | 1 - .../ECalEndcaps_Turbine_calibration.xml | 1 - .../ECalEndcaps_Turbine_o1_v03.xml | 154 ++++ ...ECalEndcaps_Turbine_o1_v03_calibration.xml | 148 ++++ .../ECalEndcaps_Turbine_o1_v03_upstream.xml | 148 ++++ FCCee/ALLEGRO/compact/README.md | 4 +- .../ECalEndcap_Turbine_o1_v01_geo.cpp | 34 +- .../ECalEndcap_Turbine_o1_v02_geo.cpp | 183 ++-- .../ECalEndcap_Turbine_o1_v03_geo.cpp | 784 ++++++++++++++++++ detector/calorimeter/README.md | 5 +- .../FCCSWEndcapTurbine_k4geo.h | 129 ++- .../src/FCCSWEndcapTurbine_k4geo.cpp | 234 ++++-- test/CMakeLists.txt | 12 +- 18 files changed, 1891 insertions(+), 288 deletions(-) rename FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/{ECalEndcaps_Turbine.xml => ECalEndcaps_Turbine_o1_v03.xml} (50%) rename FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/{ECalEndcaps_Turbine_calibration.xml => ECalEndcaps_Turbine_o1_v03_calibration.xml} (51%) create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03_upstream.xml delete mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml delete mode 120000 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_calibration.xml create mode 100644 FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_upstream.xml create mode 100644 detector/calorimeter/ECalEndcap_Turbine_o1_v03_geo.cpp diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml index aa821a3ad..3b2f14cc1 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml @@ -46,7 +46,7 @@ - + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03.xml similarity index 50% rename from FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml rename to FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03.xml index ac5b7f2ef..c7c2b6ce6 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03.xml @@ -40,23 +40,54 @@ - - + + + + + + + + + + + + - - - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + - - + + + + @@ -73,49 +104,33 @@ - - - system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:8,module:17,rho:8,z:8 + + system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:12,module:11,rho:8,z:8 - - --> - + - + - - + - - - + + + + - + - - + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03_calibration.xml similarity index 51% rename from FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml rename to FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03_calibration.xml index 1df7dd3af..6e16b07a2 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03_calibration.xml @@ -32,23 +32,54 @@ - - + + + + + + + + + + + + - - - - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + - - + + + + @@ -65,49 +96,35 @@ - - - system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:8,module:17,rho:8,z:8 + + system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:12,module:11,rho:8,z:8 + + - - --> - - + - - + + - - - + + + + - + - - + + @@ -128,4 +145,4 @@ - \ No newline at end of file + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03_upstream.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03_upstream.xml new file mode 100644 index 000000000..49e120926 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ECalEndcaps_Turbine_o1_v03_upstream.xml @@ -0,0 +1,148 @@ + + + + + Liquid argon EM calorimeter endcap design. + Electromagnetic part (EMEC) includes lead+steel absorber. + Turbine geometry. + + + + + + + + + + + + + + + + + + + + + + offset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:12,module:11,rho:8,z:8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml index 2d30835c1..0dd33f3ff 100644 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml @@ -46,7 +46,7 @@ - + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml deleted file mode 120000 index 1b74f8d80..000000000 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine.xml +++ /dev/null @@ -1 +0,0 @@ -../ALLEGRO_o1_v03/ECalEndcaps_Turbine.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml deleted file mode 120000 index 1f39f7301..000000000 --- a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_calibration.xml +++ /dev/null @@ -1 +0,0 @@ -../ALLEGRO_o1_v03/ECalEndcaps_Turbine_calibration.xml \ No newline at end of file diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03.xml new file mode 100644 index 000000000..c7c2b6ce6 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03.xml @@ -0,0 +1,154 @@ + + + + + + Liquid argon EM calorimeter endcap design. + Electromagnetic part (EMEC) includes lead+steel absorber. + Turbine geometry. + + + + + + + + + + + + + + + + + + + + + + offset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:12,module:11,rho:8,z:8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_calibration.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_calibration.xml new file mode 100644 index 000000000..6e16b07a2 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_calibration.xml @@ -0,0 +1,148 @@ + + + + + Liquid argon EM calorimeter endcap design. + Electromagnetic part (EMEC) includes lead+steel absorber. + Turbine geometry. + + + + + + + + + + + + + + + + + + + + + + offset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:12,module:11,rho:8,z:8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_upstream.xml b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_upstream.xml new file mode 100644 index 000000000..49e120926 --- /dev/null +++ b/FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ECalEndcaps_Turbine_o1_v03_upstream.xml @@ -0,0 +1,148 @@ + + + + + Liquid argon EM calorimeter endcap design. + Electromagnetic part (EMEC) includes lead+steel absorber. + Turbine geometry. + + + + + + + + + + + + + + + + + + + + + + offset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + system:4,cryo:1,type:3,subtype:3,side:-2,wheel:3,layer:12,module:11,rho:8,z:8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FCCee/ALLEGRO/compact/README.md b/FCCee/ALLEGRO/compact/README.md index 8ea3e9a39..7a2be6cbe 100644 --- a/FCCee/ALLEGRO/compact/README.md +++ b/FCCee/ALLEGRO/compact/README.md @@ -9,9 +9,9 @@ Known caveat: the drift chamber has a larger z extent than in the IDEA detector ALLEGRO_o1_v03: with respect to v02 it features an ECal barrel with 11 layers and cell corners projective along phi. The vertex detector and drift chamber are now taken directly from IDEA_o1_v03, this effectively updates both the vertex detector (which was taken from an old CLD version) and the drift chamber (which was corresponding to IDEA_o1_v02/DriftChamber_o1_v01.xml). The z-extent of the drift chamber is now unchanged w.r.t. the IDEA detector (2 m) since it requires optimization anyway. Magnetic fields (solenoid + MDI) have been added. -Added "turbine-style" endcap ecal, and invoke this in the top-level xml (replacing the coneCyro geometry). +Added "turbine-style" endcap ecal, and invoke this in the top-level xml (replacing the coneCyro geometry). Updated to allow a more flexible geometry and calibration (details in detector/calorimeter/README.md). Added HCalBarrel_TileCal_v02.xml which uses HCalTileBarrel_o1_v02_geo.cpp and removed unused readout BarHCal_Readout_phi. Added HCalEndcaps_ThreeParts_TileCal_v02.xml which uses HCalThreePartsEndcap_o1_v02_geo.cpp. Additionally, wrt v02 the readout was migrated to the theta-phi segmentation; unused readout *Readout_phi was removed; radial dimensions of layers were modified, so the outer radius of all three cylinders is the same. For the muon tagger, switched from eta-phi to theta-phi segmentation. -ALLEGRO_o1_v04: same as v03, but material in inner part of absorber in first layer of ECAL is configurable and set by default to G10 \ No newline at end of file +ALLEGRO_o1_v04: same as v03, but material in inner part of absorber in first layer of ECAL is configurable and set by default to G10 diff --git a/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp b/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp index 3a48717cc..7687e1351 100644 --- a/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp +++ b/detector/calorimeter/ECalEndcap_Turbine_o1_v01_geo.cpp @@ -29,11 +29,6 @@ namespace det { double d = c*c*r*r/(1+c*c); return (TMath::Sqrt(d)-zp)*TMath::Sin(bladeangle); - // try approximating the arclength as dx. Less accurate, but that - // approximation is used in calculating the LAr gap, so maybe this - // will make it more consistent? - //return s*TMath::Sin(bladeangle); - } // return position of the inner edge of a blade @@ -87,10 +82,12 @@ namespace det { float BladeAngle = genericBladeElem.attr(_Unicode(angle)); bool decreaseAnglePerWheel = genericBladeElem.attr(_Unicode(decreaseAnglePerWheel)); dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Making wheel with inner, outer radii %f, %f", ri, ro); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Blade angle is %f; decrease angle per wheel? ", BladeAngle, decreaseAnglePerWheel); dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); double grmin = dim.rmin1(); dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "delZ is %f", delZ); + if (decreaseAnglePerWheel) { float tubeFracCovered = delZ/(2*grmin*TMath::Tan(BladeAngle)); BladeAngle = TMath::ATan(delZ/(2*ri*tubeFracCovered)); @@ -98,6 +95,7 @@ namespace det { if (TMath::Abs(TMath::Tan(BladeAngle)) < delZ/(2.*ri)) { dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v01", "The requested blade angle is too small for the given delZ and ri values. Please adjust to at least %f degrees!", TMath::ATan(delZ/(2.*ri))*180./TMath::Pi() ); + return; } @@ -163,8 +161,7 @@ namespace det { leftoverS = (circ - nUnitCells*delrPhiNoGap); delrPhiGapOnly = leftoverS/(2*nUnitCells); float LArgapo = delrPhiGapOnly*TMath::Sin(BladeAngle); - // LArgapo *= 2.; - + float riLayer = ri; std::vector claddingLayerVols; @@ -212,14 +209,13 @@ namespace det { AbsThicko = AbsThicki; } dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Inner and outer absorber thicknesses %f, %f ", AbsThicki, AbsThicko); + dd4hep::Solid claddingLayer = buildOneBlade(AbsThicki+GlueThick+CladdingThick, AbsThicko+GlueThick+CladdingThick, xRange, roLayer, riLayer, BladeAngle, delZ ); dd4hep::Solid glueLayer = buildOneBlade(AbsThicki+GlueThick, AbsThicko+GlueThick, xRange, roLayer, riLayer, BladeAngle, delZ ); - // dd4hep::SubtractionSolid claddingLayer(absGlueCladdingLayer, absGlueLayer); dd4hep::Solid absBladeLayer = buildOneBlade(AbsThicki, AbsThicko, xRange, roLayer, riLayer, BladeAngle, delZ ); - // dd4hep::SubtractionSolid glueLayer(absGlueLayer, absBladeLayer); dd4hep::Volume claddingLayerVol("claddingLayer", claddingLayer, aLcdd.material(claddingElem.materialStr())); if (claddingElem.isSensitive()) { claddingLayerVol.setSensitiveDetector(aSensDet); @@ -280,7 +276,6 @@ namespace det { } electrodeBladeLayerVols.push_back(electrodeBladeLayerVol); - // dd4hep::SubtractionSolid LArShapeTotalLayer(electrodeBladeAndGapLayer, electrodeBladeLayer); dd4hep::Volume LArTotalLayerVol("LArTotalLayerVol", electrodeBladeAndGapLayer, aLcdd.material(nobleLiquidElem.materialStr())); if ( nobleLiquidElem.isSensitive() ) { @@ -295,7 +290,6 @@ namespace det { dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "ECal endcap materials: nobleLiquid: %s absorber %s electrode %s", nobleLiquidElem.materialStr().c_str(), absBladeElem.materialStr().c_str(), electrodeBladeElem.materialStr().c_str() ); int nUnitCellsToDraw = nUnitCells; - // nUnitCellsToDraw = 2; dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Number of unit cells %d", nUnitCells); @@ -334,9 +328,6 @@ namespace det { glueVol_pv.addPhysVolID("subtype", 1); // 0 = absorber, 1 = glue, 2 = cladding glueVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); - // dd4hep::DetElement glueDetElem(passiveDetElem, "glue_",ECalEndCapElementCounter++); - // glueDetElem.setPlacement(glueVol_pv); - riLayer = roLayer; iLayer++; } @@ -358,9 +349,6 @@ namespace det { claddingVol_pv.addPhysVolID("subtype", 2); // 0 = absorber, 1 = glue, 2 = cladding claddingVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); - // dd4hep::DetElement claddingDetElem(passiveDetElem, "cladding_", ECalEndCapElementCounter++); - // claddingDetElem.setPlacement(claddingVol_pv); - riLayer = roLayer; iLayer++; } @@ -436,7 +424,7 @@ namespace det { riLayer = ri; float xCell = ((ro+zminri)/2.)*TMath::Cos(phi); - float yCell = ((ro+zminri)/2.)*TMath::Sin(phi); //ri*TMath::Sin(phi)/6.; + float yCell = ((ro+zminri)/2.)*TMath::Sin(phi); float zCell = 0.; dd4hep::Transform3D comCell(r3d, dd4hep::Translation3D(xCell,yCell,zCell)); @@ -451,7 +439,7 @@ namespace det { // place active volume in LAr bath xCell = ((ro+zminri)/2.)*TMath::Cos(phi+delPhi/2.); - yCell = ((ro+zminri)/2.)*TMath::Sin(phi+delPhi/2.); //ri*TMath::Sin(phi)/6.; + yCell = ((ro+zminri)/2.)*TMath::Sin(phi+delPhi/2.); zCell = 0.; dd4hep::Transform3D comCell2(r3d2, dd4hep::Translation3D(xCell,yCell,zCell)); dd4hep::PlacedVolume activePhysVol = aEnvelope.placeVolume(activeVol, comCell2); @@ -511,7 +499,9 @@ namespace det { dd4hep::Tube bathOuterShape(bathRmin, bathRmax, bathDelZ); // make it 4 volumes + 5th for detector envelope dd4hep::Tube bathAndServicesOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), caloDim.dz()); // make it 4 volumes + 5th for detector envelope + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Cryostat front thickness is %f cm", cryoDim.rmin2() / dd4hep::cm ); + if (cryoThicknessFront > 0) { // 1. Create cryostat dd4hep::Tube cryoFrontShape(cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); @@ -560,6 +550,7 @@ namespace det { std::string nobleLiquidMaterial = nobleLiquid.materialStr(); dd4hep::Volume bathVol(nobleLiquidMaterial + "_bath", bathOuterShape, aLcdd.material(nobleLiquidMaterial)); dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "ECAL endcap bath: material = %s rmin (cm) = %f rmax (cm) = %f, dz (cm) = %f, thickness in front of ECal (cm) = %f, thickness behind ECal (cm) = %f", nobleLiquidMaterial.c_str(), bathRmin, bathRmax, caloDim.dz(), caloDim.rmin() - cryoDim.rmin2(), cryoDim.rmax1() - caloDim.rmax()); + dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); // 3. Create detector structure @@ -569,6 +560,7 @@ namespace det { dd4hep::xml::DetElement supportTubeElem = calo.child(_Unicode(supportTube)); unsigned nWheels = supportTubeElem.attr(_Unicode(nWheels)); dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v01", "Will build %d wheels", nWheels); + double rmin = bathRmin; double rmax = bathRmax; float radiusRatio = pow(rmax/rmin, 1./nWheels); @@ -587,7 +579,6 @@ namespace det { } dd4hep::PlacedVolume supportTube_pv = bathVol.placeVolume(supportTubeVol, dd4hep::Position(0,0,zOffsetEnvelope + dim.dz() )); supportTube_pv.addPhysVolID("cryo", 1); - // supportTube_pv.addPhysVolID("side",sign); supportTube_pv.addPhysVolID("wheel", iWheel); dd4hep::DetElement supportTubeDetElem(bathDetElem, "supportTube_"+std::to_string(iWheel), 0); supportTubeDetElem.setPlacement(supportTube_pv); @@ -630,8 +621,7 @@ createECalEndcapTurbine(dd4hep::Detector& aLcdd, dd4hep::xml::Handle_t aXmlEleme dd4hep::Volume envelopeVol(nameDet + "_vol", endcapShape, aLcdd.material("Air")); - // dd4hep::DetElement caloPositiveDetElem(caloDetElem, "positive", 0); - // dd4hep::DetElement caloNegativeDetElem(caloDetElem, "negative", 0); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v01", "Placing detector on the positive side: (cm) %f with min, max radii %f %f",dim.z_offset(), dim.rmin1(), dim.rmax1() ); unsigned iModule = 0; buildOneSide_Turbine(aLcdd, aSensDet, envelopeVol, aXmlElement, iModule); diff --git a/detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp b/detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp index 54ef2a071..110041ad3 100644 --- a/detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp +++ b/detector/calorimeter/ECalEndcap_Turbine_o1_v02_geo.cpp @@ -1,5 +1,6 @@ #include "DD4hep/DetFactoryHelper.h" #include "DD4hep/Printout.h" + #include "TMatrixT.h" #include "XML/Utilities.h" #include @@ -8,9 +9,11 @@ #define endmsg std::endl #define lLog std::cout namespace MSG { + const std::string ERROR = " Error: "; const std::string DEBUG = " Debug: "; const std::string INFO = " Info: "; + } namespace det { @@ -86,26 +89,32 @@ namespace det { dd4hep::xml::DetElement nobleLiquidElem = genericBladeElem.child(_Unicode(nobleLiquidGap)); float BladeAngle = 0.0, AbsThickMin = 0.0, BladeThicknessScaleFactor=0.0; + int nUnitCells = -1; + // hardcode for three wheels if (iWheel == 0) { BladeAngle = genericBladeElem.attr(_Unicode(angle1)); AbsThickMin = absBladeElem.attr(_Unicode(thickness1)); BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor1)); + nUnitCells = genericBladeElem.attr(_Unicode(nUnitCells1)); } if (iWheel == 1) { BladeAngle = genericBladeElem.attr(_Unicode(angle2)); AbsThickMin = absBladeElem.attr(_Unicode(thickness2)); BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor2)); + nUnitCells = genericBladeElem.attr(_Unicode(nUnitCells2)); } if (iWheel == 2) { BladeAngle = genericBladeElem.attr(_Unicode(angle3)); AbsThickMin = absBladeElem.attr(_Unicode(thickness3)); BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor3)); + nUnitCells = genericBladeElem.attr(_Unicode(nUnitCells3)); } dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Making wheel with inner, outer radii %f, %f", ri, ro); dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Blade angle is %f ", BladeAngle); dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "delZ is %f", delZ); if (TMath::Abs(TMath::Tan(BladeAngle)) < delZ/(2.*ri)) { @@ -130,7 +139,8 @@ namespace det { bool sameNUnitCells = genericBladeElem.attr(_Unicode(sameNUnitCells)); char* nUnitCellsStrArr = (char*)genericBladeElem.attr(_Unicode(nUnitCells)).c_str(); char* nUnitCellsCStr = strtok(nUnitCellsStrArr, " "); - int nUnitCells = -1; + + if (!sameNUnitCells) { for (unsigned i = 0; i < iWheel; i++) { nUnitCellsCStr = strtok(NULL, " "); @@ -138,7 +148,6 @@ namespace det { std::string nUnitCellsStr = nUnitCellsCStr; nUnitCells = std::stoi(nUnitCellsStr); } - int nUnitCellsLeastCommonMultiple = genericBladeElem.attr(_Unicode(nUnitCellsLeastCommonMultiple)); dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "nUnitCells: %d", nUnitCells); @@ -169,7 +178,6 @@ namespace det { leftoverS = (circ - nUnitCells*delrPhiNoGap); delrPhiGapOnly = leftoverS/(2*nUnitCells); float LArgapo = delrPhiGapOnly*TMath::Sin(BladeAngle); - // LArgapo *= 2.; dd4hep::Solid absBlade; float riLayer = ri; @@ -180,13 +188,12 @@ namespace det { std::vector LArTotalLayerVols; std::vector electrodeBladeLayerVols; - dd4hep::Solid passiveShape = buildOneBlade(AbsThicki+GlueThick+CladdingThick, AbsThicko+GlueThick+CladdingThick, xRange, ro, ri, BladeAngle, delZ ); dd4hep::Volume passiveVol("passive", passiveShape, aLcdd.material("Air")); dd4hep::Solid activeShape = buildOneBlade(ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2, xRange, ro, ri, BladeAngle, delZ); dd4hep::Volume activeVol("active", activeShape, aLcdd.material("Air")); - + unsigned numNonActiveLayers = 1; // check that either all non-active volumes are set to sensitive (for // sampling fraction calculations) or none are (for normal running) @@ -220,10 +227,8 @@ namespace det { dd4hep::Solid glueLayer = buildOneBlade(AbsThicki+GlueThick, AbsThicko+GlueThick, xRange, roLayer, riLayer, BladeAngle, delZ ); - // dd4hep::SubtractionSolid claddingLayer(absGlueCladdingLayer, absGlueLayer); dd4hep::Solid absBladeLayer = buildOneBlade(AbsThicki, AbsThicko, xRange, roLayer, riLayer, BladeAngle, delZ ); - // dd4hep::SubtractionSolid glueLayer(absGlueLayer, absBladeLayer); dd4hep::Volume claddingLayerVol("claddingLayer", claddingLayer, aLcdd.material(claddingElem.materialStr())); if (claddingElem.isSensitive()) { claddingLayerVol.setSensitiveDetector(aSensDet); @@ -279,7 +284,6 @@ namespace det { } electrodeBladeLayerVols.push_back(electrodeBladeLayerVol); - // dd4hep::SubtractionSolid LArShapeTotalLayer(electrodeBladeAndGapLayer, electrodeBladeLayer); dd4hep::Volume LArTotalLayerVol("LArTotalLayerVol", electrodeBladeAndGapLayer, aLcdd.material(nobleLiquidElem.materialStr())); if ( nobleLiquidElem.isSensitive() ) { @@ -294,7 +298,6 @@ namespace det { dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECal endcap materials: nobleLiquid: %s absorber %s electrode %s", nobleLiquidElem.materialStr().c_str(), absBladeElem.materialStr().c_str(), electrodeBladeElem.materialStr().c_str() ); int nUnitCellsToDraw = nUnitCells; - // nUnitCellsToDraw = 2; dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Number of unit cells %d", nUnitCells); @@ -303,43 +306,45 @@ namespace det { unsigned iLayer = 0; riLayer = ri; - + for (auto absBladeLayerVol: absBladeLayerVols) { float roLayer = riLayer+delrNonActive; - dd4hep::Position posLayer(0,0,(riLayer-ri+roLayer-ro)/2.); + dd4hep::Position posLayer(0,0,0); dd4hep::PlacedVolume absBladeVol_pv = glueLayerVols[iLayer].placeVolume(absBladeLayerVol, posLayer); - absBladeVol_pv.addPhysVolID("subtype", 0); // 0 = absorber, 1 = glue, 2 = cladding + absBladeVol_pv.addPhysVolID("subtype", 1); // 1 = absorber, 2 = glue, 3 = cladding dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "Blade layer, rho is %d, %f, %f", iLayer, absBladeVol_pv.position().Rho(), roLayer/2.); absBladeVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "AbsBalde volume %s", absBladeVol_pv.toString().c_str()); riLayer = roLayer; iLayer++; } + riLayer = ri; iLayer =0; - + for (auto glueLayerVol: glueLayerVols) { float roLayer = riLayer+delrNonActive; - dd4hep::Position posLayer(0,0,(riLayer-ri+roLayer-ro)/2.); + // dd4hep::Position posLayer(0,0,(riLayer-ri+roLayer-ro)/2.); + dd4hep::Position posLayer(0,0,0); dd4hep::PlacedVolume glueVol_pv = claddingLayerVols[iLayer].placeVolume(glueLayerVol, posLayer); - glueVol_pv.addPhysVolID("subtype", 1); // 0 = absorber, 1 = glue, 2 = cladding + glueVol_pv.addPhysVolID("subtype", 2); // 1 = absorber, 2 = glue, 3 = cladding glueVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); - // dd4hep::DetElement glueDetElem(passiveDetElem, "glue_",ECalEndCapElementCounter++); - // glueDetElem.setPlacement(glueVol_pv); - + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "Glue volume %s", glueVol_pv.toString().c_str()); riLayer = roLayer; iLayer++; } - + + riLayer = ri; iLayer =0; @@ -354,11 +359,10 @@ namespace det { dd4hep::Position posLayer(0,0,(zminLayer-zminri+roLayer-ro)/2.); dd4hep::PlacedVolume claddingVol_pv = passiveVol.placeVolume(claddingLayerVol, posLayer); - claddingVol_pv.addPhysVolID("subtype", 2); // 0 = absorber, 1 = glue, 2 = cladding + claddingVol_pv.addPhysVolID("subtype", 3); // 1 = absorber, 2 = glue, 3 = cladding claddingVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); - // dd4hep::DetElement claddingDetElem(passiveDetElem, "cladding_", ECalEndCapElementCounter++); - // claddingDetElem.setPlacement(claddingVol_pv); + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "Cladding volume %s", claddingVol_pv.toString().c_str()); riLayer = roLayer; iLayer++; @@ -374,7 +378,9 @@ namespace det { dd4hep::PlacedVolume electrodeBladeVol_pv = LArTotalLayerVols[iLayer].placeVolume(electrodeBladeLayerVol); electrodeBladeVol_pv.addPhysVolID("layer", iWheel*numNonActiveLayers+iLayer); - + electrodeBladeVol_pv.addPhysVolID("type", 2); // 0 = active, 1 = passive, 2 = readout + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "Electrode volume %s", electrodeBladeVol_pv.toString().c_str()); riLayer = roLayer; iLayer++; } @@ -382,6 +388,8 @@ namespace det { riLayer = ri; iLayer = 0; + std::vector LArVol_pvs; + for (auto LArTotalLayerVol: LArTotalLayerVols) { float roLayer = riLayer+delrActive; @@ -391,13 +399,15 @@ namespace det { dd4hep::Position posLayer(0,0,(zminLayer-zminri+roLayer-ro)/2.); dd4hep::PlacedVolume LArVol_pv(activeVol.placeVolume(LArTotalLayerVol, posLayer)); - dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "LAr layer: %d", iLayer ); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "LAr layer: %d layer in readout: %d", iLayer, iWheel*ECalEndcapNumCalibLayers+iLayer ); LArVol_pv.addPhysVolID("layer", iWheel*ECalEndcapNumCalibLayers+iLayer); - + LArVol_pvs.push_back(LArVol_pv); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "LAr volume %s", LArVol_pv.toString().c_str()); riLayer = roLayer; iLayer++; } - + for (int iUnitCell = 0; iUnitCell < nUnitCellsToDraw; iUnitCell++) { int modIndex = iUnitCell-nUnitCellsToDraw/2; @@ -443,11 +453,12 @@ namespace det { // place passive volume in LAr bath dd4hep::PlacedVolume passivePhysVol = aEnvelope.placeVolume(passiveVol, comCell); - passivePhysVol.addPhysVolID("module", modIndex*nUnitCellsLeastCommonMultiple/nUnitCells); + passivePhysVol.addPhysVolID("module", modIndex); passivePhysVol.addPhysVolID("wheel", iWheel); passivePhysVol.addPhysVolID("type", 1); // 0 = active, 1 = passive, 2 = readout - dd4hep::DetElement passiveDetElem(bathDetElem, "passive_" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), ECalEndCapElementCounter++); - passiveDetElem.setPlacement(passivePhysVol); + dd4hep::DetElement passiveDetElem( "passive_" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), ECalEndCapElementCounter++); passiveDetElem.setPlacement(passivePhysVol); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "Passive volume %s", passivePhysVol.toString().c_str()); // place active volume in LAr bath @@ -456,13 +467,22 @@ namespace det { zCell = 0.; dd4hep::Transform3D comCell2(r3d2, dd4hep::Translation3D(xCell,yCell,zCell)); dd4hep::PlacedVolume activePhysVol = aEnvelope.placeVolume(activeVol, comCell2); - activePhysVol.addPhysVolID("module", modIndex*nUnitCellsLeastCommonMultiple/nUnitCells); + activePhysVol.addPhysVolID("module", modIndex); activePhysVol.addPhysVolID("wheel", iWheel); activePhysVol.addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout - dd4hep::DetElement activeDetElem(bathDetElem, "active_" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), ECalEndCapElementCounter++); - activeDetElem.setPlacement(activePhysVol); + dd4hep::DetElement activeDetElem(bathDetElem, "active" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), modIndex); + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02_geo", "Active volume %s", activePhysVol.toString().c_str()); + + activeDetElem.setPlacement(activePhysVol); + iLayer = 0; + for (auto LArVol_pv: LArVol_pvs) { + dd4hep::DetElement LArDetElem(activeDetElem,"layer"+std::to_string(modIndex)+"_"+std::to_string(iWheel)+"_"+std::to_string(iLayer), iLayer); + LArDetElem.setPlacement(LArVol_pv); + iLayer++; + } + riLayer = ri; iLayer =0; @@ -475,7 +495,7 @@ namespace det { } - void buildOneSide_Turbine(dd4hep::Detector& aLcdd, dd4hep::SensitiveDetector& aSensDet, + void buildOneSide_Turbine(dd4hep::Detector& aLcdd, dd4hep::DetElement& caloDetElem, dd4hep::SensitiveDetector& aSensDet, dd4hep::Volume& aEnvelope, dd4hep::xml::Handle_t& aXmlElement, unsigned& iModule) { @@ -488,37 +508,42 @@ namespace det { dd4hep::xml::DetElement xmlDetElem = aXmlElement; std::string nameDet = xmlDetElem.nameStr(); - dd4hep::DetElement caloDetElem(nameDet, xmlDetElem.id()); - + // dd4hep::DetElement caloDetElem(nameDet, xmlDetElem.id()); + dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); //build cryostat // Retrieve cryostat data dd4hep::xml::DetElement cryostat = calo.child(_Unicode(cryostat)); dd4hep::xml::Dimension cryoDim(cryostat.dimensions()); - double cryoThicknessFront = cryoDim.rmin2() - cryoDim.rmin1(); - + double cryoThicknessFront = aLcdd.constant("CryoEMECThicknessFront"); + double cryoThicknessBack = aLcdd.constant("CryoEMECThicknessBack"); + double bathThicknessFront = aLcdd.constant("BathThicknessFront"); + double bathThicknessBack = aLcdd.constant("BathThicknessBack"); + dd4hep::xml::DetElement cryoFront = cryostat.child(_Unicode(front)); dd4hep::xml::DetElement cryoBack = cryostat.child(_Unicode(back)); - dd4hep::xml::DetElement cryoSide = cryostat.child(_Unicode(side)); + dd4hep::xml::DetElement cryoInner = cryostat.child(_Unicode(inner)); + dd4hep::xml::DetElement cryoOuter = cryostat.child(_Unicode(outer)); + bool cryoFrontSensitive = cryoFront.isSensitive(); bool cryoBackSensitive = cryoBack.isSensitive(); - bool cryoSideSensitive = cryoSide.isSensitive(); - - double bathRmin = caloDim.rmin(); // - margin for inclination - double bathRmax = caloDim.rmax(); // + margin for inclination - double bathDelZ = caloDim.dz(); + bool cryoInnerSensitive = cryoInner.isSensitive(); + bool cryoOuterSensitive = cryoOuter.isSensitive(); + + double bathRmin = cryoDim.rmin2(); // - margin for inclination + double bathRmax = cryoDim.rmax1(); // + margin for inclination + double bathDelZ = cryoDim.dz(); dd4hep::Tube bathOuterShape(bathRmin, bathRmax, bathDelZ); // make it 4 volumes + 5th for detector envelope - dd4hep::Tube bathAndServicesOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), caloDim.dz()); // make it 4 volumes + 5th for detector envelope - + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat front thickness is %f", cryoDim.rmin2() ); if (cryoThicknessFront > 0) { // 1. Create cryostat - dd4hep::Tube cryoFrontShape(cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); - dd4hep::Tube cryoBackShape(cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); - dd4hep::Tube cryoSideOuterShape(cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz()); - dd4hep::SubtractionSolid cryoSideShape(cryoSideOuterShape, bathAndServicesOuterShape); + dd4hep::Tube cryoFrontShape(cryoDim.rmin1(), cryoDim.rmax2(), cryoThicknessFront/2.); + dd4hep::Tube cryoBackShape(cryoDim.rmin2(), cryoDim.rmax2(), cryoThicknessBack/2.); + dd4hep::Tube cryoInnerShape(cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); + dd4hep::Tube cryoOuterShape(cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL endcap cryostat: front: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f ", cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL encdap cryostat: back: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL endcap cryostat: side: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz() - caloDim.dz()); @@ -526,10 +551,15 @@ namespace det { dd4hep::Volume cryoFrontVol(cryostat.nameStr()+"_front", cryoFrontShape, aLcdd.material(cryostat.materialStr())); dd4hep::Volume cryoBackVol(cryostat.nameStr()+"_back", cryoBackShape, aLcdd.material(cryostat.materialStr())); - dd4hep::Volume cryoSideVol(cryostat.nameStr()+"_side", cryoSideShape, aLcdd.material(cryostat.materialStr())); - dd4hep::PlacedVolume cryoFrontPhysVol = aEnvelope.placeVolume(cryoFrontVol); - dd4hep::PlacedVolume cryoBackPhysVol = aEnvelope.placeVolume(cryoBackVol); - dd4hep::PlacedVolume cryoSidePhysVol = aEnvelope.placeVolume(cryoSideVol); + dd4hep::Volume cryoInnerVol(cryostat.nameStr()+"_inner", cryoInnerShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoOuterVol(cryostat.nameStr()+"_outer", cryoOuterShape, aLcdd.material(cryostat.materialStr())); + + dd4hep::Position cryoFrontPos(0,0,-cryoDim.dz()); + dd4hep::PlacedVolume cryoFrontPhysVol = aEnvelope.placeVolume(cryoFrontVol, cryoFrontPos); + dd4hep::Position cryoBackPos(0,0,cryoDim.dz()); + dd4hep::PlacedVolume cryoBackPhysVol = aEnvelope.placeVolume(cryoBackVol, cryoBackPos); + dd4hep::PlacedVolume cryoInnerPhysVol = aEnvelope.placeVolume(cryoInnerVol); + dd4hep::PlacedVolume cryoOuterPhysVol = aEnvelope.placeVolume(cryoOuterVol); unsigned sidetype = 0x4; // probably not needed anymore... if (cryoFrontSensitive) { cryoFrontVol.setSensitiveDetector(aSensDet); @@ -543,26 +573,41 @@ namespace det { cryoBackPhysVol.addPhysVolID("type", sidetype+2); dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat back volume set as sensitive" ); } - if (cryoSideSensitive) { - cryoSideVol.setSensitiveDetector(aSensDet); - cryoSidePhysVol.addPhysVolID("cryo", 1); - cryoSidePhysVol.addPhysVolID("type", sidetype+3); - dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat side volume set as sensitive" ); + if (cryoInnerSensitive) { + cryoInnerVol.setSensitiveDetector(aSensDet); + cryoInnerPhysVol.addPhysVolID("cryo", 1); + cryoInnerPhysVol.addPhysVolID("type", sidetype+3); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat inner volume set as sensitive" ); } + if (cryoOuterSensitive) { + cryoOuterVol.setSensitiveDetector(aSensDet); + cryoOuterPhysVol.addPhysVolID("cryo", 1); + cryoOuterPhysVol.addPhysVolID("type", sidetype+4); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "Cryostat outer volume set as sensitive" ); + } dd4hep::DetElement cryoFrontDetElem(caloDetElem, "cryo_front", 0); cryoFrontDetElem.setPlacement(cryoFrontPhysVol); dd4hep::DetElement cryoBackDetElem(caloDetElem, "cryo_back", 0); cryoBackDetElem.setPlacement(cryoBackPhysVol); - dd4hep::DetElement cryoSideDetElem(caloDetElem, "cryo_side", 0); - cryoSideDetElem.setPlacement(cryoSidePhysVol); + dd4hep::DetElement cryoInnerDetElem(caloDetElem, "cryo_inner", 0); + cryoInnerDetElem.setPlacement(cryoInnerPhysVol); + dd4hep::DetElement cryoOuterDetElem(caloDetElem, "cryo_outer", 0); + cryoOuterDetElem.setPlacement(cryoOuterPhysVol); } // 2. Create noble liquid bath std::string nobleLiquidMaterial = nobleLiquid.materialStr(); dd4hep::Volume bathVol(nobleLiquidMaterial + "_bath", bathOuterShape, aLcdd.material(nobleLiquidMaterial)); dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v02", "ECAL endcap bath: material = %s rmin (cm) = %f rmax (cm) = %f, dz (cm) = %f, thickness in front of ECal (cm) = %f, thickness behind ECal (cm) = %f", nobleLiquidMaterial.c_str(), bathRmin, bathRmax, caloDim.dz(), caloDim.rmin() - cryoDim.rmin2(), cryoDim.rmax1() - caloDim.rmax()); + + dd4hep::Position bathPos(0,0,(cryoThicknessFront-cryoThicknessBack)/2.); + + dd4hep::PlacedVolume bathPhysVol = aEnvelope.placeVolume(bathVol, bathPos); + dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); + bathDetElem.setPlacement(bathPhysVol); + // 3. Create detector structure double length = dim.dz() * 2.; double zOffsetEnvelope = -length / 2.; @@ -579,6 +624,7 @@ namespace det { float supportTubeThickness=supportTubeElem.thickness(); unsigned iSupportTube = 0; + for (unsigned iWheel = 0; iWheel < nWheels; iWheel++) { dd4hep::Tube supportTube(ro, ro+supportTubeThickness, bathDelZ ); @@ -589,13 +635,12 @@ namespace det { } dd4hep::PlacedVolume supportTube_pv = bathVol.placeVolume(supportTubeVol, dd4hep::Position(0,0,zOffsetEnvelope + dim.dz() )); supportTube_pv.addPhysVolID("cryo", 1); - // supportTube_pv.addPhysVolID("side",sign); supportTube_pv.addPhysVolID("wheel", iWheel); dd4hep::DetElement supportTubeDetElem(bathDetElem, "supportTube_"+std::to_string(iWheel), 0); supportTubeDetElem.setPlacement(supportTube_pv); - buildWheel(aLcdd, aSensDet, bathVol, aXmlElement, bathDetElem, ri+supportTubeThickness, ro, bathDelZ*2, iWheel); + buildWheel(aLcdd, aSensDet, bathVol, aXmlElement, bathDetElem, ri+supportTubeThickness, ro, bathDelZ*2-bathThicknessFront-bathThicknessBack, iWheel); ri = ro; ro *= radiusRatio; if (ro > rmax) ro = rmax; @@ -603,9 +648,6 @@ namespace det { } - dd4hep::PlacedVolume bathPhysVol = aEnvelope.placeVolume(bathVol); - bathDetElem.setPlacement(bathPhysVol); - dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Total number of modules: %d", iModule); @@ -634,13 +676,10 @@ namespace det { dd4hep::Volume envelopeVol(nameDet + "_vol", endcapShape, aLcdd.material("Air")); - // dd4hep::DetElement caloPositiveDetElem(caloDetElem, "positive", 0); - // dd4hep::DetElement caloNegativeDetElem(caloDetElem, "negative", 0); - dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v02", "Placing detector on the positive side: (cm) %f with min, max radii %f %f",dim.z_offset(), dim.rmin1(), dim.rmax1() ); unsigned iModule = 0; - buildOneSide_Turbine(aLcdd, aSensDet, envelopeVol, aXmlElement, iModule); + buildOneSide_Turbine(aLcdd, caloDetElem, aSensDet, envelopeVol, aXmlElement, iModule); dd4hep::Assembly endcapsAssembly("ECalEndcaps_turbine"); @@ -649,18 +688,12 @@ namespace det { dd4hep::PlacedVolume envelopePositivePhysVol = endcapsAssembly.placeVolume(envelopeVol, envelopePositiveVolume_tr); envelopePositivePhysVol.addPhysVolID("side", 1); - dd4hep::DetElement caloPositiveDetElem(caloDetElem, "positive", 0); - caloPositiveDetElem.setPlacement(envelopePositivePhysVol); - // make another placement for the negative z endcap dd4hep::Transform3D envelopeNegativeVolume_tr(dd4hep::RotationZYX( 0 ,0,180*dd4hep::deg), dd4hep::Translation3D(0, 0, -dim.z_offset())); dd4hep::PlacedVolume envelopeNegativePhysVol = endcapsAssembly.placeVolume(envelopeVol, envelopeNegativeVolume_tr); envelopeNegativePhysVol.addPhysVolID("side", -1); - dd4hep::DetElement caloNegativeDetElem(caloDetElem, "negative", 0); - caloNegativeDetElem.setPlacement(envelopeNegativePhysVol); - dd4hep::Volume motherVol = aLcdd.pickMotherVolume(caloDetElem); dd4hep::PlacedVolume envelopePhysVol = motherVol.placeVolume(endcapsAssembly); caloDetElem.setPlacement(envelopePhysVol); diff --git a/detector/calorimeter/ECalEndcap_Turbine_o1_v03_geo.cpp b/detector/calorimeter/ECalEndcap_Turbine_o1_v03_geo.cpp new file mode 100644 index 000000000..86a36d2ca --- /dev/null +++ b/detector/calorimeter/ECalEndcap_Turbine_o1_v03_geo.cpp @@ -0,0 +1,784 @@ +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "TMatrixT.h" + +// todo: remove gaudi logging and properly capture output +#define endmsg std::endl +#define lLog std::cout +namespace MSG { + const std::string ERROR = " Error: "; + const std::string DEBUG = " Debug: "; + const std::string INFO = " Info: "; +} + +namespace det { + + namespace ECalEndcap_Turbine_o1_v03 { + unsigned ECalEndCapElementCounter = 0; + const unsigned nWheels = 3; + + unsigned ECalEndcapNumCalibRhoLayersArr[nWheels], ECalEndcapNumCalibZLayersArr[nWheels]; + + + double tForArcLength(double s, double bladeangle, double delZ, double r) { + + // some intermediate constants + double zpos = delZ/2.; + double zp = zpos/TMath::Tan(bladeangle); + double b = zp/(TMath::Sqrt(r*r-zp*zp)); + double c = (TMath::Tan(s/r) +b)/(1.-b*TMath::Tan(s/r)); + double d = c*c*r*r/(1+c*c); + return (TMath::Sqrt(d)-zp)*TMath::Sin(bladeangle); + + + } + + // return position of the inner edge of a blade + double getZmin(double r, double bladeangle, double delZ) { + // r: distance from the beamline + // bladeangle: angle of turbine blades wrt xy plane, in radians + // delZ: z extent of the blades + return TMath::Sqrt(r*r - ((delZ/2)/TMath::Tan(bladeangle))*((delZ/2)/TMath::Tan(bladeangle))); + } + + dd4hep::Solid buildOneBlade(double thickness_inner, + double thickness_outer, + double width, + double ro, double ri, + double bladeangle, + double delZ, + double zStart) + { + + dd4hep::Solid shapeBeforeSubtraction; + + // set max and min extent of the blade (along the z axis in the body frame) + double zmax = ro; + double zmin = getZmin(ri, bladeangle, delZ); + + dd4hep::Trd2 tmp1(thickness_inner/2., thickness_outer/2., width/2., width/2., (zmax-zmin)/2. ); + shapeBeforeSubtraction = tmp1; + + dd4hep::Tube allowedTube(ri, ro, delZ); + + return dd4hep::IntersectionSolid (shapeBeforeSubtraction, allowedTube, dd4hep::Transform3D(dd4hep::RotationZYX( 0, TMath::Pi()/2.-bladeangle, TMath::Pi()/2.),dd4hep::Position(0,-zStart, -(zmin+zmax)/2.))); + + } + + void buildWheel(dd4hep::Detector& aLcdd, + dd4hep::SensitiveDetector& aSensDet, + dd4hep::Volume& aEnvelope, + dd4hep::xml::Handle_t& aXmlElement, + dd4hep::DetElement& bathDetElem, + float ri, float ro, float delZ, float offsetZ, + unsigned iWheel) { + + + dd4hep::xml::DetElement calorimeterElem = aXmlElement.child(_Unicode(calorimeter)); + dd4hep::xml::DetElement genericBladeElem = calorimeterElem.child(_Unicode(turbineBlade)); + dd4hep::xml::DetElement absBladeElem = genericBladeElem.child(_Unicode(absorberBlade)); + dd4hep::xml::DetElement claddingElem = genericBladeElem.child(_Unicode(cladding)); + dd4hep::xml::DetElement glueElem = genericBladeElem.child(_Unicode(glue)); + dd4hep::xml::DetElement electrodeBladeElem = genericBladeElem.child(_Unicode(electrodeBlade)); + dd4hep::xml::DetElement nobleLiquidElem = genericBladeElem.child(_Unicode(nobleLiquidGap)); + + float BladeAngle = 0.0, AbsThickMin = 0.0, BladeThicknessScaleFactor=0.0; + unsigned nUnitCells = 0; + // hardcode for three wheels + unsigned ECalEndcapNumCalibRhoLayers = ECalEndcapNumCalibRhoLayersArr[iWheel], ECalEndcapNumCalibZLayers=ECalEndcapNumCalibZLayersArr[iWheel]; + + unsigned LayerIndexBaseline = 0; + + if (iWheel == 0) { + BladeAngle = genericBladeElem.attr(_Unicode(angle1)); + AbsThickMin = absBladeElem.attr(_Unicode(thickness1)); + BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor1)); + + nUnitCells = genericBladeElem.attr(_Unicode(nUnitCells1)); + } + if (iWheel == 1) { + BladeAngle = genericBladeElem.attr(_Unicode(angle2)); + AbsThickMin = absBladeElem.attr(_Unicode(thickness2)); + BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor2)); + nUnitCells = genericBladeElem.attr(_Unicode(nUnitCells2)); + LayerIndexBaseline = ECalEndcapNumCalibRhoLayersArr[0]*ECalEndcapNumCalibZLayersArr[0]; + } + if (iWheel == 2) { + BladeAngle = genericBladeElem.attr(_Unicode(angle3)); + AbsThickMin = absBladeElem.attr(_Unicode(thickness3)); + BladeThicknessScaleFactor = absBladeElem.attr(_Unicode(thicknessScaleFactor3)); + nUnitCells = genericBladeElem.attr(_Unicode(nUnitCells3)); + LayerIndexBaseline = ECalEndcapNumCalibRhoLayersArr[0]*ECalEndcapNumCalibZLayersArr[0] + ECalEndcapNumCalibRhoLayersArr[1]*ECalEndcapNumCalibZLayersArr[1]; + } + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "Making wheel with inner, outer radii %f, %f", ri, ro); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "Blade angle is %f ", BladeAngle); + dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "delZ is %f", delZ); + + if (TMath::Abs(TMath::Tan(BladeAngle)) < delZ/(2.*ri)) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "The requested blade angle is too small for the given delZ and ri values. Please adjust to at least %f degrees!", TMath::ATan(delZ/(2.*ri))*180./TMath::Pi() ); + return; + } + + Float_t xRange = delZ/(TMath::Sin(BladeAngle)); + + double delrPhiNoGap; + + float GlueThick = glueElem.attr(_Unicode(thickness)); + + float CladdingThick = claddingElem.attr(_Unicode(thickness)); + + AbsThickMin = AbsThickMin-(GlueThick+CladdingThick); + if (AbsThickMin < 0.) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Error: requested absorber thickness is negative after accounting for glue and cladding thickness"); + } + float ElectrodeThick = electrodeBladeElem.attr(_Unicode(thickness)); + float LArgapi = nobleLiquidElem.attr(_Unicode(gap)); + + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "nUnitCells: %d", nUnitCells); + + float AbsThicki = AbsThickMin; + // make volumes for the noble liquid, electrode, and absorber blades + float AbsThicko; + AbsThicko = AbsThicki + BladeThicknessScaleFactor*((ro/ri)-1.)*AbsThicki; + + // Calculate gap thickness at inner layer + double circ = 2*TMath::Pi()*ri; + double x2 =(AbsThickMin+(GlueThick+CladdingThick)+ElectrodeThick)/TMath::Sin(BladeAngle); + double y2 = TMath::Sqrt(ri*ri-x2*x2); + double rPhi1 = ri*TMath::Pi()/2.; + double rPhi2 = ri*TMath::ATan(y2/x2); + delrPhiNoGap = TMath::Abs(rPhi1-rPhi2); + double leftoverS = (circ - nUnitCells*delrPhiNoGap); + double delrPhiGapOnly = leftoverS/(2*nUnitCells); + LArgapi = delrPhiGapOnly*TMath::Sin(BladeAngle); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "LArGap at inner radius is %f", LArgapi); + + // now find gap at outer radius + circ = 2*TMath::Pi()*ro; + x2 = (AbsThicko+GlueThick+CladdingThick+ElectrodeThick)/TMath::Sin(BladeAngle); + y2 = TMath::Sqrt(ro*ro-x2*x2); + rPhi1 = ro*TMath::Pi()/2.; + rPhi2 = ro*TMath::ATan(y2/x2); + delrPhiNoGap = TMath::Abs(rPhi1-rPhi2); + leftoverS = (circ - nUnitCells*delrPhiNoGap); + delrPhiGapOnly = leftoverS/(2*nUnitCells); + float LArgapo = delrPhiGapOnly*TMath::Sin(BladeAngle); + // LArgapo *= 2.; + + dd4hep::Solid absBlade; + float riLayer = ri; + + std::vector claddingLayerVols; + std::vector glueLayerVols; + std::vector absBladeLayerVols; + std::vector LArTotalLayerVols; + std::vector electrodeBladeLayerVols; + + + dd4hep::Solid passiveShape = buildOneBlade(AbsThicki+GlueThick+CladdingThick, AbsThicko+GlueThick+CladdingThick, xRange, ro, ri, BladeAngle, delZ, 0 ); + dd4hep::Volume passiveVol("passive", passiveShape, aLcdd.material("Air")); + + dd4hep::Solid activeShape = buildOneBlade(ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2, xRange, ro, ri, BladeAngle, delZ, 0); + dd4hep::Volume activeVol("active", activeShape, aLcdd.material("Air")); + + unsigned numNonActiveRhoLayers = 1; + unsigned numNonActiveZLayers = 1; + + // check that either all non-active volumes are set to sensitive (for + // sampling fraction calculations) or none are (for normal running) + bool allNonActiveSensitive = ( claddingElem.isSensitive() && + glueElem.isSensitive() && + absBladeElem.isSensitive() && + electrodeBladeElem.isSensitive() ); + bool allNonActiveNotSensitive = ( !claddingElem.isSensitive() && + !glueElem.isSensitive() && + !absBladeElem.isSensitive() && + !electrodeBladeElem.isSensitive() ); + if (allNonActiveSensitive) { + numNonActiveRhoLayers = ECalEndcapNumCalibRhoLayers; + numNonActiveZLayers = ECalEndcapNumCalibZLayers; + } + else if (!allNonActiveNotSensitive) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Some non-active layers are sensitive and others are not -- this is likely a misconfiguration"); + } + + float delrNonActive = (ro-ri)/numNonActiveRhoLayers; + float delrActive = (ro-ri)/ECalEndcapNumCalibRhoLayers; + + for (unsigned iRhoLayer = 0; iRhoLayer < numNonActiveRhoLayers; iRhoLayer++) { + float roLayer = riLayer + delrNonActive; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Making layer with inner, outer radii %f, %f", riLayer, roLayer); + + AbsThicko = AbsThicki + BladeThicknessScaleFactor*((roLayer/riLayer)-1.)*AbsThicki; + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "Inner and outer absorber thicknesses %f, %f ", AbsThicki, AbsThicko); + + float zStart = -xRange/2. + xRange/(2.*numNonActiveZLayers); + + for (unsigned iZLayer = 0; iZLayer < numNonActiveZLayers; iZLayer++) { + + dd4hep::Solid claddingLayer = buildOneBlade(AbsThicki+GlueThick+CladdingThick, AbsThicko+GlueThick+CladdingThick, xRange/numNonActiveZLayers, roLayer, riLayer, BladeAngle, delZ, zStart ); + + dd4hep::Solid glueLayer = buildOneBlade(AbsThicki+GlueThick, AbsThicko+GlueThick, xRange/numNonActiveZLayers, roLayer, riLayer, BladeAngle, delZ, zStart ); + + dd4hep::Solid absBladeLayer = buildOneBlade(AbsThicki, AbsThicko, xRange/numNonActiveZLayers, roLayer, riLayer, BladeAngle, delZ, zStart ); + + dd4hep::Volume claddingLayerVol("claddingLayer", claddingLayer, aLcdd.material(claddingElem.materialStr())); + if (claddingElem.isSensitive()) { + claddingLayerVol.setSensitiveDetector(aSensDet); + } + claddingLayerVols.push_back(claddingLayerVol); + + dd4hep::Volume glueLayerVol("glueLayer", glueLayer, aLcdd.material(glueElem.materialStr())); + if (glueElem.isSensitive()) { + glueLayerVol.setSensitiveDetector(aSensDet); + } + glueLayerVols.push_back(glueLayerVol); + + dd4hep::Volume absBladeLayerVol("absBladeLayer", absBladeLayer, aLcdd.material(absBladeElem.materialStr())); + if (absBladeElem.isSensitive()) { + absBladeLayerVol.setSensitiveDetector(aSensDet); + } + absBladeLayerVols.push_back(absBladeLayerVol); + + zStart+=xRange/numNonActiveZLayers; + } + riLayer = roLayer; + AbsThicki = AbsThicko; + + } + + + riLayer = ri; + + AbsThicki = AbsThickMin; + + + for (unsigned iRhoLayer = 0; iRhoLayer < ECalEndcapNumCalibRhoLayers; iRhoLayer++) { + + float roLayer = riLayer + delrActive; + + AbsThicko = AbsThicki + BladeThicknessScaleFactor*((roLayer/riLayer)-1.)*AbsThicki; + + // now find gap at outer layer + circ = 2*TMath::Pi()*roLayer; + x2 = (AbsThicko+GlueThick+CladdingThick+ElectrodeThick)/TMath::Sin(BladeAngle); + y2 = TMath::Sqrt(roLayer*roLayer-x2*x2); + rPhi1 = roLayer*TMath::Pi()/2.; + rPhi2 = roLayer*TMath::ATan(y2/x2); + delrPhiNoGap = TMath::Abs(rPhi1-rPhi2); + leftoverS = (circ - nUnitCells*delrPhiNoGap); + delrPhiGapOnly = leftoverS/(2*nUnitCells); + LArgapo = delrPhiGapOnly*TMath::Sin(BladeAngle); + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "Outer LAr gap is %f", LArgapo) ; + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Inner and outer thicknesses of noble liquid volume %f, %f", ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2); + + float zStart = -xRange/2. + xRange/(2.*ECalEndcapNumCalibZLayers); + + for (unsigned iZLayer = 0; iZLayer < ECalEndcapNumCalibZLayers; iZLayer++) { + + dd4hep::Solid electrodeBladeAndGapLayer = buildOneBlade(ElectrodeThick+LArgapi*2, ElectrodeThick+LArgapo*2, xRange/ECalEndcapNumCalibZLayers, roLayer, riLayer, BladeAngle, delZ, zStart); + + dd4hep::Solid electrodeBladeLayer = buildOneBlade(ElectrodeThick, ElectrodeThick, xRange/ECalEndcapNumCalibZLayers, roLayer, riLayer, BladeAngle, delZ, zStart); + + dd4hep::Volume electrodeBladeLayerVol("electrodeBladeLayer", electrodeBladeLayer, aLcdd.material(electrodeBladeElem.materialStr())); + if (electrodeBladeElem.isSensitive()) { + electrodeBladeLayerVol.setSensitiveDetector(aSensDet); + } + electrodeBladeLayerVols.push_back(electrodeBladeLayerVol); + + dd4hep::Volume LArTotalLayerVol("LArTotalLayerVol", electrodeBladeAndGapLayer, aLcdd.material(nobleLiquidElem.materialStr())); + + if ( nobleLiquidElem.isSensitive() ) { + LArTotalLayerVol.setSensitiveDetector(aSensDet); + } + LArTotalLayerVols.push_back(LArTotalLayerVol); + + zStart += xRange/ECalEndcapNumCalibZLayers; + } + riLayer = roLayer; + LArgapi = LArgapo; + AbsThicki = AbsThicko; + + } + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "ECal endcap materials: nobleLiquid: %s absorber %s electrode %s", nobleLiquidElem.materialStr().c_str(), absBladeElem.materialStr().c_str(), electrodeBladeElem.materialStr().c_str() ); + + int nUnitCellsToDraw = nUnitCells; + + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Number of unit cells %d", nUnitCells); + + // place all components of the absorber blade inside passive volume + + unsigned iLayer = 0; + + riLayer = ri; + + double xOffset = -xRange/2 + xRange/(2*numNonActiveZLayers); + + for (auto absBladeLayerVol: absBladeLayerVols) { + + float roLayer = riLayer+delrNonActive; + + dd4hep::Position posLayer(0,0,0); + xOffset += xRange/numNonActiveZLayers; + dd4hep::PlacedVolume absBladeVol_pv = glueLayerVols[iLayer].placeVolume(absBladeLayerVol, posLayer); + + absBladeVol_pv.addPhysVolID("subtype", 1); // 1 = absorber, 2 = glue, 3 = cladding + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "Blade layer, rho is %d, %f, %f", iLayer, absBladeVol_pv.position().Rho(), roLayer/2.); + absBladeVol_pv.addPhysVolID("layer", LayerIndexBaseline+iLayer); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "AbsBalde volume %s", absBladeVol_pv.toString().c_str()); + + + iLayer++; + if (iLayer % numNonActiveZLayers ==0) { + riLayer = roLayer; + xOffset = -xRange/2 + xRange/(2*numNonActiveZLayers); + } + } + + + riLayer = ri; + iLayer =0; + + xOffset = -xRange/2 + xRange/(2*numNonActiveZLayers); + + for (auto glueLayerVol: glueLayerVols) { + + float roLayer = riLayer+delrNonActive; + + dd4hep::Position posLayer(0,xOffset/2.,0); + dd4hep::PlacedVolume glueVol_pv = claddingLayerVols[iLayer].placeVolume(glueLayerVol, posLayer); + xOffset += xRange/numNonActiveZLayers; + + glueVol_pv.addPhysVolID("subtype", 2); // 1 = absorber, 2 = glue, 3 = cladding + glueVol_pv.addPhysVolID("layer", LayerIndexBaseline+iLayer); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "Glue volume %s", glueVol_pv.toString().c_str()); + + iLayer++; + if (iLayer % numNonActiveZLayers ==0) { + riLayer = roLayer; + xOffset = -xRange/2 + xRange/(2*numNonActiveZLayers); + } + } + + + riLayer = ri; + iLayer =0; + + double zminri = getZmin(ri, BladeAngle, delZ); + + xOffset = -xRange/2 + xRange/(2*numNonActiveZLayers); + + for (auto claddingLayerVol: claddingLayerVols) { + + float roLayer = riLayer+delrNonActive; + + double zminLayer = getZmin(riLayer, BladeAngle, delZ); + + dd4hep::Position posLayer(0,xOffset/2.,(zminLayer-zminri+roLayer-ro)/2.); + xOffset += xRange/numNonActiveZLayers; + dd4hep::PlacedVolume claddingVol_pv = passiveVol.placeVolume(claddingLayerVol, posLayer); + + claddingVol_pv.addPhysVolID("subtype", 3); // 1 = absorber, 2 = glue, 3 = cladding + claddingVol_pv.addPhysVolID("layer", LayerIndexBaseline+iLayer); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "Cladding volume %s", claddingVol_pv.toString().c_str()); + + iLayer++; + if (iLayer % numNonActiveZLayers ==0) { + riLayer = roLayer; + xOffset = -xRange/2 + xRange/(2*numNonActiveZLayers); + } + + } + + + riLayer = ri; + iLayer = 0; + + xOffset = -xRange/2 + xRange/(2*ECalEndcapNumCalibZLayers); + + for (auto electrodeBladeLayerVol: electrodeBladeLayerVols) { + + float roLayer = riLayer+delrActive; + dd4hep::Position posLayer(0,0,0); + + dd4hep::PlacedVolume electrodeBladeVol_pv = LArTotalLayerVols[iLayer].placeVolume(electrodeBladeLayerVol, posLayer); + xOffset += xRange/ECalEndcapNumCalibZLayers; + electrodeBladeVol_pv.addPhysVolID("layer", LayerIndexBaseline+iLayer); + electrodeBladeVol_pv.addPhysVolID("type", 2); // 0 = active, 1 = passive, 2 = readout + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "Electrode volume %s", electrodeBladeVol_pv.toString().c_str()); + + iLayer++; + if (iLayer % ECalEndcapNumCalibZLayers ==0) { + riLayer = roLayer; + xOffset = -xRange/2 + xRange/(2*ECalEndcapNumCalibZLayers); + } + } + + riLayer = ri; + iLayer = 0; + + std::vector LArVol_pvs; + + xOffset = -xRange/2 + xRange/(2*ECalEndcapNumCalibZLayers); + + for (auto LArTotalLayerVol: LArTotalLayerVols) { + + float roLayer = riLayer+delrActive; + + double zminLayer = getZmin(riLayer, BladeAngle, delZ); + + dd4hep::Position posLayer(0,xOffset,(zminLayer-zminri+roLayer-ro)/2.); + + dd4hep::PlacedVolume LArVol_pv(activeVol.placeVolume(LArTotalLayerVol, posLayer)); + xOffset += xRange/ECalEndcapNumCalibZLayers; + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "LAr layer: %d layer in readout: %d", iLayer, LayerIndexBaseline+iLayer ); + LArVol_pv.addPhysVolID("layer", LayerIndexBaseline+iLayer); + LArVol_pvs.push_back(LArVol_pv); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "LAr volume %s", LArVol_pv.toString().c_str()); + + iLayer++; + if (iLayer % ECalEndcapNumCalibZLayers ==0) { + riLayer = roLayer; + xOffset = -xRange/2 + xRange/(2*ECalEndcapNumCalibZLayers); + } + + } + + for (int iUnitCell = 0; iUnitCell < nUnitCellsToDraw; iUnitCell++) { + + int modIndex = iUnitCell-nUnitCellsToDraw/2; + if (modIndex < 0) modIndex += nUnitCells; + float phi = (iUnitCell-nUnitCellsToDraw/2)*2*TMath::Pi()/nUnitCells; + float delPhi = 2*TMath::Pi()/nUnitCells; + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "Placing blade, ro, ri = %f %f", ro, ri); + + TGeoRotation tgr; + tgr.RotateZ(BladeAngle*180/TMath::Pi()); + tgr.RotateX(-phi*180/TMath::Pi()); + tgr.RotateY(90); + + const Double_t *rotMatPtr; + + rotMatPtr = tgr.GetRotationMatrix(); + TMatrixT rotMat(3,3, rotMatPtr); + dd4hep::Rotation3D r3d; + r3d.SetComponents(rotMat(0,0), rotMat(0,1), rotMat(0,2), + rotMat(1,0), rotMat(1,1), rotMat(1,2), + rotMat(2,0), rotMat(2,1), rotMat(2,2)); + + tgr.Clear(); + tgr.RotateZ(BladeAngle*180/TMath::Pi()); + tgr.RotateX(-(phi+delPhi/2.)*180/TMath::Pi()); + tgr.RotateY(90); + + rotMatPtr = tgr.GetRotationMatrix(); + TMatrixT rotMat2(3,3, rotMatPtr); + dd4hep::Rotation3D r3d2; + r3d2.SetComponents(rotMat2(0,0), rotMat2(0,1), rotMat2(0,2), + rotMat2(1,0), rotMat2(1,1), rotMat2(1,2), + rotMat2(2,0), rotMat2(2,1), rotMat2(2,2)); + + riLayer = ri; + + float xCell = ((ro+zminri)/2.)*TMath::Cos(phi); + float yCell = ((ro+zminri)/2.)*TMath::Sin(phi); //ri*TMath::Sin(phi)/6.; + float zCell = offsetZ; + + dd4hep::Transform3D comCell(r3d, dd4hep::Translation3D(xCell,yCell,zCell)); + + // place passive volume in LAr bath + dd4hep::PlacedVolume passivePhysVol = aEnvelope.placeVolume(passiveVol, comCell); + passivePhysVol.addPhysVolID("module", modIndex); + passivePhysVol.addPhysVolID("wheel", iWheel); + passivePhysVol.addPhysVolID("type", 1); // 0 = active, 1 = passive, 2 = readout + dd4hep::DetElement passiveDetElem( "passive_" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), ECalEndCapElementCounter++); passiveDetElem.setPlacement(passivePhysVol); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "Passive volume %s", passivePhysVol.toString().c_str()); + + // place active volume in LAr bath + + xCell = ((ro+zminri)/2.)*TMath::Cos(phi+delPhi/2.); + yCell = ((ro+zminri)/2.)*TMath::Sin(phi+delPhi/2.); //ri*TMath::Sin(phi)/6.; + zCell = offsetZ; + dd4hep::Transform3D comCell2(r3d2, dd4hep::Translation3D(xCell,yCell,zCell)); + dd4hep::PlacedVolume activePhysVol = aEnvelope.placeVolume(activeVol, comCell2); + activePhysVol.addPhysVolID("module", modIndex); + activePhysVol.addPhysVolID("wheel", iWheel); + activePhysVol.addPhysVolID("type", 0); // 0 = active, 1 = passive, 2 = readout + + dd4hep::DetElement activeDetElem(bathDetElem, "active" + std::to_string(iUnitCell)+"_"+std::to_string(iWheel), modIndex); + + dd4hep::printout( dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03_geo", "Active volume %s", activePhysVol.toString().c_str()); + + activeDetElem.setPlacement(activePhysVol); + iLayer = 0; + for (auto LArVol_pv: LArVol_pvs) { + dd4hep::DetElement LArDetElem(activeDetElem,"layer"+std::to_string(modIndex)+"_"+std::to_string(iWheel)+"_"+std::to_string(iLayer), iLayer); + LArDetElem.setPlacement(LArVol_pv); + iLayer++; + } + + riLayer = ri; + iLayer =0; + + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "LArTotalLayerVols.size = %d", LArTotalLayerVols.size()); + + } + + return; + + } + + void buildOneSide_Turbine(dd4hep::Detector& aLcdd, dd4hep::DetElement& caloDetElem, dd4hep::SensitiveDetector& aSensDet, + dd4hep::Volume& aEnvelope, dd4hep::xml::Handle_t& aXmlElement, + unsigned& iModule) { + + dd4hep::xml::DetElement calo = aXmlElement.child(_Unicode(calorimeter)); + dd4hep::xml::Dimension caloDim(calo.dimensions()); + + + dd4hep::xml::DetElement blade = calo.child(_Unicode(turbineBlade)); + dd4hep::xml::DetElement nobleLiquid = blade.child(_Unicode(nobleLiquidGap)); + + dd4hep::xml::DetElement xmlDetElem = aXmlElement; + std::string nameDet = xmlDetElem.nameStr(); + + dd4hep::xml::Dimension dim(aXmlElement.child(_Unicode(dimensions))); + + //build cryostat + // Retrieve cryostat data + dd4hep::xml::DetElement cryostat = calo.child(_Unicode(cryostat)); + dd4hep::xml::Dimension cryoDim(cryostat.dimensions()); + double cryoThicknessFront = aLcdd.constant("CryoEMECThicknessFront"); + double cryoThicknessBack = aLcdd.constant("CryoEMECThicknessBack"); + double bathThicknessFront = aLcdd.constant("BathThicknessFront"); + double bathThicknessBack = aLcdd.constant("BathThicknessBack"); + + dd4hep::xml::DetElement cryoFront = cryostat.child(_Unicode(front)); + dd4hep::xml::DetElement cryoBack = cryostat.child(_Unicode(back)); + dd4hep::xml::DetElement cryoInner = cryostat.child(_Unicode(inner)); + dd4hep::xml::DetElement cryoOuter = cryostat.child(_Unicode(outer)); + + bool cryoFrontSensitive = cryoFront.isSensitive(); + bool cryoBackSensitive = cryoBack.isSensitive(); + bool cryoInnerSensitive = cryoInner.isSensitive(); + bool cryoOuterSensitive = cryoOuter.isSensitive(); + + double bathRmin = cryoDim.rmin2(); // - margin for inclination + double bathRmax = cryoDim.rmax1(); // + margin for inclination + double bathDelZ = cryoDim.dz(); + dd4hep::Tube bathOuterShape(bathRmin, bathRmax, bathDelZ); // make it 4 volumes + 5th for detector envelope + + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Cryostat front thickness is %f", cryoDim.rmin2() ); + + if (cryoThicknessFront > 0) { + // 1. Create cryostat + dd4hep::Tube cryoFrontShape(cryoDim.rmin1(), cryoDim.rmax2(), cryoThicknessFront/2.); + dd4hep::Tube cryoBackShape(cryoDim.rmin2(), cryoDim.rmax2(), cryoThicknessBack/2.); + dd4hep::Tube cryoInnerShape(cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); + dd4hep::Tube cryoOuterShape(cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "ECAL endcap cryostat: front: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f ", cryoDim.rmin1(), cryoDim.rmin2(), cryoDim.dz()); + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "ECAL encdap cryostat: back: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmax1(), cryoDim.rmax2(), cryoDim.dz()); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "ECAL endcap cryostat: side: rmin (cm) = %f rmax (cm) = %f dz (cm) = %f", cryoDim.rmin2(), cryoDim.rmax1(), cryoDim.dz() - caloDim.dz()); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Cryostat is made out of %s", cryostat.materialStr().c_str() ); + + dd4hep::Volume cryoFrontVol(cryostat.nameStr()+"_front", cryoFrontShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoBackVol(cryostat.nameStr()+"_back", cryoBackShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoInnerVol(cryostat.nameStr()+"_inner", cryoInnerShape, aLcdd.material(cryostat.materialStr())); + dd4hep::Volume cryoOuterVol(cryostat.nameStr()+"_outer", cryoOuterShape, aLcdd.material(cryostat.materialStr())); + + dd4hep::Position cryoFrontPos(0,0,-cryoDim.dz()); + dd4hep::PlacedVolume cryoFrontPhysVol = aEnvelope.placeVolume(cryoFrontVol, cryoFrontPos); + dd4hep::Position cryoBackPos(0,0,cryoDim.dz()); + dd4hep::PlacedVolume cryoBackPhysVol = aEnvelope.placeVolume(cryoBackVol, cryoBackPos); + dd4hep::PlacedVolume cryoInnerPhysVol = aEnvelope.placeVolume(cryoInnerVol); + dd4hep::PlacedVolume cryoOuterPhysVol = aEnvelope.placeVolume(cryoOuterVol); + unsigned sidetype = 0x4; // probably not needed anymore... + if (cryoFrontSensitive) { + cryoFrontVol.setSensitiveDetector(aSensDet); + cryoFrontPhysVol.addPhysVolID("cryo", 1); + cryoFrontPhysVol.addPhysVolID("type", sidetype+1); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Cryostat front volume set as sensitive"); + } + if (cryoBackSensitive) { + cryoBackVol.setSensitiveDetector(aSensDet); + cryoBackPhysVol.addPhysVolID("cryo", 1); + cryoBackPhysVol.addPhysVolID("type", sidetype+2); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Cryostat back volume set as sensitive" ); + } + if (cryoInnerSensitive) { + cryoInnerVol.setSensitiveDetector(aSensDet); + cryoInnerPhysVol.addPhysVolID("cryo", 1); + cryoInnerPhysVol.addPhysVolID("type", sidetype+3); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Cryostat inner volume set as sensitive" ); + } + if (cryoOuterSensitive) { + cryoOuterVol.setSensitiveDetector(aSensDet); + cryoOuterPhysVol.addPhysVolID("cryo", 1); + cryoOuterPhysVol.addPhysVolID("type", sidetype+4); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Cryostat outer volume set as sensitive" ); + } + dd4hep::DetElement cryoFrontDetElem(caloDetElem, "cryo_front", 0); + cryoFrontDetElem.setPlacement(cryoFrontPhysVol); + dd4hep::DetElement cryoBackDetElem(caloDetElem, "cryo_back", 0); + cryoBackDetElem.setPlacement(cryoBackPhysVol); + dd4hep::DetElement cryoInnerDetElem(caloDetElem, "cryo_inner", 0); + cryoInnerDetElem.setPlacement(cryoInnerPhysVol); + dd4hep::DetElement cryoOuterDetElem(caloDetElem, "cryo_outer", 0); + cryoOuterDetElem.setPlacement(cryoOuterPhysVol); + } + + // 2. Create noble liquid bath + std::string nobleLiquidMaterial = nobleLiquid.materialStr(); + dd4hep::Volume bathVol(nobleLiquidMaterial + "_bath", bathOuterShape, aLcdd.material(nobleLiquidMaterial)); + dd4hep::printout( dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "ECAL endcap bath: material = %s rmin (cm) = %f rmax (cm) = %f, dz (cm) = %f, thickness in front of ECal (cm) = %f, thickness behind ECal (cm) = %f", nobleLiquidMaterial.c_str(), bathRmin, bathRmax, caloDim.dz(), caloDim.rmin() - cryoDim.rmin2(), cryoDim.rmax1() - caloDim.rmax()); + + dd4hep::Position bathPos(0,0,(cryoThicknessFront-cryoThicknessBack)/2.); + + dd4hep::PlacedVolume bathPhysVol = aEnvelope.placeVolume(bathVol, bathPos); + + dd4hep::DetElement bathDetElem(caloDetElem, "bath", 1); + + bathDetElem.setPlacement(bathPhysVol); + + // 3. Create detector structure + double length = dim.dz() * 2.; + double zOffsetEnvelope = -length / 2.; + + dd4hep::xml::DetElement supportTubeElem = calo.child(_Unicode(supportTube)); + unsigned nWheelsXML = supportTubeElem.attr(_Unicode(nWheels)); + if (nWheelsXML != nWheels) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Number of wheels in XML (%d) does not match hard-coded number of wheels (%d) ", nWheelsXML, nWheels); + } + + dd4hep::printout(dd4hep::INFO, "ECalEndcap_Turbine_o1_v03", "Will build %d wheels", nWheels); + double rmin = bathRmin; + double rmax = bathRmax; + float radiusRatio = pow(rmax/rmin, 1./nWheels); + double ro = rmin*radiusRatio; + double ri = rmin; + + float supportTubeThickness=supportTubeElem.thickness(); + unsigned iSupportTube = 0; + + + for (unsigned iWheel = 0; iWheel < nWheels; iWheel++) { + + dd4hep::Tube supportTube(ro, ro+supportTubeThickness, bathDelZ ); + + dd4hep::Volume supportTubeVol("supportTube", supportTube, aLcdd.material(supportTubeElem.materialStr())); + if (supportTubeElem.isSensitive()) { + supportTubeVol.setSensitiveDetector(aSensDet); + } + dd4hep::PlacedVolume supportTube_pv = bathVol.placeVolume(supportTubeVol, dd4hep::Position(0,0,zOffsetEnvelope + dim.dz() )); + supportTube_pv.addPhysVolID("cryo", 1); + supportTube_pv.addPhysVolID("wheel", iWheel); + dd4hep::DetElement supportTubeDetElem(bathDetElem, "supportTube_"+std::to_string(iWheel), 0); + supportTubeDetElem.setPlacement(supportTube_pv); + + + buildWheel(aLcdd, aSensDet, bathVol, aXmlElement, bathDetElem, ri+supportTubeThickness, ro, bathDelZ*2-bathThicknessFront-bathThicknessBack, (bathThicknessFront-bathThicknessBack)/2., iWheel); + ri = ro; + ro *= radiusRatio; + if (ro > rmax) ro = rmax; + iSupportTube++; + } + + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "Total number of modules: %d", iModule); + + + return; + } + + + + static dd4hep::Ref_t + createECalEndcapTurbine(dd4hep::Detector& aLcdd, dd4hep::xml::Handle_t aXmlElement, dd4hep::SensitiveDetector aSensDet) { + + dd4hep::xml::DetElement xmlDetElem = aXmlElement; + std::string nameDet = xmlDetElem.nameStr(); + int idDet = xmlDetElem.id(); + dd4hep::xml::Dimension dim(xmlDetElem.dimensions()); + dd4hep::DetElement caloDetElem(nameDet, idDet); + dd4hep::xml::Dimension sdType = xmlDetElem.child(_U(sensitive)); + aSensDet.setType(sdType.typeStr()); + + unsigned numReadoutRhoLayers, numReadoutZLayers; + ECalEndcapNumCalibRhoLayersArr[0] = aLcdd.constant("ECalEndcapNumCalibRhoLayersWheel1"); + numReadoutRhoLayers = aLcdd.constant("ECalEndcapNumReadoutRhoLayersWheel1"); + if ((numReadoutRhoLayers % ECalEndcapNumCalibRhoLayersArr[0]) != 0) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Number of readout layers must be a multiple of number of calibration layers"); + } + ECalEndcapNumCalibRhoLayersArr[1] = aLcdd.constant("ECalEndcapNumCalibRhoLayersWheel2"); + numReadoutRhoLayers = aLcdd.constant("ECalEndcapNumReadoutRhoLayersWheel2"); + if ((numReadoutRhoLayers % ECalEndcapNumCalibRhoLayersArr[1]) != 0) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Number of readout layers must be a multiple of number of calibration layers"); + } + ECalEndcapNumCalibRhoLayersArr[2] = aLcdd.constant("ECalEndcapNumCalibRhoLayersWheel3"); + numReadoutRhoLayers = aLcdd.constant("ECalEndcapNumReadoutRhoLayersWheel3"); + if ((numReadoutRhoLayers % ECalEndcapNumCalibRhoLayersArr[2]) != 0) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Number of readout layers must be a multiple of number of calibration layers"); + } + ECalEndcapNumCalibZLayersArr[0] = aLcdd.constant("ECalEndcapNumCalibZLayersWheel1"); + numReadoutZLayers = aLcdd.constant("ECalEndcapNumReadoutZLayersWheel1"); + if ((numReadoutZLayers % ECalEndcapNumCalibZLayersArr[0]) != 0) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Number of readout layers must be a multiple of number of calibration layers"); + } + ECalEndcapNumCalibZLayersArr[1] = aLcdd.constant("ECalEndcapNumCalibZLayersWheel2"); + numReadoutZLayers = aLcdd.constant("ECalEndcapNumReadoutZLayersWheel2"); + if ((numReadoutZLayers % ECalEndcapNumCalibZLayersArr[1]) != 0) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Number of readout layers must be a multiple of number of calibration layers"); + } + ECalEndcapNumCalibZLayersArr[2] = aLcdd.constant("ECalEndcapNumCalibZLayersWheel3"); + numReadoutZLayers = aLcdd.constant("ECalEndcapNumReadoutZLayersWheel3"); + if ((numReadoutZLayers % ECalEndcapNumCalibZLayersArr[2]) != 0) { + dd4hep::printout(dd4hep::ERROR, "ECalEndcap_Turbine_o1_v03", "Number of readout layers must be a multiple of number of calibration layers"); + } + + // Create air envelope for one endcap (will be copied to make both endcaps) + dd4hep::Tube endcapShape( dim.rmin1(), dim.rmax1(), dim.dz()); + + dd4hep::Volume envelopeVol(nameDet + "_vol", endcapShape, aLcdd.material("Air")); + + + dd4hep::printout(dd4hep::DEBUG, "ECalEndcap_Turbine_o1_v03", "Placing detector on the positive side: (cm) %f with min, max radii %f %f",dim.z_offset(), dim.rmin1(), dim.rmax1() ); + + unsigned iModule = 0; + buildOneSide_Turbine(aLcdd, caloDetElem, aSensDet, envelopeVol, aXmlElement, iModule); + + dd4hep::Assembly endcapsAssembly("ECalEndcaps_turbine"); + + // Place the envelope + dd4hep::Transform3D envelopePositiveVolume_tr(dd4hep::RotationZYX( 0 ,0,0), dd4hep::Translation3D(0, 0, dim.z_offset())); + dd4hep::PlacedVolume envelopePositivePhysVol = endcapsAssembly.placeVolume(envelopeVol, envelopePositiveVolume_tr); + envelopePositivePhysVol.addPhysVolID("side", 1); + + // make another placement for the negative z endcap + dd4hep::Transform3D envelopeNegativeVolume_tr(dd4hep::RotationZYX( 0 ,0,180*dd4hep::deg), dd4hep::Translation3D(0, 0, -dim.z_offset())); + dd4hep::PlacedVolume envelopeNegativePhysVol = + endcapsAssembly.placeVolume(envelopeVol, envelopeNegativeVolume_tr); + envelopeNegativePhysVol.addPhysVolID("side", -1); + + dd4hep::Volume motherVol = aLcdd.pickMotherVolume(caloDetElem); + dd4hep::PlacedVolume envelopePhysVol = motherVol.placeVolume(endcapsAssembly); + caloDetElem.setPlacement(envelopePhysVol); + envelopePhysVol.addPhysVolID("system", idDet); + return caloDetElem; + } + } +} // namespace det + +DECLARE_DETELEMENT(ECalEndcap_Turbine_o1_v03, det::ECalEndcap_Turbine_o1_v03::createECalEndcapTurbine) diff --git a/detector/calorimeter/README.md b/detector/calorimeter/README.md index 771b6acf6..a61677543 100644 --- a/detector/calorimeter/README.md +++ b/detector/calorimeter/README.md @@ -30,7 +30,10 @@ Sub-detector for the ecal endcaps, with the absorbers and readout boards arrange Initial implementation. A custom segmentation that creates readout cells and constant radius and z is also included (FCCSWEndcapTurbine_k4geo). ### o1_v02 -Changes wrt o1_v01: Added flexibility to configure the wheels individual (to allow for example the possibiliity of having different blade angles in each). This is still a work in progress, so o1_v01 should be used for integrated tests. +Changes wrt o1_v01: Added flexibility to configure the wheels individual (to allow for example the possibiliity of having different blade angles in each). + +### o1_v03 +Changes wrt o1_v02: Modified the calibration "layers" to be a 2d grid in both dimensions on the surface of an absorber plate (which map to the rho and z dimensions in the global coordinate system), since the NL gap varies in both directions. The readout segmentation is also a 2d grid in the same coordinates, but the readout is allowed to be finer-grained than the calibration. ## HCalTileBarrel This sub-detector makes calorimeter barrel. It is used in ALLEGRO detector concept. diff --git a/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h b/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h index 3b1d93bb6..61b56b5eb 100644 --- a/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h +++ b/detectorSegmentations/include/detectorSegmentations/FCCSWEndcapTurbine_k4geo.h @@ -20,7 +20,8 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { FCCSWEndcapTurbine_k4geo(const std::string& aCellEncoding); /// Default constructor used by derived classes passing an existing decoder FCCSWEndcapTurbine_k4geo(const BitFieldCoder* decoder); - + ///common setup that needs to be done for either of the above constructors + void commonSetup(); /// destructor virtual ~FCCSWEndcapTurbine_k4geo() = default; @@ -34,6 +35,37 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { */ virtual CellID cellID(const Vector3D& aLocalPosition, const Vector3D& aGlobalPosition, const VolumeID& aVolumeID) const; + + /** Determine the transverse distance from the beamline (rho) based on the cell ID. + * @param[in] aCellId ID of a cell. + * return rho. + */ + double rho(const CellID& aCellID) const; + /** Get the grid size in rho for a given wheel + * return grid size in rho + */ + inline double gridSizeRho(int iWheel) const { return m_gridSizeRho[iWheel]; } + /** Get the number of cells in rho for a given wheel + * @param[in] iWheel wheel index + * return number of cells in rho for the specified wheel + */ + inline int numCellsRho(int iWheel) const {return m_numReadoutRhoLayers[iWheel];} + + /** Get the number of calibration cells in rho for a given wheel + * @param[in] iWheel wheel index + * return number of calibration cells in rho for the specified wheel + */ + inline int numCellsRhoCalib(int iWheel) const {return m_numCalibRhoLayers[iWheel];} + + /** Get the coordinate offset in rho for a given wheel. + * return The offset in rho. + */ + inline double offsetRho(int iWheel) const { return m_offsetRho[iWheel]; } + /** Get the field name for rho. + * return The field name for rho. + */ + + inline const std::string& fieldNameRho() const { return m_rhoID; } /** Determine the azimuthal angle based on the cell ID. * @param[in] aCellId ID of a cell. * return Phi. @@ -52,6 +84,11 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { * return The field name for phi. */ inline const std::string& fieldNamePhi() const { return m_phiID; } + /** Get the angle of the turbine blades in a given wheel + * @param[in] iWheel index of wheel. + * return the blade angle for the requested wheel + */ + double bladeAngle(unsigned iWheel) const {return m_bladeAngle[iWheel];} /** Set the number of bins in azimuthal angle. * @param[in] aNumberBins Number of bins in phi. */ @@ -68,44 +105,41 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { * @param[in] aFieldName Field name for phi. */ inline void setFieldNamePhi(const std::string& fieldName) { m_phiID = fieldName; } - /** Determine the transverse distance from the beamline rho based on the cell ID. - * @param[in] aCellId ID of a cell. - * return rho. - */ - double rho(const CellID& aCellID) const; - /** Get the coordinate offset in rho. - * return The offset in rho. - */ - inline double offsetRho(int iWheel) const { return m_offsetRho[iWheel]; } - /** Get the field name for rho. - * return The field name for rho. - */ - inline const std::string& fieldNameRho() const { return m_rhoID; } - /** Set the number of bins in rho. - * @param[in] aNumberBins Number of bins in rho. - */ - inline void setRhoBins(int bins) { m_rhoBins = bins; } - /** Set the coordinate offset in rho. - * @param[in] aOffset Offset in rho. - */ - // inline void setOffsetRho(double offset) { m_offsetRho = offset; } - /** Set the field name used for transverse distance from IP rho. - * @param[in] aFieldName Field name for rho. - */ - inline void setFieldNameRho(const std::string& fieldName) { m_rhoID = fieldName; } /** Set the field name used for the wheel ID. * @param[in] aFieldName Field name for wheel. */ inline void setFieldNameWheel(const std::string& fieldName) {m_wheelID = fieldName; } + /** Determine the x coordinate based on the cell ID. + * @param[in] aCellId ID of a cell. + * return x. + */ + double x(const CellID& aCellID) const; /** Determine the z coordinate based on the cell ID. * @param[in] aCellId ID of a cell. * return z. */ double z(const CellID& aCellID) const; + /** Get the grid size in z for a given wheel + * return grid size in z + */ + inline double gridSizeZ(int iWheel) const { return m_gridSizeZ[iWheel]; } /** Get the coordinate offset in z. * return The offset in z. */ - inline double offsetZ() const { return m_offsetZ; } + /** Get the number of cells in z for a given wheel + * @param[in] iWheel wheel index + * return number of cells in z for the specified wheel + */ + inline int numCellsZ(int iWheel) const {return m_numReadoutZLayers[iWheel];} + /** Get the number of calibration cells in z for a given wheel + * @param[in] iWheel wheel index + * return number of calibration cells in z for the specified wheel + */ + inline int numCellsZCalib(int iWheel) const {return m_numCalibZLayers[iWheel];} /** Get the offset in z for a given wheel + * @param[in] iWheel wheel index + * return offset in z for the specified wheel + */ + inline double offsetZ(int iWheel) const { return m_offsetZ[iWheel]; } /** Get the field name for z. * return The field name for z. */ @@ -114,10 +148,11 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { * @param[in] aNumberBins Number of bins in z. */ inline void setZBins(int bins) { m_zBins = bins; } - /** Set the coordinate offset in z. + /** Set the coordinate offset in z for the specified wheel. + * @param[in] iWheel wheel index * @param[in] aOffset Offset in z. */ - inline void setOffsetZ(double offset) { m_offsetZ = offset; } + inline void setOffsetZ(int iWheel, double offset) { m_offsetZ[iWheel] = offset; } /** Set the field name used for z. * @param[in] aFieldName Field name for z. */ @@ -127,11 +162,32 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { return vec.Perp(); } + /** return the number of unit cells in each wheel + * @param[in] iWheel wheel identifier + */ + inline int nModules(int iWheel) { + return m_nUnitCells[iWheel]; + } + /** return the expected value of the layer index + * @param[in] iWheel wheel identifier + * @param[in] iRho rho readout cell identifier + * @param[in] iZ z readout cell identifier + */ + unsigned expLayer(unsigned iWheel, unsigned iRho, unsigned iZ) const; + protected: - /// turbine blade angle + /// turbine blade angle in each wheel std::vector m_bladeAngle; - /// least common multiple of number of unit cells - int m_nUnitCellsLeastCommonMultiple; + /// number of unit cells in each wheel + std::vector m_nUnitCells; + /// the number of cells in rho for each wheel + std::vector m_numReadoutRhoLayers; + /// the number of cells in z for each wheel + std::vector m_numReadoutZLayers; + /// the number of calibration cells in rho for each wheel + std::vector m_numCalibRhoLayers; + /// the number of calibration cells in z for each wheel + std::vector m_numCalibZLayers; /// the number of bins in phi int m_phiBins; /// the coordinate offset in phi @@ -142,9 +198,9 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { /// the number of bins in rho int m_rhoBins; ////grid size in rho - std::vector m_gridSizeRho; + std::vector m_gridSizeRho; /// the coordinate offset in rho - std::vector m_offsetRho; + std::vector m_offsetRho; /// the field name used for rho std::string m_rhoID; /// the field name used for wheel @@ -154,12 +210,13 @@ class FCCSWEndcapTurbine_k4geo : public Segmentation { /// the number of bins in z int m_zBins; ///grid size in z - double m_gridSizeZ; + std::vector m_gridSizeZ; /// the coordinate offset in z - double m_offsetZ; + std::vector m_offsetZ; /// the field name used for z std::string m_zID; std::string m_sideID; + std::string m_layerID; }; } } diff --git a/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp b/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp index a3cf00b35..ab5a43628 100644 --- a/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp +++ b/detectorSegmentations/src/FCCSWEndcapTurbine_k4geo.cpp @@ -6,112 +6,194 @@ namespace DDSegmentation { /// default constructor using an encoding string FCCSWEndcapTurbine_k4geo::FCCSWEndcapTurbine_k4geo(const std::string& cellEncoding) : Segmentation(cellEncoding) { + + commonSetup(); +} + + FCCSWEndcapTurbine_k4geo::FCCSWEndcapTurbine_k4geo(const BitFieldCoder* decoder) : Segmentation(decoder) { // define type and description + + commonSetup(); + +} + +/// initialize variables, etc (needed for either version of the ctor) +void FCCSWEndcapTurbine_k4geo::commonSetup() { _type = "FCCSWEndcapTurbine_k4geo"; _description = "Turbine-specific segmentation in the global coordinates"; // register all necessary parameters - registerParameter("grid_size_rho", "Grid size in rho", m_gridSizeRho, std::vector()); - registerParameter("offset_rho", "Offset in rho", m_offsetRho, std::vector()); - registerIdentifier("identifier_rho", "Cell ID identifier for rho", m_rhoID, "rho"); // might want to have separate concepts for rho and layer... - registerParameter("grid_size_z", "Grid size in z", m_gridSizeZ, 0.); - registerParameter("offset_z", "Offset in z", m_offsetZ, 0.); + m_offsetRho.resize(3); + m_gridSizeRho.resize(3); + m_gridSizeZ.resize(3); + m_offsetZ.resize(3); + + registerParameter("offset_rho1", "Offset in rho1", m_offsetRho[0], 0.); + registerParameter("offset_rho2", "Offset in rho2", m_offsetRho[1], 0.); + registerParameter("offset_rho3", "Offset in rho3", m_offsetRho[2], 0.); + + registerIdentifier("identifier_rho", "Cell ID identifier for rho", m_rhoID, "rho"); + + registerParameter("grid_size_rho1", "Grid size in rho1", m_gridSizeRho[0], 0.); + registerParameter("grid_size_rho2", "Grid size in rho2", m_gridSizeRho[1], 0.); + registerParameter("grid_size_rho3", "Grid size in rho3", m_gridSizeRho[2], 0.); + + registerParameter("grid_size_z1", "Grid size in z1", m_gridSizeZ[0], 0.); + registerParameter("grid_size_z2", "Grid size in z2", m_gridSizeZ[1], 0.); + registerParameter("grid_size_z3", "Grid size in z3", m_gridSizeZ[2], 0.); + registerParameter("offset_z1", "Offset in z1", m_offsetZ[0], 0.); + registerParameter("offset_z2", "Offset in z2", m_offsetZ[1], 0.); + registerParameter("offset_z3", "Offset in z3", m_offsetZ[2], 0.); + registerParameter("offset_theta", "Angular offset in theta", m_offsetTheta, 0., SegmentationParameter::AngleUnit, true); registerIdentifier("identifier_z", "Cell ID identifier for z", m_zID, "z"); registerIdentifier("identifier_side", "Cell ID identifier for side", m_sideID, "side"); - + registerIdentifier("identifier_wheel", "Cell ID identifier for wheel", m_wheelID, "wheel"); + registerIdentifier("identifier_module", "Cell ID identifier for module", m_moduleID, "module"); + registerIdentifier("identifier_layer", "Cell ID identifier for layer", m_layerID, "layer"); dd4hep::Detector* dd4hepgeo = &(dd4hep::Detector::getInstance()); + m_bladeAngle.clear(); try { m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle1")); - std::cout << "Blade angle 1 is " << m_bladeAngle[0] << std::endl; } catch(...) { - std::cout << "Blade angle 1 not found in detector metadata, exiting..." << std::endl; + std::cout << "BladeAngle1 not found in detector metadata, exiting..." << std::endl; exit(1); } try { m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle2")); - std::cout << "Blade angle 2 is " << m_bladeAngle[1] << std::endl; } catch(...) { - std::cout << "Blade angle 2 not found in detector metadata, exiting..." << std::endl; + std::cout << "BladeAngle2 not found in detector metadata, exiting..." << std::endl; exit(1); } try { m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle3")); - std::cout << "Blade angle 3 is " << m_bladeAngle[2] << std::endl; } catch(...) { - std::cout << "Blade angle 3 not found in detector metadata, exiting..." << std::endl; + std::cout << "BladeAngle3 not found in detector metadata, exiting..." << std::endl; exit(1); } + + m_nUnitCells.clear(); try { - m_nUnitCellsLeastCommonMultiple = dd4hepgeo->constant("nUnitCellsLeastCommonMultiple"); + m_nUnitCells.push_back(dd4hepgeo->constant("nUnitCells1")); } catch(...) { - std::cout << "nUnitCellsLeastCommonMultiple not found in detector metadata, exiting..." << std::endl; + std::cout << "nUnitCells1 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_nUnitCells.push_back(dd4hepgeo->constant("nUnitCells2")); + } + catch(...) { + std::cout << "nUnitCells2 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_nUnitCells.push_back(dd4hepgeo->constant("nUnitCells3")); + } + catch(...) { + std::cout << "nUnitCells3 not found in detector metadata, exiting..." << std::endl; exit(1); } - -} - - FCCSWEndcapTurbine_k4geo::FCCSWEndcapTurbine_k4geo(const BitFieldCoder* decoder) : Segmentation(decoder) { - // define type and description - _type = "FCCSWEndcapTurbine_k4geo"; - _description = "Turbine-specific segmentation in the global coordinates"; - // register all necessary parameters - registerParameter("grid_size_rho", "Grid size in rho", m_gridSizeRho, std::vector()); - registerParameter("offset_rho", "Offset in rho", m_offsetRho, std::vector()); - registerIdentifier("identifier_rho", "Cell ID identifier for rho", m_rhoID, "rho"); - registerParameter("grid_size_z", "Grid size in z", m_gridSizeZ, 0.); - registerParameter("offset_z", "Offset in z", m_offsetZ, 0.); - registerParameter("offset_theta", "Angular offset in theta", m_offsetTheta, 0., SegmentationParameter::AngleUnit, true); - registerIdentifier("identifier_z", "Cell ID identifier for z", m_zID, "z"); - registerIdentifier("identifier_side", "Cell ID identifier for side", m_sideID, "side"); - registerIdentifier("identifier_wheel", "Cell ID identifier for wheel", m_wheelID, "wheel"); - registerIdentifier("identifier_module", "Cell ID identifier for module", m_moduleID, "module"); - dd4hep::Detector* dd4hepgeo = &(dd4hep::Detector::getInstance()); + m_numReadoutRhoLayers.clear(); + try { + m_numReadoutRhoLayers.push_back(dd4hepgeo->constant("ECalEndcapNumReadoutRhoLayersWheel1")); + } + catch(...) { + std::cout << "ECalEndcapNumReadoutRhoLayersWheel1 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_numReadoutRhoLayers.push_back(dd4hepgeo->constant("ECalEndcapNumReadoutRhoLayersWheel2")); + } + catch(...) { + std::cout << "ECalEndcapNumReadoutRhoLayersWheel2 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_numReadoutRhoLayers.push_back(dd4hepgeo->constant("ECalEndcapNumReadoutRhoLayersWheel3")); + } + catch(...) { + std::cout << "ECalEndcapNumReadoutRhoLayersWheel3 not found in detector metadata, exiting..." << std::endl; + exit(1); + } - m_bladeAngle.clear(); - + m_numReadoutZLayers.clear(); try { - m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle1")); - std::cout << "Blade angle 1 is " << m_bladeAngle[0] << std::endl; + m_numReadoutZLayers.push_back(dd4hepgeo->constant("ECalEndcapNumReadoutZLayersWheel1")); } catch(...) { - std::cout << "Blade angle 1 not found in detector metadata, exiting..." << std::endl; + std::cout << "ECalEndcapNumReadoutZLayersWheel1 not found in detector metadata, exiting..." << std::endl; exit(1); } try { - m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle2")); - std::cout << "Blade angle 2 is " << m_bladeAngle[1] << std::endl; + m_numReadoutZLayers.push_back(dd4hepgeo->constant("ECalEndcapNumReadoutZLayersWheel2")); } catch(...) { - std::cout << "Blade angle 2 not found in detector metadata, exiting..." << std::endl; + std::cout << "ECalEndcapNumReadoutZLayersWheel2 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_numReadoutZLayers.push_back(dd4hepgeo->constant("ECalEndcapNumReadoutZLayersWheel3")); + } + catch(...) { + std::cout << "ECalEndcapNumReadoutZLayersWheel3 not found in detector metadata, exiting..." << std::endl; exit(1); } + + m_numCalibRhoLayers.clear(); try { - m_bladeAngle.push_back(dd4hepgeo->constant("BladeAngle3")); - std::cout << "Blade angle 3 is " << m_bladeAngle[2] << std::endl; + m_numCalibRhoLayers.push_back(dd4hepgeo->constant("ECalEndcapNumCalibRhoLayersWheel1")); } catch(...) { - std::cout << "Blade angle 3 not found in detector metadata, exiting..." << std::endl; + std::cout << "ECalEndcapNumCalibRhoLayersWheel1 not found in detector metadata, exiting..." << std::endl; exit(1); } try { - m_nUnitCellsLeastCommonMultiple = dd4hepgeo->constant("nUnitCellsLeastCommonMultiple"); + m_numCalibRhoLayers.push_back(dd4hepgeo->constant("ECalEndcapNumCalibRhoLayersWheel2")); } catch(...) { - std::cout << "nUnitCellsLeastCommonMultiple not found in detector metadata, exiting..." << std::endl; + std::cout << "ECalEndcapNumCalibRhoLayersWheel2 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_numCalibRhoLayers.push_back(dd4hepgeo->constant("ECalEndcapNumCalibRhoLayersWheel3")); + } + catch(...) { + std::cout << "ECalEndcapNumCalibRhoLayersWheel3 not found in detector metadata, exiting..." << std::endl; exit(1); } + m_numCalibZLayers.clear(); + try { + m_numCalibZLayers.push_back(dd4hepgeo->constant("ECalEndcapNumCalibZLayersWheel1")); + } + catch(...) { + std::cout << "ECalEndcapNumCalibZLayersWheel1 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_numCalibZLayers.push_back(dd4hepgeo->constant("ECalEndcapNumCalibZLayersWheel2")); + } + catch(...) { + std::cout << "ECalEndcapNumCalibZLayersWheel2 not found in detector metadata, exiting..." << std::endl; + exit(1); + } + try { + m_numCalibZLayers.push_back(dd4hepgeo->constant("ECalEndcapNumCalibZLayersWheel3")); + } + catch(...) { + std::cout << "ECalEndcapNumCalibZLayersWheel3 not found in detector metadata, exiting..." << std::endl; + exit(1); + } } - + /// determine the local position based on the cell ID Vector3D FCCSWEndcapTurbine_k4geo::position(const CellID& cID) const { @@ -121,6 +203,7 @@ Vector3D FCCSWEndcapTurbine_k4geo::position(const CellID& cID) const { Vector3D pos = PositionRhoZPhi(rhoVal, zVal, phiVal); // account for the fact that the -z endcap is mirrored wrt to the +z one if (pos.Z < 0.) pos.Y = -pos.Y; + return pos; } @@ -128,26 +211,44 @@ Vector3D FCCSWEndcapTurbine_k4geo::position(const CellID& cID) const { CellID FCCSWEndcapTurbine_k4geo::cellID(const Vector3D& /* localPosition */, const Vector3D& globalPosition, const VolumeID& vID) const { CellID cID = vID; - double lRho = rhoFromXYZ(globalPosition); CellID iWheel = _decoder->get(cID, m_wheelID); - _decoder->set(cID, m_rhoID, positionToBin(lRho, m_gridSizeRho[iWheel], m_offsetRho[iWheel])); + CellID iLayer = _decoder->get(cID, m_layerID); + double lRho = rhoFromXYZ(globalPosition); + int iRho = positionToBin(lRho, m_gridSizeRho[iWheel], m_offsetRho[iWheel]); + if (iRho < 0) iRho = 0; + if (iRho >= m_numReadoutRhoLayers[iWheel]) iRho = m_numReadoutRhoLayers[iWheel]-1; + + _decoder->set(cID, m_rhoID, iRho); + double lZ = TMath::Abs(globalPosition.Z); - _decoder->set(cID, m_zID, positionToBin(lZ, m_gridSizeZ, m_offsetZ)); + int iZ = positionToBin(lZ, m_gridSizeZ[iWheel], m_offsetZ[iWheel]); + if (iZ < 0) iZ = 0; + if (iZ >= m_numReadoutZLayers[iWheel]) iZ = m_numReadoutZLayers[iWheel]-1; + _decoder->set(cID, m_zID, iZ); + if (expLayer(iWheel, iRho, iZ) != iLayer) { + _decoder->set(cID, m_layerID, expLayer(iWheel, iRho, iZ)); + } + return cID; } + /// determine rho based on the cell ID +double FCCSWEndcapTurbine_k4geo::rho(const CellID& cID) const { + CellID rhoValue = _decoder->get(cID, m_rhoID); + CellID iWheel = _decoder->get(cID, m_wheelID); + + return binToPosition(rhoValue,m_gridSizeRho[iWheel], m_offsetRho[iWheel]); +} + /// determine the azimuthal angle phi based on the cell ID double FCCSWEndcapTurbine_k4geo::phi(const CellID& cID) const { - CellID iModule = _decoder->get(cID, m_moduleID); CellID iWheel = _decoder->get(cID, m_wheelID); - double phiCent = twopi*(iModule+0.5)/m_nUnitCellsLeastCommonMultiple; - + double phiCent = twopi*(iModule+0.5)/m_nUnitCells[iWheel]; double rhoLoc = rho(cID); - double zLoc = TMath::Abs(z(cID))-m_offsetZ - 45; // hard-code midpoint in z for now - + double zLoc = TMath::Abs(z(cID))-m_offsetZ[iWheel] - 45/2.; // hard-code midpoint in z for now double zCotBladeAngle = zLoc/TMath::Tan(m_bladeAngle[iWheel]); @@ -158,21 +259,28 @@ double FCCSWEndcapTurbine_k4geo::phi(const CellID& cID) const { double yprime = y*TMath::Cos(phiCent) -x*TMath::Sin(phiCent); return TMath::ATan2(xprime,yprime); -} -/// determine the transverse distance from the beamline r based on the cell ID -double FCCSWEndcapTurbine_k4geo::rho(const CellID& cID) const { - CellID rhoValue = _decoder->get(cID, m_rhoID); - CellID iWheel = _decoder->get(cID, m_wheelID); + } - return binToPosition(rhoValue,m_gridSizeRho[iWheel], m_offsetRho[iWheel]); -} + /// determine local x in plane of blade based on the cell ID double FCCSWEndcapTurbine_k4geo::z(const CellID& cID) const { CellID zValue = _decoder->get(cID, m_zID); CellID sideValue = _decoder->get(cID, m_sideID); - return ((long long int)sideValue)*binToPosition(zValue,m_gridSizeZ,m_offsetZ); + CellID iWheel = _decoder->get(cID, m_wheelID); + return ((long long int)sideValue)*binToPosition(zValue,m_gridSizeZ[iWheel],m_offsetZ[iWheel]); } + /// determine expected layer value based on wheel, rho, and z indices + unsigned FCCSWEndcapTurbine_k4geo::expLayer(unsigned iWheel, unsigned iRho, unsigned iZ) const { + unsigned layerOffset = 0; + if (iWheel == 1) { + layerOffset = m_numCalibZLayers[0]*m_numCalibRhoLayers[0]; + } + else if (iWheel == 2) { + layerOffset = m_numCalibZLayers[0]*m_numCalibRhoLayers[0]+layerOffset + m_numCalibZLayers[1]*m_numCalibRhoLayers[1]; + } + return layerOffset + iZ/(m_numReadoutZLayers[iWheel]/m_numCalibZLayers[iWheel]) + iRho*m_numCalibZLayers[iWheel]/(m_numReadoutRhoLayers[iWheel]/m_numCalibRhoLayers[iWheel]); + } } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ae8cfa79..2c47e7f01 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -138,10 +138,10 @@ SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION "Except #-------------------------------------------------- # test for ALLEGRO o1 v03 if(DCH_INFO_H_EXIST) -SET( test_name "test_ALLEGRO_o1_v03" ) -ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" - ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml --runType=batch -G -N=1 --outputFile=testALLEGRO_o1_v03.root ) -SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" ) + SET( test_name "test_ALLEGRO_o1_v03" ) + ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/ALLEGRO/compact/ALLEGRO_o1_v03/ALLEGRO_o1_v03.xml --runType=batch -G -N=50000 --gun.distribution uniform --gun.particle geantino --outputFile=testALLEGRO_o1_v03.root ) + SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 600) endif() #-------------------------------------------------- @@ -149,8 +149,8 @@ endif() if(DCH_INFO_H_EXIST) SET( test_name "test_ALLEGRO_o1_v04" ) ADD_TEST( t_${test_name} "${CMAKE_INSTALL_PREFIX}/bin/run_test_${PackageName}.sh" - ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml --runType=batch -G -N=1 --outputFile=testALLEGRO_o1_v04.root --gun.direction "1,0,1" ) -SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception;EXCEPTION;ERROR;Error" ) + ddsim --compactFile=${CMAKE_CURRENT_SOURCE_DIR}/../FCCee/ALLEGRO/compact/ALLEGRO_o1_v04/ALLEGRO_o1_v04.xml --runType=batch -G -N=50000 --gun.distribution uniform --gun.particle geantino --outputFile=testALLEGRO_o1_v04.root ) + SET_TESTS_PROPERTIES( t_${test_name} PROPERTIES FAIL_REGULAR_EXPRESSION " Exception; EXCEPTION;ERROR;Error" TIMEOUT 600) endif() #--------------------------------------------------