diff --git a/athena.xml b/athena.xml index 89f8c620e6a9bb737f8bce93de1cf61a40e4984b..8592b4afe6594eec8b946ac22d82ca5082fd1837 100644 --- a/athena.xml +++ b/athena.xml @@ -164,7 +164,7 @@ <!--include ref="compact/dirc.xml"/--> <!--include ref="compact/mrich.xml"/--> <include ref="compact/forward_trd.xml"/> - <include ref="compact/gaseous_rich.xml"/> + <include ref="compact/drich.xml"/> <documentation level="10"> ## Central calorimetry diff --git a/compact/definitions.xml b/compact/definitions.xml index f44c6e99011b788bb6718fee974178dd6bcd81cb..dc7901d34a07c1104d6f9bb313b77c1cbf37c20a 100644 --- a/compact/definitions.xml +++ b/compact/definitions.xml @@ -324,7 +324,7 @@ Examples: ### PID Detector Region Parameters </documentation> - <constant name="ForwardRICH_length" value="1.1*m"/> + <constant name="ForwardRICH_length" value="180.0*cm"/> <constant name="ForwardTRD_length" value="10.0*cm"/> <constant name="ForwardTOF_length" value="3.0*cm"/> @@ -353,7 +353,7 @@ Examples: Generic tracking space allocations </documentation> - <constant name="ForwardTracking_length" value="0.0*cm"/> + <constant name="ForwardTracking_length" value="25.0*cm"/> <documentation> `BackwardTracking_length` and `ForwardTracking_length` compensate for the asymmetry of the setup </documentation> diff --git a/compact/display.xml b/compact/display.xml index d20038bedd9c4eae65fc735e3fb10f567633a3e5..2aeb55714c26ce59bdc3560ceee2e269b34d6d6d 100644 --- a/compact/display.xml +++ b/compact/display.xml @@ -77,6 +77,15 @@ <vis name="ci_GEMVis" r= "0.8" g="0.4" b="0.3" alpha="0.8" showDaughters="true" visible="true"/> <vis name="ci_HCALVis" r= "0.6" g="0" b="0.6" alpha="1.0" showDaughters="true" visible="true"/> + <vis name="DRICH_vessel_vis" alpha="1.0" r="1.0" g="1.0" b="1.0" showDaughters="true" visible="true" /> + <vis name="DRICH_gas_vis" alpha="1.0" r="1.0" g="0.0" b="0.0" showDaughters="true" visible="true" /> + <vis name="DRICH_aerogel_vis" alpha="1.0" r="0.0" g="1.0" b="1.0" showDaughters="true" visible="true" /> + <vis name="DRICH_filter_vis" alpha="1.0" r="1.0" g="1.0" b="0.0" showDaughters="true" visible="true" /> + <vis name="DRICH_mirror_vis" alpha="1.0" r="0.5" g="0.5" b="0.5" showDaughters="true" visible="true" /> + <vis name="DRICH_sensor_vis" alpha="1.0" r="0.0" g="1.0" b="0.0" showDaughters="true" visible="true" /> + + </display> + <comment> Deprecated colors. vis name="GreenVis" alpha="1.0" r= "0.0" g="1.0" b="0.0" showDaughters="true" visible="true"/ diff --git a/compact/drich.xml b/compact/drich.xml new file mode 100644 index 0000000000000000000000000000000000000000..6a700900565736d4acd92b83ba53f4dc193efdae --- /dev/null +++ b/compact/drich.xml @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="UTF-8"?> +<lccdd> + + <define> + <!-- TODO [low priority]: some of these, viz. radii, could be parameterized + with respect to other variables; for now they are hard coded in case + other detectors' parameters are changing --> + <!-- parameters for re-scaling fun4all design to ATHENA --> + <constant name="DRICH_scale" value="0.963"/> <!-- overall scale factor from fun4all to ATHENA --> + <constant name="DRICH_f4a_length" value="161.0*cm"/> <!-- z-length of fun4all design --> + <!-- vessel (=snout+tank) geometry --> + <constant name="DRICH_zmin" value="BarrelTracking_length/2.0 + ForwardTracking_length "/> <!-- vessel front --> + <constant name="DRICH_Length" value="ForwardRICH_length"/> <!-- overall vessel length (including snout) --> + <constant name="DRICH_rmin0" value="ForwardPID_rmin1"/> <!-- bore radius at dRICh vessel frontplane --> + <constant name="DRICH_rmin1" value="19.0*cm"/> <!-- bore radius at dRICh vessel backplane --> + <constant name="DRICH_wall_thickness" value="0.5*cm"/> <!-- thickness of radial walls --> + <constant name="DRICH_window_thickness" value="0.1*cm"/> <!-- thickness of entrance and exit walls --> + <!-- snout geometry: cone with front radius rmax0 and back radius of rmax1 --> + <constant name="DRICH_SnoutLength" value="50.0*cm"/> + <constant name="DRICH_rmax0" value="110.0*cm"/> + <constant name="DRICH_rmax1" value="125.0*cm"/> + <!-- tank geometry: cylinder, holding the majority of detector components --> + <constant name="DRICH_rmax2" value="200*cm"/> <!-- cylinder radius; 20 cm gap between dRICh and HCalBarrel --> + <!-- additional parameters --> + <constant name="DRICH_aerogel_thickness" value="4.0*cm"/> <!-- aerogel thickness --> + </define> + + <detectors> + + <detector + id="ForwardRICH_ID" + name="DRICH" + type="athena_DRICH" + readout="DRICHHits" + gas="C2F6_DRICH" + material="Aluminum" + vis_vessel="DRICH_vessel_vis" + vis_gas="DRICH_gas_vis" + > + + <!-- envelope dimensions (see above) + - `wall_thickness`: thickness of radial walls + - `window_thickness`: thickness of entrance and exit disks + --> + <dimensions + z0="DRICH_zmin" + length="DRICH_Length" + snout_length="DRICH_SnoutLength" + rmin0="DRICH_rmin0" + rmin1="DRICH_rmin1" + rmax0="DRICH_rmax0" + rmax1="DRICH_rmax1" + rmax2="DRICH_rmax2" + nsectors="6" + wall_thickness="DRICH_wall_thickness" + window_thickness="DRICH_window_thickness" + /> + + <!-- radiator defined in a wedge of azimuthal space + - `phiw` is phi width of wedge + - `thickness` defined separately for aerogel and filter + - `frontplane` is the front of the aerogel, w.r.t. front plane of vessel envelope + - `pitch` controls the angle of the radiator (0=vertical) + - filter is applied to backplane of aerogel + --> + <radiator + rmin="DRICH_rmin0 + DRICH_wall_thickness + 2.0*cm" + rmax="DRICH_rmax0 - DRICH_wall_thickness - 2.0*cm" + phiw="56*degree" + frontplane="DRICH_window_thickness + 0.5*DRICH_aerogel_thickness" + pitch="0*degree" + > + <aerogel + material="Aerogel_DRICH" + vis="DRICH_aerogel_vis" + thickness="DRICH_aerogel_thickness" + /> + <filter + material="Acrylic_DRICH" + vis="DRICH_filter_vis" + thickness="0.3*mm" + /> + </radiator> + + + <!-- spherical mirror is part of a sphere + - `rmin` and `rmax` provide polar angle boundaries + - `phiw` is the azimuthal width + - `radius` is the radius of the sphere + - `centerx` is the transverse position of the center + of the sphere, for the sector on the +x axis + - the back of the mirror will pass through `backplane` + - set `debug` to 1 so draw reference sphere instead, view with y-clipping + --> + <mirror + material="Acrylic_DRICH" + surface="MirrorSurface_DRICH" + vis="DRICH_mirror_vis" + backplane="DRICH_Length-2.0*cm" + thickness="0.2*cm" + radius="290*DRICH_scale*cm" + centerx="145*DRICH_scale*cm" + rmin="DRICH_rmin1 + DRICH_wall_thickness + 0.0*cm" + rmax="DRICH_rmax2 - DRICH_wall_thickness - 2.0*cm" + phiw="54*degree" + debug="0" + /> + + <sensors> + <!-- geometry for a single square sensor + - based on Hamamatsu H13700 MAPMT + (https://www.hamamatsu.com/us/en/product/type/H13700/index.html) + - N.B. not ideal for a magnetic field, SiPM matrix would be better + - effective area: 48.5x48.5mm + - enclosure size: 52x52mm + - 16x16 channel matrix (see readout segmentation below) + - pixel size: 3x3mm + - `side` is the side length of the square + - `thickness` is the depth of the sensor + - `gap` provides room between the squares, to help + prevent them from overlapping + - the value of `side` will determine how many sensors there are, + since the sensor placement algorithm will try to place as many + as it can in the specified patch below + --> + <module + material="Silicon" + surface="SensorSurface_DRICH" + vis="DRICH_sensor_vis" + side="48*mm" + thickness="35*mm" + gap="0.5*(52-48)*mm + 2*mm" + /> + <!-- sensors will be tiled on this sphere + - `center{x,y,z} is defined for sector on +x axis, defined w.r.t. snout frontplane, + and `radius` is the sphere radius; the first term of each of these comes from + the fun4all design + - these attributes were determined from a spherical fit to the + sensor placement in the fun4all port + - set `debug` to 1 so draw reference sphere instead, view with y-clipping + --> + <sphere + radius="159.76*DRICH_scale*cm" + centerx="144.91*DRICH_scale*cm" + centery="0*DRICH_scale*cm" + centerz="-197.25*DRICH_scale*cm + DRICH_Length - 0.5*DRICH_scale*DRICH_f4a_length" + debug="0" + /> + <!-- sensors will be limited to a patch of the sphere + - `thetamin` and `thetamax` define pseudorapidity coverage + - `widthfactor` controls the azimuthal coverage, where lower=wider + - `taper` defines half the angle between the azimuthal boundaries + - the size of the sensor controls how many sensors are placed + --> + <sphericalpatch + thetamin="-10*degree" + thetamax="22*degree" + widthfactor="1.8" + taper="56*degree" + /> + </sensors> + + </detector> + </detectors> + + <readouts> + <readout name="DRICHHits"> + <segmentation type="CartesianGridXY" grid_size_x="3*mm" grid_size_y="3*mm"/> + <!-- cellID: 64bits + - bits 1-8: dRICh ID + - bits 9-16: sector number + - bits 17-32: photosensor number + - bits 33-48: x pixel (signed) + - bits 49-64: y pixel (signed) + --> + <id>system:8,sector:8,module:16,x:32:-16,y:-16</id> + </readout> + </readouts> + +</lccdd> diff --git a/compact/materials.xml b/compact/materials.xml index e305c5fad3028b4f4f0cdb0b8d7c51d3d41b1cfe..a1ab3a2ac37b18c2d6fa6310a5154e4320b74c99 100644 --- a/compact/materials.xml +++ b/compact/materials.xml @@ -24,7 +24,7 @@ <composite n="15" ref="C"/> <composite n="7" ref="O"/> </material> - <material name="Quartz"> + <material name="Quartz"> <!-- different density than `SiliconDioxide` --> <D type="density" value="2.2" unit="g/cm3"/> <composite n="1" ref="Si"/> <composite n="2" ref="O"/> @@ -45,11 +45,16 @@ <fraction n="0.998" ref="Fe"/> <fraction n=".002" ref="C"/> </material> - <material name="SiliconOxide"> + <material name="SiliconOxide"> <!-- different density than `SiliconDioxide` --> <D type="density" value="2.65" unit="g/cm3"/> <composite n="1" ref="Si"/> <composite n="2" ref="O"/> </material> + <material name="SiliconDioxide"> <!-- density from `G4_SILICON_DIOXIDE` (NIST DB) --> + <D type="density" value="2.32" unit="g/cm3"/> + <composite n="1" ref="Si"/> + <composite n="2" ref="O"/> + </material> <material name="BoronOxide"> <D type="density" value="2.46" unit="g/cm3"/> <composite n="2" ref="B"/> @@ -258,6 +263,18 @@ <D type="density" value="2.21" unit="g/cm3"/> <composite n="1" ref="C"/> </material> + <material name="PolyvinylAcetate"> + <D type="density" value="1.19" unit="g/cm3"/> + <composite n="4" ref="C"/> + <composite n="6" ref="H"/> + <composite n="2" ref="O"/> + </material> + <material name="Plexiglass"> + <D type="density" value="1.19" unit="g/cm3"/> + <composite n="5" ref="C"/> + <composite n="8" ref="H"/> + <composite n="2" ref="O"/> + </material> <material name="StainlessSteel"> <D type="density" value="8.3" unit="g / cm3"/> <fraction n="0.74" ref="Fe"/> diff --git a/compact/optical_materials.xml b/compact/optical_materials.xml index 75daac07776c820bc5965bea763a7ecafa6957ba..c510b81513c72995cc76a0bb66553f5d9734ef2e 100644 --- a/compact/optical_materials.xml +++ b/compact/optical_materials.xml @@ -47,6 +47,298 @@ 1240*eV/600 1.49 1240*eV/400 1.49 "/> + <!-- BEGIN dRICh material properties + - dumped from fun4all implementation + - see https://github.com/cisbani/dRICh/blob/main/share/source/g4dRIChOptics.hh + --> + <!-- dRICh gas --> + <matrix name="RINDEX__C2F6_DRICH" coldim="2" values=" + 1.7712*eV 1.00075 + 1.92389*eV 1.00075 + 2.10539*eV 1.00075 + 2.3247*eV 1.00075 + 2.59502*eV 1.00076 + 2.93647*eV 1.00076 + 3.38139*eV 1.00077 + 3.98521*eV 1.00078 + 4.85156*eV 1.0008 + 6.19921*eV 1.00084 + "/> + <matrix name="ABSLENGTH__C2F6_DRICH" coldim="2" values=" + 1.7712*eV 1000*mm + 1.92389*eV 1000*mm + 2.10539*eV 1000*mm + 2.3247*eV 1000*mm + 2.59502*eV 1000*mm + 2.93647*eV 1000*mm + 3.38139*eV 1000*mm + 3.98521*eV 1000*mm + 4.85156*eV 1000*mm + 6.19921*eV 1000*mm + "/> + <!-- dRICh aerogel --> + <matrix name="RINDEX__Aerogel_DRICH" coldim="2" values=" + 1.87855*eV 1.01638 + 1.96673*eV 1.01642 + 2.0549*eV 1.01647 + 2.14308*eV 1.01652 + 2.23126*eV 1.01657 + 2.31943*eV 1.01662 + 2.40761*eV 1.01667 + 2.49579*eV 1.01673 + 2.58396*eV 1.01679 + 2.67214*eV 1.01685 + 2.76032*eV 1.01691 + 2.84849*eV 1.01698 + 2.93667*eV 1.01705 + 3.02485*eV 1.01712 + 3.11302*eV 1.01719 + 3.2012*eV 1.01727 + 3.28938*eV 1.01734 + 3.37755*eV 1.01742 + 3.46573*eV 1.01751 + 3.55391*eV 1.01759 + 3.64208*eV 1.01768 + 3.73026*eV 1.01777 + 3.81844*eV 1.01787 + 3.90661*eV 1.01796 + 3.99479*eV 1.01806 + 4.08297*eV 1.01816 + 4.17114*eV 1.01827 + 4.25932*eV 1.01838 + 4.3475*eV 1.01849 + 4.43567*eV 1.0186 + 4.52385*eV 1.01872 + 4.61203*eV 1.01884 + 4.7002*eV 1.01897 + 4.78838*eV 1.01909 + 4.87656*eV 1.01922 + 4.96473*eV 1.01936 + 5.05291*eV 1.0195 + 5.14109*eV 1.01964 + 5.22927*eV 1.01979 + 5.31744*eV 1.01994 + 5.40562*eV 1.02009 + 5.4938*eV 1.02025 + 5.58197*eV 1.02041 + 5.67015*eV 1.02057 + 5.75833*eV 1.02074 + 5.8465*eV 1.02092 + 5.93468*eV 1.0211 + 6.02286*eV 1.02128 + 6.11103*eV 1.02147 + 6.19921*eV 1.02167 + "/> + <matrix name="ABSLENGTH__Aerogel_DRICH" coldim="2" values=" + 1.87855*eV 154*mm + 1.96673*eV 156.17*mm + 2.0549*eV 158.154*mm + 2.14308*eV 159.974*mm + 2.23126*eV 161.651*mm + 2.31943*eV 163.2*mm + 2.40761*eV 164.636*mm + 2.49579*eV 165.97*mm + 2.58396*eV 167.213*mm + 2.67214*eV 168.374*mm + 2.76032*eV 169.461*mm + 2.84849*eV 170.481*mm + 2.93667*eV 171.439*mm + 3.02485*eV 172.342*mm + 3.11302*eV 173.193*mm + 3.2012*eV 173.998*mm + 3.28938*eV 174.759*mm + 3.37755*eV 175.481*mm + 3.46573*eV 176.165*mm + 3.55391*eV 176.817*mm + 3.64208*eV 162.708*mm + 3.73026*eV 140.953*mm + 3.81844*eV 122.516*mm + 3.90661*eV 106.833*mm + 3.99479*eV 93.4428*mm + 4.08297*eV 81.9694*mm + 4.17114*eV 72.1072*mm + 4.25932*eV 63.6011*mm + 4.3475*eV 56.2434*mm + 4.43567*eV 49.8599*mm + 4.52385*eV 44.3054*mm + 4.61203*eV 39.4601*mm + 4.7002*eV 35.2211*mm + 4.78838*eV 31.5049*mm + 4.87656*eV 28.2374*mm + 4.96473*eV 25.359*mm + 5.05291*eV 22.8166*mm + 5.14109*eV 20.5674*mm + 5.22927*eV 18.5724*mm + 5.31744*eV 16.7992*mm + 5.40562*eV 15.2205*mm + 5.4938*eV 13.8125*mm + 5.58197*eV 12.5541*mm + 5.67015*eV 11.4277*mm + 5.75833*eV 10.4166*mm + 5.8465*eV 9.50928*mm + 5.93468*eV 8.69176*mm + 6.02286*eV 7.95608*mm + 6.11103*eV 7.29168*mm + 6.19921*eV 6.69064*mm + "/> + <matrix name="RAYLEIGH__Aerogel_DRICH" coldim="2" values=" + 1.87855*eV 309.218*mm + 1.96673*eV 257.383*mm + 2.0549*eV 215.968*mm + 2.14308*eV 182.559*mm + 2.23126*eV 155.367*mm + 2.31943*eV 133.053*mm + 2.40761*eV 114.606*mm + 2.49579*eV 99.2482*mm + 2.58396*eV 86.3795*mm + 2.67214*eV 75.5291*mm + 2.76032*eV 66.3313*mm + 2.84849*eV 58.4918*mm + 2.93667*eV 51.777*mm + 3.02485*eV 45.998*mm + 3.11302*eV 41.0045*mm + 3.2012*eV 36.6696*mm + 3.28938*eV 32.8931*mm + 3.37755*eV 29.5904*mm + 3.46573*eV 26.6917*mm + 3.55391*eV 24.1402*mm + 3.64208*eV 21.8856*mm + 3.73026*eV 19.8884*mm + 3.81844*eV 18.1144*mm + 3.90661*eV 16.533*mm + 3.99479*eV 15.1206*mm + 4.08297*eV 13.856*mm + 4.17114*eV 12.7208*mm + 4.25932*eV 11.7005*mm + 4.3475*eV 10.7791*mm + 4.43567*eV 9.94752*mm + 4.52385*eV 9.1938*mm + 4.61203*eV 8.51136*mm + 4.7002*eV 7.88964*mm + 4.78838*eV 7.32468*mm + 4.87656*eV 6.80988*mm + 4.96473*eV 6.33864*mm + 5.05291*eV 5.907*mm + 5.14109*eV 5.51232*mm + 5.22927*eV 5.14932*mm + 5.31744*eV 4.81668*mm + 5.40562*eV 4.51044*mm + 5.4938*eV 4.22796*mm + 5.58197*eV 3.9666*mm + 5.67015*eV 3.72504*mm + 5.75833*eV 3.50196*mm + 5.8465*eV 3.29604*mm + 5.93468*eV 3.10464*mm + 6.02286*eV 2.92644*mm + 6.11103*eV 2.76144*mm + 6.19921*eV 2.607*mm + "/> + <!-- dRICh acrylic --> + <matrix name="RINDEX__Acrylic_DRICH" coldim="2" values=" + 4.13281*eV 1.5017 + 4.22099*eV 1.5017 + 4.30916*eV 1.5017 + 4.39734*eV 1.5017 + 4.48552*eV 1.5017 + 4.57369*eV 1.5017 + 4.66187*eV 1.5017 + 4.75005*eV 1.5017 + 4.83822*eV 1.5017 + 4.9264*eV 1.5017 + 5.01458*eV 1.5017 + 5.10275*eV 1.5017 + 5.19093*eV 1.5017 + 5.27911*eV 1.5017 + 5.36728*eV 1.5017 + 5.45546*eV 1.5017 + 5.54364*eV 1.5017 + 5.63181*eV 1.5017 + 5.71999*eV 1.5017 + 5.80817*eV 1.5017 + 5.89634*eV 1.5017 + 5.98452*eV 1.5017 + 6.0727*eV 1.5017 + 6.16087*eV 1.5017 + 6.24905*eV 1.5017 + 6.33723*eV 1.5017 + 6.4254*eV 1.5017 + 6.51358*eV 1.5017 + 6.60176*eV 1.5017 + 6.68993*eV 1.5017 + 6.77811*eV 1.5017 + 6.86629*eV 1.5017 + 6.95446*eV 1.5017 + 7.04264*eV 1.5017 + 7.13082*eV 1.5017 + 7.21899*eV 1.5017 + 7.30717*eV 1.5017 + 7.39535*eV 1.5017 + 7.48353*eV 1.5017 + 7.5717*eV 1.5017 + 7.65988*eV 1.5017 + 7.74806*eV 1.5017 + 7.83623*eV 1.5017 + 7.92441*eV 1.5017 + 8.01259*eV 1.5017 + 8.10076*eV 1.5017 + 8.18894*eV 1.5017 + 8.27712*eV 1.5017 + 8.36529*eV 1.5017 + 8.45347*eV 1.5017 + "/> + <matrix name="ABSLENGTH__Acrylic_DRICH" coldim="2" values=" + 4.13281*eV 82.0704*mm + 4.22099*eV 36.9138*mm + 4.30916*eV 13.3325*mm + 4.39734*eV 5.03627*mm + 4.48552*eV 2.3393*mm + 4.57369*eV 1.36177*mm + 4.66187*eV 0.933192*mm + 4.75005*eV 0.708268*mm + 4.83822*eV 0.573082*mm + 4.9264*eV 0.483641*mm + 5.01458*eV 0.420282*mm + 5.10275*eV 0.373102*mm + 5.19093*eV 0.33662*mm + 5.27911*eV 0.307572*mm + 5.36728*eV 0.283902*mm + 5.45546*eV 0.264235*mm + 5.54364*eV 0.247641*mm + 5.63181*eV 0.233453*mm + 5.71999*eV 0.221177*mm + 5.80817*eV 0.210456*mm + 5.89634*eV 0.201012*mm + 5.98452*eV 0.192627*mm + 6.0727*eV 0.185134*mm + 6.16087*eV 0.178399*mm + 6.24905*eV 0.172309*mm + 6.33723*eV 0.166779*mm + 6.4254*eV 0.166779*mm + 6.51358*eV 0.166779*mm + 6.60176*eV 0.166779*mm + 6.68993*eV 0.166779*mm + 6.77811*eV 0.166779*mm + 6.86629*eV 0.166779*mm + 6.95446*eV 0.166779*mm + 7.04264*eV 0.166779*mm + 7.13082*eV 0.166779*mm + 7.21899*eV 0.166779*mm + 7.30717*eV 0.166779*mm + 7.39535*eV 0.166779*mm + 7.48353*eV 0.166779*mm + 7.5717*eV 0.166779*mm + 7.65988*eV 0.166779*mm + 7.74806*eV 0.166779*mm + 7.83623*eV 0.166779*mm + 7.92441*eV 0.166779*mm + 8.01259*eV 0.166779*mm + 8.10076*eV 0.166779*mm + 8.18894*eV 0.166779*mm + 8.27712*eV 0.166779*mm + 8.36529*eV 0.166779*mm + 8.45347*eV 0.166779*mm + "/> + <!-- END dRICh optical properties --> </properties> <materials> <material name="AirOptical"> @@ -86,6 +378,32 @@ <composite n="8" ref="H"/> <property name="RINDEX" ref="RINDEX__Acrylic"/> </material> + <!-- BEGIN dRICh material definitions --> + <material name="C2F6_DRICH"> + <D type="density" value="0.005734" unit="g/cm3"/> + <composite n="2" ref="C"/> + <composite n="6" ref="F"/> + <property name="RINDEX" ref="RINDEX__C2F6_DRICH"/> + <property name="ABSLENGTH" ref="ABSLENGTH__C2F6_DRICH"/> + </material> + <material name="Aerogel_DRICH"> + <D type="density" value="0.1" unit="g/cm3"/> + <comment> n_air = [dens(Si02)-dens(aerogel)] / [dens(Si02)-dens(Air) ] </comment> + <fraction n=" (2.32-0.1) / (2.32-0.0012)" ref="Air"/> + <fraction n="1 - (2.32-0.1) / (2.32-0.0012)" ref="SiliconDioxide"/> + <property name="RINDEX" ref="RINDEX__Aerogel_DRICH"/> + <property name="ABSLENGTH" ref="ABSLENGTH__Aerogel_DRICH"/> + <property name="RAYLEIGH" ref="RAYLEIGH__Aerogel_DRICH"/> + </material> + <material name="Acrylic_DRICH"> + <D type="density" value="1.19" unit="g/cm3"/> + <comment> TO BE IMPROVED </comment> + <fraction n="0.99" ref="Plexiglass"/> + <fraction n="0.01" ref="PolyvinylAcetate"/> + <property name="RINDEX" ref="RINDEX__Acrylic_DRICH"/> + <property name="ABSLENGTH" ref="ABSLENGTH__Acrylic_DRICH"/> + </material> + <!-- END dRICh material definitions --> </materials> <surfaces> <opticalsurface finish="polished" model="glisur" name="MirrorOpticalSurface" type="dielectric_metal" value="0"> @@ -131,5 +449,70 @@ --> </opticalsurface> + <!-- BEGIN dRICh surface definitions --> + <opticalsurface name="MirrorSurface_DRICH" model="unified" finish="polishedfrontpainted" type="dielectric_dielectric"> + <property name="REFLECTIVITY" coldim="2" values=" + 2.04358*eV 0.867812 + 2.0664*eV 0.865156 + 2.09046*eV 0.863906 + 2.14023*eV 0.86375 + 2.16601*eV 0.864062 + 2.20587*eV 0.864531 + 2.23327*eV 0.864375 + 2.26137*eV 0.865625 + 2.31972*eV 0.865313 + 2.35005*eV 0.865 + 2.38116*eV 0.864844 + 2.41313*eV 0.863828 + 2.44598*eV 0.863516 + 2.47968*eV 0.863125 + 2.53081*eV 0.862187 + 2.58354*eV 0.861719 + 2.6194*eV 0.861328 + 2.69589*eV 0.861016 + 2.73515*eV 0.861094 + 2.79685*eV 0.861602 + 2.86139*eV 0.862305 + 2.95271*eV 0.86375 + 3.04884*eV 0.865586 + 3.12665*eV 0.867383 + 3.2393*eV 0.870059 + 3.39218*eV 0.874199 + 3.52508*eV 0.878105 + 3.66893*eV 0.88252 + 3.82396*eV 0.887617 + 3.99949*eV 0.893721 + 4.13281*eV 0.898184 + 4.27679*eV 0.902744 + 4.48244*eV 0.907837 + 4.65057*eV 0.9102 + 4.89476*eV 0.909316 + 5.02774*eV 0.906174 + 5.16816*eV 0.900422 + 5.31437*eV 0.891521 + 5.63821*eV 0.859954 + 5.90401*eV 0.820831 + 6.19921*eV 0.762502 + "/> + </opticalsurface> + <opticalsurface name="SensorSurface_DRICH" model="glisur" finish="polished" type="dielectric_metal"> + <property name="EFFICIENCY" coldim="2" values=" + 1*eV 1 + 4*eV 1 + 7*eV 1 + "/> + <property name="IMAGINARYRINDEX" coldim="2" values=" + 1*eV 1.69 + 4*eV 1.69 + 7*eV 1.69 + "/> + <property name="REALRINDEX" coldim="2" values=" + 1*eV 1.92 + 4*eV 1.92 + 7*eV 1.92 + "/> + </opticalsurface> + <!-- END dRICh surface definitions --> + </surfaces> </lccdd> diff --git a/src/DRich.cpp b/src/DRich.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d9ebd83f148264430a0a4cbdb80d4c429a6804e --- /dev/null +++ b/src/DRich.cpp @@ -0,0 +1,395 @@ +//========================================================================== +// dRICh: Dual Ring Imaging Cherenkov Detector +//-------------------------------------------------------------------------- +// +// Author: Christopher Dilks (Duke University) +// +// - Design Adapted from Standalone Fun4all and GEMC implementations +// [ Evaristo Cisbani, Cristiano Fanelli, Alessio Del Dotto, et al. ] +// +//========================================================================== + +#include <XML/Helper.h> +#include "TMath.h" +#include "TString.h" +#include "GeometryHelpers.h" +#include "Math/Point2D.h" +#include "DDRec/Surface.h" +#include "DDRec/DetectorData.h" +#include "DD4hep/OpticalSurfaces.h" +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::rec; + +// create the detector +static Ref_t createDetector(Detector& desc, xml::Handle_t handle, SensitiveDetector sens) { + xml::DetElement detElem = handle; + std::string detName = detElem.nameStr(); + int detID = detElem.id(); + + DetElement det(detName, detID); + xml::Component dims = detElem.dimensions(); + OpticalSurfaceManager surfMgr = desc.surfaceManager(); + + // attributes ----------------------------------------------------------- + // TODO [low priority]: some attributes have default values, some do not; + // make this more consistent + // - vessel + double vesselZ0 = dims.attr<double>(_Unicode(z0)); + double vesselLength = dims.attr<double>(_Unicode(length)); + double vesselRmin0 = dims.attr<double>(_Unicode(rmin0)); + double vesselRmin1 = dims.attr<double>(_Unicode(rmin1)); + double vesselRmax0 = dims.attr<double>(_Unicode(rmax0)); + double vesselRmax1 = dims.attr<double>(_Unicode(rmax1)); + double vesselRmax2 = dims.attr<double>(_Unicode(rmax2)); + double snoutLength = dims.attr<double>(_Unicode(snout_length)); + int nSectors = getAttrOrDefault<int>(dims, _Unicode(nsectors), 6); + double wallThickness = getAttrOrDefault<double>(dims, _Unicode(wall_thickness), 0.5*cm); + double windowThickness = getAttrOrDefault<double>(dims, _Unicode(window_thickness), 0.1*cm); + auto vesselMat = desc.material(getAttrOrDefault(detElem, _Unicode(material), "Aluminum")); + auto gasvolMat = desc.material(getAttrOrDefault(detElem, _Unicode(gas), "AirOptical")); + auto vesselVis = desc.visAttributes(detElem.attr<std::string>(_Unicode(vis_vessel))); + auto gasvolVis = desc.visAttributes(detElem.attr<std::string>(_Unicode(vis_gas))); + // - radiator (applies to aerogel and filter) + auto radiatorElem = detElem.child(_Unicode(radiator)); + double radiatorRmin = getAttrOrDefault<double>(radiatorElem, _Unicode(rmin), 10.*cm); + double radiatorRmax = getAttrOrDefault<double>(radiatorElem, _Unicode(rmax), 80.*cm); + double radiatorPhiw = getAttrOrDefault<double>(radiatorElem, _Unicode(phiw), 2*M_PI/nSectors); + double radiatorPitch = getAttrOrDefault<double>(radiatorElem, _Unicode(pitch), 0.*degree); + double radiatorFrontplane = getAttrOrDefault<double>(radiatorElem, _Unicode(frontplane), 2.5*cm); + // - aerogel + auto aerogelElem = radiatorElem.child(_Unicode(aerogel)); + auto aerogelMat = desc.material(aerogelElem.attr<std::string>(_Unicode(material))); + auto aerogelVis = desc.visAttributes(aerogelElem.attr<std::string>(_Unicode(vis))); + double aerogelThickness = getAttrOrDefault<double>(aerogelElem, _Unicode(thickness), 2.5*cm); + // - filter + auto filterElem = radiatorElem.child(_Unicode(filter)); + auto filterMat = desc.material(filterElem.attr<std::string>(_Unicode(material))); + auto filterVis = desc.visAttributes(filterElem.attr<std::string>(_Unicode(vis))); + double filterThickness = getAttrOrDefault<double>(filterElem, _Unicode(thickness), 2.5*cm); + // - mirror + auto mirrorElem = detElem.child(_Unicode(mirror)); + auto mirrorMat = desc.material(mirrorElem.attr<std::string>(_Unicode(material))); + auto mirrorVis = desc.visAttributes(mirrorElem.attr<std::string>(_Unicode(vis))); + auto mirrorSurf = surfMgr.opticalSurface(getAttrOrDefault(mirrorElem, _Unicode(surface), "MirrorOpticalSurface")); + double mirrorBackplane = getAttrOrDefault<double>(mirrorElem, _Unicode(backplane), 240.*cm); + double mirrorThickness = getAttrOrDefault<double>(mirrorElem, _Unicode(thickness), 2.*mm); + double mirrorRadius = getAttrOrDefault<double>(mirrorElem, _Unicode(radius), 190*cm); + double mirrorCenterX = getAttrOrDefault<double>(mirrorElem, _Unicode(centerx), 95*cm); + double mirrorRmin = getAttrOrDefault<double>(mirrorElem, _Unicode(rmin), 10.*cm); + double mirrorRmax = getAttrOrDefault<double>(mirrorElem, _Unicode(rmax), 150.*cm); + double mirrorPhiw = getAttrOrDefault<double>(mirrorElem, _Unicode(phiw), 2*M_PI/nSectors); + int mirrorDebug = getAttrOrDefault<int>(mirrorElem, _Unicode(debug), 0); + // - sensor module + auto sensorElem = detElem.child(_Unicode(sensors)).child(_Unicode(module)); + auto sensorMat = desc.material(sensorElem.attr<std::string>(_Unicode(material))); + auto sensorVis = desc.visAttributes(sensorElem.attr<std::string>(_Unicode(vis))); + auto sensorSurf = surfMgr.opticalSurface(getAttrOrDefault(sensorElem, _Unicode(surface), "MirrorOpticalSurface")); + double sensorSide = sensorElem.attr<double>(_Unicode(side)); + double sensorGap = sensorElem.attr<double>(_Unicode(gap)); + double sensorThickness = sensorElem.attr<double>(_Unicode(thickness)); + // - sensor sphere + auto sensorSphElem = detElem.child(_Unicode(sensors)).child(_Unicode(sphere)); + double sensorSphRadius = sensorSphElem.attr<double>(_Unicode(radius)); + double sensorSphCenterX = sensorSphElem.attr<double>(_Unicode(centerx)); + double sensorSphCenterY = sensorSphElem.attr<double>(_Unicode(centery)); + double sensorSphCenterZ = sensorSphElem.attr<double>(_Unicode(centerz)); + int sensorSphDebug = getAttrOrDefault<int>(sensorSphElem, _Unicode(debug), 0); + // - sensor sphere patch cuts + auto sensorSphPatchElem = detElem.child(_Unicode(sensors)).child(_Unicode(sphericalpatch)); + double sensorSphPatchThetaMin = sensorSphPatchElem.attr<double>(_Unicode(thetamin)); + double sensorSphPatchThetaMax = sensorSphPatchElem.attr<double>(_Unicode(thetamax)); + double sensorSphPatchWidthFactor = sensorSphPatchElem.attr<double>(_Unicode(widthfactor)); + double sensorSphPatchTaper = sensorSphPatchElem.attr<double>(_Unicode(taper)); + + + // BUILD VESSEL ==================================================================== + /* - `vessel`: aluminum enclosure, the mother volume of the dRICh + * - `gasvol`: gas volume, which fills `vessel`; all other volumes defined below + * are children of `gasvol` + * - the dRICh vessel geometry has two regions: the snout refers to the conic region + * in the front, housing the aerogel, while the tank refers to the cylindrical + * region, housing the rest of the detector components + */ + + // snout solids + double boreDelta = vesselRmin1 - vesselRmin0; + Cone vesselSnout( + snoutLength/2.0, + vesselRmin0, + vesselRmax0, + vesselRmin0 + boreDelta * snoutLength / vesselLength, + vesselRmax1 + ); + Cone gasvolSnout( + /* note: `gasvolSnout` extends a bit into the tank, so it touches `gasvolTank` + * - the extension distance is equal to the tank `windowThickness`, so the + * length of `gasvolSnout` == length of `vesselSnout` + * - the extension backplane radius is calculated using similar triangles + */ + snoutLength/2.0, + vesselRmin0 + wallThickness, + vesselRmax0 - wallThickness, + vesselRmin0 + boreDelta * (snoutLength-windowThickness) / vesselLength + wallThickness, + vesselRmax1 - wallThickness + windowThickness * (vesselRmax1 - vesselRmax0) / snoutLength + ); + + // tank solids + Cone vesselTank( + (vesselLength - snoutLength)/2.0, + vesselSnout.rMin2(), + vesselRmax2, + vesselRmin1, + vesselRmax2 + ); + Cone gasvolTank( + (vesselLength - snoutLength)/2.0 - windowThickness, + gasvolSnout.rMin2(), + vesselRmax2 - wallThickness, + vesselRmin1 + wallThickness, + vesselRmax2 - wallThickness + ); + + // snout + tank solids + UnionSolid vesselSolid( + vesselTank, + vesselSnout, + Position(0., 0., -vesselLength/2.) + ); + UnionSolid gasvolSolid( + gasvolTank, + gasvolSnout, + Position(0., 0., -vesselLength/2. + windowThickness) + ); + + + // volumes + Volume vesselVol(detName, vesselSolid, vesselMat); + Volume gasvolVol(detName + "_gas", gasvolSolid, gasvolMat); + vesselVol.setVisAttributes(vesselVis); + gasvolVol.setVisAttributes(gasvolVis); + + // reference position + auto snoutFront = Position(0., 0., -(vesselLength + snoutLength)/2.); + + + // sensitive detector type + sens.setType("photoncounter"); + + + // SECTOR LOOP ////////////////////////////////// + for(int isec=0; isec<nSectors; isec++) { + + if(mirrorDebug*isec>0 || sensorSphDebug*isec>0) continue; // if debugging, draw only 1 sector + double sectorRotation = isec * 360/nSectors * degree; // sector rotation about z axis + + // BUILD RADIATOR ==================================================================== + + // derived attributes + auto radiatorPos = Position(0., 0., radiatorFrontplane) + snoutFront; + + // solid and volume: create aerogel and filter sectors + Tube aerogelSolid(radiatorRmin, radiatorRmax, aerogelThickness/2, -radiatorPhiw/2.0, radiatorPhiw/2.0); + Tube filterSolid( radiatorRmin, radiatorRmax, filterThickness/2, -radiatorPhiw/2.0, radiatorPhiw/2.0); + Volume aerogelVol("aerogel_v", aerogelSolid, aerogelMat); + Volume filterVol( "filter_v", filterSolid, filterMat); + aerogelVol.setVisAttributes(aerogelVis); + filterVol.setVisAttributes(filterVis); + + // placement + auto aerogelPV = gasvolVol.placeVolume(aerogelVol, + RotationZ(sectorRotation) // rotate about beam axis to sector + * Translation3D(radiatorPos.x(), radiatorPos.y(), radiatorPos.z()) // re-center to snoutFront + * RotationY(radiatorPitch) // change polar angle to specified pitch + ); + auto filterPV = gasvolVol.placeVolume(filterVol, + RotationZ(sectorRotation) // rotate about beam axis to sector + * Translation3D(radiatorPos.x(), radiatorPos.y(), radiatorPos.z()) // re-center to snoutFront + * RotationY(radiatorPitch) // change polar angle + * Translation3D(0., 0., (aerogelThickness+filterThickness)/2.) // move to aerogel backplane + ); + + // properties + // TODO [critical]: define skin properties for aerogel and filter + DetElement aerogelDE(det, Form("aerogel_de%d", isec), isec); + aerogelDE.setPlacement(aerogelPV); + //SkinSurface aerogelSkin(desc, aerogelDE, Form("mirror_optical_surface%d", isec), aerogelSurf, aerogelVol); + //aerogelSkin.isValid(); + DetElement filterDE(det, Form("filter_de%d", isec), isec); + filterDE.setPlacement(filterPV); + //SkinSurface filterSkin(desc, filterDE, Form("mirror_optical_surface%d", isec), filterSurf, filterVol); + //filterSkin.isValid(); + + + // BUILD MIRROR ==================================================================== + + // derived attributes + auto mirrorPos = Position(mirrorCenterX, 0., mirrorBackplane) + snoutFront; + double mirrorThetaRot = std::asin(mirrorCenterX/mirrorRadius); + double mirrorTheta1 = mirrorThetaRot - std::asin((mirrorCenterX-mirrorRmin)/mirrorRadius); + double mirrorTheta2 = mirrorThetaRot + std::asin((mirrorRmax-mirrorCenterX)/mirrorRadius); + + // if debugging, draw full sphere + if(mirrorDebug>0) { mirrorTheta1=0; mirrorTheta2=M_PI; mirrorPhiw=2*M_PI; }; + + // solid and volume: create sphere at origin, with specified angular limits + Sphere mirrorSolid( + mirrorRadius-mirrorThickness, + mirrorRadius, + mirrorTheta1, + mirrorTheta2, + -mirrorPhiw/2.0, + mirrorPhiw/2.0 + ); + Volume mirrorVol("mirror_v", mirrorSolid, mirrorMat); + mirrorVol.setVisAttributes(mirrorVis); + + // placement (note: transformations are in reverse order) + auto mirrorPV = gasvolVol.placeVolume(mirrorVol, + RotationZ(sectorRotation) // rotate about beam axis to sector + * Translation3D(0,0,-mirrorRadius) // move longitudinally so it intersects snoutFront + * Translation3D(mirrorPos.x(), mirrorPos.y(), mirrorPos.z()) // re-center to snoutFront + * RotationY(-mirrorThetaRot) // rotate about origin + ); + + // properties + DetElement mirrorDE(det, Form("mirror_de%d", isec), isec); + mirrorDE.setPlacement(mirrorPV); + SkinSurface mirrorSkin(desc, mirrorDE, Form("mirror_optical_surface%d", isec), mirrorSurf, mirrorVol); + mirrorSkin.isValid(); + + + // BUILD SENSORS ==================================================================== + + // if debugging sphere properties, restrict number of sensors drawn + if(sensorSphDebug>0) { sensorSide = 2*M_PI*sensorSphRadius / 64; }; + + // solid and volume: single sensor module + Box sensorSolid(sensorSide/2., sensorSide/2., sensorThickness/2.); + Volume sensorVol("sensor_v", sensorSolid, sensorMat); + sensorVol.setVisAttributes(sensorVis); + + // sensitivity + sensorVol.setSensitiveDetector(sens); + + // SENSOR MODULE LOOP ------------------------ + /* ALGORITHM: generate sphere of positions + * - NOTE: there are two coordinate systems here: + * - "global" the main ATHENA coordinate system + * - "generator" (vars end in `Gen`) is a local coordinate system for + * generating points on a sphere; it is related to the global system by + * a rotation; we do this so the "patch" (subset of generated + * positions) of sensors we choose to build is near the equator, where + * point distribution is more uniform + * - PROCEDURE: loop over `thetaGen`, with subloop over `phiGen`, each divided evenly + * - the number of points to generate depends how many sensors (+`sensorGap`) + * can fit within each ring of constant `thetaGen` or `phiGen` + * - we divide the relevant circumference by the sensor + * size(+`sensorGap`), and this number is allowed to be a fraction, + * because likely we don't care about generating a full sphere and + * don't mind a "seam" at the overlap point + * - if we pick a patch of the sphere near the equator, and not near + * the poles or seam, the sensor distribution will appear uniform + */ + + // initialize module number for this sector + int imod=1; + + // thetaGen loop: iterate less than "0.5 circumference / sensor size" times + double nTheta = M_PI*sensorSphRadius / (sensorSide+sensorGap); + for(int t=0; t<(int)(nTheta+0.5); t++) { + double thetaGen = t/((double)nTheta) * M_PI; + + // phiGen loop: iterate less than "circumference at this latitude / sensor size" times + double nPhi = 2*M_PI * sensorSphRadius * std::sin(thetaGen) / (sensorSide+sensorGap); + for(int p=0; p<(int)(nPhi+0.5); p++) { + double phiGen = p/((double)nPhi) * 2*M_PI - M_PI; // shift to [-pi,pi] + + // determine global phi and theta + // - convert {radius,thetaGen,phiGen} -> {xGen,yGen,zGen} + double xGen = sensorSphRadius * std::sin(thetaGen) * std::cos(phiGen); + double yGen = sensorSphRadius * std::sin(thetaGen) * std::sin(phiGen); + double zGen = sensorSphRadius * std::cos(thetaGen); + // - convert {xGen,yGen,zGen} -> global {x,y,z} via rotation + double x = zGen; + double y = xGen; + double z = yGen; + // - convert global {x,y,z} -> global {phi,theta} + double phi = std::atan2(y,x); + double theta = std::acos(z/sensorSphRadius); + + // cut spherical patch + // TODO [low priority]: instead of cutting a patch with complicated parameters, + // can we use something simpler such as Union or + // Intersection of solids? + // - applied on global coordinates + // - theta cuts are signed, since we will offset the patch along +x; + // from the offset position, toward barrel is positive, toward beam is negative + double thetaSigned = (x<0?-1:1) * theta; + // - position of yz planes, associated to theta cuts + double xmin = sensorSphRadius * std::sin(sensorSphPatchThetaMin/2); + double xmax = sensorSphRadius * std::sin(sensorSphPatchThetaMax/2); + // - we want a phi wedge, but offset from the origin to allow more width, so + // define phiCheck to account for the offset; the amount of the offset, + // and hence the width, is controlled by `sensorSphPatchWidthFactor` + double phiCheck = std::atan2(y,(x+sensorSphCenterX)/sensorSphPatchWidthFactor); + // - apply cuts (only if not debugging) + // - NOTE: use `x<xmax` for straight cuts, or `theta<sensorSphPatchThetaMax` for + // rounded cuts (which allows for more sensors) + if( ( std::fabs(phiCheck)<sensorSphPatchTaper && x>xmin && theta<sensorSphPatchThetaMax && z>0 ) + || sensorSphDebug>0 + ) { + + // placement (note: transformations are in reverse order) + // - transformations operate on global coordinates; the corresponding + // generator coordinates are provided in the comments + auto sensorPV = gasvolVol.placeVolume(sensorVol, + RotationZ(sectorRotation) // rotate about beam axis to sector + * Translation3D(sensorSphCenterX, sensorSphCenterY, sensorSphCenterZ) // move sphere to specified center + * Translation3D(snoutFront.x(), snoutFront.y(), snoutFront.z()) // move sphere to reference position + * RotationX(phiGen) // rotate about `zGen` + * RotationZ(thetaGen) // rotate about `yGen` + * Translation3D(sensorSphRadius, 0., 0.) // push radially to spherical surface + * RotationY(M_PI/2) // rotate sensor to be compatible with generator coords + ); + + // properties + sensorPV.addPhysVolID("sector", isec).addPhysVolID("module", imod); + DetElement sensorDE(det, Form("sensor_de%d_%d", isec, imod), 10000*isec+imod); + sensorDE.setPlacement(sensorPV); + SkinSurface sensorSkin(desc, sensorDE, Form("sensor_optical_surface%d", isec), sensorSurf, sensorVol); + sensorSkin.isValid(); + + // increment sensor module number + imod++; + + }; // end patch cuts + }; // end phiGen loop + }; // end thetaGen loop + // END SENSOR MODULE LOOP ------------------------ + + + }; // END SECTOR LOOP ////////////////////////// + + + // place gas volume + PlacedVolume gasvolPV = vesselVol.placeVolume(gasvolVol,Position(0, 0, 0)); + DetElement gasvolDE(det, "gasvol_de", 0); + gasvolDE.setPlacement(gasvolPV); + + // place mother volume (vessel) + Volume motherVol = desc.pickMotherVolume(det); + PlacedVolume vesselPV = motherVol.placeVolume(vesselVol, + Position(0, 0, vesselZ0) - snoutFront + ); + vesselPV.addPhysVolID("system", detID); + det.setPlacement(vesselPV); + + return det; +}; + +// clang-format off +DECLARE_DETELEMENT(athena_DRICH, createDetector)