Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4Prototype3InnerHcalDetector.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4Prototype3InnerHcalDetector.cc
2 
3 #include <phparameter/PHParameters.h>
4 
5 #include <g4main/PHG4Detector.h> // for PHG4Detector
6 #include <g4main/PHG4Units.h>
7 
8 #include <TSystem.h>
9 
10 #include <Geant4/G4AssemblyVolume.hh>
11 #include <Geant4/G4Box.hh>
12 #include <Geant4/G4Colour.hh>
13 #include <Geant4/G4ExtrudedSolid.hh>
14 #include <Geant4/G4LogicalVolume.hh>
15 #include <Geant4/G4Material.hh>
16 #include <Geant4/G4PVPlacement.hh>
17 #include <Geant4/G4RotationMatrix.hh> // for G4RotationMatrix
18 #include <Geant4/G4String.hh> // for G4String
19 #include <Geant4/G4SystemOfUnits.hh> // for mm, deg, cm, cm3, rad
20 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
21 #include <Geant4/G4TwoVector.hh>
22 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
23 #include <Geant4/G4VSolid.hh> // for G4VSolid
24 #include <Geant4/G4VisAttributes.hh>
25 
26 #include <boost/format.hpp>
27 
28 #include <cmath>
29 #include <iostream> // for operator<<, endl
30 #include <sstream>
31 #include <utility> // for pair, make_pair
32 #include <vector> // for vector, vector<>::...
33 
34 class PHCompositeNode;
35 
36 using namespace std;
37 
38 static const string scintimothername = "InnerHcalScintiMother";
39 static const string steelplatename = "InnerHcalSteelPlate";
40 
42  : PHG4Detector(subsys, Node, dnam)
43  , m_params(parameters)
44  , m_InnerHcalSteelPlate(nullptr)
45  , m_InnerHcalAssembly(nullptr)
46  , m_scintibox(nullptr)
47  , m_SteelPlateCornerUpperLeft(1154.49 * mm, -189.06 * mm)
48  , m_SteelPlateCornerUpperRight(1297.94 * mm, -349.22 * mm)
49  , m_SteelPlateCornerLowerRight(1288.18 * mm, -357.8 * mm)
50  , m_SteelPlateCornerLowerLeft(1157.3 * mm, -205.56 * mm)
51  //
52  , m_ScintiTile9DistanceToCorner(26.44 * mm)
53  , m_ScintiTile9FrontSize(140.3 * mm)
54  , m_ScintiTile9CornerUpperLeft(0 * mm, 0 * mm)
55  , m_ScintiTile9CornerUpperRight(191. * mm, -134.4 * 191. / 198.1 * mm)
56  , m_ScintiTile9CornerLowerRight(191. * mm, -191. * mm / tan(52.02 / 180. * M_PI) - m_ScintiTile9FrontSize)
57  , m_ScintiTile9CornerLowerLeft(0 * mm, -m_ScintiTile9FrontSize)
58  //
59  , m_ScintiTile10FrontSize(149.2 * mm)
60  , m_ScintiTile10CornerUpperLeft(0 * mm, 0 * mm)
61  , m_ScintiTile10CornerUpperRight(191. * mm, -154.6 * 191. / 198.1 * mm)
62  , m_ScintiTile10CornerLowerRight(191. * mm, -191. * mm / tan(48.34 / 180. * M_PI) - m_ScintiTile10FrontSize)
63  , m_ScintiTile10CornerLowerLeft(0 * mm, -m_ScintiTile10FrontSize)
64  //
65  , m_ScintiTile11FrontSize(144.3 * mm)
66  , m_ScintiTile11CornerUpperLeft(0 * mm, 0 * mm)
67  , m_ScintiTile11CornerUpperRight(191. * mm, -176.2 * 191. / 198.1 * mm)
68  , m_ScintiTile11CornerLowerRight(191. * mm, -191. * mm / tan(45.14 / 180. * M_PI) - m_ScintiTile11FrontSize)
69  , m_ScintiTile11CornerLowerLeft(0 * mm, -m_ScintiTile11FrontSize)
70  //
71  , m_ScintiTile12FrontSize(186.6 * mm)
72  , m_ScintiTile12CornerUpperLeft(0 * mm, 0 * mm)
73  , m_ScintiTile12CornerUpperRight(191. * mm, -197.11 * 191. / 198.1 * mm)
74  , m_ScintiTile12CornerLowerRight(191. * mm, -191. * mm / tan(41.47 / 180. * M_PI) - m_ScintiTile12FrontSize)
75  , m_ScintiTile12CornerLowerLeft(0 * mm, -m_ScintiTile12FrontSize)
76  //
77  , m_ScintiX(198.1 * mm)
78  , m_SteelZ(901.7 * mm)
79  , m_ScintiTileZ(m_SteelZ)
80  , m_ScintiTileThickness(7 * mm)
81  , m_GapBetweenTiles(1 * mm)
82  , m_ScintiGap(10 * mm)
83  , m_DeltaPhi(2 * M_PI / 256.)
84  , m_VolumeSteel(NAN)
85  , m_VolumeScintillator(0)
86  , m_ScintiCornerLowerLeft(45.573 * inch, -7.383 * inch)
87  , m_ScintiCornerLowerRight(50.604 * inch, -12.972 * inch)
88  // leave this in in case we ever need those coordinates
89  // m_ScintiCornerUpperRight(50.809*inch,-12.787*inch),
90  // m_ScintiCornerUpperLeft(45.778*inch,-7.198*inch),
91  , m_NumScintiPlates(16)
92  , m_NumSteelPlates(m_NumScintiPlates + 1)
93  , m_Active(m_params->get_int_param("active"))
94  , m_AbsorberActive(m_params->get_int_param("absorberactive"))
95  , m_Layer(0)
96 {
97  // patch to get the upper steel plate location right within less than a mm
98  m_DeltaPhi += 0.00125 * m_DeltaPhi;
99 }
100 
102 {
103  delete m_InnerHcalAssembly;
104 }
105 
106 //_______________________________________________________________
107 //_______________________________________________________________
109 {
110  G4LogicalVolume *logvol = volume->GetLogicalVolume();
111  if (m_AbsorberActive && logvol == m_InnerHcalSteelPlate)
112  {
113  return -1;
114  }
115  if (m_Active && m_ActiveVolumeSet.find(logvol) != m_ActiveVolumeSet.end())
116  {
117  return 1;
118  }
119  return 0;
120 }
121 
122 G4LogicalVolume *
124 {
126  {
127  G4VSolid *steel_plate;
128 
129  std::vector<G4TwoVector> vertexes;
130  vertexes.push_back(m_SteelPlateCornerUpperLeft);
131  vertexes.push_back(m_SteelPlateCornerUpperRight);
132  vertexes.push_back(m_SteelPlateCornerLowerRight);
133  vertexes.push_back(m_SteelPlateCornerLowerLeft);
134  G4TwoVector zero(0, 0);
135  steel_plate = new G4ExtrudedSolid("InnerHcalSteelPlateSolid",
136  vertexes,
137  m_SteelZ / 2.0,
138  zero, 1.0,
139  zero, 1.0);
140 
141  m_VolumeSteel = steel_plate->GetCubicVolume() * m_NumSteelPlates;
142  m_InnerHcalSteelPlate = new G4LogicalVolume(steel_plate, G4Material::GetMaterial(m_params->get_string_param("material")), steelplatename, 0, 0, 0);
143  G4VisAttributes visattchk;
144  visattchk.SetVisibility(true);
145  visattchk.SetForceSolid(false);
146  visattchk.SetColour(G4Colour::Blue());
147  m_InnerHcalSteelPlate->SetVisAttributes(visattchk);
148  }
149  return m_InnerHcalSteelPlate;
150 }
151 
152 G4LogicalVolume *
154 {
155  int copynum = 0;
156  G4VSolid *scintiboxsolid = new G4Box(scintimothername, m_ScintiX / 2., (m_ScintiGap) / 2., m_ScintiTileZ / 2.);
157  //DisplayVolume(scintiboxsolid,hcalenvelope);
158 
159  G4LogicalVolume *scintiboxlogical = new G4LogicalVolume(scintiboxsolid, G4Material::GetMaterial("G4_AIR"), G4String(scintimothername), 0, 0, 0);
160  G4VisAttributes hcalVisAtt;
161  hcalVisAtt.SetVisibility(true);
162  hcalVisAtt.SetForceSolid(false);
163  hcalVisAtt.SetColour(G4Colour::Magenta());
164  G4LogicalVolume *scintit9_logic = ConstructScintiTile9(hcalenvelope);
165  scintit9_logic->SetVisAttributes(hcalVisAtt);
166  double distance_to_corner = -m_SteelZ / 2. + m_ScintiTile9DistanceToCorner;
167  G4RotationMatrix *Rot;
168  Rot = new G4RotationMatrix();
169  Rot->rotateX(90 * deg);
170  new G4PVPlacement(Rot, G4ThreeVector(-m_ScintiX / 2., 0, distance_to_corner), scintit9_logic, (boost::format("InnerScinti_%d") % copynum).str(), scintiboxlogical, false, copynum, OverlapCheck());
171 
172  hcalVisAtt.SetVisibility(true);
173  hcalVisAtt.SetForceSolid(false);
174  hcalVisAtt.SetColour(G4Colour::Blue());
175  G4LogicalVolume *scintit10_logic = ConstructScintiTile10(hcalenvelope);
176  scintit10_logic->SetVisAttributes(hcalVisAtt);
177 
178  distance_to_corner += m_ScintiTile9FrontSize + m_GapBetweenTiles;
179  Rot = new G4RotationMatrix();
180  Rot->rotateX(90 * deg);
181  copynum++;
182  new G4PVPlacement(Rot, G4ThreeVector(-m_ScintiX / 2., 0, distance_to_corner), scintit10_logic, (boost::format("InnerScinti_%d") % copynum).str(), scintiboxlogical, false, copynum, OverlapCheck());
183 
184  hcalVisAtt.SetVisibility(true);
185  hcalVisAtt.SetForceSolid(false);
186  hcalVisAtt.SetColour(G4Colour::Yellow());
187  G4LogicalVolume *scintit11_logic = ConstructScintiTile11(hcalenvelope);
188  scintit11_logic->SetVisAttributes(hcalVisAtt);
189 
190  distance_to_corner += m_ScintiTile10FrontSize + m_GapBetweenTiles;
191  Rot = new G4RotationMatrix();
192  Rot->rotateX(90 * deg);
193  copynum++;
194  new G4PVPlacement(Rot, G4ThreeVector(-m_ScintiX / 2., 0, distance_to_corner), scintit11_logic, (boost::format("InnerScinti_%d") % copynum).str(), scintiboxlogical, false, copynum, OverlapCheck());
195 
196  hcalVisAtt.SetVisibility(true);
197  hcalVisAtt.SetForceSolid(false);
198  hcalVisAtt.SetColour(G4Colour::Cyan());
199  G4LogicalVolume *scintit12_logic = ConstructScintiTile12(hcalenvelope);
200  scintit12_logic->SetVisAttributes(hcalVisAtt);
201 
202  distance_to_corner += m_ScintiTile11FrontSize + m_GapBetweenTiles;
203  Rot = new G4RotationMatrix();
204  Rot->rotateX(90 * deg);
205  copynum++;
206  new G4PVPlacement(Rot, G4ThreeVector(-m_ScintiX / 2., 0, distance_to_corner), scintit12_logic, (boost::format("InnerScinti_%d") % copynum).str(), scintiboxlogical, false, copynum, OverlapCheck());
207  // DisplayVolume(scintiboxlogical,hcalenvelope);
208  return scintiboxlogical;
209 }
210 
211 G4LogicalVolume *
213 {
214  std::vector<G4TwoVector> vertexes;
215  vertexes.push_back(m_ScintiTile9CornerUpperLeft);
216  vertexes.push_back(m_ScintiTile9CornerUpperRight);
217  vertexes.push_back(m_ScintiTile9CornerLowerRight);
218  vertexes.push_back(m_ScintiTile9CornerLowerLeft);
219  G4TwoVector zero(0, 0);
220  G4VSolid *scintit9 = new G4ExtrudedSolid("InnerHcalScintiT9",
221  vertexes,
222  m_ScintiTileThickness / 2.0,
223  zero, 1.0,
224  zero, 1.0);
225 
226  m_VolumeScintillator += scintit9->GetCubicVolume() * m_NumScintiPlates;
227  G4LogicalVolume *scintit9_logic = new G4LogicalVolume(scintit9, G4Material::GetMaterial("G4_POLYSTYRENE"), "InnerHcalScintiT9", nullptr, nullptr, nullptr);
228  // DisplayVolume(scintit9,hcalenvelope);
229  m_ActiveVolumeSet.insert(scintit9_logic);
230  return scintit9_logic;
231 }
232 
233 G4LogicalVolume *
235 {
236  std::vector<G4TwoVector> vertexes;
237  vertexes.push_back(m_ScintiTile10CornerUpperLeft);
238  vertexes.push_back(m_ScintiTile10CornerUpperRight);
239  vertexes.push_back(m_ScintiTile10CornerLowerRight);
240  vertexes.push_back(m_ScintiTile10CornerLowerLeft);
241  G4TwoVector zero(0, 0);
242  G4VSolid *scintit10 = new G4ExtrudedSolid("InnerHcalScintiT10",
243  vertexes,
244  m_ScintiTileThickness / 2.0,
245  zero, 1.0,
246  zero, 1.0);
247 
248  m_VolumeScintillator += scintit10->GetCubicVolume() * m_NumScintiPlates;
249  G4LogicalVolume *scintit10_logic = new G4LogicalVolume(scintit10, G4Material::GetMaterial("G4_POLYSTYRENE"), "InnerHcalScintiT10", nullptr, nullptr, nullptr);
250  // DisplayVolume(scintit10,hcalenvelope);
251  m_ActiveVolumeSet.insert(scintit10_logic);
252  return scintit10_logic;
253 }
254 
255 G4LogicalVolume *
257 {
258  std::vector<G4TwoVector> vertexes;
259  vertexes.push_back(m_ScintiTile11CornerUpperLeft);
260  vertexes.push_back(m_ScintiTile11CornerUpperRight);
261  vertexes.push_back(m_ScintiTile11CornerLowerRight);
262  vertexes.push_back(m_ScintiTile11CornerLowerLeft);
263  G4TwoVector zero(0, 0);
264  G4VSolid *scintit11 = new G4ExtrudedSolid("InnerHcalScintiT11",
265  vertexes,
266  m_ScintiTileThickness / 2.0,
267  zero, 1.0,
268  zero, 1.0);
269 
270  m_VolumeScintillator += scintit11->GetCubicVolume() * m_NumScintiPlates;
271  G4LogicalVolume *scintit11_logic = new G4LogicalVolume(scintit11, G4Material::GetMaterial("G4_POLYSTYRENE"), "InnerHcalScintiT11", nullptr, nullptr, nullptr);
272  // DisplayVolume(scintit11,hcalenvelope);
273  m_ActiveVolumeSet.insert(scintit11_logic);
274  return scintit11_logic;
275 }
276 
277 G4LogicalVolume *
279 {
280  std::vector<G4TwoVector> vertexes;
281  vertexes.push_back(m_ScintiTile12CornerUpperLeft);
282  vertexes.push_back(m_ScintiTile12CornerUpperRight);
283  vertexes.push_back(m_ScintiTile12CornerLowerRight);
284  vertexes.push_back(m_ScintiTile12CornerLowerLeft);
285  G4TwoVector zero(0, 0);
286  G4VSolid *scintit12 = new G4ExtrudedSolid("InnerHcalScintiT12",
287  vertexes,
288  m_ScintiTileThickness / 2.0,
289  zero, 1.0,
290  zero, 1.0);
291 
292  m_VolumeScintillator += scintit12->GetCubicVolume() * m_NumScintiPlates;
293  G4LogicalVolume *scintit12_logic = new G4LogicalVolume(scintit12, G4Material::GetMaterial("G4_POLYSTYRENE"), "InnerHcalScintiT12", nullptr, nullptr, nullptr);
294  // DisplayVolume(scintit12,hcalenvelope);
295  m_ActiveVolumeSet.insert(scintit12_logic);
296  return scintit12_logic;
297 }
298 
299 // Construct the envelope and the call the
300 // actual inner hcal construction
301 void PHG4Prototype3InnerHcalDetector::ConstructMe(G4LogicalVolume *logicWorld)
302 {
303  G4ThreeVector g4vec(m_params->get_double_param("place_x") * cm,
304  m_params->get_double_param("place_y") * cm,
305  m_params->get_double_param("place_z") * cm);
306  G4RotationMatrix Rot;
307  Rot.rotateX(m_params->get_double_param("rot_x") * deg);
308  Rot.rotateY(m_params->get_double_param("rot_y") * deg);
309  Rot.rotateZ(m_params->get_double_param("rot_z") * deg);
310  m_InnerHcalAssembly = new G4AssemblyVolume();
311  ConstructInnerHcal(logicWorld);
312  m_InnerHcalAssembly->MakeImprint(logicWorld, g4vec, &Rot, 0, OverlapCheck());
313  // this is rather pathetic - there is no way to extract the name when a volume is added
314  // to the assembly. The only thing we can do is get an iterator over the placed volumes
315  // in the order in which they were placed. Since this code does not install the scintillators
316  // for the Al version, parsing the volume names to get the id does not work since it changes
317  // So now we loop over all volumes and store them in a map for fast lookup of the row
318  int isteel = 0;
319  int iscinti = 0;
320  vector<G4VPhysicalVolume *>::iterator it = m_InnerHcalAssembly->GetVolumesIterator();
321  for (unsigned int i = 0; i < m_InnerHcalAssembly->TotalImprintedVolumes(); i++)
322  {
323  string volname = (*it)->GetName();
324  if (volname.find(steelplatename) != string::npos)
325  {
326  m_SteelPlateIdMap.insert(make_pair(volname, isteel));
327  ++isteel;
328  }
329  else if (volname.find(scintimothername) != string::npos)
330  {
331  m_ScintillatorIdMap.insert(make_pair(volname, iscinti));
332  ++iscinti;
333  }
334  ++it;
335  }
336  // print out volume names and their assigned id
337  // map<string,int>::const_iterator iter;
338  // for (iter = m_SteelPlateIdMap.begin(); iter != m_SteelPlateIdMap.end(); ++iter)
339  // {
340  // cout << iter->first << ", " << iter->second << endl;
341  // }
342  // for (iter = m_ScintillatorIdMap.begin(); iter != m_ScintillatorIdMap.end(); ++iter)
343  // {
344  // cout << iter->first << ", " << iter->second << endl;
345  // }
346  return;
347 }
348 
349 int PHG4Prototype3InnerHcalDetector::ConstructInnerHcal(G4LogicalVolume *hcalenvelope)
350 {
351  G4LogicalVolume *steel_plate = ConstructSteelPlate(hcalenvelope); // bottom steel plate
352  if (m_params->get_int_param("scintillators"))
353  {
354  if (m_params->get_int_param("hi_eta"))
355  {
357  }
358  else
359  {
360  cout << "midrapidity scintillator not implemented" << endl;
361  gSystem->Exit(1);
362  }
363  }
364  double phi = 0.;
365  double phislat = 0.;
366  // the coordinate of the center of the bottom of the bottom steel plate
367  // to get the radius of the circle which is the center of the scintillator box
368 
369  double bottom_xmiddle_steel_tile = (m_SteelPlateCornerLowerRight.x() + m_SteelPlateCornerLowerLeft.x()) / 2.;
370  double bottom_ymiddle_steel_tile = (m_SteelPlateCornerLowerLeft.y() + m_SteelPlateCornerLowerRight.y()) / 2.;
371  // the math is not exact, need to move the middle radius by 14mm to
372  // get the upper steel plate right
373  double middlerad = sqrt(bottom_xmiddle_steel_tile * bottom_xmiddle_steel_tile + bottom_ymiddle_steel_tile * bottom_ymiddle_steel_tile) - 0.14 * cm;
374  // another fudge factor to get the upper steel location right
375  double philow = atan((bottom_ymiddle_steel_tile - (m_ScintiGap * 25. / 32.)) / bottom_xmiddle_steel_tile);
376 
377  double scintiangle = GetScintiAngle();
378 
379  // need to shift in x to get the upper steel plate close to right
380  double xstart = 0;
381  double xoff = 0.015 * cm;
382  for (int i = 0; i < m_NumSteelPlates; i++)
383  {
384  G4RotationMatrix Rot;
385  Rot.rotateZ(phi * rad);
386  G4ThreeVector g4vec(xstart, 0, 0);
387  m_InnerHcalAssembly->AddPlacedVolume(steel_plate, g4vec, &Rot);
388  if (m_scintibox && i > 0)
389  {
390  double ypos = sin(phi + philow) * middlerad;
391  double xpos = cos(phi + philow) * middlerad;
392  G4RotationMatrix Rot1;
393  Rot1.rotateZ(scintiangle + phislat);
394  G4ThreeVector g4vecsc(xpos + xstart, ypos, 0);
395  m_InnerHcalAssembly->AddPlacedVolume(m_scintibox, g4vecsc, &Rot1);
396  phislat += m_DeltaPhi;
397  }
398  phi += m_DeltaPhi;
399  xstart += xoff;
400  }
401  return 0;
402 }
403 
404 // calculate the angle of the bottom scintillator. It is the angle of the top edge
405 // of the steel plate
406 double
408 {
409  double xlen = m_ScintiCornerLowerRight.x() - m_ScintiCornerLowerLeft.x();
410  double ylen = m_ScintiCornerLowerRight.y() - m_ScintiCornerLowerLeft.y();
411  double angle = atan(ylen / xlen);
412  return angle;
413 }
414 
415 void PHG4Prototype3InnerHcalDetector::Print(const string &what) const
416 {
417  cout << "Inner Hcal Detector:" << endl;
418  if (what == "ALL" || what == "VOLUME")
419  {
420  cout << "Volume Steel: " << m_VolumeSteel / cm3 << " cm^3" << endl;
421  cout << "Volume Scintillator: " << m_VolumeScintillator / cm3 << " cm^3" << endl;
422  }
423  return;
424 }
425 
427 {
428  int id = -9999;
429  auto it = m_ScintillatorIdMap.find(volname);
430  if (it != m_ScintillatorIdMap.end())
431  {
432  id = it->second;
433  }
434  else
435  {
436  cout << "unknown scintillator volume name: " << volname << endl;
437  }
438 
439  return id;
440 }
441 
443 {
444  int id = -9999;
445  auto it = m_SteelPlateIdMap.find(volname);
446  if (it != m_SteelPlateIdMap.end())
447  {
448  id = it->second;
449  }
450  else
451  {
452  cout << "unknown steel volume name: " << volname << endl;
453  }
454  return id;
455 }