Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • 1810337/CEPCSW
  • shexin/CEPCSW
  • dudejing/CEPCSW
  • yudian2002/cepcsw-otb-development
  • cepcsw/CEPCSW
  • cepc/CEPCSW
  • shixin/CEPCSW
  • lizhan/CEPCSW
  • 1365447033/CEPCSW
  • shihy/CEPCSW
  • sunwy/CEPCSW
  • guofangyi/cepcsw-release
  • lintao/CEPCSW
  • tanggy/CEPCSW
  • gongjd1119/CEPCSW
  • 221840222/CEPCSW
  • lihn/CEPCSW
  • thinking/CEPCSW
  • myliu/CEPCSW
  • shihy/cepcsw-dose
  • zhaog/CEPCSW
  • 201840277/CEPCSW
  • wangchu/CEPCSW
  • xiaolin.wang/CEPCSW
  • fucd/CEPCSW1
  • tyzhang/CEPCSW
  • yudian2002/cepcsw-ote-development
  • songwz/cepcsw-tdr
  • luhc/CEPCSW
  • tangyb/CEPCSW
  • dhb112358/CEPCSW
  • chenbp/CEPCSW
  • guolei/CEPCSW
  • yudian2002/cepcsw-otk-end-cap-development
  • jiangxj/CEPCSW
  • yudian2002/cepcsw-geo-upgrade
  • fangwx/CEPCSW
  • yudian2002/cepcsw-geo-upgrade-v-2
  • mengwq/CEPCSW
  • zhangxm/CEPCSW
  • chenye/CEPCSW
  • wuchonghao9612/CEPCSW
  • xuchj7/CEPCSW
  • yudian2002/cepcsw-otk-endcap-update-01
  • lizhihao/CEPCSW
  • laipz/CEPCSW
  • zhangkl/CEPCSW
  • lihp29/CEPCSW
  • shuxian/CEPCSW
  • zhangyz/CEPCSW
  • zhangjinxian/CEPCSW_20250110
  • glliu/CEPCSW
  • shuohan/CEPCSW
  • fucd/CEPCSW
  • starr136a/CEPCSW
  • yudian2002/CEPCSW
  • wanjw03/CEPCSW
  • zyjonah/CEPCSW
  • maxt/CEPCSW
  • wangshi/CEPCSW
60 results
Show changes
Showing
with 3921 additions and 157 deletions
......@@ -6,7 +6,7 @@ all hardcoded overall dimensions which differ between large and small models
<constant name="Field_nominal_value" value="3.0*tesla"/>
<constant name="top_TPC_outer_radius" value="1808*mm"/>
<constant name="Ecal_endcap_extra_size" value="52.68*mm"/>
<constant name="Ecal_endcap_extra_size" value="60.8*mm"/>
<constant name="Ecal_endcap_number_of_towers" type="string" value="4 5"/>
</define>
......@@ -6,7 +6,7 @@
<detectors>
<detector name="TPC" type="TPC10" vis="TPCVis" id="ILDDetID_TPC" limits="Tracker_limits" readout="TPCCollection" insideTrackingVolume="true">
<detector name="TPC" type="TPC10" vis="TPCVis" id="ILDDetID_TPC" limits="TPC_limits" readout="TPCCollection" insideTrackingVolume="true">
<envelope vis="ILD_TPCVis">
......@@ -20,40 +20,42 @@
<!-- SQL command: "SELECT * FROM `global`;" -->
<!-- ORIGINAL : dr_InnerServiceArea="30*mm" dr_OuterServiceArea="30*mm" DANIEL REDUCED TO FIT THICK ECAL -->
<!-- dr_InnerServiceArea="18.1*mm" dr_OuterServiceArea="18.1*mm" recover to tpc10_01 matching CEPC_v4, by fucd-->
<global TPC_pad_height="6*mm" TPC_pad_width="1*mm" TPC_max_step_length="5*mm" dr_InnerWall="25*mm"
dr_InnerServiceArea="18.1*mm" dr_OuterServiceArea="18.1*mm"
dr_OuterWall="55*mm" dz_Cathode="0.06*mm" dz_Readout="25*mm" dz_Endplate="100*mm"
dr_InnerServiceArea="30*mm" dr_OuterServiceArea="30*mm"
dr_OuterWall="60*mm" dz_Cathode="0.06*mm" dz_Readout="25*mm" dz_Endplate="100*mm"
chamber_Gas="TDR_gas" sensitive_threshold_eV="32*eV" />
<!-- updates from Dimitra 4/7/17 -->
<cathode dz_Cathode_Insulator="0.046*mm" dz_Cathode_Conductor="0.004*mm" material_Cathode_Insulator="G4_KAPTON"
material_Cathode_Conductor="G4_Cu" dr_Cathode_Grip="18*mm" dz_Cathode_Grip="15*mm" material_Cathode_Grip="SiC_foam" />
<!--cathode dz_Cathode_Insulator="0.046*mm" dz_Cathode_Conductor="0.004*mm" material_Cathode_Insulator="G4_KAPTON"
material_Cathode_Conductor="G4_Cu" dr_Cathode_Grip="18*mm" dz_Cathode_Grip="15*mm" material_Cathode_Grip="SiC_foam" /-->
<!-- recover to tpc10_01 matching CEPC_v4, by fucd-->
<cathode dz_Cathode_Insulator="0.0275*mm" dz_Cathode_Conductor="0.0025*mm" material_Cathode_Insulator="G4_KAPTON"
material_Cathode_Conductor="G4_Cu" dr_Cathode_Grip="20*mm" dz_Cathode_Grip="15*mm" material_Cathode_Grip="SiC_foam" />
<!-- SQL command: "SELECT * FROM `innerWall`;" -->
<innerWall>
<!-- updates from Dimitra 4/7/17 -->
<row dr="0.07*mm" material="G4_Cu" />
<row dr="0.01*mm" material="G4_Al" />
<row dr="0.05*mm" material="G4_KAPTON" />
<row dr="0.3*mm" material="g10" />
<row dr="24.22*mm" material="G4_AIR" />
<row dr="0.3*mm" material="g10" />
<row dr="0.05*mm" material="G4_KAPTON" />
<row dr="0.01*mm" material="G4_Al" />
<row dr="0.07*mm" material="G4_Cu" />
</innerWall>
<!-- SQL command: "SELECT * FROM `outerWall`;" -->
<outerWall>
<!-- updates from Dimitra 4/7/17 -->
<row dr="0.03*mm" material="G4_Al" />
<row dr="0.15*mm" material="G4_KAPTON" />
<row dr="0.9*mm" material="g10" />
<!-- updates from Dimitra 4/7/17 --> <!--recover to tpc10_01 matching CEPC_v4, by fucd-->
<row dr="0.07*mm" material="G4_Cu" />
<row dr="0.05*mm" material="G4_KAPTON" />
<row dr="0.3*mm" material="g10" />
<!-- row dr="57.66*mm" material="G4_AIR" / -->
<row dr="52.66*mm" material="G4_AIR" /> <!-- removed 5 mm to accomadate fat ecal: to be finalised when numbers available -->
<row dr="0.9*mm" material="g10" />
<row dr="0.15*mm" material="G4_KAPTON" />
<row dr="0.21*mm" material="G4_Cu" />
<row dr="59.22*mm" material="G4_AIR" /> <!-- removed 5 mm to accomadate fat ecal: to be finalised when numbers available -->
<row dr="0.3*mm" material="g10" />
<row dr="0.05*mm" material="G4_KAPTON" />
<row dr="0.01*mm" material="G4_Al" />
</outerWall>
<!-- SQL command: "SELECT * FROM `readout`;" -->
<readout>
......@@ -84,8 +86,7 @@
<readouts>
<readout name="TPCCollection">
<!-- fixme: for now DD4hep cannot handle signed values - side should actually be "-2" -->
<id>system:5,side:2,layer:9,module:8,sensor:8</id>
<id>system:5,side:-2,layer:13,module:8,sensor:8</id>
</readout>
</readouts>
......
<define>
<constant name="TUBE_innerCylinder_zEnd_real" value="500*mm"/>
<constant name="TUBE_innerCylinder_zEnd" value="TUBE_IPInnerTube_end_z"/>
<constant name="TUBE_innerCylinder_rInner" value="TUBE_central_inner_radius"/>
<constant name="TUBE_innerCylinder_thickness" value="TUBE_central_thickness"/>
<constant name="TUBE_firstCone_zEnd_real" value="700*mm"/>
<constant name="TUBE_firstCone_zStart" value="TUBE_innerCylinder_zEnd"/>
<constant name="TUBE_firstCone_zEnd" value="TUBE_IPInnerBulge_end_z"/>
<constant name="TUBE_firstCone_rInnerStart" value="TUBE_innerCylinder_rInner"/>
<constant name="TUBE_firstCone_rInnerEnd" value="TUBE_IPInnerBulge_end_innerradius"/>
<constant name="TUBE_firstCone_thickness" value="0.5*mm"/>
<constant name="TUBE_firstCone_rInnerEnd_real" value="17*mm"/>
<!--
D. Jeans, update april 2017
in this driver, we have to define the what I call the radial thickness
......@@ -25,7 +28,7 @@
<constant name="TUBE_secondCylinder_zStart" value="TUBE_firstCone_zEnd"/>
<constant name="TUBE_secondCylinder_zEnd" value="TUBE_IPOuterTube_end_z"/>
<constant name="TUBE_secondCylinder_rInner" value="TUBE_firstCone_rInnerEnd"/>
<constant name="TUBE_secondCylinder_thickness" value="3*mm"/>
<constant name="TUBE_secondCylinder_thickness" value="0.5*mm"/>
<constant name="TUBE_IPOuterTube_end_radius" value="TUBE_secondCylinder_rInner+TUBE_secondCylinder_thickness"/>
......
<!--
VXD parameters for ILD_o1_v5
-->
<lccdd>
<detectors>
<detector name="VXD" type="VXD04" vis="VXDVis" id="ILDDetID_VXD" limits="Tracker_limits" readout="VXDCollection" insideTrackingVolume="true">
<envelope vis="ILD_VXDVis">
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="Tube" rmin="VXD_inner_radius" rmax="VXD_outer_radius" dz="VXD_half_length" />
<shape type="Tube" rmin="0." rmax="VXD_inner_radius_1" dz="(VXD_half_length - VXD_cone_max_z)/2. + env_safety " />
<position x="0" y="0" z="VXD_half_length-(VXD_half_length - VXD_cone_max_z)/2.+ env_safety"/>
</shape>
<shape type="Tube" rmin="0." rmax="VXD_inner_radius_1" dz="(VXD_half_length - VXD_cone_max_z)/2. + env_safety " />
<position x="0" y="0" z="- ( VXD_half_length-(VXD_half_length - VXD_cone_max_z)/2.+ env_safety ) "/>
<rotation x="0" y="180.*deg" z="0" />
</shape>
<shape type="Cone" rmin1="0" rmax1="VXD_inner_radius" rmin2="0" rmax2="VXD_inner_radius_1"
z="(VXD_cone_max_z-VXD_cone_min_z)/2. + env_safety "/>
<position x="0" y="0" z="VXD_cone_min_z+(VXD_cone_max_z-VXD_cone_min_z)/2."/>
</shape>
<shape type="Cone" rmin1="0" rmax1="VXD_inner_radius" rmin2="0" rmax2="VXD_inner_radius_1"
z="(VXD_cone_max_z-VXD_cone_min_z)/2. + env_safety "/>
<position x="0" y="0" z="-(VXD_cone_min_z+(VXD_cone_max_z-VXD_cone_min_z)/2.)"/>
<rotation x="0" y="180.*deg" z="0" />
</shape>
</envelope>
<!-- set the detecor type flag - note: using the '+' operator here as the evaluator does not understand '|'
-> be carefull not to add any flags twice !!! -->
<type_flags type=" DetType_TRACKER + DetType_PIXEL + DetType_VERTEX "/>
<!-- database : TMP_DB10 -->
<!-- SQL command: "select * from layers_common_parameters;" -->
<layers_common_parameters id="1"
electronics_structure_thickness="0.1*mm"
active_silicon_thickness="0.05*mm"
support_structure_radial_thickness="0.49392*mm"
end_electronics_half_z="5*mm"
strip_final_beampipe_radious="VXD_inner_radius_1"
side_band_electronics_option="1"
end_ladd_electronics_option="1"
side_band_electronics_width="0.5*mm"
side_band_electronics_thickness="0.05*mm"
active_side_band_electronics_option="0"
layer_gap="2*mm"
flex_cable_material="G4_KAPTON"
flex_cable_thickness="0.05*mm"
foam_spacer_material="SiC_foam"
foam_spacer_thickness="0.94*mm"
metal_traces_material="G4_Al"
metal_traces_thickness="0.01*mm"
cool_pipe_material="titanium"
cool_pipe_inner_radius="0.75*mm"
cool_pipe_outer_radius="1*mm"
external_kapton_thickness="0.05*mm"
external_metal_thickness="0.009*mm" />
<!-- SQL command: "SELECT * FROM cryostat;" -->
<cryostat id="1" alu_skin_inner_radious="100*mm" alu_skin_tickness="0.5*mm" foam_inner_radious="90*mm" foam_tickness="10*mm" foam_half_z="166.6*mm"
endplate_inner_radious="VXD_inner_radius_1+5.6*mm"
cryostat_option="1" cryostat_apperture="30*mm" cryostat_apperture_radius="1.5*mm" />
<!-- SQL command: "select * from support_shell;" -->
<support_shell id="0" inner_radious="65*mm" half_z="145*mm" thickess="0.49392*mm" endplate_inner_radious="30*mm" endplate_inner_radius_L1="15.7*mm" endplate_outer_radius_L1="20*mm"
offset_ladder_block="0.28224*mm" beryllium_ladder_block_length="5*mm" beryllium_ladder_block_thickness="0.25*mm" shell_endplate_thickness="2*mm" forward_shell_half_z="6.5*mm" />
<!-- SQL command: "select * from layer;" -->
<layer id="0" layer_radius="VXD_radius_r1" ladder_length="VXD_length_r1" ladder_width="5.5*mm" nb_ladder="10" ladder_gap="0" strip_line_final_z="150*mm" end_electronics_width="5.5*mm"
initial_kapton_striplines_thickness="0.04566*mm" final_kapton_striplines_thickness="0.02435*mm" initial_metal_striplines_thickness="0.00806*mm"
final_metal_striplines_thickness="0.0043*mm" support_width="4.5*mm" />
<layer id="1" layer_radius="VXD_radius_r1" ladder_length="VXD_length_r1" ladder_width="5.5*mm" nb_ladder="10" ladder_gap="0" strip_line_final_z="150*mm" end_electronics_width="5.5*mm"
initial_kapton_striplines_thickness="0.04566*mm" final_kapton_striplines_thickness="0.02435*mm" initial_metal_striplines_thickness="0.00806*mm"
final_metal_striplines_thickness="0.0043*mm" support_width="4.5*mm" />
<layer id="2" layer_radius="VXD_radius_r3" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="11" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04102*mm" final_kapton_striplines_thickness="0.05059*mm" initial_metal_striplines_thickness="0.00724*mm"
final_metal_striplines_thickness="0.00893*mm" support_width="10*mm" />
<layer id="3" layer_radius="VXD_radius_r3" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="11" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04102*mm" final_kapton_striplines_thickness="0.05059*mm" initial_metal_striplines_thickness="0.00724*mm"
final_metal_striplines_thickness="0.00893*mm" support_width="10*mm" />
<layer id="4" layer_radius="VXD_radius_r5" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="17" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04044*mm" final_kapton_striplines_thickness="0.07819*mm" initial_metal_striplines_thickness="0.00714*mm"
final_metal_striplines_thickness="0.0138*mm" support_width="10*mm" />
<layer id="5" layer_radius="VXD_radius_r5" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="17" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04044*mm" final_kapton_striplines_thickness="0.07819*mm" initial_metal_striplines_thickness="0.00714*mm"
final_metal_striplines_thickness="0.0138*mm" support_width="10*mm" />
</detector> <!--vxd-->
</detectors>
<readouts>
<readout name="VXDCollection">
<!-- fixme: for now DD4hep cannot handle signed values - side should actually be "-2" -->
<id>system:5,side:-2,layer:9,module:8,sensor:8,barrelside:-2</id>
</readout>
</readouts>
</lccdd>
<!--
VXD parameters for ILD_o1_v5
-->
<lccdd>
<detectors>
<detector name="VXD" type="VXD04" vis="VXDVis" id="ILDDetID_VXD" limits="Tracker_limits" readout="VXDCollection" insideTrackingVolume="true">
<envelope vis="ILD_VXDVis">
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="Tube" rmin="VXD_inner_radius" rmax="VXD_outer_radius" dz="VXD_half_length" />
<shape type="Tube" rmin="0." rmax="VXD_inner_radius_1" dz="(VXD_half_length - VXD_cone_max_z)/2. + env_safety " />
<position x="0" y="0" z="VXD_half_length-(VXD_half_length - VXD_cone_max_z)/2.+ env_safety"/>
</shape>
<shape type="Tube" rmin="0." rmax="VXD_inner_radius_1" dz="(VXD_half_length - VXD_cone_max_z)/2. + env_safety " />
<position x="0" y="0" z="- ( VXD_half_length-(VXD_half_length - VXD_cone_max_z)/2.+ env_safety ) "/>
<rotation x="0" y="180.*deg" z="0" />
</shape>
<shape type="Cone" rmin1="0" rmax1="VXD_inner_radius" rmin2="0" rmax2="VXD_inner_radius_1"
z="(VXD_cone_max_z-VXD_cone_min_z)/2. + env_safety "/>
<position x="0" y="0" z="VXD_cone_min_z+(VXD_cone_max_z-VXD_cone_min_z)/2."/>
</shape>
<shape type="Cone" rmin1="0" rmax1="VXD_inner_radius" rmin2="0" rmax2="VXD_inner_radius_1"
z="(VXD_cone_max_z-VXD_cone_min_z)/2. + env_safety "/>
<position x="0" y="0" z="-(VXD_cone_min_z+(VXD_cone_max_z-VXD_cone_min_z)/2.)"/>
<rotation x="0" y="180.*deg" z="0" />
</shape>
</envelope>
<!-- set the detecor type flag - note: using the '+' operator here as the evaluator does not understand '|'
-> be carefull not to add any flags twice !!! -->
<type_flags type=" DetType_TRACKER + DetType_PIXEL + DetType_VERTEX "/>
<!-- database : TMP_DB10 -->
<!-- SQL command: "select * from layers_common_parameters;" -->
<layers_common_parameters id="1"
electronics_structure_thickness="0.1*mm"
active_silicon_thickness="0.05*mm"
support_structure_radial_thickness="0.49392*mm"
end_electronics_half_z="5*mm"
strip_final_beampipe_radious="VXD_inner_radius_1"
side_band_electronics_option="1"
end_ladd_electronics_option="1"
side_band_electronics_width="0.5*mm"
side_band_electronics_thickness="0.05*mm"
active_side_band_electronics_option="0"
layer_gap="2*mm"
flex_cable_material="G4_KAPTON"
flex_cable_thickness="0.05*mm"
foam_spacer_material="SiC_foam"
foam_spacer_thickness="0.94*mm"
metal_traces_material="G4_Al"
metal_traces_thickness="0.01*mm"
cool_pipe_material="titanium"
cool_pipe_inner_radius="0.75*mm"
cool_pipe_outer_radius="1*mm"
external_kapton_thickness="0.05*mm"
external_metal_thickness="0.009*mm" />
<!-- SQL command: "SELECT * FROM cryostat;" -->
<cryostat id="1" alu_skin_inner_radious="100*mm" alu_skin_tickness="0.5*mm" foam_inner_radious="90*mm" foam_tickness="10*mm" foam_half_z="166.6*mm"
endplate_inner_radious="VXD_inner_radius_1"
cryostat_option="1" cryostat_apperture="30*mm" cryostat_apperture_radius="1.5*mm" />
<!-- SQL command: "select * from support_shell;" -->
<support_shell id="0" inner_radious="65*mm" half_z="145*mm" thickess="0.49392*mm" endplate_inner_radious="30*mm" endplate_inner_radius_L1="15.7*mm" endplate_outer_radius_L1="20*mm"
offset_ladder_block="0.28224*mm" beryllium_ladder_block_length="5*mm" beryllium_ladder_block_thickness="0.25*mm" shell_endplate_thickness="2*mm" forward_shell_half_z="6.5*mm" />
<!-- SQL command: "select * from layer;" -->
<layer id="0" layer_radius="VXD_radius_r1" ladder_length="VXD_length_r1" ladder_width="5.5*mm" nb_ladder="10" ladder_gap="0" strip_line_final_z="150*mm" end_electronics_width="5.5*mm"
initial_kapton_striplines_thickness="0.04566*mm" final_kapton_striplines_thickness="0.02435*mm" initial_metal_striplines_thickness="0.00806*mm"
final_metal_striplines_thickness="0.0043*mm" support_width="4.5*mm" />
<layer id="1" layer_radius="VXD_radius_r1" ladder_length="VXD_length_r1" ladder_width="5.5*mm" nb_ladder="10" ladder_gap="0" strip_line_final_z="150*mm" end_electronics_width="5.5*mm"
initial_kapton_striplines_thickness="0.04566*mm" final_kapton_striplines_thickness="0.02435*mm" initial_metal_striplines_thickness="0.00806*mm"
final_metal_striplines_thickness="0.0043*mm" support_width="4.5*mm" />
<layer id="2" layer_radius="VXD_radius_r3" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="11" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04102*mm" final_kapton_striplines_thickness="0.05059*mm" initial_metal_striplines_thickness="0.00724*mm"
final_metal_striplines_thickness="0.00893*mm" support_width="10*mm" />
<layer id="3" layer_radius="VXD_radius_r3" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="11" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04102*mm" final_kapton_striplines_thickness="0.05059*mm" initial_metal_striplines_thickness="0.00724*mm"
final_metal_striplines_thickness="0.00893*mm" support_width="10*mm" />
<layer id="4" layer_radius="VXD_radius_r5" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="17" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04044*mm" final_kapton_striplines_thickness="0.07819*mm" initial_metal_striplines_thickness="0.00714*mm"
final_metal_striplines_thickness="0.0138*mm" support_width="10*mm" />
<layer id="5" layer_radius="VXD_radius_r5" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="17" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04044*mm" final_kapton_striplines_thickness="0.07819*mm" initial_metal_striplines_thickness="0.00714*mm"
final_metal_striplines_thickness="0.0138*mm" support_width="10*mm" />
</detector> <!--vxd-->
</detectors>
<readouts>
<readout name="VXDCollection">
<!-- fixme: for now DD4hep cannot handle signed values - side should actually be "-2" -->
<id>system:5,side:-2,layer:9,module:8,sensor:8,barrelside:-2</id>
</readout>
</readouts>
</lccdd>
<!-- VXD parameters for updating new MDI on CEPCv4, only envelope changed-->
<lccdd>
<define>
<constant name="VXD_inner_radius_center" value="BeamPipe_VertexRegion_rmax+env_safety"/>
<constant name="VXD_inner_radius_side" value="BeamPipe_ForwardRegion_rmax+env_safety"/>
</define>
<detectors>
<detector name="VXD" type="VXD04" vis="VXDVis" id="ILDDetID_VXD" limits="Tracker_limits" readout="VXDCollection" insideTrackingVolume="true">
<envelope vis="ILD_VXDVis">
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="BooleanShape" operation="Subtraction" material="Air" >
<shape type="Tube" rmin="VXD_inner_radius_center" rmax="VXD_outer_radius" dz="VXD_half_length" />
<shape type="Tube" rmin="0." rmax="VXD_inner_radius_side" dz="(VXD_half_length - VXD_cone_max_z)/2. + env_safety " />
<position x="0" y="0" z="VXD_half_length-(VXD_half_length - VXD_cone_max_z)/2.+ env_safety"/>
</shape>
<shape type="Tube" rmin="0." rmax="VXD_inner_radius_side" dz="(VXD_half_length - VXD_cone_max_z)/2. + env_safety " />
<position x="0" y="0" z="- ( VXD_half_length-(VXD_half_length - VXD_cone_max_z)/2.+ env_safety ) "/>
<rotation x="0" y="180.*deg" z="0" />
</shape>
<shape type="Cone" rmin1="0" rmax1="VXD_inner_radius_center" rmin2="0" rmax2="VXD_inner_radius_side"
z="(VXD_cone_max_z-VXD_cone_min_z)/2. + env_safety "/>
<position x="0" y="0" z="VXD_cone_min_z+(VXD_cone_max_z-VXD_cone_min_z)/2."/>
</shape>
<shape type="Cone" rmin1="0" rmax1="VXD_inner_radius_center" rmin2="0" rmax2="VXD_inner_radius_side"
z="(VXD_cone_max_z-VXD_cone_min_z)/2. + env_safety "/>
<position x="0" y="0" z="-(VXD_cone_min_z+(VXD_cone_max_z-VXD_cone_min_z)/2.)"/>
<rotation x="0" y="180.*deg" z="0" />
</shape>
</envelope>
<!-- set the detecor type flag - note: using the '+' operator here as the evaluator does not understand '|'
-> be carefull not to add any flags twice !!! -->
<type_flags type=" DetType_TRACKER + DetType_PIXEL + DetType_VERTEX "/>
<!-- database : TMP_DB10 -->
<!-- SQL command: "select * from layers_common_parameters;" -->
<layers_common_parameters id="1"
electronics_structure_thickness="0.1*mm"
active_silicon_thickness="0.05*mm"
support_structure_radial_thickness="0.49392*mm"
end_electronics_half_z="5*mm"
strip_final_beampipe_radious="VXD_inner_radius_1"
side_band_electronics_option="1"
end_ladd_electronics_option="1"
side_band_electronics_width="0.5*mm"
side_band_electronics_thickness="0.05*mm"
active_side_band_electronics_option="0"
layer_gap="2*mm"
flex_cable_material="G4_KAPTON"
flex_cable_thickness="0.05*mm"
foam_spacer_material="SiC_foam"
foam_spacer_thickness="0.94*mm"
metal_traces_material="G4_Al"
metal_traces_thickness="0.01*mm"
cool_pipe_material="titanium"
cool_pipe_inner_radius="0.75*mm"
cool_pipe_outer_radius="1*mm"
external_kapton_thickness="0.05*mm"
external_metal_thickness="0.009*mm" />
<!-- SQL command: "SELECT * FROM cryostat;" -->
<cryostat id="1" alu_skin_inner_radious="100*mm" alu_skin_tickness="0.5*mm" foam_inner_radious="90*mm" foam_tickness="10*mm" foam_half_z="166.6*mm"
endplate_inner_radious="VXD_inner_radius_1+5.6*mm"
cryostat_option="1" cryostat_apperture="30*mm" cryostat_apperture_radius="1.5*mm" />
<!-- SQL command: "select * from support_shell;" -->
<support_shell id="0" inner_radious="65*mm" half_z="145*mm" thickess="0.49392*mm" endplate_inner_radious="30*mm" endplate_inner_radius_L1="15.7*mm" endplate_outer_radius_L1="20*mm"
offset_ladder_block="0.28224*mm" beryllium_ladder_block_length="5*mm" beryllium_ladder_block_thickness="0.25*mm" shell_endplate_thickness="2*mm" forward_shell_half_z="6.5*mm" />
<!-- SQL command: "select * from layer;" -->
<layer id="0" layer_radius="VXD_radius_r1" ladder_length="VXD_length_r1" ladder_width="5.5*mm" nb_ladder="10" ladder_gap="0" strip_line_final_z="150*mm" end_electronics_width="5.5*mm"
initial_kapton_striplines_thickness="0.04566*mm" final_kapton_striplines_thickness="0.02435*mm" initial_metal_striplines_thickness="0.00806*mm"
final_metal_striplines_thickness="0.0043*mm" support_width="4.5*mm" />
<layer id="1" layer_radius="VXD_radius_r1" ladder_length="VXD_length_r1" ladder_width="5.5*mm" nb_ladder="10" ladder_gap="0" strip_line_final_z="150*mm" end_electronics_width="5.5*mm"
initial_kapton_striplines_thickness="0.04566*mm" final_kapton_striplines_thickness="0.02435*mm" initial_metal_striplines_thickness="0.00806*mm"
final_metal_striplines_thickness="0.0043*mm" support_width="4.5*mm" />
<layer id="2" layer_radius="VXD_radius_r3" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="11" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04102*mm" final_kapton_striplines_thickness="0.05059*mm" initial_metal_striplines_thickness="0.00724*mm"
final_metal_striplines_thickness="0.00893*mm" support_width="10*mm" />
<layer id="3" layer_radius="VXD_radius_r3" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="11" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04102*mm" final_kapton_striplines_thickness="0.05059*mm" initial_metal_striplines_thickness="0.00724*mm"
final_metal_striplines_thickness="0.00893*mm" support_width="10*mm" />
<layer id="4" layer_radius="VXD_radius_r5" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="17" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04044*mm" final_kapton_striplines_thickness="0.07819*mm" initial_metal_striplines_thickness="0.00714*mm"
final_metal_striplines_thickness="0.0138*mm" support_width="10*mm" />
<layer id="5" layer_radius="VXD_radius_r5" ladder_length="VXD_length_r3" ladder_width="11*mm" nb_ladder="17" ladder_gap="0*mm" strip_line_final_z="150*mm" end_electronics_width="11*mm"
initial_kapton_striplines_thickness="0.04044*mm" final_kapton_striplines_thickness="0.07819*mm" initial_metal_striplines_thickness="0.00714*mm"
final_metal_striplines_thickness="0.0138*mm" support_width="10*mm" />
</detector> <!--vxd-->
</detectors>
<readouts>
<readout name="VXDCollection">
<!-- fixme: for now DD4hep cannot handle signed values - side should actually be "-2" -->
<id>system:5,side:-2,layer:9,module:8,sensor:8,barrelside:-2</id>
</readout>
</readouts>
</lccdd>
<define>
<constant name="Yoke_cells_size" value="30*mm"/>
<constant name="Yoke_barrel_inner_radius" value="Yoke_inner_radius"/>
<constant name="Hcal_Yoke_plug_gap" value="45*mm"/>
</define>
......
......@@ -136,8 +136,6 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
string det_name = x_det.nameStr();
Layering layering (element);
Material carbon_fibre = theDetector.material("CarbonFiber");
int det_id = x_det.id();
DetElement sdet (det_name,det_id);
......@@ -193,6 +191,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
double Ecal_radiator_thickness3 = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness");
// CF support dimensions
std::string Ecal_support_material = theDetector.constant<string>("Ecal_support_material");
double Ecal_support_thickness = theDetector.constant<double>("Ecal_support_thickness");
double Ecal_front_face_thickness = theDetector.constant<double>("Ecal_front_face_thickness");
double Ecal_lateral_face_thickness = theDetector.constant<double>("Ecal_lateral_face_thickness");
......@@ -231,6 +230,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
}
//---------------------------------
Material carbon_fibre = theDetector.material(Ecal_support_material);
// set up the helper, which will make a module for us
......@@ -258,7 +258,12 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
Ecal_fiber_thickness_alveolus, // N_FIBERS_ALVEOLUS*Ecal_fiber_thickness,
Ecal_front_face_thickness,
Ecal_support_thickness);
cout << "SEcal05_Barrel: CF "
<< Ecal_fiber_thickness_structure/dd4hep::mm << " mm "
<< Ecal_fiber_thickness_alveolus/dd4hep::mm << " mm "
<< Ecal_front_face_thickness/dd4hep::mm << " mm "
<< Ecal_support_thickness/dd4hep::mm << " mm " << endl;
helper.setPlugLength( Ecal_plugLength );
// check resulting thickness is consistent with what's in compact description
......@@ -320,7 +325,8 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
// double min_dim_x = max_dim_x - 2*module_thickness; // shorter one (assumes octagon)
// double max_dim_x = 2. * tan(M_PI/nsides) * Ecal_inner_radius + module_thickness_noSupport / tan( 2*M_PI/nsides ); // longest side
double max_dim_x = 2. * tan(M_PI/nsides) * Ecal_inner_radius + module_thickness_noSupport / sin( 2*M_PI/nsides ); // longest side : fix DJeans 03/2017
//double max_dim_x = 2. * tan(M_PI/nsides) * Ecal_inner_radius + module_thickness_noSupport / sin( 2*M_PI/nsides ); // longest side : fix DJeans 03/2017
double max_dim_x = 2. * tan(M_PI/nsides) * Ecal_inner_radius + module_thickness / sin( 2*M_PI/nsides ); // in order to same as MokkaC's CEPC_v4, fucd
double min_dim_x = max_dim_x - 2*module_thickness/tan( 2*M_PI/nsides ) ; // shorter one
if ( min_dim_x<0 || max_dim_x<0 ) {
......@@ -388,7 +394,8 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
// altered to get alignment as in ECAL interface design doc fig10
// end of slabs aligned to inner face of support plate in next stave (not the outer surface)
// double Y = (module_thickness/2.) / sin(M_PI/4.);
double Y = (module_thickness_noSupport/2.) / sin(2.*M_PI/nsides);
// double Y = (module_thickness_noSupport/2.) / sin(2.*M_PI/nsides);
double Y = -(module_thickness/2.) / sin(2.*M_PI/nsides);
// stave numbering from 1->8
// stave = 1 is in +ve x direction
......@@ -415,7 +422,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
for (int imodule = 0; imodule < Ecal_barrel_z_modules; imodule++) {
int module_id = imodule+1;
Transform3D tr( RotationZYX( 0 , phirot, M_PI/2.), // magic rotation!
Transform3D tr( RotationZYX( M_PI , phirot, M_PI/2.), // magic rotation!
Translation3D(
( X*cos(phirot2)-Y*sin(phirot2) ) ,
( X*sin(phirot2)+Y*cos(phirot2) ) ,
......
......@@ -121,7 +121,6 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
Layering layering (element);
Material air = theDetector.air();
Material CF = theDetector.material("CarbonFiber");
int det_id = x_det.id();
xml_comp_t x_staves = x_det.staves();
......@@ -164,6 +163,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
double Ecal_radiator_thickness3 = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness");
double Ecal_Barrel_halfZ = theDetector.constant<double>("Ecal_Barrel_halfZ");
std::string Ecal_support_material = theDetector.constant<string>("Ecal_support_material");
double Ecal_support_thickness = theDetector.constant<double>("Ecal_support_thickness");
double Ecal_front_face_thickness = theDetector.constant<double>("Ecal_front_face_thickness");
double Ecal_lateral_face_thickness = theDetector.constant<double>("Ecal_lateral_face_thickness");
......@@ -185,11 +185,15 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
double EcalEndcapRing_max_z = theDetector.constant<double>("EcalEndcapRing_max_z");
double crossing_angle = theDetector.constant<double>("CepC_Main_Crossing_Angle");
//double crossing_angle = theDetector.constant<double>("CepC_Main_Crossing_Angle");
double crossing_angle = theDetector.constant<double>("Ecal_ECRing_Crossing_Angle");
bool Ecal_Barrel_PreshowerLayer = theDetector.constant<int>("Ecal_Barrel_Preshower") > 0;
double Ecal_barrel_thickness = theDetector.constant<double>("Ecal_barrel_thickness");
Material CF = theDetector.material(Ecal_support_material);
//========== fill data for reconstruction ============================
dd4hep::rec::LayeredCalorimeterData* caloData = new dd4hep::rec::LayeredCalorimeterData ;
caloData->layoutType = dd4hep::rec::LayeredCalorimeterData::EndcapLayout ;
......@@ -203,7 +207,8 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
caloData->extent[2] = EcalEndcapRing_min_z ;
caloData->extent[3] = EcalEndcapRing_max_z ;
cout << " Z: " << EcalEndcapRing_min_z << " -> " << EcalEndcapRing_max_z << endl;
cout << " R: " << EcalEndcapRing_inner_radius << " -> " << EcalEndcapRing_outer_radius << endl;
//====================================================================
//
// general calculated parameters
......@@ -257,7 +262,6 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
std::cout << " module_thickness = " << module_thickness << std::endl;
#endif
double ECRingSiplateSize = Ecal_endcap_center_box_size
- 2 * Ecal_EC_Ring_gap
- 2 * Ecal_lateral_face_thickness;
......@@ -295,7 +299,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
SubtractionSolid ECRingSolid( CenterECBox, CenterECTub, hole_position);
// Volume EnvLogECRing("ECRing",ECRingSolid,theDetector.material("g10"));
Volume EnvLogECRing("ECRing",ECRingSolid,theDetector.material("CarbonFiber")); // DJeans 5-sep-2016
Volume EnvLogECRing("ECRing",ECRingSolid,theDetector.material(Ecal_support_material)); // DJeans 5-sep-2016
//==============================================================
// build the layer and place into the ECRing
......@@ -401,7 +405,7 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
// #########################
Tube CenterECTubForSi(0.,
Lcal_outer_radius + Ecal_Lcal_ring_gap + 0.001, // + tolerance,
Lcal_outer_radius + Ecal_Lcal_ring_gap + 1e-9*dd4hep::mm, //0.001, // + tolerance,
module_thickness,
0.,
2 * M_PI);
......
......@@ -130,7 +130,8 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
double Ecal_Barrel_halfZ = theDetector.constant<double>("Ecal_Barrel_halfZ");
int Ecal_barrel_number_of_towers = theDetector.constant<int>("Ecal_barrel_number_of_towers");
std::string Ecal_support_material = theDetector.constant<string>("Ecal_support_material");
double Ecal_support_thickness = theDetector.constant<double>("Ecal_support_thickness");
double Ecal_front_face_thickness = theDetector.constant<double>("Ecal_front_face_thickness");
double Ecal_lateral_face_thickness = theDetector.constant<double>("Ecal_lateral_face_thickness");
......@@ -248,12 +249,24 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
// check that resulting quadrant size is consistent with compact description
// here we assume that the width of an alveolus in the endcaps is the same as that in the barrel.
double barrel_alv_width = ( Ecal_Barrel_halfZ*2./Ecal_barrel_z_modules - 2.*Ecal_lateral_face_thickness ) / Ecal_barrel_number_of_towers;
/*
double calc_endcap_rout(EcalEndcap_inner_radius);
for (size_t i=0; i<ntowers.size(); i++) {
calc_endcap_rout+=ntowers[i]*barrel_alv_width + 2.*Ecal_lateral_face_thickness;
}
cout << "alveolus width = " << barrel_alv_width << endl;
*/
// varied endcap alveolus same as MokkaC's CEPC_v4, fucd
// alveolus_dim_z in order to match, in fact, barrel_alv_width is okay.
double alveolus_dim_z = barrel_alv_width - 2 * Ecal_fiber_thickness_alveolus - 2 * Ecal_Slab_H_fiber_thickness - 2 * Ecal_Slab_shielding;
double calc_endcap_rout = EcalBarrel_inner_radius + module_thickness + Ecal_endcap_extra_size;
double endcap_y_botton = EcalEndcap_inner_radius + Ecal_lateral_face_thickness;
double endcap_y_top = calc_endcap_rout - Ecal_lateral_face_thickness;
double endcap_y_height = endcap_y_top - endcap_y_botton;
double endcap_alv_n = int((endcap_y_height/alveolus_dim_z) + 0.5);
//double endcap_alv_width = endcap_y_height/endcap_alv_n - 2 * Ecal_fiber_thickness_alveolus - 2 * Ecal_Slab_H_fiber_thickness - 2 * Ecal_Slab_shielding;
double endcap_alv_width = endcap_y_height/endcap_alv_n;
// compare calculated size vs that in compact description
if ( fabs( calc_endcap_rout - EcalEndcap_outer_radius ) > 0.1*dd4hep::mm ) {
......@@ -266,9 +279,9 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
helper.setTowersUnits( ntowers,
barrel_alv_width,
endcap_alv_width, //barrel_alv_width,
Ecal_n_wafers_per_tower,
Ecal_lateral_face_thickness,
0, //Ecal_lateral_face_thickness,
Ecal_fiber_thickness_alveolus + Ecal_Slab_H_fiber_thickness + Ecal_Slab_shielding,
Ecal_guard_ring_size );
......@@ -288,14 +301,16 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
PolyhedraRegular ECPolyHedra(8, M_PI/8., 0., calc_endcap_rout, module_thickness);
// take just one quadrant of the octagon, and remove the centre box
double quadr = calc_endcap_rout; // anything which is big enough
Box quadrant( quadr, quadr , module_thickness);
IntersectionSolid EndCapSolid( ECPolyHedra,
quadrant,
Position( quadr - EcalEndcap_inner_radius,
quadr + EcalEndcap_inner_radius, 0 ) );
Volume EnvLogEndCap("EcalEndcapQuadrant",EndCapSolid,theDetector.material("CarbonFiber"));
Volume EnvLogEndCap("EcalEndcapQuadrant",EndCapSolid,theDetector.material(Ecal_support_material));
// kink position wrt bottom of quadrant (inside the lateral support)
// Y==0 is defined as outer edge of lateral face of inner module of quadrant
......@@ -303,11 +318,11 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
helper.setModuleDimensions(1, // xytype
0, // xztype
calc_endcap_rout + EcalEndcap_inner_radius, // dxMax
calc_endcap_rout + EcalEndcap_inner_radius - 2*Ecal_lateral_face_thickness, // dxMax
kink_y
);
helper.setTranslation ( Position ( -EcalEndcap_inner_radius , EcalEndcap_inner_radius, -module_thickness/2. ) );
helper.setTranslation ( Position ( -EcalEndcap_inner_radius , EcalEndcap_inner_radius + Ecal_lateral_face_thickness, -module_thickness/2. ) );
// make the module
......@@ -315,13 +330,13 @@ static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDete
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
DetElement mod_det ("quad0",det_id);
helper.makeModule( EnvLogEndCap,
mod_det,
*caloData,
theDetector,
sens );
for (size_t i=0; i<caloData->layers.size(); i++) {
caloData->layers[i].distance += Ecal_Barrel_halfZ + Ecal_cables_gap; // add IP->front face distance
}
......
......@@ -149,6 +149,7 @@ std::vector <SEcal05_Helpers::dimposXYStruct> SEcal05_Helpers::getAbsPlateXYDime
ss.posY = _module_dY_total/2.;
absorbersheets.push_back(ss);
}
return absorbersheets;
}
......@@ -205,8 +206,7 @@ std::vector <SEcal05_Helpers::dimposXYStruct> SEcal05_Helpers::getSlabXYDimensio
ss.posX = ss.sizeX/2.; // this aligns the -X end of slab
ss.sizeX -= _plugLength; // DANIELHACK
ss.posX += _plugLength/2.; // DANIELHACK
ss.posX += _plugLength/2.; // DANIELHACK
} else {
cout << " SEcal05_Helpers ERROR _module_XYtype = " << _module_XYtype << "!!!" << endl;
assert(0);
......@@ -409,7 +409,7 @@ void SEcal05_Helpers::makeModule( dd4hep::Volume & mod_vol, // the volume we'll
int det_id = _x_det->id();
xml_comp_t x_staves = _x_det->staves();
_carbon_fibre_material = theDetector.material("CarbonFiber");
_carbon_fibre_material = theDetector.material(theDetector.constant<std::string>("Ecal_support_material"));
_radiator_material = theDetector.material(x_staves.materialStr());
_air_material = theDetector.air();
......@@ -511,7 +511,6 @@ void SEcal05_Helpers::makeModule( dd4hep::Volume & mod_vol, // the volume we'll
// Position the layer.
dd4hep::Position bsl_pos = getTranslatedPosition(plSize.posX, plSize.posY, currentLayerBase_pos_Z + rad_pos_Z );
// dd4hep::PlacedVolume barrelStructureLayer_phv =
mod_vol.placeVolume(barrelStructureLayer_vol, bsl_pos);
} // loop over sheets
......@@ -580,11 +579,9 @@ void SEcal05_Helpers::makeModule( dd4hep::Volume & mod_vol, // the volume we'll
for (size_t islab = 0; islab<slabDims.size(); islab++) {
myLayerNumTemp = myLayerNum;
double slab_dim_X = slabDims[islab].sizeX;
double slab_dim_Y = slabDims[islab].sizeY - 2.*_towerGap; //fucd
// make an air volume for the alveolus
dd4hep::Box l_box( slab_dim_X/2. ,
slabDims[islab].sizeY/2. - _CF_alvWall,
slab_dim_Z/2. );
dd4hep::Box l_box( slab_dim_X/2., slab_dim_Y/2, slab_dim_Z/2. );
dd4hep::Volume l_vol( _det_name+"_alveolus_"+l_name, l_box, _air_material);
l_vol.setVisAttributes(theDetector.visAttributes( "GrayVis" ) );
......@@ -607,10 +604,10 @@ void SEcal05_Helpers::makeModule( dd4hep::Volume & mod_vol, // the volume we'll
dd4hep::Material slice_material = theDetector.material( x_slice.materialStr() );
std::string vis_str = x_slice.visStr();
if ( !x_slice.isSensitive() ) { // not the sensitive slice: just a layer of stuff
dd4hep::Box s_box( slab_dim_X/2. , slabDims[islab].sizeY/2. - _CF_alvWall, s_thick/2. );
dd4hep::Box s_box( slab_dim_X/2. , slab_dim_Y/2, s_thick/2. );
dd4hep::Volume s_vol(_det_name+"_"+l_name+"_"+s_name, s_box, slice_material);
s_vol.setVisAttributes(theDetector.visAttributes( vis_str ));
......@@ -619,12 +616,16 @@ void SEcal05_Helpers::makeModule( dd4hep::Volume & mod_vol, // the volume we'll
l_vol.placeVolume(s_vol, s_pos );
} else { // sensitive slice
dd4hep::Box s_box( slab_dim_X/2. , slab_dim_Y/2, s_thick/2. );
dd4hep::Volume s_vol(_det_name+"_"+l_name+"_"+s_name, s_box, slice_material);
s_vol.setVisAttributes(theDetector.visAttributes( vis_str ));
dd4hep::Position s_pos( 0, 0, s_pos_Z + s_thick/2. );
l_vol.placeVolume(s_vol, s_pos );
// Normal squared wafers - this is just the sensitive part
// square piece of silicon, not including guard ring. guard ring material is not included
dd4hep::Box WaferSiSolid( unit_sensitive_dim_Y/2., unit_sensitive_dim_Y/2., s_thick/2.);
// get the standard cell size in X for this layer
double cell_size_x = waferSeg ? waferSeg->cellDimensions(0)[0] : megatileSeg->cellDimensions(myLayerNumTemp, 0)[0];
double cell_size_y = waferSeg ? waferSeg->cellDimensions(0)[1] : megatileSeg->cellDimensions(myLayerNumTemp, 0)[1];
......@@ -682,8 +683,10 @@ void SEcal05_Helpers::makeModule( dd4hep::Volume & mod_vol, // the volume we'll
WaferSiLog.setVisAttributes(theDetector.visAttributes( wafer_vis_str ));
WaferSiLog.setSensitiveDetector(sens);
dd4hep::Position w_pos(wafer_pos_X + megatile_size_x/2., wafer_pos_Y, s_pos_Z + s_thick/2. );
dd4hep::PlacedVolume wafer_phv = l_vol.placeVolume(WaferSiLog, w_pos );
//dd4hep::Position w_pos(wafer_pos_X + megatile_size_x/2., wafer_pos_Y, s_pos_Z + s_thick/2. );
//dd4hep::PlacedVolume wafer_phv = l_vol.placeVolume(WaferSiLog, w_pos );
dd4hep::Position w_pos(wafer_pos_X + megatile_size_x/2., wafer_pos_Y, 0);
dd4hep::PlacedVolume wafer_phv = s_vol.placeVolume(WaferSiLog, w_pos );
wafer_phv.addPhysVolID("wafer", wafer_num);
wafer_phv.addPhysVolID("layer", myLayerNumTemp );
......
//====================================================================
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDSegmentation/TiledLayerGridXY.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::RotationZ;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "--------------------------" << endl;
cout << "creating SHcalRpc01_Barrel" << endl;
cout << "--------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id);
Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, element , det ) ;
dd4hep::xml::setDetectorTypeFlag(element, det) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
sens.setType("calorimeter");
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
dd4hep::DDSegmentation::TiledLayerGridXY* tiledSeg = dynamic_cast<dd4hep::DDSegmentation::TiledLayerGridXY*> (seg.segmentation());
assert(tiledSeg && "no TiledLayerGridXY found" );
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeZ = cellSizeVector[1];
double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius_set = theDetector.constant<double>("Hcal_outer_radius");
double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_inner_symmetry = theDetector.constant<int>("Hcal_inner_symmetry");
int Hcal_outer_symmetry = 0;
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_modules_gap = theDetector.constant<double>("Hcal_modules_gap");
double Ecal_outer_radius = theDetector.constant<double>("Ecal_outer_radius");
int Hcal_barrel_number_modules = theDetector.constant<int>("Hcal_barrel_number_modules");
double hPrime = Ecal_outer_radius + theDetector.constant<double>("Hcal_Ecal_gap");
Hcal_inner_radius = hPrime / cos(pi/8.);
double Hcal_normal_dim_z = (2*Hcal_half_length - (Hcal_barrel_number_modules-1)*Hcal_modules_gap)/Hcal_barrel_number_modules;
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
int Hcal_nlayers = x_layer.repeat();
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " cell size xy = " << cell_sizeX << " cell size z = " << cell_sizeZ << endl;
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int MinNumCellsInTransvPlane = theDetector.constant<int>("Hcal_MinNumCellsInTransvPlane");
double RPC_EdgeWidth = theDetector.constant<double>("Hcal_gas_edge_width");
double RPCGazInletInnerRadius = theDetector.constant<double>("Hcal_gasInlet_inner_radius");
double RPCGazInletOuterRadius = theDetector.constant<double>("Hcal_gasInlet_outer_radius");
double RPCGazInletLength = theDetector.constant<double>("Hcal_gasInlet_length");
double RPC_PadSeparation = theDetector.constant<double>("Hcal_pad_separation");
double Hcal_spacer_thickness = theDetector.constant<double>("Hcal_spacer_thickness");
double Hcal_spacer_separation = theDetector.constant<double>("Hcal_spacer_separation");
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
caloData->inner_symmetry = Hcal_inner_symmetry ;
caloData->outer_symmetry = Hcal_outer_symmetry ;
caloData->phi0 = 0 ; // fg: also hardcoded below
// general calculated parameters
double AngleRatio=0.76536686;//"k"
double d_InnerOctoSize=AngleRatio*Hcal_inner_radius;//"d"
double LMin = 2*RPC_EdgeWidth+cell_sizeX*MinNumCellsInTransvPlane+(MinNumCellsInTransvPlane+1)*RPC_PadSeparation;
double Ynl = 0.5*d_InnerOctoSize - Hcal_nlayers*layerThickness;
double Hcal_outer_radius = sqrt((LMin-Ynl)*(LMin-Ynl) + (hPrime + Hcal_nlayers*layerThickness)*(hPrime + Hcal_nlayers*layerThickness));
if(Hcal_outer_radius!=Hcal_outer_radius_set){
cout << "calculated Hcal_outer_radius != input, will impact HcalEndcap and HcalEndcapRing. Hcal_outer_radius = " << Hcal_outer_radius
<< " but set as " << Hcal_outer_radius_set << " difference = " << Hcal_outer_radius-Hcal_outer_radius_set << endl;
}
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in cm.
caloData->extent[0] = Hcal_inner_radius ;
caloData->extent[1] = Hcal_outer_radius ;
caloData->extent[2] = 0. ; // Barrel zmin is "0" by default.
caloData->extent[3] = Hcal_half_length ;
double Hcal_total_dim_y = Hcal_outer_radius - hPrime;
// the y_dim1_for_z kept as the original value in TDR
double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z - 2 *(Hcal_lateral_plate_thickness);
//int N_cells_z = static_cast <int> ( (Hcal_regular_chamber_dim_z - 2*RPC_EdgeWidth - RPC_PadSeparation) / (Hcal_cell_dim_x + RPC_PadSeparation) );
// Hcal_cell_dim_z=(Hcal_regular_chamber_dim_z-RPC_PadSeparation )/N_cells_z
// - RPC_PadSeparation;
Tube solidCaloTube(0, Hcal_outer_radius, Hcal_half_length);
PolyhedraRegular solidOctogon(8, 0, hPrime, 4*Hcal_half_length);
RotationZYX rotOctogon(dd4hep::twopi/16,0,0);
SubtractionSolid solidCalo(solidCaloTube, solidOctogon, rotOctogon);
Volume logicCalo(name+"_radiator", solidCalo, stavesMaterial);
logicCalo.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
PlacedVolume calo_pv = envelope.placeVolume(logicCalo, Position(0,0,0));
DetElement calo(det, "envelope", det_id);
calo.setPlacement(calo_pv);
if(tiledSeg) tiledSeg->setOffsetY(-(Hcal_regular_chamber_dim_z/2.-RPC_EdgeWidth)+0.5*cell_sizeZ);
for(int layer_id=1; layer_id<=Hcal_nlayers; layer_id++){
double yn = sqrt(Hcal_outer_radius*Hcal_outer_radius - (hPrime + layer_id*layerThickness)*(hPrime + layer_id*layerThickness));
double Yn = 0.5*d_InnerOctoSize - layer_id*layerThickness;
double halfX = Hcal_chamber_thickness/2.;
double halfY = (yn+Yn)/2.;
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeZ;
//double halfZ = Hcal_normal_dim_z / 2.;
double halfZ = Hcal_regular_chamber_dim_z / 2.;
double localXPos = hPrime + Hcal_radiator_thickness + Hcal_chamber_thickness/2. + (layer_id-1)*layerThickness;
double localYPos = -Yn + 0.5*(Yn + yn);
Box chamberSolid(halfY, halfZ, halfX);
string chamberLogical_name = name+_toString(layer_id,"_layer%d");
Volume chamberLogical(chamberLogical_name, chamberSolid, air);
chamberLogical.setAttributes(theDetector, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr());
if(tiledSeg) tiledSeg->setLayerOffsetX((-(halfY-RPC_EdgeWidth)+0.5*cell_sizeX)*2/cell_sizeX);
string layer_name = name+_toString(layer_id,"_layer%d");
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
nRadiationLengths = Hcal_radiator_thickness/(stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness/(stavesMaterial.intLength());
double slice_pos_z = -halfX;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
string slice_name = layer_name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
if(layer_id==1) cout<<" Layer_slice: "<< slice_name<<" slice_thickness: "<< slice_thickness<< endl;
slice_pos_z += slice_thickness/2.;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// Slice volume & box
Box sliceSolid(halfY, halfZ, slice_thickness/2.);
Volume sliceVol(slice_name, sliceSolid, slice_material);
if ( x_slice.isSensitive() ) {
sliceVol.setSensitiveDetector(sens);
if(RPC_EdgeWidth>0){
double RPC_GazInlet_In_Z = halfZ - RPC_EdgeWidth - RPCGazInletOuterRadius;
double RPC_GazInlet_In_Y = halfY - RPC_EdgeWidth/2;
double RPC_GazInlet_Out_Z = -RPC_GazInlet_In_Z;
double RPC_GazInlet_Out_Y = RPC_GazInlet_In_Y;
string mateialName = x_slice.attr<string>(_Unicode(edge_material));
Material edge_material = theDetector.material(mateialName);
Box solidRPCEdge1(halfY, halfZ, slice_thickness/2.);
Box solidRPCEdge2(halfY-RPC_EdgeWidth, halfZ-RPC_EdgeWidth, slice_thickness/2.);
SubtractionSolid solidRPCEdge(solidRPCEdge1, solidRPCEdge2, Position(0,0,0));
Volume logicRPCEdge(slice_name+"_edge", solidRPCEdge, edge_material);
logicRPCEdge.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
sliceVol.placeVolume(logicRPCEdge);
RotationZYX rotGaz(0, pi/2., 0);
Tube solidRPCGazInlet(RPCGazInletInnerRadius,RPCGazInletOuterRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInlet(slice_name+"_GazInlet", solidRPCGazInlet, edge_material);
logicRPCGazInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
Tube solidRPCGazInsideInlet(0,RPCGazInletInnerRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInsideInlet(slice_name+"_GazInsideInlet", solidRPCGazInsideInlet, slice_material);
logicRPCGazInsideInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz,Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
}
if(Hcal_spacer_thickness>0){
Tube solidRPCSpacer(0,Hcal_spacer_thickness/2,slice_thickness/2);
Material space_material = theDetector.material(x_slice.attr<string>(_Unicode(spacer_material)));
Volume logicRPCSpacer(slice_name+"_spacer", solidRPCSpacer, space_material);
logicRPCSpacer.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
RotationZYX rotSpacer(0, 0, 0);
double gap_hZ = halfZ-RPC_EdgeWidth;
double gap_hY = halfY-RPC_EdgeWidth;
int y_number_of_separations = (int)(2*gap_hY/Hcal_spacer_separation);
int z_number_of_separations = (int)(2*gap_hZ/Hcal_spacer_separation);
double y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
double z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
if(y_lateral_space < Hcal_spacer_thickness/2.){
y_number_of_separations = (int)((2*gap_hY-Hcal_spacer_thickness)/Hcal_spacer_separation);
y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
}
if(z_lateral_space < Hcal_spacer_thickness/2.){
z_number_of_separations = (int)((2*gap_hZ-Hcal_spacer_thickness)/Hcal_spacer_separation);
z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
}
for(int y_counter = 0; y_counter <=y_number_of_separations; y_counter++){
double SpacerY = gap_hY - y_lateral_space - y_counter*Hcal_spacer_separation;
for(int z_counter = 0; z_counter <=z_number_of_separations; z_counter++){
double SpacerZ = gap_hZ - z_lateral_space - z_counter*Hcal_spacer_separation;
PlacedVolume space_pv = sliceVol.placeVolume(logicRPCSpacer, Transform3D(rotSpacer, Position(SpacerY,SpacerZ,0)));
}
}
}
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
if(layer_id==1) cout<<"Hcal_Barrel: inner_thickness= "<<thickness_sum<<endl;
//Store readout gasgap thickness
caloLayer.sensitive_thickness = slice_thickness;
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
}
else{
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
}
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// slice PlacedVolume
PlacedVolume slice_phv = chamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
if ( x_slice.isSensitive() ) {
int slice_id = (layer_id > Hcal_nlayers)? 1:-1;
slice_phv.addPhysVolID("layer",layer_id).addPhysVolID("slice",slice_id);
}
DetElement sliceDetE(layer_name,_toString(slice_number,"slice%d"),x_det.id());
sliceDetE.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
if(layer_id==1) cout << "Hcal_Barrel: outer_thickness= " << thickness_sum << endl;
double chamber_y_offset = -(-Hcal_total_dim_y/2. + (layer_id-1)*layerThickness + layerThickness/2.);
caloLayer.distance = Hcal_inner_radius + Hcal_total_dim_y/2.0 + chamber_y_offset ;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
double stave_phi_offset, module_z_offset;
stave_phi_offset = pi*0.5;
for(int stave_id = 1; stave_id <= 8; stave_id++){
double phirot = stave_phi_offset+(stave_id-1)*pi/4.;
RotationZYX rot(pi/2, pi/2, 0); //phirot);
RotationZ rotZ(phirot);
RotationZYX rotAll = rotZ*rot;
RotationZYX rotInverse(phirot, 0, 0);
for(int module_id = 1; module_id <= Hcal_barrel_number_modules; module_id++){
module_z_offset = - Hcal_half_length + Hcal_normal_dim_z/2. + (module_id-1)*(Hcal_normal_dim_z+Hcal_modules_gap);
Position localPos(localXPos,localYPos,module_z_offset);
Position newPos = rotInverse*localPos;
Transform3D tran3D(rotAll, newPos);
PlacedVolume pv = logicCalo.placeVolume(chamberLogical, tran3D);
pv.addPhysVolID("stave",stave_id).addPhysVolID("module",module_id).addPhysVolID("layer",layer_id);
DetElement layer(calo, name+_toString(stave_id,"_stave%d")+_toString(module_id,"_module%d")+_toString(layer_id,"_layer%d"), det_id);
layer.setPlacement(pv);
}
}
}
det.addExtension< LayeredCalorimeterData >( caloData ) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc01_Barrel, create_detector)
//====================================================================
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::IntersectionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "------------------------------" << endl;
cout << "creating SHcalRpc01_EndcapRing" << endl;
cout << "------------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id) ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , det ) ;
dd4hep::xml::setDetectorTypeFlag( element, det ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
sens.setType("calorimeter");
DetElement module(det,"module0",det_id);
DetElement layer(module, "stave_layer", det_id);
DetElement slice(layer, "slice", det_id);
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeY = cellSizeVector[1];
double Hcal_outer_radius = theDetector.constant<double>("Hcal_outer_radius");
int Hcal_endcap_outer_symmetry = theDetector.constant<int>("Hcal_endcap_outer_symmetry");
double Hcal_stave_gaps = theDetector.constant<double>("Hcal_stave_gaps");
int Hcal_nlayers = theDetector.constant<int>("Hcal_endcap_nlayers");
double Hcal_start_z = theDetector.constant<double>("Hcal_endcap_zmin");
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Ecal_endcap_zmin = theDetector.constant<double>("Ecal_endcap_zmin");
double Hcal_endcap_ecal_gap = theDetector.constant<double>("Hcal_endcap_ecal_gap");
double Ecal_endcap_outer_radius = theDetector.constant<double>("EcalEndcap_outer_radius");
double Hcal_radial_ring_inner_gap = theDetector.constant<double>("Hcal_radial_ring_inner_gap");
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int numSide = Hcal_endcap_outer_symmetry;
double Hcal_endcap_rmax = Hcal_outer_radius * cos(pi/numSide);
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
caloData->inner_symmetry = numSide;
caloData->outer_symmetry = numSide;
caloData->phi0 = 0;
double start_z = Ecal_endcap_zmin;
double SpaceForLayers = Hcal_start_z - Hcal_endcap_ecal_gap - Ecal_endcap_zmin - 2*Hcal_lateral_plate_thickness;
int MaxNumberOfLayers = (int)(SpaceForLayers / (Hcal_chamber_thickness + Hcal_radiator_thickness));
double stop_z = start_z + MaxNumberOfLayers*layerThickness + 2*Hcal_lateral_plate_thickness;
double pRMax = Hcal_endcap_rmax;
double pDz = (stop_z - start_z)/2.;
double pRMin = Ecal_endcap_outer_radius + Hcal_radial_ring_inner_gap;
cout << "Rings will have " << MaxNumberOfLayers << " layers." << endl;
cout << " Z: " << start_z << " -> " << stop_z << endl;
cout << " R: " << pRMin << " -> " << pRMax << endl;
caloData->extent[0] = pRMin;
caloData->extent[1] = pRMax;
caloData->extent[2] = start_z;
caloData->extent[3] = stop_z;
PolyhedraRegular EndCapRingSolidPoly(numSide, -pi/numSide, pRMin, pRMax, 2*pDz);
Volume EndCapRingLogical(name+"_radiator", EndCapRingSolidPoly, stavesMaterial);
EndCapRingLogical.setAttributes(theDetector,x_staves.regionStr(),x_staves.limitsStr(),x_staves.visStr());
int number_of_chambers = Hcal_nlayers;
if(MaxNumberOfLayers < number_of_chambers) number_of_chambers = MaxNumberOfLayers;
double rInner = pRMin + Hcal_lateral_plate_thickness;
double rOuter = pRMax - Hcal_lateral_plate_thickness;
PolyhedraRegular EndCapRingChamberPoly(numSide, -pi/numSide, rInner, rOuter, Hcal_chamber_thickness);
Box IntersectionStaveBox(rOuter/2., rOuter/2., Hcal_chamber_thickness/2);
Position IntersectPos(rOuter/2. + Hcal_stave_gaps/2., rOuter/2. + Hcal_stave_gaps/2., 0.);
IntersectionSolid EndCapRingStaveSolid(EndCapRingChamberPoly, IntersectionStaveBox, IntersectPos);
Volume EndCapRingChamberLogical(name+"_chamber", EndCapRingStaveSolid, air);
EndCapRingChamberLogical.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
double nRadiationLengthsInside=0.;
double nInteractionLengthsInside=0.;
double inner_thickness=0;
double sensitive_thickness=0;
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
double slice_pos_z = -Hcal_chamber_thickness/2.;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
string slice_name = name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
cout<<" Layer_slice: " << slice_name << " slice_thickness: " << slice_thickness<< endl;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
slice_pos_z += slice_thickness/2.;
PolyhedraRegular slicePoly(numSide, -pi/numSide, rInner, rOuter, slice_thickness);
IntersectionSolid sliceStaveSolid(slicePoly, IntersectionStaveBox, IntersectPos);
Volume sliceVol(name + _toString(slice_number,"_slice%d"), sliceStaveSolid, slice_material);
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
if(x_slice.isSensitive()){
sliceVol.setSensitiveDetector(sens);
nRadiationLengthsInside = nRadiationLengths;
nInteractionLengthsInside = nInteractionLengths;
inner_thickness = thickness_sum;
sensitive_thickness = slice_thickness;
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// slice PlacedVolume
PlacedVolume slice_phv = EndCapRingChamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
//DetElement slice(layer_name,_toString(slice_number,"slice%d"),x_det.id());
slice.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
// chamber placements
for(int stave_id = 1; stave_id <= 4; stave_id++){
double angle = -pi/2.*(stave_id-1);
RotationZYX lrot(angle,0,0);
for (int layer_id = 1; layer_id <= number_of_chambers; layer_id++){
double Zoff = -pDz + (layer_id-1)*layerThickness + Hcal_radiator_thickness + Hcal_chamber_thickness/2.;
Position l_pos(0., 0., Zoff);
Position l_new = lrot*l_pos;
Transform3D ltran3D(lrot,l_new);
PlacedVolume layer_phv = EndCapRingLogical.placeVolume(EndCapRingChamberLogical, ltran3D);
layer_phv.addPhysVolID("layer",layer_id);
layer_phv.addPhysVolID("stave",stave_id);
//string l_name = _toString(layer_id,"layer%d");
//string stave_name = _toString(stave_id,"stave%d");
//DetElement layer(module_det, l_name+stave_name, det_id);
layer.setPlacement(layer_phv);
if(stave_id==1&&layer_id==1){
cout << "Hcal_EndcapRing: inner_thickness= " << inner_thickness << endl;
cout << "Hcal_EndcapRing: outer_thickness= " << thickness_sum << endl;
}
if(stave_id==1){//only one needed, according to wenxingfang's
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
caloLayer.inner_nRadiationLengths = nRadiationLengthsInside;
caloLayer.inner_nInteractionLengths = nInteractionLengthsInside;
caloLayer.inner_thickness = inner_thickness;
caloLayer.sensitive_thickness = sensitive_thickness;
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
caloLayer.distance = start_z + (layer_id-1)*layerThickness;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
}
}
}
// Placements
double endcap_z_offset = start_z + pDz;
for(int side = 0; side <= 1; side++){
int module_id = (side==0) ? 6 : 0;
double this_module_z_offset = (side==0) ? endcap_z_offset : -endcap_z_offset;
// use reflect volume for z<0, therefore, same rotation
// segmentation violation happen if EndCapRingLogical.reflect(), back to rotate Y
// double this_module_rotY = (side==0) ? 0.0 : 0.0;
double this_module_rotY = (side==0) ? 0.0 : pi;
//double this_module_rotZ = (side==0) ? pi/8. : pi/8;
RotationZYX rot(0,this_module_rotY,0);
Transform3D tran3D(rot,Position(0,0,this_module_z_offset));
PlacedVolume module_phv;
//if(side==0) module_phv = envelope.placeVolume(EndCapRingLogical, tran3D);
//else module_phv = envelope.placeVolume(EndCapRingLogical.reflect(), tran3D);
module_phv = envelope.placeVolume(EndCapRingLogical, tran3D);
module_phv.addPhysVolID("module", module_id);
//DetElement sd = (module_id==0) ? module_det : module_det.clone(_toString(side,"module%d"));
module.setPlacement(module_phv);
}
det.addExtension<LayeredCalorimeterData>(caloData) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc01_EndcapRing, create_detector)
//====================================================================
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::IntersectionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "--------------------------" << endl;
cout << "creating SHcalRpc01_Endcap" << endl;
cout << "--------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id) ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , det ) ;
dd4hep::xml::setDetectorTypeFlag( element, det ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
sens.setType("calorimeter");
DetElement module(det,"module0",det_id);
DetElement layer(module, "stave_layer", det_id);
DetElement slice(layer, "slice", det_id);
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeY = cellSizeVector[1];
//double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius = theDetector.constant<double>("Hcal_outer_radius");
//double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_endcap_outer_symmetry = theDetector.constant<int>("Hcal_endcap_outer_symmetry");
//double Hcal_cells_size = theDetector.constant<double>("Hcal_cells_size");
double Hcal_stave_gaps = theDetector.constant<double>("Hcal_stave_gaps");
int Hcal_nlayers = theDetector.constant<int>("Hcal_endcap_nlayers");
double Hcal_start_z = theDetector.constant<double>("Hcal_endcap_zmin");
double Hcal_end_z = theDetector.constant<double>("HcalEndcap_max_z");
double Hcal_back_plate_thickness = theDetector.constant<double>("Hcal_back_plate_thickness");
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_endcap_center_box_size = theDetector.constant<double>("Hcal_endcap_center_box_size");
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int numSide = Hcal_endcap_outer_symmetry;
double Hcal_endcap_thickness = Hcal_nlayers*layerThickness + Hcal_back_plate_thickness;
double Hcal_endcap_rmax = Hcal_outer_radius * cos(pi/numSide);
cout << " module thickness = " << Hcal_endcap_thickness << endl;
if(Hcal_end_z!=Hcal_start_z+Hcal_endcap_thickness){
cout << "Hcal_end_z input != Hcal_start_z + Hcal_endcap_thickness: " << "Hcal_end_z=" << Hcal_end_z
<< " but Hcal_start_z=" << Hcal_start_z << " and calculate as " << Hcal_start_z+Hcal_endcap_thickness << endl;
}
LayeredCalorimeterData* caloData = new LayeredCalorimeterData;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout;
caloData->inner_symmetry = 4;
caloData->outer_symmetry = Hcal_endcap_outer_symmetry;
caloData->phi0 = 0;
caloData->extent[0] = Hcal_endcap_center_box_size/2.;
caloData->extent[1] = Hcal_outer_radius;
caloData->extent[2] = Hcal_start_z;
caloData->extent[3] = Hcal_start_z+Hcal_endcap_thickness;
double pRMax = Hcal_endcap_rmax;
double pDz = Hcal_endcap_thickness/2.;
double pRMin = Hcal_endcap_center_box_size/2.;
PolyhedraRegular EndCapSolidPoly(numSide, -pi/numSide, 0., pRMax, 2*pDz);
Box hcalECInnerHole(pRMin, pRMin, pDz);
SubtractionSolid solidHCalEC(EndCapSolidPoly,hcalECInnerHole);
Volume EndCapLogical(name+"_radiator", solidHCalEC, stavesMaterial);
EndCapLogical.setAttributes(theDetector,x_staves.regionStr(),x_staves.limitsStr(),x_staves.visStr());
int number_of_chambers = Hcal_nlayers;
int possible_number_of_chambers = (int) (floor(abs(Hcal_endcap_thickness-Hcal_back_plate_thickness) / (Hcal_chamber_thickness + Hcal_radiator_thickness)));
if(possible_number_of_chambers < number_of_chambers) number_of_chambers = possible_number_of_chambers;
double rInner = 0.;
double rOuter= Hcal_endcap_rmax - Hcal_lateral_plate_thickness;
PolyhedraRegular EndCapChamberPoly(numSide, -pi/numSide, rInner, rOuter, Hcal_chamber_thickness);
Box hcalECChamberInnerHole(pRMin + Hcal_lateral_plate_thickness, pRMin + Hcal_lateral_plate_thickness, Hcal_chamber_thickness/2);
SubtractionSolid EndCapChamberSolid(EndCapChamberPoly, hcalECChamberInnerHole);
Box IntersectionStaveBox(rOuter/2., rOuter/2., Hcal_chamber_thickness/2);
Position pos(rOuter/2. + Hcal_stave_gaps/2., rOuter/2. + Hcal_stave_gaps/2., 0.);
Position IntersectPos = pos;
IntersectionSolid EndCapStaveSolid(EndCapChamberSolid, IntersectionStaveBox, IntersectPos);
Volume EndCapChamberLogical(name+"_chamber", EndCapStaveSolid, air);
EndCapChamberLogical.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
double nRadiationLengthsInside=0.;
double nInteractionLengthsInside=0.;
double inner_thickness=0;
double sensitive_thickness=0;
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
double slice_pos_z = -Hcal_chamber_thickness/2.;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
string slice_name = name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
cout<<" Layer_slice: " << slice_name << " slice_thickness: " << slice_thickness<< endl;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
slice_pos_z += slice_thickness/2.;
PolyhedraRegular slicePoly(numSide, -pi/numSide, rInner, rOuter, slice_thickness);
SubtractionSolid sliceSolid(slicePoly, hcalECChamberInnerHole);
IntersectionSolid sliceStaveSolid(sliceSolid, IntersectionStaveBox, IntersectPos);
Volume sliceVol(name + _toString(slice_number,"_slice%d"), sliceStaveSolid, slice_material);
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
if(x_slice.isSensitive()){
sliceVol.setSensitiveDetector(sens);
nRadiationLengthsInside = nRadiationLengths;
nInteractionLengthsInside = nInteractionLengths;
inner_thickness = thickness_sum;
sensitive_thickness = slice_thickness;
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// slice PlacedVolume
PlacedVolume slice_phv = EndCapChamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
//DetElement slice(layer_name,_toString(slice_number,"slice%d"),x_det.id());
slice.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
if(possible_number_of_chambers < number_of_chambers) number_of_chambers = possible_number_of_chambers;
// chamber placements
for(int stave_id = 1; stave_id <= 4; stave_id++){
double angle = -pi/2.*(stave_id-1);
//RotationZ lrotz(angle);
RotationZYX lrot(angle,0,0);
for (int layer_id = 1; layer_id <= number_of_chambers; layer_id++){
double Zoff = -Hcal_endcap_thickness/2. + (layer_id-1) *(Hcal_chamber_thickness + Hcal_radiator_thickness) + Hcal_radiator_thickness + Hcal_chamber_thickness/2.;
Position l_pos(0., 0., Zoff);
Position l_new = lrot*l_pos;
Transform3D ltran3D(lrot,l_new);
PlacedVolume layer_phv = EndCapLogical.placeVolume(EndCapChamberLogical, ltran3D);
layer_phv.addPhysVolID("layer",layer_id);
layer_phv.addPhysVolID("stave",stave_id);
//string l_name = _toString(layer_id,"layer%d");
//string stave_name = _toString(stave_id,"stave%d");
//DetElement layer(module_det, l_name+stave_name, det_id);
layer.setPlacement(layer_phv);
if(stave_id==1&&layer_id==1){
cout << "Hcal_Endcap: inner_thickness= " << inner_thickness << endl;
cout << "Hcal_Endcap: outer_thickness= " << thickness_sum << endl;
}
if(stave_id==1){// only for one stave is good. by wenxingfang
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
caloLayer.inner_nRadiationLengths = nRadiationLengthsInside;
caloLayer.inner_nInteractionLengths = nInteractionLengthsInside;
caloLayer.inner_thickness = inner_thickness;
caloLayer.sensitive_thickness = sensitive_thickness;
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
caloLayer.distance = Hcal_start_z + (layer_id-1)*layerThickness;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
}
}
}
// Placements
double endcap_z_offset = Hcal_start_z + Hcal_endcap_thickness/2.;
for(int side = 0; side <= 1; side++){
int module_id = (side==0) ? 6 : 0;
double this_module_z_offset = (side==0) ? endcap_z_offset : -endcap_z_offset;
// use reflect volume for z<0, therefore, same rotation
// segmentation violation happen if EndCapRingLogical.reflect(), back to rotate Y
// double this_module_rotY = (side==0) ? 0.0 : 0.0;
double this_module_rotY = (side==0) ? 0.0 : pi;
//double this_module_rotZ = (side==0) ? pi/8. : pi/8;
RotationZYX rot(0,this_module_rotY,0);
Transform3D tran3D(rot,Position(0,0,this_module_z_offset));
PlacedVolume module_phv;
//if(side==0) module_phv = envelope.placeVolume(EndCapRingLogical, tran3D);
//else module_phv = envelope.placeVolume(EndCapRingLogical.reflect(), tran3D);
module_phv = envelope.placeVolume(EndCapLogical, tran3D);
module_phv.addPhysVolID("module", module_id);
//DetElement sd = (module_id==0) ? module_det : module_det.clone(_toString(side,"module%d"));
module.setPlacement(module_phv);
}
det.addExtension<LayeredCalorimeterData>(caloData) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc01_Endcaps, create_detector)
//====================================================================
// SHcalRpc02 - update fixed 8 staves to optinal staves, FU Chengdong
// SHcalRpc01 - Implementation from ILCSoft's Mokka version
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/DetType.h"
#include "DDSegmentation/TiledLayerGridXY.h"
#include "DDRec/Surface.h"
#include "DDRec/DetectorData.h"
#include "XML/Utilities.h"
using namespace std;
using dd4hep::Ref_t;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::Segmentation;
using dd4hep::Readout;
using dd4hep::Material;
using dd4hep::Volume;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationZYX;
using dd4hep::RotationZ;
using dd4hep::Transform3D;
using dd4hep::Box;
using dd4hep::Tube;
using dd4hep::PolyhedraRegular;
using dd4hep::SubtractionSolid;
using dd4hep::_toString;
using dd4hep::pi;
using dd4hep::rec::LayeredCalorimeterData;
/** Construction of SHcalRpc01 detector, ported from Mokka driver SHcalRpc01.cc
*
* Mokka History:
* - first implementation from ILCSoft
* - http://cepcgit.ihep.ac.cn/cepcsoft/MokkaC
*/
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
cout << "--------------------------" << endl;
cout << "creating SHcalRpc01_Barrel" << endl;
cout << "--------------------------" << endl;
xml_det_t x_det = element;
string name = x_det.nameStr();
int det_id = x_det.id();
DetElement det(name, det_id);
Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, element , det ) ;
envelope.setVisAttributes(theDetector, "GrayVis");
dd4hep::xml::setDetectorTypeFlag(element, det) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return det ;
xml_comp_t x_staves = x_det.staves();
string Hcal_radiator_material = x_staves.materialStr();
Material stavesMaterial = theDetector.material(Hcal_radiator_material);
Material air = theDetector.air();
sens.setType("calorimeter");
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
dd4hep::DDSegmentation::TiledLayerGridXY* tiledSeg = dynamic_cast<dd4hep::DDSegmentation::TiledLayerGridXY*> (seg.segmentation());
assert(tiledSeg && "no TiledLayerGridXY found" );
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0);
double cell_sizeX = cellSizeVector[0];
double cell_sizeZ = cellSizeVector[1];
double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius_set = theDetector.constant<double>("Hcal_outer_radius");
double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_inner_symmetry = theDetector.constant<int>("Hcal_inner_symmetry");
int Hcal_outer_symmetry = 0;
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_modules_gap = theDetector.constant<double>("Hcal_modules_gap");
double Ecal_outer_radius = theDetector.constant<double>("Ecal_outer_radius");
int Hcal_barrel_number_modules = theDetector.constant<int>("Hcal_barrel_number_modules");
double hPrime = Ecal_outer_radius + theDetector.constant<double>("Hcal_Ecal_gap");
Hcal_inner_radius = hPrime / cos(pi/Hcal_inner_symmetry);
double Hcal_normal_dim_z = (2*Hcal_half_length - (Hcal_barrel_number_modules-1)*Hcal_modules_gap)/Hcal_barrel_number_modules;
xml_coll_t c(x_det,_U(layer));
xml_comp_t x_layer = c;
int Hcal_nlayers = x_layer.repeat();
double Hcal_radiator_thickness = 0;
double layerThickness = 0.0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
layerThickness += x_slice.thickness();
if(x_slice.materialStr()==Hcal_radiator_material) Hcal_radiator_thickness = x_slice.thickness();
}
cout << " inner symmetry = " << Hcal_inner_symmetry << endl;
cout << " Hcal_inner_radius = " << hPrime << endl;
cout << " cell size xy = " << cell_sizeX << " cell size z = " << cell_sizeZ << endl;
cout << " layer_thickness (from slices) = " << layerThickness << " and radiator_thickness = " << Hcal_radiator_thickness << endl;
double Hcal_chamber_thickness = layerThickness - Hcal_radiator_thickness;
int MinNumCellsInTransvPlane = theDetector.constant<int>("Hcal_MinNumCellsInTransvPlane");
double RPC_EdgeWidth = theDetector.constant<double>("Hcal_gas_edge_width");
double RPCGazInletInnerRadius = theDetector.constant<double>("Hcal_gasInlet_inner_radius");
double RPCGazInletOuterRadius = theDetector.constant<double>("Hcal_gasInlet_outer_radius");
double RPCGazInletLength = theDetector.constant<double>("Hcal_gasInlet_length");
double RPC_PadSeparation = theDetector.constant<double>("Hcal_pad_separation");
double Hcal_spacer_thickness = theDetector.constant<double>("Hcal_spacer_thickness");
double Hcal_spacer_separation = theDetector.constant<double>("Hcal_spacer_separation");
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
caloData->inner_symmetry = Hcal_inner_symmetry ;
caloData->outer_symmetry = Hcal_outer_symmetry ;
caloData->phi0 = 0 ; // fg: also hardcoded below
// general calculated parameters
double AngleRatio=tan(dd4hep::pi/Hcal_inner_symmetry);
double d_InnerOctoSize=2*AngleRatio*Hcal_inner_radius;//"d"
double LMin = 2*RPC_EdgeWidth+cell_sizeX*MinNumCellsInTransvPlane+(MinNumCellsInTransvPlane+1)*RPC_PadSeparation;
cout << "LMin=" << LMin << endl;
double Ynl = 0.5*d_InnerOctoSize - Hcal_nlayers*layerThickness/tan(dd4hep::twopi/Hcal_inner_symmetry);
double Hcal_outer_radius = sqrt((LMin-Ynl)*(LMin-Ynl) + (hPrime + Hcal_nlayers*layerThickness)*(hPrime + Hcal_nlayers*layerThickness));
if(Hcal_outer_radius!=Hcal_outer_radius_set){
cout << "calculated Hcal_outer_radius != input, will impact HcalEndcap and HcalEndcapRing. Hcal_outer_radius = " << Hcal_outer_radius
<< " but set as " << Hcal_outer_radius_set << " difference = " << Hcal_outer_radius-Hcal_outer_radius_set << endl;
cout << "if Coil put inside of Hcal, it is possible!" << endl;
}
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in cm.
caloData->extent[0] = Hcal_inner_radius ;
caloData->extent[1] = Hcal_outer_radius ;
caloData->extent[2] = 0. ; // Barrel zmin is "0" by default.
caloData->extent[3] = Hcal_half_length ;
double Hcal_total_dim_y = Hcal_outer_radius - hPrime;
// the y_dim1_for_z kept as the original value in TDR
double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z - 2 *(Hcal_lateral_plate_thickness);
//int N_cells_z = static_cast <int> ( (Hcal_regular_chamber_dim_z - 2*RPC_EdgeWidth - RPC_PadSeparation) / (Hcal_cell_dim_x + RPC_PadSeparation) );
// Hcal_cell_dim_z=(Hcal_regular_chamber_dim_z-RPC_PadSeparation )/N_cells_z
// - RPC_PadSeparation;
Tube solidCaloTube(0, Hcal_outer_radius, Hcal_half_length);
PolyhedraRegular solidOctogon(Hcal_inner_symmetry, 0, hPrime, 4*Hcal_half_length);
RotationZYX rotOctogon(dd4hep::twopi/2/Hcal_inner_symmetry,0,0);
SubtractionSolid solidCalo(solidCaloTube, solidOctogon, rotOctogon);
Volume logicCalo(name+"_radiator", solidCalo, stavesMaterial);
logicCalo.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
PlacedVolume calo_pv = envelope.placeVolume(logicCalo, Position(0,0,0));
DetElement calo(det, "envelope", det_id);
calo.setPlacement(calo_pv);
if(tiledSeg) tiledSeg->setOffsetY(-(Hcal_regular_chamber_dim_z/2.-RPC_EdgeWidth)+0.5*cell_sizeZ);
for(int layer_id=1; layer_id<=Hcal_nlayers; layer_id++){
double yn = sqrt(Hcal_outer_radius*Hcal_outer_radius - (hPrime + layer_id*layerThickness)*(hPrime + layer_id*layerThickness));
double Yn = 0.5*d_InnerOctoSize - layer_id*layerThickness/tan(dd4hep::twopi/Hcal_inner_symmetry);
double halfX = Hcal_chamber_thickness/2.;
double halfY = (yn+Yn)/2.;
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeZ;
//double halfZ = Hcal_normal_dim_z / 2.;
double halfZ = Hcal_regular_chamber_dim_z / 2.;
double localXPos = hPrime + Hcal_radiator_thickness + Hcal_chamber_thickness/2. + (layer_id-1)*layerThickness;
double localYPos = -Yn + 0.5*(Yn + yn);
Box chamberSolid(halfY, halfZ, halfX);
string chamberLogical_name = name+_toString(layer_id,"_layer%d");
Volume chamberLogical(chamberLogical_name, chamberSolid, air);
chamberLogical.setAttributes(theDetector, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr());
if(tiledSeg) tiledSeg->setLayerOffsetX((-(halfY-RPC_EdgeWidth)+0.5*cell_sizeX)*2/cell_sizeX);
string layer_name = name+_toString(layer_id,"_layer%d");
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
nRadiationLengths = Hcal_radiator_thickness/(stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness/(stavesMaterial.intLength());
double slice_pos_z = -halfX;
int slice_number = 0;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
if(x_slice.materialStr()==Hcal_radiator_material) continue;
string slice_name = layer_name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
if(layer_id==1) cout<<" Layer_slice: "<< slice_name<<" slice_thickness: "<< slice_thickness<< endl;
slice_pos_z += slice_thickness/2.;
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// Slice volume & box
Box sliceSolid(halfY, halfZ, slice_thickness/2.);
Volume sliceVol(slice_name, sliceSolid, slice_material);
if ( x_slice.isSensitive() ) {
sliceVol.setSensitiveDetector(sens);
if(RPC_EdgeWidth>0){
double RPC_GazInlet_In_Z = halfZ - RPC_EdgeWidth - RPCGazInletOuterRadius;
double RPC_GazInlet_In_Y = halfY - RPC_EdgeWidth/2;
double RPC_GazInlet_Out_Z = -RPC_GazInlet_In_Z;
double RPC_GazInlet_Out_Y = RPC_GazInlet_In_Y;
string mateialName = x_slice.attr<string>(_Unicode(edge_material));
Material edge_material = theDetector.material(mateialName);
Box solidRPCEdge1(halfY, halfZ, slice_thickness/2.);
Box solidRPCEdge2(halfY-RPC_EdgeWidth, halfZ-RPC_EdgeWidth, slice_thickness/2.);
SubtractionSolid solidRPCEdge(solidRPCEdge1, solidRPCEdge2, Position(0,0,0));
Volume logicRPCEdge(slice_name+"_edge", solidRPCEdge, edge_material);
logicRPCEdge.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
sliceVol.placeVolume(logicRPCEdge);
RotationZYX rotGaz(0, pi/2., 0);
Tube solidRPCGazInlet(RPCGazInletInnerRadius,RPCGazInletOuterRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInlet(slice_name+"_GazInlet", solidRPCGazInlet, edge_material);
logicRPCGazInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInlet, Transform3D(rotGaz, Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
Tube solidRPCGazInsideInlet(0,RPCGazInletInnerRadius,RPC_EdgeWidth/*RPCGazInletLength*//2);
Volume logicRPCGazInsideInlet(slice_name+"_GazInsideInlet", solidRPCGazInsideInlet, slice_material);
logicRPCGazInsideInlet.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz, Position(RPC_GazInlet_In_Y,RPC_GazInlet_In_Z, 0)));
logicRPCEdge.placeVolume(logicRPCGazInsideInlet, Transform3D(rotGaz,Position(RPC_GazInlet_Out_Y,RPC_GazInlet_Out_Z, 0)));
}
if(Hcal_spacer_thickness>0){
Tube solidRPCSpacer(0,Hcal_spacer_thickness/2,slice_thickness/2);
Material space_material = theDetector.material(x_slice.attr<string>(_Unicode(spacer_material)));
Volume logicRPCSpacer(slice_name+"_spacer", solidRPCSpacer, space_material);
logicRPCSpacer.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
RotationZYX rotSpacer(0, 0, 0);
double gap_hZ = halfZ-RPC_EdgeWidth;
double gap_hY = halfY-RPC_EdgeWidth;
int y_number_of_separations = (int)(2*gap_hY/Hcal_spacer_separation);
int z_number_of_separations = (int)(2*gap_hZ/Hcal_spacer_separation);
double y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
double z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
if(y_lateral_space < Hcal_spacer_thickness/2.){
y_number_of_separations = (int)((2*gap_hY-Hcal_spacer_thickness)/Hcal_spacer_separation);
y_lateral_space = (2*gap_hY - y_number_of_separations*Hcal_spacer_separation)/2;
}
if(z_lateral_space < Hcal_spacer_thickness/2.){
z_number_of_separations = (int)((2*gap_hZ-Hcal_spacer_thickness)/Hcal_spacer_separation);
z_lateral_space = (2*gap_hZ - z_number_of_separations*Hcal_spacer_separation)/2;
}
for(int y_counter = 0; y_counter <=y_number_of_separations; y_counter++){
double SpacerY = gap_hY - y_lateral_space - y_counter*Hcal_spacer_separation;
for(int z_counter = 0; z_counter <=z_number_of_separations; z_counter++){
double SpacerZ = gap_hZ - z_lateral_space - z_counter*Hcal_spacer_separation;
PlacedVolume space_pv = sliceVol.placeVolume(logicRPCSpacer, Transform3D(rotSpacer, Position(SpacerY,SpacerZ,0)));
}
}
}
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
if(layer_id==1) cout<<"Hcal_Barrel: inner_thickness= "<<thickness_sum<<endl;
//Store readout gasgap thickness
caloLayer.sensitive_thickness = slice_thickness;
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),"SeeThrough");
}
else{
sliceVol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
}
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// slice PlacedVolume
PlacedVolume slice_phv = chamberLogical.placeVolume(sliceVol,Position(0,0,slice_pos_z));
if ( x_slice.isSensitive() ) {
int slice_id = (layer_id > Hcal_nlayers)? 1:-1;
slice_phv.addPhysVolID("layer",layer_id).addPhysVolID("slice",slice_id);
}
DetElement sliceDetE(layer_name,_toString(slice_number,"slice%d"),x_det.id());
sliceDetE.setPlacement(slice_phv);
// Increment x position for next slice.
slice_pos_z += slice_thickness/2.;
// Increment slice number.
++slice_number;
}
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
if(layer_id==1) cout << "Hcal_Barrel: outer_thickness= " << thickness_sum << endl;
double chamber_y_offset = -(-Hcal_total_dim_y/2. + (layer_id-1)*layerThickness + layerThickness/2.);
caloLayer.distance = Hcal_inner_radius + Hcal_total_dim_y/2.0 + chamber_y_offset ;
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
double stave_phi_offset, module_z_offset;
//stave_phi_offset = pi/Hcal_inner_symmetry;
stave_phi_offset = pi*0.5;
for(int stave_id = 1; stave_id <= Hcal_inner_symmetry; stave_id++){
double phirot = stave_phi_offset+(stave_id-1)*pi/Hcal_inner_symmetry*2;
RotationZYX rot(pi/2, pi/2, 0); //phirot);
RotationZ rotZ(phirot);
RotationZYX rotAll = rotZ*rot;
RotationZYX rotInverse(phirot, 0, 0);
for(int module_id = 1; module_id <= Hcal_barrel_number_modules; module_id++){
module_z_offset = - Hcal_half_length + Hcal_normal_dim_z/2. + (module_id-1)*(Hcal_normal_dim_z+Hcal_modules_gap);
Position localPos(localXPos,localYPos,module_z_offset);
Position newPos = rotInverse*localPos;
Transform3D tran3D(rotAll, newPos);
PlacedVolume pv = logicCalo.placeVolume(chamberLogical, tran3D);
pv.addPhysVolID("stave",stave_id).addPhysVolID("module",module_id);//.addPhysVolID("layer",layer_id);
DetElement layer(calo, name+_toString(stave_id,"_stave%d")+_toString(module_id,"_module%d")+_toString(layer_id,"_layer%d"), det_id);
layer.setPlacement(pv);
}
}
}
det.addExtension< LayeredCalorimeterData >( caloData ) ;
return det;
}
DECLARE_DETELEMENT(SHcalRpc02_Barrel, create_detector)
//====================================================================
// DD4hep Geometry driver for HcalBarrel
//--------------------------------------------------------------------
// S.Lu, DESY
// F. Gaede, DESY : v04 : prepare for multi segmentation
// 18.04.2017 - copied from SHcalSc04_Barrel_v01.cpp
// - add optional parameter <subsegmentation key="" value=""/>
// defines the segmentation to be used in reconstruction
//====================================================================
#include "DD4hep/Printout.h"
#include "DD4hep/DetFactoryHelper.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
#include "DDSegmentation/BitField64.h"
#include "DDSegmentation/TiledLayerGridXY.h"
#include "DDSegmentation/Segmentation.h"
#include "DDSegmentation/MultiSegmentation.h"
#include "LcgeoExceptions.h"
#include <iostream>
#include <vector>
using namespace std;
using dd4hep::_toString;
using dd4hep::Box;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::Detector;
using dd4hep::DetElement;
using dd4hep::IntersectionSolid;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::Rotation3D;
using dd4hep::RotationZ;
using dd4hep::RotationZYX;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Trapezoid;
using dd4hep::Tube;
using dd4hep::Volume;
using dd4hep::rec::LayeredCalorimeterData;
// After reading in all the necessary parameters.
// To check the radius range and the space for placing the total layers
static bool validateEnvelope(double rInner, double rOuter, double radiatorThickness, double layerThickness, int layerNumber, int nsymmetry)
{
bool Error = false;
bool Warning = false;
double spaceAllowed = rOuter * cos(M_PI / nsymmetry) - rInner;
double spaceNeeded = (radiatorThickness + layerThickness) * layerNumber;
double spaceToleranted = (radiatorThickness + layerThickness) * (layerNumber + 1);
double rOuterRecommaned = (rInner + spaceNeeded) / cos(M_PI / 16.);
int layerNumberRecommaned = floor((spaceAllowed) / (radiatorThickness + layerThickness));
if (spaceNeeded > spaceAllowed)
{
printout(dd4hep::ERROR, "SHcalSc04_Barrel_v04", " Layer number is more than it can be built! ");
Error = true;
}
else if (spaceToleranted < spaceAllowed)
{
printout(dd4hep::WARNING, "SHcalSc04_Barrel_v04", " Layer number is less than it is able to build!");
Warning = true;
}
else
{
printout(dd4hep::DEBUG, "SHcalSc04_Barrel_v04", " has been validated and start to build it.");
Error = false;
Warning = false;
}
if (Error)
{
cout << "\n ============> First Help Documentation <=============== \n"
<< " When you see this message, that means you are crashing the module. \n"
<< " Please take a cup of cafe, and think about what you want to do! \n"
<< " Here are few FirstAid# for you. Please read them carefully. \n"
<< " \n"
<< " ### FirstAid 1: ###\n"
<< " If you want to build HCAL within the rInner and rOuter range, \n"
<< " please reduce the layer number to " << layerNumberRecommaned << " \n"
<< " with the current layer thickness structure. \n"
<< " \n"
<< " You may redisgn the layer structure and thickness, too. \n"
<< " \n"
<< " ### FirstAid 2: ###\n"
<< " If you want to build HCAL with this layer number and the layer thickness, \n"
<< " you have to update rOuter to " << rOuterRecommaned * 10. << "*mm \n"
<< " and to inform other subdetector, you need this space for building your design. \n"
<< " \n"
<< " ### FirstAid 3: ###\n"
<< " Do you think that you are looking for another type of HCAL driver? \n"
<< " \n"
<< endl;
throw lcgeo::GeometryException("SHcalSc04_Barrel: Error: Layer number is more than it can be built!");
}
else if (Warning)
{
cout << "\n ============> First Help Documentation <=============== \n"
<< " When you see this warning message, that means you are changing the module. \n"
<< " Please take a cup of cafe, and think about what you want to do! \n"
<< " Here are few FirstAid# for you. Please read them carefully. \n"
<< " \n"
<< " ### FirstAid 1: ###\n"
<< " If you want to build HCAL within the rInner and rOuter range, \n"
<< " You could build the layer number up to " << layerNumberRecommaned << " \n"
<< " with the current layer thickness structure. \n"
<< " \n"
<< " You may redisgn the layer structure and thickness, too. \n"
<< " \n"
<< " ### FirstAid 2: ###\n"
<< " If you want to build HCAL with this layer number and the layer thickness, \n"
<< " you could reduce rOuter to " << rOuterRecommaned * 10. << "*mm \n"
<< " and to reduce the back plate thickness, which you may not need for placing layer. \n"
<< " \n"
<< " ### FirstAid 3: ###\n"
<< " Do you think that you are looking for another type of HCAL driver? \n"
<< " \n"
<< endl;
return Warning;
}
else
{
return true;
}
}
static Ref_t create_detector(Detector &theDetector, xml_h element, SensitiveDetector sens)
{
double boundarySafety = 0.0001;
xml_det_t x_det = element;
string det_name = x_det.nameStr();
int det_id = x_det.id();
DetElement sdet(det_name, det_id);
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope(theDetector, element, sdet);
dd4hep::xml::setDetectorTypeFlag(element, sdet);
if (theDetector.buildType() == BUILD_ENVELOPE)
return sdet;
//-----------------------------------------------------------------------------------
xml_comp_t x_staves = x_det.staves(); // absorber
Material stavesMaterial = theDetector.material(x_staves.materialStr());
Material air = theDetector.air();
PlacedVolume pv;
sens.setType("calorimeter");
//====================================================================
//
// Read all the constant from ILD_o1_v05.xml
// Use them to build HcalBarrel
//
//====================================================================
double Hcal_inner_radius = theDetector.constant<double>("Hcal_inner_radius");
double Hcal_outer_radius = theDetector.constant<double>("Hcal_outer_radius");
double Hcal_half_length = theDetector.constant<double>("Hcal_half_length");
int Hcal_inner_symmetry = theDetector.constant<int>("Hcal_inner_symmetry");
int Hcal_outer_symmetry = 0; // Fixed shape for Tube, and not allow to modify from compact xml
double Hcal_cell_size = theDetector.constant<double>("Hcal_cell_size");
double Hcal_cell_size_abnormal = theDetector.constant<double>("Hcal_cell_size_abnormal");
double Hcal_scintillator_air_gap = theDetector.constant<double>("Hcal_scintillator_air_gap");
double Hcal_scintillator_ESR_thickness = theDetector.constant<double>("Hcal_scintillator_ESR_thickness");
double Hcal_scintillator_thickness = theDetector.constant<double>("Hcal_scintillator_thickness");
double Hcal_radiator_thickness = theDetector.constant<double>("Hcal_radiator_thickness");
double Hcal_chamber_thickness = theDetector.constant<double>("Hcal_chamber_thickness");
double Hcal_back_plate_thickness = theDetector.constant<double>("Hcal_back_plate_thickness");
double Hcal_lateral_plate_thickness = theDetector.constant<double>("Hcal_lateral_structure_thickness");
double Hcal_stave_gaps = theDetector.constant<double>("Hcal_stave_gaps");
// double Hcal_modules_gap = theDetector.constant<double>("Hcal_modules_gap");
double Hcal_middle_stave_gaps = theDetector.constant<double>("Hcal_middle_stave_gaps");
double Hcal_layer_air_gap = theDetector.constant<double>("Hcal_layer_air_gap");
// double Hcal_cells_size = theDetector.constant<double>("Hcal_cells_size");
int Hcal_nlayers = theDetector.constant<int>("Hcal_nlayers");
//=================================================================================
// if Hcal_outer_radius stands for the radius of circumcircle, comment next line
Hcal_outer_radius /= cos(M_PI / Hcal_inner_symmetry);
//=================================================================================
printout(dd4hep::INFO, "SHcalSc04_Barrel_v04", "Hcal_inner_radius : %e - Hcal_outer_radius %e ", Hcal_inner_radius, Hcal_outer_radius);
validateEnvelope(Hcal_inner_radius, Hcal_outer_radius, Hcal_radiator_thickness, Hcal_chamber_thickness, Hcal_nlayers, Hcal_inner_symmetry);
// fg: this is a bit tricky: we first have to check whether a multi segmentation is used and then, if so, we
// will check the <subsegmentation key="" value=""/> element, for which subsegmentation to use for filling the
// DDRec:LayeredCalorimeterData information.
// Additionally, we need to figure out if there is a TiledLayerGridXY instance defined -
// and in case, there is more than one defined, we need to pick the correct one specified via the
// <subsegmentation key="" value=""/> element.
// This involves a lot of casting: review the API in DD4hep !!
// check if we have a multi segmentation :
//========== fill data for reconstruction ============================
LayeredCalorimeterData *caloData = new LayeredCalorimeterData;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout;
caloData->inner_symmetry = Hcal_inner_symmetry;
caloData->outer_symmetry = Hcal_outer_symmetry;
caloData->phi0 = 0; // fg: also hardcoded below
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = Hcal_inner_radius;
caloData->extent[1] = Hcal_outer_radius;
caloData->extent[2] = 0.; // Barrel zmin is "0" by default.
caloData->extent[3] = Hcal_half_length;
//====================================================================
//
// general calculated parameters
//
//====================================================================
double Hcal_total_dim_y = Hcal_nlayers * (Hcal_radiator_thickness + Hcal_chamber_thickness) + Hcal_back_plate_thickness;
// double Hcal_y_dim1_for_x = Hcal_outer_radius * cos(M_PI / Hcal_inner_symmetry) - Hcal_inner_radius;
double Hcal_bottom_dim_x = 2. * Hcal_inner_radius * tan(M_PI / Hcal_inner_symmetry) - Hcal_lateral_plate_thickness * 2 - Hcal_stave_gaps;
// double Hcal_normal_dim_z = (2 * Hcal_half_length - Hcal_modules_gap) / 2.;
double Hcal_normal_dim_z = Hcal_half_length;
// only the middle has the steel plate.
// double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z - Hcal_lateral_plate_thickness;
double Hcal_regular_chamber_dim_z = Hcal_normal_dim_z;
// double Hcal_cell_dim_x = Hcal_cells_size;
// double Hcal_cell_dim_z = Hcal_regular_chamber_dim_z / floor (Hcal_regular_chamber_dim_z/Hcal_cell_dim_x);
// ========= Create Hcal Barrel stave ====================================
// It will be the volume for palcing the Hcal Barrel Chamber(i.e. Layers).
// Itself will be placed into the world volume.
// ==========================================================================
// stave modules shaper parameters
double BHX = (Hcal_bottom_dim_x + Hcal_lateral_plate_thickness * 2 + Hcal_stave_gaps) / 2.;
double THX = (Hcal_total_dim_y + Hcal_inner_radius) * tan(M_PI / Hcal_inner_symmetry);
double YXH = Hcal_total_dim_y / 2.;
// double DHZ = (Hcal_normal_dim_z - Hcal_lateral_plate_thickness) / 2.;
double DHZ = Hcal_normal_dim_z;
Trapezoid stave_shaper(THX, BHX, DHZ, DHZ, YXH);
Tube solidCaloTube(0, Hcal_outer_radius, DHZ + boundarySafety);
RotationZYX mrot(0, 0, M_PI / 2.);
Rotation3D mrot3D(mrot);
Position mxyzVec(0, 0, (Hcal_inner_radius + Hcal_total_dim_y / 2.));
Transform3D mtran3D(mrot3D, mxyzVec);
IntersectionSolid barrelModuleSolid(stave_shaper, solidCaloTube, mtran3D);
Volume EnvLogHcalModuleBarrel(det_name + "_module", barrelModuleSolid, stavesMaterial);
EnvLogHcalModuleBarrel.setAttributes(theDetector, x_staves.regionStr(), x_staves.limitsStr(), x_staves.visStr());
// stave modules lateral plate shaper parameters
// double BHX_LP = BHX;
// double THX_LP = THX;
// double YXH_LP = YXH;
// // build lateral palte here to simulate lateral plate in the middle of barrel.
// double DHZ_LP = Hcal_lateral_plate_thickness / 2.0;
// Trapezoid stave_shaper_LP(THX_LP, BHX_LP, DHZ_LP, DHZ_LP, YXH_LP);
// Tube solidCaloTube_LP(0, Hcal_outer_radius, DHZ_LP + boundarySafety);
// IntersectionSolid Module_lateral_plate(stave_shaper_LP, solidCaloTube_LP, mtran3D);
// Volume EnvLogHcalModuleBarrel_LP(det_name + "_Module_lateral_plate", Module_lateral_plate, stavesMaterial);
// EnvLogHcalModuleBarrel_LP.setAttributes(theDetector, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
#ifdef SHCALSC04_DEBUG
std::cout << " ==> Hcal_outer_radius: " << Hcal_outer_radius << std::endl;
#endif
//====================================================================
//
// Chambers in the HCAL BARREL
//
//====================================================================
// Build Layer Chamber fill with air, which include the tolarance space at the two side
// place the slice into the Layer Chamber
// Place the Layer Chamber into the Stave module
// place the Stave module into the asembly Volume
// place the module middle lateral plate into asembly Volume
double x_halflength; // dimension of an Hcal barrel layer on the x-axis
double y_halfheight; // dimension of an Hcal barrel layer on the y-axis
double z_halfwidth; // dimension of an Hcal barrel layer on the z-axis
x_halflength = 0.; // Each Layer the x_halflength has new value.
y_halfheight = Hcal_chamber_thickness / 2.;
z_halfwidth = Hcal_regular_chamber_dim_z;
double xOffset = 0.; // the x_halflength of a barrel layer is calculated as a
// barrel x-dimension plus (bottom barrel) or minus
//(top barrel) an x-offset, which depends on the angle M_PI/Hcal_inner_symmetry
double xShift = 0.; // Geant4 draws everything in the barrel related to the
// center of the bottom barrel, so we need to shift the layers to
// the left (or to the right) with the quantity xShift
// read sensitive cell parameters and create it
// xml_comp_t x_scintillator = x_det.solid();
// Material sensitiveMaterial = theDetector.material(x_scintillator.materialStr());
// xml_comp_t x_ESR = x_det.shape();
// Material ladderMaterial = theDetector.material(x_ESR.materialStr());
Volume cell_vol;
Volume scintillator_vol;
Volume cell_vol_abnormal;
Volume scintillator_vol_abnormal;
xml_comp_t x_layer_tmp(x_det.child(_U(layer)));
for (xml_coll_t k(x_layer_tmp, _U(slice)); k; ++k)
{
xml_comp_t x_slice = k;
if (x_slice.isSensitive())
{
// child elements: ladder and sensitive
xml_comp_t x_sensitive(x_slice.child(_U(sensitive)));
xml_comp_t x_ladder(x_slice.child(_U(ladder)));
Material sensitiveMaterial = theDetector.material(x_sensitive.materialStr());
Material ladderMaterial = theDetector.material(x_ladder.materialStr());
// Store scintillator thickness
double cell_thickness = Hcal_scintillator_thickness + 2 * Hcal_scintillator_ESR_thickness;
double cell_size = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size;
// place sensitive cell into ESR cell
string cell_name = "cell";
string scintillator_name = cell_name + "_scintillator";
// create sensitive cell with ESR
Box cell_box(cell_size / 2., cell_size / 2., cell_thickness / 2.);
// string cell_name=
// Volume cell_vol_tmp(cell_name, cell_box, ladderMaterial);
cell_vol = Volume(cell_name, cell_box, ladderMaterial);
cell_vol.setAttributes(theDetector, x_ladder.regionStr(), x_ladder.limitsStr(), x_ladder.visStr());
Box scintillator_box(Hcal_cell_size / 2., Hcal_cell_size / 2., Hcal_scintillator_thickness / 2.);
// Volume scintillator_vol_tmp(scintillator_name, scintillator_box, sensitiveMaterial);
scintillator_vol = Volume(scintillator_name, scintillator_box, sensitiveMaterial);
scintillator_vol.setAttributes(theDetector, x_sensitive.regionStr(), x_sensitive.limitsStr(), x_sensitive.visStr());
scintillator_vol.setSensitiveDetector(sens);
cell_vol.placeVolume(scintillator_vol, Position(0., 0., 0.));
// cout << x_ladder.visStr() << " " << x_sensitive.visStr() << endl;
///////////////////////////////
// abnormal cell //
///////////////////////////////
double cell_size_abnormal = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size_abnormal;
// place sensitive cell into ESR cell
string cell_name_abnormal = "cell_abnormal";
string scintillator_name_abnormal = cell_name_abnormal + "_scintillator_abnormal";
// create sensitive cell with ESR
Box cell_box_abnormal(cell_size_abnormal / 2., cell_size / 2., cell_thickness / 2.);
// string cell_name=
// Volume cell_vol_tmp_abnormal(cell_name_abnormal, cell_box_abnormal, ladderMaterial);
cell_vol_abnormal = Volume(cell_name_abnormal, cell_box_abnormal, ladderMaterial);
cell_vol_abnormal.setAttributes(theDetector, x_ladder.regionStr(), x_ladder.limitsStr(), x_ladder.visStr());
Box scintillator_box_abnormal(Hcal_cell_size_abnormal / 2., Hcal_cell_size / 2., Hcal_scintillator_thickness / 2.);
// Volume scintillator_vol_tmp_abnormal(scintillator_name_abnormal, scintillator_box_abnormal, sensitiveMaterial);
scintillator_vol_abnormal = Volume(scintillator_name_abnormal, scintillator_box_abnormal, sensitiveMaterial);
scintillator_vol_abnormal.setAttributes(theDetector, x_sensitive.regionStr(), x_sensitive.limitsStr(), x_sensitive.visStr());
scintillator_vol_abnormal.setSensitiveDetector(sens);
cell_vol_abnormal.placeVolume(scintillator_vol_abnormal, Position(0., 0., 0.));
}
}
// sensitive cell creating done
//-------------------- start loop over HCAL layers ----------------------
// int n_x_layer_1 = 0;
for (int layer_id = 1; layer_id <= (Hcal_nlayers); layer_id++)
{
double TanPiDiv8 = tan(M_PI / Hcal_inner_symmetry);
double x_total = 0.;
// double x_halfLength;
x_halflength = 0.;
// int layer_id = 0;
// if ((layer_id < Hcal_nlayers) || (layer_id > Hcal_nlayers && layer_id < (2 * Hcal_nlayers)))
// layer_id = layer_id % Hcal_nlayers;
// else if ((layer_id == Hcal_nlayers) || (layer_id == 2 * Hcal_nlayers))
// layer_id = Hcal_nlayers;
//---- bottom barrel------------------------------------------------------------
// if (layer_id * (Hcal_radiator_thickness + Hcal_chamber_thickness) < (Hcal_outer_radius * cos(M_PI / Hcal_inner_symmetry) - Hcal_inner_radius))
// {
xOffset = (layer_id * Hcal_radiator_thickness + (layer_id - 1) * Hcal_chamber_thickness) * TanPiDiv8;
x_total = Hcal_bottom_dim_x - Hcal_middle_stave_gaps + xOffset * 2;
x_halflength = x_total - 2 * Hcal_layer_air_gap;
// x_halfLength = x_halflength / 2.;
// }
// else
// { //----- top barrel -------------------------------------------------
// double y_layerID = layer_id * (Hcal_radiator_thickness + Hcal_chamber_thickness) + Hcal_inner_radius;
// double ro_layer = Hcal_outer_radius - Hcal_radiator_thickness;
// x_total = sqrt(ro_layer * ro_layer - y_layerID * y_layerID);
// x_halflength = x_total - Hcal_middle_stave_gaps;
// x_halfLength = x_halflength / 2.;
// xOffset = (layer_id * Hcal_radiator_thickness + (layer_id - 1) * Hcal_chamber_thickness - Hcal_y_dim1_for_x) / TanPiDiv8 + Hcal_chamber_thickness / TanPiDiv8;
// }
x_halflength = x_halflength / 2.;
LayeredCalorimeterData::Layer caloLayer;
caloLayer.cellSize0 = Hcal_cell_size;
caloLayer.cellSize1 = Hcal_cell_size;
//--------------------------------------------------------------------------------
// build chamber box, with the calculated dimensions
//-------------------------------------------------------------------------------
printout(dd4hep::DEBUG, "SHcalSc04_Barrel_v04", " \n Start to build layer chamber - layer_id: %d", layer_id);
printout(dd4hep::DEBUG, "SHcalSc04_Barrel_v04", " chamber x:y:z: %e:%e:%e", x_halflength * 2., z_halfwidth * 2., y_halfheight * 2.);
// check if x_halflength (scintillator length) is divisible with x_integerTileSize
Box ChamberSolid((x_halflength + Hcal_layer_air_gap), // x + air gaps at two side, do not need to build air gaps individualy.
z_halfwidth, // z attention!
y_halfheight); // y attention!
string ChamberLogical_name = det_name + _toString(layer_id, "_layer%d");
Volume ChamberLogical(ChamberLogical_name, ChamberSolid, air);
ChamberLogical.setAttributes(theDetector, x_layer_tmp.regionStr(), x_layer_tmp.limitsStr(), x_layer_tmp.visStr());
double layer_thickness = y_halfheight * 2.;
double nRadiationLengths = 0.;
double nInteractionLengths = 0.;
double thickness_sum = 0;
nRadiationLengths = Hcal_radiator_thickness / (stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness / (stavesMaterial.intLength());
thickness_sum = Hcal_radiator_thickness;
//====================================================================
// Create Hcal Barrel Chamber without radiator
// Place into the Hcal Barrel stave, after each radiator
//====================================================================
xml_coll_t c(x_det, _U(layer));
xml_comp_t x_layer = c;
string layer_name = det_name + _toString(layer_id, "_layer%d");
// Create the slices (sublayers) within the Hcal Barrel Chamber.
double slice_pos_z = layer_thickness / 2.;
int slice_number = 0;
for (xml_coll_t k(x_layer, _U(slice)); k; ++k)
{
xml_comp_t x_slice = k;
string slice_name = layer_name + _toString(slice_number, "_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
DetElement slice(layer_name, _toString(slice_number, "slice%d"), x_det.id());
slice_pos_z -= slice_thickness / 2.;
// Slice volume & box
Volume slice_vol(slice_name, Box(x_halflength, z_halfwidth, slice_thickness / 2.), slice_material);
slice_vol.setAttributes(theDetector, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr());
nRadiationLengths += slice_thickness / (2. * slice_material.radLength());
nInteractionLengths += slice_thickness / (2. * slice_material.intLength());
thickness_sum += slice_thickness / 2;
if (x_slice.isSensitive())
{
// Store "inner" quantities
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
// Store scintillator thickness
caloLayer.sensitive_thickness = Hcal_scintillator_thickness;
double cell_size = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size;
double cell_size_abnormal = 2 * Hcal_scintillator_ESR_thickness + Hcal_cell_size_abnormal;
double cell_x_offset = 0, cell_z_offset = 0, cell_y_offset = 0;
// place cell into slice one by one
double total_cell_size = cell_size + Hcal_scintillator_air_gap; // include air gap
double total_cell_size_abnormal = cell_size_abnormal + Hcal_scintillator_air_gap; // include air gap
int n_x = (2 * x_halflength) / total_cell_size;
int n_z = (2 * z_halfwidth) / total_cell_size;
int nx_abnormal = (2 * x_halflength - n_x * total_cell_size) / (total_cell_size_abnormal - total_cell_size);
n_x -= nx_abnormal;
// if(layer_id==1){n_x_layer_1=n_x;}
// else{
// n_x=(n_x-n_x_layer_1)/2;
// n_x=n_x*2+n_x_layer_1;
// }
for (int index_cell_z = 0; index_cell_z < n_z; index_cell_z++)
{
cell_x_offset = (n_x * total_cell_size + nx_abnormal * total_cell_size_abnormal) / 2.;
cell_z_offset = (n_z / 2. - index_cell_z - 0.5) * total_cell_size;
for (int index_cell_x = 0; index_cell_x < n_x; index_cell_x++)
{
cell_x_offset -= total_cell_size / 2.;
int cell_number = index_cell_x + 100 * index_cell_z;
string cell_name = slice_name + _toString(cell_number, "_cell%d");
string scintillator_name = cell_name + "_scintillator";
// cell_y_offset = slice_thickness / 2.;
PlacedVolume cell_phv = slice_vol.placeVolume(cell_vol, Position(cell_x_offset, cell_z_offset, cell_y_offset));
cell_phv.addPhysVolID("tile", cell_number);
DetElement cell(cell_name, _toString(cell_number, "cell%d"), cell_number);
cell.setPlacement(cell_phv);
cell_x_offset -= total_cell_size / 2.;
}
for (int index_cell_x = 0; index_cell_x < nx_abnormal; index_cell_x++)
{
cell_x_offset -= total_cell_size_abnormal / 2.;
int cell_number = index_cell_x + n_x + 100 * index_cell_z;
string cell_name = slice_name + _toString(cell_number, "_cell%d");
string scintillator_name = cell_name + "_scintillator";
// cell_y_offset = slice_thickness / 2.;
PlacedVolume cell_phv = slice_vol.placeVolume(cell_vol_abnormal, Position(cell_x_offset, cell_z_offset, cell_y_offset));
cell_phv.addPhysVolID("tile", cell_number);
DetElement cell(cell_name, _toString(cell_number, "cell%d"), cell_number);
cell.setPlacement(cell_phv);
cell_x_offset -= total_cell_size_abnormal / 2.;
}
}
//printf("layerID: %2d, x_length: %3.3lf, x_cell: %3.3lf, x_cell_abnormal: %3.3lf, x_dead: %3.3lf, z_length: %3.3lf,z_cell: %3.3lf, z_dead: %3.3lf,\n", layer_id, 2 * x_halflength, n_x * total_cell_size, nx_abnormal * total_cell_size_abnormal, 2 * x_halflength - n_x * total_cell_size - nx_abnormal * total_cell_size_abnormal, 2 * z_halfwidth, n_z * total_cell_size, 2 * z_halfwidth - n_z * total_cell_size);
// Reset counters to measure "outside" quantitites
nRadiationLengths = 0.;
nInteractionLengths = 0.;
thickness_sum = 0.;
// }
}
nRadiationLengths += slice_thickness / (2. * slice_material.radLength());
nInteractionLengths += slice_thickness / (2. * slice_material.intLength());
thickness_sum += slice_thickness / 2;
// Set region, limitset, and vis.
// slice_vol.setAttributes(theDetector, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr());
// slice PlacedVolume
PlacedVolume slice_phv = ChamberLogical.placeVolume(slice_vol, Position(0., 0., slice_pos_z));
slice_phv.addPhysVolID("layer", layer_id);
slice.setPlacement(slice_phv);
// Increment z position for next slice.
slice_pos_z -= slice_thickness / 2.;
// Increment slice number.
++slice_number;
}
// Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
//--------------------------- Chamber Placements -----------------------------------------
double chamber_x_offset, chamber_y_offset, chamber_z_offset;
chamber_x_offset = xShift;
chamber_z_offset = 0;
chamber_y_offset = -(-Hcal_total_dim_y / 2. + (layer_id - 1) * (Hcal_chamber_thickness + Hcal_radiator_thickness) + Hcal_radiator_thickness + Hcal_chamber_thickness / 2.);
pv = EnvLogHcalModuleBarrel.placeVolume(ChamberLogical,
Position(chamber_x_offset, chamber_z_offset, chamber_y_offset));
//-----------------------------------------------------------------------------------------
if (layer_id <= Hcal_nlayers)
{ // add the first set of layers to the reconstruction data
caloLayer.distance = Hcal_inner_radius + Hcal_total_dim_y / 2.0 - chamber_y_offset - caloLayer.inner_thickness;
// Will be added later at "DDMarlinPandora/DDGeometryCreator.cc:226" to get center of sensitive element
caloLayer.absorberThickness = Hcal_radiator_thickness;
caloData->layers.push_back(caloLayer);
}
//-----------------------------------------------------------------------------------------
} // end loop over HCAL nlayers;
//====================================================================
// Place HCAL Barrel stave module into the envelope
//====================================================================
double stave_phi_offset, module_z_offset = 0;
double Y = Hcal_inner_radius + Hcal_total_dim_y / 2.;
stave_phi_offset = M_PI / Hcal_inner_symmetry - M_PI / 2.;
//-------- start loop over HCAL BARREL staves ----------------------------
for (int stave_id = 1; stave_id <= Hcal_inner_symmetry; stave_id++)
{
double phirot = stave_phi_offset;
RotationZYX srot(0, phirot, M_PI * 0.5);
Rotation3D srot3D(srot);
// for (int module_id = 1; module_id <= 2; module_id++)
// {
Position sxyzVec(-Y * sin(phirot), Y * cos(phirot), module_z_offset);
Transform3D stran3D(srot3D, sxyzVec);
// Place Hcal Barrel volume into the envelope volume
pv = envelope.placeVolume(EnvLogHcalModuleBarrel, stran3D);
pv.addPhysVolID("stave", stave_id);
// pv.addPhysVolID("module", module_id);
pv.addPhysVolID("system", det_id);
// const int staveCounter = (stave_id - 1) * 2 + module_id - 1;
const int staveCounter = stave_id - 1;
DetElement stave(sdet, _toString(staveCounter, "stave%d"), staveCounter);
stave.setPlacement(pv);
// Position xyzVec_LP(-Y * sin(phirot), Y * cos(phirot), lateral_plate_z_offset);
// Transform3D tran3D_LP(srot3D, xyzVec_LP);
// pv = envelope.placeVolume(EnvLogHcalModuleBarrel_LP, tran3D_LP);
// module_z_offset = -module_z_offset;
// lateral_plate_z_offset = -lateral_plate_z_offset;
// }
stave_phi_offset -= M_PI * 2.0 / Hcal_inner_symmetry;
} //-------- end loop over HCAL BARREL staves ----------------------------
sdet.addExtension<LayeredCalorimeterData>(caloData);
return sdet;
}
DECLARE_DETELEMENT(SHcalSc04_Barrel_v04, create_detector)
//====================================================================
// AIDA Detector description implementation
// for LDC AHCAL Endcap
//--------------------------------------------------------------------
//
// Author : S.Lu
// F. Gaede, DESY : v01 : prepare for multi segmentation
// 18.04.2017 - copied from SHcalSc04_Barrel_v01.cpp
// - add optional parameter <subsegmentation key="" value=""/>
// defines the segmentation to be used in reconstruction
//
// Basic idea:
// 1. Create the Hcal Endcap module envelope (16 modules).
// Note: with default material Steel235.
//
// 2. Create the Hcal Endcap Chamber(i.e. Layer) for each module.
// Create the Layer with slices (Polystyrene,Cu,FR4,air).
// Place each slice into the chamber with the right position,
// And registry the IDs for slice
//
// 3. Place the same Layer into the endcap module envelope.
// It will be repeated repeat 48 times.
// And registry the IDs for layer, and endcapID.
//
// 4. Place the endcap module into the world volume,
// with the right position and rotation.
// And registry the IDs for stave,module and endcapID.
//
// 5. Customer material FR4 and Steel235 defined in materials.xml
//
//====================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
#include "DDSegmentation/BitField64.h"
#include "DDSegmentation/Segmentation.h"
#include "DDSegmentation/MultiSegmentation.h"
#include "LcgeoExceptions.h"
using namespace std;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::BitField64;
using dd4hep::Box;
using dd4hep::DetElement;
using dd4hep::DetType;
using dd4hep::Detector;
using dd4hep::Layering;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::RotationX;
using dd4hep::Segmentation;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Translation3D;
using dd4hep::Volume;
using dd4hep::_toString;
using dd4hep::rec::LayeredCalorimeterData;
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
xml_det_t x_det = element;
Layering layering(x_det);
xml_dim_t dim = x_det.dimensions();
string det_name = x_det.nameStr();
Material air = theDetector.air();
Material stavesMaterial = theDetector.material(x_det.materialStr());
int numSides = dim.numsides();
int det_id = x_det.id();
DetElement sdet(det_name,det_id);
PlacedVolume pVol;
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ;
sdet.setTypeFlag( DetType::CALORIMETER | DetType::ENDCAP | DetType::HADRONIC ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
//-----------------------------------------------------------------------------------
sens.setType("calorimeter");
DetElement stave_det("module0stave0",det_id);
// The way to reaad constant from XML/Detector file.
double Hcal_radiator_thickness = theDetector.constant<double>("Hcal_radiator_thickness");
double Hcal_endcap_lateral_structure_thickness = theDetector.constant<double>("Hcal_endcap_lateral_structure_thickness");
double Hcal_endcap_layer_air_gap = theDetector.constant<double>("Hcal_endcap_layer_air_gap");
//double Hcal_cells_size = theDetector.constant<double>("Hcal_cells_size");
double HcalEndcap_inner_radius = theDetector.constant<double>("Hcal_endcap_inner_radius");
double HcalEndcap_outer_radius = theDetector.constant<double>("Hcal_endcap_outer_radius");
double HcalEndcap_min_z = theDetector.constant<double>("Hcal_endcap_zmin");
double HcalEndcap_max_z = theDetector.constant<double>("Hcal_endcap_zmax");
double Hcal_steel_cassette_thickness = theDetector.constant<double>("Hcal_steel_cassette_thickness");
double HcalServices_outer_FR4_thickness = theDetector.constant<double>("Hcal_services_outer_FR4_thickness");
double HcalServices_outer_Cu_thickness = theDetector.constant<double>("Hcal_services_outer_Cu_thickness");
double Hcal_endcap_services_module_width = theDetector.constant<double>("Hcal_endcap_services_module_width");
Material stainless_steel = theDetector.material("stainless_steel");
Material PCB = theDetector.material("PCB");
Material copper = theDetector.material("Cu");
std::cout <<"\n HcalEndcap_inner_radius = "
<<HcalEndcap_inner_radius/dd4hep::mm <<" mm"
<<"\n HcalEndcap_outer_radius = "
<<HcalEndcap_outer_radius/dd4hep::mm <<" mm"
<<"\n HcalEndcap_min_z = "
<<HcalEndcap_min_z/dd4hep::mm <<" mm"
<<"\n HcalEndcap_max_z = "
<<HcalEndcap_max_z/dd4hep::mm <<" mm"
<<std::endl;
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
BitField64 encoder = seg.decoder();
encoder.setValue(0) ;
// we first have to check whether a multi segmentation is used and then, if so, we
// will check the <subsegmentation key="" value=""/> element, for which subsegmentation to use for filling the
// DDRec:LayeredCalorimeterData information.
// check if we have a multi segmentation :
dd4hep::DDSegmentation::MultiSegmentation* multiSeg =
dynamic_cast< dd4hep::DDSegmentation::MultiSegmentation*>( seg.segmentation() ) ;
int sensitive_slice_number = -1 ;
if( multiSeg ){
try{
// check if we have an entry for the subsegmentation to be used
xml_comp_t segxml = x_det.child( _Unicode( subsegmentation ) ) ;
std::string keyStr = segxml.attr<std::string>( _Unicode(key) ) ;
int keyVal = segxml.attr<int>( _Unicode(value) ) ;
encoder[ keyStr ] = keyVal ;
// if we have a multisegmentation that uses the slice as key, we need to know for the
// computation of the layer parameters in LayeredCalorimeterData::Layer below
if( keyStr == "slice" ){
sensitive_slice_number = keyVal ;
}
} catch(const std::runtime_error &) {
throw lcgeo::GeometryException( "SHcalSc04_Endcaps_v01: Error: MultiSegmentation specified but no "
" <subsegmentation key="" value=""/> element defined for detector ! " ) ;
}
}
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
caloData->inner_symmetry = 4 ; // hard code cernter box hole
caloData->outer_symmetry = 0 ; // outer tube, or 8 for Octagun
caloData->phi0 = 0 ;
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = HcalEndcap_inner_radius ;
caloData->extent[1] = HcalEndcap_outer_radius ;
caloData->extent[2] = HcalEndcap_min_z ;
caloData->extent[3] = HcalEndcap_max_z ;
int endcapID = 0;
for(xml_coll_t c(x_det.child(_U(dimensions)),_U(dimensions)); c; ++c)
{
xml_comp_t l(c);
double dim_x = l.attr<double>(_Unicode(dim_x));
double dim_y = l.attr<double>(_Unicode(dim_y));
double dim_z = l.attr<double>(_Unicode(dim_z));
double pos_y = l.attr<double>(_Unicode(y_offset));
// Hcal Endcap module shape
double box_half_x= dim_x/2.0; // module width, all are same
double box_half_y= dim_y/2.0; // module length, changing
double box_half_z= dim_z/2.0; // total thickness, all are same
double x_offset = box_half_x*numSides-box_half_x*endcapID*2.0-box_half_x;
double y_offset = pos_y;
Box EndcapModule(box_half_x,box_half_y,box_half_z);
// define the name of each endcap Module
string envelopeVol_name = det_name+_toString(endcapID,"_EndcapModule%d");
Volume envelopeVol(envelopeVol_name,EndcapModule,stavesMaterial);
// Set envelope volume attributes.
envelopeVol.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
double FEE_half_x = box_half_x-Hcal_endcap_services_module_width/2.0;
double FEE_half_y = Hcal_endcap_services_module_width/2.0;
double FEE_half_z = box_half_z;
Box FEEBox(FEE_half_x,FEE_half_y,FEE_half_z);
Volume FEEModule("Hcal_endcap_FEE",FEEBox,air);
double FEELayer_thickness = Hcal_steel_cassette_thickness + HcalServices_outer_FR4_thickness + HcalServices_outer_Cu_thickness;
Box FEELayerBox(FEE_half_x,FEE_half_y,FEELayer_thickness/2.0);
Volume FEELayer("FEELayer",FEELayerBox,air);
Box FEELayerSteelBox(FEE_half_x,FEE_half_y,Hcal_steel_cassette_thickness/2.0);
Volume FEELayerSteel("FEELayerSteel",FEELayerSteelBox,stainless_steel);
pVol = FEELayer.placeVolume(FEELayerSteel,
Position(0,
0,
(-FEELayer_thickness/2.0
+Hcal_steel_cassette_thickness/2.0)));
Box FEELayerFR4Box(FEE_half_x,FEE_half_y,HcalServices_outer_FR4_thickness/2.0);
Volume FEELayerFR4("FEELayerFR4",FEELayerFR4Box,PCB);
pVol = FEELayer.placeVolume(FEELayerFR4,
Position(0,
0,
(-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness
+HcalServices_outer_FR4_thickness/2.0)));
Box FEELayerCuBox(FEE_half_x,FEE_half_y,HcalServices_outer_Cu_thickness/2.0);
Volume FEELayerCu("FEELayerCu",FEELayerCuBox,copper);
pVol = FEELayer.placeVolume(FEELayerCu,
Position(0,
0,
(-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness+HcalServices_outer_FR4_thickness +HcalServices_outer_Cu_thickness/2.0)));
// ========= Create Hcal Chamber (i.e. Layers) ==============================
// It will be the sub volume for placing the slices.
// Itself will be placed into the Hcal Endcap modules envelope.
// ==========================================================================
// create Layer (air) and place the slices (Polystyrene,Cu,FR4,air) into it.
// place the Layer into the Hcal Endcap Modules envelope (stavesMaterial).
// First Hcal Chamber position, start after first radiator
double layer_pos_z = - box_half_z + Hcal_radiator_thickness;
// Create Hcal Endcap Chamber without radiator
// Place into the Hcal Encap module envelope, after each radiator
int layer_num = 1;
for(xml_coll_t m(x_det,_U(layer)); m; ++m) {
xml_comp_t x_layer = m;
int repeat = x_layer.repeat(); // Get number of layers.
double layer_thickness = layering.layer(layer_num)->thickness();
string layer_name = envelopeVol_name+"_layer";
DetElement layer(stave_det,layer_name,det_id);
// Active Layer box & volume
double active_layer_dim_x = box_half_x - Hcal_endcap_lateral_structure_thickness - Hcal_endcap_layer_air_gap;
double active_layer_dim_y = box_half_y;
double active_layer_dim_z = layer_thickness/2.0;
// Build chamber including air gap
// The Layer will be filled with slices,
Volume layer_vol(layer_name, Box((active_layer_dim_x + Hcal_endcap_layer_air_gap),
active_layer_dim_y,active_layer_dim_z), air);
encoder["layer"] = layer_num ;
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions( encoder.getValue() );
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cellSizeVector[0];
caloLayer.cellSize1 = cellSizeVector[1];
// ========= Create sublayer slices =========================================
// Create and place the slices into Layer
// ==========================================================================
// Create the slices (sublayers) within the Hcal Chamber.
double slice_pos_z = -(layer_thickness / 2.0);
int slice_number = 0;
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
nRadiationLengths = Hcal_radiator_thickness/(stavesMaterial.radLength());
nInteractionLengths = Hcal_radiator_thickness/(stavesMaterial.intLength());
thickness_sum = Hcal_radiator_thickness;
for(xml_coll_t k(x_layer,_U(slice)); k; ++k) {
xml_comp_t x_slice = k;
string slice_name = layer_name + _toString(slice_number,"_slice%d");
double slice_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
DetElement slice(layer,_toString(slice_number,"slice%d"),det_id);
slice_pos_z += slice_thickness / 2.0;
// Slice volume & box
Volume slice_vol(slice_name,Box(active_layer_dim_x,active_layer_dim_y,slice_thickness/2.0),slice_material);
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
if ( x_slice.isSensitive() ) {
slice_vol.setSensitiveDetector(sens);
// if we have a multisegmentation based on slices, we need to use the correct slice here
if ( sensitive_slice_number<0 || sensitive_slice_number == slice_number ) {
//Store "inner" quantities
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
//Store scintillator thickness
caloLayer.sensitive_thickness = slice_thickness;
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}
}
nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
thickness_sum += slice_thickness/2;
// Set region, limitset, and vis.
slice_vol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
// slice PlacedVolume
PlacedVolume slice_phv = layer_vol.placeVolume(slice_vol,Position(0,0,slice_pos_z));
slice_phv.addPhysVolID("slice",slice_number);
slice.setPlacement(slice_phv);
// Increment Z position for next slice.
slice_pos_z += slice_thickness / 2.0;
// Increment slice number.
++slice_number;
}
// Set region, limitset, and vis.
layer_vol.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
//Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
// ========= Place the Layer (i.e. Chamber) =================================
// Place the Layer into the Hcal Endcap module envelope.
// with the right position and rotation.
// Registry the IDs (layer, stave, module).
// Place the same layer 48 times into Endcap module
// ==========================================================================
for (int j = 0; j < repeat; j++) {
// Layer position in y within the Endcap Modules.
layer_pos_z += layer_thickness / 2.0;
PlacedVolume layer_phv = envelopeVol.placeVolume(layer_vol,
Position(0,0,layer_pos_z));
// registry the ID of Layer, stave and module
layer_phv.addPhysVolID("layer",layer_num);
// then setPlacement for it.
layer.setPlacement(layer_phv);
pVol = FEEModule.placeVolume(FEELayer,
Position(0,0,layer_pos_z));
//-----------------------------------------------------------------------------------------
if ( caloData->layers.size() < (unsigned int)repeat ) {
caloLayer.distance = HcalEndcap_min_z + box_half_z + layer_pos_z
- caloLayer.inner_thickness ; // Will be added later at "DDMarlinPandora/DDGeometryCreator.cc:226" to get center of sensitive element
caloLayer.absorberThickness = Hcal_radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
}
//-----------------------------------------------------------------------------------------
// ===== Prepare for next layer (i.e. next Chamber) =========================
// Prepare the chamber placement position and the chamber dimension
// ==========================================================================
// Increment the layer_pos_y
// Place Hcal Chamber after each radiator
layer_pos_z += layer_thickness / 2.0;
layer_pos_z += Hcal_radiator_thickness;
++layer_num;
}
}
// =========== Place Hcal Endcap envelope ===================================
// Finally place the Hcal Endcap envelope into the world volume.
// Registry the stave(up/down), module(left/right) and endcapID.
// ==========================================================================
// Acording to the number of staves and modules,
// Place the same Hcal Endcap module volume into the world volume
// with the right position and rotation.
for(int stave_num=0;stave_num<2;stave_num++){
double EndcapModule_pos_x = 0;
double EndcapModule_pos_y = 0;
double EndcapModule_pos_z = 0;
double rot_EM = 0;
double EndcapModule_center_pos_z = HcalEndcap_min_z + box_half_z;
double FEEModule_pos_x = 0;
double FEEModule_pos_y = 0;
double FEEModule_pos_z = 0;
double FEEModule_center_pos_z = HcalEndcap_min_z + box_half_z;
switch (stave_num)
{
case 0 :
EndcapModule_pos_x = x_offset;
EndcapModule_pos_y = y_offset;
FEEModule_pos_x = x_offset;
FEEModule_pos_y = y_offset + box_half_y + Hcal_endcap_services_module_width/2.0;
break;
case 1 :
EndcapModule_pos_x = -x_offset;
EndcapModule_pos_y = -y_offset;
FEEModule_pos_x = -x_offset;
FEEModule_pos_y = -y_offset - box_half_y - Hcal_endcap_services_module_width/2.0;
break;
}
for(int module_num=0;module_num<2;module_num++) {
int module_id = (module_num==0)? 0:6;
rot_EM = (module_id==0)?M_PI:0;
EndcapModule_pos_z = (module_id==0)? -EndcapModule_center_pos_z:EndcapModule_center_pos_z;
PlacedVolume env_phv = envelope.placeVolume(envelopeVol,
Transform3D(RotationX(rot_EM),
Translation3D(EndcapModule_pos_x,
EndcapModule_pos_y,
EndcapModule_pos_z)));
env_phv.addPhysVolID("tower",endcapID);
env_phv.addPhysVolID("stave",stave_num); // y: up /down
env_phv.addPhysVolID("module",module_id); // z: -/+ 0/6
env_phv.addPhysVolID("system",det_id);
FEEModule_pos_z = (module_id==0)? -FEEModule_center_pos_z:FEEModule_center_pos_z;
if (!(endcapID==0))
env_phv = envelope.placeVolume(FEEModule,
Transform3D(RotationX(rot_EM),
Translation3D(FEEModule_pos_x,
FEEModule_pos_y,
FEEModule_pos_z)));
DetElement sd = (module_num==0&&stave_num==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_num,"stave%d"));
sd.setPlacement(env_phv);
}
}
endcapID++;
}
sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
return sdet;
}
DECLARE_DETELEMENT(SHcalSc04_Endcaps_v01, create_detector)
//================================================================================
// Description — End-Cap AHCAL
//--------------------------------------------------------------------------------
// Author: Ji-Yuan CHEN (SJTU; jy_chen@sjtu.edu.cn)
//--------------------------------------------------------------------------------
//
// End-cap AHCAL with 40×40×3 mm³ scintillator tiles.
// Adding the dead materials (cassette, PCB and electronic components, ESR wrapper and steel absorber) and including the air gaps, the size of each cell becomes 40.3×40.3×27.2 mm³.
//
// The inner radius, end-cap thickness, unit size, etc. are directly read from XML file.
//
// Structure in a layer: Cassette → ESR → scintillator → ESR → PCB (including electronic components) → cassette → steel absorber.
//
// Default layout: The absorber is designed as a whole with some space left for the sensitive units (the cross-section is not a polygon); steel frame on the edges of each module; 16 modules (called 'staves' in this program), 48 layers; 72 rows in r direction, with uniform granularity. For a schematic diagram, see Page 3 of <https://indico.ihep.ac.cn/event/22010/contributions/153187/attachments/77666/96430/2024_0324_Calorimeter_Endcaps.pdf> (the design on the left; the numbers have been modified).
//================================================================================
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DD4hepUnits.h"
#include "DD4hep/Shapes.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
#include "DDSegmentation/Segmentation.h"
#include <sstream>
#include <cassert>
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::to_string;
#define MYDEBUG(x) cout << __FILE__ << ":" << __LINE__ << ": " << x << endl;
#define MYDEBUGVAL(x) cout << __FILE__ << ":" << __LINE__ << ": "<< #x << ": " << x << endl;
using dd4hep::Ref_t;
using dd4hep::Detector;
using dd4hep::SensitiveDetector;
using dd4hep::pi;
using dd4hep::mm;
using dd4hep::Material;
using dd4hep::DetElement;
using dd4hep::Volume;
using dd4hep::PolyhedraRegular;
using dd4hep::Tube;
using dd4hep::UnionSolid;
using dd4hep::Trapezoid;
using dd4hep::Box;
using dd4hep::SubtractionSolid;
using dd4hep::PlacedVolume;
using dd4hep::Position;
using dd4hep::RotationX;
using dd4hep::_toString;
using dd4hep::Transform3D;
using dd4hep::RotationZ;
using dd4hep::RotationY;
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens)
{
xml_det_t x_det = e;
const string det_name = x_det.nameStr();
const string det_type = x_det.typeStr();
const int det_id = x_det.id();
MYDEBUGVAL(det_name)
MYDEBUGVAL(det_type)
MYDEBUGVAL(det_id)
// To prevent overlapping
const double boundary_safety = theDetector.constant<double>("boundary_safety");
// Global geometry
const double r_in = theDetector.constant<double>("hcalendcap_inner_radius");
const double r_out = theDetector.constant<double>("hcalendcap_outer_radius");
const double module_thickness = theDetector.constant<double>("hcalendcap_thickness");
const double pos_z = theDetector.constant<double>("hcalendcap_z");
const int Nmodules = theDetector.constant<int>("Nmodules");
const double angle = 2 * pi / Nmodules;
// Unit size
const double scintillator_xy = theDetector.constant<double>("scintillator_xy");
const double scintillator_z = theDetector.constant<double>("scintillator_z");
const double wrapped_scintillator_xy = theDetector.constant<double>("wrapped_scintillator_xy");
const double wrapped_scintillator_z = theDetector.constant<double>("wrapped_scintillator_z");
// Dead materials
const double cassette_thickness = theDetector.constant<double>("cassette_thickness");
const double esr_thickness = theDetector.constant<double>("esr_thickness"); // Wrapper
[[maybe_unused]] const double sipm_xy = theDetector.constant<double>("sipm_xy");
[[maybe_unused]] const double sipm_z = theDetector.constant<double>("sipm_z");
const double pcb_thickness = theDetector.constant<double>("pcb_thickness");
const double absorber_thickness = theDetector.constant<double>("absorber_thickness");
const double air_gap_xy = 0.5 * (wrapped_scintillator_xy - scintillator_xy) - esr_thickness;
[[maybe_unused]] const double air_gap_z = 0.5 * (wrapped_scintillator_z - scintillator_z) - esr_thickness;
// Odd-shaped cells
const int Nodd = theDetector.constant<int>("Nodd");
const double short_elongation_1 = theDetector.constant<double>("short_elongation_1");
const double short_elongation_2 = theDetector.constant<double>("short_elongation_2");
const double short_elongation_3 = theDetector.constant<double>("short_elongation_3");
const double short_elongation_4 = theDetector.constant<double>("short_elongation_4");
const double short_elongation_5 = theDetector.constant<double>("short_elongation_5");
const double elongation_angle_esr_out = wrapped_scintillator_xy * tan(0.5 * angle); // Elongation of the outer edge of ESR: long side - short side
const double elongation_angle_esr_in = (wrapped_scintillator_xy - esr_thickness / cos(0.5 * angle)) * tan(0.5 * angle); // Elongation of the inner edge of ESR: long side - short side
const double elongation_angle_sc = scintillator_xy * tan(0.5 * angle); // Elongation of the scintillator: long side - short side
const vector<double> short_elongation_esr_out = { short_elongation_1, short_elongation_2, short_elongation_3, short_elongation_4, short_elongation_5 };
assert(Nodd == short_elongation_esr_out.size());
vector<double> short_elongation_sc(short_elongation_esr_out.size()), long_elongation_sc(short_elongation_esr_out.size()), short_elongation_esr_in(short_elongation_esr_out.size()), long_elongation_esr_in(short_elongation_esr_out.size()), long_elongation_esr_out(short_elongation_esr_out.size());
for (int i = 0; i < Nodd; ++i)
{
short_elongation_sc.at(i) = short_elongation_esr_out.at(i) - (air_gap_xy + esr_thickness) / cos(0.5 * angle);
long_elongation_sc.at(i) = short_elongation_sc.at(i) + elongation_angle_sc;
short_elongation_esr_in.at(i) = short_elongation_esr_out.at(i) - esr_thickness / cos(0.5 * angle);
long_elongation_esr_in.at(i) = short_elongation_esr_in.at(i) + elongation_angle_esr_in;
long_elongation_esr_out.at(i) = short_elongation_esr_out.at(i) + elongation_angle_esr_out;
}
// Mechanical structure
const double inner_structure_thickness = theDetector.constant<double>("inner_structure_thickness");
[[maybe_unused]] const double outer_structure_width = theDetector.constant<double>("outer_structure_width");
[[maybe_unused]] const double outer_structure_thickness = theDetector.constant<double>("outer_structure_thickness");
const double frame_thickness = theDetector.constant<double>("frame_thickness");
const double layer_thickness = wrapped_scintillator_z + pcb_thickness + 2 * cassette_thickness + absorber_thickness + 5 * boundary_safety;
const double non_absorber_thickness = wrapped_scintillator_z + pcb_thickness + 3 * boundary_safety;
MYDEBUGVAL(layer_thickness)
// Module size
const double dim_in_frame = (r_in + inner_structure_thickness + frame_thickness) * tan(0.5 * angle);
const double dim_out_frame = r_out * sin(0.5 * angle);
const double dim_in = dim_in_frame - frame_thickness / cos(0.5 * angle);
const double dim_out = dim_out_frame - frame_thickness / cos(0.5 * angle);
const double height = r_out * cos(0.5 * angle) - r_in - inner_structure_thickness;
const double r0 = r_in + inner_structure_thickness + 0.5 * height; // Rotation radius for placing the modules
const int Nrows = (int) (height / (wrapped_scintillator_xy + boundary_safety));
const int Nlayers = (int) (module_thickness / layer_thickness);
int Ncells_phi;
MYDEBUGVAL(Nrows)
MYDEBUGVAL(Nlayers)
// Materials
Material mat_air(theDetector.material("Air"));
Material mat_PCB(theDetector.material("PCB"));
[[maybe_unused]] Material mat_SiPM(theDetector.material("G4_Si"));
Material mat_sensitive(theDetector.material( x_det.materialStr() ));
Material mat_ESR(theDetector.material("G4_ESR"));
Material mat_steel(theDetector.material("Steel235"));
// The detector and mother volumes (world)
DetElement AHCAL(det_name, det_id);
Volume motherVol = theDetector.pickMotherVolume(AHCAL);
// Create two tube-like envelopes to represent the end-cap volumes
// PolyhedraRegular envelope_side(Nmodules, 0.5 * angle, r_in + inner_structure_thickness, r_out, module_thickness);
Tube envelope_side(r_in, r_out, 0.5 * module_thickness);
UnionSolid envelope(envelope_side, envelope_side, Position(0, 0, 2 * pos_z));
Volume envelopeVol(det_name, envelope, mat_steel);
PlacedVolume envelopePlv = motherVol.placeVolume(envelopeVol, Position(0, 0, -pos_z));
envelopePlv.addPhysVolID("system", det_id);
envelopeVol.setVisAttributes(theDetector, "SeeThrough");
AHCAL.setPlacement(envelopePlv);
DetElement stave_det(AHCAL, "sector", det_id);
// Module (stave)
Trapezoid stave(dim_in, dim_out, 0.5 * module_thickness, 0.5 * module_thickness, 0.5 * height);
Volume stave_vol("stave_vol", stave, mat_steel);
stave_vol.setVisAttributes(theDetector, "BlueVis");
// Layer with only wrapped scintillators, electronic components and PCB
Trapezoid layer(dim_in, dim_out, 0.5 * non_absorber_thickness, 0.5 * non_absorber_thickness, 0.5 * height);
Volume layer_vol("layer_vol", layer, mat_steel);
layer_vol.setVisAttributes(theDetector, "SeeThrough");
// Scintillator, ESR, SiPM, PCB, cassette, and absorber
Box normal_scintillator(0.5 * scintillator_xy, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Volume scintillator("scintillator", normal_scintillator, mat_sensitive); // Order: phi → z → r
scintillator.setVisAttributes(theDetector, "SeeThrough");
scintillator.setSensitiveDetector(sens);
[[maybe_unused]] Volume sipm("SiPM", Box(0.5 * sipm_xy, 0.5 * sipm_xy, 0.5 * sipm_z), mat_SiPM);
sipm.setVisAttributes(theDetector, "CyanVis");
Box esr_out(0.5 * wrapped_scintillator_xy, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Box esr_in(0.5 * wrapped_scintillator_xy - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Volume esr("esr", SubtractionSolid(esr_out, esr_in, Position(0, 0, 0)), mat_ESR);
esr.setVisAttributes(theDetector, "SeeThrough");
// Odd-shaped scintillators
Trapezoid odd_add_0_scintillator(0, long_elongation_sc.at(0) - short_elongation_sc.at(0), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_45_scintillator(short_elongation_sc.at(1), long_elongation_sc.at(1), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_9_scintillator(short_elongation_sc.at(2), long_elongation_sc.at(2), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_14_scintillator(short_elongation_sc.at(3), long_elongation_sc.at(3), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Trapezoid odd_add_17_scintillator(short_elongation_sc.at(4), long_elongation_sc.at(4), 0.5 * scintillator_z, 0.5 * scintillator_z, 0.5 * scintillator_xy);
Box odd_scintillator_0_rect(0.5 * (scintillator_xy + short_elongation_sc.at(0)), 0.5 * scintillator_z, 0.5 * scintillator_xy);
Volume odd_0_scintillator("odd_0_scintillator", UnionSolid(odd_scintillator_0_rect, odd_add_0_scintillator, Position(0.5 * (scintillator_xy + short_elongation_sc.at(0)), 0, 0)), mat_sensitive);
odd_0_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_0_scintillator.setSensitiveDetector(sens);
Volume odd_45_scintillator("odd_45_scintillator", UnionSolid(normal_scintillator, odd_add_45_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_45_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_45_scintillator.setSensitiveDetector(sens);
Volume odd_9_scintillator("odd_9_scintillator", UnionSolid(normal_scintillator, odd_add_9_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_9_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_9_scintillator.setSensitiveDetector(sens);
Volume odd_14_scintillator("odd_14_scintillator", UnionSolid(normal_scintillator, odd_add_14_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_14_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_14_scintillator.setSensitiveDetector(sens);
Volume odd_17_scintillator("odd_17_scintillator", UnionSolid(normal_scintillator, odd_add_17_scintillator, Position(0.5 * scintillator_xy, 0, 0)), mat_sensitive);
odd_17_scintillator.setVisAttributes(theDetector, "SeeThrough");
odd_17_scintillator.setSensitiveDetector(sens);
// Odd-shaped ESR
// Outer edge
Trapezoid odd_add_0_esr_out(short_elongation_esr_out.at(0), long_elongation_esr_out.at(0), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_45_esr_out(short_elongation_esr_out.at(1), long_elongation_esr_out.at(1), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_9_esr_out(short_elongation_esr_out.at(2), long_elongation_esr_out.at(2), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_14_esr_out(short_elongation_esr_out.at(3), long_elongation_esr_out.at(3), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
Trapezoid odd_add_17_esr_out(short_elongation_esr_out.at(4), long_elongation_esr_out.at(4), 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_z, 0.5 * wrapped_scintillator_xy);
UnionSolid odd_0_esr_out(esr_out, odd_add_0_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_45_esr_out(esr_out, odd_add_45_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_9_esr_out(esr_out, odd_add_9_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_14_esr_out(esr_out, odd_add_14_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_17_esr_out(esr_out, odd_add_17_esr_out, Position(0.5 * wrapped_scintillator_xy, 0, 0));
// Inner edge
Trapezoid odd_add_0_esr_in(0, long_elongation_esr_in.at(0) - short_elongation_esr_in.at(0), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_45_esr_in(short_elongation_esr_in.at(1), long_elongation_esr_in.at(1), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_9_esr_in(short_elongation_esr_in.at(2), long_elongation_esr_in.at(2), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_14_esr_in(short_elongation_esr_in.at(3), long_elongation_esr_in.at(3), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Trapezoid odd_add_17_esr_in(short_elongation_esr_in.at(4), long_elongation_esr_in.at(4), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
Box odd_esr_in_0_rect(0.5 * (wrapped_scintillator_xy - 2 * esr_thickness + short_elongation_esr_in.at(0)), 0.5 * wrapped_scintillator_z - esr_thickness, 0.5 * wrapped_scintillator_xy - esr_thickness);
UnionSolid odd_0_esr_in(odd_esr_in_0_rect, odd_add_0_esr_in, Position(0.5 * (wrapped_scintillator_xy + short_elongation_esr_in.at(0)), 0, 0));
UnionSolid odd_45_esr_in(esr_in, odd_add_45_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_9_esr_in(esr_in, odd_add_9_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_14_esr_in(esr_in, odd_add_14_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
UnionSolid odd_17_esr_in(esr_in, odd_add_17_esr_in, Position(0.5 * wrapped_scintillator_xy, 0, 0));
// Odd-shaped ESR, from the subtraction of outer and inner frames
Volume odd_0_esr("odd_0_esr", SubtractionSolid(odd_0_esr_out, odd_0_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_45_esr("odd_45_esr", SubtractionSolid(odd_45_esr_out, odd_45_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_9_esr("odd_9_esr", SubtractionSolid(odd_9_esr_out, odd_9_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_14_esr("odd_14_esr", SubtractionSolid(odd_14_esr_out, odd_14_esr_in, Position(0, 0, 0)), mat_ESR);
Volume odd_17_esr("odd_17_esr", SubtractionSolid(odd_17_esr_out, odd_17_esr_in, Position(0, 0, 0)), mat_ESR);
// Positions
const double scintillator_pos_z = -0.5 * non_absorber_thickness + boundary_safety + 0.5 * wrapped_scintillator_z;
const double esr_pos_z = scintillator_pos_z;
const double pcb_pos_z = esr_pos_z + 0.5 * wrapped_scintillator_z + boundary_safety + 0.5 * pcb_thickness;
// Loop for placing the units in a layer
for (int ir = 1; ir <= Nrows; ++ir)
{
const double layer_length = dim_in + (ir - 1) * wrapped_scintillator_xy * tan(0.5 * angle);
Ncells_phi = (int) (2 * layer_length / wrapped_scintillator_xy);
const double layer_phi = Ncells_phi * wrapped_scintillator_xy;
const double single_elongation = layer_length - 0.5 * layer_phi;
Volume slice("slice", Trapezoid(layer_length, layer_length + elongation_angle_esr_out, 0.5 * non_absorber_thickness, 0.5 * non_absorber_thickness, 0.5 * (wrapped_scintillator_xy + boundary_safety)), mat_air);
slice.setVisAttributes(theDetector, "SeeThrough");
string slicename = "Slice_" + to_string(ir);
DetElement sd(stave_det, slicename, det_id);
Volume slice_pcb("slice_pcb", Box(0.5 * layer_phi, 0.5 * pcb_thickness, 0.5 * wrapped_scintillator_xy), mat_PCB);
slice_pcb.setVisAttributes(theDetector, "SeeThrough");
PlacedVolume pcb_unit = slice.placeVolume(slice_pcb, Position(0, pcb_pos_z, 0));
pcb_unit.addPhysVolID("row", ir);
for (int iphi = 1; iphi <= Ncells_phi; ++iphi)
{
PlacedVolume scintillator_unit;
PlacedVolume esr_unit;
Position position_scintillator((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy, scintillator_pos_z, 0);
Position position_esr((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy, esr_pos_z, 0);
Transform3D transform_scintillator(RotationZ(pi), position_scintillator);
Transform3D transform_esr(RotationZ(pi), position_esr);
if (iphi == 1)
{
if (single_elongation >= short_elongation_esr_out.at(4))
{
scintillator_unit = slice.placeVolume(odd_17_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_17_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(3))
{
scintillator_unit = slice.placeVolume(odd_14_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_14_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(2))
{
scintillator_unit = slice.placeVolume(odd_9_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_9_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(1))
{
scintillator_unit = slice.placeVolume(odd_45_scintillator, transform_scintillator);
esr_unit = slice.placeVolume(odd_45_esr, transform_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(0))
{
scintillator_unit = slice.placeVolume(odd_0_scintillator, Transform3D(RotationZ(pi),
Position((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy - 0.5 * short_elongation_esr_in.at(0),
scintillator_pos_z,
0)));
esr_unit = slice.placeVolume(odd_0_esr, transform_esr);
}
}
else if (iphi == Ncells_phi)
{
if (single_elongation >= short_elongation_esr_out.at(4))
{
scintillator_unit = slice.placeVolume(odd_17_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_17_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(3))
{
scintillator_unit = slice.placeVolume(odd_14_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_14_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(2))
{
scintillator_unit = slice.placeVolume(odd_9_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_9_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(1))
{
scintillator_unit = slice.placeVolume(odd_45_scintillator, position_scintillator);
esr_unit = slice.placeVolume(odd_45_esr, position_esr);
}
else if (single_elongation >= short_elongation_esr_out.at(0))
{
scintillator_unit = slice.placeVolume(odd_0_scintillator,
Position((-0.5 * (Ncells_phi + 1) + iphi) * wrapped_scintillator_xy + 0.5 * short_elongation_esr_in.at(0),
scintillator_pos_z,
0));
esr_unit = slice.placeVolume(odd_0_esr, position_esr);
}
}
else
{
scintillator_unit = slice.placeVolume(scintillator, position_scintillator);
esr_unit = slice.placeVolume(esr, position_esr);
}
scintillator_unit.addPhysVolID("row", ir).addPhysVolID("phi", iphi);
esr_unit.addPhysVolID("row", ir).addPhysVolID("phi", iphi);
string scintillator_name = "Scintillator_" + to_string(ir) + "_" + to_string(iphi);
DetElement unit(sd, scintillator_name, det_id);
unit.setPlacement(scintillator_unit);
}
PlacedVolume plv = layer_vol.placeVolume(slice, Position(0, 0, (-0.5 * (Nrows + 1) + ir) * (wrapped_scintillator_xy + boundary_safety)));
plv.addPhysVolID("row", ir);
sd.setPlacement(plv);
}
// Loop for placing the layers in a module
for (int ilayer = 1; ilayer <= Nlayers; ++ilayer)
{
PlacedVolume plv = stave_vol.placeVolume(layer_vol, Position(0, (ilayer - 1) * layer_thickness + cassette_thickness + 0.5 * non_absorber_thickness - 0.5 * module_thickness, 0));
plv.addPhysVolID("layer", ilayer);
DetElement sd(stave_det, _toString(ilayer, "layer_%3d"), det_id);
sd.setPlacement(plv);
}
// Loop for placing the modules
for (int i = 0; i < Nmodules; ++i)
{
const double m_rot = i * angle;
const double posx = -r0 * sin(m_rot);
const double posy = r0 * cos(m_rot);
Transform3D transform_neg(RotationZ(m_rot) * RotationX(-0.5 * pi), Position(posx, posy, 0));
Transform3D transform_pos(RotationZ(m_rot) * RotationY(pi) * RotationX(-0.5 * pi), Position(posx, posy, 2 * pos_z));
PlacedVolume plv_neg = envelopeVol.placeVolume(stave_vol, transform_neg);
PlacedVolume plv_pos = envelopeVol.placeVolume(stave_vol, transform_pos);
plv_neg.addPhysVolID("stave", i);
plv_pos.addPhysVolID("stave", i + Nmodules);
DetElement sd_neg(AHCAL, _toString(i, "sector%3d"), det_id);
DetElement sd_pos(AHCAL, _toString(i + Nmodules, "sector%3d"), det_id);
sd_neg.setPlacement(plv_neg);
sd_pos.setPlacement(plv_pos);
}
sens.setType("calorimeter");
MYDEBUG("create_detector FINISHED.");
return AHCAL;
}
DECLARE_DETELEMENT(SHcalSc04_Endcaps_v02, create_detector)
//====================================================================
// lcgeo - LC detector models in DD4hep
//--------------------------------------------------------------------
// DD4hep Geometry driver for YokeBarrel
// Ported from Mokka
//--------------------------------------------------------------------
// S.Lu, DESY
// $Id$
//====================================================================
// *********************************************************
// * Mokka *
// * -- A Detailed Geant 4 Simulation for the ILC -- *
// * *
// * polywww.in2p3.fr/geant4/tesla/www/mokka/mokka.html *
// *********************************************************
//
// $Id$
// $Name: $
//
// History:
// - first implementation P. Mora de Freitas (May 2001)
// - selectable symmetry, self-scaling, removed pole tips
// - Adrian Vogel, 2006-03-17
// - muon system plus
// instrumented pole tip back for TESLA models
// - Predrag Krstonosic , 2006-08-30
// - added barrelEndcapGap, gear parameters, made barrel
// and endcap same thickness, made plug insensitive,
// - F.Gaede, DESY 2008-10-04
//
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "TGeoTrd2.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
using namespace std;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::Box;
using dd4hep::DetElement;
using dd4hep::DetType;
using dd4hep::Detector;
using dd4hep::Layering;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::PolyhedraRegular;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::Rotation3D;
using dd4hep::RotationZYX;
using dd4hep::Segmentation;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Volume;
using dd4hep::_toString;
using dd4hep::rec::LayeredCalorimeterData;
#define VERBOSE 1
// workaround for DD4hep v00-14 (and older)
#ifndef DD4HEP_VERSION_GE
#define DD4HEP_VERSION_GE(a,b) 0
#endif
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
static double tolerance = 0e0;
xml_det_t x_det = element;
string det_name = x_det.nameStr();
Layering layering (element);
xml_comp_t x_dim = x_det.dimensions();
int nsides = x_dim.numsides();
Material air = theDetector.air();
xml_comp_t x_staves = x_det.staves();
Material yokeMaterial = theDetector.material(x_staves.materialStr());
//unused: Material env_mat = theDetector.material(x_dim.materialStr());
xml_comp_t env_pos = x_det.position();
xml_comp_t env_rot = x_det.rotation();
Position pos(env_pos.x(),env_pos.y(),env_pos.z());
RotationZYX rotZYX(env_rot.z(),env_rot.y(),env_rot.x());
Transform3D tr(rotZYX,pos);
int det_id = x_det.id();
DetElement sdet (det_name,det_id);
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ;
dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
//-----------------------------------------------------------------------------------
sens.setType("calorimeter");
//====================================================================
//
// Read all the constant from ILD_o1_v05.xml
// Use them to build Yoke05Barrel
//
//====================================================================
double Yoke_barrel_inner_radius = theDetector.constant<double>("Yoke_barrel_inner_radius");
//double Yoke_thickness = theDetector.constant<double>("Yoke_thickness");
//double Yoke_Barrel_Half_Z = theDetector.constant<double>("Yoke_Barrel_Half_Z");
double Yoke_Z_start_endcaps = theDetector.constant<double>("Yoke_Z_start_endcaps");
//double Yoke_cells_size = theDetector.constant<double>("Yoke_cells_size");
//Database *db = new Database(env.GetDBName());
//db->exec("SELECT * FROM `yoke`;");
//db->getTuple();
////... Geometry parameters from the environment and from the database
//symmetry = db->fetchInt("symmetry");
//const G4double rInnerBarrel =
// env.GetParameterAsDouble("Yoke_barrel_inner_radius");
//const G4double rInnerEndcap =
// env.GetParameterAsDouble("Yoke_endcap_inner_radius");
//const G4double zStartEndcap =
// env.GetParameterAsDouble("Yoke_Z_start_endcaps");
//
//db->exec("SELECT * FROM `muon`;");
//db->getTuple();
//iron_thickness = db->fetchDouble("iron_thickness");
//G4double gap_thickness = db->fetchDouble("layer_thickness");
//number_of_layers = db->fetchInt("number_of_layers");
//G4double yokeBarrelEndcapGap = db->fetchInt("barrel_endcap_gap");
//G4double cell_dim_x = db->fetchDouble("cell_size");
//G4double cell_dim_z = db->fetchDouble("cell_size");
//G4double chamber_thickness = 10*mm;
double yokeBarrelEndcapGap = 2.5;// ?? theDetector.constant<double>("barrel_endcap_gap"); //25.0*mm
//====================================================================
//
// general calculated parameters
//
//====================================================================
//port from Mokka Yoke05, the following parameters used by Yoke05
int symmetry = nsides;
double rInnerBarrel = Yoke_barrel_inner_radius;
double zStartEndcap = Yoke_Z_start_endcaps; // has been updated to 4072.0*mm by driver SCoil02
//TODO: put all magic numbers into ILD_o1_v05.xml file.
double gap_thickness = 4.0;
double iron_thickness = 10.0; //10.0 cm
int number_of_layers = 10;
//... Barrel parameters:
//... tolerance 1 mm
double yokeBarrelThickness = gap_thickness
+ number_of_layers*(iron_thickness + gap_thickness)
+ 3*(5.6*iron_thickness + gap_thickness)
+ 0.1; // the tolerance 1 mm
double rOuterBarrel = rInnerBarrel + yokeBarrelThickness;
double z_halfBarrel = zStartEndcap - yokeBarrelEndcapGap;
// In this release the number of modules is fixed to 3
double Yoke_Barrel_module_dim_z = 2.0*(zStartEndcap-yokeBarrelEndcapGap)/3.0 ;
//double Yoke_cell_dim_x = Yoke_cells_size;
//double Yoke_cell_dim_z = Yoke_Barrel_module_dim_z / floor (Yoke_Barrel_module_dim_z/Yoke_cell_dim_x);
cout<<" Build the yoke within this dimension "<<endl;
cout << " ...Yoke db: symmetry " << symmetry <<endl;
cout << " ...Yoke db: rInnerBarrel " << rInnerBarrel <<endl;
cout << " ...Yoke db: zStartEndcap " << zStartEndcap <<endl;
cout << " ...Muon db: iron_thickness " << iron_thickness <<endl;
cout << " ...Muon db: gap_thickness " << gap_thickness <<endl;
cout << " ...Muon db: number_of_layers " << number_of_layers <<endl;
cout << " ...Muon par: yokeBarrelThickness " << yokeBarrelThickness <<endl;
cout << " ...Muon par: Barrel_half_z " << z_halfBarrel <<endl;
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID
double cell_sizeX = cellSizeVector[0];
double cell_sizeY = cellSizeVector[1];
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
caloData->inner_symmetry = symmetry ;
caloData->outer_symmetry = symmetry ;
caloData->phi0 = 0 ; // also hardcoded below
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = rInnerBarrel ;
caloData->extent[1] = rOuterBarrel ;
caloData->extent[2] = 0. ;
caloData->extent[3] = z_halfBarrel ;
// ========= Create Yoke Barrel module ====================================
PolyhedraRegular YokeBarrelSolid( symmetry, M_PI/2.0-M_PI/symmetry, rInnerBarrel, rOuterBarrel, Yoke_Barrel_module_dim_z);
Volume mod_vol(det_name+"_module", YokeBarrelSolid, yokeMaterial);
//Volume mod_vol(det_name+"_module", YokeBarrelSolid, air);
mod_vol.setVisAttributes(theDetector.visAttributes(x_det.visStr()));
//====================================================================
// Build chamber volume
//====================================================================
//double gap_thickness = db->fetchDouble("layer_thickness");
//-------------------- start loop over Yoke layers ----------------------
// Loop over the sets of layer elements in the detector.
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
int l_num = 1;
for(xml_coll_t li(x_det,_U(layer)); li; ++li) {
xml_comp_t x_layer = li;
int repeat = x_layer.repeat();
// Loop over number of repeats for this layer.
for (int i=0; i<repeat; i++) {
//if(i>11) continue;
string l_name = _toString(l_num,"layer%d");
//double l_thickness = layering.layer(l_num-1)->thickness(); // Layer's thickness.
double l_thickness = layering.layer(i)->thickness(); // Layer's thickness.
//double gap_thickness = l_thickness;
//double iron_thickness = 10.0; //10.0 cm
double radius_low = rInnerBarrel+ 0.05 + i*gap_thickness + i*iron_thickness;
//rInnerBarrel+ 0.5*mm + i*gap_thickness + i*iron_thickness;
//double radius_mid = radius_low+0.5*gap_thickness;
//double radius_sensitive = radius_mid;
if( i>=10 ) radius_low = rInnerBarrel + 0.05 + i*gap_thickness + (i+(i-10)*4.6)*iron_thickness;
//{ radius_low =
// rInnerBarrel + 0.5*mm + i*gap_thickness
// + (i+(i-10)*4.6)*iron_thickness;
//radius_mid = radius_low+0.5*gap_thickness;
//radius_sensitive = radius_mid;
//}
//... safety margines of 0.1 mm for x,y of chambers
//double dx = radius_low*tan(Angle2)-0.1*mm;
//double dy = (zStartEndcap-yokeBarrelEndcapGap)/3.0-0.1*mm;
double Angle2 = M_PI/symmetry;
double dx = radius_low*tan(Angle2)-0.01;
double dy = (zStartEndcap-yokeBarrelEndcapGap)/3.0-0.01;
//Box ChamberSolid(dx,gap_thickness/2.,dy);
//Volume ChamberLog("muonSci",ChamberSolid,air);
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
Box ChamberSolid(dx,l_thickness/2.0, dy);
Volume ChamberLog(det_name+"_"+l_name,ChamberSolid,air);
DetElement layer(l_name, det_id);
ChamberLog.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));
// Loop over the sublayers or slices for this layer.
int s_num = 1;
double s_pos_y = -(l_thickness / 2);
//--------------------------------------------------------------------------------
// Build Layer, Sensitive Scintilator in the middle, and Air tolorance at two sides
//--------------------------------------------------------------------------------
double radiator_thickness = 0.05; // Yoke05 Barrel: No radiator before first sensitive layer.
if ( i>0 ) radiator_thickness = gap_thickness + iron_thickness - l_thickness;
if ( i>=10 ) radiator_thickness = gap_thickness + 5.6*iron_thickness - l_thickness;
nRadiationLengths = radiator_thickness/(yokeMaterial.radLength());
nInteractionLengths = radiator_thickness/(yokeMaterial.intLength());
thickness_sum = radiator_thickness;
for(xml_coll_t si(x_layer,_U(slice)); si; ++si) {
xml_comp_t x_slice = si;
string s_name = _toString(s_num,"slice%d");
double s_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
s_pos_y += s_thickness/2.;
double slab_dim_x = dx-tolerance;
double slab_dim_y = s_thickness/2.;
double slab_dim_z = dy-tolerance;
Box s_box(slab_dim_x,slab_dim_y,slab_dim_z);
Volume s_vol(det_name+"_"+l_name+"_"+s_name,s_box,slice_material);
DetElement slice(layer,s_name,det_id);
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
if ( x_slice.isSensitive() ) {
s_vol.setSensitiveDetector(sens);
std::cout << " ...Barrel i, position: " << i << " " << radius_low + l_thickness/2.0 + s_pos_y << std::endl;
#if DD4HEP_VERSION_GE( 0, 15 )
//Store "inner" quantities
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
//Store scintillator thickness
caloLayer.sensitive_thickness = s_thickness;
#endif
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
// Set region, limitset, and vis.
s_vol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
Position s_pos(0,s_pos_y,0); // Position of the layer.
PlacedVolume s_phv = ChamberLog.placeVolume(s_vol,s_pos);
slice.setPlacement(s_phv);
// Increment x position for next slice.
s_pos_y += s_thickness/2.;
++s_num;
}
#if DD4HEP_VERSION_GE( 0, 15 )
//Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
#endif
++l_num;
double phirot = 0;
for(int j=0;j<symmetry;j++)
{
double Y = radius_low + l_thickness/2.0;
Position xyzVec(-Y*sin(phirot), Y*cos(phirot), 0);
RotationZYX rot(phirot,0,0);
Rotation3D rot3D(rot);
Transform3D tran3D(rot3D,xyzVec);
PlacedVolume layer_phv = mod_vol.placeVolume(ChamberLog,tran3D);
layer_phv.addPhysVolID("layer", l_num).addPhysVolID("stave",j+1);
string stave_name = _toString(j+1,"stave%d");
string stave_layer_name = stave_name+_toString(l_num,"layer%d");
DetElement stave(stave_layer_name,det_id);;
stave.setPlacement(layer_phv);
sdet.add(stave);
phirot -= M_PI/symmetry*2.0;
}
//-----------------------------------------------------------------------------------------
caloLayer.distance = radius_low - radiator_thickness ;
caloLayer.absorberThickness = radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
//-----------------------------------------------------------------------------------------
}
}
//====================================================================
// Place Yoke05 Barrel stave module into the world volume
//====================================================================
for (int module_id = 1; module_id < 4; module_id++)
{
double module_z_offset = (module_id-2) * Yoke_Barrel_module_dim_z;
Position mpos(0,0,module_z_offset);
PlacedVolume m_phv = envelope.placeVolume(mod_vol,mpos);
m_phv.addPhysVolID("module",module_id).addPhysVolID("system", det_id);
m_phv.addPhysVolID("tower", 1);// Not used
string m_name = _toString(module_id,"module%d");
DetElement sd (m_name,det_id);
sd.setPlacement(m_phv);
sdet.add(sd);
}
sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
return sdet;
}
DECLARE_DETELEMENT(Yoke05_Barrel,create_detector)
//====================================================================
// lcgeo - LC detector models in DD4hep
//--------------------------------------------------------------------
// DD4hep Geometry driver for YokeEndcaps
// Ported from Mokka
//--------------------------------------------------------------------
// S.Lu, DESY
// $Id$
//====================================================================
// *********************************************************
// * Mokka *
// * -- A Detailed Geant 4 Simulation for the ILC -- *
// * *
// * polywww.in2p3.fr/geant4/tesla/www/mokka/mokka.html *
// *********************************************************
//
// $Id$
// $Name: $
//
// History:
// - first implementation P. Mora de Freitas (May 2001)
// - selectable symmetry, self-scaling, removed pole tips
// - Adrian Vogel, 2006-03-17
// - muon system plus
// instrumented pole tip back for TESLA models
// - Predrag Krstonosic , 2006-08-30
// - added barrelEndcapGap, gear parameters, made barrel
// and endcap same thickness, made plug insensitive,
// - F.Gaede, DESY 2008-10-04
//
#include "DD4hep/DetFactoryHelper.h"
#include "DD4hep/DetType.h"
#include "XML/Layering.h"
#include "XML/Utilities.h"
#include "DDRec/DetectorData.h"
using namespace std;
using dd4hep::BUILD_ENVELOPE;
using dd4hep::DetElement;
using dd4hep::DetType;
using dd4hep::Detector;
using dd4hep::Layering;
using dd4hep::Material;
using dd4hep::PlacedVolume;
using dd4hep::PolyhedraRegular;
using dd4hep::Position;
using dd4hep::Readout;
using dd4hep::Ref_t;
using dd4hep::Rotation3D;
using dd4hep::RotationZYX;
using dd4hep::Segmentation;
using dd4hep::SensitiveDetector;
using dd4hep::Transform3D;
using dd4hep::Volume;
using dd4hep::_toString;
using dd4hep::rec::LayeredCalorimeterData;
#define VERBOSE 1
// workaround for DD4hep v00-14 (and older)
#ifndef DD4HEP_VERSION_GE
#define DD4HEP_VERSION_GE(a,b) 0
#endif
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens) {
double tolerance = 0.1;
xml_det_t x_det = element;
string det_name = x_det.nameStr();
Layering layering (element);
xml_comp_t x_dim = x_det.dimensions();
int nsides = x_dim.numsides();
Material air = theDetector.air();
//unused: Material vacuum = theDetector.vacuum();
Material yokeMaterial = theDetector.material(x_det.materialStr());;
int det_id = x_det.id();
DetElement sdet (det_name,det_id);
// --- create an envelope volume and position it into the world ---------------------
Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ;
dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
//-----------------------------------------------------------------------------------
sens.setType("calorimeter");
//====================================================================
//
// Read all the constant from ILD_o1_v05.xml
// Use them to build Yoke05Endcaps
//
//====================================================================
double Yoke_barrel_inner_radius = theDetector.constant<double>("Yoke_barrel_inner_radius");
double Yoke_endcap_inner_radius = theDetector.constant<double>("Yoke_endcap_inner_radius");
double Yoke_Z_start_endcaps = theDetector.constant<double>("Yoke_Z_start_endcaps");
double HCAL_R_max = theDetector.constant<double>("Hcal_outer_radius");
//double Yoke_cells_size = theDetector.constant<double>("Yoke_cells_size");
double yokeBarrelEndcapGap = 2.5;// ?? theDetector.constant<double>("barrel_endcap_gap"); //25.0*mm
//====================================================================
//
// general calculated parameters
//
//====================================================================
//port from Mokka Yoke05, the following parameters used by Yoke05
int symmetry = nsides;
double rInnerBarrel = Yoke_barrel_inner_radius;
double zStartEndcap = Yoke_Z_start_endcaps; // has been updated to 4072.0*mm by driver SCoil02
//TODO: put all magic numbers into ILD_o1_v05.xml file.
double gap_thickness = 4.0;
double iron_thickness = 10.0; //10.0 cm
int number_of_layers = 10;
//... Barrel parameters:
//... tolerance 1 mm
double yokeBarrelThickness = gap_thickness
+ number_of_layers*(iron_thickness + gap_thickness)
+ 3*(5.6*iron_thickness + gap_thickness)
+ 0.1; // the tolerance 1 mm
double yokeEndcapThickness = number_of_layers*(iron_thickness + gap_thickness)
+ 2*(5.6*iron_thickness + gap_thickness); // + gap_thickness;
double rInnerEndcap = Yoke_endcap_inner_radius;
double rOuterEndcap = rInnerBarrel + yokeBarrelThickness;
double z_halfBarrel = zStartEndcap - yokeBarrelEndcapGap;
//Port from Mokka:
// Endcap Thickness has no tolerance
// But the placement should shift_middle by -0.05 (0.5*mm) later
double Yoke_Endcap_module_dim_z = yokeEndcapThickness;
//double Yoke_cell_dim_x = rOuterEndcap*2.0 / floor (rOuterEndcap*2.0/Yoke_cells_size);
//double Yoke_cell_dim_y = Yoke_cell_dim_x;
cout<<" Build the yoke within this dimension "<<endl;
cout << " ...Yoke db: symmetry " << symmetry <<endl;
cout << " ...Yoke db: rInnerEndcap " << rInnerEndcap <<endl;
cout << " ...Yoke db: rOuterEndcap " << rOuterEndcap <<endl;
cout << " ...Yoke db: zStartEndcap " << zStartEndcap <<endl;
cout << " ...Muon db: iron_thickness " << iron_thickness <<endl;
cout << " ...Muon db: gap_thickness " << gap_thickness <<endl;
cout << " ...Muon db: number_of_layers " << number_of_layers <<endl;
cout << " ...Muon par: yokeEndcapThickness " << yokeEndcapThickness <<endl;
cout << " ...Muon par: Barrel_half_z " << z_halfBarrel <<endl;
Readout readout = sens.readout();
Segmentation seg = readout.segmentation();
std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID
double cell_sizeX = cellSizeVector[0];
double cell_sizeY = cellSizeVector[1];
//========== fill data for reconstruction ============================
LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
caloData->inner_symmetry = symmetry ;
caloData->outer_symmetry = symmetry ;
caloData->phi0 = 0 ; // hardcoded
/// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
caloData->extent[0] = rInnerEndcap ;
caloData->extent[1] = rOuterEndcap ;
caloData->extent[2] = zStartEndcap ;
caloData->extent[3] = zStartEndcap + Yoke_Endcap_module_dim_z ;
PolyhedraRegular YokeEndcapSolid( symmetry, M_PI/symmetry, rInnerEndcap, rOuterEndcap, Yoke_Endcap_module_dim_z);
Volume mod_vol(det_name+"_module", YokeEndcapSolid, yokeMaterial);
mod_vol.setVisAttributes(theDetector.visAttributes(x_det.visStr()));
//====================================================================
// Build chamber volume
//====================================================================
//double gap_thickness = db->fetchDouble("layer_thickness");
//-------------------- start loop over Yoke layers ----------------------
// Loop over the sets of layer elements in the detector.
double nRadiationLengths=0.;
double nInteractionLengths=0.;
double thickness_sum=0;
int l_num = 1;
for(xml_coll_t li(x_det,_U(layer)); li; ++li) {
xml_comp_t x_layer = li;
int repeat = x_layer.repeat();
// Loop over number of repeats for this layer.
for (int i=0; i<repeat; i++) {
//if(i>11) continue;
string l_name = _toString(l_num,"layer%d");
double l_thickness = layering.layer(i)->thickness(); // Layer's thickness.
LayeredCalorimeterData::Layer caloLayer ;
caloLayer.cellSize0 = cell_sizeX;
caloLayer.cellSize1 = cell_sizeY;
PolyhedraRegular ChamberSolid( symmetry, M_PI/symmetry, rInnerEndcap + tolerance, rOuterEndcap - tolerance, l_thickness);
Volume ChamberLog(det_name+"_"+l_name,ChamberSolid,air);
DetElement layer(l_name, det_id);
ChamberLog.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));
// Loop over the sublayers or slices for this layer.
int s_num = 1;
double s_pos_z = -(l_thickness / 2);
double shift_middle = - yokeEndcapThickness/2 - 0.05 //-0.5*mm since PolyhedraRegular from -Yoke_Endcap_module_dim_z/2 to Yoke_Endcap_module_dim_z/2
+ iron_thickness*(i+1)
+ (i+0.5)*gap_thickness;
if( i>= 10){
shift_middle = - yokeEndcapThickness/2 - 0.05 //0.5*mm
+ iron_thickness*(i+1+(i-9)*4.6) + (i+0.5)*gap_thickness;
}
//--------------------------------------------------------------------------------
// Build Layer, Sensitive Scintilator in the middle, and Air tolorance at two sides
//--------------------------------------------------------------------------------
double radiator_thickness = -0.05 + 0.5*gap_thickness + iron_thickness - l_thickness/2.0 ;
if ( i>0 ) radiator_thickness = gap_thickness + iron_thickness - l_thickness ;
if ( i>=10 ) radiator_thickness = gap_thickness + 5.6*iron_thickness - l_thickness ;
nRadiationLengths = radiator_thickness/(yokeMaterial.radLength());
nInteractionLengths = radiator_thickness/(yokeMaterial.intLength());
thickness_sum = radiator_thickness;
for(xml_coll_t si(x_layer,_U(slice)); si; ++si) {
xml_comp_t x_slice = si;
string s_name = _toString(s_num,"slice%d");
double s_thickness = x_slice.thickness();
Material slice_material = theDetector.material(x_slice.materialStr());
s_pos_z += s_thickness/2.;
PolyhedraRegular sliceSolid( symmetry, M_PI/symmetry, rInnerEndcap + tolerance + 0.01, rOuterEndcap - tolerance -0.01, s_thickness);
Volume s_vol(det_name+"_"+l_name+"_"+s_name,sliceSolid,slice_material);
DetElement slice(layer,s_name,det_id);
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
if ( x_slice.isSensitive() ) {
s_vol.setSensitiveDetector(sens);
cout << " ...Endcap i, position: " << i << " " << zStartEndcap + yokeEndcapThickness/2 + shift_middle + l_thickness/2.0 + s_pos_z << endl;
#if DD4HEP_VERSION_GE( 0, 15 )
//Store "inner" quantities
caloLayer.inner_nRadiationLengths = nRadiationLengths;
caloLayer.inner_nInteractionLengths = nInteractionLengths;
caloLayer.inner_thickness = thickness_sum;
//Store scintillator thickness
caloLayer.sensitive_thickness = s_thickness;
#endif
//Reset counters to measure "outside" quantitites
nRadiationLengths=0.;
nInteractionLengths=0.;
thickness_sum = 0.;
}
nRadiationLengths += s_thickness/(2.*slice_material.radLength());
nInteractionLengths += s_thickness/(2.*slice_material.intLength());
thickness_sum += s_thickness/2;
// Set region, limitset, and vis.
s_vol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
Position s_pos(0,0,s_pos_z); // Position of the layer.
PlacedVolume s_phv = ChamberLog.placeVolume(s_vol,s_pos);
slice.setPlacement(s_phv);
// Increment x position for next slice.
s_pos_z += s_thickness/2.;
++s_num;
}
#if DD4HEP_VERSION_GE( 0, 15 )
//Store "outer" quantities
caloLayer.outer_nRadiationLengths = nRadiationLengths;
caloLayer.outer_nInteractionLengths = nInteractionLengths;
caloLayer.outer_thickness = thickness_sum;
#endif
++l_num;
Position xyzVec(0,0,shift_middle);
PlacedVolume layer_phv = mod_vol.placeVolume(ChamberLog,xyzVec);
layer_phv.addPhysVolID("layer", l_num);
//string stave_name = "stave1";
string stave_layer_name = "stave1"+_toString(l_num,"layer%d");
DetElement stave(stave_layer_name,det_id);;
stave.setPlacement(layer_phv);
sdet.add(stave);
//-----------------------------------------------------------------------------------------
caloLayer.distance = zStartEndcap + yokeEndcapThickness/2.0 + shift_middle
- caloLayer.inner_thickness ;
caloLayer.absorberThickness = radiator_thickness ;
caloData->layers.push_back( caloLayer ) ;
//-----------------------------------------------------------------------------------------
}
}
//====================================================================
// Check Yoke05 plug module
//====================================================================
bool build_plug = false;
double HCAL_z = theDetector.constant<double>("HcalEndcap_max_z");;
double HCAL_plug_gap = theDetector.constant<double>("Hcal_Yoke_plug_gap");
int Hcal_endcap_outer_symmetry = theDetector.constant<int>("Hcal_endcap_outer_symmetry");
double plug_thickness = zStartEndcap-HCAL_z-HCAL_plug_gap;
double rInnerPlug = Yoke_endcap_inner_radius;
double rOuterPlug = HCAL_R_max*cos(dd4hep::pi/16.) *cos(dd4hep::pi/Hcal_endcap_outer_symmetry);
double Yoke_Plug_module_dim_z = plug_thickness;
// Is there a space to build Yoke plug
if( Yoke_Plug_module_dim_z > 0 )
{
build_plug = true;
cout << " ...Plug par: build_plug is true, there is space to build yoke plug" <<endl;
cout << " ...Plug par: HCAL_half_z " << HCAL_z <<endl;
cout << " ...Plug par: HCAL_Plug_Gap " << HCAL_plug_gap <<endl;
cout << " ...Plug par: Plug Thickness " << plug_thickness <<endl;
cout << " ...Plug par: Plug Radius " << rOuterPlug <<endl;
}
//====================================================================
// Place Yoke05 Endcaps module into the world volume
//====================================================================
double zEndcap = zStartEndcap + yokeEndcapThickness/2.0 + 0.1; // Need 0.1 (1.0*mm) according to the Mokka Yoke05 driver.
double zPlug = zStartEndcap - plug_thickness/2.0 -0.05; // Need 0.05 (0.5*mm) according to the Mokka Yoke05 driver.
for(int module_num=0;module_num<2;module_num++) {
int module_id = ( module_num == 0 ) ? 0:6;
double this_module_z_offset = ( module_id == 0 ) ? - zEndcap : zEndcap;
double this_module_rotY = ( module_id == 0 ) ? M_PI:0;
Position xyzVec(0,0,this_module_z_offset);
RotationZYX rot(0,this_module_rotY,0);
Rotation3D rot3D(rot);
Transform3D tran3D(rot3D,xyzVec);
PlacedVolume pv = envelope.placeVolume(mod_vol,tran3D);
pv.addPhysVolID("module",module_id); // z: -/+ 0/6
string m_name = _toString(module_id,"module%d");
DetElement sd (m_name,det_id);
sd.setPlacement(pv);
sdet.add(sd);
//====================================================================
// If build_plug is true, Place the plug module into the world volume
//====================================================================
if(build_plug == true){
PolyhedraRegular YokePlugSolid( symmetry, M_PI/symmetry, rInnerPlug, rOuterPlug, Yoke_Plug_module_dim_z);
Volume plug_vol(det_name+"_plug", YokePlugSolid, yokeMaterial);
plug_vol.setVisAttributes(theDetector.visAttributes(x_det.visStr()));
double this_plug_z_offset = ( module_id == 0 ) ? - zPlug : zPlug;
Position plug_pos(0,0,this_plug_z_offset);
PlacedVolume plug_phv = envelope.placeVolume(plug_vol,plug_pos);
string plug_name = _toString(module_id,"plug%d");
DetElement plug (plug_name,det_id);
plug.setPlacement(plug_phv);
}
}
sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
return sdet;
}
DECLARE_DETELEMENT(Yoke05_Endcaps,create_detector)