3 # contact tylerdalion@gmail.com for any GDML/generate questions
4 # I would love to help!
6 # Each subroutine generates a fragment GDML file, and the last subroutine
7 # creates an XML file that make_gdml.pl will use to appropriately arrange
8 # the fragment GDML files to create the final desired DUNE GDML file,
9 # to be named by make_gdml output command
11 # If you are playing with different geometries, you can use the
12 # suffix command to help organize your work.
19 Math::BigFloat->precision(-16);
21 open(my $wout, '>', 'gdmlWireCenters.txt');
23 GetOptions( "help|h" => \$help,
24 "suffix|s:s" => \$suffix,
25 "output|o:s" => \$output,
26 "wires|w:s" => \$wires,
27 "protoDune|p:s" => \$protoDune,
28 "workspace|k:s" => \$workspace);
32 # If the user requested help, print the usage notes and exit.
37 if ( ! defined $suffix )
39 # The user didn't supply a suffix, so append nothing to the file
45 # Otherwise, stick a "-" before the suffix, so that a suffix of
46 # "test" applied to filename.gdml becomes "filename-test.gdml".
47 $suffix = "-" . $suffix;
50 if ( ! defined $workspace )
53 if ( ! defined $protoDune )
56 print "\t\tCreating full geometry.\n";
58 elsif ( $protoDune == 1 )
60 print "\t\tCreating rough version of protoDUNE.\n";
63 elsif ( $workspace == 1)
65 print "\t\tCreating smaller (1x2x2-APA) workspace geometry.\n";
67 elsif ( $workspace == 2)
69 print "\t\tCreating 1x2x6-APA geometry.\n";
72 # set wires on to be the default, unless given an input by the user
73 $wires_on = 1; # 1=on, 0=off
83 # options for different parameters
89 #++++++++++++++++++++++++ Begin defining variables +++++++++++++++++++++++++
91 ## The GDML is build from the inside out to avoid overlaps, but that means
92 ## that the larger dimensions (such as the cryostat dimensions) are calculated
93 ## to be slightly different than the parameters calculated and reported by
94 ## engineers. All of this error is within reason and for the better, since
95 ## we don't want this Geometry to be overly complex or long.
100 ##################################################################
101 ##################### Wire Plane Parameters ######################
104 $UWirePitch = 0.4667;
105 $VWirePitch = 0.4667;
109 $nZChannelsPerAPA = 960;
111 # dune10kt 3mm version
112 if($Pitch3mmVersion==1){
116 $nZChannelsPerAPA = 2*(229.44/0.3 + 1);
119 # dune10kt ~45 deg UV wires version
120 if($UVAngle45Option==1){
135 $SinUAngle = sin( deg2rad($UAngle) );
136 $CosUAngle = cos( deg2rad($UAngle) );
137 $TanUAngle = tan( deg2rad($UAngle) );
139 $SinVAngle = sin( deg2rad($VAngle) );
140 $CosVAngle = cos( deg2rad($VAngle) );
141 $TanVAngle = tan( deg2rad($VAngle) );
143 $UWire_yint = $UWirePitch/$SinUAngle;
144 $UWire_zint = $UWirePitch/$CosUAngle;
146 $VWire_yint = $VWirePitch/$SinVAngle;
147 $VWire_zint = $VWirePitch/$CosVAngle;
149 $TPCWireThickness = 0.015;
151 $TPCWirePlaneThickness = $TPCWireThickness;
152 #height and length defined lower
156 ##################################################################
157 ################### Cryostat/APA parameters ######################
163 elsif($workspace==2){
168 $nAPAs = $nAPAWide*$nAPAHigh*$nAPALong;
171 $G10thickness = $inch/8;
172 $WrapCover = $inch/16;
174 $SpaceAPAToCryoWall = 15;
175 $SpaceAPAToFloor = 59.4 - 10.2; # 10.2cm just adjusts for how spaces are reported
176 $SpaceAPAToTopLAr = 50.9 - 10.2;
177 $UpstreamLArPadding = 311.4 - 10.2;
178 $DownstreamLArPadding = 59.4 - 10.2;
181 $SpaceAPAToCryoWall = 20;
182 $SpaceAPAToFloor = 45;
183 $SpaceAPAToTopLAr = 45;
184 $UpstreamLArPadding = 80;
185 $DownstreamLArPadding = 80;
188 #InnerDrift is the max distance form the edge of the CPA to the edge of the first wire plane
190 $OuterDrift = $SpaceAPAToCryoWall;
191 $APAFrame_x = 5.0661; # ~2in -- this does not include the wire spacing
193 $TPCWireThickness = 0.015;
194 $TPCWirePlaneThickness = $TPCWireThickness;
195 #$APAWirePlaneSpacing = 0.4730488 + $TPCWirePlaneThickness; # center to center spacing between all of the wire planes (g, u, v, and x)
197 if($Pitch3mmVersion==1){
198 $APAWirePlaneSpacing = 0.3;
200 $APAWirePlaneSpacing = 0.476;
203 # At creation of the plane volumes, the y and z boundaries will be increased
204 # by this much at each of the 4 edges. this is so the corners of the wire
205 # tubes don't extrude. For all other purposes, the plane dimensions stay as originally defined
206 $UVPlaneBoundNudge = $TPCWireThickness;
210 # The following are all widths about the z center of an APA
211 $Zactive_z = ($nZChannelsPerAPA/2-1)*$XWirePitch + $TPCWireThickness;
212 $APAFrame_z = 231.59 - 2*(2*$G10thickness+$WrapCover);
213 $Vactive_z = $APAFrame_z;
214 $Uactive_z = $APAFrame_z + 2*$G10thickness;
219 $ReadoutBoardOverlap = 7.61; #board overlaps wires, chop this off of their active height
221 $Zactive_y = $APAFrame_y + 0*$G10thickness - $ReadoutBoardOverlap;
222 $Vactive_y = $APAFrame_y + 1*$G10thickness - $ReadoutBoardOverlap;
223 $Uactive_y = $APAFrame_y + 2*$G10thickness - $ReadoutBoardOverlap;
224 # the last G10 board for the grid, then a cover. This is not "covered" by the board
225 $APAphys_y = $APAFrame_y + 4*$G10thickness + $WrapCover;
227 $APAGap_y = 0.4; #separation between APAs (cover to cover) along the incident beam axis
228 $APAGap_z = 0.8; #separation between APAs (cover to cover) along the vertical axis
231 # include APA spacing in y and z so volTPCs touch in y and z directions with correct APA
232 # spacing - this makes for smoother event generation.
234 $APA_UtoU_x = $APAFrame_x + 6*$APAWirePlaneSpacing + $TPCWirePlaneThickness; # thickness of APA between its
235 # outer wire planes (center to center)
236 $TPCInner_x = $InnerDrift + 3*$APAWirePlaneSpacing + $TPCWirePlaneThickness;
237 $TPCOuter_x = $OuterDrift + 3*$APAWirePlaneSpacing + $TPCWirePlaneThickness;
239 $TPC_z = $APAphys_z + $APAGap_z;
240 $TPC_y = $APAphys_y + $APAGap_y;
243 #$CPATube_ID = 4.747;
246 $Cathode_y = $APAphys_y - $CPATube_OD;
247 $Cathode_z = $APAphys_z - $CPATube_OD;
250 $APAToAPA = $APAFrame_x
252 + $Cathode_x; # center to center
254 $CPAToAPA = $APAFrame_x/2
256 + $Cathode_x/2; # center to center
258 $SteelThickness = 0.5*$inch; #half inch
259 $HeightGaseousAr = 50;
261 $Argon_x = ($nAPAWide-1)*$APAToAPA
262 + $APA_UtoU_x + $TPCWirePlaneThickness
263 + 2*$SpaceAPAToCryoWall;
265 if($workspace==1||$workspace==2){ # this is arbitrary for the workspace, but size down a little
266 $Argon_x = 2*$CPAToAPA + $Cathode_x + 2*$SpaceAPAToCryoWall;
270 $Argon_y = $nAPAHigh*$APAphys_y
271 + ($nAPAHigh-1)*$APAGap_y
272 + $SpaceAPAToFloor + $SpaceAPAToTopLAr
274 # both liquid AND gaseous argon
276 $Argon_z = $nAPALong*$APAphys_z
277 + ($nAPALong-1)*$APAGap_z
278 + $UpstreamLArPadding + $DownstreamLArPadding;
280 $Cryostat_x = $Argon_x + 2*$SteelThickness;
281 $Cryostat_y = $Argon_y + 2*$SteelThickness;
282 $Cryostat_z = $Argon_z + 2*$SteelThickness;
286 ##################################################################
287 ############## DetEnc and World relevant parameters #############
290 $SteelSupport_x = 100;
291 $SteelSupport_y = 50;
292 $SteelSupport_z = 100;
294 $FracMassOfSteel = 0.998; #The steel support is not a solid block, but a mixture of air and steel
295 $FracMassOfAir = 1-$FracMassOfSteel;
297 $SpaceSteelSupportToWall = 100;
298 $SpaceSteelSupportToCeiling = 100;
300 $DetEncWidth = $Cryostat_x
301 + 2*($SteelSupport_x + $FoamPadding) + $SpaceSteelSupportToCeiling;
302 $DetEncHeight = $Cryostat_y
303 + 2*($SteelSupport_y + $FoamPadding) + 2*$SpaceSteelSupportToWall;
304 $DetEncLength = $Cryostat_z
305 + 2*($SteelSupport_z + $FoamPadding) + 2*$SpaceSteelSupportToWall;
307 $posCryoInDetEnc_y = - $DetEncHeight/2 + $SteelSupport_y + $FoamPadding + $Cryostat_y/2;
309 $RockThickness = 3000;
310 if ($workspace == 0){
311 # Initially, the world dimensions and the OriginZSet
312 # left only ~222cm to the world boundary from the
313 # +z boundary of volDetEnclosure. Bump that up to
314 # at least 10m for good measure.
315 # This is in an if statement so that it does not affect
316 # the workspace geometries, which are already being used
317 $RockThickness += 800
320 # We want the world origin to be at the very front of the fiducial volume.
321 # move it to the front of the enclosure, then back it up through the concrete/foam,
322 # then through the Cryostat shell, then through the upstream dead LAr (including the
323 # dead LAr on the edge of the TPC, but this is covered in $UpstreamLArPadding).
324 # This is to be added to the z position of every volume in volWorld
326 $OriginZSet = $DetEncLength/2
327 - $SpaceSteelSupportToWall
331 - $UpstreamLArPadding
332 - ($APAphys_z - $Uactive_z)/2;
334 # We want the world origin to be vertically centered between the stacked APAs.
335 # This is to be added to the y position of every volume in volWorld
337 $OriginYSet = $DetEncHeight/2
345 if($protoDune==1){ # bring the origin to the bottom of the APAs for protoDUNE
346 $OriginYSet = $OriginYSet + $APAphys_y + $APAGap_y/2;
349 $OriginXSet = 0; # centered for now
356 ####################################################################
357 ######################## Paddle Dimensions ########################
359 $APAFrameZSide_y = 4*$inch;
360 $APAFrameYSide_z = 4*$inch;
361 $LightPaddle_x = 0.476;
362 $LightPaddle_y = 4*$inch;
363 $LightPaddle_z = $APAFrame_z - 2*$APAFrameYSide_z;
364 $nLightPaddlesPerAPA = 10; # 10, or 20 for double coverage (for now)
365 $PaddleYInterval = (2*$APAphys_y+$APAGap_y-$LightPaddle_y-2*$APAFrameZSide_y)
366 /(2*$nLightPaddlesPerAPA-1);
367 $FrameToPaddleSpace = ($PaddleYInterval-$APAGap_y)/2;
371 # $PaddleYInterval is defined so that the center-to-center distance in the
372 # y direction between paddles is uniform between vertically stacked APAs.
373 # $FrameToPaddleSpace is from the BOTTOM of the APA frame (4" in y direction)
374 # to the CENTER of a paddle, including the 4" part of the frame. This variable's
375 # primary purpose is to position the lowest paddle in each APA.
380 #+++++++++++++++++++++++++ End defining variables ++++++++++++++++++++++++++
383 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
384 #+++++++++++++++++++++++++++++++++++++++++ usage +++++++++++++++++++++++++++++++++++++++++
385 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
389 print "Usage: $0 [-h|--help] [-o|--output <fragments-file>] [-s|--suffix <string>]\n";
390 print " if -o is omitted, output goes to STDOUT; <fragments-file> is input to make_gdml.pl\n";
391 print " -s <string> appends the string to the file names; useful for multiple detector versions\n";
392 print " -h prints this message, then quits\n";
397 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
398 #++++++++++++++++++++++++++++++++++++++ gen_Define +++++++++++++++++++++++++++++++++++++++
399 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
404 # Create the <define> fragment file name,
405 # add file to list of fragments,
407 $DEF = "dune10kt_v1_Def" . $suffix . ".gdml";
408 push (@gdmlFiles, $DEF);
410 open(DEF) or die("Could not open file $DEF for writing");
414 <?xml version='1.0'?>
424 <position name="posCryoInDetEnc" unit="cm" x="0" y="$posCryoInDetEnc_y" z="0"/>
425 <position name="posCenter" unit="cm" x="0" y="0" z="0"/>
426 <rotation name="rPlus90AboutX" unit="deg" x="90" y="0" z="0"/>
427 <rotation name="rMinus90AboutY" unit="deg" x="0" y="270" z="0"/>
428 <rotation name="rMinus90AboutYMinus90AboutX" unit="deg" x="270" y="270" z="0"/>
429 <rotation name="rPlusUAngleAboutX" unit="deg" x="90-$UAngle" y="0" z="0"/>
430 <rotation name="rPlusVAngleAboutX" unit="deg" x="90+$VAngle" y="0" z="0"/>
431 <rotation name="rPlus180AboutX" unit="deg" x="180" y="0" z="0"/>
432 <rotation name="rPlus180AboutY" unit="deg" x="0" y="180" z="0"/>
433 <rotation name="rPlus180AboutXPlus180AboutY" unit="deg" x="180" y="180" z="0"/>
434 <rotation name="rIdentity" unit="deg" x="0" y="0" z="0"/>
441 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
442 #+++++++++++++++++++++++++++++++++++++ gen_Materials +++++++++++++++++++++++++++++++++++++
443 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
448 # Create the <materials> fragment file name,
449 # add file to list of output GDML fragments,
451 $MAT = "dune10kt_v1_Materials" . $suffix . ".gdml";
452 push (@gdmlFiles, $MAT);
455 open(MAT) or die("Could not open file $MAT for writing");
457 # Add any materials special to this geometry by defining a mulitline string
458 # and passing it to the gdmlMaterials::gen_Materials() function.
460 $DensityAirSteel = 1/(0.001205/$FracMassOfAir + 7.9300/$FracMassOfSteel);
463 <!-- preliminary values -->
464 <material name="AirSteelMixture" formula="AirSteelMixture">
465 <D value="$DensityAirSteel" unit="g/cm3"/>
466 <fraction n="$FracMassOfSteel" ref="STEEL_STAINLESS_Fe7Cr2Ni"/>
467 <fraction n="$FracMassOfAir" ref="Air"/>
471 # add the general materials used anywere
472 print MAT gdmlMaterials::gen_Materials( $asmix );
477 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
478 #++++++++++++++++++++++++++++++++++++++++ gen_TPC ++++++++++++++++++++++++++++++++++++++++
479 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
490 my $TPCActive_x = $_[0]-(3*$APAWirePlaneSpacing);
491 my $TPCActive_y = $_[1] - $APAGap_y/2 - $ReadoutBoardOverlap ; #TODO: make the Active height more accurate
492 my $TPCActive_z = $_[2];
495 #constructs everything inside volTPC, namely
496 # (moving from left to right, or from +x to -x)
498 # -volTPCPlaneU: with wires angled from vertical slightly different than in V
499 # -volTPCPlaneV: with wires angled from vertical slightly differently than in U
500 # -volTPCPlaneX: with vertical wires
503 # Create the TPC fragment file name,
504 # add file to list of output GDML fragments,
506 $TPC = "dune10kt_v1_TPC_${_[3]}" . $suffix . ".gdml";
507 push (@gdmlFiles, $TPC);
509 open(TPC) or die("Could not open file $TPC for writing");
512 print $wout "\n\n\n----- Wires for $_[3] -----\n\n\n";
515 # The standard XML prefix and starting the gdml
517 <?xml version='1.0'?>
522 # All the TPC solids save the wires.
525 <box name="$_[3]" lunit="cm"
529 <box name="${_[3]}UPlane" lunit="cm"
530 x="$TPCWirePlaneThickness"
531 y="$Uactive_y + $UVPlaneBoundNudge"
532 z="$Uactive_z + $UVPlaneBoundNudge"/>
533 <box name="${_[3]}VPlane" lunit="cm"
534 x="$TPCWirePlaneThickness"
535 y="$Vactive_y + $UVPlaneBoundNudge"
536 z="$Vactive_z + $UVPlaneBoundNudge"/>
537 <box name="${_[3]}ZPlane" lunit="cm"
538 x="$TPCWirePlaneThickness"
541 <box name="${_[3]}Active" lunit="cm"
548 #++++++++++++++++++++++++++++ Wire Solids ++++++++++++++++++++++++++++++
552 <tube name="${_[3]}WireVert"
553 rmax="0.5*$TPCWireThickness"
560 # Set number of wires to default to zero, when $wires_on = 0, for a low memory
561 # version. But if $wires_on = 1, calculate the number of wires on each side of each
562 # plane to be used in the for loops
564 my $NumberCornerUWires = 0;
565 my $NumberSideUWires = 0;
566 my $NumberCommonUWires = 0;
567 my $NumberCornerVWires = 0;
568 my $NumberSideVWires = 0;
569 my $NumberCommonVWires = 0;
570 my $NumberVerticalWires = 0;
574 # Number of wires in one corner
575 $NumberCornerUWires = int( $APAFrame_z/($UWirePitch/$CosUAngle) );
577 $NumberCornerVWires = int( $APAFrame_z/($VWirePitch/$CosVAngle) );
580 # Total number of wires touching one vertical (longer) side
581 # Note that the total number of wires per plane is this + another set of corner wires
582 $NumberSideUWires = int( $Uactive_y/$UWire_yint );
583 if($Pitch3mmVersion==1){ $NumberSideUWires = $NumberSideUWires-1; }
585 $NumberSideVWires = int( $Vactive_y/$VWire_yint );
587 # Number of wires per side that aren't cut off by the corner
588 $NumberCommonUWires = $NumberSideUWires - $NumberCornerUWires;
590 $NumberCommonVWires = $NumberSideVWires - $NumberCornerVWires;
592 # Number of wires on the vertical plane
593 # Since APA Active z is defined in docdb 3383 to be distance
594 # between outer vertical wires, + 1 since the floor of this
595 # division will be one under, giving the amt of spaces, not wires
596 $NumberVerticalWires = int( $Zactive_z/$XWirePitch ) + 1;
597 #$NumberVerticalWires = 960;
600 $nUchans = 2*$NumberCornerUWires;
601 $nVchans = 2*$NumberCornerVWires;
603 print $wout "$nUchans U channels\n";
604 print $wout "$nVchans V channels\n";
605 print $wout "$NumberVerticalWires Z channels per side\n";
607 print $wout "$NumberCornerUWires U corner wires\n";
608 print $wout "$NumberCommonUWires U common wires\n";
609 print $wout "$NumberCornerVWires V corner wires\n";
610 print $wout "$NumberCommonVWires V common wires\n";
614 # hard codeed number will be a factor determined from engineering spreadsheets on wire endpoints,
615 # but since that won't exist for a while, use this number to avoid overlaps
616 my $FirstUWireOffset = .55 + $G10thickness + 2*$G10thickness*$TanUAngle - $UWire_zint;
617 my $FirstVWireOffset = .5; # doesnt include a G10 board in width
619 if($Pitch3mmVersion==1){
620 my $FirstUWireOffset = .15 + $G10thickness + 2*$G10thickness*$TanUAngle - $UWire_zint;
621 my $FirstVWireOffset = .15; # doesnt include a G10 board in width
624 if($UVAngle45Option==1){$FirstVWireOffset = .7;}
627 my $FirstTopUWire_yspan =
630 + $FirstUWireOffset/$TanUAngle # walk us up to the first wire
631 + $UWire_yint*($NumberSideUWires-1) # up to the top of the top common wire
632 - $Uactive_z/$TanUAngle # back to the bottom of the top common wire
633 + $UWire_yint); # nudge up to bottom of the first top corner wire
635 my $FirstTopVWire_yspan =
638 + $FirstVWireOffset/$TanVAngle # walk us up to the first wire
639 + $VWire_yint*($NumberSideVWires-1) # up to the top of the top common wire
640 - $Vactive_z/$TanVAngle # back to the bottom of the top common wire
641 + $VWire_yint); # nudge up to bottom of the first top corner wire
644 # The corner wires for the U plane
647 for ($i = 0; $i < $NumberCornerUWires; $i++)
649 $CornerUWireLength[$i] = ($FirstUWireOffset + $i*$UWire_zint)/$SinUAngle;
652 <tube name="${_[3]}WireU$i"
653 rmax="0.5*$TPCWireThickness"
654 z="$CornerUWireLength[$i]"
662 $CommonUWireLength = $Uactive_z/$SinUAngle;
665 <tube name="${_[3]}WireUCommon"
666 rmax="0.5*$TPCWireThickness"
667 z="$CommonUWireLength"
673 for ($i = 0; $i < $NumberCornerUWires; $i++)
676 $TopCornerUWireLength[$i] = ($FirstTopUWire_yspan - $i*$UWire_yint)/$CosUAngle;
678 $j = $i + $NumberSideUWires;
681 <tube name="${_[3]}WireU$j"
682 rmax="0.5*$TPCWireThickness"
683 z="$TopCornerUWireLength[$i]"
694 # The corner wires for the V plane
697 for ($i = 0; $i < $NumberCornerVWires; ++$i)
699 $CornerVWireLength[$i] = ($FirstVWireOffset + $i*$VWire_zint)/$SinVAngle;
703 <tube name="${_[3]}WireV$i"
704 rmax="0.5*$TPCWireThickness"
705 z="$CornerVWireLength[$i]"
714 # The wire used many times in the middle of the V plane
715 # Same subtraction as U common
717 $CommonVWireLength = $Vactive_z/$SinVAngle;
720 <tube name="${_[3]}WireVCommon"
721 rmax="0.5*$TPCWireThickness"
722 z="$CommonVWireLength"
728 for ($i = 0; $i < $NumberCornerVWires; $i++)
731 $TopCornerVWireLength[$i] = ($FirstTopVWire_yspan - $i*$VWire_yint)/$CosVAngle;
733 $j = $i + $NumberSideVWires;
736 <tube name="${_[3]}WireV$j"
737 rmax="0.5*$TPCWireThickness"
738 z="$TopCornerVWireLength[$i]"
749 # Begin structure and create the vertical wire logical volume
753 <volume name="volTPCActive${_[3]}">
754 <materialref ref="LAr"/>
755 <solidref ref="${_[3]}Active"/>
764 <volume name="volTPCWireVert${_[3]}">
765 <materialref ref="Copper_Beryllium_alloy25"/>
766 <solidref ref="${_[3]}WireVert"/>
770 # Corner U wires logical volumes
771 for ($i = 0; $i < $NumberCornerUWires; ++$i)
774 <volume name="volTPCWireU$i${_[3]}">
775 <materialref ref="Copper_Beryllium_alloy25"/>
776 <solidref ref="${_[3]}WireU$i"/>
782 # Top Corner U wires logical volumes
783 for ($j = $NumberSideUWires; $j < $NumberSideUWires + $NumberCornerUWires; ++$j)
786 <volume name="volTPCWireU$j${_[3]}">
787 <materialref ref="Copper_Beryllium_alloy25"/>
788 <solidref ref="${_[3]}WireU$j"/>
794 # Common U wire logical volume, referenced many times
796 <volume name="volTPCWireUCommon${_[3]}">
797 <materialref ref="Copper_Beryllium_alloy25"/>
798 <solidref ref="${_[3]}WireUCommon"/>
803 # Corner V wires logical volumes
804 for ($i = 0; $i < $NumberCornerVWires; ++$i)
807 <volume name="volTPCWireV$i${_[3]}">
808 <materialref ref="Copper_Beryllium_alloy25"/>
809 <solidref ref="${_[3]}WireV$i"/>
815 # Top Corner V wires logical volumes
816 for ($j = $NumberSideVWires; $j < $NumberSideVWires + $NumberCornerVWires; ++$j)
819 <volume name="volTPCWireV$j${_[3]}">
820 <materialref ref="Copper_Beryllium_alloy25"/>
821 <solidref ref="${_[3]}WireV$j"/>
826 # Common V wire logical volume, referenced many times
828 <volume name="volTPCWireVCommon${_[3]}">
829 <materialref ref="Copper_Beryllium_alloy25"/>
830 <solidref ref="${_[3]}WireVCommon"/>
841 #+++++++++++++++++++++++++ Position physical wires ++++++++++++++++++++++++++
843 # ++++++++++++++++++++++ U Plane +++++++++++++++++++++++
845 # Create U plane logical volume
847 <volume name="volTPCPlaneU${_[3]}">
848 <materialref ref="LAr"/>
849 <solidref ref="${_[3]}UPlane"/>
853 print $wout "\n- Wires for U plane -\n\n";
854 print $wout " Uplane_y: $Uactive_y\n";
855 print $wout " Uplane_z: $Uactive_z\n";
861 # Starting with the bottom left corner wires:
862 # x=0 to center the wires in the plane
863 # y positioning: (-0.5*$TPCWirePlaneHeight) starts the incremental increase
864 # from the bottom of the plane, and trigonometry gives the increment
865 # z positioning: Looking at the plane from the positive x direction,
866 # (0.5*$TPCWirePlaneLength) starts the incremental increase from
867 # the lower left corner.
868 # rotation: same as common wire in code below
870 $FirstU_ypos = - $Uactive_y/2 + $FirstUWireOffset/$TanUAngle/2;
871 $FirstU_zpos = + $Uactive_z/2 - $FirstUWireOffset/2;
873 for ($i = 0; $i < $NumberCornerUWires; ++$i)
876 my $ypos = $FirstU_ypos + ($i)*0.5*$UWire_yint;
877 my $zpos = $FirstU_zpos - ($i)*0.5*$UWire_zint;
879 $pitch = ($ypos - $lastYpos) * $SinUAngle
880 - ($zpos - $lastZpos) * $CosUAngle;
884 <volumeref ref="volTPCWireU$i${_[3]}"/>
885 <position name="pos${_[3]}WireU$i" unit="cm" x="0" y="$ypos " z="$zpos"/>
886 <rotation name="rUAngle$i" unit="deg" x="90-$UAngle" y="0" z="0"/>
890 $topY = $ypos + ($CosUAngle*$CornerUWireLength[$i]/2);
891 $bottomY = $ypos - ($CosUAngle*$CornerUWireLength[$i]/2);
892 $edgeZ_p = $zpos + ($SinUAngle*$CornerUWireLength[$i]/2);
893 $edgeZ_m = $zpos - ($SinUAngle*$CornerUWireLength[$i]/2);
894 print $wout "U$i: ( $ypos , $zpos ) (pitch = $pitch)\n";
895 print $wout " -- Y: $bottomY to $topY -- Z: $edgeZ_m to $edgeZ_p \n";
903 # Moving upwards to the common wires:
904 # x and z are zero to center the wires along a vertical axis
905 # y positioning: The trick is positioning the lowest common wire so that the pitch
906 # is consistent, then the increment is double the increment of
907 # the corner wires since there is no z incriment.
908 # rotation: wires in \\\\ direction, so +90deg to bring them to vertical and
909 # +UAngle counterclockwise to arrive at proper orientation
910 # Note that the counter maintains wire number (in pos. name) counting bottom to top
913 my $StartCommonUWires_ypos = $lastYpos + $UWire_yint - abs( $lastZpos )/$TanUAngle;
915 for ($i = $NumberCornerUWires; $i < $NumberSideUWires; ++$i)
918 $j = $i - $NumberCornerUWires;
919 my $ypos = $StartCommonUWires_ypos + $UWire_yint*($j);
922 if ( $ypos < $lastYpos ){ print "WARNING: y position dropped from $lastYpos (wire U$lastWnum) to $ypos (wire U$i)\n"; }
923 if ( $ypos == $lastYpos ){ print "WARNING: y position between wire U$lastWnum and U$lastWnum did not move: $ypos\n"; }
926 $pitch = ($ypos - $lastYpos) * $SinUAngle - ($zpos - $lastZpos) * $CosUAngle ;
930 <volumeref ref="volTPCWireUCommon${_[3]}"/>
931 <position name="pos${_[3]}WireU$i" unit="cm" x="0" y="$ypos " z="0"/>
932 <rotation name="rUAngle$i" unit="deg" x="90-$UAngle" y="0" z="0"/>
936 $topY = $ypos + ($CosUAngle*$CommonUWireLength/2);
937 $bottomY = $ypos - ($CosUAngle*$CommonUWireLength/2);
938 $edgeZ_p = + ($SinUAngle*$CommonUWireLength/2);
939 $edgeZ_m = - ($SinUAngle*$CommonUWireLength/2);
940 print $wout "U$i: ( $ypos , 0 ) (pitch = $pitch)\n";
941 print $wout " -- Y: $bottomY to $topY -- Z: $edgeZ_m to $edgeZ_p \n";
950 my $FirstTopUWire_zspan = $FirstTopUWire_yspan*$TanUAngle;
951 my $StartTopUWires_ypos = + $Uactive_y/2 - $FirstTopUWire_yspan/2;
952 my $StartTopUWires_zpos = - $Uactive_z/2 + $FirstTopUWire_zspan/2;
954 # Finally moving to the corner wires on the top right:
955 # x=0 to center the wires in the plane
956 # y positioning: plug wire number into same equation
957 # z positioning: start at z=0 and go negatively at the same z increment
958 # rotation: same as common wire in code above
959 # note that the counter maintains wire number shown in the position name
961 for ($j = $NumberSideUWires; $j < $NumberSideUWires+$NumberCornerUWires; ++$j)
964 $i = $j - $NumberSideUWires;
966 my $ypos = $StartTopUWires_ypos + ($i)*0.5*$UWire_yint;
967 my $zpos = $StartTopUWires_zpos - ($i)*0.5*$UWire_zint;
970 if ( $ypos < $lastYpos ){ print "WARNING: y position dropped from $lastYpos (wire U$lastWnum) to $ypos (wire U$j)\n"; }
971 if ( $ypos == $lastYpos ){ print "WARNING: y position between wire U$lastWnum and U$j did not move: $ypos\n"; }
973 $pitch = ($ypos - $lastYpos) * $SinUAngle - ($zpos - $lastZpos) * $CosUAngle ;
977 <volumeref ref="volTPCWireU$j${_[3]}"/>
978 <position name="pos${_[3]}WireU$j" unit="cm" x="0" y="$ypos " z="$zpos"/>
979 <rotation name="rUAngle$j" unit="deg" x="90-$UAngle" y="0" z="0"/>
983 $topY = $ypos + ($CosUAngle*$TopCornerUWireLength[$i]/2);
984 $bottomY = $ypos - ($CosUAngle*$TopCornerUWireLength[$i]/2);
985 $edgeZ_p = $zpos + ($SinUAngle*$TopCornerUWireLength[$i]/2);
986 $edgeZ_m = $zpos - ($SinUAngle*$TopCornerUWireLength[$i]/2);
987 print $wout "U$j: ( $ypos , $zpos ) (pitch = $pitch)\n";
988 print $wout " -- Y: $bottomY to $topY -- Z: $edgeZ_m to $edgeZ_p \n";
998 # ++++++++++++++++++++++ V Plane +++++++++++++++++++++++
1000 # End U plane and create V plane logical volume
1004 <volume name="volTPCPlaneV${_[3]}">
1005 <materialref ref="LAr"/>
1006 <solidref ref="${_[3]}VPlane"/>
1009 print $wout "\n- Wires for V plane -\n\n";
1010 print $wout " Vplane_y: $Vactive_y\n";
1011 print $wout " Vplane_z: $Vactive_z\n";
1017 # Starting with the bottom right corner wires:
1018 # x=0 to center the wires in the plane
1019 # y positioning: (-0.5*$TPCWirePlaneHeight) starts the incremental increase
1020 # from the bottom of the plane, and trigonometry gives the increment
1021 # z positioning: Looking at the plane from the positive x direction,
1022 # (-0.5*$TPCWirePlaneLength) starts the incremental increase from
1023 # the lower right corner.
1024 # rotation: same as common wire in code below
1026 $FirstV_ypos = - $Vactive_y/2 + $FirstVWireOffset/$TanVAngle/2;
1027 $FirstV_zpos = - $Vactive_z/2 + $FirstVWireOffset/2;
1029 for ($i = 0; $i < $NumberCornerVWires; ++$i)
1032 my $ypos = $FirstV_ypos + ($i)*0.5*$VWire_yint;
1033 my $zpos = $FirstV_zpos + ($i)*0.5*$VWire_zint;
1037 <volumeref ref="volTPCWireV$i${_[3]}"/>
1038 <position name="pos${_[3]}WireV$i" unit="cm" x="0" y="$ypos " z="$zpos"/>
1039 <rotation name="rVAngle$i" unit="deg" x="90+$VAngle" y="0" z="0"/>
1043 $topY = $ypos + ($CosVAngle*$CornerVWireLength[$i]/2);
1044 $bottomY = $ypos - ($CosVAngle*$CornerVWireLength[$i]/2);
1045 $edgeZ_p = $zpos + ($SinVAngle*$CornerVWireLength[$i]/2);
1046 $edgeZ_m = $zpos - ($SinVAngle*$CornerVWireLength[$i]/2);
1047 print $wout "V$i: ( $ypos , $zpos ) \n";
1048 print $wout " -- Y: $bottomY to $topY -- Z: $edgeZ_m to $edgeZ_p \n";
1056 # Moving upwards to the common wires:
1057 # x and z are zero to center the wires along a vertical axis
1058 # y positioning: Plug wire number into the same corner ypos equation
1059 # rotation: wires in //// direction, so +90deg to bring them to vertical and
1060 # --VAngle counterclockwise to arrive at proper orientation
1061 # Note that the counter maintains wire number in the position name
1063 my $StartCommonVWires_ypos = $lastYpos + $VWire_yint - abs( $lastZpos )/$TanVAngle;
1065 for ($i = $NumberCornerVWires; $i < $NumberSideVWires; ++$i)
1068 $j = $i - $NumberCornerVWires;
1069 my $ypos = $StartCommonVWires_ypos + $VWire_yint*($j);
1073 <volumeref ref="volTPCWireVCommon${_[3]}"/>
1074 <position name="pos${_[3]}WireV$i" unit="cm" x="0" y="$ypos " z="0"/>
1075 <rotation name="rVAngle$i" unit="deg" x="90+$VAngle" y="0" z="0"/>
1079 $topY = $ypos + ($CosVAngle*$CommonVWireLength/2);
1080 $bottomY = $ypos - ($CosVAngle*$CommonVWireLength/2);
1081 $edgeZ_p = + ($SinVAngle*$CommonVWireLength/2);
1082 $edgeZ_m = - ($SinVAngle*$CommonVWireLength/2);
1083 print $wout "V$i: ( $ypos , 0 ) \n";
1084 print $wout " -- Y: $bottomY to $topY -- Z: $edgeZ_m to $edgeZ_p \n";
1087 #$lastZpos = $zpos; always 0
1092 my $FirstTopVWire_zspan = $FirstTopVWire_yspan*$TanVAngle;
1093 my $StartTopVWires_ypos = + $Vactive_y/2 - $FirstTopVWire_yspan/2;
1094 my $StartTopVWires_zpos = + $Vactive_z/2 - $FirstTopVWire_zspan/2;
1096 # Finally moving to the corner wires on the top right:
1097 # x=0 to center the wires in the plane
1098 # y positioning: plug wire number into same equation
1099 # z positioning: start at z=0 and go positively at the same z increment
1100 # rotation: same as common wire in code above
1101 # note that the counter maintains wire number shown in the position name
1103 for ($j = $NumberSideVWires; $j < $NumberSideVWires+$NumberCornerVWires; ++$j)
1106 $i = $j - $NumberSideVWires;
1108 my $ypos = $StartTopVWires_ypos + ($i)*0.5*$VWire_yint;
1109 my $zpos = $StartTopVWires_zpos + ($i)*0.5*$VWire_zint;
1113 <volumeref ref="volTPCWireV$j${_[3]}"/>
1114 <position name="pos${_[3]}WireV$j" unit="cm" x="0" y="$ypos " z="$zpos"/>
1115 <rotation name="rVAngle$j" unit="deg" x="90+$VAngle" y="0" z="0"/>
1119 $topY = $ypos + ($CosVAngle*$TopCornerVWireLength[$i]/2);
1120 $bottomY = $ypos - ($CosVAngle*$TopCornerVWireLength[$i]/2);
1121 $edgeZ_p = $zpos + ($SinVAngle*$TopCornerVWireLength[$i]/2);
1122 $edgeZ_m = $zpos - ($SinVAngle*$TopCornerVWireLength[$i]/2);
1123 print $wout "V$j: ( $ypos , $zpos ) \n";
1124 print $wout " -- Y: $bottomY to $topY -- Z: $edgeZ_m to $edgeZ_p \n";
1137 # ++++++++++++++++++++++ Z Plane +++++++++++++++++++++++
1139 # End V plane and create Z plane logical volume
1143 <volume name="volTPCPlaneZ${_[3]}">
1144 <materialref ref="LAr"/>
1145 <solidref ref="${_[3]}ZPlane"/>
1151 # This is the simplest plane, one loop creates all of the wires
1152 # x and y position at zero to center the wires
1153 # z position: moving from front of detector to back, in the positive z direction,
1154 # starting at (-0.5*$TPCWirePlaneLength), the right side looking from
1157 for ($i=0; $i<$NumberVerticalWires; ++$i)
1159 my $zpos = (-0.5*$Zactive_z) + $i*$XWirePitch + $TPCWireThickness/2;
1163 <volumeref ref="volTPCWireVert${_[3]}"/>
1164 <position name="pos${_[3]}WireZ$i" unit="cm" x="0" y="0 " z="$zpos"/>
1165 <rotationref ref="rPlus90AboutX"/>
1177 #+++++++++++++++++++++ ^^ Position physical wires Above ^^ +++++++++++++++++++++
1179 ## make the TPC active volume extend down to the G10 for the grid
1181 my $BottomOfAPA = - $TPC_y/2 + $APAGap_y/2;
1184 $posZplane[0] = -$_[0]/2 + $APAWirePlaneSpacing - $TPCWirePlaneThickness/2;
1185 $posZplane[1] = $BottomOfAPA + $WrapCover + 4*$G10thickness + $Zactive_y/2;
1188 $posVplane[0] = $posZplane[0] + $APAWirePlaneSpacing;
1189 $posVplane[1] = $BottomOfAPA + $WrapCover + 3*$G10thickness + $Vactive_y/2;
1190 $posVplane[2] = $posZplane[2];
1192 $posUplane[0] = $posVplane[0] + $APAWirePlaneSpacing;
1193 $posUplane[1] = $BottomOfAPA + $WrapCover + 2*$G10thickness + $Uactive_y/2;
1194 $posUplane[2] = $posZplane[2];
1196 $posTPCActive[0] = $posUplane[0] + ($TPCWirePlaneThickness/2 + $TPCActive_x/2);
1197 $posTPCActive[1] = -$_[1]/2 + $TPCActive_y/2;
1198 $posTPCActive[2] = 0;
1200 #wrap up the TPC file
1202 <volume name="volTPC${_[3]}">
1203 <materialref ref="LAr"/>
1204 <solidref ref="${_[3]}"/>
1206 <volumeref ref="volTPCPlaneZ${_[3]}"/>
1207 <position name="pos${_[3]}PlaneZ" unit="cm"
1208 x="$posZplane[0]" y="$posZplane[1]" z="$posZplane[2]"/>
1209 <rotationref ref="rIdentity"/>
1212 <volumeref ref="volTPCPlaneV${_[3]}"/>
1213 <position name="pos${_[3]}PlaneV" unit="cm"
1214 x="$posVplane[0]" y="$posVplane[1]" z="$posVplane[2]"/>
1215 <rotationref ref="rIdentity"/>
1218 <volumeref ref="volTPCPlaneU${_[3]}"/>
1219 <position name="pos${_[3]}PlaneU" unit="cm"
1220 x="$posUplane[0]" y="$posUplane[1]" z="$posUplane[2]"/>
1221 <rotationref ref="rIdentity"/>
1225 # Option to omit the active volume on the outside for the prototype.
1226 if( !($killOuterActive==1 && $_[3] eq 'Outer') ){
1229 <volumeref ref="volTPCActive${_[3]}"/>
1230 <position name="pos${_[3]}Active" unit="cm"
1231 x="$posTPCActive[0]" y="$posTPCActive[1]" z="$posTPCActive[2]"/>
1232 <rotationref ref="rIdentity"/>
1245 } #end of sub gen_TPC
1249 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1250 #++++++++++++++++++++++++++++++++++++++ gen_Cryostat +++++++++++++++++++++++++++++++++++++
1251 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1256 # Create the cryostat fragment file name,
1257 # add file to list of output GDML fragments,
1259 $CRYO = "dune10kt_v1_Cryostat" . $suffix . ".gdml";
1260 push (@gdmlFiles, $CRYO);
1261 $CRYO = ">" . $CRYO;
1262 open(CRYO) or die("Could not open file $CRYO for writing");
1265 # The standard XML prefix and starting the gdml
1267 <?xml version='1.0'?>
1271 $APAFrameZSide_x = $APAFrame_x;
1272 $APAFrameZSide_y = 4*$inch;
1273 $APAFrameZSide_z = $APAFrame_z;
1275 $APAFrameYSide_x = $APAFrame_x;
1276 $APAFrameYSide_y = $APAFrame_y-2*$APAFrameZSide_y;
1277 $APAFrameYSide_z = 4*$inch;
1279 # Two outer Y supports will sandwich the light paddles
1280 $APAFrameYOuterSupport_x = ($APAFrame_x-$LightPaddle_x)/2;
1281 $APAFrameYOuterSupport_y = $APAFrame_y-2*$APAFrameZSide_y;
1282 $APAFrameYOuterSupport_z = 4*$inch;
1284 $EdgeFrameSteelThickness = 0.12*$inch;
1285 $InnerFrameSteelThickness = 0.062*$inch;
1288 $G10BoardYSide_x = $APAFrame_x;
1289 $G10BoardYSide_y = $APAFrame_y;
1290 $G10BoardYSide_z = $G10thickness;
1292 $G10BoardZSide_x = $APAFrame_x;
1293 $G10BoardZSide_y = $G10thickness;
1294 $G10BoardZSide_z = $APAFrame_z;
1297 # All the cryostat solids.
1300 <box name="Cryostat" lunit="cm"
1304 <box name="ArgonInterior" lunit="cm"
1308 <box name="GaseousArgon" lunit="cm"
1310 y="$HeightGaseousAr"
1312 <subtraction name="SteelShell">
1313 <first ref="Cryostat"/>
1314 <second ref="ArgonInterior"/>
1317 <box name="Cathode" lunit="cm"
1322 <box name="LightPaddle" lunit="cm"
1325 z="$LightPaddle_z + $SiPM_z"/>
1327 <box name="APAFrameYSideHollow" lunit="cm"
1328 x="$APAFrameYSide_x-2*$EdgeFrameSteelThickness"
1329 y="$APAFrameYSide_y-2*$EdgeFrameSteelThickness"
1330 z="$APAFrameYSide_z"/>
1331 <box name="APAFrameYSideShell" lunit="cm"
1332 x="$APAFrameYSide_x"
1333 y="$APAFrameYSide_y"
1334 z="$APAFrameYSide_z"/>
1335 <subtraction name="APAFrameYSide">
1336 <first ref="APAFrameYSideShell"/>
1337 <second ref="APAFrameYSideHollow"/>
1338 <positionref ref="posCenter"/>
1339 <rotationref ref="rIdentity"/>
1342 <box name="APAFrameZSideHollow" lunit="cm"
1343 x="$APAFrameZSide_x-2*$EdgeFrameSteelThickness"
1344 y="$APAFrameZSide_y-2*$EdgeFrameSteelThickness"
1345 z="$APAFrameZSide_z"/>
1346 <box name="APAFrameZSideShell" lunit="cm"
1347 x="$APAFrameZSide_x"
1348 y="$APAFrameZSide_y"
1349 z="$APAFrameZSide_z"/>
1350 <subtraction name="APAFrameZSide">
1351 <first ref="APAFrameZSideShell"/>
1352 <second ref="APAFrameZSideHollow"/>
1353 <positionref ref="posCenter"/>
1354 <rotationref ref="rIdentity"/>
1357 <box name="APAFrameYOuterSupport" lunit="cm"
1358 x="$EdgeFrameSteelThickness"
1359 y="$APAFrameYOuterSupport_y"
1360 z="$APAFrameYOuterSupport_z"/>
1363 <box name="G10BoardYSideCenterSeg" lunit="cm"
1364 x="$G10BoardYSide_x"
1365 y="$G10BoardYSide_y"
1366 z="$G10BoardYSide_z"/>
1368 <box name="G10BoardZSideCenterSeg" lunit="cm"
1369 x="$G10BoardZSide_x"
1370 y="$G10BoardZSide_y"
1371 z="$G10BoardZSide_z"/>
1376 # Cryostat structure
1379 <volume name="volSteelShell">
1380 <materialref ref="STEEL_STAINLESS_Fe7Cr2Ni" />
1381 <solidref ref="SteelShell" />
1383 <volume name="volGaseousArgon">
1384 <materialref ref="ArGas"/>
1385 <solidref ref="GaseousArgon"/>
1388 <volume name="volCathode">
1389 <materialref ref="STEEL_STAINLESS_Fe7Cr2Ni" />
1390 <solidref ref="Cathode" />
1394 for($i=0 ; $i<$nAPAs ; $i++){
1395 for($p=0 ; $p<10 ; $p++){
1397 <volume name="volOpDetSensitive_$i\-$p">
1398 <materialref ref="Acrylic"/>
1399 <solidref ref="LightPaddle"/>
1408 <volume name="volAPAFrameYSide">
1409 <materialref ref="STEEL_STAINLESS_Fe7Cr2Ni"/>
1410 <solidref ref="APAFrameYSide"/>
1413 <volume name="volAPAFrameZSide">
1414 <materialref ref="STEEL_STAINLESS_Fe7Cr2Ni"/>
1415 <solidref ref="APAFrameZSide"/>
1418 <volume name="volAPAFrameYOuterSupport">
1419 <materialref ref="STEEL_STAINLESS_Fe7Cr2Ni"/>
1420 <solidref ref="APAFrameYOuterSupport"/>
1423 <volume name="volG10BoardYSideCenterSeg">
1424 <materialref ref="G10"/>
1425 <solidref ref="G10BoardYSideCenterSeg"/>
1428 <volume name="volG10BoardZSideCenterSeg">
1429 <materialref ref="G10"/>
1430 <solidref ref="G10BoardZSideCenterSeg"/>
1433 <volume name="volCryostat">
1434 <materialref ref="LAr" />
1435 <solidref ref="Cryostat" />
1437 <volumeref ref="volGaseousArgon"/>
1438 <position name="posGaseousArgon" unit="cm" x="0" y="$Argon_y/2-$HeightGaseousAr/2" z="0"/>
1441 <volumeref ref="volSteelShell"/>
1442 <position name="posSteelShell" unit="cm" x="0" y="0" z="0"/>
1446 # nested for loops to place the non-rotated AND rotated volTPC
1447 # x loop rotation: There are six drift volumes. Looking into the
1448 # detector from incident direction, and counting from right (-x) to
1449 # left (+x), odd number volumes need to be rotated 180deg about Y in
1450 # order for the cathode to be on the right of the APA.
1457 for($k=0 ; $k<$nAPALong ; $k++)
1459 $APACenter_z = - $Argon_z/2
1460 + $UpstreamLArPadding
1462 + $k*($APAphys_z+$APAGap_z);
1465 for($j=0 ; $j<$nAPAHigh ; $j++) # nAPAHigh always going to be 2
1466 { # $j=0 for bottom APAs
1468 $APACenter_y = - $Argon_y/2 + $SpaceAPAToFloor
1470 + $j*($APAphys_y+$APAGap_y);
1473 if( $workspace == 0 )
1476 for($i=0 ; $i<$nAPAWide ; $i++)
1480 $APACenter_x = - $Argon_x/2
1481 + $SpaceAPAToCryoWall + $APA_UtoU_x/2 + $TPCWirePlaneThickness/2
1484 $CPA_x = $APACenter_x + $CPAToAPA;
1487 place_APA($APACenter_x, $APACenter_y, $APACenter_z, $apa_i, $j);
1488 place_OpDets($APACenter_x, $APACenter_y, $APACenter_z, $apa_i);
1489 $tpc_0 = 2*$apa_i+0;
1490 $tpc_1 = 2*$apa_i+1;
1493 $SelectTPC_0 = "Inner";
1494 $SelectTPC_1 = "Inner";
1495 $TPC_0_x = $TPCInner_x;
1496 $TPC_1_x = $TPCInner_x;
1497 $rot_0 = "rPlus180AboutY";
1498 $rot_1 = "rIdentity";
1499 if($i == 0) { $SelectTPC_0 = "Outer"; $TPC_0_x = $TPCOuter_x; }
1500 if($i == $nAPAWide-1) { $SelectTPC_1 = "Outer"; $TPC_1_x = $TPCOuter_x; }
1501 if($j == 0) { $rot_0 = "rPlus180AboutXPlus180AboutY";
1502 $rot_1 = "rPlus180AboutX"; } #put the readout end at the bottom for bottom APAs
1509 <volumeref ref="volTPC$SelectTPC_0"/>
1510 <position name="posTPC\-$tpc_0" unit="cm"
1511 x="$APACenter_x - $APAFrame_x/2 - $TPC_0_x/2"
1514 <rotationref ref="$rot_0"/>
1517 <volumeref ref="volTPC$SelectTPC_1"/>
1518 <position name="posTPC\-$tpc_1" unit="cm"
1519 x="$APACenter_x + $APAFrame_x/2 + $TPC_1_x/2"
1522 <rotationref ref="$rot_1"/>
1528 if( $i < $nAPAWide - 1 ){ # avoid placeing the last row of CPAs since the APAs are on the outside
1533 <volumeref ref="volCathode"/>
1534 <position name="posCathode\-$cpa_i" unit="cm"
1538 <rotationref ref="rIdentity"/>
1548 } # end if not the smaller workspace
1551 # Make the workspace have only one center APA with CPAs and the full drift on either side
1552 elsif( $workspace == 1 || $workspace==2 ){
1555 $CPA_0_x = $APACenter_x - $CPAToAPA;
1556 $CPA_1_x = $APACenter_x + $CPAToAPA;
1559 place_APA($APACenter_x, $APACenter_y, $APACenter_z, $apa_i, $j);
1560 place_OpDets($APACenter_x, $APACenter_y, $APACenter_z, $apa_i);
1562 $tpc_0 = 2*$apa_i+0;
1563 $tpc_1 = 2*$apa_i+1;
1566 $rot_0 = "rPlus180AboutY";
1567 $rot_1 = "rIdentity";
1568 if($j == 0) { $rot_0 = "rPlus180AboutXPlus180AboutY";
1569 $rot_1 = "rPlus180AboutX"; } #put the readout end at the bottom for bottom APAs
1574 <volumeref ref="volTPCInner"/>
1575 <position name="posTPC\-$tpc_0" unit="cm"
1576 x="$APACenter_x - $APAFrame_x/2 - $TPCInner_x/2"
1579 <rotationref ref="$rot_0"/>
1582 <volumeref ref="volTPCInner"/>
1583 <position name="posTPC\-$tpc_1" unit="cm"
1584 x="$APACenter_x + $APAFrame_x/2 + $TPCInner_x/2"
1587 <rotationref ref="$rot_1"/>
1591 <volumeref ref="volCathode"/>
1592 <position name="posCathode\-$apa_i-0" unit="cm"
1596 <rotationref ref="rIdentity"/>
1599 <volumeref ref="volCathode"/>
1600 <position name="posCathode\-$apa_i-1" unit="cm"
1604 <rotationref ref="rIdentity"/>
1609 } # if the smaller workspace
1628 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1629 #++++++++++++++++++++++++++++++++++++ place_OpDets +++++++++++++++++++++++++++++++++++++++
1630 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1635 $APACenter_x = $_[0];
1636 $APACenter_y = $_[1];
1637 $APACenter_z = $_[2];
1640 for ($paddle = 0; $paddle<$nLightPaddlesPerAPA; $paddle++)
1643 # All Light Paddle centers will have the same
1644 # X coordinate as the center of the current APA
1645 # Z coordinate as the current TPC pair
1646 # The Y coordinate must be looped over:
1648 #the multiplication by j here is a temporary dirty trick to get around some strange behavior
1650 $Paddle_Y = $APACenter_y
1652 + $j*$FrameToPaddleSpace
1653 + (1-$j)*($LightPaddle_y/2 + $APAFrameZSide_y)
1654 + $PaddleYInterval*$paddle;
1656 # Alternate the paddle orientations
1657 if ( $paddle % 2 == 0 ) { $rot = "rIdentity"; }
1658 else { $rot = "rPlus180AboutY"; }
1663 <volumeref ref="volOpDetSensitive_$apa_i\-$paddle"/>
1664 <position name="posPaddle\-$paddle\-TPC\-$i\-$j\-$k" unit="cm"
1667 z="$APACenter_z + $SiPM_z/2"/>
1668 <rotationref ref="$rot"/>
1672 }#end Paddle for-loop
1678 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1679 #++++++++++++++++++++++++++++++++++++++ place_APA ++++++++++++++++++++++++++++++++++++++++
1680 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1683 # Must be called only within gen_Cryostat(),
1686 # $_[0] = x APA physical center
1687 # $_[1] = y APA physical center
1688 # $_[2] = z APA physical center
1689 # $_[3] = APA number
1690 # $_[4] = 0 for APA with readout on bottom
1691 # 1 for APA with readout on top
1698 ####################################################################
1699 ################# APA Frame and Paddle Dimensions ##################
1701 # The center passed to this function is the physical APA center,
1702 # which is not quite the frame's center, since there are more boards
1703 # at the bottom. Transform them:
1705 $APAFrameCenter_x = $_[0];
1706 $APAFrameCenter_z = $_[2];
1708 # The bottom APAs are upside down relative to how the TPC is initially generated,
1709 # and the center needs to be slightly shifted since there is extra G10 on the
1710 # end that doesn't read out.
1712 if($_[4]==1) # top APAs
1714 $APAFrameCenter_y = $_[1] - $APAphys_y/2
1715 + $WrapCover + 4*$G10thickness
1718 elsif($_[4]==0) # bottom APAs
1720 $APAFrameCenter_y = $_[1] + $APAphys_y/2
1721 - $WrapCover - 4*$G10thickness
1724 else{ print "APA not labeled as top or bottom"; }
1726 $APAFrameZSide_x = $APAFrame_x;
1727 $APAFrameZSide_y = 4*$inch;
1728 $APAFrameZSide_z = $APAFrame_z;
1730 $APAFrameYSide_x = $APAFrame_x;
1731 $APAFrameYSide_y = $APAFrame_y-2*$APAFrameZSide_y;
1732 $APAFrameYSide_z = 4*$inch;
1734 # Two outer Y supports will sandwich the light paddles
1735 $APAFrameYOuterSupport_x = ($APAFrame_x-$LightPaddle_x)/2;
1736 $APAFrameYOuterSupport_y = $APAFrame_y-2*$APAFrameZSide_y;
1737 $APAFrameYOuterSupport_z = 4*$inch;
1739 # if there were an inner support to fill the hole
1740 $APAFrameYInnerSupport_x = $LightPaddle_x;
1742 $EdgeFrameSteelThickness = 0.12*$inch;
1743 $InnerFrameSteelThickness = 0.062*$inch;
1746 $G10BoardYSide_x = $APAFrame_x;
1747 $G10BoardYSide_y = $APAFrame_y;
1748 $G10BoardYSide_z = $G10thickness;
1750 $G10BoardZSide_x = $APAFrame_x;
1751 $G10BoardZSide_y = $G10thickness;
1752 $G10BoardZSide_z = $APAFrame_z;
1754 if($_[4]==1) # top APAs
1756 $posG10ZSideZ_y = $APAFrameCenter_y - $APAFrame_y/2 - (0+.5)*($G10BoardZSide_y);
1757 $posG10ZSideV_y = $APAFrameCenter_y - $APAFrame_y/2 - (1+.5)*($G10BoardZSide_y);
1758 $posG10ZSideU_y = $APAFrameCenter_y - $APAFrame_y/2 - (2+.5)*($G10BoardZSide_y);
1759 $posG10ZSideGrid_y = $APAFrameCenter_y - $APAFrame_y/2 - (3+.5)*($G10BoardZSide_y);
1761 elsif($_[4]==0) # bottom APAs
1763 $posG10ZSideZ_y = $APAFrameCenter_y + $APAFrame_y/2 + (0+.5)*($G10BoardZSide_y);
1764 $posG10ZSideV_y = $APAFrameCenter_y + $APAFrame_y/2 + (1+.5)*($G10BoardZSide_y);
1765 $posG10ZSideU_y = $APAFrameCenter_y + $APAFrame_y/2 + (2+.5)*($G10BoardZSide_y);
1766 $posG10ZSideGrid_y = $APAFrameCenter_y + $APAFrame_y/2 + (3+.5)*($G10BoardZSide_y);
1768 else{ print "APA not labeled as top or bottom"; }
1770 # First put in the frame
1774 # <volumeref ref="volAPAFrameYOuterSupport\-$APA_i"/>
1775 # <position name="posAPAFrameYOuterSupportNeg\-$APA_i" unit="cm"
1776 # x="$APAFrameCenter_x - ($APAFrameYOuterSupport_x + $APAFrameYInnerSupport_x/2 - $EdgeFrameSteelThickness/2)"
1777 # y="$APAFrameCenter_y"
1778 # z="$APAFrameCenter_z"/>
1779 # <rotationref ref="rIdentity"/>
1782 # <volumeref ref="volAPAFrameYOuterSupport\-$APA_i"/>
1783 # <position name="posAPAFrameYOuterSupportPos\-$APA_i" unit="cm"
1784 # x="$APAFrameCenter_x + ($APAFrameYOuterSupport_x + $APAFrameYInnerSupport_x/2 - $EdgeFrameSteelThickness/2)"
1785 # y="$APAFrameCenter_y"
1786 # z="$APAFrameCenter_z"/>
1787 # <rotationref ref="rIdentity"/>
1793 <volumeref ref="volAPAFrameYSide"/>
1794 <position name="posAPAFrameYSideNeg\-$APA_i" unit="cm"
1795 x="$APAFrameCenter_x"
1796 y="$APAFrameCenter_y"
1797 z="$APAFrameCenter_z - $APAFrame_z/2 + $APAFrameYSide_z/2"/>
1798 <rotationref ref="rIdentity"/>
1801 <volumeref ref="volAPAFrameYSide"/>
1802 <position name="posAPAFrameYSidePos\-$APA_i" unit="cm"
1803 x="$APAFrameCenter_x"
1804 y="$APAFrameCenter_y"
1805 z="$APAFrameCenter_z + $APAFrame_z/2 - $APAFrameYSide_z/2"/>
1806 <rotationref ref="rIdentity"/>
1809 <volumeref ref="volAPAFrameZSide"/>
1810 <position name="posAPAFrameZSidePos\-$APA_i" unit="cm"
1811 x="$APAFrameCenter_x"
1812 y="$APAFrameCenter_y + $APAFrame_y/2 - $APAFrameZSide_y/2"
1813 z="$APAFrameCenter_z"/>
1814 <rotationref ref="rIdentity"/>
1817 <volumeref ref="volAPAFrameZSide"/>
1818 <position name="posAPAFrameZSideNeg\-$APA_i" unit="cm"
1819 x="$APAFrameCenter_x"
1820 y="$APAFrameCenter_y - $APAFrame_y/2 + $APAFrameZSide_y/2"
1821 z="$APAFrameCenter_z"/>
1822 <rotationref ref="rIdentity"/>
1826 <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1827 - Add the *parts* of the G10 boards that exist directly in volCryostat.
1828 - There are two boards on each the up and downstream end,
1829 one each to wrap the U and V views around the APA frame
1830 - There are 4 on the bottom which anchor the U V and Z wires and the grid plane
1831 - The rest of the parts of the G10 boards must be placed directly in volTPC -->
1834 <volumeref ref="volG10BoardYSideCenterSeg"/>
1835 <position name="posG10BoardYSideCenterSeg\-Vup\-$APA_i" unit="cm"
1836 x="$APAFrameCenter_x"
1837 y="$APAFrameCenter_y"
1838 z="$APAFrameCenter_z - $APAFrame_z/2 - (0+.5)*($G10BoardYSide_z)"/>
1839 <rotationref ref="rIdentity"/>
1842 <volumeref ref="volG10BoardYSideCenterSeg"/>
1843 <position name="posG10BoardYSideCenterSeg\-Uup\-$APA_i" unit="cm"
1844 x="$APAFrameCenter_x"
1845 y="$APAFrameCenter_y"
1846 z="$APAFrameCenter_z - $APAFrame_z/2 - (1+.5)*($G10BoardYSide_z)"/>
1847 <rotationref ref="rIdentity"/>
1851 <volumeref ref="volG10BoardYSideCenterSeg"/>
1852 <position name="posG10BoardYSideCenterSeg\-Vdown\-$APA_i" unit="cm"
1853 x="$APAFrameCenter_x"
1854 y="$APAFrameCenter_y"
1855 z="$APAFrameCenter_z + $APAFrame_z/2 + (0+.5)*($G10BoardYSide_z)"/>
1856 <rotationref ref="rIdentity"/>
1859 <volumeref ref="volG10BoardYSideCenterSeg"/>
1860 <position name="posG10BoardYSideCenterSeg\-Udown\-$APA_i" unit="cm"
1861 x="$APAFrameCenter_x"
1862 y="$APAFrameCenter_y"
1863 z="$APAFrameCenter_z + $APAFrame_z/2 + (1+.5)*($G10BoardYSide_z)"/>
1864 <rotationref ref="rIdentity"/>
1868 <volumeref ref="volG10BoardZSideCenterSeg"/>
1869 <position name="posG10BoardZSideCenterSeg\-Z\-$APA_i" unit="cm"
1870 x="$APAFrameCenter_x"
1872 z="$APAFrameCenter_z"/>
1873 <rotationref ref="rIdentity"/>
1876 <volumeref ref="volG10BoardZSideCenterSeg"/>
1877 <position name="posG10BoardZSideCenterSeg\-V\-$APA_i" unit="cm"
1878 x="$APAFrameCenter_x"
1880 z="$APAFrameCenter_z"/>
1881 <rotationref ref="rIdentity"/>
1884 <volumeref ref="volG10BoardZSideCenterSeg"/>
1885 <position name="posG10BoardZSideCenterSeg\-U\-$APA_i" unit="cm"
1886 x="$APAFrameCenter_x"
1888 z="$APAFrameCenter_z"/>
1889 <rotationref ref="rIdentity"/>
1892 <volumeref ref="volG10BoardZSideCenterSeg"/>
1893 <position name="posG10BoardZSideCenterSeg\-Grid\-$APA_i" unit="cm"
1894 x="$APAFrameCenter_x"
1895 y="$posG10ZSideGrid_y"
1896 z="$APAFrameCenter_z"/>
1897 <rotationref ref="rIdentity"/>
1908 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1909 #+++++++++++++++++++++++++++++++++++++ gen_Enclosure +++++++++++++++++++++++++++++++++++++
1910 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1915 # Create the detector enclosure fragment file name,
1916 # add file to list of output GDML fragments,
1918 $ENCL = "dune10kt_v1_DetEnclosure" . $suffix . ".gdml";
1919 push (@gdmlFiles, $ENCL);
1920 $ENCL = ">" . $ENCL;
1921 open(ENCL) or die("Could not open file $ENCL for writing");
1924 # The standard XML prefix and starting the gdml
1926 <?xml version='1.0'?>
1931 # All the detector enclosure solids.
1935 <box name="FoamPadBlock" lunit="cm"
1936 x="$Cryostat_x + 2*$FoamPadding"
1937 y="$Cryostat_y + 2*$FoamPadding"
1938 z="$Cryostat_z + 2*$FoamPadding" />
1940 <box name="FoamPadInner" lunit="cm"
1941 x="$Cryostat_x + 0.01"
1942 y="$Cryostat_y + 0.01"
1943 z="$Cryostat_z + 0.01" />
1945 <subtraction name="FoamPadding">
1946 <first ref="FoamPadBlock"/>
1947 <second ref="FoamPadInner"/>
1948 <positionref ref="posCenter"/>
1951 <box name="SteelSupportBlock" lunit="cm"
1952 x="$Cryostat_x + 2*$FoamPadding + 2*$SteelSupport_x"
1953 y="$Cryostat_y + 2*$FoamPadding + 2*$SteelSupport_y"
1954 z="$Cryostat_z + 2*$FoamPadding + 2*$SteelSupport_z" />
1956 <box name="SteelSupportInner" lunit="cm"
1957 x="$Cryostat_x + 2*$FoamPadding + 0.01"
1958 y="$Cryostat_y + 2*$FoamPadding + 0.01"
1959 z="$Cryostat_z + 2*$FoamPadding + 0.01" />
1961 <subtraction name="SteelSupport">
1962 <first ref="SteelSupportBlock"/>
1963 <second ref="SteelSupportInner"/>
1964 <positionref ref="posCenter"/>
1967 <box name="DetEnclosure" lunit="cm"
1977 # Detector enclosure structure
1980 <volume name="volFoamPadding">
1981 <materialref ref="FD_foam"/>
1982 <solidref ref="FoamPadding"/>
1985 <volume name="volSteelSupport">
1986 <materialref ref="AirSteelMixture"/>
1987 <solidref ref="SteelSupport"/>
1990 <volume name="volDetEnclosure">
1991 <materialref ref="Air"/>
1992 <solidref ref="DetEnclosure"/>
1995 <volumeref ref="volFoamPadding"/>
1996 <positionref ref="posCryoInDetEnc"/>
1999 <volumeref ref="volSteelSupport"/>
2000 <positionref ref="posCryoInDetEnc"/>
2003 <volumeref ref="volCryostat"/>
2004 <positionref ref="posCryoInDetEnc"/>
2023 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2024 #+++++++++++++++++++++++++++++++++++++++ gen_World +++++++++++++++++++++++++++++++++++++++
2025 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2030 # Create the WORLD fragment file name,
2031 # add file to list of output GDML fragments,
2033 $WORLD = "dune10kt_v1_World" . $suffix . ".gdml";
2034 push (@gdmlFiles, $WORLD);
2035 $WORLD = ">" . $WORLD;
2036 open(WORLD) or die("Could not open file $WORLD for writing");
2039 # The standard XML prefix and starting the gdml
2041 <?xml version='1.0'?>
2046 # All the World solids.
2049 <box name="World" lunit="cm"
2050 x="$DetEncWidth+2*$RockThickness"
2051 y="$DetEncHeight+2*$RockThickness"
2052 z="$DetEncLength+2*$RockThickness"/>
2059 <volume name="volWorld" >
2060 <materialref ref="DUSEL_Rock"/>
2061 <solidref ref="World"/>
2064 <volumeref ref="volDetEnclosure"/>
2065 <position name="posDetEnclosure" unit="cm" x="$OriginXSet" y="$OriginYSet" z="$OriginZSet"/>
2073 # make_gdml.pl will take care of <setup/>
2080 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2081 #++++++++++++++++++++++++++++++++++++ write_fragments ++++++++++++++++++++++++++++++++++++
2082 #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2084 sub write_fragments()
2086 # This subroutine creates an XML file that summarizes the the subfiles output
2087 # by the other sub routines - it is the input file for make_gdml.pl which will
2088 # give the final desired GDML file. Specify its name with the output option.
2089 # (you can change the name when running make_gdml)
2091 # This code is taken straigh from the similar MicroBooNE generate script, Thank you.
2093 if ( ! defined $output )
2095 $output = "-"; # write to STDOUT
2098 # Set up the output file.
2099 $OUTPUT = ">" . $output;
2100 open(OUTPUT) or die("Could not open file $OUTPUT");
2103 <?xml version='1.0'?>
2105 <!-- Input to Geometry/gdml/make_gdml.pl; define the GDML fragments
2106 that will be zipped together to create a detector description.
2113 <!-- These files contain GDML <constant></constant>
2114 blocks. They are read in separately, so they can be
2115 interpreted into the remaining GDML. See make_gdml.pl for
2121 foreach $filename (@defFiles)
2124 <filename> $filename </filename>
2134 <!-- The GDML file fragments to be zipped together. -->
2138 foreach $filename (@gdmlFiles)
2141 <filename> $filename </filename>
2157 # run the sub routines that generate the fragments
2159 gen_Define(); # generates definitions at beginning of GDML
2160 gen_Materials(); # generates materials to be used
2163 gen_TPC( $TPCInner_x, $TPC_y, $TPC_z, 'Inner');
2164 gen_TPC( $TPCOuter_x, $TPC_y, $TPC_z, 'Outer');
2168 gen_Cryostat(); # places (2*nAPAWide x nAPAHigh x nAPALong) volTPC,
2169 # half rotated 180 about Y
2170 gen_Enclosure(); # places two cryostats and concrete volumes
2172 gen_World(); # places the enclosure among DUSEL Rock
2175 write_fragments(); # writes the XML input for make_gdml.pl
2176 # which zips together the final GDML