ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4ForwardHcalDetector.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4ForwardHcalDetector.cc
3 
4 #include <phparameter/PHParameters.h>
5 
6 #include <g4main/PHG4Detector.h> // for PHG4Detector
7 #include <g4main/PHG4DisplayAction.h> // for PHG4DisplayAction
8 #include <g4main/PHG4Subsystem.h>
9 
10 #include <phool/recoConsts.h>
11 
12 #include <Geant4/G4Box.hh>
13 #include <Geant4/G4Cons.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/G4SubtractionSolid.hh>
19 #include <Geant4/G4SystemOfUnits.hh>
20 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
21 #include <Geant4/G4Transform3D.hh> // for G4Transform3D
22 #include <Geant4/G4Types.hh> // for G4double, G4int
23 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
24 
25 #include <TSystem.h>
26 
27 #include <cmath>
28 #include <cstdlib>
29 #include <fstream>
30 #include <iostream>
31 #include <sstream>
32 #include <utility> // for pair, make_pair
33 
34 class G4VSolid;
35 class PHCompositeNode;
36 
37 //_______________________________________________________________________
39  : PHG4Detector(subsys, Node, dnam)
40  , m_DisplayAction(dynamic_cast<PHG4ForwardHcalDisplayAction*>(subsys->GetDisplayAction()))
41  , m_Params(parameters)
42  , m_ActiveFlag(m_Params->get_int_param("active"))
43  , m_AbsorberActiveFlag(m_Params->get_int_param("absorberactive"))
44  , m_SupportActiveFlag(m_Params->get_int_param("supportactive"))
45  , m_TowerLogicNamePrefix("hHcalTower")
46  , m_SuperDetector("NONE")
47 {
48 }
49 //_______________________________________________________________________
51 {
52  G4LogicalVolume* mylogvol = volume->GetLogicalVolume();
53  if (m_ActiveFlag)
54  {
55  if (m_ScintiLogicalVolSet.find(mylogvol) != m_ScintiLogicalVolSet.end())
56  {
57  return 1;
58  }
59  }
60 
62  {
63  if (m_AbsorberLogicalVolSet.find(mylogvol) != m_AbsorberLogicalVolSet.end())
64  {
65  return -1;
66  }
67  }
68 
70  {
71  if (m_SupportLogicalVolSet.find(mylogvol) != m_SupportLogicalVolSet.end())
72  {
73  return -2;
74  }
75  }
76  return 0;
77 }
78 
79 //_______________________________________________________________________
81 {
82  if (Verbosity() > 0)
83  {
84  std::cout << "PHG4ForwardHcalDetector: Begin Construction" << std::endl;
85  }
86 
87  if (m_Params->get_string_param("mapping_file").empty())
88  {
89  std::cout << "ERROR in PHG4ForwardHcalDetector: No mapping file specified. Abort detector construction." << std::endl;
90  std::cout << "Please run set_string_param(\"mapping_file\", std::string filename ) first." << std::endl;
91  gSystem->Exit(1);
92  }
93 
94  /* Read parameters for detector construction and mappign from file */
96 
97  /* Create the cone envelope = 'world volume' for the crystal calorimeter */
100 
101  G4VSolid* beampipe_cutout = new G4Cons("FHCAL_beampipe_cutout",
102  0, m_Params->get_double_param("rMin1") * cm,
103  0, m_Params->get_double_param("rMin2") * cm,
104  m_Params->get_double_param("dz") * cm / 2.0,
105  0, 2 * M_PI);
106  G4VSolid* hcal_envelope_solid = new G4Cons("FHCAL_envelope_solid_cutout",
107  0, m_Params->get_double_param("rMax1") * cm,
108  0, m_Params->get_double_param("rMax2") * cm,
109  m_Params->get_double_param("dz") * cm / 2.0,
110  0, 2 * M_PI);
111  hcal_envelope_solid = new G4SubtractionSolid(G4String("FHCAL_envelope_solid"), hcal_envelope_solid, beampipe_cutout, 0, G4ThreeVector(m_Params->get_double_param("xoffset") * cm, m_Params->get_double_param("yoffset") * cm, 0.));
112 
113  G4LogicalVolume* hcal_envelope_log = new G4LogicalVolume(hcal_envelope_solid, WorldMaterial, "hFHCAL_envelope", 0, 0, 0);
114 
115  m_DisplayAction->AddVolume(hcal_envelope_log, "FHcalEnvelope");
116 
117  /* Define rotation attributes for envelope cone */
118  G4RotationMatrix hcal_rotm;
119  hcal_rotm.rotateX(m_Params->get_double_param("rot_x") * deg);
120  hcal_rotm.rotateY(m_Params->get_double_param("rot_y") * deg);
121  hcal_rotm.rotateZ(m_Params->get_double_param("rot_z") * deg);
122 
123  /* Place envelope cone in simulation */
124  std::string name_envelope = m_TowerLogicNamePrefix + "_envelope";
125 
127  m_Params->get_double_param("place_y") * cm,
128  m_Params->get_double_param("place_z") * cm)),
129  hcal_envelope_log, name_envelope, logicWorld, 0, false, OverlapCheck());
130 
131  /* Construct single calorimeter tower */
132  G4LogicalVolume* singletower = ConstructTower();
133 
134  /* Place calorimeter tower within envelope */
135  PlaceTower(hcal_envelope_log, singletower);
136 
137  return;
138 }
139 
140 //_______________________________________________________________________
143 {
144  if (Verbosity() > 0)
145  {
146  std::cout << "PHG4ForwardHcalDetector: Build logical volume for single tower..." << std::endl;
147  }
148 
149  /* create logical volume for single tower */
152  double TowerDx = m_Params->get_double_param("tower_dx") * cm;
153  double TowerDy = m_Params->get_double_param("tower_dy") * cm;
154  double TowerDz = m_Params->get_double_param("tower_dz") * cm;
155  double WlsDw = m_Params->get_double_param("wls_dw") * cm;
156  double SupportDw = m_Params->get_double_param("support_dw") * cm;
157  G4VSolid* single_tower_solid = new G4Box("single_tower_solid",
158  TowerDx / 2.0,
159  TowerDy / 2.0,
160  TowerDz / 2.0);
161 
162  G4LogicalVolume* single_tower_logic = new G4LogicalVolume(single_tower_solid,
163  WorldMaterial,
164  "single_tower_logic",
165  0, 0, 0);
166 
167  /* create geometry volumes for scintillator and absorber plates to place inside single_tower */
168  // based on STAR forward upgrade design: https://drupal.star.bnl.gov/STAR/files/ForwardUpgrade.v20.pdf
169  G4double thickness_absorber = m_Params->get_double_param("thickness_absorber") * cm;
170  G4double thickness_scintillator = m_Params->get_double_param("thickness_scintillator") * cm;
171  G4int nlayers = TowerDz / (thickness_absorber + thickness_scintillator);
172 
173  G4VSolid* solid_absorber = new G4Box("single_plate_absorber_solid",
174  (TowerDx - WlsDw) / 2.0,
175  (TowerDy - SupportDw) / 2.0,
176  thickness_absorber / 2.0);
177 
178  G4VSolid* solid_scintillator = new G4Box("single_plate_scintillator",
179  (TowerDx - WlsDw) / 2.0,
180  (TowerDy - SupportDw) / 2.0,
181  thickness_scintillator / 2.0);
182 
183  G4VSolid* solid_WLS_plate = new G4Box("single_plate_wls",
184  (WlsDw) / 2.0,
185  (TowerDy - SupportDw) / 2.0,
186  TowerDz / 2.0);
187 
188  G4VSolid* solid_support_plate = new G4Box("single_plate_support",
189  (TowerDx) / 2.0,
190  (SupportDw) / 2.0,
191  TowerDz / 2.0);
192 
193  /* create logical volumes for scintillator and absorber plates to place inside single_tower */
194  G4Material* material_scintillator = GetDetectorMaterial(m_Params->get_string_param("scintillator"));
195  G4Material* material_absorber = GetDetectorMaterial(m_Params->get_string_param("absorber"));
196  G4Material* material_wls = GetDetectorMaterial(m_Params->get_string_param("scintillator"));
197  G4Material* material_support = GetDetectorMaterial(m_Params->get_string_param("support"));
198 
199  if (m_Params->get_int_param("absorber_FeTungsten") == 1)
200  {
201  G4double density;
202  G4int natoms;
203  material_absorber = new G4Material("FeTungstenMix", density = 10.1592 * g / cm3, natoms = 2);
204  material_absorber->AddMaterial(GetDetectorMaterial("G4_Fe"), 80 * perCent); // Steel
205  material_absorber->AddMaterial(GetDetectorMaterial("G4_W"), 20 * perCent); // Tungsten
206  }
207  G4LogicalVolume* logic_absorber = new G4LogicalVolume(solid_absorber,
208  material_absorber,
209  "single_plate_absorber_logic",
210  0, 0, 0);
211 
212  m_AbsorberLogicalVolSet.insert(logic_absorber);
213 
214  G4LogicalVolume* logic_scint = new G4LogicalVolume(solid_scintillator,
215  material_scintillator,
216  "hHcal_scintillator_plate_logic",
217  0, 0, 0);
218  m_ScintiLogicalVolSet.insert(logic_scint);
219 
220  G4LogicalVolume* logic_wls = new G4LogicalVolume(solid_WLS_plate,
221  material_wls,
222  "hHcal_wls_plate_logic",
223  0, 0, 0);
224 
225  m_SupportLogicalVolSet.insert(logic_wls);
226  G4LogicalVolume* logic_support = new G4LogicalVolume(solid_support_plate,
227  material_support,
228  "hHcal_support_plate_logic",
229  0, 0, 0);
230 
231  m_SupportLogicalVolSet.insert(logic_support);
232 
233  m_DisplayAction->AddVolume(logic_absorber, "Absorber");
234  m_DisplayAction->AddVolume(logic_scint, "Scintillator");
235  m_DisplayAction->AddVolume(logic_wls, "WLSplate");
236  m_DisplayAction->AddVolume(logic_support, "SupportPlate");
237 
238  /* place physical volumes for absorber and scintillator plates */
239  G4double xpos_i = -WlsDw / 2.0;
240  G4double ypos_i = -SupportDw / 2.0;
241  G4double zpos_i = (-1 * TowerDz / 2.0) + thickness_absorber / 2.0;
242 
243  std::string name_absorber = m_TowerLogicNamePrefix + "_single_plate_absorber";
244 
245  std::string name_scintillator = m_TowerLogicNamePrefix + "_single_plate_scintillator";
246 
247  std::string name_wls = m_TowerLogicNamePrefix + "_single_plate_wls";
248 
249  std::string name_support = m_TowerLogicNamePrefix + "_single_plate_support";
250 
251  for (int i = 1; i <= nlayers; i++)
252  {
253  new G4PVPlacement(0, G4ThreeVector(xpos_i, ypos_i, zpos_i),
254  logic_absorber,
255  name_absorber,
256  single_tower_logic,
257  0, 0, OverlapCheck());
258 
259  zpos_i += (thickness_absorber / 2. + thickness_scintillator / 2.);
260 
261  new G4PVPlacement(0, G4ThreeVector(xpos_i, ypos_i, zpos_i),
262  logic_scint,
263  name_scintillator,
264  single_tower_logic,
265  0, 0, OverlapCheck());
266 
267  zpos_i += (thickness_absorber / 2. + thickness_scintillator / 2.);
268  }
269  new G4PVPlacement(0, G4ThreeVector(0, (TowerDy / 2) - SupportDw / 2, 0),
270  logic_support,
271  name_support,
272  single_tower_logic,
273  0, 0, OverlapCheck());
274 
275  new G4PVPlacement(0, G4ThreeVector((TowerDx / 2) - WlsDw / 2, -SupportDw / 2, 0),
276  logic_wls,
277  name_wls,
278  single_tower_logic,
279  0, 0, OverlapCheck());
280  m_DisplayAction->AddVolume(single_tower_logic, "SingleTower");
281 
282  if (Verbosity() > 0)
283  {
284  std::cout << "PHG4ForwardHcalDetector: Building logical volume for single tower done." << std::endl;
285  }
286 
287  return single_tower_logic;
288 }
289 
291 {
292  /* Loop over all tower positions in vector and place tower */
293  for (std::map<std::string, towerposition>::iterator iterator = m_TowerPostionMap.begin(); iterator != m_TowerPostionMap.end(); ++iterator)
294  {
295  if (Verbosity() > 0)
296  {
297  std::cout << "PHG4ForwardHcalDetector: Place tower " << iterator->first
298  << " idx_j = " << iterator->second.idx_j << ", idx_k = " << iterator->second.idx_k
299  << " at x = " << iterator->second.x << " , y = " << iterator->second.y << " , z = " << iterator->second.z << std::endl;
300  }
301 
302  int copyno = (iterator->second.idx_j << 16) + iterator->second.idx_k;
303  new G4PVPlacement(0, G4ThreeVector(iterator->second.x, iterator->second.y, iterator->second.z),
304  singletower,
305  iterator->first,
306  hcalenvelope,
307  0, copyno, OverlapCheck());
308  }
309 
310  return 0;
311 }
312 
314 {
315  /* Open the datafile, if it won't open return an error */
316  std::ifstream istream_mapping;
317  istream_mapping.open(m_Params->get_string_param("mapping_file"));
318  if (!istream_mapping.is_open())
319  {
320  std::cout << "ERROR in PHG4ForwardHcalDetector: Failed to open mapping file " << m_Params->get_string_param("mapping_file") << std::endl;
321  gSystem->Exit(1);
322  }
323 
324  /* loop over lines in file */
325  std::string line_mapping;
326  while (getline(istream_mapping, line_mapping))
327  {
328  /* Skip lines starting with / including a '#' */
329  if (line_mapping.find("#") != std::string::npos)
330  {
331  if (Verbosity() > 0)
332  {
333  std::cout << "PHG4ForwardHcalDetector: SKIPPING line in mapping file: " << line_mapping << std::endl;
334  }
335  continue;
336  }
337 
338  std::istringstream iss(line_mapping);
339 
340  /* If line starts with keyword Tower, add to tower positions */
341  if (line_mapping.find("Tower ") != std::string::npos)
342  {
343  unsigned idx_j, idx_k, idx_l;
344  G4double pos_x, pos_y, pos_z;
345  G4double size_x, size_y, size_z;
346  G4double rot_x, rot_y, rot_z;
347  G4double dummy;
348  std::string dummys;
349 
350  /* read string- break if error */
351  if (!(iss >> dummys >> dummy >> idx_j >> idx_k >> idx_l >> pos_x >> pos_y >> pos_z >> size_x >> size_y >> size_z >> rot_x >> rot_y >> rot_z))
352  {
353  std::cout << "ERROR in PHG4ForwardHcalDetector: Failed to read line in mapping file " << m_Params->get_string_param("mapping_file") << std::endl;
354  gSystem->Exit(1);
355  }
356 
357  /* Construct unique name for tower */
358  /* Mapping file uses cm, this class uses mm for length */
359  std::ostringstream towername;
360  towername.str("");
361  towername << m_TowerLogicNamePrefix << "_j_" << idx_j << "_k_" << idx_k;
362 
363  /* Add Geant4 units */
364  pos_x = pos_x * cm;
365  pos_y = pos_y * cm;
366  pos_z = pos_z * cm;
367 
368  /* insert tower into tower map */
369  towerposition tower_new;
370  tower_new.x = pos_x;
371  tower_new.y = pos_y;
372  tower_new.z = pos_z;
373  tower_new.idx_j = idx_j;
374  tower_new.idx_k = idx_k;
375  m_TowerPostionMap.insert(make_pair(towername.str(), tower_new));
376  }
377  else
378  {
379  /* If this line is not a comment and not a tower, save parameter as string / value. */
380  std::string parname;
381  G4double parval;
382 
383  /* read string- break if error */
384  if (!(iss >> parname >> parval))
385  {
386  std::cout << "ERROR in PHG4ForwardHcalDetector: Failed to read line in mapping file " << m_Params->get_string_param("mapping_file") << std::endl;
387  gSystem->Exit(1);
388  }
389 
390  m_GlobalParameterMap.insert(make_pair(parname, parval));
391  }
392  }
393 
394  /* Update member variables for global parameters based on parsed parameter file */
395  std::map<std::string, G4double>::iterator parit;
396 
397  parit = m_GlobalParameterMap.find("Gtower_dx");
398  if (parit != m_GlobalParameterMap.end())
399  {
400  m_Params->set_double_param("tower_dx", parit->second); // in cm
401  }
402 
403  parit = m_GlobalParameterMap.find("Gtower_dy");
404  if (parit != m_GlobalParameterMap.end())
405  {
406  m_Params->set_double_param("tower_dy", parit->second); // in cm
407  }
408 
409  parit = m_GlobalParameterMap.find("Gtower_dz");
410  if (parit != m_GlobalParameterMap.end())
411  {
412  m_Params->set_double_param("tower_dz", parit->second); // in cm
413  }
414 
415  parit = m_GlobalParameterMap.find("Gr1_inner");
416  if (parit != m_GlobalParameterMap.end())
417  {
418  m_Params->set_double_param("rMin1", parit->second);
419  }
420 
421  parit = m_GlobalParameterMap.find("Gr1_outer");
422  if (parit != m_GlobalParameterMap.end())
423  {
424  m_Params->set_double_param("rMax1", parit->second);
425  }
426 
427  parit = m_GlobalParameterMap.find("Gr2_inner");
428  if (parit != m_GlobalParameterMap.end())
429  {
430  m_Params->set_double_param("rMin2", parit->second);
431  }
432 
433  parit = m_GlobalParameterMap.find("Gr2_outer");
434  if (parit != m_GlobalParameterMap.end())
435  {
436  m_Params->set_double_param("rMax2", parit->second);
437  }
438 
439  parit = m_GlobalParameterMap.find("Gdz");
440  if (parit != m_GlobalParameterMap.end())
441  {
442  m_Params->set_double_param("dz", parit->second);
443  }
444 
445  parit = m_GlobalParameterMap.find("Gx0");
446  if (parit != m_GlobalParameterMap.end())
447  {
448  m_Params->set_double_param("place_x", parit->second);
449  }
450 
451  parit = m_GlobalParameterMap.find("Gy0");
452  if (parit != m_GlobalParameterMap.end())
453  {
454  m_Params->set_double_param("place_y", parit->second);
455  }
456 
457  parit = m_GlobalParameterMap.find("Gz0");
458  if (parit != m_GlobalParameterMap.end())
459  {
460  m_Params->set_double_param("place_z", parit->second);
461  }
462 
463  parit = m_GlobalParameterMap.find("Grot_x");
464  if (parit != m_GlobalParameterMap.end())
465  {
466  m_Params->set_double_param("rot_x", parit->second * rad / deg);
467  }
468 
469  parit = m_GlobalParameterMap.find("Grot_y");
470  if (parit != m_GlobalParameterMap.end())
471  {
472  m_Params->set_double_param("rot_y", parit->second * rad / deg);
473  }
474 
475  parit = m_GlobalParameterMap.find("Grot_z");
476  if (parit != m_GlobalParameterMap.end())
477  {
478  m_Params->set_double_param("rot_z", parit->second * rad / deg);
479  }
480 
481  parit = m_GlobalParameterMap.find("xoffset");
482  if (parit != m_GlobalParameterMap.end())
483  m_Params->set_double_param("xoffset", parit->second);
484 
485  parit = m_GlobalParameterMap.find("yoffset");
486  if (parit != m_GlobalParameterMap.end())
487  m_Params->set_double_param("yoffset", parit->second);
488 
489  return 0;
490 }