WCSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
WCSimConstructCylinder.cc
Go to the documentation of this file.
1 // -*- mode:c++; tab-width:4; -*-
3 
4 #include "G4Material.hh"
5 #include "G4Element.hh"
6 #include "G4Box.hh"
7 #include "G4Tubs.hh"
8 #include "G4UnionSolid.hh"
9 #include "G4Sphere.hh"
10 #include "G4Trd.hh"
11 #include "G4IntersectionSolid.hh"
12 #include "G4Polyhedra.hh"
13 #include "G4LogicalVolume.hh"
14 #include "G4ThreeVector.hh"
15 #include "G4RotationMatrix.hh"
16 #include "G4PVReplica.hh"
17 #include "G4PVPlacement.hh"
18 #include "G4PVParameterised.hh"
19 #include "G4AssemblyVolume.hh"
20 #include "G4SubtractionSolid.hh"
21 #include "globals.hh"
22 #include "G4VisAttributes.hh"
23 #include "G4LogicalBorderSurface.hh"
24 #include "G4LogicalSkinSurface.hh"
25 #include "G4OpBoundaryProcess.hh"
26 #include "G4OpticalSurface.hh"
27 #include "G4UserLimits.hh"
28 #include "G4ReflectionFactory.hh"
29 #include "G4GeometryTolerance.hh"
30 #include "G4GeometryManager.hh"
31 
32 #include "WCSimTuningParameters.hh" //jl145
33 
34 #include "G4SystemOfUnits.hh"
35 #include "G4PhysicalConstants.hh"
36 
37 /***********************************************************
38  *
39  * This file containts the functions which construct a
40  * cylindrical WC detector. It used by both the SK and
41  * LBNE WC detector modes. It is called in the Construct()
42  * method in WCSimDetectorConstruction.cc.
43  *
44  * Sourcefile for the WCSimDetectorConstruction class
45  *
46  ***********************************************************/
47 
48 //-----------------------------------------------------
49 // Defining colors used for debugging geom
50 //-----------------------------------------------------
51 
52 G4Colour white (1.0, 1.0, 1.0) ; // white
53 G4Colour black (0.0, 0.0, 0.0) ; // black
54 G4Colour red (1.0, 0.0, 0.0) ; // red
55 G4Colour green (0.0, 1.0, 0.0) ; // green
56 G4Colour blue (0.0, 0.0, 1.0) ; // blue
57 G4Colour cyan (0.0, 1.0, 1.0) ; // cyan
58 G4Colour magenta (1.0, 0.0, 1.0) ; // magenta
59 G4Colour yellow (1.0, 1.0, 0.0) ; // yellow
60 
61 //-----------------------------------------------------
62 //-----------------------------------------------------
63 
65 {
66  G4cout << "**** Building Cylindrical Detector ****" << G4endl;
67 
68  //-----------------------------------------------------
69  // Positions
70  //-----------------------------------------------------
71 
72  debugMode = false;
73 
74  WCPosition=0.;//Set the WC tube offset to zero
75 
77  // the number of regular cell in phi direction:
79  // the part of one ring, that is covered by the regular cells:
81  // angle per regular cell:
83  // it's hight:
85  // the hight of all regular cells together:
87 
88 
90  outerAnnulusRadius = WCIDRadius + WCBlackSheetThickness + 1.*mm;//+ Stealstructure etc.
91  if(isODConstructed)
93  // the radii are measured to the center of the surfaces
94  // (tangent distance). Thus distances between the corner and the center are bigger.
95  WCLength = WCIDHeight + 2*2.3*m; //jl145 - reflects top veto blueprint, cf. Farshid Feyzi
96  WCRadius = (WCIDDiameter/2. + WCBlackSheetThickness + 1.5*m)/cos(dPhi/2.) ; // TODO: OD
97  if(isODConstructed){
100  }
101 
102  // now we know the extend of the detector and are able to tune the tolerance
103  G4GeometryManager::GetInstance()->SetWorldMaximumExtent(WCLength > WCRadius ? WCLength : WCRadius);
104  G4cout << "Computed tolerance = "
105  << G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/mm
106  << " mm" << G4endl;
107 
108  //Decide if adding Gd
109  water = "Water";
110  if (WCAddGd)
111  {water = "Doped Water";}
112 
113 
114  //-----------------------------------------------------
115  // Volumes
116  //-----------------------------------------------------
117 
118  // The water barrel is placed in an tubs of air
119 
120  G4Tubs* solidWC = new G4Tubs("WC",
121  0.0*m,
122  WCRadius+2.*m,
123  .5*WCLength+4.2*m, //jl145 - per blueprint
124  0.*deg,
125  360.*deg);
126 
127  G4LogicalVolume* logicWC =
128  new G4LogicalVolume(solidWC,
129  G4Material::GetMaterial("Air"),
130  "WC",
131  0,0,0);
132 
133 
134  G4VisAttributes* showColor = new G4VisAttributes(G4Colour(0.0,1.0,0.0));
135  logicWC->SetVisAttributes(showColor);
136 
137  logicWC->SetVisAttributes(G4VisAttributes::Invisible); //amb79
138 
139  //-----------------------------------------------------
140  // everything else is contained in this water tubs
141  //-----------------------------------------------------
142  G4Tubs* solidWCBarrel = new G4Tubs("WCBarrel",
143  0.0*m,
144  WCRadius+1.*m, // add a bit of extra space
145  .5*WCLength, //jl145 - per blueprint
146  0.*deg,
147  360.*deg);
148 
149  G4LogicalVolume* logicWCBarrel =
150  new G4LogicalVolume(solidWCBarrel,
151  G4Material::GetMaterial(water),
152  "WCBarrel",
153  0,0,0);
154 
155  G4VPhysicalVolume* physiWCBarrel =
156  new G4PVPlacement(0,
157  G4ThreeVector(0.,0.,0.),
158  logicWCBarrel,
159  "WCBarrel",
160  logicWC,
161  false,
162  0);
163 
164  if(isODConstructed) {
165  //-----------------------------------------------------
166  // Cylinder wall's tyvek
167  //-----------------------------------------------------
168 
169  G4Tubs *solidCaveTyvek = new G4Tubs("WC",
170  WCRadius,
171  WCRadius + WCODTyvekSheetThickness,
172  .5 * WCLength, //jl145 - per blueprint
173  0. * deg,
174  360. * deg);
175 
176  G4LogicalVolume *logicCaveTyvek =
177  new G4LogicalVolume(solidCaveTyvek,
178  G4Material::GetMaterial("Tyvek"),
179  "CaveTyvek",
180  0, 0, 0);
181 
182  G4VPhysicalVolume *physiCaveTyvek =
183  new G4PVPlacement(0,
184  G4ThreeVector(0., 0., 0.),
185  logicCaveTyvek,
186  "CaveBarrelTyvek",
187  logicWCBarrel,
188  false,
189  0);
190 
191  G4LogicalSkinSurface *TyvekCaveBarrelSurface = new G4LogicalSkinSurface("TyvekCaveBarrelSurface", logicCaveTyvek, OpWaterTySurface);
192 
193  G4VisAttributes *showTyvekCave = new G4VisAttributes(green);
194  showTyvekCave->SetForceWireframe(true);// This line is used to give definition to the rings in OGLSX Visualizer
195  logicCaveTyvek->SetVisAttributes(showTyvekCave);
196  //logicCaveTyvek->SetVisAttributes(G4VisAttributes::Invisible); //amb79
197 
198  //-----------------------------------------------------
199  // Cylinder caps' tyvek
200  //-----------------------------------------------------
201 
202  G4Tubs *solidCaveCapsTyvek = new G4Tubs("CaveCapsTyvek",
203  0,
204  WCRadius,
206  0. * deg,
207  360. * deg);
208 
209  G4LogicalVolume *logicCaveCapsTyvek =
210  new G4LogicalVolume(solidCaveCapsTyvek,
211  G4Material::GetMaterial("Tyvek"),
212  "CaveCapTyvek",
213  0, 0, 0);
214 
215  G4LogicalSkinSurface *TyvekCaveTopSurface = new G4LogicalSkinSurface("TyvekCaveTopSurface", logicCaveCapsTyvek, OpWaterTySurface);
216 
217  G4VisAttributes *CapsCaveTyvekVisAtt = new G4VisAttributes(yellow);
218  CapsCaveTyvekVisAtt->SetForceWireframe(true);
219  logicCaveCapsTyvek->SetVisAttributes(CapsCaveTyvekVisAtt);
220  //logicCaveCapsTyvek->SetVisAttributes(G4VisAttributes::Invisible); //amb79
221 
222  G4ThreeVector CaveTyvekPosition(0., 0., WCLength / 2);
223 
224  G4VPhysicalVolume *physiTopCaveTyvek =
225  new G4PVPlacement(0,
226  CaveTyvekPosition,
227  logicCaveCapsTyvek,
228  "CaveTopTyvek",
229  logicCaveCapsTyvek,
230  false,
231  0);
232 
233 
234  CaveTyvekPosition.setZ(-CaveTyvekPosition.getZ());
235 
236  G4VPhysicalVolume *physiBottomCaveTyvek =
237  new G4PVPlacement(0,
238  CaveTyvekPosition,
239  logicCaveCapsTyvek,
240  "CaveBottomTyvek",
241  logicWCBarrel,
242  false,
243  0);
244 
245 
246  } // END Tyvek cave
247  //-----------------------------------------------------
248 
249 // This volume needs to made invisible to view the blacksheet and PMTs with RayTracer
250  if (Vis_Choice == "RayTracer")
251  {logicWCBarrel->SetVisAttributes(G4VisAttributes::Invisible);}
252 
253  else
254  {//{if(!debugMode)
255  G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4VisAttributes::Invisible);
256  tmpVisAtt->SetForceWireframe(true);// This line is used to give definition to the rings in OGLSX Visualizer
257  logicWCBarrel->SetVisAttributes(tmpVisAtt);
258  }
259  //-----------------------------------------------------
260  // Form annular section of barrel to hold PMTs
261  //----------------------------------------------------
262 
263 
264  G4double mainAnnulusZ[2] = {-mainAnnulusHeight/2., mainAnnulusHeight/2};
265  G4double mainAnnulusRmin[2] = {innerAnnulusRadius, innerAnnulusRadius};
266  G4double mainAnnulusRmax[2] = {outerAnnulusRadius, outerAnnulusRadius};
267 
268  G4Polyhedra* solidWCBarrelAnnulus = new G4Polyhedra("WCBarrelAnnulus",
269  0.*deg, // phi start
270  totalAngle,
271  (G4int)WCBarrelRingNPhi, //NPhi-gon
272  2,
273  mainAnnulusZ,
274  mainAnnulusRmin,
275  mainAnnulusRmax);
276 
277  G4LogicalVolume* logicWCBarrelAnnulus =
278  new G4LogicalVolume(solidWCBarrelAnnulus,
279  G4Material::GetMaterial(water),
280  "WCBarrelAnnulus",
281  0,0,0);
282  // G4cout << *solidWCBarrelAnnulus << G4endl;
283  G4VPhysicalVolume* physiWCBarrelAnnulus =
284  new G4PVPlacement(0,
285  G4ThreeVector(0.,0.,0.),
286  logicWCBarrelAnnulus,
287  "WCBarrelAnnulus",
288  logicWCBarrel,
289  false,
290  0,true);
291 if(!debugMode)
292  logicWCBarrelAnnulus->SetVisAttributes(G4VisAttributes::Invisible); //amb79
293  //-----------------------------------------------------
294  // Subdivide the BarrelAnnulus into rings
295  //-----------------------------------------------------
296  G4double RingZ[2] = {-barrelCellHeight/2.,
297  barrelCellHeight/2.};
298 
299  G4Polyhedra* solidWCBarrelRing = new G4Polyhedra("WCBarrelRing",
300  0.*deg,//+dPhi/2., // phi start
301  totalAngle, //phi end
302  (G4int)WCBarrelRingNPhi, //NPhi-gon
303  2,
304  RingZ,
305  mainAnnulusRmin,
306  mainAnnulusRmax);
307 
308  G4LogicalVolume* logicWCBarrelRing =
309  new G4LogicalVolume(solidWCBarrelRing,
310  G4Material::GetMaterial(water),
311  "WCBarrelRing",
312  0,0,0);
313 
314  G4VPhysicalVolume* physiWCBarrelRing =
315  new G4PVReplica("WCBarrelRing",
316  logicWCBarrelRing,
317  logicWCBarrelAnnulus,
318  kZAxis,
319  (G4int)WCBarrelNRings-2,
321 
322 if(!debugMode)
323  {G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4Colour(0,0.5,1.));
324  tmpVisAtt->SetForceWireframe(true);// This line is used to give definition to the rings in OGLSX Visualizer
325  logicWCBarrelRing->SetVisAttributes(tmpVisAtt);
326  //If you want the rings on the Annulus to show in OGLSX, then comment out the line below.
327  logicWCBarrelRing->SetVisAttributes(G4VisAttributes::Invisible);
328  }
329 else {
330  G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4Colour(0,0.5,1.));
331  tmpVisAtt->SetForceWireframe(true);
332  logicWCBarrelRing->SetVisAttributes(tmpVisAtt);
333  }
334 
335  //-----------------------------------------------------
336  // Subdivisions of the BarrelRings are cells
337  //------------------------------------------------------
338 
339 
340  G4Polyhedra* solidWCBarrelCell = new G4Polyhedra("WCBarrelCell",
341  -dPhi/2.+0.*deg, // phi start
342  dPhi, //total Phi
343  1, //NPhi-gon
344  2,
345  RingZ,
346  mainAnnulusRmin,
347  mainAnnulusRmax);
348  //G4cout << *solidWCBarrelCell << G4endl;
349  G4LogicalVolume* logicWCBarrelCell =
350  new G4LogicalVolume(solidWCBarrelCell,
351  G4Material::GetMaterial(water),
352  "WCBarrelCell",
353  0,0,0);
354 
355  G4VPhysicalVolume* physiWCBarrelCell =
356  new G4PVReplica("WCBarrelCell",
357  logicWCBarrelCell,
358  logicWCBarrelRing,
359  kPhi,
360  (G4int)WCBarrelRingNPhi,
361  dPhi,
362  0.);
363 
364  if(!debugMode)
365  {G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4Colour(1.,0.5,0.5));
366  tmpVisAtt->SetForceWireframe(true);// This line is used to give definition to the cells in OGLSX Visualizer
367  logicWCBarrelCell->SetVisAttributes(tmpVisAtt);
368  //If you want the columns on the Annulus to show in OGLSX, then comment out the line below.
369  logicWCBarrelCell->SetVisAttributes(G4VisAttributes::Invisible);
370  }
371  else {
372  G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4Colour(1.,0.5,0.5));
373  tmpVisAtt->SetForceWireframe(true);
374  logicWCBarrelCell->SetVisAttributes(tmpVisAtt);
375  }
376 
377  //-----------------------------------------------------------
378  // The Blacksheet, a daughter of the cells containing PMTs,
379  // and also some other volumes to make the edges light tight
380  //-----------------------------------------------------------
381 
382  //-------------------------------------------------------------
383  // add barrel blacksheet to the normal barrel cells
384  // ------------------------------------------------------------
385  G4double annulusBlackSheetRmax[2] = {(WCIDRadius+WCBlackSheetThickness),
387  G4double annulusBlackSheetRmin[2] = {(WCIDRadius),
388  WCIDRadius};
389 
390  G4Polyhedra* solidWCBarrelCellBlackSheet = new G4Polyhedra("WCBarrelCellBlackSheet",
391  -dPhi/2., // phi start
392  dPhi, //total phi
393  1, //NPhi-gon
394  2,
395  RingZ,
396  annulusBlackSheetRmin,
397  annulusBlackSheetRmax);
398 
400  new G4LogicalVolume(solidWCBarrelCellBlackSheet,
401  G4Material::GetMaterial("Blacksheet"),
402  "WCBarrelCellBlackSheet",
403  0,0,0);
404 
405  G4VPhysicalVolume* physiWCBarrelCellBlackSheet =
406  new G4PVPlacement(0,
407  G4ThreeVector(0.,0.,0.),
409  "WCBarrelCellBlackSheet",
410  logicWCBarrelCell,
411  false,
412  0,true);
413 
414  G4LogicalBorderSurface * WaterBSBarrelCellSurface
415  = new G4LogicalBorderSurface("WaterBSBarrelCellSurface",
416  physiWCBarrelCell,
417  physiWCBarrelCellBlackSheet,
419 
420  // Change made here to have the if statement contain the !debugmode to be consistent
421  // This code gives the Blacksheet its color.
422 
423 if (Vis_Choice == "RayTracer"){
424 
425  G4VisAttributes* WCBarrelBlackSheetCellVisAtt
426  = new G4VisAttributes(G4Colour(0.2,0.9,0.2)); // green color
427  WCBarrelBlackSheetCellVisAtt->SetForceSolid(true); // force the object to be visualized with a surface
428  WCBarrelBlackSheetCellVisAtt->SetForceAuxEdgeVisible(true); // force auxiliary edges to be shown
429  if(!debugMode)
430  logicWCBarrelCellBlackSheet->SetVisAttributes(WCBarrelBlackSheetCellVisAtt);
431  else
432  logicWCBarrelCellBlackSheet->SetVisAttributes(G4VisAttributes::Invisible);}
433 
434 else {
435 
436  G4VisAttributes* WCBarrelBlackSheetCellVisAtt
437  = new G4VisAttributes(G4Colour(0.2,0.9,0.2));
438  if(!debugMode)
439  logicWCBarrelCellBlackSheet->SetVisAttributes(G4VisAttributes::Invisible);
440  else
441  logicWCBarrelCellBlackSheet->SetVisAttributes(WCBarrelBlackSheetCellVisAtt);}
442 
443  //-----------------------------------------------------------
444  // add extra tower if nessecary
445  // ---------------------------------------------------------
446 
447  // we have to declare the logical Volumes
448  // outside of the if block to access it later on
449  G4LogicalVolume* logicWCExtraTowerCell;
450  G4LogicalVolume* logicWCExtraBorderCell;
451  if(!(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal)){
452 
453  // as the angles between the corners of the main annulus
454  // and the corners extra tower are different, we need to adjust the
455  // tangent distance the surfaces of the extra tower. Otherwise
456  // the corners of the main annulus and the extra tower would
457  // not match.
458  G4double extraTowerRmin[2];
459  G4double extraTowerRmax[2];
460  for(int i = 0; i < 2 ; i++){
461  extraTowerRmin[i] = mainAnnulusRmin[i] != 0 ? mainAnnulusRmin[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.) : 0.;
462  extraTowerRmax[i] = mainAnnulusRmax[i] != 0 ? mainAnnulusRmax[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.) : 0.;
463  }
464  G4Polyhedra* solidWCExtraTower = new G4Polyhedra("WCextraTower",
465  totalAngle-2.*pi,//+dPhi/2., // phi start
466  2.*pi - totalAngle // total angle.
467  -G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/(10.*m),
468  // we need this little Gap between the extra tower and the main annulus
469  // to avoid a shared surface. Without the gap the photons stuck
470  // at this place for mare than 25 steps and the howl simulation
471  // crashes.
472  1, //NPhi-gon
473  2,
474  mainAnnulusZ,
475  extraTowerRmin,
476  extraTowerRmax);
477 
478  G4LogicalVolume* logicWCExtraTower =
479  new G4LogicalVolume(solidWCExtraTower,
480  G4Material::GetMaterial(water),
481  "WCExtraTower",
482  0,0,0);
483  G4VPhysicalVolume* physiWCExtraTower =
484  new G4PVPlacement(0,
485  G4ThreeVector(0.,0.,0.),
486  logicWCExtraTower,
487  "WCExtraTower",
488  logicWCBarrel,
489  false,
490  0,true);
491 
492 
493  logicWCExtraTower->SetVisAttributes(G4VisAttributes::Invisible);
494  //-------------------------------------------
495  // subdivide the extra tower into cells
496  //------------------------------------------
497 
498  G4Polyhedra* solidWCExtraTowerCell = new G4Polyhedra("WCExtraTowerCell",
499  totalAngle-2.*pi,//+dPhi/2., // phi start
500  2.*pi - totalAngle -G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/(10.*m), //phi end
501  1, //NPhi-gon
502  2,
503  RingZ,
504  extraTowerRmin,
505  extraTowerRmax);
506  //G4cout << * solidWCExtraTowerCell << G4endl;
507  logicWCExtraTowerCell =
508  new G4LogicalVolume(solidWCExtraTowerCell,
509  G4Material::GetMaterial(water),
510  "WCExtraTowerCell",
511  0,0,0);
512  G4VPhysicalVolume* physiWCTowerCell =
513  new G4PVReplica("extraTowerCell",
514  logicWCExtraTowerCell,
515  logicWCExtraTower,
516  kZAxis,
517  (G4int)WCBarrelNRings-2,
519  logicWCExtraTowerCell->SetVisAttributes(G4VisAttributes::Invisible);
520 
521  //---------------------------------------------
522  // add blacksheet to this cells
523  //--------------------------------------------
524 
525  G4double towerBSRmin[2];
526  G4double towerBSRmax[2];
527  for(int i = 0; i < 2; i++){
528  towerBSRmin[i] = annulusBlackSheetRmin[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.);
529  towerBSRmax[i] = annulusBlackSheetRmax[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.);
530  }
531  G4Polyhedra* solidWCTowerBlackSheet = new G4Polyhedra("WCExtraTowerBlackSheet",
532  totalAngle-2.*pi,//+dPhi/2., // phi start
533  2.*pi - totalAngle -G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/(10.*m), //phi end
534  1, //NPhi-gon
535  2,
536  RingZ,
537  towerBSRmin,
538  towerBSRmax);
539  //G4cout << * solidWCTowerBlackSheet << G4endl;
541  new G4LogicalVolume(solidWCTowerBlackSheet,
542  G4Material::GetMaterial("Blacksheet"),
543  "WCExtraTowerBlackSheet",
544  0,0,0);
545 
546  G4VPhysicalVolume* physiWCTowerBlackSheet =
547  new G4PVPlacement(0,
548  G4ThreeVector(0.,0.,0.),
550  "WCExtraTowerBlackSheet",
551  logicWCExtraTowerCell,
552  false,
553  0,true);
554 
555  G4LogicalBorderSurface * WaterBSTowerCellSurface
556  = new G4LogicalBorderSurface("WaterBSBarrelCellSurface",
557  physiWCTowerCell,
558  physiWCTowerBlackSheet,
560 
561 // These lines add color to the blacksheet in the extratower. If using RayTracer, comment the first chunk and use the second. The Blacksheet should be green.
562 
563  if (Vis_Choice == "OGLSX"){
564 
565  G4VisAttributes* WCBarrelBlackSheetCellVisAtt
566  = new G4VisAttributes(G4Colour(0.2,0.9,0.2)); // green color
567 
568  if(!debugMode)
569  {logicWCTowerBlackSheet->SetVisAttributes(G4VisAttributes::Invisible);}
570  else
571  {logicWCTowerBlackSheet->SetVisAttributes(WCBarrelBlackSheetCellVisAtt);}}
572 
573  if (Vis_Choice == "RayTracer"){
574 
575  G4VisAttributes* WCBarrelBlackSheetCellVisAtt
576  = new G4VisAttributes(G4Colour(0.2,0.9,0.2)); // green color
577  WCBarrelBlackSheetCellVisAtt->SetForceSolid(true); // force the object to be visualized with a surface
578  WCBarrelBlackSheetCellVisAtt->SetForceAuxEdgeVisible(true); // force auxiliary edges to be shown
579 
580  if(!debugMode)
581  logicWCTowerBlackSheet->SetVisAttributes(WCBarrelBlackSheetCellVisAtt);
582  else
583  logicWCTowerBlackSheet->SetVisAttributes(WCBarrelBlackSheetCellVisAtt);}
584 
585  else {
586 
587  G4VisAttributes* WCBarrelBlackSheetCellVisAtt
588  = new G4VisAttributes(G4Colour(0.2,0.9,0.2)); // green color
589 
590  if(!debugMode)
591  {logicWCTowerBlackSheet->SetVisAttributes(G4VisAttributes::Invisible);}
592  else
593  {logicWCTowerBlackSheet->SetVisAttributes(WCBarrelBlackSheetCellVisAtt);}}
594 
595 
596 }
597 
598  //jl145------------------------------------------------
599  // Add top veto volume
600  //-----------------------------------------------------
601 
602  G4bool WCTopVeto = (WCSimTuningParams->GetTopVeto());
603 
604  G4LogicalVolume* logicWCTopVeto;
605 
606  if(WCTopVeto){
607 
608  G4double WCTyvekThickness = 1.0*mm; //completely made up
609 
610  G4VSolid* solidWCTopVeto;
611  solidWCTopVeto =
612  new G4Tubs( "WCTopVeto",
613  0.0*m,
614  WCIDRadius + WCTyvekThickness,
615  0.5*m + WCTyvekThickness,
616  0.*deg,
617  360.*deg);
618 
619  logicWCTopVeto =
620  new G4LogicalVolume(solidWCTopVeto,
621  G4Material::GetMaterial(water),
622  "WCTopVeto",
623  0,0,0);
624 
625  G4VPhysicalVolume* physiWCTopVeto =
626  new G4PVPlacement( 0,
627  G4ThreeVector(0.,0.,WCIDHeight/2
628  +1.0*m),
629  logicWCTopVeto,
630  "WCTopVeto",
631  logicWCBarrel,
632  false,0,true);
633 
634  //Add the top veto Tyvek
635  //-----------------------------------------------------
636 
637  G4VSolid* solidWCTVTyvek;
638  solidWCTVTyvek =
639  new G4Tubs( "WCTVTyvek",
640  0.0*m,
641  WCIDRadius,
642  WCTyvekThickness/2,
643  0.*deg,
644  360.*deg);
645 
646 
647  G4LogicalVolume* logicWCTVTyvek =
648  new G4LogicalVolume(solidWCTVTyvek,
649  G4Material::GetMaterial("Tyvek"),
650  "WCTVTyvek",
651  0,0,0);
652 
653  //Bottom
654  G4VPhysicalVolume* physiWCTVTyvekBot =
655  new G4PVPlacement( 0,
656  G4ThreeVector(0.,0.,-0.5*m
657  -WCTyvekThickness/2),
658  logicWCTVTyvek,
659  "WCTVTyvekBot",
660  logicWCTopVeto,
661  false,0,true);
662 
663  G4LogicalBorderSurface * WaterTyTVSurfaceBot =
664  new G4LogicalBorderSurface( "WaterTyTVSurfaceBot",
665  physiWCTopVeto,
666  physiWCTVTyvekBot,
668 
669  //Top
670  G4VPhysicalVolume* physiWCTVTyvekTop =
671  new G4PVPlacement( 0,
672  G4ThreeVector(0.,0.,0.5*m
673  +WCTyvekThickness/2),
674  logicWCTVTyvek,
675  "WCTVTyvekTop",
676  logicWCTopVeto,
677  false,0,true);
678 
679  G4LogicalBorderSurface * WaterTyTVSurfaceTop =
680  new G4LogicalBorderSurface( "WaterTyTVSurfaceTop",
681  physiWCTopVeto,
682  physiWCTVTyvekTop,
684 
685  //Side
686  G4VSolid* solidWCTVTyvekSide;
687  solidWCTVTyvekSide =
688  new G4Tubs( "WCTVTyvekSide",
689  WCIDRadius,
690  WCIDRadius + WCTyvekThickness,
691  0.5*m + WCTyvekThickness,
692  0.*deg,
693  360.*deg);
694 
695 
696  G4LogicalVolume* logicWCTVTyvekSide =
697  new G4LogicalVolume(solidWCTVTyvekSide,
698  G4Material::GetMaterial("Tyvek"),
699  "WCTVTyvekSide",
700  0,0,0);
701 
702  G4VPhysicalVolume* physiWCTVTyvekSide =
703  new G4PVPlacement( 0,
704  G4ThreeVector(0.,0.,0.),
705  logicWCTVTyvekSide,
706  "WCTVTyvekSide",
707  logicWCTopVeto,
708  false,0,true);
709 
710  G4LogicalBorderSurface * WaterTyTVSurfaceSide =
711  new G4LogicalBorderSurface( "WaterTyTVSurfaceSide",
712  physiWCTopVeto,
713  physiWCTVTyvekSide,
715 
716  }
717 
718  //
719  //
720  //jl145------------------------------------------------
721 
722 
724  // place the PMTs in the truncated cells
725  //-----------------------------------------------------
726  // The PMT
727  //-----------------------------------------------------
728 
730  // from any specific detector geometry so that any geometry can use the same definition.
731  // K.Zbiri: The PMT volume and the PMT glass are now put in parallel.
732  // The PMT glass is the sensitive volume in this new configuration.
733 
734  G4LogicalVolume* logicWCPMT = ConstructPMT(WCPMTName, WCIDCollectionName, "tank");
735 
736 
737  /*These lines of code will give color and volume to the PMTs if it hasn't been set in WCSimConstructPMT.cc.
738 I recommend setting them in WCSimConstructPMT.cc.
739 If used here, uncomment the SetVisAttributes(WClogic) line, and comment out the SetVisAttributes(G4VisAttributes::Invisible) line.*/
740 
741  G4VisAttributes* WClogic
742  = new G4VisAttributes(G4Colour(0.4,0.0,0.8));
743  WClogic->SetForceSolid(true);
744  WClogic->SetForceAuxEdgeVisible(true);
745 
746  //logicWCPMT->SetVisAttributes(WClogic);
747  logicWCPMT->SetVisAttributes(G4VisAttributes::Invisible);
748 
749  //jl145------------------------------------------------
750  // Add top veto PMTs
751  //-----------------------------------------------------
752 
753  if(WCTopVeto){
754 
755  G4double WCTVPMTSpacing = (WCSimTuningParams->GetTVSpacing())*cm;
756  G4double WCTVEdgeLimit = WCCapEdgeLimit;
757  G4int TVNCell = WCTVEdgeLimit/WCTVPMTSpacing + 2;
758 
759  int icopy = 0;
760 
761  for ( int i = -TVNCell ; i < TVNCell; i++) {
762  for (int j = -TVNCell ; j < TVNCell; j++) {
763 
764  G4double xoffset = i*WCTVPMTSpacing + WCTVPMTSpacing*0.5;
765  G4double yoffset = j*WCTVPMTSpacing + WCTVPMTSpacing*0.5;
766 
767  G4ThreeVector cellpos =
768  G4ThreeVector( xoffset, yoffset, -0.5*m);
769 
770  if ((sqrt(xoffset*xoffset + yoffset*yoffset) + WCPMTRadius) < WCTVEdgeLimit) {
771 
772  G4VPhysicalVolume* physiCapPMT =
773  new G4PVPlacement( 0, // no rotation
774  cellpos, // its position
775  logicWCPMT, // its logical volume
776  "WCPMT", // its name
777  logicWCTopVeto, // its mother volume
778  false, // no boolean os
779  icopy); // every PMT need a unique id.
780 
781  icopy++;
782  }
783  }
784  }
785 
786  G4double WCTVEfficiency = icopy*WCPMTRadius*WCPMTRadius/((WCIDRadius)*(WCIDRadius));
787  G4cout << "Total on top veto: " << icopy << "\n";
788  G4cout << "Coverage was calculated to be: " << WCTVEfficiency << "\n";
789 
790  }
791 
792  //
793  //
794  //jl145------------------------------------------------
795 
796 
798  G4RotationMatrix* WCPMTRotation = new G4RotationMatrix;
799  WCPMTRotation->rotateY(90.*deg);
800 
801  G4double barrelCellWidth = 2.*WCIDRadius*tan(dPhi/2.);
802  G4double horizontalSpacing = barrelCellWidth/WCPMTperCellHorizontal;
803  G4double verticalSpacing = barrelCellHeight/WCPMTperCellVertical;
804 
805  for(G4double i = 0; i < WCPMTperCellHorizontal; i++){
806  for(G4double j = 0; j < WCPMTperCellVertical; j++){
807  G4ThreeVector PMTPosition = G4ThreeVector(WCIDRadius,
808  -barrelCellWidth/2.+(i+0.5)*horizontalSpacing,
809  -barrelCellHeight/2.+(j+0.5)*verticalSpacing);
810 
811  G4VPhysicalVolume* physiWCBarrelPMT =
812  new G4PVPlacement(WCPMTRotation, // its rotation
813  PMTPosition,
814  logicWCPMT, // its logical volume
815  "WCPMT", // its name
816  logicWCBarrelCell, // its mother volume
817  false, // no boolean operations
818  (int)(i*WCPMTperCellVertical+j),
819  true);
820 
821  // logicWCPMT->GetDaughter(0),physiCapPMT is the glass face. If you add more
822  // daugter volumes to the PMTs (e.g. a acryl cover) you have to check, if
823  // this is still the case.
824  }
825  }
826  //-------------------------------------------------------------
827  // Add PMTs in extra Tower if necessary
828  //------------------------------------------------------------
829 
830 
831  if(!(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal)){
832 
833  G4RotationMatrix* WCPMTRotation = new G4RotationMatrix;
834  WCPMTRotation->rotateY(90.*deg);
835  WCPMTRotation->rotateX((2*pi-totalAngle)/2.);//align the PMT with the Cell
836 
837  G4double towerWidth = WCIDRadius*tan(2*pi-totalAngle);
838 
839  G4double horizontalSpacing = towerWidth/(WCBarrelNumPMTHorizontal-WCBarrelRingNPhi*WCPMTperCellHorizontal);
840  G4double verticalSpacing = barrelCellHeight/WCPMTperCellVertical;
841 
842  for(G4double i = 0; i < (WCBarrelNumPMTHorizontal-WCBarrelRingNPhi*WCPMTperCellHorizontal); i++){
843  for(G4double j = 0; j < WCPMTperCellVertical; j++){
844  G4ThreeVector PMTPosition = G4ThreeVector(WCIDRadius/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.),
845  towerWidth/2.-(i+0.5)*horizontalSpacing,
846  -barrelCellHeight/2.+(j+0.5)*verticalSpacing);
847  PMTPosition.rotateZ(-(2*pi-totalAngle)/2.); // align with the symmetry
848  //axes of the cell
849 
850  G4VPhysicalVolume* physiWCBarrelPMT =
851  new G4PVPlacement(WCPMTRotation, // its rotation
852  PMTPosition,
853  logicWCPMT, // its logical volume
854  "WCPMT", // its name
855  logicWCExtraTowerCell, // its mother volume
856  false, // no boolean operations
857  (int)(i*WCPMTperCellVertical+j),
858  true);
859 
860  // logicWCPMT->GetDaughter(0),physiCapPMT is the glass face. If you add more
861  // daugter volumes to the PMTs (e.g. a acryl cover) you have to check, if
862  // this is still the case.
863  }
864  }
865 
866  }
867 
868 
869  // # -------------------------------------- #
870  // ##########################################
871  // # Prototype Outer-Detector OD Hyper-K HK #
872  // ##########################################
873  // # -------------------------------------- #
874 
875  // Goal is to create a dedicated ConstructOD() method in charge of defining an OD geometry
876  // for any WC detector.
877  // Parameters will be :
878  // - NPMTs by Cells horizontally and vertically
879  // - Coverage
880  // - Dead Volume Size
881  // - Water Size
882 
883  if(isODConstructed){
884 
886 
887  //-------------------------------------------------------------
888  // OD Tyvek Caps
889  // ------------------------------------------------------------
890 
891  G4Tubs* solidWCODCapsTyvek = new G4Tubs("WCODCapsTyvek",
892  0,
893  WCIDRadius,
895  0.*deg,
896  360.*deg);
897 
898  G4LogicalVolume* logicWCODCapTyvek =
899  new G4LogicalVolume(solidWCODCapsTyvek,
900  G4Material::GetMaterial("Tyvek"),
901  "WCODTopCapTyvek",
902  0,0,0);
903 
904  G4LogicalSkinSurface *WaterTySurfaceTop = new G4LogicalSkinSurface("WaterTySurfaceTop", logicWCODCapTyvek, OpWaterTySurface);
905 
906  G4VisAttributes* WCCapsODTyvekCellVisAtt
907  = new G4VisAttributes(yellow);
908  WCCapsODTyvekCellVisAtt->SetForceWireframe(true);
909 
910  logicWCODCapTyvek->SetVisAttributes(G4VisAttributes::Invisible);
912  // logicWCODCapTyvek->SetVisAttributes(WCCapsODTyvekCellVisAtt);
913 
914  G4ThreeVector CapTyvekPosition(0.,0.,(WCIDHeight + 2*WCODDeadSpace)/2);
915 
916  G4VPhysicalVolume* physiWCODTopCapsTyvek =
917  new G4PVPlacement(0,
918  CapTyvekPosition,
919  logicWCODCapTyvek,
920  "WCODTopCapsTyvek",
921  logicWCBarrel,
922  false,
923  0);
924 
925 
926  CapTyvekPosition.setZ(-CapTyvekPosition.getZ());
927 
928  G4VPhysicalVolume* physiWCODBottomCapsTyvek =
929  new G4PVPlacement(0,
930  CapTyvekPosition,
931  logicWCODCapTyvek,
932  "WCODBottomCapsTyvek",
933  logicWCBarrel,
934  false,
935  0);
936 
937 
938  //-------------------------------------------------------------
939  // OD Tyvek Barrel side
940  // ------------------------------------------------------------
941 
942  G4double annulusODTyvekRmax[2] = {(WCODRadius),
943  WCODRadius};
944  G4double annulusODTyvekRmin[2] = {(WCODRadius-WCODTyvekSheetThickness),
946 
947  G4Polyhedra* solidWCBarrelCellODTyvek = new G4Polyhedra("WCBarrelCellODTyvek",
948  -dPhi/2., // phi start
949  dPhi, //total phi
950  1, //NPhi-gon
951  2,
952  RingZ,
953  annulusODTyvekRmin,
954  annulusODTyvekRmax);
955 
957  new G4LogicalVolume(solidWCBarrelCellODTyvek,
958  G4Material::GetMaterial("Tyvek"),
959  "WCBarrelCellODTyvek",
960  0,0,0);
961 
962  G4LogicalSkinSurface *WaterTySurfaceSide = new G4LogicalSkinSurface("WaterTySurfaceSide", logicWCBarrelCellODTyvek, OpWaterTySurface);
963 
964  G4VisAttributes* WCBarrelODTyvekCellVisAtt
965  = new G4VisAttributes(yellow);
966  WCBarrelODTyvekCellVisAtt->SetForceWireframe(true);
967 
968  logicWCBarrelCellODTyvek->SetVisAttributes(G4VisAttributes::Invisible);
970  logicWCBarrelCellODTyvek->SetVisAttributes(WCBarrelODTyvekCellVisAtt);
971 
972 
973  G4VPhysicalVolume* physiWCBarrelCellODTyvek =
974  new G4PVPlacement(0,
975  G4ThreeVector(0.,0.,0.),
977  "WCBarrelCellODTyvek",
978  logicWCBarrelCell,
979  false,
980  0,true);
981 
982 
983 
984  //-------------------------------------------------------------
985  // OD PMTs Barrel Side
986  // ------------------------------------------------------------
987 
988  G4LogicalVolume* logicWCPMTOD = ConstructPMT(WCPMTODName, WCODCollectionName, "OD");
989 
991  G4RotationMatrix* WCPMTODRotation = new G4RotationMatrix;
992  WCPMTODRotation->rotateY(270.*deg);
993 
994  G4double barrelODCellWidth = 2.*WCODRadius*tan(dPhi/2.);
995  G4double barrelODCellHeight = barrelCellHeight * (barrelODCellWidth/barrelCellWidth);
996 
997  // ------------------- //
998  // COMPUTE OD COVERAGE //
999  // ------------------- //
1000  G4double AreaRingOD = WCBarrelRingNPhi * barrelODCellWidth * barrelODCellHeight;
1001  G4double AreaPMTOD = 3.1415*std::pow(WCPMTODRadius,2);
1002  G4double NPMTODCovered = (AreaRingOD/AreaPMTOD) * WCPMTODPercentCoverage/100.;
1003  G4double NPMTODByCell = round(NPMTODCovered/WCBarrelRingNPhi); // NPMT required par cell to achieve ODPercentOverage
1004 
1005  // ------ DEBUG ------ //
1006  G4cout << G4endl;
1007  G4cout << "AreaRingOD : " << AreaRingOD/m2 << " (m2)" << G4endl;
1008  G4cout << "AreaPMTOD : " << AreaPMTOD/m2 << " (m2)" << G4endl;
1009  G4cout << "--> NbPMTODCovered : " << NPMTODCovered << G4endl;
1010  G4cout << "--> NbPMTODByCell : " << NPMTODByCell << G4endl;
1011  G4cout << G4endl;
1012  // ------------------- //
1013 
1014  if((G4int)WCPMTODperCellHorizontal == 0 && (G4int)WCPMTODperCellVertical == 0){
1016  }
1017 
1018  G4double horizontalODSpacing = barrelODCellWidth/WCPMTODperCellHorizontal;
1019  G4double verticalODSpacing = barrelODCellHeight/WCPMTODperCellVertical;
1020 
1021  if(WCODPMTShift > barrelODCellWidth/2. - WCPMTODRadius) WCODPMTShift == 0.*cm;
1022 
1023  for(G4double i = 0; i < WCPMTODperCellHorizontal; i++){
1024  for(G4double j = 0; j < WCPMTODperCellVertical; j++){
1025  G4ThreeVector PMTPosition = G4ThreeVector(WCODRadius,
1026  -barrelODCellWidth/2.+(i+0.5)*horizontalODSpacing+((G4int)(std::pow(-1,j))*(G4int)(WCODPMTShift)/2),
1027  -(barrelCellHeight * (barrelODCellWidth/barrelCellWidth))/2.+(j+0.5)*verticalODSpacing);
1028 
1029  G4VPhysicalVolume* physiWCBarrelPMT =
1030  new G4PVPlacement(WCPMTODRotation, // its rotation
1031  PMTPosition,
1032  logicWCPMTOD, // its logical volume
1033  "WCPMTOD", // its name
1034  logicWCBarrelCell, // its mother volume
1035  false, // no boolean operations
1036  (int)(i*WCPMTODperCellVertical+j),
1037  true);
1038 
1039  }
1040  }
1041 
1042 
1043  //-------------------------------------------------------------
1044  // Add PMTs in extra Tower if necessary
1045  //------------------------------------------------------------
1046 
1047  // EXTRA TOWER PART
1048  if(!(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal)){
1049 
1050  // TYVEK
1051 
1052  G4double towerODTyvekRmin[2];
1053  G4double towerODTyvekRmax[2];
1054  for(int i = 0; i < 2; i++){
1055  towerODTyvekRmin[i] = annulusODTyvekRmin[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.);
1056  towerODTyvekRmax[i] = annulusODTyvekRmax[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.);
1057  }
1058  G4Polyhedra* solidWCTowerODTyvek = new G4Polyhedra("WCExtraTowerODTyvek",
1059  totalAngle-2.*pi,//+dPhi/2., // phi start
1060  2.*pi - totalAngle -G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/(10.*m), //phi end
1061  1, //NPhi-gon
1062  2,
1063  RingZ,
1064  towerODTyvekRmin,
1065  towerODTyvekRmax);
1066 
1068  new G4LogicalVolume(solidWCTowerODTyvek,
1069  G4Material::GetMaterial("Tyvek"),
1070  "WCExtraTowerODTyvek",
1071  0,0,0);
1072 
1073  logicWCTowerODTyvek->SetVisAttributes(G4VisAttributes::Invisible);
1075  // logicWCTowerODTyvek->SetVisAttributes(WCBarrelODTyvekCellVisAtt);
1076 
1077 
1078  G4VPhysicalVolume* physiWCTowerODTyvek =
1079  new G4PVPlacement(0,
1080  G4ThreeVector(0.,0.,0.),
1082  "WCExtraTowerODTyvek",
1083  logicWCExtraTowerCell,
1084  false,
1085  0,true);
1086 
1087  // PMTs
1088 
1089  G4RotationMatrix* WCPMTRotation = new G4RotationMatrix;
1090  WCPMTRotation->rotateY(270.*deg);
1091  WCPMTRotation->rotateX((2*pi-totalAngle)/2.);//align the PMT with the Cell
1092 
1093  G4double towerWidthOD = WCODRadius*tan(2*pi-totalAngle);
1094 
1095  G4double horizontalODSpacing = towerWidthOD/WCPMTODperCellHorizontal;
1096  G4double verticalODSpacing = barrelCellHeight*(WCODRadius/WCIDRadius)/WCPMTODperCellVertical;
1097 
1098  for(G4double i = 0; i < (WCPMTODperCellHorizontal); i++){
1099  for(G4double j = 0; j < WCPMTODperCellVertical; j++){
1100  G4ThreeVector PMTPosition = G4ThreeVector(WCODRadius/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.),
1101  -towerWidthOD/2.+(i+0.5)*horizontalODSpacing,
1102  -(barrelCellHeight * (WCODRadius/WCIDRadius))/2.+(j+0.5)*verticalODSpacing);
1103  PMTPosition.rotateZ(-(2*pi-totalAngle)/2.); // align with the symmetry
1104  //axes of the cell
1105 
1106 
1107  G4VPhysicalVolume* physiWCBarrelPMT =
1108  new G4PVPlacement(WCPMTRotation, // its rotation
1109  PMTPosition,
1110  logicWCPMTOD, // its logical volume
1111  "WCPMTOD", // its name
1112  logicWCExtraTowerCell, // its mother volume
1113  false, // no boolean operations
1114  (int)(i*WCPMTODperCellVertical+j),
1115  true);
1116 
1117  }
1118  }
1119 
1120  }
1121 
1122  //---------------------------------------------------------
1123  // Add top and bottom PMTs
1124  // -----------------------------------------------------
1125 
1126  G4double xoffset;
1127  G4double yoffset;
1128  G4int icopy = 0;
1129 
1130  G4RotationMatrix* WCCapPMTRotation = new G4RotationMatrix;
1131  WCCapPMTRotation->rotateY(180.*deg);
1132 
1133  // loop over the cap
1134  G4int CapNCell = WCODCapEdgeLimit/WCODCapPMTSpacing + 2;
1135  for ( int i = -CapNCell ; i < CapNCell; i++) {
1136  for (int j = -CapNCell ; j < CapNCell; j++) {
1137 
1138  xoffset = i*WCODCapPMTSpacing + WCODCapPMTSpacing*0.5;
1139  yoffset = j*WCODCapPMTSpacing + WCODCapPMTSpacing*0.5;
1140 
1141  G4ThreeVector topcellpos = G4ThreeVector(xoffset,
1142  yoffset,
1144 
1145  G4ThreeVector bottomcellpos = G4ThreeVector(xoffset,
1146  yoffset,
1147  -topcellpos.getZ());
1148 
1149  if (((sqrt(xoffset*xoffset + yoffset*yoffset) + WCPMTODRadius) < WCODCapEdgeLimit) ) {
1150 
1151 
1152  G4VPhysicalVolume* physiTopCapPMT =
1153  new G4PVPlacement(0,
1154  topcellpos, // its position
1155  logicWCPMTOD, // its logical volume
1156  "WCPMTOD", // its name
1157  logicWCBarrel, // its mother volume
1158  false, // no boolean os
1159  icopy); // every PMT need a unique id.
1160  icopy++;
1161 
1162  G4VPhysicalVolume* physiBottomCapPMT =
1163  new G4PVPlacement(WCCapPMTRotation,
1164  bottomcellpos, // its position
1165  logicWCPMTOD, // its logical volume
1166  "WCPMTOD", // its name
1167  logicWCBarrel, // its mother volume
1168  false, // no boolean os
1169  icopy); // every PMT need a unique id.
1170 
1171  // logicWCPMT->GetDaughter(0),physiCapPMT is the glass face. If you add more
1172  // daugter volumes to the PMTs (e.g. a acryl cover) you have to check, if
1173  // this is still the case.
1174 
1175  icopy++;
1176 
1177  }
1178  }
1179  }
1180 
1181  G4cout << "#### OD ####" << "\n";
1182  G4cout << " total on cap: " << icopy << "\n";
1183  G4cout << " Coverage was calculated to be: " << (icopy*WCPMTODRadius*WCPMTODRadius/(WCIDRadius*WCIDRadius)) << "\n";
1184  G4cout << "############" << "\n";
1185 
1186  } // END if isODConstructed
1187 
1188  G4LogicalVolume* logicTopCapAssembly = ConstructCaps(-1);
1189  G4LogicalVolume* logicBottomCapAssembly = ConstructCaps(1);
1190 
1191  // These lines make the large cap volume invisible to view the caps blacksheets. Need to make invisible for
1192  // RayTracer
1193  if (Vis_Choice == "RayTracer"){
1194  logicBottomCapAssembly->SetVisAttributes(G4VisAttributes::Invisible);
1195  logicTopCapAssembly->SetVisAttributes(G4VisAttributes::Invisible);}
1196 
1197  G4VPhysicalVolume* physiTopCapAssembly =
1198  new G4PVPlacement(0,
1199  G4ThreeVector(0.,0.,(mainAnnulusHeight/2.+ capAssemblyHeight/2.)),
1200  logicTopCapAssembly,
1201  "TopCapAssembly",
1202  logicWCBarrel,
1203  false, 0,true);
1204 
1205  G4VPhysicalVolume* physiBottomCapAssembly =
1206  new G4PVPlacement(0,
1207  G4ThreeVector(0.,0.,(-mainAnnulusHeight/2.- capAssemblyHeight/2.)),
1208  logicBottomCapAssembly,
1209  "BottomCapAssembly",
1210  logicWCBarrel,
1211  false, 0,true);
1212 
1213  return logicWC;
1214 }
1215 
1216 
1217 G4LogicalVolume* WCSimDetectorConstruction::ConstructCaps(G4int zflip)
1218 {
1219 
1221 
1222  G4Tubs* solidCapAssembly = new G4Tubs("CapAssembly",
1223  0.0*m,
1224  outerAnnulusRadius/cos(dPhi/2.),
1226  0.*deg,
1227  360.*deg);
1228 
1229  G4LogicalVolume* logicCapAssembly =
1230  new G4LogicalVolume(solidCapAssembly,
1231  G4Material::GetMaterial(water),
1232  "CapAssembly",
1233  0,0,0);
1234 
1235  G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4VisAttributes::Invisible);
1236  tmpVisAtt->SetForceWireframe(true);// This line is used to give definition to the rings in OGLSX Visualizer
1237  logicCapAssembly->SetVisAttributes(tmpVisAtt);
1238 
1239 
1240  //----------------------------------------------------
1241  // extra rings for the top and bottom of the annulus
1242  //---------------------------------------------------
1243  G4double borderAnnulusZ[3] = {-barrelCellHeight/2.*zflip,
1245  barrelCellHeight/2.*zflip};
1246  G4double borderAnnulusRmin[3] = { WCIDRadius, innerAnnulusRadius, innerAnnulusRadius};
1247  G4double borderAnnulusRmax[3] = {outerAnnulusRadius, outerAnnulusRadius,outerAnnulusRadius};
1248  G4Polyhedra* solidWCBarrelBorderRing = new G4Polyhedra("WCBarrelBorderRing",
1249  0.*deg, // phi start
1250  totalAngle,
1251  (G4int)WCBarrelRingNPhi, //NPhi-gon
1252  3,
1253  borderAnnulusZ,
1254  borderAnnulusRmin,
1255  borderAnnulusRmax);
1256  G4LogicalVolume* logicWCBarrelBorderRing =
1257  new G4LogicalVolume(solidWCBarrelBorderRing,
1258  G4Material::GetMaterial(water),
1259  "WCBarrelRing",
1260  0,0,0);
1261  //G4cout << *solidWCBarrelBorderRing << G4endl;
1262 
1263  G4VPhysicalVolume* physiWCBarrelBorderRing =
1264  new G4PVPlacement(0,
1265  G4ThreeVector(0.,0.,(capAssemblyHeight/2.- barrelCellHeight/2.)*zflip),
1266  logicWCBarrelBorderRing,
1267  "WCBarrelBorderRing",
1268  logicCapAssembly,
1269  false, 0,true);
1270 
1271 
1272 
1273  if(!debugMode)
1274  logicWCBarrelBorderRing->SetVisAttributes(G4VisAttributes::Invisible);
1275  //----------------------------------------------------
1276  // Subdevide border rings into cells
1277  // --------------------------------------------------
1278  G4Polyhedra* solidWCBarrelBorderCell = new G4Polyhedra("WCBarrelBorderCell",
1279  -dPhi/2., // phi start
1280  dPhi, //total angle
1281  1, //NPhi-gon
1282  3,
1283  borderAnnulusZ,
1284  borderAnnulusRmin,
1285  borderAnnulusRmax);
1286 
1287  G4LogicalVolume* logicWCBarrelBorderCell =
1288  new G4LogicalVolume(solidWCBarrelBorderCell,
1289  G4Material::GetMaterial(water),
1290  "WCBarrelBorderCell",
1291  0,0,0);
1292  //G4cout << *solidWCBarrelBorderCell << G4endl;
1293  G4VPhysicalVolume* physiWCBarrelBorderCell =
1294  new G4PVReplica("WCBarrelBorderCell",
1295  logicWCBarrelBorderCell,
1296  logicWCBarrelBorderRing,
1297  kPhi,
1298  (G4int)WCBarrelRingNPhi,
1299  dPhi,
1300  0.);
1301 
1302 // These lines of code below will turn the border rings invisible.
1303 
1304 // used for RayTracer
1305  if (Vis_Choice == "RayTracer"){
1306 
1307  if(!debugMode){
1308  G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4Colour(1.,0.5,0.5));
1309  tmpVisAtt->SetForceSolid(true);
1310  logicWCBarrelBorderCell->SetVisAttributes(tmpVisAtt);
1311  logicWCBarrelBorderCell->SetVisAttributes(G4VisAttributes::Invisible);}
1312  else {
1313  G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4Colour(1.,0.5,0.5));
1314  tmpVisAtt->SetForceWireframe(true);
1315  logicWCBarrelBorderCell->SetVisAttributes(tmpVisAtt);
1316  logicWCBarrelBorderCell->SetVisAttributes(G4VisAttributes::Invisible);}}
1317 
1318 // used for OGLSX
1319  else {
1320 
1321  if(!debugMode)
1322  {logicWCBarrelBorderCell->SetVisAttributes(G4VisAttributes::Invisible);}
1323  else {
1324  G4VisAttributes* tmpVisAtt = new G4VisAttributes(G4Colour(1.,0.5,0.5));
1325  tmpVisAtt->SetForceWireframe(true);
1326  logicWCBarrelBorderCell->SetVisAttributes(tmpVisAtt);}}
1327 
1328 
1329  //------------------------------------------------------------
1330  // add blacksheet to the border cells.
1331  // We can use the same logical volume as for the normal
1332  // barrel cells.
1333  // ---------------------------------------------------------
1334 
1335 
1336  G4VPhysicalVolume* physiWCBarrelBorderCellBlackSheet =
1337  new G4PVPlacement(0,
1338  G4ThreeVector(0.,0.,0.),
1340  "WCBarrelCellBlackSheet",
1341  logicWCBarrelBorderCell,
1342  false,
1343  0,true);
1344 
1345  G4LogicalBorderSurface * WaterBSBarrelBorderCellSurface
1346  = new G4LogicalBorderSurface("WaterBSBarrelCellSurface",
1347  physiWCBarrelBorderCell,
1348  physiWCBarrelBorderCellBlackSheet,
1350 
1351  // we have to declare the logical Volumes
1352  // outside of the if block to access it later on
1353  G4LogicalVolume* logicWCExtraTowerCell;
1354  G4LogicalVolume* logicWCExtraBorderCell;
1355  G4VPhysicalVolume* physiWCExtraBorderCell;
1356  if(!(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal)){
1357  //----------------------------------------------
1358  // also the extra tower need special cells at the
1359  // top and th bottom.
1360  // (the top cell is created later on by reflecting the
1361  // bottom cell)
1362  //---------------------------------------------
1363  G4double extraBorderRmin[3];
1364  G4double extraBorderRmax[3];
1365  for(int i = 0; i < 3; i++){
1366  extraBorderRmin[i] = borderAnnulusRmin[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.);
1367  extraBorderRmax[i] = borderAnnulusRmax[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.);
1368  }
1369  G4Polyhedra* solidWCExtraBorderCell = new G4Polyhedra("WCspecialBarrelBorderCell",
1370  totalAngle-2.*pi,//+dPhi/2., // phi start
1371  2.*pi - totalAngle -G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/(10.*m), //total phi
1372  1, //NPhi-gon
1373  3,
1374  borderAnnulusZ,
1375  extraBorderRmin,
1376  extraBorderRmax);
1377 
1378  logicWCExtraBorderCell =
1379  new G4LogicalVolume(solidWCExtraBorderCell,
1380  G4Material::GetMaterial(water),
1381  "WCspecialBarrelBorderCell",
1382  0,0,0);
1383  //G4cout << *solidWCExtraBorderCell << G4endl;
1384 
1385  physiWCExtraBorderCell =
1386  new G4PVPlacement(0,
1387  G4ThreeVector(0.,0.,(capAssemblyHeight/2.- barrelCellHeight/2.)*zflip),
1388  logicWCExtraBorderCell,
1389  "WCExtraTowerBorderCell",
1390  logicCapAssembly,
1391  false, 0,true);
1392 
1393  logicWCExtraBorderCell->SetVisAttributes(G4VisAttributes::Invisible);
1394 
1395  G4VPhysicalVolume* physiWCExtraBorderBlackSheet =
1396  new G4PVPlacement(0,
1397  G4ThreeVector(0.,0.,0.),
1399  "WCExtraTowerBlackSheet",
1400  logicWCExtraBorderCell,
1401  false,
1402  0,true);
1403 
1404  G4LogicalBorderSurface * WaterBSExtraBorderCellSurface
1405  = new G4LogicalBorderSurface("WaterBSBarrelCellSurface",
1406  physiWCExtraBorderCell,
1407  physiWCExtraBorderBlackSheet,
1409 
1410  }
1411  //------------------------------------------------------------
1412  // add caps
1413  // -----------------------------------------------------------
1414 
1415  G4double capZ[4] = { (-WCBlackSheetThickness-1.*mm)*zflip,
1416  WCBarrelPMTOffset*zflip,
1417  WCBarrelPMTOffset*zflip,
1419  G4double capRmin[4] = { 0. , 0., 0., 0.} ;
1421  G4VSolid* solidWCCap;
1422  if(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal){
1423  solidWCCap
1424  = new G4Polyhedra("WCCap",
1425  0.*deg, // phi start
1426  totalAngle, //phi end
1427  (int)WCBarrelRingNPhi, //NPhi-gon
1428  4, // 2 z-planes
1429  capZ, //position of the Z planes
1430  capRmin, // min radius at the z planes
1431  capRmax// max radius at the Z planes
1432  );
1433  } else {
1434  // if there is an extra tower, the cap volume is a union of
1435  // to polyhedra. We have to unite both parts, because there are
1436  // PMTs that are on the border between both parts.
1437  G4Polyhedra* mainPart
1438  = new G4Polyhedra("WCCapMainPart",
1439  0.*deg, // phi start
1440  totalAngle, //phi end
1441  (int)WCBarrelRingNPhi, //NPhi-gon
1442  4, // 2 z-planes
1443  capZ, //position of the Z planes
1444  capRmin, // min radius at the z planes
1445  capRmax// max radius at the Z planes
1446  );
1447  G4double extraCapRmin[4];
1448  G4double extraCapRmax[4];
1449  for(int i = 0; i < 4 ; i++){
1450  extraCapRmin[i] = capRmin[i] != 0. ? capRmin[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.) : 0.;
1451  extraCapRmax[i] = capRmax[i] != 0. ? capRmax[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.) : 0.;
1452  }
1453  G4Polyhedra* extraSlice
1454  = new G4Polyhedra("WCCapExtraSlice",
1455  totalAngle-2.*pi, // phi start
1456  2.*pi - totalAngle -G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/(10.*m), //total phi
1457  // fortunately there are no PMTs an the gap!
1458  1, //NPhi-gon
1459  4, // z-planes
1460  capZ, //position of the Z planes
1461  extraCapRmin, // min radius at the z planes
1462  extraCapRmax// max radius at the Z planes
1463  );
1464  solidWCCap =
1465  new G4UnionSolid("WCCap", mainPart, extraSlice);
1466 
1467  //G4cout << *solidWCCap << G4endl;
1468 
1469  }
1470  // G4cout << *solidWCCap << G4endl;
1471  G4LogicalVolume* logicWCCap =
1472  new G4LogicalVolume(solidWCCap,
1473  G4Material::GetMaterial(water),
1474  "WCCapPolygon",
1475  0,0,0);
1476 
1477  G4VPhysicalVolume* physiWCCap =
1478  new G4PVPlacement(0, // no rotation
1479  G4ThreeVector(0.,0.,(-capAssemblyHeight/2.+1*mm+WCBlackSheetThickness)*zflip), // its position
1480  logicWCCap, // its logical volume
1481  "WCCap", // its name
1482  logicCapAssembly, // its mother volume
1483  false, // no boolean operations
1484  0,true); // Copy #
1485 
1486 
1487 // used for RayTracer
1488  if (Vis_Choice == "RayTracer"){
1489  if(!debugMode){
1490  G4VisAttributes* tmpVisAtt2 = new G4VisAttributes(G4Colour(1,0.5,0.5));
1491  tmpVisAtt2->SetForceSolid(true);
1492  logicWCCap->SetVisAttributes(tmpVisAtt2);
1493  logicWCCap->SetVisAttributes(G4VisAttributes::Invisible);
1494 
1495  } else{
1496 
1497  G4VisAttributes* tmpVisAtt2 = new G4VisAttributes(G4Colour(0.6,0.5,0.5));
1498  tmpVisAtt2->SetForceSolid(true);
1499  logicWCCap->SetVisAttributes(tmpVisAtt2);}}
1500 
1501 // used for OGLSX
1502  else{
1503  if(!debugMode){
1504  logicWCCap->SetVisAttributes(G4VisAttributes::Invisible);
1505  } else
1506  {G4VisAttributes* tmpVisAtt2 = new G4VisAttributes(G4Colour(.6,0.5,0.5));
1507  tmpVisAtt2->SetForceWireframe(true);
1508  logicWCCap->SetVisAttributes(tmpVisAtt2);}}
1509 
1510  //---------------------------------------------------------------------
1511  // add cap blacksheet
1512  // -------------------------------------------------------------------
1513 
1514  G4double capBlackSheetZ[4] = {-WCBlackSheetThickness*zflip, 0., 0., WCBarrelPMTOffset*zflip};
1515  G4double capBlackSheetRmin[4] = {0., 0., WCIDRadius, WCIDRadius};
1516  G4double capBlackSheetRmax[4] = {WCIDRadius+WCBlackSheetThickness,
1519  WCIDRadius+WCBlackSheetThickness};
1520  G4VSolid* solidWCCapBlackSheet;
1521  if(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal){
1522  solidWCCapBlackSheet
1523  = new G4Polyhedra("WCCapBlackSheet",
1524  0.*deg, // phi start
1525  totalAngle, //total phi
1526  WCBarrelRingNPhi, //NPhi-gon
1527  4, // z-planes
1528  capBlackSheetZ, //position of the Z planes
1529  capBlackSheetRmin, // min radius at the z planes
1530  capBlackSheetRmax// max radius at the Z planes
1531  );
1532  // G4cout << *solidWCCapBlackSheet << G4endl;
1533  } else {
1534  // same as for the cap volume
1535  G4Polyhedra* mainPart
1536  = new G4Polyhedra("WCCapBlackSheetMainPart",
1537  0.*deg, // phi start
1538  totalAngle, //phi end
1539  WCBarrelRingNPhi, //NPhi-gon
1540  4, // z-planes
1541  capBlackSheetZ, //position of the Z planes
1542  capBlackSheetRmin, // min radius at the z planes
1543  capBlackSheetRmax// max radius at the Z planes
1544  );
1545  G4double extraBSRmin[4];
1546  G4double extraBSRmax[4];
1547  for(int i = 0; i < 4 ; i++){
1548  extraBSRmin[i] = capBlackSheetRmin[i] != 0. ? capBlackSheetRmin[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.) : 0.;
1549  extraBSRmax[i] = capBlackSheetRmax[i] != 0. ? capBlackSheetRmax[i]/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.) : 0.;
1550  }
1551  G4Polyhedra* extraSlice
1552  = new G4Polyhedra("WCCapBlackSheetextraSlice",
1553  totalAngle-2.*pi, // phi start
1554  2.*pi - totalAngle -G4GeometryTolerance::GetInstance()->GetSurfaceTolerance()/(10.*m), //
1555  WCBarrelRingNPhi, //NPhi-gon
1556  4, // z-planes
1557  capBlackSheetZ, //position of the Z planes
1558  extraBSRmin, // min radius at the z planes
1559  extraBSRmax// max radius at the Z planes
1560  );
1561 
1562  solidWCCapBlackSheet =
1563  new G4UnionSolid("WCCapBlackSheet", mainPart, extraSlice);
1564  }
1565  G4LogicalVolume* logicWCCapBlackSheet =
1566  new G4LogicalVolume(solidWCCapBlackSheet,
1567  G4Material::GetMaterial("Blacksheet"),
1568  "WCCapBlackSheet",
1569  0,0,0);
1570  G4VPhysicalVolume* physiWCCapBlackSheet =
1571  new G4PVPlacement(0,
1572  G4ThreeVector(0.,0.,0.),
1573  logicWCCapBlackSheet,
1574  "WCCapBlackSheet",
1575  logicWCCap,
1576  false,
1577  0,true);
1578  G4LogicalBorderSurface * WaterBSBottomCapSurface
1579  = new G4LogicalBorderSurface("WaterBSCapPolySurface",
1580  physiWCCap,physiWCCapBlackSheet,
1582 
1583  G4VisAttributes* WCCapBlackSheetVisAtt
1584  = new G4VisAttributes(G4Colour(0.9,0.2,0.2));
1585 
1586 // used for OGLSX
1587  if (Vis_Choice == "OGLSX"){
1588 
1589  G4VisAttributes* WCCapBlackSheetVisAtt
1590  = new G4VisAttributes(G4Colour(0.9,0.2,0.2));
1591 
1592  if(!debugMode)
1593  logicWCCapBlackSheet->SetVisAttributes(G4VisAttributes::Invisible);
1594  else
1595  logicWCCapBlackSheet->SetVisAttributes(WCCapBlackSheetVisAtt);}
1596 
1597 // used for RayTracer (makes the caps blacksheet yellow)
1598  if (Vis_Choice == "RayTracer"){
1599 
1600  G4VisAttributes* WCCapBlackSheetVisAtt
1601  = new G4VisAttributes(G4Colour(1.0,1.0,0.0));
1602 
1603  if(!debugMode)
1604  //logicWCCapBlackSheet->SetVisAttributes(G4VisAttributes::Invisible); //Use this line if you want to make the blacksheet on the caps invisible to view through
1605  logicWCCapBlackSheet->SetVisAttributes(WCCapBlackSheetVisAtt);
1606  else
1607  logicWCCapBlackSheet->SetVisAttributes(WCCapBlackSheetVisAtt);}
1608 
1609  //---------------------------------------------------------
1610  // Add top and bottom PMTs
1611  // -----------------------------------------------------
1612 
1613  G4LogicalVolume* logicWCPMT = ConstructPMT(WCPMTName, WCIDCollectionName, "tank");
1614 
1615  // If using RayTracer and want to view the detector without caps, comment out the top and bottom PMT's
1616 
1617  G4double xoffset;
1618  G4double yoffset;
1619  G4int icopy = 0;
1620 
1621  G4RotationMatrix* WCCapPMTRotation = new G4RotationMatrix;
1622  if(zflip==-1){
1623  WCCapPMTRotation->rotateY(180.*deg);
1624  }
1625 
1626  // loop over the cap
1627  G4int CapNCell = WCCapEdgeLimit/WCCapPMTSpacing + 2;
1628  for ( int i = -CapNCell ; i < CapNCell; i++) {
1629  for (int j = -CapNCell ; j < CapNCell; j++) {
1630 
1631 
1632  xoffset = i*WCCapPMTSpacing + WCCapPMTSpacing*0.5;
1633  yoffset = j*WCCapPMTSpacing + WCCapPMTSpacing*0.5;
1634 
1635 
1636  G4ThreeVector cellpos = G4ThreeVector(xoffset, yoffset, 0);
1637  // G4double WCBarrelEffRadius = WCIDDiameter/2. - WCCapPMTSpacing;
1638  // double comp = xoffset*xoffset + yoffset*yoffset
1639  // - 2.0 * WCBarrelEffRadius * sqrt(xoffset*xoffset+yoffset*yoffset)
1640  // + WCBarrelEffRadius*WCBarrelEffRadius;
1641  // if ( (comp > WCPMTRadius*WCPMTRadius) && ((sqrt(xoffset*xoffset + yoffset*yoffset) + WCPMTRadius) < WCCapEdgeLimit) ) {
1642  if (((sqrt(xoffset*xoffset + yoffset*yoffset) + WCPMTRadius) < WCCapEdgeLimit) ) {
1643 
1644  G4VPhysicalVolume* physiCapPMT =
1645  new G4PVPlacement(WCCapPMTRotation,
1646  cellpos, // its position
1647  logicWCPMT, // its logical volume
1648  "WCPMT", // its name
1649  logicWCCap, // its mother volume
1650  false, // no boolean os
1651  icopy); // every PMT need a unique id.
1652 
1653  // logicWCPMT->GetDaughter(0),physiCapPMT is the glass face. If you add more
1654  // daugter volumes to the PMTs (e.g. a acryl cover) you have to check, if
1655  // this is still the case.
1656 
1657  icopy++;
1658  }
1659  }
1660  }
1661 
1662  G4cout << "total on cap: " << icopy << "\n";
1663  G4cout << "Coverage was calculated to be: " << (icopy*WCPMTRadius*WCPMTRadius/(WCIDRadius*WCIDRadius)) << "\n";
1664 
1666  G4RotationMatrix* WCPMTRotation = new G4RotationMatrix;
1667  WCPMTRotation->rotateY(90.*deg);
1668 
1669  G4double barrelCellWidth = 2.*WCIDRadius*tan(dPhi/2.);
1670  G4double horizontalSpacing = barrelCellWidth/WCPMTperCellHorizontal;
1671  G4double verticalSpacing = barrelCellHeight/WCPMTperCellVertical;
1672 
1673  for(G4double i = 0; i < WCPMTperCellHorizontal; i++){
1674  for(G4double j = 0; j < WCPMTperCellVertical; j++){
1675  G4ThreeVector PMTPosition = G4ThreeVector(WCIDRadius,
1676  -barrelCellWidth/2.+(i+0.5)*horizontalSpacing,
1677  (-barrelCellHeight/2.+(j+0.5)*verticalSpacing)*zflip);
1678 
1679  G4VPhysicalVolume* physiWCBarrelBorderPMT =
1680  new G4PVPlacement(WCPMTRotation, // its rotation
1681  PMTPosition,
1682  logicWCPMT, // its logical volume
1683  "WCPMT", // its name
1684  logicWCBarrelBorderCell, // its mother volume
1685  false, // no boolean operations
1686  (int)(i*WCPMTperCellVertical+j)
1687  ,true); // no particular field
1688 
1689 
1690  // logicWCPMT->GetDaughter(0),physiCapPMT is the glass face. If you add more
1691  // daugter volumes to the PMTs (e.g. a acryl cover) you have to check, if
1692  // this is still the case.
1693  }
1694  }
1695  //-------------------------------------------------------------
1696  // Add PMTs in extra Tower if necessary
1697  //------------------------------------------------------------
1698 
1699 
1700  if(!(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal)){
1701 
1702  G4RotationMatrix* WCPMTRotation = new G4RotationMatrix;
1703  WCPMTRotation->rotateY(90.*deg);
1704  WCPMTRotation->rotateX((2*pi-totalAngle)/2.);//align the PMT with the Cell
1705 
1706  G4double towerWidth = WCIDRadius*tan(2*pi-totalAngle);
1707 
1708  G4double horizontalSpacing = towerWidth/(WCBarrelNumPMTHorizontal-WCBarrelRingNPhi*WCPMTperCellHorizontal);
1709  G4double verticalSpacing = barrelCellHeight/WCPMTperCellVertical;
1710 
1711  for(G4double i = 0; i < (WCBarrelNumPMTHorizontal-WCBarrelRingNPhi*WCPMTperCellHorizontal); i++){
1712  for(G4double j = 0; j < WCPMTperCellVertical; j++){
1713  G4ThreeVector PMTPosition = G4ThreeVector(WCIDRadius/cos(dPhi/2.)*cos((2.*pi-totalAngle)/2.),
1714  towerWidth/2.-(i+0.5)*horizontalSpacing,
1715  (-barrelCellHeight/2.+(j+0.5)*verticalSpacing)*zflip);
1716  PMTPosition.rotateZ(-(2*pi-totalAngle)/2.); // align with the symmetry
1717  //axes of the cell
1718 
1719  G4VPhysicalVolume* physiWCBarrelBorderPMT =
1720  new G4PVPlacement(WCPMTRotation, // its rotation
1721  PMTPosition,
1722  logicWCPMT, // its logical volume
1723  "WCPMT", // its name
1724  logicWCExtraBorderCell, // its mother volume
1725  false, // no boolean operations
1726  (int)(i*WCPMTperCellVertical+j)
1727  ,true); // no particular field
1728 
1729  // logicWCPMT->GetDaughter(0),physiCapPMT is the glass face. If you add more
1730  // daugter volumes to the PMTs (e.g. a acryl cover) you have to check, if
1731  // this is still the case.
1732  }
1733  }
1734 
1735  }
1736 
1737  // # -------------------------------------- #
1738  // ##########################################
1739  // # Prototype Outer-Detector OD Hyper-K HK #
1740  // ##########################################
1741  // # -------------------------------------- #
1742 
1743  if(isODConstructed){
1744 
1745  //------------------------------------------------------------
1746  // add ODTyvek to the border cells.
1747  // We can use the same logical volume as for the normal
1748  // barrel cells.
1749  // ---------------------------------------------------------
1750 
1751  G4VPhysicalVolume* physiWCBarrelBorderCellODTyvek =
1752  new G4PVPlacement(0,
1753  G4ThreeVector(0.,0.,0.),
1755  "WCBarrelCellODTyvek",
1756  logicWCBarrelBorderCell,
1757  false,
1758  0,true);
1759 
1760  G4LogicalBorderSurface * WaterTyBarrelBorderCellSurfaceBot =
1761  new G4LogicalBorderSurface( "WaterTyBarrelBorderCellSurface",
1762  physiWCBarrelBorderCell,
1763  physiWCBarrelBorderCellODTyvek,
1765 
1766 
1767  //-------------------------------------------------------------
1768  // OD BARREL PMTs
1769  // ------------------------------------------------------------
1770 
1771  G4LogicalVolume* logicWCPMTOD = ConstructPMT(WCPMTODName, WCODCollectionName, "OD");
1772 
1774  G4RotationMatrix* WCPMTODRotation = new G4RotationMatrix;
1775  WCPMTODRotation->rotateY(270.*deg);
1776 
1777  G4double barrelODCellWidth = 2.*WCODRadius*tan(dPhi/2.);
1778  G4double horizontalODSpacing = barrelODCellWidth/WCPMTODperCellHorizontal;
1779  G4double verticalODSpacing = barrelCellHeight * (barrelODCellWidth/barrelCellWidth) / WCPMTODperCellVertical;
1780 
1781  for(G4double i = 0; i < WCPMTODperCellHorizontal; i++){
1782  for(G4double j = 0; j < WCPMTODperCellVertical; j++){
1783  G4ThreeVector PMTPosition = G4ThreeVector(WCODRadius+WCODTyvekSheetThickness,
1784  -barrelODCellWidth/2.+(i+0.5)*horizontalODSpacing+((G4int)(std::pow(-1,j))*(G4int)(WCODPMTShift)/2),
1785  -(barrelCellHeight * (barrelODCellWidth/barrelCellWidth))/2.+(j+0.5)*verticalODSpacing);
1786 
1787 
1788  G4VPhysicalVolume* physiWCBarrelPMT =
1789  new G4PVPlacement(WCPMTODRotation, // its rotation
1790  PMTPosition,
1791  logicWCPMTOD, // its logical volume
1792  "WCPMTOD", // its name
1793  logicWCBarrelBorderCell, // its mother volume
1794  false, // no boolean operations
1795  (int)(i*WCPMTODperCellVertical+j),
1796  true);
1797 
1798  }
1799  }
1800 
1801  if(!(WCBarrelRingNPhi*WCPMTperCellHorizontal == WCBarrelNumPMTHorizontal)){
1802 
1803  G4VPhysicalVolume* physiWCExtraBorderODTyvek =
1804  new G4PVPlacement(0,
1805  G4ThreeVector(0.,0.,0.),
1807  "WCExtraTowerODTyvek",
1808  logicWCExtraBorderCell,
1809  false,
1810  0,true);
1811 
1812  G4LogicalBorderSurface * WaterTyBarrelBorderCellSurfaceBot =
1813  new G4LogicalBorderSurface( "WaterTyBarrelBorderCellSurface",
1814  physiWCExtraBorderCell,
1815  physiWCExtraBorderODTyvek,
1817 
1818  G4RotationMatrix* WCPMTRotation = new G4RotationMatrix;
1819  WCPMTRotation->rotateY(270.*deg);
1820  WCPMTRotation->rotateX((2*pi-totalAngle)/2.);//align the PMT with the Cell
1821 
1822  G4double towerWidthOD = WCODRadius*tan(2*pi-totalAngle);
1823 
1824  G4double horizontalODSpacing = towerWidthOD/WCPMTODperCellHorizontal;
1825  G4double verticalODSpacing = barrelCellHeight*(WCODRadius/WCIDRadius)/WCPMTODperCellVertical;
1826 
1827  for(G4double i = 0; i < (WCPMTODperCellHorizontal); i++){
1828  for(G4double j = 0; j < WCPMTODperCellVertical; j++){
1829  G4ThreeVector PMTPosition = G4ThreeVector(WCODRadius,
1830  -towerWidthOD/2.+(i+0.5)*horizontalODSpacing,
1831  -(barrelCellHeight * (WCODRadius/WCIDRadius))/2.+(j+0.5)*verticalODSpacing);
1832  PMTPosition.rotateZ(-(2*pi-totalAngle)/2.); // align with the symmetry
1833  //axes of the cell
1834 
1835 
1836  G4VPhysicalVolume* physiWCBarrelPMT =
1837  new G4PVPlacement(WCPMTRotation, // its rotation
1838  PMTPosition,
1839  logicWCPMTOD, // its logical volume
1840  "WCPMTOD", // its name
1841  logicWCExtraBorderCell, // its mother volume
1842  false, // no boolean operations
1843  (int)(i*WCPMTODperCellVertical+j),
1844  true);
1845 
1846  }
1847  }
1848 
1849  }
1850 
1851  } // END isODConstructed
1852 
1853  return logicCapAssembly;
1854 
1855 }
1856 
1857 
1858 void ComputeWCODPMT(G4int NPMT, G4double *NPMTHorizontal, G4double *NPMTVertical){
1859  switch (NPMT) {
1860  case 0:
1861  G4cout << "N PMTs for OD is equal 0, increase coverage" << G4endl;
1862  *NPMTHorizontal = 1;
1863  *NPMTVertical = 1;
1864  break;
1865  case 1:
1866  *NPMTHorizontal = 1;
1867  *NPMTVertical = 1;
1868  break;
1869  case 2:
1870  *NPMTHorizontal = 1;
1871  *NPMTVertical = 2;
1872  break;
1873  case 3:
1874  *NPMTHorizontal = 2;
1875  *NPMTVertical = 2;
1876  break;
1877  case 4:
1878  *NPMTHorizontal = 2;
1879  *NPMTVertical = 2;
1880  break;
1881  default:
1882  if(NPMT%2 == 0){
1883  *NPMTHorizontal = NPMT/2;
1884  *NPMTVertical = NPMT/2;
1885  }else{
1886  *NPMTHorizontal = NPMT/2 + 1;
1887  *NPMTVertical = NPMT/2;
1888  }
1889 
1890  break;
1891  }
1892 }
G4Colour black(0.0, 0.0, 0.0)
G4LogicalVolume * ConstructPMT(G4String, G4String, G4String detectorElement="tank")
G4LogicalVolume * ConstructCylinder()
G4Colour cyan(0.0, 1.0, 1.0)
G4Colour white(1.0, 1.0, 1.0)
WCSimTuningParameters * WCSimTuningParams
G4Colour blue(0.0, 0.0, 1.0)
G4LogicalVolume * ConstructCaps(G4int zflip)
void ComputeWCODPMT(G4int NPMT, G4double *NPMTHorizontal, G4double *NPMTVertical)
G4Colour green(0.0, 1.0, 0.0)
G4Colour red(1.0, 0.0, 0.0)
G4Colour yellow(1.0, 1.0, 0.0)
G4Colour magenta(1.0, 0.0, 1.0)