G4StationConstruction.cc
Go to the documentation of this file.
2 
3 #include <fwk/RunController.h>
4 #include <fwk/CentralConfig.h>
5 
6 #include <utl/CoordinateSystem.h>
7 #include <utl/Point.h>
8 #include <utl/TabulatedFunction.h>
9 #include <utl/Reader.h>
10 #include <utl/AugerUnits.h>
11 #include <utl/AugerException.h>
12 #include <utl/Math.h>
13 
14 #include <G4PhysicalConstants.hh>
15 #include <G4SystemOfUnits.hh>
16 #include <G4PVReplica.hh>
17 
18 #include <vector>
19 #include <sstream>
20 #include <algorithm>
21 
22 using sdet::SDetector;
25 using utl::Point;
27 using utl::Branch;
28 
29 using namespace fwk;
30 
31 using namespace std;
32 
33 
34 namespace G4StationSimulatorOG {
35 
36  // declare variables that static members above refer to.
37  G4ThreeVector G4StationConstruction::fgTankCenter;
38 
39  double G4StationConstruction::fgTankRadius = 0;
40  double G4StationConstruction::fgTankHalfHeight = 0;
41  double G4StationConstruction::fgTankThickness = 0;
42 
43  double G4StationConstruction::fgHeightz = 0;
44  double G4StationConstruction::fgPmtRmax = 0;
45  double G4StationConstruction::fgPmtRzmax = 0;
46  double G4StationConstruction::fgInterfaceRmax = 0;
47  double G4StationConstruction::fgInterfaceRzmax = 0;
48  double G4StationConstruction::fgDomeRmax = 0;
49  double G4StationConstruction::fgDomeRzmax = 0;
50 
51  double G4StationConstruction::fPmtRmin_SPMT = 0;
52  double G4StationConstruction::fPmtRmax_SPMT = 0;
53  double G4StationConstruction::fInterfaceRadius_SPMT = 0;
54  double G4StationConstruction::fDomeRadius_SPMT = 0;
55  double G4StationConstruction::fGlassThickness_SPMT = 0;
56  double G4StationConstruction::fInterfaceThickness_SPMT = 0;
57  double G4StationConstruction::fDomeThickness_SPMT = 0;
58 
59  TabulatedFunction G4StationConstruction::fgInterfaceRINDEX;
60  TabulatedFunction G4StationConstruction::fgPmtdomeRINDEX;
61  TabulatedFunction G4StationConstruction::fgInterfaceABSORPTION;
62  TabulatedFunction G4StationConstruction::fgPmtdomeABSORPTION;
63 
64  double G4StationConstruction::fgSIGMA_ALPHA = 0;
65 
66  TabulatedFunction G4StationConstruction::fgLinerREFLECTIVITY;
67  TabulatedFunction G4StationConstruction::fgLinerSPECULARLOBECONSTANT;
68  TabulatedFunction G4StationConstruction::fgLinerSPECULARSPIKECONSTANT;
69  TabulatedFunction G4StationConstruction::fgLinerBACKSCATTERCONSTANT;
70  TabulatedFunction G4StationConstruction::fgWaterABSORPTION;
71 
72  //
73 
74  const double kDistanceToG4 = CLHEP::m / utl::m;
75  const double kEnergyToG4 = CLHEP::eV / utl::eV;
76 
77 
78  // helpers
79 
80  template<class T>
81  inline
82  void
83  Scale(T& v, const double factor)
84  {
85  for (auto& x : v)
86  x *= factor;
87  }
88 
89 
90  template<class T>
91  inline
92  void
93  Scale(const T& b, const T& e, const double factor)
94  {
95  for (auto it = b; it != e; ++it)
96  *it *= factor;
97  }
98 
99 
100  template<class T>
101  inline
102  void
103  Renew(T* (&p), T* const val)
104  {
105  delete p;
106  p = val;
107  }
108 
109 
110  // TODO this function needs to be removed; suitable member pointers replaced with local vars
111  // Needed for replication of identical logical volumes places in
112  // different postions and, therefore, generating different physical volumes
113  template<class T>
114  inline
115  void
116  NotRenew(T* (&p), T* const val)
117  {
118  p = val;
119  }
120 
121 
122  inline
123  G4ThreeVector
125  {
126  const utl::Point::Triple t = p.GetCoordinates(cs);
127  return kDistanceToG4 * G4ThreeVector(t.get<0>(), t.get<1>(), t.get<2>());
128  }
129 
130 
131  template<class Material>
132  inline
133  void
134  AddProperty(Material* const m, const char* const name, const TabulatedFunction& f)
135  {
136  // const-correctness of G4 is broken, AddProperty actually does not modify the arrays
137  m->AddProperty(name, (double*)&f.XFront(), (double*)&f.YFront(), f.GetNPoints());
138  }
139 
140 
141  G4StationConstruction::G4StationConstruction(const double simRadius, const bool umdEnabled,
142  const double scintYield, const bool martaEnabled) :
143  fG4StationSimulator(
144  dynamic_cast<G4StationSimulator&>(RunController::GetInstance().GetModule("G4StationSimulatorOG"))
145  )
146  {
147  /* Set hardware version. This is used in determining whether or not
148  to set xmlparameters and construct and register hardware-version-dependent volumes (e.g.
149  those relating to the small PMT and the scintillator) */
150 
151  const auto& dStation = G4StationSimulator::fgCurrent.GetDetectorStation();
152  fHasSmallPMT = dStation.HasSmallPMT();
153  fHasScintillator = dStation.HasScintillator();
154  // Needed to be consistent with CachedShowerRegenerator area of injection (NB: variable loaded with units)
155  fSimulationRadius = simRadius;
156  fUMDEnabled = umdEnabled;
157  fScintYield = scintYield;
158  fMARTAEnabled = martaEnabled;
159 
163 
164  // disable solar panel, electronics box for now:
165 
167 
168  fNistManager = G4NistManager::Instance();
169  }
170 
171 
172  void
174  {
175  // The "experimental hall" in which the detector is contained:
176  const double exp_hall_side_side = fSimulationRadius;
177 
178  // The ground beneath the tank
180 
181  fExpHall_x = exp_hall_side_side;
182  fExpHall_y = exp_hall_side_side;
184 
185  // The position of the center of the tank in the local Geant4 coordinate system
186  fTankPos_x = 0;
187  fTankPos_y = 0;
188  fTankPos_z = 0;
189  }
190 
191 
192  void
194  {
195  const auto& dStation = G4StationSimulator::fgCurrent.GetDetectorStation();
196  // Set tank properties
197  fgTankRadius = dStation.GetRadius() * kDistanceToG4;
198  fgTankHalfHeight = 0.5 * dStation.GetHeight() * kDistanceToG4;
199  fgTankThickness = dStation.GetThickness() * kDistanceToG4;
200 
201  fgTankCenter =
202  G4ThreeVector(fTankPos_x, fTankPos_y, fTankPos_z) +
203  G4ThreeVector(0, 0, fgTankHalfHeight + fgTankThickness);
204 
205  // Set pmt position (relative to the center of the tank)
206 
207  const auto cs = dStation.GetLocalCoordinateSystem();
208 
209  for (auto& p : fPMTs)
210  p.Clear();
211  fPMTs.clear();
212  for (const auto& dpmt : dStation.PMTsRange()) {
213  PMTConstruction pmt;
214  pmt.fPMTPosition = Convert(dpmt.GetPosition(), cs);
215  pmt.fId = dpmt.GetId();
216  pmt.fPMTType = dpmt.GetType();
217  fPMTs.push_back(pmt);
218  }
219 
220  // Set pmt optical properties
221  // For now, assume that all pmts have the same properties
222 
223  fPmtfaceRINDEX = dStation.GetPMT(1).GetFaceRefractionIndex();
225 
226  fgInterfaceRINDEX = dStation.GetPMT(1).GetRTVRefractionIndex();
227  Scale(fgInterfaceRINDEX.XBegin(), fgInterfaceRINDEX.XEnd(), kEnergyToG4);
228 
229  fgPmtdomeRINDEX = dStation.GetPMT(1).GetDomeRefractionIndex();
230  Scale(fgPmtdomeRINDEX.XBegin(), fgPmtdomeRINDEX.XEnd(), kEnergyToG4);
231 
232  // These parameters specify the pmt geometry (already converted to G4 units)
233 
244  fgDomeRmax = fFaceRadius + fInterfaceThickness + fDomeThickness;
245  fgDomeRzmax = fFaceRadiusz + fInterfaceThickness + fDomeThickness;
246 
247  G4double alpha = 0;
248  // Taking into account that the radius of the photocathode is fFaceActiveRadius
249  if (fFaceActiveRadius >= 114*mm) {
250  fFaceActiveRadius = 113.926112814*mm;
251  fgHeightz = 0;
252  } else if (fFaceActiveRadius > 97.27*mm) {
253  alpha = acos(1/62.*(fFaceActiveRadius/mm - 133*sin(47*deg) + 62*cos(43*deg)));
254  fgHeightz = 62*mm*sin(alpha);
255  } else {
256  alpha = asin(fFaceActiveRadius/mm/133);
257  fgHeightz = (133*cos(alpha) - (133 - 62)*cos(47*deg))*mm;
258  }
259 
260  // Set liner properties
261 
262  fgSIGMA_ALPHA = dStation.GetLinerSigmaAlpha();
263 
264  fgLinerREFLECTIVITY = dStation.GetLinerReflectivity();
266 
267  fgLinerSPECULARLOBECONSTANT = dStation.GetLinerSpecularLobe();
268  Scale(fgLinerSPECULARLOBECONSTANT.XBegin(), fgLinerSPECULARLOBECONSTANT.XEnd(), kEnergyToG4);
269 
270  fgLinerSPECULARSPIKECONSTANT = dStation.GetLinerSpecularSpike();
271  Scale(fgLinerSPECULARSPIKECONSTANT.XBegin(), fgLinerSPECULARSPIKECONSTANT.XEnd(), kEnergyToG4);
272 
273  // Set water properties
274 
275  fgWaterABSORPTION = dStation.GetWaterAbsorptionLength();
276  Scale(fgWaterABSORPTION.XBegin(), fgWaterABSORPTION.XEnd(), kEnergyToG4);
277  Scale(fgWaterABSORPTION.YBegin(), fgWaterABSORPTION.YEnd(), kDistanceToG4);
278 
279  fWaterRINDEX = dStation.GetWaterRefractionIndex();
280  Scale(fWaterRINDEX.XBegin(), fWaterRINDEX.XEnd(), kEnergyToG4);
281 
282  // hardware-version-specific detector parameters
283 
284  if (dStation.HasScintillator()) {
285  const sdet::Scintillator& scintillator = dStation.GetScintillator();
286  // scintillator bars
290  fNScintillatorBars = scintillator.GetNBars();
291  fScintillatorGap = scintillator.GetGap() * kDistanceToG4;
292  // polystyrene housing
296  // aluminum casing
298  // sandwich panel
300  // roof
303  // positioning
304  fScintillatorPosition = Convert(scintillator.GetPosition(), cs);
305  }
306 
307  // These parameters specify the small PMT geometry ( already converted to G4 units )
308 
313 
317 
318  // Creates Amiga underground primitives
319  if (fUMDEnabled) {
320  if (!dStation.ExistsAssociatedCounter()) {
321  ostringstream err;
322  err << "Trying to simulate the UMD in a WCD (Id "<< dStation.GetId()
323  << ") that has not an underground AMIGA scintillator associated!";
324  //throw utl::NonExistentComponentException(err.str());
325  WARNING(err);
326  }
328  }
329 
330  // Creates MARTA underground primitives
331  if (fMARTAEnabled) {
333 
334  // Raises the tank by the height of the precast
335  const double martaSupportHeight =
339 
340  fTankPos_z += martaSupportHeight;
341 
342  fgTankCenter =
343  G4ThreeVector(fTankPos_x, fTankPos_y, fTankPos_z) +
344  G4ThreeVector(0, 0, fgTankHalfHeight + fgTankThickness);
345  }
346  }
347 
348 
349  // Defines area kinds for UMD modules
350  void
352  {
353  const auto& dStation = G4StationSimulator::fgCurrent.GetDetectorStation();
354  // Get the muon detector
355  const mdet::MDetector& mDetector = det::Detector::GetInstance().GetMDetector();
356  const mdet::Counter& cmDet = mDetector.GetCounter(dStation.GetAssociatedCounterId());
357 
359  // Largest length on manifold is 940mm, shortest is 530mm
360  // Therefore the largest relative difference is 410mm
362 
363  UMDScintiBox sbox;
364  UMDFiberTube ftub;
365  // Loop over muon modules (may only differs in bar lengths)
366  for (auto mmDet = cmDet.ModulesBegin(); mmDet != cmDet.ModulesEnd(); ++mmDet) {
367 
368  const mdet::Scintillator& s = *mmDet->ScintillatorsBegin();
369  const mdet::Fiber& f = mmDet->GetFiberFor(s);
370 
371  double l = 0;
372  f.VisitShape(ftub).GetDimensions(l, fUMDFiberRadius);
373  s.VisitShape(sbox).GetDimensions(l, fUMDScintsW, fUMDScintsH);
374 
375  l *= kDistanceToG4;
378  fUMDScints = mmDet->GetNumberOfScintillators();
380 
381  mdet::Module::AreaKind area = mmDet->GetAreaKind();
382  if (!fModAreaLenghts.count(area))
383  fModAreaLenghts[area] = l;
384  }
385  }
386 
387 
388  void
390  {
391  const auto& dStation = G4StationSimulator::fgCurrent.GetDetectorStation();
392  const int sId = dStation.GetId();
393  const cdet::Station& station = det::Detector::GetInstance().GetCDetector().GetStation(sId);
394 
395  {
396  vector<double> t;
397 
398  t = station.GetTankSupportTopSlabDimensions();
399  fTankSupportTopSlabDimensions = G4ThreeVector(t[0], t[1], t[2]) * kDistanceToG4;
400 
402  fTankSupportCentralFootDimensions = G4ThreeVector(t[0], t[1], t[2]) * kDistanceToG4;
403 
405  fTankSupportCentralFootBaseDimensions = G4ThreeVector(t[0], t[1], t[2]) * kDistanceToG4;
406 
407  t = station.GetTankSupportOuterFootDimensions();
408  fTankSupportOuterFootDimensions = G4ThreeVector(t[0], t[1], t[2]) * kDistanceToG4;
409 
411  fTankSupportOuterFootBaseDimensions = G4ThreeVector(t[0], t[1], t[2]) * kDistanceToG4;
412 
413  t = station.GetRPCHousingInnerDimensions();
414  fAlBoxInnerDimensions = G4ThreeVector(t[0], t[1], t[2]) * kDistanceToG4;
415 
416  t = station.GetRPCHousingThickness();
417  fAlBoxThickness = G4ThreeVector(t[0], t[1], t[2]) * kDistanceToG4;
418  }
419 
421 
424 
425  fRPCsizeX = station.GetRPCSizeX() * kDistanceToG4;
426  fRPCsizeY = station.GetRPCSizeY() * kDistanceToG4;
427 
428  const unsigned int nRPC = station.GetNumberRPCChambers();
429 
430  {
431  ostringstream msg;
432  msg << "Number of RPC chambers " << nRPC;
433  INFO(msg);
434  }
435 
436  const CoordinateSystemPtr cs = dStation.GetLocalCoordinateSystem();
437 
438  for (unsigned int i = 1; i <= nRPC; ++i) {
439  const G4ThreeVector pG4 = Convert(station.GetRPCPosition(i), cs);
440  fRPCPositions.push_back(pG4);
441  const G4double rG4 = station.GetRPCRotation(i) * CLHEP::degree / utl::degree;
442  fRPCRotations.push_back(rG4);
443  }
444 
445  INFO("RPC positions and rotation in SD station coordinate system:");
446  for (unsigned int i = 0; i < fRPCPositions.size(); ++i)
447  G4cerr << fRPCPositions[i] / CLHEP::m << " m "
448  << fRPCRotations[i] / CLHEP::degree << " deg" << G4endl;
449 
450  // Do not build the tank support if any dimension is zero
467 
468  if (!fMakeTankSupport)
469  WARNING("Tank support will not be build!");
470  else {
471  // Check validity of tank support dimensions
472  // Feet must have same height
474  fTankSupportCentralFootBaseDimensions[2] != fTankSupportOuterFootBaseDimensions[2]) {
475  const string err = "Feet of tank support have different heights! "
476  "Refuse to simulate this configuration!";
478  }
479 
480  // Feet must have same length (i.e. along Y)
482  fTankSupportCentralFootBaseDimensions[1] != fTankSupportOuterFootBaseDimensions[1]) {
483  const string err = "Feet of tank support have different lengths! "
484  "Refuse to simulate this configuration!";
486  }
487 
488  // Outer feet can not stick out of top slab along X or Y
491  const string err = "Outer feet of tank support stick out of top slab! "
492  "Refuse to simulate this configuration!";
494  }
495 
496  // Feet base can not overlap
498  const string err = "Central foot overlaps outer feet! "
499  "Refuse to simulate this configuration !";
501  }
502 
503  if (0.5*fTankSupportCentralFootBaseDimensions[0] > fTankSupportOuterFootDistanceToCenter - 0.5*fTankSupportOuterFootBaseDimensions[0]) {
504  const string err = "Base of central foot overlap base of outer feet! "
505  "Refuse to simulate this configuration !";
507  }
508 
509  const G4ThreeVector alBoxDimensions(fAlBoxInnerDimensions[0] + 2*fAlBoxThickness[0],
512 
513  const G4ThreeVector precastHoleDimensions(
518  );
519 
520  if (alBoxDimensions[0] >= precastHoleDimensions[0] ||
521  alBoxDimensions[1] >= precastHoleDimensions[1] ||
522  alBoxDimensions[2] >= precastHoleDimensions[2]) {
523  ostringstream err;
524  err << "RPC housing larger than inner size of concrete tank support!\n"
525  "x,y,z (m) : ("
526  << alBoxDimensions[0]/CLHEP::m << ", "
527  << alBoxDimensions[1]/CLHEP::m << ", "
528  << alBoxDimensions[2]/CLHEP::m << ") > ("
529  << precastHoleDimensions[0]/CLHEP::m << ", "
530  << precastHoleDimensions[1]/CLHEP::m << ", "
531  << precastHoleDimensions[2]/CLHEP::m << ')';
532  throw utl::InvalidConfigurationException(err.str());
533  }
534  }
535 
537  ostringstream err;
538  err << "Dimensions of RPC chamber greater than inner size of Al box!\n"
539  "x,y (m) : ("
540  << fRPCsizeX / CLHEP::m << ", "
541  << fRPCsizeY / CLHEP::m << ") > ("
542  << fAlBoxInnerDimensions[0] / CLHEP::m << ", "
543  << fAlBoxInnerDimensions[1] / CLHEP::m << ')';
544  throw utl::InvalidConfigurationException(err.str());
545  }
546  }
547 
548 
549  void
551  {
552  CentralConfig& cc = *CentralConfig::GetInstance();
553 
554  Branch topBranch = cc.GetTopBranch("G4StationSimulator");
555 
556  vector<double> pmt_pp;
557  topBranch.GetChild("pmt_momentum_bins").GetData(pmt_pp);
558 
559  vector<double> pmt_face_abs;
560  topBranch.GetChild("pmtface_AbsLength").GetData(pmt_face_abs);
561 
562  vector<double> pmt_interface_abs;
563  topBranch.GetChild("interface_AbsLength").GetData(pmt_interface_abs);
564 
565  vector<double> pmt_dome_abs;
566  topBranch.GetChild("dome_AbsLength").GetData(pmt_dome_abs);
567 
568  topBranch.GetChild("interface_thickness").GetData(fInterfaceThickness);
570 
571  topBranch.GetChild("pmtface_thickness").GetData(fGlassThickness);
573 
574  {
575  const unsigned int size = pmt_pp.size();
576 
577  if (pmt_face_abs.size() != size ||
578  pmt_interface_abs.size() != size ||
579  pmt_dome_abs.size() != size) {
580  const string err = "TabulatedFunction size mismatch for pmt properties";
581  ERROR(err);
582  throw utl::OutOfBoundException(err);
583  }
584 
585  for (unsigned int i = 0; i < size; ++i) {
586  fPmtfaceABSORPTION.PushBack(pmt_pp[i] * kEnergyToG4, pmt_face_abs[i] * kDistanceToG4);
587  fgInterfaceABSORPTION.PushBack(pmt_pp[i] * kEnergyToG4, pmt_interface_abs[i] * kDistanceToG4);
588  fgPmtdomeABSORPTION.PushBack( pmt_pp[i] * kEnergyToG4, pmt_dome_abs[i] * kDistanceToG4);
589  }
590  }
591 
592  topBranch.GetChild("face_radius").GetData(fFaceRadius);
594 
595  topBranch.GetChild("face_radius_z").GetData(fFaceRadiusz);
597 
598  topBranch.GetChild("face_active_radius").GetData(fFaceActiveRadius);
600 
601  // hardware-version-specific detector parameters
602  if (fHasSmallPMT) {
603  topBranch.GetChild("interface_thickness_spmt").GetData(fInterfaceThickness_SPMT);
605 
606  topBranch.GetChild("pmtface_thickness_spmt").GetData(fGlassThickness_SPMT);
608 
609  topBranch.GetChild("dome_thickness_spmt").GetData(fDomeThickness_SPMT);
611 
612  topBranch.GetChild("face_radius_spmt").GetData(fFaceRadius_SPMT);
614 
615  topBranch.GetChild("face_active_radius_spmt").GetData(fFaceActiveRadius_SPMT);
617 
618  topBranch.GetChild("window_radius_spmt").GetData(fWindowRadius_SPMT);
620 
621  }
622 
623  vector<double> liner_pp;
624  topBranch.GetChild("liner_momentum_bins").GetData(liner_pp);
625 
626  vector<double> liner_rindex;
627  topBranch.GetChild("liner_Rindex").GetData(liner_rindex);
628 
629  vector<double> liner_abs;
630  topBranch.GetChild("liner_AbsLength").GetData(liner_abs);
631 
632  vector<double> liner_backscatter;
633  topBranch.GetChild("backScatter").GetData(liner_backscatter);
634 
635  topBranch.GetChild("dome_thickness").GetData(fDomeThickness);
637 
638  {
639  const unsigned int size = liner_pp.size();
640 
641  if (liner_rindex.size() != size ||
642  liner_abs.size() != size ||
643  liner_backscatter.size() != size) {
644  const string err = "Tabulated function size mismatch for liner properties";
645  ERROR(err);
646  throw utl::OutOfBoundException(err);
647  }
648 
649  for (unsigned int i = 0; i < size; ++i) {
650  fLinerTYVEK_RINDEX.PushBack(liner_pp[i] * kEnergyToG4, liner_rindex[i]);
651  fLinerABSORPTION.PushBack(liner_pp[i] * kEnergyToG4, liner_abs[i] * kDistanceToG4);
652  fgLinerBACKSCATTERCONSTANT.PushBack(liner_pp[i] * kEnergyToG4, liner_backscatter[i]);
653  }
654  }
655  }
656 
657 
658  G4VPhysicalVolume*
660  {
661  if (!expHall_phys) {
662  CreateElements();
663  CreateMaterials();
664  return CreateTank();
665  }
666  return expHall_phys;
667  }
668 
669 
670  void
672  {
673  // G4Element(name, symbol, Z, n(molar mass))
674  Renew(elN, new G4Element("Nitrogen", "N", 7, 14.01 * g/mole));
675  Renew(elO, new G4Element("Oxygen", "O", 8, 16.00 * g/mole));
676  Renew(elAl, new G4Element("Aluminum", "Al", 13, 29.98 * g/mole));
677  Renew(elFe, new G4Element("Iron", "Fe", 26, 55.85 * g/mole));
678  Renew(elH, new G4Element("Hydrogen", "H", 1, 1.01 * g/mole));
679  Renew(elSi, new G4Element("Silicon", "Si", 14, 28.09 * g/mole));
680  Renew(elB, new G4Element("Boron", "B", 5, 10.811 * g/mole));
681  Renew(elNa, new G4Element("Sodium", "Na", 11, 22.98977 * g/mole));
682  Renew(elC, new G4Element("Carbon", "C", 6, 12.0107 * g/mole));
683  Renew(elCl, new G4Element("Chlorine", "Cl", 17, 35.453 * g/mole));
684  Renew(elTi, new G4Element("Titanium", "Ti", 22, 47.867 * g/mole));
685 
686  // Re-used material for Pyrex
687  const G4double density = 2.23*g/cm3;
688 
689  // G4Material(name, density, nel)
690  Renew(SiO2, new G4Material("SiO2", density, 2));
691  // AddElement(ptr, natoms)
692  SiO2->AddElement(elSi, 1);
693  SiO2->AddElement(elO, 2);
694 
695  Renew(B2O2, new G4Material("B2O2", density, 2));
696  B2O2->AddElement(elB, 2);
697  B2O2->AddElement(elO, 2);
698 
699  Renew(Na2O, new G4Material("Na2O", density, 2));
700  Na2O->AddElement(elNa, 2);
701  Na2O->AddElement(elO, 1);
702 
703  Renew(TiO2, new G4Material( "TiO2", 1.060 * g/cm3, 2));
704  TiO2->AddElement(elTi, 1);
705  TiO2->AddElement(elO, 2);
706  }
707 
708 
709  void
711  {
712  CreateAir();
713  CreateWater();
714  CreateVacuum();
715  CreatePyrex();
716  CreatePyrex1();
717  CreateLucite();
718  CreateInterface();
719  CreateHDPE();
720  CreateLiner();
721  CreateAluminium();
722  CreateDirt();
726  CreatePVC();
728  CreateWLS();
729 
730  CreateConcrete();
731  CreateAcrylic();
733  CreateR134A();
734  CreateBakelite();
735  }
736 
737 
738  G4VPhysicalVolume*
740  {
742  CreateHall();
743  AssembleStation();
744  return expHall_phys;
745  }
746 
747 
748  void
750  {
751  Renew(Air, new G4Material("Air", 1.29e-3 * g/cm3, 2));
752  Air->AddElement(elN, 0.7);
753  Air->AddElement(elO, 0.3);
754 
755  // Add material property table for Air to simulate empty tank
756  double airPP[2] = { 2.08*eV, 4.20*eV };
757  double airRINDEX[2] = { 1.000273, 1.000273 };
758  double airABSLENGTH[2] = { 10000*m, 10000*m };
759 
760  Renew(airMPT, new G4MaterialPropertiesTable());
761  airMPT->AddProperty("RINDEX", airPP, airRINDEX, 2);
762  airMPT->AddProperty("ABSLENGTH", airPP, airABSLENGTH, 2);
763 
764  Air->SetMaterialPropertiesTable(airMPT);
765  }
766 
767 
768  void
770  {
771  Renew(Water, new G4Material("Water", 1 * g/cm3, 2));
772  Water->AddElement(elH, 2);
773  Water->AddElement(elO, 1);
774 
775  // Set water material properties
776  Renew(waterMPT, new G4MaterialPropertiesTable());
777 
778  // water rindex
779  AddProperty(waterMPT, "RINDEX", fWaterRINDEX);
780 
781  // water abs. length
782  AddProperty(waterMPT, "ABSLENGTH", fgWaterABSORPTION);
783 
784  Water->SetMaterialPropertiesTable(waterMPT);
785  }
786 
787 
788  void
790  {
791  // ATTENTION: change from STP to avoid the warning...
792  Renew(Vacuum, new G4Material("Vacuum", 1, 1 * g/mole, universe_mean_density,
793  kStateUndefined, STP_Temperature, STP_Pressure));
794  }
795 
796 
797  void
799  {
800  // Borosilicate glass (Pyrex) for the active pmt faces
801  //----------------------------------------------------
802  /*
803  NOTE : The "face" is actually an ellipsoidal surface
804  The active area (photocathode) covers 90% of it.
805  The refractive index is the same as the dome
806  refractive index. The absorption length is set
807  so that no photons propagate through the
808  photocathode.
809  */
810 
811  // from PDG:
812  // 80% SiO2 + 13% B2O2 + 7% Na2O
813  // by fractional mass?
814 
815  Renew(Pyrex, new G4Material("Pyrex", 2.23 * g/cm3, 3));
816  Pyrex->AddMaterial(SiO2, 0.80);
817  Pyrex->AddMaterial(B2O2, 0.13);
818  Pyrex->AddMaterial(Na2O, 0.07);
819 
820  // Fill material properties table for pmt face
821  Renew(pmtfaceMPT, new G4MaterialPropertiesTable());
822 
823  // pmt face rindex
825 
826  // Fill and add pmt face absorption length
828 
829  Pyrex->SetMaterialPropertiesTable(pmtfaceMPT);
830  }
831 
832 
833  void
835  {
836  // Borosilicate glass (Pyrex1) for the inactive part of the pmt faces
837  /* NOTE : The inactive part of the "face" is about 10% of
838  the total ellipsoidal surface seen by the photons.
839  The refractive index is the same as the dome
840  refractive index. The absorption length is set
841  so that photons can propagate through this part.
842  To simplify things we use the same absorption length
843  as for the dome. */
844  const G4double density = 2.23 * g/cm3;
845 
846  Renew(Pyrex1, new G4Material("Pyrex1", density, 3));
847  Pyrex1->AddMaterial(SiO2, 0.80);
848  Pyrex1->AddMaterial(B2O2, 0.13);
849  Pyrex1->AddMaterial(Na2O, 0.07);
850 
851  Renew(pmtfaceMPT1, new G4MaterialPropertiesTable());
852 
853  // Fill material properties table for non sensitive pmt face
854 
855  // non-sensitive pmt face rindex = sensitive pmt face rindex
857 
858  // Fill and add non-sensitive pmt face absorption length = dome absorption length
860 
861  Pyrex1->SetMaterialPropertiesTable(pmtfaceMPT1);
862  }
863 
864 
865  void
867  {
868  // Lucite (for the pmt domes)
869  const G4double density = 1.20 * g/cm3;
870 
871  Renew(CH3, new G4Material("CH3", density, 2));
872  CH3->AddElement(elC, 1);
873  CH3->AddElement(elH, 3);
874 
875  Renew(CH2, new G4Material("CH2", density, 2));
876  CH2->AddElement(elC, 1);
877  CH2->AddElement(elH, 2);
878 
879  Renew(C, new G4Material("C", density, 1));
880  C->AddElement(elC, 1);
881 
882  Renew(CO2, new G4Material("CO2", density, 2));
883  CO2->AddElement(elC, 1);
884  CO2->AddElement(elO, 2);
885 
886  /* NOTE : Do not know the fractional mass comp.
887  of lucite, only the molecular composition.
888  Perhaps it is a standard material defined in g4.
889  for now define by number of atoms.
890  It really doesn't matter at this point
891  anyway, since we are more concerned about
892  the optical properties. */
893 
894  Renew(Lucite, new G4Material("Lucite", density, 3));
895  Lucite->AddElement(elC, 4);
896  Lucite->AddElement(elH, 8);
897  Lucite->AddElement(elO, 2);
898 
899  Renew(pmtdomeMPT, new G4MaterialPropertiesTable());
900 
901  // pmt dome rindex
903 
904  // pmt dome absorption length
906 
907  Lucite->SetMaterialPropertiesTable(pmtdomeMPT);
908  }
909 
910 
911  void
913  {
914  // Interface for production tanks is Wacker SilGel 612 (Registered trademark of Wacker Group
915  const G4double density = 0.97 * g/cm3; // guess - not explicitly set by Troy
916 
917  Renew(Interface, new G4Material("Interface", density, 3));
918  Interface->AddElement(elC, 4);
919  Interface->AddElement(elH, 8);
920  Interface->AddElement(elO, 2);
921 
922  Renew(interfaceMPT, new G4MaterialPropertiesTable());
923 
924  // interface rindex
926 
927  // interface abs. length
929 
930  Interface->SetMaterialPropertiesTable(interfaceMPT);
931  }
932 
933 
934  void
936  {
937  // HDPE (for tank walls)
938  const G4double density = 0.94 * g/cm3;
939 
940  Renew(HDPE, new G4Material("HDPE", density, 2));
941  HDPE->AddElement(elC, 2);
942  HDPE->AddElement(elH, 4);
943 
944  Renew(linerMPT, new G4MaterialPropertiesTable());
945 
946  // liner abs. length
947  AddProperty(linerMPT, "ABSLENGTH", fLinerABSORPTION);
948 
949  HDPE->SetMaterialPropertiesTable(linerMPT);
950  }
951 
952 
953  void
955  {
956  // Optical surface properties
957 
958  // Define the optical model and set optical properties of the surfaces
959 
960  /* Note that diffuse reflection is implicitly defined, since:
961  SPECULARSPIKECONSTANT+SPECULARLOBECONSTANT+BACKSCATTERCONSTANT=
962  1-DIFFUSEL0BECONSTANT */
963 
964  Renew(linerOpticalMPT, new G4MaterialPropertiesTable());
965  AddProperty(linerOpticalMPT, "SPECULARLOBECONSTANT", fgLinerSPECULARLOBECONSTANT);
966  AddProperty(linerOpticalMPT, "SPECULARSPIKECONSTANT", fgLinerSPECULARSPIKECONSTANT);
968  AddProperty(linerOpticalMPT, "BACKSCATTERCONSTANT", fgLinerBACKSCATTERCONSTANT);
970 
971  Renew(OpLinerSurface, new G4OpticalSurface("WallSurface"));
972  OpLinerSurface->SetModel(unified);
973  OpLinerSurface->SetType(dielectric_metal);
974  OpLinerSurface->SetFinish(ground);
975  OpLinerSurface->SetSigmaAlpha(fgSIGMA_ALPHA);
976  OpLinerSurface->SetMaterialPropertiesTable(linerOpticalMPT);
977  }
978 
979 
980  void
982  {
983  // Aluminum for electronics boxes and (possibly) solar panel
984  const G4double density = 2.700 * g/cm3;
985  const G4double a = 29.98 * g/mole;
986  Renew(Al, new G4Material("Aluminum", /*z*/13, a, density));
987  }
988 
989 
990  void
992  {
993  // Dirt for the ground
994  /* Soil density samples (see Informe_Preliminar__Intemin_1_11_07
995  Samples at:
996  A.- Hilda tank
997  B.- Lety tank
998  C.- TierraDelFuego tank */
999 
1000  const G4double density = (
1001  2.43 + 2.39 + 2.41 + // Hilda
1002  2.39 + 2.45 + 2.32 + // Lety
1003  2.35 + 2.40 + 2.28 // TierraDelFuego
1004  ) / 9 * g/cm3;
1005  Renew(Dirt, new G4Material("Dirt", density, 4));
1006  Dirt->AddElement(elO, 51*perCent);
1007  Dirt->AddElement(elSi, 35.2*perCent);
1008  Dirt->AddElement(elAl, 8.2*perCent);
1009  Dirt->AddElement(elFe, 5.6*perCent);
1010  }
1011 
1012 
1013  void
1015  {
1016  // Polystyrene for the scintillator bars Dow STYRON 663 W
1017  const G4double density = 1.04 * g/cm3;
1018  Renew(Polystyrene, new G4Material("Polystyrene", density, 2));
1019  Polystyrene->AddElement(elC, 8);
1020  Polystyrene->AddElement(elH, 8);
1021  }
1022 
1023 
1024  void
1026  {
1027  /* Scintillator made of Polystyrene ( C6H5-CH-CH2 ) + PPO + POPOP
1028  Plastic:
1029  Is a replication on an aromatic ring (C6H5) with one out of the six H
1030  replaced by a CH bond with another CH2.
1031 
1032  CH2
1033  //
1034  CH
1035  |
1036  / \
1037  C6H5: | |
1038  \ /
1039  */
1040 
1041  {
1042  const G4double density = 1.060 * g/cm3;
1043  // PPO:
1044  Renew(PPO, new G4Material("PPO", density, 4));
1045  PPO->AddElement(elC, 15);
1046  PPO->AddElement(elH, 11);
1047  PPO->AddElement(elN, 1);
1048  PPO->AddElement(elO, 1);
1049  // POPOP:
1050  Renew(POPOP, new G4Material("POPOP", density, 4));
1051  POPOP->AddElement(elC, 24);
1052  POPOP->AddElement(elH, 16);
1053  POPOP->AddElement(elN, 2);
1054  POPOP->AddElement(elO, 2);
1055  // Scintillator material:
1056  Renew(ScintMat, new G4Material("ScintMat", density, 3));
1057  ScintMat->AddMaterial(Polystyrene, 98.7*perCent);
1058  ScintMat->AddMaterial(PPO, 1*perCent);
1059  ScintMat->AddMaterial(POPOP, 0.3*perCent);
1060  }
1061 
1062  // Scintillator Coating - 15% TiO2 and 85% polystyrene by weight.
1063  const G4double density = 1.52 * g/cm3;
1064  Renew(ScintCoating, new G4Material("ScintCoating", density, 2));
1065  ScintCoating->AddMaterial(TiO2, 15*perCent);
1066  ScintCoating->AddMaterial(Polystyrene, 85*perCent);
1067 
1068  // Do not add scintillation properties to material for fast mode (PE photons will be created
1069  // from parametriezed curve in (see G4UMDScintStripAction.cc)
1072  }
1073 
1074 
1075  void
1077  {
1078  // WLSfiber PMMA
1079  Renew(PMMA, new G4Material("PMMA", 1.190 * g/cm3, 3));
1080  PMMA->AddElement(elC, 5);
1081  PMMA->AddElement(elH, 8);
1082  PMMA->AddElement(elO, 2);
1083 
1084  // Cladding (polyethylene)
1085  Renew(Pethylene, new G4Material("Pethylene", 1.200 * g/cm3, 2));
1086  Pethylene->AddElement(elC, 2);
1087  Pethylene->AddElement(elH, 4);
1088 
1089  // Double Cladding (fluorinated polyethylene)
1090  Renew(FPethylene, new G4Material("FPethylene", 1.400*g/cm3, 2));
1091  FPethylene->AddElement(elC, 2);
1092  FPethylene->AddElement(elH, 4);
1093 
1094  G4double photonEnergy[] = {
1095  2.00, 2.03, 2.06, 2.09, 2.12,
1096  2.15, 2.18, 2.21, 2.24, 2.27,
1097  2.30, 2.33, 2.36, 2.39, 2.42,
1098  2.45, 2.48, 2.51, 2.54, 2.57,
1099  2.60, 2.63, 2.66, 2.69, 2.72,
1100  2.75, 2.78, 2.81, 2.84, 2.87,
1101  2.90, 2.93, 2.96, 2.99, 3.02,
1102  3.05, 3.08, 3.11, 3.14, 3.17,
1103  3.20, 3.23, 3.26, 3.29, 3.32,
1104  3.35, 3.38, 3.41, 3.44, 3.47
1105  };
1106  Scale(photonEnergy, CLHEP::eV);
1107 
1108  const auto n = utl::Length(photonEnergy);
1109 
1110  // PMMA for WLSfibers
1111  G4double refractiveIndexWLSfiber[] = {
1112  1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60,
1113  1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60,
1114  1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60,
1115  1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60,
1116  1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60, 1.60
1117  };
1118  assert(utl::Length(refractiveIndexWLSfiber) == n);
1119 
1120  G4double absWLSfiber[] = {
1121  10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00,
1122  10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00,
1123  10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 1.0,
1124  0.0001, 0.0001, 0.0001, 0.0001, 0.0001,0.0001, 0.0001, 0.0001, 0.0001, 0.0001,
1125  0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001
1126  };
1127  Scale(absWLSfiber, CLHEP::m);
1128  assert(utl::Length(absWLSfiber) == n);
1129 
1130  G4double emissionFib[] = {
1131  0.05, 0.10, 0.30, 0.50, 0.75, 1.00, 1.50, 1.85, 2.30, 2.75,
1132  3.25, 3.80, 4.50, 5.20, 6.00, 7.00, 8.50, 9.50, 11.1, 12.4,
1133  12.9, 13.0, 12.8, 12.3, 11.1, 11.0, 12.0, 11.0, 17.0, 16.9,
1134  15.0, 9.00, 2.50, 1.00, 0.05, 0.00, 0.00, 0.00, 0.00, 0.00,
1135  0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00
1136  };
1137  assert(utl::Length(emissionFib) == n);
1138 
1139  // Add entries into properties table
1140  G4MaterialPropertiesTable* const mptWLSfiber = new G4MaterialPropertiesTable();
1141  mptWLSfiber->AddProperty("RINDEX", photonEnergy, refractiveIndexWLSfiber, n);
1142  mptWLSfiber->AddProperty("WLSABSLENGTH", photonEnergy, absWLSfiber, n);
1143  mptWLSfiber->AddProperty("WLSCOMPONENT", photonEnergy, emissionFib, n);
1144  mptWLSfiber->AddConstProperty("WLSTIMECONSTANT", 20*ns);
1145 
1146  PMMA->SetMaterialPropertiesTable(mptWLSfiber);
1147 
1148  // Polyethylene
1149 
1150  G4double refractiveIndexClad1[] = {
1151  1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49,
1152  1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49,
1153  1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49,
1154  1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49,
1155  1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49, 1.49
1156  };
1157 
1158  assert(utl::Length(refractiveIndexClad1) == n);
1159 
1160  G4double absClad[] = {
1161  20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0,
1162  20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0,
1163  20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0,
1164  20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0,
1165  20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0
1166  };
1167  Scale(absClad, CLHEP::m);
1168  assert(utl::Length(absClad) == n);
1169 
1170  // Add entries into properties table
1171  G4MaterialPropertiesTable* const mptClad1 = new G4MaterialPropertiesTable();
1172  mptClad1->AddProperty("RINDEX", photonEnergy, refractiveIndexClad1, n);
1173  mptClad1->AddProperty("ABSLENGTH", photonEnergy, absClad, n);
1174 
1175  Pethylene->SetMaterialPropertiesTable(mptClad1);
1176 
1177  // Fluorinated Polyethylene
1178 
1179  G4double refractiveIndexClad2[] = {
1180  1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42,
1181  1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42,
1182  1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42,
1183  1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42,
1184  1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42, 1.42
1185  };
1186 
1187  assert(utl::Length(refractiveIndexClad2) == n);
1188 
1189  // Add entries into properties table
1190  G4MaterialPropertiesTable* const mptClad2 = new G4MaterialPropertiesTable();
1191  mptClad2->AddProperty("RINDEX", photonEnergy, refractiveIndexClad2, n);
1192  mptClad2->AddProperty("ABSLENGTH", photonEnergy, absClad, n);
1193 
1194  FPethylene->SetMaterialPropertiesTable(mptClad2);
1195  }
1196 
1197 
1198  void
1200  {
1201  // ------------ Generate & Add Material Properties Table ------------
1202 
1203  G4double photonEnergy[] = {
1204  2.00, 2.03, 2.06, 2.09, 2.12,
1205  2.15, 2.18, 2.21, 2.24, 2.27,
1206  2.30, 2.33, 2.36, 2.39, 2.42,
1207  2.45, 2.48, 2.51, 2.54, 2.57,
1208  2.60, 2.63, 2.66, 2.69, 2.72,
1209  2.75, 2.78, 2.81, 2.84, 2.87,
1210  2.90, 2.93, 2.96, 2.99, 3.02,
1211  3.05, 3.08, 3.11, 3.14, 3.17,
1212  3.20, 3.23, 3.26, 3.29, 3.32,
1213  3.35, 3.38, 3.41, 3.44, 3.47
1214  };
1215  Scale(photonEnergy, CLHEP::eV);
1216  const auto n = utl::Length(photonEnergy);
1217 
1218  // Scintillator (Polystyrene based)
1219 
1220  G4double refractiveIndexPS[] = {
1221  1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50,
1222  1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50,
1223  1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50,
1224  1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50,
1225  1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50, 1.50
1226  };
1227  assert(utl::Length(refractiveIndexPS) == n);
1228 
1229  G4double absPS[] = {
1230  1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1231  1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1232  1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1233  20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0,
1234  20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0, 20.0
1235  };
1236  Scale(absPS, CLHEP::cm);
1237  assert(utl::Length(absPS) == n);
1238 
1239  G4double scintilFast[] = {
1240  0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1241  0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1242  0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1243  1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1244  1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
1245  };
1246  assert(utl::Length(scintilFast) == n);
1247 
1248  G4double scintilSlow[] = {
1249  1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1250  1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1251  1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
1252  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1253  0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
1254  };
1255  assert(utl::Length(scintilSlow) == n);
1256 
1257  // Add entries into properties table
1258  G4MaterialPropertiesTable* const mptPolystyrene = new G4MaterialPropertiesTable();
1259  mptPolystyrene->AddProperty("RINDEX", photonEnergy, refractiveIndexPS, n);
1260  mptPolystyrene->AddProperty("ABSLENGTH", photonEnergy, absPS, n);
1261  mptPolystyrene->AddProperty("FASTCOMPONENT", photonEnergy, scintilFast, n);
1262  mptPolystyrene->AddProperty("SLOWCOMPONENT", photonEnergy, scintilSlow, n);
1263 
1264  mptPolystyrene->AddConstProperty("SCINTILLATIONYIELD", fScintYield / CLHEP::keV);
1265  mptPolystyrene->AddConstProperty("RESOLUTIONSCALE", 1);
1266  mptPolystyrene->AddConstProperty("FASTTIMECONSTANT", 5.*CLHEP::ns);
1267  mptPolystyrene->AddConstProperty("SLOWTIMECONSTANT", 50.*CLHEP::ns);
1268  mptPolystyrene->AddConstProperty("YIELDRATIO", 1);
1269 
1270  ScintMat->SetMaterialPropertiesTable(mptPolystyrene);
1271 
1272  // Set the Birks Constant for the Polystyrene scintillator
1273  //ScintMat->GetIonisation()->SetBirksConstant(0.126*CLHEP::mm/CLHEP::MeV);
1274 
1275  // Optical Skin properties
1276  // Strip coating properties
1277  const double extrusion_polish = 1;
1278  Renew(fUMDScintSkinSurf, new G4OpticalSurface("StripSkin", glisur, ground, dielectric_metal, extrusion_polish));
1279  Renew(fUMDScintSkinSurfBack, new G4OpticalSurface("StripSkinBack", glisur, ground, dielectric_metal, extrusion_polish));
1280 
1281  const double refl = 1;
1282  G4double skin_refl[] = {
1283  refl, refl, refl, refl, refl, refl, refl, refl, refl, refl,
1284  refl, refl, refl, refl, refl, refl, refl, refl, refl, refl,
1285  refl, refl, refl, refl, refl, refl, refl, refl, refl, refl,
1286  refl, refl, refl, refl, refl, refl, refl, refl, refl, refl,
1287  refl, refl, refl, refl, refl, refl, refl, refl, refl, refl
1288  };
1289  assert(utl::Length(skin_refl) == n);
1290 
1291  G4double skin_effi[] = {
1292  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1293  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1294  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1295  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1296  0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1297  };
1298  assert(utl::Length(skin_effi) == n);
1299 
1300  G4MaterialPropertiesTable* const scint_skin_MPT = new G4MaterialPropertiesTable();
1301  G4MaterialPropertiesTable* const scint_skin_back_MPT = new G4MaterialPropertiesTable();
1302  scint_skin_MPT->AddProperty("REFLECTIVITY", photonEnergy, skin_refl, n);
1303  scint_skin_MPT->AddProperty("EFFICIENCY", photonEnergy, skin_effi, n);
1304  // black painted (total absorption)
1305  scint_skin_back_MPT->AddProperty("REFLECTIVITY", photonEnergy, skin_effi, n);
1306  scint_skin_back_MPT->AddProperty("EFFICIENCY", photonEnergy, skin_effi, n);
1307 
1308  fUMDScintSkinSurf->SetMaterialPropertiesTable(scint_skin_MPT);
1309  fUMDScintSkinSurfBack->SetMaterialPropertiesTable(scint_skin_back_MPT);
1310  }
1311 
1312 
1313  void
1315  {
1316  new G4LogicalSkinSurface("SkinTopBot_large", umd_top_bot_coat_log_large, fUMDScintSkinSurf);
1317  new G4LogicalSkinSurface("SkinSide_large", umd_side_coat_log_large, fUMDScintSkinSurf);
1318  new G4LogicalSkinSurface("SkinTopBot_small", umd_top_bot_coat_log_small, fUMDScintSkinSurf);
1319  new G4LogicalSkinSurface("SkinSide_small", umd_side_coat_log_small, fUMDScintSkinSurf);
1320  new G4LogicalSkinSurface("SkinBack", umd_back_side_coat_log, fUMDScintSkinSurfBack);
1321  }
1322 
1323 
1324  void
1326  {
1327  // Styrofoam used to fill upper portion of SSD
1328  Renew(ExpandedPolystyreneFoam, new G4Material("ExpandedPolystyreneFoam", 0.01414 * g/cm3, 2));
1329  ExpandedPolystyreneFoam->AddElement(elC, 8);
1330  ExpandedPolystyreneFoam->AddElement(elH, 8);
1331  }
1332 
1333 
1334  void
1336  {
1337  // Foam in-between aluminum sheets of the sandwich panel
1338  Renew(ExtrudedPolystyreneFoam, new G4Material("ExtrudedPolystyreneFoam", 0.032 * g/cm3, 2));
1339  ExtrudedPolystyreneFoam->AddElement(elC, 8);
1340  ExtrudedPolystyreneFoam->AddElement(elH, 8);
1341  }
1342 
1343 
1344  void
1346  {
1347  // PVC for the casing
1348  // flexible PVC
1349  Renew(PVC, new G4Material("PVC", 1.35 * g/cm3, 3));
1350  PVC->AddElement(elC, 2);
1351  PVC->AddElement(elH, 3);
1352  PVC->AddElement(elCl, 1);
1353  }
1354 
1355 
1356  void
1358  {
1359  fG4_Concrete = fNistManager->FindOrBuildMaterial("G4_CONCRETE");
1360  }
1361 
1362 
1363  void
1365  {
1366  fG4_Acrylic = fNistManager->FindOrBuildMaterial("G4_POLYACRYLONITRILE");
1367  }
1368 
1369 
1370  void
1372  {
1373  G4Material* const G4_CaO = fNistManager->FindOrBuildMaterial("G4_CALCIUM_OXIDE");
1374  G4Material* const G4_MgO = fNistManager->FindOrBuildMaterial("G4_MAGNESIUM_OXIDE");
1375 
1376  Renew(fSoda_lime_glass, new G4Material("Soda-lime_glass", 2.52 * g/cm3, 4));
1377  fSoda_lime_glass->AddMaterial(SiO2, 0.73);
1378  fSoda_lime_glass->AddMaterial(Na2O, 0.14);
1379  fSoda_lime_glass->AddMaterial(G4_CaO, 0.09);
1380  fSoda_lime_glass->AddMaterial(G4_MgO, 0.04);
1381  }
1382 
1383 
1384  void
1386  {
1387  const vector<G4String> elements({ "H", "C", "F" });
1388  const vector<G4int> nbAtoms({ 2, 2, 4 });
1389  fNistManager->ConstructNewMaterial(
1390  "TetraFluoroethane_STP",
1391  elements, nbAtoms, 0.00425 * g/cm3,
1392  true, kStateGas
1393  );
1394  fR134a = fNistManager->ConstructNewGasMaterial(
1395  "TetraFluoroethane", "TetraFluoroethane_STP",
1396  273.*CLHEP::kelvin,
1397  0.8*CLHEP::atmosphere
1398  );
1399  }
1400 
1401 
1402  void
1404  {
1405  fG4_Bakelite = fNistManager->FindOrBuildMaterial("G4_BAKELITE");
1406  }
1407 
1408 
1409  void
1411  {
1412  Renew(expHall_box, new G4Box("World", fExpHall_x, fExpHall_y, fExpHall_z));
1413  Renew(ground_solid, new G4Tubs("ground_solid", 0, fSimulationRadius, fGroundThickness/2, 0, 360*deg));
1414  // tank casing
1415  Renew(tank_solid, new G4Tubs("tank_solid", 0, fgTankRadius, fgTankHalfHeight, 0, 360*deg));
1416  Renew(top_solid, new G4Tubs("top_solid", 0, fgTankRadius + fgTankThickness, fgTankThickness/2, 0, 360*deg));
1417  Renew(side_solid, new G4Tubs("side_solid", fgTankRadius, fgTankRadius + fgTankThickness, fgTankHalfHeight, 0, 360*deg));
1418  Renew(inner_solid, new G4Ellipsoid("inner_solid", fPmtRmin, fPmtRmin, fPmtRzmin, -fPmtRzmin, 0));
1419  // Active photocathode covered area
1420  Renew(pmt_aux, new G4Ellipsoid("pmt_aux", fgPmtRmax, fgPmtRmax, fgPmtRzmax, -fgPmtRzmax, -fgHeightz));
1421  Renew(pmt_solid, new G4SubtractionSolid("pmt_solid", pmt_aux, inner_solid));
1422  Renew(pmt_aux1, new G4Ellipsoid("pmt_aux1", fgPmtRmax, fgPmtRmax, fgPmtRzmax, -fgHeightz, 0));
1423  Renew(pmt_solid1, new G4SubtractionSolid("pmt_solid1", pmt_aux1, inner_solid));
1424 
1425  Renew(interface_in_aux, new G4Ellipsoid("interface_in_aux", fInterfaceRmin, fInterfaceRmin, fInterfaceRzmin, -fInterfaceRzmin, 0));
1426  Renew(interface_out_aux, new G4Ellipsoid("interface_out_aux", fgInterfaceRmax, fgInterfaceRmax, fgInterfaceRzmax, -fgInterfaceRzmax, 0));
1427  Renew(interface_solid, new G4SubtractionSolid("interface_solid", interface_out_aux, interface_in_aux));
1428 
1429  Renew(dome_in_aux, new G4Ellipsoid("dome_in_aux", fDomeRmin, fDomeRmin, fDomeRzmin, -fDomeRzmin, 0));
1430  Renew(dome_out_aux, new G4Ellipsoid("dome_out_aux", fgDomeRmax, fgDomeRmax, fgDomeRzmax, -fgDomeRzmax, 0));
1431  Renew(dome_solid, new G4SubtractionSolid("dome_solid", dome_out_aux, dome_in_aux));
1432 
1433  if (fHasSmallPMT) {
1434  // SPMT AT LINER LEVEL
1435  Renew(s_pmt_solid, new G4Tubs("s_pmt_solid", 0, fPmtRmin_SPMT, fGlassThickness_SPMT/2, 0,360*deg));
1436  Renew(s_pmt_aux, new G4Tubs("s_pmt_aux", 0, fPmtRmin_SPMT, fGlassThickness_SPMT/2, 0, 360*deg));
1437  Renew(s_pmt_aux1, new G4Tubs("s_pmt_aux1", 0, fPmtRmax_SPMT, fGlassThickness_SPMT/2, 0, 360*deg));
1438  Renew(s_pmt_solid1, new G4SubtractionSolid("s_pmt_solid1", s_pmt_aux1, s_pmt_aux));
1439  Renew(s_interface_solid, new G4Tubs("s_interface_solid", 0, fInterfaceRadius_SPMT, fInterfaceThickness_SPMT/2, 0, 360*deg));
1440  Renew(s_dome_solid, new G4Tubs("s_dome_solid", 0, fDomeRadius_SPMT, fDomeThickness_SPMT/2, 0, 360*deg));
1441  }
1442 
1443  // Creates Amiga underground primitives
1444  if (fUMDEnabled) {
1445  const auto& dStation = G4StationSimulator::fgCurrent.GetDetectorStation();
1446  if (!dStation.ExistsAssociatedCounter()) {
1447  ostringstream err;
1448  err << "Trying to simulate the UMD in a WCD (Id "<< dStation.GetId() << ") "
1449  "that has not an underground AMIGA scintillator associated!";
1450  WARNING(err);
1451  }
1453  }
1454 
1455  // Creates MARTA primitives
1456  if (fMARTAEnabled)
1458  }
1459 
1460 
1461  // Creates casings for scintillators
1462  void
1464  {
1467  fPixelL = 0.5*CLHEP::cm;
1468 
1469  INFO("UMD areas:");
1470  for (const auto& ml : fModAreaLenghts) {
1471  const auto module = ml.first;
1472  const auto len = ml.second;
1473  const double x = len + fUMDManifoldL/2;
1474  const double y = fUMDScintsW/2 * fUMDScints/2;
1475  const double z = fUMDScintsH/2;
1476  const double t = fUMDThicknessCasing;
1477  if (module == mdet::Module::AreaKind::eLarge) {
1478 
1479  Renew(umd_casing_solid_large, new G4Box("umd_casing_large", x+t, y+t, z+t));
1480  Renew(umd_strip_solid_large, new G4Box("umd_strip_solid_large", len/2 - fCoatingThickness, fUMDScintsW/2 - fCoatingThickness, fUMDScintsH/2 - fCoatingThickness));
1481  Renew(umd_top_bot_coat_solid_large, new G4Box("umd_top_bot_coat_solid_large", len/2 - fCoatingThickness, fUMDScintsW/2 - fCoatingThickness, fCoatingThickness/2));
1482  Renew(umd_side_coat_solid_large, new G4Box("umd_side_coat_solid_large", len/2 - fCoatingThickness, fCoatingThickness/2, fUMDScintsH/2));
1483 
1484  Renew(umd_fiber_core_solid_large, new G4Tubs("umd_fiber_core_solid_large", 0, fUMDFiberRadius - 2*fCladingThickness, len/2 - fCoatingThickness, 0, 360*CLHEP::deg));
1485  Renew(umd_fiber_clad1_solid_large, new G4Tubs("umd_fiber_clad1_solid_large", 0, fUMDFiberRadius - fCladingThickness, len/2 - fCoatingThickness, 0, 360*CLHEP::deg));
1486  Renew(umd_fiber_clad2_solid_large, new G4Tubs("umd_fiber_clad2_solid_large", 0, fUMDFiberRadius, len/2 - fCoatingThickness, 0, 360*CLHEP::deg));
1487 
1488  } else {
1489 
1490  Renew(umd_casing_solid_small, new G4Box("umd_casing_small", x+t, y+t, z+t));
1491  Renew(umd_strip_solid_small, new G4Box("umd_strip_solid_small", len/2 - fCoatingThickness, fUMDScintsW/2 - fCoatingThickness, fUMDScintsH/2 - fCoatingThickness));
1492  Renew(umd_top_bot_coat_solid_small, new G4Box("umd_top_bot_coat_solid_small", len/2 - fCoatingThickness, fUMDScintsW/2 - fCoatingThickness, fCoatingThickness/2));
1493  Renew(umd_side_coat_solid_small, new G4Box("umd_side_coat_solid_small", len/2 - fCoatingThickness, fCoatingThickness/2, fUMDScintsH/2));
1494 
1495  Renew(umd_fiber_core_solid_small, new G4Tubs("umd_fiber_core_solid_small", 0, fUMDFiberRadius - 2*fCladingThickness, len/2 - fCoatingThickness, 0, 360*CLHEP::deg));
1496  Renew(umd_fiber_clad1_solid_small, new G4Tubs("umd_fiber_clad1_solid_small", 0, fUMDFiberRadius - fCladingThickness, len/2 - fCoatingThickness, 0, 360*CLHEP::deg));
1497  Renew(umd_fiber_clad2_solid_small, new G4Tubs("umd_fiber_clad2_solid_small", 0, fUMDFiberRadius, len/2 - fCoatingThickness, 0, 360*CLHEP::deg));
1498 
1499  }
1500 
1501  // Same for all areas
1502  Renew(umd_back_side_coat_solid, new G4Box("umd_back_side_coat", fCoatingThickness/2, fUMDScintsW/2, fUMDScintsH/2));
1503  Renew(pixel_solid, new G4Tubs("pixel_solid", 0, fUMDFiberRadius, fPixelL/2, 0, 360*CLHEP::deg));
1504  }
1505  }
1506 
1507 
1508  void
1510  {
1511  // Al box
1512  const G4ThreeVector alBoxSize = fAlBoxInnerDimensions + 2*fAlBoxThickness;
1513 
1514  // We sum 0.1 mm of the thickness to the size of the inner part of the tank support to guarantee that
1515  // if a wall thickness of 0 is chosen the solid subtraction below will be correctly performed.
1516  const G4ThreeVector alBoxHoleSize = fAlBoxInnerDimensions + 2*0.1*CLHEP::mm * G4ThreeVector(1,1,1);
1517 
1518  G4Box* const alBox_hole = new G4Box("AlBox_hole", alBoxHoleSize[0]/2, alBoxHoleSize[1]/2, alBoxHoleSize[2]/2);
1519 
1520  G4Box* const alBox_out = new G4Box("AlBox_out", alBoxSize[0]/2, alBoxSize[1]/2, alBoxSize[2]/2);
1521 
1522  Renew(AlBox_solid, new G4SubtractionSolid("AlBox_solid", alBox_out, alBox_hole));
1523 
1524  // Double 1mm gap RPC
1525  const double rpcAcrylicThickness = 0.80*CLHEP::mm;
1526  const double rpcGlassThickness = 1.85*CLHEP::mm;
1527  const double rpcGasThickness = 1.0*CLHEP::mm;
1528  const double rpcHeight = 2*rpcAcrylicThickness + 3*rpcGlassThickness + 2*rpcGasThickness;
1529 
1530  const double rpc_halfX = fRPCsizeX/2;
1531  const double rpc_halfY = fRPCsizeY/2;
1532  const double rpc_halfZ = rpcHeight/2;
1533 
1534  const double glass_halfX = rpc_halfX - 0.5*CLHEP::mm;
1535  const double glass_halfY = rpc_halfY - 0.5*CLHEP::mm;
1536  const double glass_halfZ = (3*rpcGlassThickness + 2*rpcGasThickness)/2;
1537 
1538  const double gas_halfX = glass_halfX - 0.5*CLHEP::mm;
1539  const double gas_halfY = glass_halfY - 0.5*CLHEP::mm;
1540  const double gas_halfZ = rpcGasThickness/2;
1541 
1542  const double pcb_halfX = rpc_halfX;
1543  const double pcb_halfY = rpc_halfY;
1544  const double pcb_halfZ = fPCBThickness/2;
1545 
1546  const double spacer_thickness = fSpacerThickness;
1547  const double spacer_halfX = rpc_halfX;
1548  const double spacer_halfY = rpc_halfY;
1549  const double spacer_halfZ = spacer_thickness/2;
1550 
1551  if (rpcHeight + 2*fPCBThickness + spacer_thickness > fAlBoxInnerDimensions[2] + 5*CLHEP::mm) {
1552  ostringstream errMsg;
1553  errMsg << "Total height of RPC + 2 x PCB + Spacer = "
1554  << rpcHeight/CLHEP::mm << " + "
1555  << 2*fPCBThickness/CLHEP::mm << " + "
1556  << spacer_thickness/CLHEP::mm << " mm "
1557  << " greater than inner height of Al box ("
1558  << fAlBoxInnerDimensions[2]/CLHEP::mm << " mm)!";
1559  ERROR(errMsg);
1560  throw utl::OutOfBoundException(errMsg.str());
1561  }
1562 
1563  Renew(rpc_solid, new G4Box("rpc_solid", rpc_halfX, rpc_halfY, rpc_halfZ));
1564  Renew(glass_solid, new G4Box("rpc_glass_solid", glass_halfX, glass_halfY, glass_halfZ));
1565  Renew(gas_solid, new G4Box("rpc_gas_solid", gas_halfX, gas_halfY, gas_halfZ));
1566  Renew(pcb_solid, new G4Box("pcb_solid", pcb_halfX, pcb_halfY, pcb_halfZ));
1567  Renew(spacer_solid, new G4Box("spacer_solid", spacer_halfX, spacer_halfY, spacer_halfZ));
1568  }
1569 
1570 
1571  void
1573  {
1574  // Experimental hall
1575  Renew(expHall_log, new G4LogicalVolume(expHall_box, Air, "World", 0, 0, 0));
1576  Renew(expHall_phys, new G4PVPlacement(nullptr, G4ThreeVector(), "World", expHall_log, 0, false, 0));
1577  expHall_log->SetVisAttributes(G4VisAttributes::Invisible);
1578 
1579  // Ground around the detector
1580  if (fGroundEnable) {
1581  // Create sensitive soil to avoid simulation of low energy particles (or other restrictions to speed up cpu time)
1582  Renew(ground_log, new G4LogicalVolume(ground_solid, Dirt, "ground_solid"));
1583  Renew(ground_phys, new G4PVPlacement(nullptr, G4ThreeVector(0, 0, -fGroundThickness/2), "ground", ground_log, expHall_phys, false, 0));
1584  G4VisAttributes gVisatt(G4Colour::Brown());
1585  if (fG4StationSimulator.fVerbosity<2) ground_log->SetVisAttributes(G4VisAttributes::Invisible);
1586  // registration
1587  G4SoilAction* const soilSD = new G4SoilAction("/soil");
1588  G4SDManager* const sdMan = G4SDManager::GetSDMpointer();
1589  sdMan->AddNewDetector(soilSD);
1590  ground_log->SetSensitiveDetector(soilSD);
1591  }
1592  }
1593 
1594 
1595  void
1597  {
1598  G4SDManager* const sdMan = G4SDManager::GetSDMpointer();
1599 
1600  // Water tank
1601  Renew(tank_log, new G4LogicalVolume(tank_solid, Water, "tank_log", 0, 0, 0));
1602  Renew(tank_phys, new G4PVPlacement(nullptr, G4ThreeVector(fTankPos_x, fTankPos_y, fTankPos_z + fgTankHalfHeight + fgTankThickness), "tank", tank_log, expHall_phys, false, 0));
1603 
1604  // Top, bottom, side walls
1605  Renew(top_log, new G4LogicalVolume(top_solid, HDPE, "top_log", 0, 0, 0));
1606  Renew(bottom_log, new G4LogicalVolume(top_solid, HDPE, "bottom_log", 0, 0, 0));
1607  Renew(side_log, new G4LogicalVolume(side_solid, HDPE, "side_log", 0, 0, 0));
1608 
1609  Renew(top_phys, new G4PVPlacement(nullptr, G4ThreeVector(fTankPos_x, fTankPos_y, fTankPos_z + 2*fgTankHalfHeight + 1.5*fgTankThickness), "top", top_log, expHall_phys, false, 0));
1610  Renew(bottom_phys, new G4PVPlacement(nullptr, G4ThreeVector(fTankPos_x, fTankPos_y, fTankPos_z + 0.5*fgTankThickness), "bottom", bottom_log, expHall_phys, false, 0));
1611  Renew(side_phys, new G4PVPlacement(nullptr, G4ThreeVector(fTankPos_x, fTankPos_y, fTankPos_z + fgTankHalfHeight + fgTankThickness), "side", side_log, expHall_phys, false, 0));
1612 
1613  // the tank liner
1614  Renew(topsurface, new G4LogicalBorderSurface("topsurface", tank_phys, top_phys, OpLinerSurface));
1615  Renew(bottomsurface, new G4LogicalBorderSurface("bottomsurface", tank_phys, bottom_phys, OpLinerSurface));
1616  Renew(sidesurface, new G4LogicalBorderSurface("sidesurface", tank_phys, side_phys, OpLinerSurface));
1617 
1618  // PMTs and such
1619 
1620  // the interior volume of the pmt
1621  Renew(inner_log, new G4LogicalVolume(inner_solid, Vacuum, "inner_log", 0, 0, 0)); // standard pmt
1622 
1623  for (auto& pmt : fPMTs) {
1624  const unsigned int id = pmt.fId;
1625  const int pmtType = pmt.fPMTType;
1626  if (pmtType)
1627  continue;
1628 
1629  const auto& pos = pmt.fPMTPosition;
1630  const double x = pos.x();
1631  const double y = pos.y();
1632  const double z = fgTankHalfHeight;
1633 
1634  const G4ThreeVector p(x, y, z);
1635 
1636  ostringstream name;
1637  name << "inner" << id;
1638  Renew(pmt.fInner_phys, new G4PVPlacement(nullptr, p, inner_log, name.str().c_str(), tank_log, false, 0));
1639 
1640  // Sensitive surface of pmt faces
1641  name.str("");
1642  name << "pmt" << id << "_log";
1643  Renew(pmt.fPMT_log, new G4LogicalVolume(pmt_solid, Pyrex, name.str().c_str(), 0, 0, 0));
1644 
1645  name.str("");
1646  name << "pmt" << id;
1647  Renew(pmt.fPMT_phys, new G4PVPlacement(nullptr, p, pmt.fPMT_log, name.str().c_str(), tank_log, false, 0));
1648 
1649  // Non-sensitive surface of pmt faces
1650  name.str("");
1651  name << "pmt" << id << "_log1";
1652  Renew(pmt.fPMT_log1, new G4LogicalVolume(pmt_solid1, Pyrex1, name.str().c_str(), 0, 0, 0));
1653 
1654  name.str("");
1655  name << "pmt" << id << "1";
1656  Renew(pmt.fPMT_phys1, new G4PVPlacement(nullptr, p, pmt.fPMT_log1, name.str().c_str(), tank_log, false, 0));
1657 
1658  // The dome/face interface
1659  name.str("");
1660  name << "interface" << id << "_log";
1661  Renew(pmt.fInterface_log, new G4LogicalVolume(interface_solid, Interface, name.str().c_str(), 0, 0, 0));
1662 
1663  name.str("");
1664  name << "interface" << id;
1665  Renew(pmt.fInterface_phys, new G4PVPlacement(nullptr, p, pmt.fInterface_log, name.str().c_str(), tank_log, false, 0));
1666 
1667  // PMT domes
1668  name.str("");
1669  name << "dome" << id << "_log";
1670  Renew(pmt.fDome_log, new G4LogicalVolume(dome_solid, Lucite, name.str().c_str(), 0, 0, 0));
1671 
1672  name.str("");
1673  name << "dome" << id;
1674  Renew(pmt.fDome_phys, new G4PVPlacement(nullptr, p, pmt.fDome_log, name.str().c_str(), tank_log, false, 0));
1675 
1676  // Register the PMT's as sensitive detectors
1677  name.str("");
1678  name << "/Tank/pmt" << id;
1679  G4TankPMTAction* const pmtSD = new G4TankPMTAction(name.str().c_str(), pmt.fId);
1680  sdMan->AddNewDetector(pmtSD);
1681  pmt.fPMT_log->SetSensitiveDetector(pmtSD);
1682  }
1683 
1684  // Solar panel
1685  if (fSolarPanelEnable) {
1686  Renew(solarPanel_solid, new G4Box("SolarPanel", fSolarPanelThickness/2, fSolarPanelWidth/2, fSolarPanelLength/2));
1687  Renew(solarPanel_log, new G4LogicalVolume(solarPanel_solid, Al, "solarPanel_log")); // MAY BE CHANGED
1688 
1689  G4RotationMatrix* const solarPanelRot = new G4RotationMatrix();
1690  solarPanelRot->rotate(M_PI/2, G4ThreeVector(0, 0, 1));
1691  solarPanelRot->rotate(fSolarPanelTiltAngle, G4ThreeVector(0, 1, 0));
1692 
1693  Renew(solarPanel_phys, new G4PVPlacement(solarPanelRot, G4ThreeVector(fSolarPanelX, fSolarPanelY, fSolarPanelZ), "solarPanel", solarPanel_log, expHall_phys, false, 0));
1694  }
1695 
1696  // Chunk of Aluminum representing electronics box
1697  if (fElecBoxEnable) {
1698  Renew(elecBox_solid, new G4Box("ElecBox", fElecBoxThickness/2, fElecBoxWidth/2, fElecBoxLength/2));
1699  Renew(elecBox_log, new G4LogicalVolume(elecBox_solid, Al, "elecBox_log")); // MAY BE CHANGED
1700 
1701  G4RotationMatrix* const elecBoxRot = new G4RotationMatrix();
1702  elecBoxRot->rotate(M_PI/2, G4ThreeVector(0, 0, 1));
1703  elecBoxRot->rotate(fElecBoxTiltAngle, G4ThreeVector(0, 1, 0));
1704 
1705  Renew(elecBox_phys, new G4PVPlacement(elecBoxRot, G4ThreeVector(fElecBoxX, fElecBoxY, fElecBoxZ), "elecBox", elecBox_log, expHall_phys, false, 0));
1706  }
1707 
1708  // Elements specific to non-zero hardware versions
1709  if (fHasSmallPMT) {
1710 
1711  // Half the tank's height is used for the z-coordinate since the PMT volumes
1712  // are placed in the logical volume of the water, not the world volume
1713 
1714  // only for spmt but loop could be used to get scint pmt too
1715  for (auto& pmt : fPMTs) {
1716 
1717  const unsigned int id = pmt.fId;
1718  const int pmtType = pmt.fPMTType;
1719  if (pmtType != 1) // when scintillator we will put a || 2
1720  continue;
1721 
1722  const auto& pos = pmt.fPMTPosition;
1723  const double x = pos.x();
1724  const double y = pos.y();
1725  const double z = -fgTankThickness / 2;
1726  ostringstream name;
1727 
1728  // Sensitive surface of spmt face
1729  name.str("");
1730  name << "pmt" << id << "_log";
1731  Renew(pmt.fPMT_log, new G4LogicalVolume(s_pmt_solid, Pyrex, name.str().c_str(), 0, 0, 0));
1732 
1733  name.str("");
1734  name << "pmt" << id;
1735  Renew(pmt.fPMT_phys, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z + fPmtZ_SPMT), pmt.fPMT_log, name.str().c_str(), top_log, false, 0));
1736 
1737  // Non-sensitive surface of spmt face
1738  name.str("");
1739  name << "pmt" << id << "_log1";
1740  Renew(pmt.fPMT_log1, new G4LogicalVolume(s_pmt_solid1, Pyrex1, name.str().c_str(), 0, 0, 0));
1741 
1742  name.str("");
1743  name << "pmt" << id << "1";
1744  Renew(pmt.fPMT_phys1, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z + fPmtZ_SPMT), pmt.fPMT_log1, name.str().c_str(), top_log, false, 0));
1745 
1746  // The dome/face interface
1747  name.str("");
1748  name << "interface" << id << "_log";
1749  Renew(pmt.fInterface_log, new G4LogicalVolume(s_interface_solid, Interface, name.str().c_str(), 0, 0, 0));
1750 
1751  name.str("");
1752  name << "interface" << id;
1753  Renew(pmt.fInterface_phys, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z + fInterfaceZ_SPMT), pmt.fInterface_log, name.str().c_str(), top_log, false, 0));
1754 
1755  // sPMT dome
1756  name.str("");
1757  name << "dome" << id << "_log";
1758  Renew(pmt.fDome_log, new G4LogicalVolume(s_dome_solid, Lucite, name.str().c_str(), 0, 0, 0));
1759 
1760  name.str("");
1761  name << "dome" << id;
1762  Renew(pmt.fDome_phys, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z + fDomeZ_SPMT), pmt.fDome_log, name.str().c_str(), top_log, false, 0));
1763 
1764  // Register the sPMT as sensitive detector
1765  name.str("");
1766  name << "/Tank/pmt" << id;
1767  G4TankPMTAction* const pmtSD = new G4TankPMTAction(name.str().c_str(), pmt.fId);
1768  sdMan->AddNewDetector(pmtSD);
1769  pmt.fPMT_log->SetSensitiveDetector(pmtSD);
1770 
1771  }
1772  }
1773 
1774  if (fHasScintillator) {
1775  /* The scintillator origin is directly between two scintillator halves
1776  and mid-way through the thickness of the polystyrene scintillator material.
1777  The locations of all volumes are defined here are defined relative to this
1778  position. See SModelConfig for a schematic and more details. */
1779  const double x = fScintillatorPosition.x();
1780  const double y = fScintillatorPosition.y();
1781  const double z = fScintillatorPosition.z();
1782  // aluminum casing
1785  Renew(scin_casing_log, new G4LogicalVolume(scin_casing_solid, Al, "scin_casing_log"));
1786  Renew(scin_casing_phys, new G4PVPlacement(nullptr, G4ThreeVector(x, y, casing_z), "scin_casing", scin_casing_log, expHall_phys, false, 0));
1787  // sandwich panel (mother volume: casing)
1790  Renew(scin_sandwich_log, new G4LogicalVolume(scin_sandwich_solid, ExtrudedPolystyreneFoam, "scin_sandwich_log"));
1791  Renew(scin_sandwich_phys, new G4PVPlacement(nullptr, G4ThreeVector(0, 0, sandwich_z), scin_sandwich_log, "scin_sandwich", scin_casing_log, true, 0));
1792  // styrofoam (mother volume: casing)
1794  const double styro_z = fScintillatorHousingThickness/2 - styro_thickness/2;
1795  Renew(scin_styro_solid, new G4Box("scin_sandwich_solid", fScintillatorHousingLength/2, fScintillatorHousingWidth/2, styro_thickness/2));
1796  Renew(scin_styro_log, new G4LogicalVolume(scin_styro_solid, ExpandedPolystyreneFoam, "scin_styro_log"));
1797  Renew(scin_styro_phys, new G4PVPlacement(nullptr, G4ThreeVector(0, 0, styro_z), scin_styro_log, "scin_styro", scin_casing_log, true, 0));
1798  // scintillator (mother volume: styrofoam)
1799  const double bars_z = fScintillatorCasingThickness + fScintillatorBarThickness/2 - styro_thickness/2;
1801  Renew(scin_log, new G4LogicalVolume(scin_solid, Polystyrene, "scin_log"));
1802  Renew(scin_phys1, new G4PVPlacement(nullptr, G4ThreeVector(-(fScintillatorGap + fScintillatorBarLength)/2, 0, bars_z), scin_log, "scin_bars", scin_styro_log, true, 0));
1803  Renew(scin_phys2, new G4PVPlacement(nullptr, G4ThreeVector((fScintillatorGap + fScintillatorBarLength)/2, 0, bars_z), scin_log, "scin_bars", scin_styro_log, true, 1));
1804  // registration
1805  G4ScintillatorAction* const scintillatorSD = new G4ScintillatorAction("/Scintillator/scin_bars");
1806  sdMan->AddNewDetector(scintillatorSD);
1807  scin_log->SetSensitiveDetector(scintillatorSD);
1808  // roof
1809  const double roof_z = z - 0.5*fScintillatorBarThickness - fScintillatorCasingThickness - fScintillatorSandwichPanelThickness + fScintillatorHousingThickness + fScintillatorRoofOffset + 0.5*fScintillatorRoofThickness;
1811  Renew(scin_roof_log, new G4LogicalVolume(scin_roof_solid, Al, "scin_roof_log"));
1812  Renew(scin_roof_phys, new G4PVPlacement(nullptr, G4ThreeVector(x, y, roof_z), "scin_roof", scin_roof_log, expHall_phys, false, 0));
1813  }
1814 
1815  // Creates Amiga underground primitives
1816  if (fUMDEnabled) {
1817  const auto& dStation = G4StationSimulator::fgCurrent.GetDetectorStation();
1818  if (!dStation.ExistsAssociatedCounter()) {
1819  ostringstream err;
1820  err << "Trying to simulate the UMD in a WCD (Id " << dStation.GetId() << ") that has not an underground AMIGA scintillator associated!";
1821  //throw utl::NonExistentComponentException(err.str());
1822  WARNING(err);
1823  }
1824  AssembleUMD();
1825  }
1826 
1827  // Assembles MARTA RPC
1828  if (fMARTAEnabled)
1829  AssembleMARTA();
1830  }
1831 
1832 
1833  void
1835  {
1836  G4SDManager* const sdMan = G4SDManager::GetSDMpointer();
1837 
1838  // Casings
1839  Renew(umd_casing_log_large, new G4LogicalVolume(umd_casing_solid_large, PVC, "umd_casing_log_large", 0, 0, 0));
1840  Renew(umd_casing_log_small, new G4LogicalVolume(umd_casing_solid_small, PVC, "umd_casing_log_small", 0, 0, 0));
1841 
1842  // Scintillator Strips
1843  Renew(umd_strip_log_large, new G4LogicalVolume(umd_strip_solid_large, ScintMat, "umd_strip_log_large", 0, 0, 0));
1844  const G4VisAttributes blue(G4Colour::Blue());
1845  umd_strip_log_large->SetVisAttributes(blue);
1846 
1847  // registration
1848  G4UMDScintStripAction* const umdScintStripLargeSD = new G4UMDScintStripAction("/UMDStrip/umd_strip_large");
1849  sdMan->AddNewDetector(umdScintStripLargeSD);
1850  umd_strip_log_large->SetSensitiveDetector(umdScintStripLargeSD);
1851 
1852  Renew(umd_strip_log_small, new G4LogicalVolume(umd_strip_solid_small, ScintMat, "umd_strip_log_small", 0, 0, 0));
1853  umd_strip_log_small->SetVisAttributes(blue);
1854  // registration
1855  G4UMDScintStripAction* const umdScintStripSmallSD = new G4UMDScintStripAction("/UMDStrip/umd_strip_small");
1856  sdMan->AddNewDetector(umdScintStripSmallSD);
1857  umd_strip_log_small->SetSensitiveDetector(umdScintStripSmallSD);
1858 
1859  // Reflective TiO2 coating (surface)
1860  Renew(umd_top_bot_coat_log_large, new G4LogicalVolume(umd_top_bot_coat_solid_large, ScintCoating, "umd_top_bot_coat_log_large", 0, 0, 0));
1861  const G4VisAttributes black(G4Colour::Black());
1862  umd_top_bot_coat_log_large->SetVisAttributes(black);
1863 
1864  Renew(umd_side_coat_log_large, new G4LogicalVolume(umd_side_coat_solid_large, ScintCoating, "umd_side_coat_log_large", 0, 0, 0));
1865  umd_side_coat_log_large->SetVisAttributes(black);
1866 
1867  Renew(umd_top_bot_coat_log_small, new G4LogicalVolume(umd_top_bot_coat_solid_small, ScintCoating, "umd_top_bot_coat_log_small", 0, 0, 0));
1868  umd_top_bot_coat_log_small->SetVisAttributes(black);
1869 
1870  Renew(umd_side_coat_log_small, new G4LogicalVolume(umd_side_coat_solid_small, ScintCoating, "umd_side_coat_log_small", 0, 0, 0));
1871  umd_side_coat_log_small->SetVisAttributes(black);
1872 
1873  Renew(umd_back_side_coat_log, new G4LogicalVolume(umd_back_side_coat_solid, ScintCoating, "umd_back_side_coat_log", 0, 0, 0));
1874  const G4VisAttributes brown(G4Colour::Brown());
1875  umd_back_side_coat_log->SetVisAttributes(brown);
1876 
1877  const G4VisAttributes green(G4Colour::Green());
1879  // if detector needed for full simulation mode (optical photons)
1880  // Fibers (neglects OnManifold differences for the moment)
1881  // Core
1882  Renew(umd_fiber_core_log_large, new G4LogicalVolume(umd_fiber_core_solid_large, PMMA, "umd_fiber_core_log_large", 0, 0, 0));
1883  umd_fiber_core_log_large->SetVisAttributes(green);
1884  // Clad1 (internal)
1885  Renew(umd_fiber_clad1_log_large, new G4LogicalVolume(umd_fiber_clad1_solid_large, Pethylene, "umd_fiber_clad1_log_large", 0, 0, 0));
1886  umd_fiber_clad1_log_large->SetVisAttributes(blue);
1887  // Clad2 (external)
1888  Renew(umd_fiber_clad2_log_large, new G4LogicalVolume(umd_fiber_clad2_solid_large, FPethylene, "umd_fiber_clad2_log_large", 0, 0, 0));
1889  umd_fiber_clad2_log_large->SetVisAttributes(blue);
1890  // Core
1891  Renew(umd_fiber_core_log_small, new G4LogicalVolume(umd_fiber_core_solid_small, PMMA, "umd_fiber_core_log_small", 0, 0, 0));
1892  umd_fiber_core_log_small->SetVisAttributes(green);
1893  // Clad1 (internal)
1894  Renew(umd_fiber_clad1_log_small, new G4LogicalVolume(umd_fiber_clad1_solid_small, Pethylene, "umd_fiber_clad1_log_small", 0, 0, 0));
1895  umd_fiber_clad1_log_small->SetVisAttributes(blue);
1896  // Clad2 (external)
1897  Renew(umd_fiber_clad2_log_small, new G4LogicalVolume(umd_fiber_clad2_solid_small, FPethylene, "umd_fiber_clad2_log_small", 0, 0, 0));
1898  umd_fiber_clad2_log_small->SetVisAttributes(blue);
1899  // Pixels (for sensitive detector)
1900  Renew(pixel_log, new G4LogicalVolume(pixel_solid, Pyrex, "pixel_log", 0, 0, 0));
1901  pixel_log->SetVisAttributes(black);
1902  // registration
1903  G4UMDPixelAction* const umdPixelSD = new G4UMDPixelAction("/UMDPixel/umd_pixel");
1904  sdMan->AddNewDetector(umdPixelSD);
1905  pixel_log->SetSensitiveDetector(umdPixelSD);
1906  // Skin Properties of coating
1908  }
1909 
1910  // Get the muon detector
1911  const mdet::MDetector& mDet = det::Detector::GetInstance().GetMDetector();
1912  const auto& dStation = G4StationSimulator::fgCurrent.GetDetectorStation();
1913  const mdet::Counter& dCounter = mDet.GetCounter(dStation.GetAssociatedCounterId());
1914 
1915  ostringstream name;
1916 
1917  // Loop over muon modules (may only differs in bar lengths)
1918  for (auto mIt = dCounter.ModulesBegin(); mIt != dCounter.ModulesEnd(); ++mIt) {
1919 
1920  const mdet::Module::AreaKind area = mIt->GetAreaKind();
1921  const mdet::Module& mod = *mIt;
1922 
1923  std::cout << (area == mdet::Module::AreaKind::eLarge ? "10m2" : "5m2") << std::endl;
1924 
1925  const auto cs = dCounter.GetLocalCoordinateSystem();
1926  const auto& modPos = mod.GetPosition();
1927  const double x = modPos.GetX(cs) * kDistanceToG4;
1928  const double y = modPos.GetY(cs) * kDistanceToG4;
1929  const double z = modPos.GetZ(cs) * kDistanceToG4 + fGroundThickness/2;
1930  // zero here is measured from the center of ground cylinder
1931  const G4ThreeVector pos(x, y, z);
1932 
1933  // Casing rotation
1934  G4RotationMatrix* const rotMod = new G4RotationMatrix();
1935  rotMod->rotateZ(-mod.GetPhi0()); // The minus sign is to take into account that positive angle means clockwise rotation for G4
1936  // while it is counterclockwise for Offline.
1937 
1938  name.str("");
1939  name << "module_" << mod.GetId() << '_' << dCounter.GetId();
1940 
1941  if (area == mdet::Module::AreaKind::eLarge)
1942  NotRenew(umd_casing_phys_large, new G4PVPlacement(rotMod, pos, name.str() + "_large", umd_casing_log_large, ground_phys, false, mod.GetId()));
1943  else
1944  NotRenew(umd_casing_phys_small, new G4PVPlacement(rotMod, pos, name.str() + "_small", umd_casing_log_small, ground_phys, false, mod.GetId()));
1945 
1946  }
1947 
1948  // As mother volumes (mod_phys in this case) has multiple copies, child volumes
1949  // (umd_strip_phys) do not need to be replicated
1950  // Loop only over area kinds
1951  for (const auto& ml : fModAreaLenghts) {
1952  const auto area = ml.first;
1953  std::cout << "Creating G4 physcal volume for " << (area == mdet::Module::AreaKind::eLarge ? "10m2" : "5m2") << " module" << std::endl;
1954 
1955  auto mIt = dCounter.ModulesBegin();
1956  for ( ; mIt != dCounter.ModulesEnd(); ++mIt)
1957  if (mIt->GetAreaKind() == area)
1958  break;
1959  if (mIt == dCounter.ModulesEnd())
1960  continue;
1961 
1962  const mdet::Module& mod = *mIt;
1963  const double shortestFiber = mod.GetShortestFiber();
1964 
1965  // Scintillators
1966  Renew(umd_strip_phys_large, static_cast<decltype(umd_strip_phys_large)>(nullptr));
1967  Renew(umd_strip_phys_small, static_cast<decltype(umd_strip_phys_small)>(nullptr));
1968 
1969  for (auto scIt = mod.ScintillatorsBegin(); scIt != mod.ScintillatorsEnd(); ++scIt) {
1970 
1971  const mdet::Scintillator& sc = *scIt;
1972  const mdet::Fiber& fiber = mod.GetFiberFor(sc);
1973 
1974  const auto cs = mod.GetLocalCoordinateSystem();
1975  const double x = sc.GetPosition().GetX(cs) * kDistanceToG4;
1976  const double y = sc.GetPosition().GetY(cs) * kDistanceToG4;
1977  const double z = sc.GetPosition().GetZ(cs) * kDistanceToG4;
1978 
1979  // This cannot be <= 0
1980  // removes the shortest length. Only relative difference is important
1981  const double onManiFold = fiber.GetOnManifoldLength() * kDistanceToG4 - shortestFiber * kDistanceToG4 + 2*fPixelL;
1982  const double dx = (x > 0 ? -1 : 1) * (fModAreaLenghts[area]/2 + onManiFold/2 - fCoatingThickness);
1983 
1984  NotRenew(extra_fiber_solid, new G4Tubs("extra_fiber_solid", 0, fUMDFiberRadius - 2*fCladingThickness, onManiFold/2, 0, 360*CLHEP::deg));
1985  NotRenew(extra_fiber_log, new G4LogicalVolume(extra_fiber_solid, PMMA, "extra_fiber_log", 0, 0, 0));
1986  extra_fiber_log->SetVisAttributes(green);
1987 
1988  NotRenew(extra_clad1_solid, new G4Tubs("extra_clad1_solid", 0, fUMDFiberRadius - fCladingThickness, onManiFold/2, 0, 360*CLHEP::deg));
1989  NotRenew(extra_clad1_log, new G4LogicalVolume(extra_clad1_solid, Pethylene, "extra_clad1_log", 0, 0, 0));
1990  extra_clad1_log->SetVisAttributes(blue);
1991 
1992  NotRenew(extra_clad2_solid, new G4Tubs("extra_clad2_solid", 0, fUMDFiberRadius, onManiFold/2, 0, 360*CLHEP::deg));
1993  NotRenew(extra_clad2_log, new G4LogicalVolume(extra_clad2_solid, FPethylene, "extra_clad2_log", 0, 0, 0));
1994  extra_clad2_log->SetVisAttributes(blue);
1995 
1996  if (area == mdet::Module::AreaKind::eLarge) {
1997 
1998  name.str("");
1999  name << "umd_strip_" << sc.GetId();
2000  NotRenew(umd_strip_phys_large, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z), name.str() + "_large", umd_strip_log_large, umd_casing_phys_large, false, sc.GetId()));
2001 
2003 
2004  string nm = "umd_top_coat";
2005  NotRenew(umd_top_coat_phys_large, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z + fUMDScintsH/2 - fCoatingThickness/2), nm + "_large", umd_top_bot_coat_log_large, umd_casing_phys_large, false, 0));
2006 
2007  nm = "umd_bot_coat";
2008  NotRenew(umd_bot_coat_phys_large, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z - fUMDScintsH/2 + fCoatingThickness/2), nm + "_large", umd_top_bot_coat_log_large, umd_casing_phys_large, false, 0));
2009 
2010  nm = "umd_side1_coat";
2011  NotRenew(umd_side1_coat_phys_large, new G4PVPlacement(nullptr, G4ThreeVector(x, y + fUMDScintsW/2 - fCoatingThickness/2, z), nm + "_large", umd_side_coat_log_large, umd_casing_phys_large, false, 0));
2012 
2013  nm = "umd_side2_coat";
2014  NotRenew(umd_side2_coat_phys_large, new G4PVPlacement(nullptr, G4ThreeVector(x, y - fUMDScintsW/2 + fCoatingThickness/2, z), nm + "_large", umd_side_coat_log_large, umd_casing_phys_large, false, 0));
2015 
2016  nm = "umd_back_side_coat";
2017  const double xx = (x > 0 ? 1 : -1) * (fModAreaLenghts[area]/2 - fCoatingThickness/2);
2018  NotRenew(umd_back_side_coat_phys, new G4PVPlacement(nullptr, G4ThreeVector(x + xx, y, z), nm + "_large", umd_back_side_coat_log, umd_casing_phys_large, false, 0));
2019 
2020  G4RotationMatrix* const erot = new G4RotationMatrix();
2021  erot->rotateY(M_PI/2);
2022  const double z = fUMDScintsH/2 - fCoatingThickness - fUMDFiberRadius - fCladingThickness; // at top of the strip
2023 
2024  NotRenew(extra_clad2_phy, new G4PVPlacement(erot, G4ThreeVector(x+dx, y, z), "extra_clad2", extra_clad2_log, umd_casing_phys_large, false, 0));
2025 
2026  NotRenew(extra_clad1_phy, new G4PVPlacement(nullptr, G4ThreeVector(), "extra_clad1", extra_clad1_log, extra_clad2_phy, false, 0));
2027 
2028  NotRenew(extra_fiber_phy, new G4PVPlacement(nullptr, G4ThreeVector(), "extra_fiber", extra_fiber_log, extra_clad1_phy, false, 0));
2029 
2030  G4RotationMatrix* const prot = new G4RotationMatrix();
2031  prot->rotateY(M_PI/2);
2032 
2033  name.str("");
2034  name << "mod_pix_" << sc.GetId();
2035  NotRenew(pixel_phy, new G4PVPlacement(prot, G4ThreeVector(x + dx + (x > 0 ? -1 : 1)*(onManiFold/2 + fPixelL/2), y, z), name.str(), pixel_log, umd_casing_phys_large, false, sc.GetId()));
2036  }
2037 
2038  } else {
2039 
2040  name.str("");
2041  name << "umd_strip_" << sc.GetId();
2042  NotRenew(umd_strip_phys_small, new G4PVPlacement(nullptr, G4ThreeVector(x,y,z), name.str() + "_small", umd_strip_log_small, umd_casing_phys_small, false, sc.GetId()));
2043 
2045  NotRenew(umd_top_coat_phys_small, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z + fUMDScintsH/2 - fCoatingThickness/2), "umd_top_coat_small", umd_top_bot_coat_log_small, umd_casing_phys_small, false, 0));
2046 
2047  NotRenew(umd_bot_coat_phys_small, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z - fUMDScintsH/2 + fCoatingThickness/2), "umd_bot_coat_small", umd_top_bot_coat_log_small, umd_casing_phys_small, false, 0));
2048 
2049  NotRenew(umd_side1_coat_phys_small, new G4PVPlacement(nullptr, G4ThreeVector(x, y + fUMDScintsW/2 - fCoatingThickness/2, z), "umd_side1_coat_small", umd_side_coat_log_small, umd_casing_phys_small, false, 0));
2050 
2051  NotRenew(umd_side2_coat_phys_small, new G4PVPlacement(nullptr, G4ThreeVector(x, y - fUMDScintsW/2 + fCoatingThickness/2, z), "umd_side2_coat_small", umd_side_coat_log_small, umd_casing_phys_small, false, 0));
2052 
2053  const double xx = (x > 0 ? 1 : -1) * (fModAreaLenghts[area]/2 - fCoatingThickness/2);
2054  NotRenew(umd_back_side_coat_phys, new G4PVPlacement(nullptr, G4ThreeVector(x + xx, y, z), "umd_back_side_coat_small", umd_back_side_coat_log, umd_casing_phys_small, false, 0));
2055 
2056  G4RotationMatrix* const erot = new G4RotationMatrix();
2057  erot->rotateY(M_PI/2);
2058  const double z = fUMDScintsH/2 - fCoatingThickness - fUMDFiberRadius - fCladingThickness; // at top of the strip
2059 
2060  NotRenew(extra_clad2_phy, new G4PVPlacement(erot, G4ThreeVector(x + dx, y, z), "extra_clad2", extra_clad2_log, umd_casing_phys_small, false, 0));
2061 
2062  NotRenew(extra_clad1_phy, new G4PVPlacement(nullptr, G4ThreeVector(), "extra_clad1", extra_clad1_log, extra_clad2_phy, false, 0));
2063 
2064  NotRenew(extra_fiber_phy, new G4PVPlacement(nullptr, G4ThreeVector(), "extra_fiber", extra_fiber_log, extra_clad1_phy, false, 0));
2065 
2066  G4RotationMatrix* const prot = new G4RotationMatrix();
2067  prot->rotateY(M_PI/2);
2068 
2069  name.str("");
2070  name << "mod_pix_" << sc.GetId();
2071  NotRenew(pixel_phy, new G4PVPlacement(prot, G4ThreeVector(x + dx + (x > 0 ? -1 : 1)*(onManiFold/2 + fPixelL/2), y, z), name.str(), pixel_log, umd_casing_phys_small, false, sc.GetId()));
2072  }
2073 
2074  }
2075 
2076  }
2077 
2078  }
2079 
2081  // As mother volume (umd_strip_phys) has multiple copies, child volumes (umd_strip_log) do not need to be replicated
2082  if (umd_strip_phys_large) {
2083 
2084  double x = 0;
2085  double y = 0;
2086  double z = fUMDScintsH/2 - fCoatingThickness - fUMDFiberRadius - fCladingThickness; // at top of the strip
2087  G4RotationMatrix* const frotMod_large = new G4RotationMatrix();
2088  frotMod_large->rotateY(M_PI/2);
2089  NotRenew(umd_fiber_clad2_phys_large, new G4PVPlacement(frotMod_large, G4ThreeVector(x, y, z), "umd_fiber_clad2_large", umd_fiber_clad2_log_large, umd_strip_phys_large, false, 0));
2090 
2091  x = 0;
2092  y = 0;
2093  z = 0;
2094  NotRenew(umd_fiber_clad1_phys_large, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z), "umd_fiber_clad1_large", umd_fiber_clad1_log_large, umd_fiber_clad2_phys_large, false, 0));
2095 
2096  x = 0;
2097  y = 0;
2098  z = 0;
2099  NotRenew(umd_fiber_core_phys_large, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z), "umd_fiber_core_large", umd_fiber_core_log_large, umd_fiber_clad1_phys_large, false, 0));
2100 
2101  }
2102 
2103  if (umd_strip_phys_small) {
2104 
2105  double x = 0;
2106  double y = 0;
2107  double z = fUMDScintsH/2 - fCoatingThickness - fUMDFiberRadius - fCladingThickness; // at top of the strip
2108 
2109  G4RotationMatrix* const frotMod_small = new G4RotationMatrix();
2110  frotMod_small->rotateY(M_PI/2);
2111  NotRenew(umd_fiber_clad2_phys_small, new G4PVPlacement(frotMod_small, G4ThreeVector(x, y, z), "umd_fiber_clad2_small", umd_fiber_clad2_log_small, umd_strip_phys_small, false, 0));
2112 
2113  x = 0;
2114  y = 0;
2115  z = 0;
2116  NotRenew(umd_fiber_clad1_phys_small, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z), "umd_fiber_clad1_small", umd_fiber_clad1_log_small, umd_fiber_clad2_phys_small, false, 0));
2117 
2118  x = 0;
2119  y = 0;
2120  z = 0;
2121  NotRenew(umd_fiber_core_phys_small, new G4PVPlacement(nullptr, G4ThreeVector(x, y, z), "umd_fiber_core_small", umd_fiber_core_log_small, umd_fiber_clad1_phys_small, false, 0));
2122 
2123  }
2124  }
2125  }
2126 
2127 
2128  void
2130  {
2131  if (fMakeTankSupport)
2133 
2134  // Aluminium box
2135  const G4ThreeVector alBoxSize = fAlBoxInnerDimensions + 2*fAlBoxThickness;
2136 
2137  Renew(al_box_log, new G4LogicalVolume(AlBox_solid, Al, "Al_box_log", 0, 0, 0));
2138 
2139  // RPC
2140  const double rpcAcrylicThickness = 0.80*CLHEP::mm;
2141  const double rpcGlassThickness = 1.85*CLHEP::mm;
2142  const double rpcGasThickness = 1.0*CLHEP::mm;
2143  const double rpcHeight = 2.0*rpcAcrylicThickness + 3.0*rpcGlassThickness + 2.0*rpcGasThickness;
2144 
2145  const double pcb_halfZ = fPCBThickness/2;
2146 
2147  const double spacer_thickness = fSpacerThickness;
2148  const double spacer_halfZ = spacer_thickness/2;
2149 
2150  Renew(pcb_log, new G4LogicalVolume(pcb_solid, fG4_Bakelite, "pcb_log", 0, 0, 0));
2151  Renew(spacer_log, new G4LogicalVolume(spacer_solid, ExpandedPolystyreneFoam, "spacer_log", 0, 0, 0));
2152  Renew(rpc_log, new G4LogicalVolume(rpc_solid, fG4_Acrylic, "rpc_log", 0, 0, 0));
2153  Renew(glass_log, new G4LogicalVolume(glass_solid, fSoda_lime_glass, "rpc_glass_log", 0, 0, 0));
2154  Renew(gas_log, new G4LogicalVolume(gas_solid, fR134a, "rpc_gas_log", 0, 0, 0));
2155 
2156  // Position the two gas gaps inside the glass
2157 
2158  const G4ThreeVector gasPos1(0, 0, (rpcGlassThickness + rpcGasThickness)/2);
2159  const G4ThreeVector gasPos2 = -gasPos1;
2160 
2161  new G4PVPlacement(nullptr, gasPos1, gas_log, "rpc_gas", glass_log, false, 0);
2162  new G4PVPlacement(nullptr, gasPos2, gas_log, "rpc_gas", glass_log, false, 1);
2163 
2164  // Position the glass inside the acrylic
2165 
2166  const G4ThreeVector glassPos;
2167  new G4PVPlacement(nullptr, glassPos, glass_log, "rpc_glass", rpc_log, false, 0);
2168 
2169  // end RPC
2170 
2171  // Position tank support in the world volume;
2172  // in the G4 coordinate system z=0 is the outer surface of the tank bottom
2173 
2174  // Position different components in the world volume
2175  for (unsigned int i = 0 ; i < fRPCPositions.size() ; ++i) {
2176 
2177  // Position Al box
2178  // RPC position are given in the SD coordinate system
2179 
2180  const G4ThreeVector alBox_pos =
2181  fRPCPositions[i] + fgTankCenter + G4ThreeVector(0, 0, alBoxSize[2]/2) + G4ThreeVector(0, 0, 0.1*CLHEP::cm); // for tolerance
2182 
2183  // Position RPC inside concrete precast
2184 
2185  const G4ThreeVector rpc_pos =
2186  alBox_pos - G4ThreeVector(0, 0, fAlBoxInnerDimensions[2]/2) + G4ThreeVector(0, 0, rpcHeight/2) + G4ThreeVector(0, 0, 0.1*CLHEP::cm); // for tolerance
2187 
2188  // Position PCB + Spacer
2189 
2190  const G4ThreeVector pcb_1_pos =
2191  rpc_pos + G4ThreeVector(0, 0, (rpcHeight/2 + pcb_halfZ)) + G4ThreeVector(0, 0, 0.1*CLHEP::mm); // for tolerance
2192 
2193  const G4ThreeVector spacer_pos =
2194  pcb_1_pos + G4ThreeVector(0, 0, (pcb_halfZ + spacer_halfZ)) + G4ThreeVector(0, 0, 0.1*CLHEP::mm); // for tolerance
2195 
2196  const G4ThreeVector pcb_2_pos =
2197  spacer_pos + G4ThreeVector(0, 0, (spacer_halfZ + pcb_halfZ)) + G4ThreeVector(0, 0, 0.1*CLHEP::mm); // for tolerance
2198 
2199  // Rotation of RPC chamber
2200  G4RotationMatrix* const r = new G4RotationMatrix();
2201  r->rotate(fRPCRotations[i], G4ThreeVector(0, 0, 1));
2202 
2203  new G4PVPlacement(r, alBox_pos, "Al_box",al_box_log, expHall_phys, false, i+1);
2204  new G4PVPlacement(r, rpc_pos, "rpc", rpc_log, expHall_phys, false, i+1);
2205  new G4PVPlacement(r, pcb_1_pos, "pcb1", pcb_log, expHall_phys, false, i+1);
2206  new G4PVPlacement(r, pcb_2_pos, "pcb2", pcb_log, expHall_phys, false, i+1);
2207  new G4PVPlacement(r, spacer_pos, "spacer", spacer_log, expHall_phys, false, i+1);
2208  }
2209 
2210  // Visualization attributes
2211 
2212  G4VisAttributes* const rpcVisAtt = new G4VisAttributes(G4Colour::Red());
2213  rpcVisAtt->SetForceWireframe(true);
2214  rpc_log->SetVisAttributes(rpcVisAtt);
2215 
2216  G4VisAttributes* const glassVisAtt = new G4VisAttributes(G4Colour::Yellow());
2217  glassVisAtt->SetForceWireframe(true);
2218  glass_log->SetVisAttributes(glassVisAtt);
2219 
2220  G4VisAttributes* const gasVisAtt = new G4VisAttributes(G4Colour::Cyan());
2221  gasVisAtt->SetForceWireframe(true);
2222  gas_log->SetVisAttributes(gasVisAtt);
2223 
2224  G4VisAttributes* const alBoxVisAtt = new G4VisAttributes(G4Colour::Grey());
2225  alBoxVisAtt->SetForceSolid(true);
2226  alBoxVisAtt->SetVisibility(true);
2227  alBoxVisAtt->SetForceWireframe(true);
2228  al_box_log->SetVisAttributes(alBoxVisAtt);
2229 
2230  G4VisAttributes* const pcbVisAtt = new G4VisAttributes(G4Colour::Green());
2231  pcbVisAtt->SetForceSolid(true);
2232  //pcbVisAtt->SetForceWireframe(true);
2233  pcb_log->SetVisAttributes(pcbVisAtt);
2234 
2235  spacer_log->SetVisAttributes(new G4VisAttributes(G4Colour::White()));
2236  }
2237 
2238 
2239  // Creates the MARTA RPC concrete support
2240  void
2242  {
2243  const G4ThreeVector tankSupport_pos =
2244  G4ThreeVector(0, 0, fTankPos_z - (fTankSupportTopSlabDimensions[2]/2 + 0.1*CLHEP::cm)); // for tolerance
2245 
2246  G4Box* const topSlab = new G4Box("topSlab", fTankSupportTopSlabDimensions[0]/2, fTankSupportTopSlabDimensions[1]/2, fTankSupportTopSlabDimensions[2]/2);
2247 
2248  G4Box* const centralFoot = new G4Box("centralFoot", fTankSupportCentralFootDimensions[0]/2, fTankSupportCentralFootDimensions[1]/2, fTankSupportCentralFootDimensions[2]/2);
2249 
2250  G4Box* const centralFootBase = new G4Box("centralFootBase", fTankSupportCentralFootBaseDimensions[0]/2, fTankSupportCentralFootBaseDimensions[1]/2, fTankSupportCentralFootBaseDimensions[2]/2);
2251 
2252  const G4ThreeVector trans1(0, 0, -(fTankSupportCentralFootDimensions[2]/2 + fTankSupportCentralFootBaseDimensions[2]/2 - 0.1*CLHEP::mm));
2253 
2254  G4BooleanSolid* const centralFoot_solid = new G4UnionSolid("centralFoot_solid", centralFoot, centralFootBase, 0, trans1);
2255 
2256  // Build now the outer foot
2257  G4Box* const outerFoot = new G4Box("outerFoot", fTankSupportOuterFootDimensions[0]/2, fTankSupportOuterFootDimensions[1]/2, fTankSupportOuterFootDimensions[2]/2);
2258 
2259  G4Box* const outerFootBase = new G4Box("outerFootBase", fTankSupportOuterFootBaseDimensions[0]/2, fTankSupportOuterFootBaseDimensions[1]/2, fTankSupportOuterFootBaseDimensions[2]/2);
2260 
2261  const G4ThreeVector trans2(0, 0, -(fTankSupportOuterFootDimensions[2]/2 + fTankSupportOuterFootBaseDimensions[2]/2 - 0.1*CLHEP::mm));
2262 
2263  G4BooleanSolid* const outerFoot_solid = new G4UnionSolid("outerFoot_solid", outerFoot, outerFootBase, 0, trans2);
2264 
2265  // Now join everything
2266  const G4ThreeVector trans3(0, 0, -(fTankSupportTopSlabDimensions[2]/2 + fTankSupportCentralFootDimensions[2]/2 - 0.1*CLHEP::mm));
2267 
2268  G4BooleanSolid* const tankSupport_solid_0 = new G4UnionSolid("tank_support_0", topSlab, centralFoot_solid, 0, trans3);
2269 
2271 
2272  G4BooleanSolid* const tankSupport_solid_1 = new G4UnionSolid("tank_support_1", tankSupport_solid_0, outerFoot_solid, 0, trans4);
2273 
2275 
2276  G4BooleanSolid* const tankSupport_solid = new G4UnionSolid("tank_support", tankSupport_solid_1, outerFoot_solid, 0, trans5);
2277 
2278  // tank support is made of concrete
2279  G4LogicalVolume* const tankSupport_log = new G4LogicalVolume(tankSupport_solid, fG4_Concrete, "tank_support_log", 0, 0, 0);
2280 
2281  new G4PVPlacement(nullptr, tankSupport_pos, "tank_support", tankSupport_log, expHall_phys, false, 0);
2282 
2283  G4VisAttributes* const tankSupportVisAtt = new G4VisAttributes(G4Colour::Grey());
2284  tankSupportVisAtt->SetForceSolid(true);
2285  tankSupportVisAtt->SetVisibility(true);
2286  tankSupportVisAtt->SetForceWireframe(true);
2287  if (tankSupport_log)
2288  tankSupport_log->SetVisAttributes(tankSupportVisAtt);
2289  }
2290 
2291 
2292  void
2294  {
2295  SetDetectorParameters(); // updates G4StationConstruction data tables
2296 
2297  // clean up old geometry list
2298  G4GeometryManager::GetInstance()->OpenGeometry();
2299  G4PhysicalVolumeStore::GetInstance()->Clean();
2300  G4LogicalVolumeStore::GetInstance()->Clean();
2301  G4SolidStore::GetInstance()->Clean();
2302 
2303  // update material properties (deleting out of date materials and
2304  // replacing them with new ones).
2305  CreateWater();
2306  CreatePyrex();
2307  CreateLucite();
2308  CreateInterface();
2309  CreateHDPE();
2310  CreateLiner();
2311 
2312  // assemble objects with new sizes and materials
2313  G4RunManager::GetRunManager()->DefineWorldVolume(CreateTank(), true);
2314  }
2315 
2316 }
void Convert(std::vector< T1, A1 > &destination, const std::vector< T2, A2 > &source)
const double eV
Definition: GalacticUnits.h:35
unsigned int GetNPoints() const
constexpr double eV
Definition: AugerUnits.h:185
constexpr double mm
Definition: AugerUnits.h:113
constexpr double perCent
Definition: AugerUnits.h:282
const double degree
Point object.
Definition: Point.h:32
constexpr double atmosphere
Definition: AugerUnits.h:215
constexpr double cm3
Definition: AugerUnits.h:119
static const G4Colour green(0.0, 1.0, 0.0)
boost::tuple< double, double, double > Triple
Coordinate triple for easy getting or setting of coordinates.
Definition: BasicVector.h:147
ArrayIterator XEnd()
end of array of X
Base class for exceptions arising because configuration data are not valid.
Class to hold collection (x,y) points and provide interpolation between them.
virtual G4VPhysicalVolume * Construct() override
double GetRPCSizeX() const
Dimensions of the RPC chamber.
utl::CoordinateSystemPtr GetLocalCoordinateSystem() const
Local system based on position and configured rotations.
const Fiber & GetFiberFor(const Component &c) const
Linking between fibers, scintillators, channels and pixels.
double GetHousingWidth() const
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
ScintillatorConstIterator ScintillatorsBegin() const
Begin iterator over the contained scitillators.
utl::Point GetPosition() const
std::vector< double > GetTankSupportOuterFootBaseDimensions() const
void PushBack(const double x, const double y)
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
Definition: Branch.cc:211
static utl::TabulatedFunction fgLinerSPECULARLOBECONSTANT
ModuleConstIterator ModulesEnd() const
Begin iterator for the Modules contained in the Counter.
Detector associated to muon detector hierarchy.
Definition: MDetector.h:32
TransformerConstructor< DerivedCSPolicy > CoordinateSystem
The normal coordinate system type.
double GetSandwichPanelThickness() const
Detector description interface for MARTA Station-related data.
Exception for reporting variable out of valid range.
constexpr double deg
Definition: AugerUnits.h:140
unsigned int GetNBars() const
Actual muon-sensitive objects.
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
std::vector< double > GetRPCHousingInnerDimensions() const
Size of the RPC aluminum housing.
Class representing a document branch.
Definition: Branch.h:107
std::vector< double > GetTankSupportOuterFootDimensions() const
G4ThreeVector Convert(const utl::Point p, const utl::CoordinateSystemPtr cs)
constexpr double mole
Definition: AugerUnits.h:262
constexpr double s
Definition: AugerUnits.h:163
ArrayConstReference XFront() const
read-only reference to front of array of X
double GetHousingThickness() const
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
class that handles hits to scintillator bars
const double ns
int GetNumberRPCChambers() const
Number of RPC Chambers.
std::vector< double > GetTankSupportCentralFootDimensions() const
double GetRPCSizeY() const
double GetBarLength() const
Array of Scintillator.
Auger Software Run Control.
Definition: RunController.h:26
V & VisitShape(V &v) const
Callback method for inspecting shape-aware properties.
constexpr double degree
ArrayConstReference YFront() const
read-only reference to front of array of Y
constexpr double g
Definition: AugerUnits.h:200
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void GetData(bool &b) const
Overloads of the GetData member template function.
Definition: Branch.cc:644
double GetShortestFiber() const
constexpr double kelvin
Definition: AugerUnits.h:259
Root detector of the muon detector hierarchy.
V & VisitShape(V &v) const
Callback method to query shape specific properties.
Definition: Fiber.h:89
std::vector< double > GetRPCHousingThickness() const
Thickness of walls of the RPC aluminum housing.
static utl::TabulatedFunction fgLinerBACKSCATTERCONSTANT
std::vector< double > GetTankSupportCentralFootBaseDimensions() const
double GetTankSupportOuterFootDistanceToCenter() const
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
double GetCasingThickness() const
ScintillatorConstIterator ScintillatorsEnd() const
End iterator over the contained scintillators.
void Scale(T &v, const double factor)
ArrayIterator XBegin()
begin of array of X
static utl::TabulatedFunction fgLinerREFLECTIVITY
class that handles Geant4 SD Station simulation adopted from G4TankSimulator
const utl::Point & GetRPCPosition(const unsigned int id) const
RPC position.
utl::Point GetPosition() const
constexpr double cm
Definition: AugerUnits.h:117
double GetPhi0() const
double GetBarThickness() const
string Red(const string &str)
ModuleConstIterator ModulesBegin() const
Begin iterator for the Modules contained in the Counter.
Detector description interface for SDetector-related data.
Definition: SDetector.h:42
AreaKind
Kind of module based on its area.
double GetRPCRotation(const unsigned int id) const
RPC rotation around its Z axis (axis perpendicular to RPC plane.
double GetHousingLength() const
static utl::TabulatedFunction fgLinerSPECULARSPIKECONSTANT
double GetRoofThickness() const
Main configuration utility.
Definition: CentralConfig.h:51
void AddProperty(Material *const m, const char *const name, const TabulatedFunction &f)
int GetId() const
The id of this component.
constexpr double keV
Definition: AugerUnits.h:186
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
Optical mdet::Fiber used to conect mdet::Scintillator to mdet::Pixel.
Definition: Fiber.h:54
double mod(const double d, const double periode)
const Counter & GetCounter(int id) const
Retrieve Counter by id.
Definition: MDetector.h:68
int GetId() const
Station ID.
std::map< mdet::Module::AreaKind, double > fModAreaLenghts
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
static utl::TabulatedFunction fgPmtdomeABSORPTION
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
std::vector< double > GetTankSupportTopSlabDimensions() const
static utl::TabulatedFunction fgInterfaceABSORPTION
static const G4Colour blue(0.0, 0.0, 1.0)
double GetOnManifoldLength() const
The length of the fiber along the path that joins the scintillator to its pixel on the PMT...
Definition: Fiber.cc:65

, generated on Tue Sep 26 2023.