Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4IHCalDetector.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4IHCalDetector.cc
1 #include "PHG4IHCalDetector.h"
2 
4 
6 
7 #include <phparameter/PHParameters.h>
8 
9 #include <g4main/PHG4Detector.h>
11 #include <g4main/PHG4Subsystem.h>
12 #include <g4main/PHG4Utils.h>
13 
14 #include <phool/PHCompositeNode.h>
15 #include <phool/PHIODataNode.h>
16 #include <phool/PHNode.h> // for PHNode
17 #include <phool/PHNodeIterator.h>
18 #include <phool/PHObject.h> // for PHObject
19 #include <phool/getClass.h>
20 #include <phool/phool.h>
21 #include <phool/recoConsts.h>
22 
23 #include <g4gdml/PHG4GDMLConfig.hh>
25 
26 #include <calobase/RawTowerDefs.h> // for convert_name_...
27 #include <calobase/RawTowerGeom.h> // for RawTowerGeom
28 #include <calobase/RawTowerGeomContainer.h> // for RawTowerGeomC...
29 #include <calobase/RawTowerGeomContainer_Cylinderv1.h>
30 #include <calobase/RawTowerGeomv1.h>
31 
32 #include <TSystem.h>
33 
34 #include <Geant4/G4AssemblyVolume.hh>
35 #include <Geant4/G4LogicalVolume.hh>
36 #include <Geant4/G4Material.hh>
37 #include <Geant4/G4PVPlacement.hh>
38 #include <Geant4/G4RotationMatrix.hh>
39 #include <Geant4/G4String.hh>
40 #include <Geant4/G4SystemOfUnits.hh>
41 #include <Geant4/G4ThreeVector.hh>
42 #include <Geant4/G4Transform3D.hh>
43 #include <Geant4/G4Tubs.hh>
44 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
45 #include <Geant4/G4VSolid.hh>
46 
47 #pragma GCC diagnostic push
48 #pragma GCC diagnostic ignored "-Wshadow"
49 #pragma GCC diagnostic ignored "-Wpedantic"
50 #include <Geant4/G4GDMLParser.hh>
51 #include <Geant4/G4GDMLReadStructure.hh> // for G4GDMLReadStructure
52 #pragma GCC diagnostic pop
53 
54 #include <boost/lexical_cast.hpp>
55 #include <boost/tokenizer.hpp>
56 
57 #include <cmath>
58 #include <cstdlib>
59 #include <iostream>
60 #include <memory> // for unique_ptr
61 #include <type_traits> // for __decay_and_strip<>::_...
62 #include <utility> // for pair, make_pair
63 #include <vector> // for vector, vector<>::iter...
64 
65 class G4Material;
66 class PHCompositeNode;
67 
69  : PHG4Detector(subsys, Node, dnam)
70  , m_DisplayAction(dynamic_cast<PHG4IHCalDisplayAction *>(subsys->GetDisplayAction()))
71  , m_Params(parameters)
72  , m_InnerRadius(m_Params->get_double_param("inner_radius") * cm)
73  , m_OuterRadius(m_Params->get_double_param("outer_radius") * cm)
74  , m_SizeZ(m_Params->get_double_param("size_z") * cm)
75  , m_NumScintiPlates(m_Params->get_int_param(PHG4HcalDefs::scipertwr) * m_Params->get_int_param("n_towers"))
76  , m_Active(m_Params->get_int_param("active"))
77  , m_AbsorberActive(m_Params->get_int_param("absorberactive"))
78  , m_GDMPath(m_Params->get_string_param("GDMPath"))
79 {
82 }
83 
85 {
87 }
88 
89 //_______________________________________________________________
90 //_______________________________________________________________
92 {
93  if (m_AbsorberActive)
94  {
95  if (m_SteelAbsorberLogVolSet.find(volume->GetLogicalVolume()) != m_SteelAbsorberLogVolSet.end())
96  {
97  return -1;
98  }
99  }
100  if (m_Active)
101  {
102  if (m_ScintiTileLogVolSet.find(volume->GetLogicalVolume()) != m_ScintiTileLogVolSet.end())
103  {
104  return 1;
105  }
106  }
107  return 0;
108 }
109 
110 // Construct the envelope and the call the
111 // actual inner hcal construction
112 void PHG4IHCalDetector::ConstructMe(G4LogicalVolume *logicWorld)
113 {
115  G4Material *worldmat = GetDetectorMaterial(rc->get_StringFlag("WorldMaterial"));
116  G4VSolid *hcal_envelope_cylinder = new G4Tubs("IHCal_envelope_solid", m_InnerRadius, m_OuterRadius, m_SizeZ / 2., 0, 2 * M_PI);
117  m_VolumeEnvelope = hcal_envelope_cylinder->GetCubicVolume();
118  G4LogicalVolume *hcal_envelope_log = new G4LogicalVolume(hcal_envelope_cylinder, worldmat, "Hcal_envelope", nullptr, nullptr, nullptr);
119 
120  G4RotationMatrix hcal_rotm;
121  hcal_rotm.rotateX(m_Params->get_double_param("rot_x") * deg);
122  hcal_rotm.rotateY(m_Params->get_double_param("rot_y") * deg);
123  hcal_rotm.rotateZ(m_Params->get_double_param("rot_z") * deg);
124  G4VPhysicalVolume *mothervol = new G4PVPlacement(G4Transform3D(hcal_rotm, G4ThreeVector(m_Params->get_double_param("place_x") * cm, m_Params->get_double_param("place_y") * cm, m_Params->get_double_param("place_z") * cm)), hcal_envelope_log, "IHCalEnvelope", logicWorld, false, false, OverlapCheck());
125  m_DisplayAction->SetMyTopVolume(mothervol);
126  ConstructIHCal(hcal_envelope_log);
127 
128  // disable GDML export for HCal geometries for memory saving and compatibility issues
130  gdml_config->exclude_physical_vol(mothervol);
131  gdml_config->exclude_logical_vol(hcal_envelope_log);
132 
133  const G4MaterialTable *mtable = G4Material::GetMaterialTable();
134  int nMaterials = G4Material::GetNumberOfMaterials();
135  for (G4int i = 0; i < nMaterials; ++i)
136  {
137  const G4Material *mat = (*mtable)[i];
138  if (mat->GetName() == "Uniplast_scintillator")
139  {
140  if ((mat->GetIonisation()->GetBirksConstant()) == 0)
141  {
142  mat->GetIonisation()->SetBirksConstant(m_Params->get_double_param("Birk_const"));
143  }
144  }
145  }
146  if (!m_Params->get_int_param("saveg4hit")) AddGeometryNode();
147  return;
148 }
149 
150 int PHG4IHCalDetector::ConstructIHCal(G4LogicalVolume *hcalenvelope)
151 {
152  // import the staves from the geometry file
153  std::unique_ptr<G4GDMLReadStructure> reader(new G4GDMLReadStructure());
154  G4GDMLParser gdmlParser(reader.get());
155  gdmlParser.SetOverlapCheck(OverlapCheck());
156  gdmlParser.Read(m_GDMPath, false);
157 
158  G4AssemblyVolume *abs_asym = reader->GetAssembly("InnerSector"); // absorber
159  m_ScintiMotherAssembly = reader->GetAssembly("InnerTileAssembly90"); // scintillator
160  std::vector<G4VPhysicalVolume *>::iterator it = abs_asym->GetVolumesIterator();
161  static const unsigned int tilepersec = 24 * 4 * 2;
162  for (unsigned int isector = 0; isector < abs_asym->TotalImprintedVolumes(); isector++)
163  {
164  m_DisplayAction->AddSteelVolume((*it)->GetLogicalVolume());
165  m_SteelAbsorberLogVolSet.insert((*it)->GetLogicalVolume());
166  hcalenvelope->AddDaughter((*it));
167  m_AbsorberPhysVolMap.insert(std::make_pair(*it, isector));
168  m_VolumeSteel += (*it)->GetLogicalVolume()->GetSolid()->GetCubicVolume();
169  std::vector<G4VPhysicalVolume *>::iterator its = m_ScintiMotherAssembly->GetVolumesIterator();
170  unsigned int ioff = isector * tilepersec;
171  for (unsigned int j = 0; j < ioff; j++)
172  {
173  ++its;
174  }
175  for (unsigned int j = ioff; j < ioff + tilepersec; j++)
176  {
177  m_DisplayAction->AddScintiVolume((*its)->GetLogicalVolume());
178  m_ScintiTileLogVolSet.insert((*its)->GetLogicalVolume());
179  hcalenvelope->AddDaughter((*its));
180  m_ScintiTilePhysVolMap.insert(std::make_pair(*its, ExtractLayerTowerId(isector, *its)));
181  m_VolumeScintillator += (*its)->GetLogicalVolume()->GetSolid()->GetCubicVolume();
182  ++its;
183  }
184 
185  ++it;
186  }
187  return 0;
188 }
189 
191 {
192  // just make sure the parameters make a bit of sense
194  {
195  std::cout << PHWHERE << ": Inner Radius " << m_InnerRadius / cm
196  << " cm larger than Outer Radius " << m_OuterRadius / cm
197  << " cm" << std::endl;
198  gSystem->Exit(1);
199  }
200  return 0;
201 }
202 
203 void PHG4IHCalDetector::Print(const std::string &what) const
204 {
205  std::cout << "Inner Hcal Detector:" << std::endl;
206  if (what == "ALL" || what == "VOLUME")
207  {
208  std::cout << "Volume Envelope: " << m_VolumeEnvelope / cm3 << " cm^3" << std::endl;
209  std::cout << "Volume Steel: " << m_VolumeSteel / cm3 << " cm^3" << std::endl;
210  std::cout << "Volume Scintillator: " << m_VolumeScintillator / cm3 << " cm^3" << std::endl;
211  std::cout << "Volume Air: " << (m_VolumeEnvelope - m_VolumeSteel - m_VolumeScintillator) / cm3 << " cm^3" << std::endl;
212  }
213  return;
214 }
215 
216 std::tuple<int, int, int> PHG4IHCalDetector::GetLayerTowerId(G4VPhysicalVolume *volume) const
217 {
218  auto it = m_ScintiTilePhysVolMap.find(volume);
219  if (it != m_ScintiTilePhysVolMap.end())
220  {
221  return it->second;
222  }
223  std::cout << "could not locate volume " << volume->GetName()
224  << " in Inner Hcal scintillator map" << std::endl;
225  gSystem->Exit(1);
226  // that's dumb but code checkers do not know that gSystem->Exit()
227  // terminates, so using the standard exit() makes them happy
228  exit(1);
229 }
230 
232 {
233  auto it = m_AbsorberPhysVolMap.find(volume);
234  if (it != m_AbsorberPhysVolMap.end())
235  {
236  return it->second;
237  }
238  std::cout << "could not locate volume " << volume->GetName()
239  << " in Inner Hcal Absorber map" << std::endl;
240  gSystem->Exit(1);
241  // that's dumb but code checkers do not know that gSystem->Exit()
242  // terminates, so using the standard exit() makes them happy
243  exit(1);
244 }
245 
246 std::tuple<int, int, int> PHG4IHCalDetector::ExtractLayerTowerId(const unsigned int isector, G4VPhysicalVolume *volume)
247 {
248  boost::char_separator<char> sep("_");
249  boost::tokenizer<boost::char_separator<char>> tok(volume->GetName(), sep);
250  boost::tokenizer<boost::char_separator<char>>::const_iterator tokeniter;
251  int layer_id = -1, tower_id = -1;
252  for (tokeniter = tok.begin(); tokeniter != tok.end(); ++tokeniter)
253  {
254  if (*tokeniter == "impr")
255  {
256  ++tokeniter;
257  if (tokeniter != tok.end())
258  {
259  layer_id = boost::lexical_cast<int>(*tokeniter) / 2;
260  layer_id--;
261  if (layer_id < 0 || layer_id >= m_NumScintiPlates)
262  {
263  std::cout << "invalid scintillator row " << layer_id
264  << ", valid range 0 < row < " << m_NumScintiPlates << std::endl;
265  gSystem->Exit(1);
266  }
267  }
268  else
269  {
270  std::cout << PHWHERE << " Error parsing " << volume->GetName()
271  << " for mother volume number " << std::endl;
272  gSystem->Exit(1);
273  }
274  break;
275  }
276  }
277  for (tokeniter = tok.begin(); tokeniter != tok.end(); ++tokeniter)
278  {
279  if (*tokeniter == "pv")
280  {
281  ++tokeniter;
282  if (tokeniter != tok.end())
283  {
284  tower_id = boost::lexical_cast<int>(*tokeniter);
285  }
286  }
287  }
288  int column = map_towerid(tower_id);
289  int row = map_layerid(layer_id);
290  return std::make_tuple(isector, row, column);
291 }
292 
293 // map gdml tower ids to our columns
294 int PHG4IHCalDetector::map_towerid(const int tower_id)
295 {
296  // odd id's go in one direction, even id's in the other one
297  // this is a shortcut to derive the observed dependency
298  // commented out after this code
299  int itwr = -1;
300  int itmp = tower_id / 2;
301  if (tower_id % 2)
302  {
303  itwr = 12 + itmp;
304  }
305  else
306  {
307  itwr = 11 - itmp;
308  }
309  return itwr;
310  // here is the mapping in long form
311  // if (tower_id == 23)
312  // {
313  // itwr = 0;
314  // }
315  // else if (tower_id == 21)
316  // {
317  // itwr = 1;
318  // }
319  // else if (tower_id ==19 )
320  // {
321  // itwr = 2;
322  // }
323  // else if (tower_id == 17)
324  // {
325  // itwr = 3;
326  // }
327  // else if (tower_id == 15)
328  // {
329  // itwr = 4;
330  // }
331  // else if (tower_id == 13)
332  // {
333  // itwr = 5;
334  // }
335  // else if (tower_id == 11)
336  // {
337  // itwr = 6;
338  // }
339  // else if (tower_id == 9)
340  // {
341  // itwr = 7;
342  // }
343  // else if (tower_id == 7)
344  // {
345  // itwr = 8;
346  // }
347  // else if (tower_id == 5)
348  // {
349  // itwr = 9;
350  // }
351  // else if (tower_id == 3)
352  // {
353  // itwr = 10;
354  // }
355  // else if (tower_id == 1)
356  // {
357  // itwr = 11;
358  // }
359  // else if (tower_id == 0)
360  // {
361  // itwr = 12;
362  // }
363  // else if (tower_id == 2)
364  // {
365  // itwr = 13;
366  // }
367  // else if (tower_id == 4)
368  // {
369  // itwr = 14;
370  // }
371  // else if (tower_id == 6)
372  // {
373  // itwr = 15;
374  // }
375  // else if (tower_id == 8)
376  // {
377  // itwr = 16;
378  // }
379  // else if (tower_id == 10)
380  // {
381  // itwr = 17;
382  // }
383  // else if (tower_id == 12)
384  // {
385  // itwr = 18;
386  // }
387  // else if (tower_id == 14)
388  // {
389  // itwr = 19;
390  // }
391  // else if (tower_id == 16)
392  // {
393  // itwr = 20;
394  // }
395  // else if (tower_id == 18)
396  // {
397  // itwr = 21;
398  // }
399  // else if (tower_id == 20)
400  // {
401  // itwr = 22;
402  // }
403  // else if (tower_id == 22)
404  // {
405  // itwr = 23;
406  // }
407  // else
408  // {
409  // std::cout << PHWHERE << " cannot map tower " << tower_id << std::endl;
410  // gSystem->Exit(1);
411  // exit(1);
412  // }
413 }
414 
415 int PHG4IHCalDetector::map_layerid(const int layer_id)
416 {
417  int rowid = -1;
418 
419  if (layer_id <= 60)
420  {
421  rowid = layer_id + 68;
422  }
423  else if (layer_id > 60 && layer_id < 188)
424  {
425  rowid = layer_id + 68;
426  }
427  else if (layer_id >= 188)
428  {
429  rowid = layer_id - 188;
430  }
431  // shift the row index up by 4
432  rowid += 4;
433  if (rowid > 255) rowid -= 256;
434 
435  if (rowid > 255 || rowid < 0)
436  {
437  std::cout << PHWHERE << " row id out of range: " << rowid << std::endl;
438  gSystem->Exit(1);
439  }
440  return rowid;
441 }
442 
443 // This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco.
445 {
446  PHNodeIterator iter(topNode());
447  PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
448  if (!runNode)
449  {
450  std::cout << PHWHERE << "Run Node missing, exiting." << std::endl;
451  gSystem->Exit(1);
452  exit(1);
453  }
454  PHNodeIterator runIter(runNode);
455  PHCompositeNode *RunDetNode = dynamic_cast<PHCompositeNode *>(runIter.findFirst("PHCompositeNode", m_SuperDetector));
456  if (!RunDetNode)
457  {
458  RunDetNode = new PHCompositeNode(m_SuperDetector);
459  runNode->addNode(RunDetNode);
460  }
461  m_TowerGeomNodeName = "TOWERGEOM_" + m_SuperDetector;
462  m_RawTowerGeom = findNode::getClass<RawTowerGeomContainer>(topNode(), m_TowerGeomNodeName);
463  if (!m_RawTowerGeom)
464  {
467  RunDetNode->addNode(newNode);
468  }
471  m_RawTowerGeom->set_radius(innerrad);
472  m_RawTowerGeom->set_thickness(thickness);
475  double geom_ref_radius = innerrad + thickness / 2.;
476  double phistart = m_Params->get_double_param("phistart");
477  if (!std::isfinite(phistart))
478  {
479  std::cout << PHWHERE << " phistart is not finite: " << phistart
480  << ", exiting now (this will crash anyway)" << std::endl;
481  gSystem->Exit(1);
482  }
483  for (int i = 0; i < m_Params->get_int_param(PHG4HcalDefs::n_towers); i++)
484  {
485  double phiend = phistart + 2. * M_PI / m_Params->get_int_param(PHG4HcalDefs::n_towers);
486  std::pair<double, double> range = std::make_pair(phiend, phistart);
487  phistart = phiend;
488  int tempi = i + 1;
490  m_RawTowerGeom->set_phibounds(tempi, range);
491  }
492  double etalowbound = -m_Params->get_double_param("scinti_eta_coverage_neg");
493  for (int i = 0; i < m_Params->get_int_param("etabins"); i++)
494  {
495  // double etahibound = etalowbound + 2.2 / get_int_param("etabins");
496  double etahibound = etalowbound +
497  (m_Params->get_double_param("scinti_eta_coverage_neg") + m_Params->get_double_param("scinti_eta_coverage_pos")) / m_Params->get_int_param("etabins");
498  std::pair<double, double> range = std::make_pair(etalowbound, etahibound);
499  m_RawTowerGeom->set_etabounds(i, range);
500  etalowbound = etahibound;
501  }
502  for (int iphi = 0; iphi < m_RawTowerGeom->get_phibins(); iphi++)
503  {
504  for (int ieta = 0; ieta < m_RawTowerGeom->get_etabins(); ieta++)
505  {
507 
508  const double x(geom_ref_radius * cos(m_RawTowerGeom->get_phicenter(iphi)));
509  const double y(geom_ref_radius * sin(m_RawTowerGeom->get_phicenter(iphi)));
510  const double z(geom_ref_radius / tan(PHG4Utils::get_theta(m_RawTowerGeom->get_etacenter(ieta))));
511 
513  if (tg)
514  {
515  if (Verbosity() > 0)
516  {
517  std::cout << "IHCalDetector::InitRun - Tower geometry " << key << " already exists" << std::endl;
518  }
519 
520  if (fabs(tg->get_center_x() - x) > 1e-4)
521  {
522  std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x
523  << std::endl;
524 
525  return;
526  }
527  if (fabs(tg->get_center_y() - y) > 1e-4)
528  {
529  std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y
530  << std::endl;
531  return;
532  }
533  if (fabs(tg->get_center_z() - z) > 1e-4)
534  {
535  std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z
536  << std::endl;
537  return;
538  }
539  }
540  else
541  {
542  if (Verbosity() > 0)
543  {
544  std::cout << "IHCalDetector::InitRun - building tower geometry " << key << "" << std::endl;
545  }
546 
547  tg = new RawTowerGeomv1(key);
548 
549  tg->set_center_x(x);
550  tg->set_center_y(y);
551  tg->set_center_z(z);
553  }
554  }
555  }
556  if (Verbosity() > 0)
557  {
559  }
560 }