EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HCalDetectorConstruction.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file HCalDetectorConstruction.cc
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 
27 #include "G4Box.hh"
28 #include "G4LogicalBorderSurface.hh"
29 #include "G4OpticalSurface.hh"
30 #include "G4LogicalVolume.hh"
31 #include "G4ThreeVector.hh"
32 #include "G4PVPlacement.hh"
33 
34 #include "G4SystemOfUnits.hh"
35 #include "G4VisAttributes.hh"
36 
37 #include <EicToyModel.h>
38 #include "HCalDetectorConstruction.hh"
39 
40 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
41 
42 HCalDetectorConstruction* HCalDetectorConstruction::mInstance = 0;
43 
44 HCalDetectorConstruction::HCalDetectorConstruction(): G4VUserDetectorConstruction()
45 {
46  fExpHall_x = fExpHall_y = fExpHall_z = 200.0*cm;
47 
48  mInstance = this;
49 } // HCalDetectorConstruction::HCalDetectorConstruction()
50 
51 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
52 
53 HCalDetectorConstruction::~HCalDetectorConstruction(){;}
54 
55 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
56 
57 G4double gPhotonEnergy[_GDIM_];
58 
59 const double SmallGap = 0.02*mm;
60 
61 // Assume Hamamatsu 3x3mm^2 sensors;
62 static double SiPMSize = 3.0*mm;
63 // FIXME: this is all fake;
64 static double SiPMThickness = 1.0*mm;
65 static double SensorThickness = 0.1*mm;
66 
67 // -------------------------------------------------------------------------------------
68 
69 #ifdef _USE_ZEBRA_FILTER_
70 struct HcalMaskLine {
71  // NB: Y-offset is counter from the middle;
72  double y0, width, length;
73 };
74 
75 // NB: and the other Y-symmetric 21 line;
76 #define _HCAL_MASK_LINE_NUM_ (21+1)//(2*21+1)
77 
78 static HcalMaskLine HcalMaskLines[_HCAL_MASK_LINE_NUM_] = {
79  // This is assumed to be the central line;
80  { 0.00, 1.35, 588.1},
81 
82  // Type in everything explicitely (Y-offsets are irregular);
83  { 2.25, 1.35, 168.9},
84  { 4.50, 1.35, 378.5},
85  { 6.75, 1.35, 168.9},
86  { 9.00, 1.00, 561.9},
87  { 10.90, 1.35, 247.5},
88  { 13.15, 1.35, 457.1},
89  { 15.40, 1.35, 247.5},
90  { 17.65, 1.35, 588.1},
91  { 19.90, 1.35, 247.5},
92  { 22.15, 1.35, 90.3},
93  { 24.40, 1.35, 457.1},
94  { 26.65, 1.35, 326.1},
95  { 28.90, 1.35, 90.3},
96  { 31.15, 1.00, 561.9},
97  { 33.05, 1.35, 326.1},
98  { 35.30, 1.35, 90.3},
99  { 37.55, 1.35, 483.3},
100  { 39.80, 1.35, 378.5},
101  { 42.05, 1.35, 168.9},
102  { 44.30, 1.35, 588.1},
103  { 48.00, 0.25, 840.0}};
104 #endif
105 
106 // -------------------------------------------------------------------------------------
107 
108 //#include <G4GDMLParser.hh>
109 
110 G4VPhysicalVolume *HCalDetectorConstruction::DefineHCalVolumes( void )
111 {
112 #if 0
113  {
114  // The experimental Hall;
115  G4Box* expHall_box = new G4Box("World", fExpHall_x/2, fExpHall_y/2, fExpHall_z/2);
116  G4LogicalVolume* expHall_log = new G4LogicalVolume(expHall_box, mQair, "World", 0, 0, 0);
117  G4VPhysicalVolume* expHall_phys =
118  new G4PVPlacement(0, G4ThreeVector(), expHall_log, "World", 0, false, 0);
119 
121  parser.Read("block.gdml");
122  //parser.ReadModule("00100.gdml");
123  //G4VPhysicalVolume *gdml = parser.GetWorldVolume();
124  G4LogicalVolume *gdml = parser.GetVolume("V-Product");
125  //G4LogicalVolume *gdml = parser.GetVolume("V-Open CASCADE STEP translator 6.7 110");//"V-Product");//GetWorldVolume();
126  //G4LogicalVolume *gdml = parser.GetVolume("V-Open CASCADE STEP translator 6.7 101");//"V-Product");//GetWorldVolume();
127  //gdml->SetVisAttributes(G4VisAttributes::Invisible);
128  //gdml->GetLogicalVolume()->SetVisAttributes(G4VisAttributes::Invisible);
129 
130  // Offset it more or less in sync with the beam;
131  new G4PVPlacement(0, G4ThreeVector(1.01*cm, 1.01*cm, 0), gdml, "V-Product", expHall_log, false, 0);
132  //new G4PVPlacement(0, G4ThreeVector(1.01*cm, 7.01*cm, 0), gdml, "V-Product", expHall_log, false, 0);
133  //new G4PVPlacement(0, G4ThreeVector(3.7*m, 0, 0), gdml, "V-Product", expHall_log, false, 0);
134 
135  // return gdml;//expHall_phys;
136  return expHall_phys;
137  }
138 #endif
139 
140  double TowerWidth = 100.0*mm;
141  double TowerHeight = 100.0*mm;
142  //double SteelSpacerThickness = 2.0*mm;
143 
144  // Absorber+scintillator building blocks;
145  //double SubCellLength = 13.1*mm;
146  //const unsigned SubCellNum = 64;
147  double SubCellLength = 23.4*mm;
148  // FIXME: the last 20mm steel layer problem;
149  const unsigned SubCellNum = 37;
150  // FIXME: assume all 64 cells have Pb absorber (in reality the last one was made of steel);
151  // NB: want to have some extra length for sensors;
152  double TowerLength = SubCellNum * SubCellLength + 10.0*mm;
153  //printf("Essential tower length: %7.2f\n", SubCellNum * SubCellLength);
154 
155  double TowerEnvelopeWidth = TowerWidth - 2*SmallGap;
156  double TowerEnvelopeHeight = TowerHeight - 2*SmallGap - mGeometry->mSteelSpacerThickness;
157  double TowerEnvelopeLength = TowerLength - 2*SmallGap;
158 
159  double SubCellWidth = 96.0*mm;
160  double SubCellHeight = TowerEnvelopeHeight - 2*SmallGap;
161 
162  double SubCellEnvelopeWidth = SubCellWidth - 2*SmallGap;
163  double SubCellEnvelopeHeight = SubCellHeight - 2*SmallGap;
164  double SubCellEnvelopeLength = SubCellLength - 2*SmallGap;
165 
166  double AbsorberPlateWidth = SubCellWidth - 2*SmallGap;
167  double AbsorberPlateHeight = SubCellHeight - 2*SmallGap;
168  // FIXME: ignore paint layer; just give absorber plates some
169  // optical properties (diffuse reflection, etc);
170  double AbsorberPlateThickness = 20.0*mm;
171  //double AbsorberPlateThickness = 10.0*mm;
172  //@@@double AbsorberPlateThickness = 7.5*mm;
173  //double AbsorberPlateThickness = 5.0*mm;
174 
175  // Scintillator parameters; assume they are for sure smaller than subcell XY-size;
176  double ScintillatorPlateThickness = 3.0*mm;
177  //double ScintillatorPlateThickness = 2.5*mm;
178  //@@@double ScintillatorPlateThickness = 5.0*mm;
179  //double ScintillatorPlateThickness = 7.5*mm;
180  double ScintillatorPlateWidth = 95.0*mm;
181  double ScintillatorPlateHeight = 97.0*mm;
182  double ScPlateAirAppendixLength = 0.3*mm;
183 
184  // WLS parameters;
185  double WlsPlateThickness = 3.0*mm;
186  double WlsPlateLength = SubCellNum * SubCellLength;
187  double WlsPlateHeight = 97.0*mm;
188  // Artificial air volume; its thickness does not really matter;
189  double WlsPlateAirAppendixLength = 1.0*mm;
190 
191 
192 #if _QQQ_
193  // Let it be 100um; does not really matter as long as all this crap fits into 100mm wide tower;
194  double MetallizedMylarThickness = 0.05*mm;
195 #ifdef _USE_ZEBRA_FILTER_
196  double ZebraFilterThickness = 0.05*mm;
197 #endif
198 
199  double OpticalGlueThickness = _HCAL_OPTICAL_GLUE_THICKNESS_;
200 #endif
201 
202  auto eic = EicToyModel::Instance();
203 
204  // Print IR dimensions;
205  printf("\n\nIR box size: Z +/- %.2f [cm], R ~ %.2f [cm]\n\n",
206  eic->GetIrRegionLength()/2, eic->GetIrRegionRadius());
207 
208  // The easiest: ask the model to build its IR world;
209  auto expHall_phys = eic->ConstructG4World();
210  expHall_phys->GetLogicalVolume()->SetVisAttributes(G4VisAttributes::Invisible);
211 
212 
213 
214  // Construct the integration volumes geometry, internally;
215  TFile fin(argv[1]);
216  dynamic_cast<EicToyModel *>(fin.Get("EicToyModel"));
217  eic->Construct();
218  // Populate G4 world by these volumes;
219  eic->PlaceG4Volumes(expHall_phys);
220 
221  // Place "MyHCal" tower matrix into the integration volume bubble instead of the world;
222  new G4PVPlacement(0, G4ThreeVector(0, 0, zOffset), myhcal_log, "MyHCal", expHall_log, false, 0);
223  auto hcal_bubble_log = eic->fwd()->get("HCal")->GetG4Volume()->GetLogicalVolume();
224  new G4PVPlacement(0, G4ThreeVector(0, 0, 0), myhcal_log, "MyHCal", hcal_bubble_log, false, 0);
225 
226 
227 
228  //auto expHall_log = expHall_phys->GetLogicalVolume();
229  auto expHall_log = eic->bck()->get("HCal")->GetG4Volume()->GetLogicalVolume();
230 
231  // The experimental Hall;
232  //G4Box* expHall_box = new G4Box("World", fExpHall_x/2, fExpHall_y/2, fExpHall_z/2);
233  //G4LogicalVolume* expHall_log = new G4LogicalVolume(expHall_box, mQair, "World", 0, 0, 0);
234  //G4VPhysicalVolume* expHall_phys =
235  // new G4PVPlacement(0, G4ThreeVector(), expHall_log, "World", 0, false, 0);
236  expHall_phys->GetLogicalVolume()->SetVisAttributes(G4VisAttributes::Invisible);
237 
239 
240  // Front steel plate; assume rectangular box, wedge shape is an overkill here;
241  if (mGeometry->mUseFrontSteelPlate) {
242  G4Box *front_plate_box =
243  new G4Box("FrontPlate", (mGeometry->mXdim*TowerWidth)/2, (mGeometry->mYdim*TowerHeight)/2,
244  mGeometry->mFrontSteelPlateThickness/2);
245  G4LogicalVolume *front_plate_log = new G4LogicalVolume(front_plate_box, mSteel, "FrontPlate", 0, 0, 0);
246  {
247  double zOffset = -(TowerLength + mGeometry->mFrontSteelPlateThickness)/2;
248 
249  new G4PVPlacement(0, G4ThreeVector(0, 0, zOffset),
250  front_plate_log, "FrontPlate", expHall_log, false, 0);
251  }
252  } //if
253 
254  // The "large" (tower matrix) periodic part;
255  G4Box *tower_box = new G4Box("Tower", TowerWidth/2, TowerHeight/2, TowerLength/2);
256  // NB: assume towers are optically isolated; make them out of "air without optical
257  // properties"; NB: inner envelopes will be filled with regular air (so light can travel inside);
258  G4LogicalVolume *tower_log = new G4LogicalVolume(tower_box, mQair, "Tower", 0, 0, 0);
259  for(unsigned ix=0; ix<mGeometry->mXdim; ix++)
260  for(unsigned iy=0; iy<mGeometry->mYdim; iy++) {
261  double xOffset = (ix-(mGeometry->mXdim-1)/2.0)*TowerWidth;
262  double yOffset = (iy-(mGeometry->mYdim-1)/2.0)*TowerHeight;
263 
264  //printf("%2d %2d\n", ix, iy);
265  //++new G4PVPlacement(0, G4ThreeVector(xOffset, yOffset, 0),
266  new G4PVPlacement(0, G4ThreeVector(xOffset + 50*cm, yOffset - 0*cm, 0),
267  tower_log, "Tower", expHall_log, false, ix*mGeometry->mYdim + iy);
268  } //for ix..iy
269 
270 #if _TODAY_
271  // Tower inner air envelope; see comment for SubCell envelope below;
272  G4Box *tower_envelope_box =
273  new G4Box("TowerEnvelope", TowerEnvelopeWidth/2, TowerEnvelopeHeight/2, TowerEnvelopeLength/2);
274  G4LogicalVolume *tower_envelope_log =
275  new G4LogicalVolume(tower_envelope_box, mAir, "TowerEnvelope", 0, 0, 0);
276 #ifdef _HCAL_USE_MYLAR_REFLECTOR_
277  G4VPhysicalVolume *tower_envelope_phys = 0;
278 #endif
279  {
280  double yOffset = -TowerHeight/2 + SmallGap + TowerEnvelopeHeight/2;
281 #ifdef _HCAL_USE_MYLAR_REFLECTOR_
282  tower_envelope_phys =
283 #endif
284  new G4PVPlacement(0, G4ThreeVector(0, yOffset, 0), tower_envelope_log, "TowerEnvelope", tower_log, false, 0);
285  }
286 
287  // The "small" periodic part; assume dimensions defined by lead/antimony plate XY-size;
288  {
289  G4Box *subcell_box = new G4Box("SubCell", SubCellWidth/2, SubCellHeight/2, SubCellLength/2);
290  G4LogicalVolume *subcell_log = new G4LogicalVolume(subcell_box, mAir, "SubCell", 0, 0, 0);
291  {
292  // double xOffset = -TowerEnvelopeWidth/2 + SmallGap + SubCellEnvelopeWidth/2;
293  double xOffset = -TowerEnvelopeWidth/2 + SmallGap + SubCellWidth/2;
294 
295  for(unsigned iq=0; iq<SubCellNum; iq++) {
296  double zOffset = (iq-(SubCellNum-1)/2.0)*SubCellLength;
297 
298  /*if (!iq || iq == 32 || iq == SubCellNum-1)*/ {
299  //printf("@@@ %7.2f\n", zOffset);
300  new G4PVPlacement(0, G4ThreeVector(xOffset, 0, zOffset), subcell_log,
301  "SubCell", tower_envelope_log, false, iq);
302  } //if
303  } //for iq
304  }
305 
306  // Inner air envelope volume; need it in order to define surfaces like air-to-absorber
307  // for a single subcell physical volume rather than to all its copies;
308  G4Box *subcell_envelope_box =
309  new G4Box("SubCellEnvelope", SubCellEnvelopeWidth/2, SubCellEnvelopeHeight/2, SubCellEnvelopeLength/2);
310  G4LogicalVolume *subcell_envelope_log =
311  new G4LogicalVolume(subcell_envelope_box, mAir, "SubCellEnvelope", 0, 0, 0);
312  G4VPhysicalVolume *subcell_envelope_phys =
313  new G4PVPlacement(0, G4ThreeVector(), subcell_envelope_log, "SubCellEnvelope", subcell_log, false, 0);
314 
315  // Scintillator plate;
316  {
317  G4Box *scintPlate_box = new G4Box("ScintPlate", ScintillatorPlateWidth/2, ScintillatorPlateHeight/2,
318  ScintillatorPlateThickness/2);
319  G4LogicalVolume *scintPlate_log = new G4LogicalVolume(scintPlate_box, mEJ212, "ScintPlate", 0, 0, 0);
320 
321  // Assume plate is shifted to one side of the air envelope, away from the WLS (worst case);
322  double xOffset = -SubCellEnvelopeWidth /2 + SmallGap + ScintillatorPlateWidth /2 + ScPlateAirAppendixLength;
323  double yOffset = -SubCellEnvelopeHeight/2 + SmallGap + ScintillatorPlateHeight /2;
324  double zOffset = -SubCellEnvelopeLength/2 + SmallGap + ScintillatorPlateThickness/2;
325 
326  G4VPhysicalVolume *sc_phys =
327  new G4PVPlacement(0, G4ThreeVector(xOffset, yOffset, zOffset), scintPlate_log, "ScintPlate",
328  subcell_envelope_log, false, 0);
329 
330  // Then add a small "piece of air" next to the far-from-WLS side and define a diffusive paint;
331  // FIXME: unify with the WLS code;
332  {
333  double xxOffset = -SubCellEnvelopeWidth /2 + SmallGap + ScPlateAirAppendixLength/2;
334 
335  G4Box *xx_box = new G4Box("XxPlate", ScPlateAirAppendixLength/2, ScintillatorPlateHeight/2,
336  ScintillatorPlateThickness/2);
337  G4LogicalVolume *xx_log = new G4LogicalVolume(xx_box, mAir, "XxPlate", 0, 0, 0);
338  G4PVPlacement *xx_phys =
339  new G4PVPlacement(0, G4ThreeVector(xxOffset, yOffset, zOffset),
340  xx_log, "XxPlate", subcell_envelope_log, false, 0);
341 
342  // NB: physical surface interface seems to have precedence over logical ones, so this
343  // does not disturb the other 5 facets (pretty much exactly what I need);
344  G4OpticalSurface* opScPaintSurface =
345  CreateLambertianSurface("ScPaintSurface", _BC620_PAINT_REFLECTIVITY_);
346  new G4LogicalBorderSurface("ScPaintAirSurface", sc_phys, xx_phys, opScPaintSurface);
347  new G4LogicalBorderSurface("AirPaintScSurface", xx_phys, sc_phys, opScPaintSurface);
348  }
349 
350  // NB: if 100% reflectivity and ideally polished surface is selected, no reason to overcomplicate
351  // things -> just let GEANT use material refractive indices;
352  if (_EJ212_SCINTILLATOR_SURFACE_REFLECTIVITY_ != 1.00 || _EJ212_SCINTILLATOR_SURFACE_ROUGHNESS_)
353  DefineSkinSurface("ScintSurface", scintPlate_log, _EJ212_SCINTILLATOR_SURFACE_REFLECTIVITY_,
354  _EJ212_SCINTILLATOR_SURFACE_ROUGHNESS_);
355  }
356 
357  // The absorber (lead+antimony) plate;
358  {
359  G4Box* absorber_box =
360  new G4Box("Absorber", AbsorberPlateWidth/2, AbsorberPlateHeight/2, AbsorberPlateThickness/2);
361 #ifdef _USE_STEEL_ABSORBER_
362  G4LogicalVolume* absorber_log = new G4LogicalVolume(absorber_box, mSteel, "Absorber", 0, 0, 0);
363 #else
364  G4LogicalVolume* absorber_log = new G4LogicalVolume(absorber_box, mAbsorber, "Absorber", 0, 0, 0);
365 #endif
366 
367  {
368  double zOffset = SubCellEnvelopeLength/2 - SmallGap - AbsorberPlateThickness/2;
369 
370  G4VPhysicalVolume* absorber_phys =
371  new G4PVPlacement(0, G4ThreeVector(0, 0, zOffset), absorber_log, "Absorber",
372  subcell_envelope_log, false, 0);
373 
374  // NB: don't touch anything here without a thorough check!; here play a bit different game,
375  // than with the scintillator; care only about photons in air->absorber direction and force
376  // pure diffuse (Lambertian) reflection; the easiest way to get this is to use
377  // 'groundfrontpainted' surface finish;
378  G4OpticalSurface* opAbsorberSurface =
379  CreateLambertianSurface("AbsorberSurface", _ABSORBER_PAINT_REFLECTIVITY_);
380  new G4LogicalBorderSurface("AbsorberSurface", subcell_envelope_phys, absorber_phys, opAbsorberSurface);
381  }
382  }
383  }
384 
385  // WLS volume;
386  double wlsXoffset = TowerEnvelopeWidth/2 - WlsPlateThickness/2 - SmallGap;
387  double wlsYoffset = -TowerEnvelopeHeight/2 + SmallGap + WlsPlateHeight/2;
388  {
389  G4Box *wls_box = new G4Box("WlsPlate", WlsPlateThickness/2, WlsPlateHeight/2, WlsPlateLength/2);
390  G4LogicalVolume *wls_log = new G4LogicalVolume(wls_box, mEJ280, "WlsPlate", 0, 0, 0);
391 
392  G4VPhysicalVolume *wls_phys =
393  new G4PVPlacement(0, G4ThreeVector(wlsXoffset, wlsYoffset, 0), wls_log, "WlsPlate", tower_envelope_log, false, 0);
394 
395  // Same logic as with the scintillator plate: fist make all 6 facets "almost 100%" reflecting;
396  if (_WLS_SURFACE_REFLECTIVITY_ != 1.00 || _WLS_SURFACE_ROUGHNESS_)
397  DefineSkinSurface("WlsSurface", wls_log, _WLS_SURFACE_REFLECTIVITY_,
398  _WLS_SURFACE_ROUGHNESS_);
399 
400  // Then add a small "piece of air" next to the rear side and define a diffusive paint;
401  {
402  G4Box *qq_box = new G4Box("QqPlate", WlsPlateThickness/2, WlsPlateHeight/2, WlsPlateAirAppendixLength/2);
403  G4LogicalVolume *qq_log = new G4LogicalVolume(qq_box, mAir, "QqPlate", 0, 0, 0);
404  G4PVPlacement *qq_phys =
405  new G4PVPlacement(0, G4ThreeVector(wlsXoffset, wlsYoffset, -(WlsPlateLength+WlsPlateAirAppendixLength)/2),
406  qq_log, "QqPlate", tower_envelope_log, false, 0);
407 
408  // NB: physical surface interface seems to have precedence over logical ones, so this
409  // does not disturb the other 5 facets (pretty much exactly what I need);
410  G4OpticalSurface* opWlsPaintSurface =
411  CreateLambertianSurface("WlsPaintSurface", _BC620_PAINT_REFLECTIVITY_);
412  new G4LogicalBorderSurface("WlsPaintAirSurface", wls_phys, qq_phys, opWlsPaintSurface);
413  new G4LogicalBorderSurface("AirPaintWlsSurface", qq_phys, wls_phys, opWlsPaintSurface);
414  }
415  }
416 
417  // Reflective mylar volume; length and height are the same as WLS plate;
418 #ifdef _HCAL_USE_MYLAR_REFLECTOR_
419  {
420  G4Box *mylar_box = new G4Box("Mylar", MetallizedMylarThickness/2, WlsPlateHeight/2, WlsPlateLength/2);
421  //G4Box *mylar_box = new G4Box("Mylar", 80*mm/2, 80*mm/2, 3*mm/2);
422  G4LogicalVolume *mylar_log = new G4LogicalVolume(mylar_box, mMylar, "Mylar", 0, 0, 0);
423 
424  double xOffset = (TowerEnvelopeWidth - MetallizedMylarThickness)/2 - SmallGap;
425  G4PVPlacement *mylar_phys =
426  new G4PVPlacement(0, G4ThreeVector(xOffset, wlsYoffset, 0), mylar_log, "Mylar", tower_envelope_log, false, 0);
427  //new G4PVPlacement(0, G4ThreeVector(), mylar_log, "Mylar", tower_envelope_log, false, 0);
428 
429  // FIXME: may eventually want to unify with CreateLambertianSurface() call;
430  G4OpticalSurface* opMylarSurface = new G4OpticalSurface("MylarSurface");
431  opMylarSurface->SetType(dielectric_metal);
432  // NB: assume specular reflection, right?;
433  opMylarSurface->SetFinish(polished);
434  opMylarSurface->SetModel(unified);
435 
436  G4double reflectivity[_GDIM_];
437  for(int iq=0; iq<_GDIM_; iq++)
438  reflectivity[iq] = _HCAL_MYLAR_REFLECTIVITY_;
439  G4MaterialPropertiesTable *mylarST = new G4MaterialPropertiesTable();
440  mylarST->AddProperty("REFLECTIVITY", gPhotonEnergy, reflectivity, _GDIM_);
441  opMylarSurface->SetMaterialPropertiesTable(mylarST);
442 
443  new G4LogicalBorderSurface("MylarSurface", tower_envelope_phys, mylar_phys, opMylarSurface);
444  }
445 #endif
446 
447  // Install zebra filter between scintillator plates and the WLS;
448 #ifdef _USE_ZEBRA_FILTER_
449  {
450  double xOffset = wlsXoffset - WlsPlateThickness/2 - SmallGap - ZebraFilterThickness/2;
451 
452  // Loop through all of them and install absorpting volumes;
453  for(unsigned iq=0; iq<_HCAL_MASK_LINE_NUM_; iq++) {
454  HcalMaskLine *line = HcalMaskLines + iq;
455 
456  char name[1024];
457  snprintf(name, 1024-1, "ZebraLine%2d", iq);
458 
459  G4Box *black_box = new G4Box(name, ZebraFilterThickness/2*mm, line->width/2*mm, line->length/2*mm);
460  G4LogicalVolume *black_log = new G4LogicalVolume(black_box, mMylar, name, 0, 0, 0);
461 
462  double zOffset = (WlsPlateLength - line->length*mm)/2;
463 
464  for(unsigned tb=0; tb<2; tb++) {
465  double yOffset = wlsYoffset + (tb ? -1.0 : 1.0)*line->y0*mm;
466 
467  // Only one central line, clear;
468  if (!iq && tb) continue;
469 
470  //G4VPhysicalVolume *black_phys =
471  new G4PVPlacement(0, G4ThreeVector(xOffset, yOffset, zOffset), black_log, name, tower_envelope_log, false, tb);
472  } //for tb
473  } //for iq
474  }
475 #endif
476 
477  // Use fake "sensor", directly attached to WLS and matching its size;
478  {
479  G4Box *sipm_box = new G4Box("SiPM", SiPMSize/2, WlsPlateHeight/2, SiPMThickness/2);
480  G4LogicalVolume *sipm_log = new G4LogicalVolume(sipm_box, mSilicon, "SiPM", 0, 0, 0);
481  G4VisAttributes *sipmVisAtt = new G4VisAttributes(G4Colour(0.,1.,1.));
482  sipm_log->SetVisAttributes(sipmVisAtt);
483 
484  // NB: keep SmallGap here in order to avoid off-time shallow angle travel in WLS;
485  double zOffsetSiPM = WlsPlateLength/2 + /*OpticalGlueThickness +*/ SiPMThickness/2 + SmallGap;
486 
487  new G4PVPlacement(0, G4ThreeVector(wlsXoffset, wlsYoffset, zOffsetSiPM), sipm_log,
488  "SiPM", tower_envelope_log, false, 0);
489 
490  // SiPM "sensitive layer"; FIXME: do it better later;
491  G4Box *sensor_box = new G4Box("Sensor", SiPMSize/2, WlsPlateHeight/2, SensorThickness/2);
492  G4LogicalVolume *sensor_log = new G4LogicalVolume(sensor_box, mQair, "Sensor", 0, 0, 0);
493  new G4PVPlacement(0, G4ThreeVector(), sensor_log, "Sensor", sipm_log, false, 0);
494  }
495 
496 #if _TODAY_
497  // SiPM volumes; FIXME: for now assume direct WLS->glue->SiPM contact
498  // with no reflections, etc; NB: SiPM is an envelope here (sensitive metal layer is inside);
499  G4Box *opt_glue_box = new G4Box("OptGlue", SiPMSize/2, SiPMSize/2, OpticalGlueThickness/2);
500  G4LogicalVolume *opt_glue_log = new G4LogicalVolume(opt_glue_box, mRTV3145, "OptGlue", 0, 0, 0);
501 
502  G4Box *sipm_box = new G4Box("SiPM", SiPMSize/2, SiPMSize/2, SiPMThickness/2);
503  G4LogicalVolume *sipm_log = new G4LogicalVolume(sipm_box, mSilicon, "SiPM", 0, 0, 0);
504  G4VisAttributes *sipmVisAtt = new G4VisAttributes(G4Colour(0.,1.,1.));
505  sipm_log->SetVisAttributes(sipmVisAtt);
506  {
507  //double xOffset = (TowerEnvelopeWidth - WlsPlateThickness)/2 - SmallGap;
508  double zOffsetGlue = (WlsPlateLength + OpticalGlueThickness)/2;
509  double zOffsetSiPM = WlsPlateLength/2 + OpticalGlueThickness + SiPMThickness/2;
510 
511 #ifdef _USE_31_SIPM_PER_TOWER_
512  for(unsigned iq=0; iq<31; iq++) {
513  //for(unsigned iq=15; iq<=15; iq++) {
514  // FIXME: should a small WLS plate Y-offset be taken into account here?;
515  double yOffset = (iq-15.0)*3.02*mm;
516 
517  //G4VPhysicalVolume *opt_glue_phys =
518  new G4PVPlacement(0, G4ThreeVector(wlsXoffset, yOffset, zOffsetGlue), opt_glue_log,
519  "OptGlue", tower_envelope_log, false, iq);
520 
521  //G4VPhysicalVolume *sipm_phys =
522  new G4PVPlacement(0, G4ThreeVector(wlsXoffset, yOffset, zOffsetSiPM), sipm_log,
523  "SiPM", tower_envelope_log, false, iq);
524  } //for iq
525 #else
526  // 2x4 SiPMs, located at known Y-offsets;
527  for(unsigned tb=0; tb<2; tb++)
528  for(unsigned iq=0; iq<4; iq++) {
529  // FIXME: should a small WLS plate Y-offset be taken into account here?;
530  double yOffset = (tb ? -1.0 : 1.0)*(iq+1)*10.0*mm;
531 
532  //G4VPhysicalVolume *opt_glue_phys =
533  new G4PVPlacement(0, G4ThreeVector(wlsXoffset, yOffset, zOffsetGlue), opt_glue_log,
534  "OptGlue", tower_envelope_log, false, tb*4+iq);
535 
536  //G4VPhysicalVolume *sipm_phys =
537  new G4PVPlacement(0, G4ThreeVector(wlsXoffset, yOffset, zOffsetSiPM), sipm_log,
538  "SiPM", tower_envelope_log, false, tb*4+iq);
539  } //for tb..iq
540 #endif
541  }
542 
543  // SiPM sensitive layer; FIXME: do it better later; for now assume
544  G4Box *sensor_box = new G4Box("Sensor", SiPMSize/2, SiPMSize/2, SensorThickness/2);
545  G4LogicalVolume *sensor_log = new G4LogicalVolume(sensor_box, mQair, "Sensor", 0, 0, 0);
546  new G4PVPlacement(0, G4ThreeVector(), sensor_log, "Sensor", sipm_log, false, 0);
547 #endif
548 
549  // Tower steel spacers; assume I can pack it without gaps (optical part will proceed in
550  // the light tight air envelope anyway); so it's only the steel material which matters;
551  if (mGeometry->mUseSteelSpacers) {
552  G4Box *spacer_box = new G4Box("Spacer", TowerWidth/2, mGeometry->mSteelSpacerThickness/2, TowerLength/2);
553  G4LogicalVolume *spacer_log = new G4LogicalVolume(spacer_box, mSteel, "Spacer", 0, 0, 0);
554  {
555  double yOffset = TowerHeight/2 - mGeometry->mSteelSpacerThickness/2;
556 
557  new G4PVPlacement(0, G4ThreeVector(0, yOffset, 0),
558  spacer_log, "Spacer", tower_log, false, 0);
559  }
560  } //if
561 #endif
562 
563  return expHall_phys;
564 } // HCalDetectorConstruction::DefineHCalVolumes()
565 
566 // -------------------------------------------------------------------------------------
567 
568 G4VPhysicalVolume* HCalDetectorConstruction::Construct()
569 {
570  // Global photon energy range; [360..600] nm;
571  for(int iq=0; iq<_GDIM_; iq++)
572  gPhotonEnergy[iq] = 1240.0/(600.0 - iq*10.)*eV;
573 
574  // Chemical elements;
575  DefineElements();
576 
577  // Materials;
578  DefineMaterials();
579 
580  // HCal volumes;
581  return DefineHCalVolumes();
582 } // HCalDetectorConstruction::Construct()
583 
584 // -------------------------------------------------------------------------------------
585