4 # GDML fragment generator for DUNE dual-phase 10kt detector geometry
5 # adapted from single phase cryostat geometry script from Tyler Dalion
6 # by Vyacheslav Galymov < vgalymov@ipnl.in2p3.fr >
9 #################################################################################
11 # contact tylerdalion@gmail.com for any GDML/generate questions
12 # I would love to help!
14 # Each subroutine generates a fragment GDML file, and the last subroutine
15 # creates an XML file that make_gdml.pl will use to appropriately arrange
16 # the fragment GDML files to create the final desired DUNE GDML file,
17 # to be named by make_gdml output command
19 # If you are playing with different geometries, you can use the
20 # suffix command to help organize your work.
22 ##################################################################################
30 Math::BigFloat->precision(-16);
32 GetOptions( "help|h" => \$help,
33 "suffix|s:s" => \$suffix,
34 "output|o:s" => \$output,
35 "wires|w:s" => \$wires,
36 "workspace|k:s" => \$workspace);
40 # If the user requested help, print the usage notes and exit.
45 if ( ! defined $suffix )
47 # The user didn't supply a suffix, so append nothing to the file
53 # Otherwise, stick a "-" before the suffix, so that a suffix of
54 # "test" applied to filename.gdml becomes "filename-test.gdml".
55 $suffix = "-" . $suffix;
58 if ( ! defined $workspace ) # not done
62 elsif ( $workspace == 1)
64 print "\t\tCreating smaller workspace geometry.\n";
67 # set wires on to be the default, unless given an input by the user
68 $wires_on = 1; # 1=on, 0=off
76 $basename = "dune10ktdphase_v1";
79 $basename = $basename."_nowires";
82 if ( $workspace == 1 )
84 $basename = $basename."_workspace";
87 ##################################################################
88 ############## Parameters for Charge Readout Plane ###############
91 $wirePitch = 0.3125; # channel pitch
92 $nChannelsViewPerCRM = 960; # channels per collection view
93 $borderCRM = 0.5; # dead space at the border of each CRM
95 # dimensions of a single Charge Readout Module (CRM)
96 $widthCRM_active = $wirePitch * $nChannelsViewPerCRM;
97 $lengthCRM_active = $wirePitch * $nChannelsViewPerCRM;
99 $widthCRM = $widthCRM_active + 2 * $borderCRM;
100 $lengthCRM = $lengthCRM_active + 2 * $borderCRM;
102 # number of CRMs in x and z
106 # create a smaller geometry
107 if( $workspace == 1 )
113 # calculate tpc area based on number of CRMs and their dimensions
114 $widthTPCActive = $nCRM_x * $widthCRM; # around 1200
115 $lengthTPCActive = $nCRM_z * $lengthCRM; # around 6000
117 # active volume dimensions
118 $driftTPCActive = 1200.0;
120 # model anode strips as wires
122 $ReadoutPlane = 2 * $padWidth;
124 #$padHeight = 0.0035;
126 ##################################################################
127 ############## Parameters for TPC and inner volume ###############
129 # inner volume dimensions of the cryostat
134 # width of gas argon layer on top
135 $HeightGaseousAr = 100;
137 # size of liquid argon buffer
138 $xLArBuffer = 0.5 * ($Argon_x - $widthTPCActive);
139 $yLArBuffer = $Argon_y - $driftTPCActive - $HeightGaseousAr - $ReadoutPlane;
140 $zLArBuffer = 0.5 * ($Argon_z - $lengthTPCActive);
143 $SteelThickness = 0.12; # membrane
145 $Cryostat_x = $Argon_x + 2*$SteelThickness;
146 $Cryostat_y = $Argon_y + 2*$SteelThickness;
147 $Cryostat_z = $Argon_z + 2*$SteelThickness;
149 ##################################################################
150 ############## DetEnc and World relevant parameters #############
152 $SteelSupport_x = 100;
153 $SteelSupport_y = 50;
154 $SteelSupport_z = 100;
155 $FoamPadding = 80; # only 2 layers ???
156 $FracMassOfSteel = 0.5; #The steel support is not a solid block, but a mixture of air and steel
157 $FracMassOfAir = 1 - $FracMassOfSteel;
160 $SpaceSteelSupportToWall = 100;
161 $SpaceSteelSupportToCeiling = 100;
163 $DetEncWidth = $Cryostat_x
164 + 2*($SteelSupport_x + $FoamPadding) + 2*$SpaceSteelSupportToWall;
165 $DetEncHeight = $Cryostat_y
166 + 2*($SteelSupport_y + $FoamPadding) + $SpaceSteelSupportToCeiling;
167 $DetEncLength = $Cryostat_z
168 + 2*($SteelSupport_z + $FoamPadding) + 2*$SpaceSteelSupportToWall;
170 $posCryoInDetEnc_y = - $DetEncHeight/2 + $SteelSupport_y + $FoamPadding + $Cryostat_y/2;
172 $RockThickness = 3000;
174 # We want the world origin to be at the very front of the fiducial volume.
175 # move it to the front of the enclosure, then back it up through the concrete/foam,
176 # then through the Cryostat shell, then through the upstream dead LAr (including the
177 # dead LAr on the edge of the TPC)
178 # This is to be added to the z position of every volume in volWorld
180 $OriginZSet = $DetEncLength/2.0
181 - $SpaceSteelSupportToWall
187 # We want the world origin to be vertically centered on active TPC
188 # This is to be added to the y position of every volume in volWorld
190 $OriginYSet = $DetEncHeight/2.0
195 - $driftTPCActive/2.0;
197 $OriginXSet = 0; # centered for now
200 ##################################################################
201 ############### Parameters for det elements ######################
204 $Cathode_x = $widthTPCActive;
206 $Cathode_z = $lengthTPCActive;
210 #+++++++++++++++++++++++++ End defining variables ++++++++++++++++++++++++++
213 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
214 #+++++++++++++++++++++++++++++++++++++++++ usage +++++++++++++++++++++++++++++++++++++++++
215 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
219 print "Usage: $0 [-h|--help] [-o|--output <fragments-file>] [-s|--suffix <string>]\n";
220 print " if -o is omitted, output goes to STDOUT; <fragments-file> is input to make_gdml.pl\n";
221 print " -s <string> appends the string to the file names; useful for multiple detector versions\n";
222 print " -h prints this message, then quits\n";
227 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
228 #++++++++++++++++++++++++++++++++++++++ gen_Define +++++++++++++++++++++++++++++++++++++++
229 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
234 # Create the <define> fragment file name,
235 # add file to list of fragments,
237 $DEF = $basename."_Def" . $suffix . ".gdml";
238 push (@gdmlFiles, $DEF);
240 open(DEF) or die("Could not open file $DEF for writing");
244 <?xml version='1.0'?>
254 <position name="posCryoInDetEnc" unit="cm" x="0" y="$posCryoInDetEnc_y" z="0"/>
255 <position name="posCenter" unit="cm" x="0" y="0" z="0"/>
256 <rotation name="rPlus90AboutX" unit="deg" x="90" y="0" z="0"/>
257 <rotation name="rMinus90AboutY" unit="deg" x="0" y="270" z="0"/>
258 <rotation name="rMinus90AboutYMinus90AboutX" unit="deg" x="270" y="270" z="0"/>
259 <rotation name="rPlus180AboutX" unit="deg" x="180" y="0" z="0"/>
260 <rotation name="rPlus180AboutY" unit="deg" x="0" y="180" z="0"/>
261 <rotation name="rPlus180AboutXPlus180AboutY" unit="deg" x="180" y="180" z="0"/>
262 <rotation name="rIdentity" unit="deg" x="0" y="0" z="0"/>
269 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
270 #+++++++++++++++++++++++++++++++++++++ gen_Materials +++++++++++++++++++++++++++++++++++++
271 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
276 # Create the <materials> fragment file name,
277 # add file to list of output GDML fragments,
279 $MAT = $basename."_Materials" . $suffix . ".gdml";
280 push (@gdmlFiles, $MAT);
283 open(MAT) or die("Could not open file $MAT for writing");
285 # Add any materials special to this geometry by defining a mulitline string
286 # and passing it to the gdmlMaterials::gen_Materials() function.
288 <!-- preliminary values -->
289 <material name="AirSteelMixture" formula="AirSteelMixture">
290 <D value=" 0.001205*(1-$FracMassOfSteel) + 7.9300*$FracMassOfSteel " unit="g/cm3"/>
291 <fraction n="$FracMassOfSteel" ref="STEEL_STAINLESS_Fe7Cr2Ni"/>
292 <fraction n="$FracMassOfAir" ref="Air"/>
296 # add the general materials used anywere
297 print MAT gdmlMaterials::gen_Materials( $asmix );
302 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
303 #++++++++++++++++++++++++++++++++++++++++ gen_TPC ++++++++++++++++++++++++++++++++++++++++
304 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308 my $TPCActive_x = $widthCRM_active;
309 my $TPCActive_y = $driftTPCActive;
310 my $TPCActive_z = $lengthCRM_active;
313 my $TPC_x = $widthCRM;
314 my $TPC_y = $TPCActive_y + $ReadoutPlane;
315 my $TPC_z = $lengthCRM;
318 $TPC = $basename."_TPC" . $suffix . ".gdml";
319 push (@gdmlFiles, $TPC);
321 open(TPC) or die("Could not open file $TPC for writing");
323 # The standard XML prefix and starting the gdml
325 <?xml version='1.0'?>
330 # All the TPC solids save the wires.
333 <box name="CRM" lunit="cm"
337 <box name="CRMZPlane" lunit="cm"
341 <box name="CRMXPlane" lunit="cm"
345 <box name="CRMActive" lunit="cm"
352 #++++++++++++++++++++++++++++ Wire Solids ++++++++++++++++++++++++++++++
353 # in principle we only need only one wire solid, since CRM is a square
354 # but to be more general ...
358 <tube name="CRMWireZ"
364 <tube name="CRMWireX"
375 # Begin structure and create wire logical volumes
378 <volume name="volTPCActive">
379 <materialref ref="LAr"/>
380 <solidref ref="CRMActive"/>
387 <volume name="volTPCWireZ">
388 <materialref ref="Copper_Beryllium_alloy25"/>
389 <solidref ref="CRMWireZ"/>
392 <volume name="volTPCWireX">
393 <materialref ref="Copper_Beryllium_alloy25"/>
394 <solidref ref="CRMWireX"/>
401 <volume name="volTPCPlaneZ">
402 <materialref ref="LAr"/>
403 <solidref ref="CRMZPlane"/>
406 if ($wires_on==1) # add wires to Z plane
408 for($i=0;$i<$nChannelsViewPerCRM;++$i)
410 my $zpos = -0.5 * $TPCActive_z + $i*$wirePitch + 0.5*$padWidth;
414 <volumeref ref="volTPCWireZ"/>
415 <position name="posWireZ$i" unit="cm" x="0" y="0" z="$zpos"/>
416 <rotationref ref="rMinus90AboutY"/>
425 <volume name="volTPCPlaneX">
426 <materialref ref="LAr"/>
427 <solidref ref="CRMXPlane"/>
431 if ($wires_on==1) # add wires to X plane
433 for($i=0;$i<$nChannelsViewPerCRM;++$i)
436 my $xpos = -0.5 * $TPCActive_x + $i*$wirePitch + 0.5*$padWidth;
439 <volumeref ref="volTPCWireX"/>
440 <position name="posWireX$i" unit="cm" x="$xpos" y="0" z="0"/>
441 <rotationref ref="rIdentity"/>
454 $posZplane[1] = 0.5*$TPC_y - 0.5*$padWidth;
458 $posXplane[1] = 0.5*$TPC_y - 1.5*$padWidth;
461 $posTPCActive[0] = 0;
462 $posTPCActive[1] = -$ReadoutPlane;
463 $posTPCActive[2] = 0;
466 #wrap up the TPC file
469 <volume name="volTPC">
470 <materialref ref="LAr"/>
471 <solidref ref="CRM"/>
473 <volumeref ref="volTPCPlaneZ"/>
474 <position name="posPlaneZ" unit="cm"
475 x="$posZplane[0]" y="$posZplane[1]" z="$posZplane[2]"/>
476 <rotationref ref="rIdentity"/>
479 <volumeref ref="volTPCPlaneX"/>
480 <position name="posPlaneX" unit="cm"
481 x="$posXplane[0]" y="$posXplane[1]" z="$posXplane[2]"/>
482 <rotationref ref="rIdentity"/>
485 <volumeref ref="volTPCActive"/>
486 <position name="posActive" unit="cm"
487 x="$posTPCActive[0]" y="$posTPCActive[1]" z="$posTPCActive[2]"/>
488 <rotationref ref="rIdentity"/>
503 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
504 #++++++++++++++++++++++++++++++++++++++ gen_Cryostat +++++++++++++++++++++++++++++++++++++
505 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
510 # Create the cryostat fragment file name,
511 # add file to list of output GDML fragments,
513 $CRYO = $basename."_Cryostat" . $suffix . ".gdml";
514 push (@gdmlFiles, $CRYO);
516 open(CRYO) or die("Could not open file $CRYO for writing");
519 # The standard XML prefix and starting the gdml
521 <?xml version='1.0'?>
525 # All the cryostat solids.
528 <box name="Cryostat" lunit="cm"
533 <box name="ArgonInterior" lunit="cm"
538 <box name="GaseousArgon" lunit="cm"
543 <subtraction name="SteelShell">
544 <first ref="Cryostat"/>
545 <second ref="ArgonInterior"/>
554 <volume name="volSteelShell">
555 <materialref ref="STEEL_STAINLESS_Fe7Cr2Ni" />
556 <solidref ref="SteelShell" />
558 <volume name="volGaseousArgon">
559 <materialref ref="ArGas"/>
560 <solidref ref="GaseousArgon"/>
563 <volume name="volCryostat">
564 <materialref ref="LAr" />
565 <solidref ref="Cryostat" />
567 <volumeref ref="volGaseousArgon"/>
568 <position name="posGaseousArgon" unit="cm" x="0" y="$Argon_y/2-$HeightGaseousAr/2" z="0"/>
571 <volumeref ref="volSteelShell"/>
572 <position name="posSteelShell" unit="cm" x="0" y="0" z="0"/>
577 if ($tpc_on==1) # place TPC inside croysotat
580 $posY = $Argon_y/2 - $HeightGaseousAr - 0.5*($driftTPCActive + $ReadoutPlane);
581 for($ii=0;$ii<$nCRM_z;$ii++)
583 $posZ = -0.5*$Argon_z + $zLArBuffer + ($ii+0.5)*$lengthCRM;
585 for($jj=0;$jj<$nCRM_x;$jj++)
587 $posX = -0.5*$Argon_x + $xLArBuffer + ($jj+0.5)*$widthCRM;
590 <volumeref ref="volTPC"/>
591 <position name="posTPC\-$ii\-$jj" unit="cm"
592 x="$posX" y="$posY" z="$posZ"/>
612 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
613 #+++++++++++++++++++++++++++++++++++++ gen_Enclosure +++++++++++++++++++++++++++++++++++++
614 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
619 # Create the detector enclosure fragment file name,
620 # add file to list of output GDML fragments,
622 $ENCL = $basename."_DetEnclosure" . $suffix . ".gdml";
623 push (@gdmlFiles, $ENCL);
625 open(ENCL) or die("Could not open file $ENCL for writing");
628 # The standard XML prefix and starting the gdml
630 <?xml version='1.0'?>
635 # All the detector enclosure solids.
639 <box name="FoamPadBlock" lunit="cm"
640 x="$Cryostat_x + 2*$FoamPadding"
641 y="$Cryostat_y + 2*$FoamPadding"
642 z="$Cryostat_z + 2*$FoamPadding" />
644 <subtraction name="FoamPadding">
645 <first ref="FoamPadBlock"/>
646 <second ref="Cryostat"/>
647 <positionref ref="posCenter"/>
650 <box name="SteelSupportBlock" lunit="cm"
651 x="$Cryostat_x + 2*$FoamPadding + 2*$SteelSupport_x"
652 y="$Cryostat_y + 2*$FoamPadding + 2*$SteelSupport_y"
653 z="$Cryostat_z + 2*$FoamPadding + 2*$SteelSupport_z" />
655 <subtraction name="SteelSupport">
656 <first ref="SteelSupportBlock"/>
657 <second ref="FoamPadding"/>
658 <positionref ref="posCenter"/>
661 <box name="DetEnclosure" lunit="cm"
670 # Detector enclosure structure
673 <volume name="volFoamPadding">
674 <materialref ref="FD_foam"/>
675 <solidref ref="FoamPadding"/>
678 <volume name="volSteelSupport">
679 <materialref ref="AirSteelMixture"/>
680 <solidref ref="SteelSupport"/>
683 <volume name="volDetEnclosure">
684 <materialref ref="Air"/>
685 <solidref ref="DetEnclosure"/>
688 <volumeref ref="volFoamPadding"/>
689 <positionref ref="posCryoInDetEnc"/>
692 <volumeref ref="volSteelSupport"/>
693 <positionref ref="posCryoInDetEnc"/>
696 <volumeref ref="volCryostat"/>
697 <positionref ref="posCryoInDetEnc"/>
716 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
717 #+++++++++++++++++++++++++++++++++++++++ gen_World +++++++++++++++++++++++++++++++++++++++
718 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
723 # Create the WORLD fragment file name,
724 # add file to list of output GDML fragments,
726 $WORLD = $basename."_World" . $suffix . ".gdml";
727 push (@gdmlFiles, $WORLD);
728 $WORLD = ">" . $WORLD;
729 open(WORLD) or die("Could not open file $WORLD for writing");
732 # The standard XML prefix and starting the gdml
734 <?xml version='1.0'?>
739 # All the World solids.
742 <box name="World" lunit="cm"
743 x="$DetEncWidth+2*$RockThickness"
744 y="$DetEncHeight+2*$RockThickness"
745 z="$DetEncLength+2*$RockThickness"/>
752 <volume name="volWorld" >
753 <materialref ref="DUSEL_Rock"/>
754 <solidref ref="World"/>
757 <volumeref ref="volDetEnclosure"/>
758 <position name="posDetEnclosure" unit="cm" x="$OriginXSet" y="$OriginYSet" z="$OriginZSet"/>
766 # make_gdml.pl will take care of <setup/>
773 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
774 #++++++++++++++++++++++++++++++++++++ write_fragments ++++++++++++++++++++++++++++++++++++
775 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
777 sub write_fragments()
779 # This subroutine creates an XML file that summarizes the the subfiles output
780 # by the other sub routines - it is the input file for make_gdml.pl which will
781 # give the final desired GDML file. Specify its name with the output option.
782 # (you can change the name when running make_gdml)
784 # This code is taken straigh from the similar MicroBooNE generate script, Thank you.
786 if ( ! defined $output )
788 $output = "-"; # write to STDOUT
791 # Set up the output file.
792 $OUTPUT = ">" . $output;
793 open(OUTPUT) or die("Could not open file $OUTPUT");
796 <?xml version='1.0'?>
798 <!-- Input to Geometry/gdml/make_gdml.pl; define the GDML fragments
799 that will be zipped together to create a detector description.
806 <!-- These files contain GDML <constant></constant>
807 blocks. They are read in separately, so they can be
808 interpreted into the remaining GDML. See make_gdml.pl for
814 foreach $filename (@defFiles)
817 <filename> $filename </filename>
827 <!-- The GDML file fragments to be zipped together. -->
831 foreach $filename (@gdmlFiles)
834 <filename> $filename </filename>
849 print "Some key parameters for dual-phase LAr TPC (unit cm unless noted otherwise)\n";
850 print "CRM active area : $widthCRM_active x $lengthCRM_active\n";
851 print "CRM total area : $widthCRM x $lengthCRM\n";
852 print "TPC active volume : $widthTPCActive x $driftTPCActive x $lengthTPCActive\n";
853 print "Argon buffer : ($xLArBuffer, $yLArBuffer, $zLArBuffer) \n";
854 print "Detector enclosure : $DetEncWidth x $DetEncHeight x $DetEncLength\n";
855 print "TPC Origin : ($OriginXSet, $OriginYSet, $OriginZSet) \n";
857 # run the sub routines that generate the fragments
859 gen_Define(); # generates definitions at beginning of GDML
860 gen_Materials(); # generates materials to be used
861 gen_TPC(); # generate TPC for a given unit CRM
864 gen_World(); # places the enclosure among DUSEL Rock
867 write_fragments(); # writes the XML input for make_gdml.pl
868 # which zips together the final GDML