Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4SpacalDetector.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4SpacalDetector.cc
1 
8 #include "PHG4SpacalDetector.h"
10 
12 #include "PHG4CylinderGeom_Spacalv1.h" // for PHG4CylinderGeom_Spaca...
13 
14 #include "PHG4CellDefs.h"
15 #include "PHG4CylinderCellGeom.h"
19 
20 #include <g4main/PHG4Detector.h> // for PHG4Detector
21 #include <g4main/PHG4DisplayAction.h> // for PHG4DisplayAction
22 #include <g4main/PHG4Subsystem.h>
23 #include <g4main/PHG4Utils.h>
24 
25 #include <phool/PHCompositeNode.h>
26 #include <phool/PHIODataNode.h>
27 #include <phool/PHNode.h> // for PHNode
28 #include <phool/PHNodeIterator.h> // for PHNodeIterator
29 #include <phool/PHObject.h> // for PHObject
30 #include <phool/getClass.h>
31 #include <phool/recoConsts.h>
32 
33 #include <g4gdml/PHG4GDMLConfig.hh>
35 
36 #include <calobase/RawTowerDefs.h> // for convert_name_...
37 #include <calobase/RawTowerGeom.h> // for RawTowerGeom
38 #include <calobase/RawTowerGeomContainer.h> // for RawTowerGeomC...
39 #include <calobase/RawTowerGeomContainer_Cylinderv1.h>
40 #include <calobase/RawTowerGeomv1.h>
41 
42 #include <TSystem.h>
43 
44 #include <Geant4/G4LogicalVolume.hh>
45 #include <Geant4/G4Material.hh>
46 #include <Geant4/G4PVPlacement.hh>
47 #include <Geant4/G4PhysicalConstants.hh>
48 #include <Geant4/G4String.hh> // for G4String
49 #include <Geant4/G4SystemOfUnits.hh>
50 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
51 #include <Geant4/G4Transform3D.hh> // for G4Transform3D, G4RotateZ3D
52 #include <Geant4/G4Tubs.hh>
53 #include <Geant4/G4Types.hh> // for G4double
54 #include <Geant4/G4UserLimits.hh>
55 
56 #include <cassert>
57 #include <cstdlib> // for exit
58 #include <iostream> // for operator<<, basic_ostream
59 #include <sstream>
60 
61 class PHG4CylinderGeom;
62 
63 //_______________________________________________________________
64 // note this inactive thickness is ~1.5% of a radiation length
66  PHCompositeNode *Node,
67  const std::string &dnam,
69  const int lyr,
70  bool init_geom)
71  : PHG4Detector(subsys, Node, dnam)
72  , m_DisplayAction(dynamic_cast<PHG4SpacalDisplayAction *>(subsys->GetDisplayAction()))
73  , layer(lyr)
74 {
75  if (init_geom)
76  {
77  _geom = new SpacalGeom_t();
78  if (_geom == nullptr)
79  {
80  std::cout << "PHG4SpacalDetector::Constructor - Fatal Error - invalid geometry object!" << std::endl;
81  gSystem->Exit(1);
82  exit(1);
83  }
84  assert(parameters);
85  _geom->ImportParameters(*parameters);
86 
87  // _geom->Print();
88  }
89 
92 }
93 
95 {
96  // deleting nullptr pointers is allowed (results in NOOP)
97  // so checking for not null before deleting is not needed
99  delete _geom;
100 }
101 
102 //_______________________________________________________________
104 {
105  // std::cout << "checking detector" << std::endl;
106  if (active && fiber_core_vol.find(volume) != fiber_core_vol.end())
107  {
108  // return fiber_core_vol.find(volume)->second;
109  return FIBER_CORE;
110  }
111  if (absorberactive)
112  {
113  if (fiber_vol.find(volume) != fiber_vol.end())
114  {
115  return FIBER_CLADING;
116  }
117 
118  if (block_vol.find(volume) != block_vol.end())
119  {
120  return ABSORBER;
121  }
122 
123  if (calo_vol.find(volume) != calo_vol.end())
124  {
125  return SUPPORT;
126  }
127  }
128  return INACTIVE;
129 }
130 
131 //_______________________________________________________________
132 void PHG4SpacalDetector::ConstructMe(G4LogicalVolume *logicWorld)
133 {
134  assert(_geom);
135  fiber_core_step_limits = new G4UserLimits(_geom->get_fiber_core_step_size() * cm);
136 
138 
139  if ((Verbosity() > 0))
140  {
141  std::cout << "PHG4SpacalDetector::Construct::" << GetName()
142  << " - Start. Print Geometry:" << std::endl;
143  Print();
144  }
145 
146  if ((_geom->get_zmin() * cm + _geom->get_zmax() * cm) / 2 != _geom->get_zpos() * cm)
147  {
148  std::cout << "PHG4SpacalDetector::Construct - ERROR - not yet support unsymmetric system. Let me know if you need it. - Jin" << std::endl;
149  _geom->Print();
150  gSystem->Exit(-1);
151  }
152  if (_geom->get_zmin() * cm >= _geom->get_zmax() * cm)
153  {
154  std::cout << "PHG4SpacalDetector::Construct - ERROR - zmin >= zmax!" << std::endl;
155  _geom->Print();
156  gSystem->Exit(-1);
157  }
158 
159  G4Tubs *cylinder_solid = new G4Tubs(G4String(GetName()),
161  _geom->get_length() * cm / 2.0, 0, twopi);
162 
164  G4Material *cylinder_mat = GetDetectorMaterial(rc->get_StringFlag("WorldMaterial"));
165  assert(cylinder_mat);
166 
167  G4LogicalVolume *cylinder_logic = new G4LogicalVolume(cylinder_solid, cylinder_mat, GetName(), nullptr, nullptr, nullptr);
168  GetDisplayAction()->AddVolume(cylinder_logic, "SpacalCylinder");
169  if (!m_CosmicSetupFlag)
170  {
171  new G4PVPlacement(nullptr, G4ThreeVector(_geom->get_xpos() * cm, _geom->get_ypos() * cm, _geom->get_zpos() * cm),
172  cylinder_logic, GetName(),
173  logicWorld, false, 0, OverlapCheck());
174  }
175  // install sectors
176  if (_geom->get_sector_map().size() == 0)
177  {
179  }
180 
181  if ((Verbosity() > 0))
182  {
183  std::cout << "PHG4SpacalDetector::Construct::" << GetName()
184  << " - start constructing " << _geom->get_sector_map().size() << " sectors in total. " << std::endl;
185  Print();
186  }
187 
188  std::pair<G4LogicalVolume *, G4Transform3D> psec = Construct_AzimuthalSeg();
189  G4LogicalVolume *sec_logic = psec.first;
190  const G4Transform3D &sec_trans = psec.second;
191 
193  {
194  const int sec = val.first;
195  const double rot = val.second;
196 
197  G4Transform3D sec_place = G4RotateZ3D(rot) * sec_trans;
198 
199  std::ostringstream name;
200  name << GetName() << "_sec" << sec;
201  G4PVPlacement *calo_phys = nullptr;
202  if (m_CosmicSetupFlag)
203  {
204  calo_phys = new G4PVPlacement(nullptr, G4ThreeVector(0, -(_geom->get_radius()) * cm, 0), sec_logic,
205  G4String(name.str()), logicWorld, false, sec,
206  OverlapCheck());
207  }
208  else
209  {
210  calo_phys = new G4PVPlacement(sec_place, sec_logic,
211  G4String(name.str()), cylinder_logic, false, sec,
212  OverlapCheck());
213  }
214  calo_vol[calo_phys] = sec;
215 
217  gdml_config->exclude_physical_vol(calo_phys);
218  }
220 
221  if (active)
222  {
223  std::ostringstream geonode;
224  if (superdetector != "NONE")
225  {
226  geonode << "CYLINDERGEOM_" << superdetector;
227  }
228  else
229  {
230  geonode << "CYLINDERGEOM_" << detector_type << "_" << layer;
231  }
232  PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode(), geonode.str());
233  if (!geo)
234  {
235  geo = new PHG4CylinderGeomContainer();
236  PHNodeIterator iter(topNode());
237  PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
239  geonode.str(), "PHObject");
240  runNode->addNode(newNode);
241  }
242  // here in the detector class we have internal units, convert to cm
243  // before putting into the geom object
244  PHG4CylinderGeom *mygeom = clone_geom();
245  geo->AddLayerGeom(layer, mygeom);
246  // geo->identify();
247  }
248 
249  if (absorberactive)
250  {
251  std::ostringstream geonode;
252  if (superdetector != "NONE")
253  {
254  geonode << "CYLINDERGEOM_ABSORBER_" << superdetector;
255  }
256  else
257  {
258  geonode << "CYLINDERGEOM_ABSORBER_" << detector_type << "_" << layer;
259  }
260  PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode(), geonode.str());
261  if (!geo)
262  {
263  geo = new PHG4CylinderGeomContainer();
264  PHNodeIterator iter(topNode());
265  PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
267  geonode.str(), "PHObject");
268  runNode->addNode(newNode);
269  }
270  // here in the detector class we have internal units, convert to cm
271  // before putting into the geom object
272  PHG4CylinderGeom *mygeom = clone_geom();
273  geo->AddLayerGeom(layer, mygeom);
274  // geo->identify();
275  }
276 
277  if ((Verbosity() > 0))
278  {
279  std::cout << "PHG4SpacalDetector::Construct::" << GetName()
280  << " - Completed. Print Geometry:" << std::endl;
281  Print();
282  }
283 }
284 
285 std::pair<G4LogicalVolume *, G4Transform3D>
287 {
288  G4Tubs *sec_solid = new G4Tubs(G4String(GetName() + std::string("_sec")),
290  _geom->get_length() * cm / 2.0, 0, twopi / _geom->get_azimuthal_n_sec());
291 
292  G4Material *cylinder_mat = GetDetectorMaterial(_geom->get_absorber_mat());
293  assert(cylinder_mat);
294 
295  G4LogicalVolume *sec_logic = new G4LogicalVolume(sec_solid, cylinder_mat,
296  G4String(G4String(GetName() + std::string("_sec"))), nullptr, nullptr, nullptr);
297 
298  GetDisplayAction()->AddVolume(sec_logic, "AzimuthSegment");
299 
300  const double fiber_length = _geom->get_thickness() * cm - 2 * _geom->get_fiber_outer_r() * cm;
301  G4LogicalVolume *fiber_logic = Construct_Fiber(fiber_length, std::string(""));
302 
303  int fiber_count = 0;
304  // double z_step = _geom->get_fiber_distance() * cm * sqrt(3) / 2.;
305  double z_step = _geom->get_z_distance() * cm;
306  G4double z = _geom->get_zmin() * cm - _geom->get_zpos() * cm + z_step;
307  while (z < _geom->get_zmax() * cm - _geom->get_zpos() * cm - z_step)
308  {
309  const double rot = twopi / _geom->get_azimuthal_n_sec() * ((fiber_count % 2 == 0) ? 1. / 4. : 3. / 4.);
310 
311  G4Transform3D fiber_place(G4RotateZ3D(rot) * G4TranslateZ3D(z) * G4TranslateX3D(_geom->get_half_radius() * cm) * G4RotateY3D(halfpi));
312 
313  std::ostringstream name;
314  name << GetName() << "_fiber_" << fiber_count;
315 
316  G4PVPlacement *fiber_physi = new G4PVPlacement(fiber_place, fiber_logic,
317  G4String(name.str()), sec_logic, false, fiber_count,
318  OverlapCheck());
319  fiber_vol[fiber_physi] = fiber_count;
321  gdml_config->exclude_physical_vol(fiber_physi);
322 
323  z += z_step;
324  fiber_count++;
325  }
326  _geom->set_nscint(fiber_count);
327 
328  if (Verbosity() > 0)
329  {
330  std::cout << "PHG4SpacalDetector::Construct_AzimuthalSeg::" << GetName()
331  << " - constructed " << fiber_count << " fibers" << std::endl;
332  std::cout << "\t"
333  << "_geom->get_fiber_distance() = " << _geom->get_fiber_distance()
334  << std::endl;
335  std::cout << "\t"
336  << "fiber_length = " << fiber_length
337  << "_geom->get_azimuthal_distance() = "
338  << _geom->get_azimuthal_distance() << std::endl;
339  std::cout << "\t"
340  << "_geom->is_virualize_fiber() = " << _geom->is_virualize_fiber()
341  << std::endl;
342  }
343 
344  return std::make_pair(sec_logic, G4Transform3D::Identity);
345 }
346 
347 G4LogicalVolume *
349 {
350  G4Tubs *fiber_solid = new G4Tubs(G4String(GetName() + std::string("_fiber") + id),
351  0, _geom->get_fiber_outer_r() * cm, length / 2.0, 0, twopi);
352 
353  G4Material *clading_mat = GetDetectorMaterial(_geom->get_fiber_clading_mat());
354  assert(clading_mat);
355 
356  G4LogicalVolume *fiber_logic = new G4LogicalVolume(fiber_solid, clading_mat,
357  G4String(G4String(GetName() + std::string("_fiber") + id)), nullptr, nullptr,
358  nullptr);
359 
360  {
361  GetDisplayAction()->AddVolume(fiber_logic, "Fiber");
362  }
363 
364  G4Tubs *core_solid = new G4Tubs(
365  G4String(GetName() + std::string("_fiber_core") + id), 0,
366  _geom->get_fiber_core_diameter() * cm / 2, length / 2.0, 0, twopi);
367 
368  G4Material *core_mat = GetDetectorMaterial(_geom->get_fiber_core_mat());
369  assert(core_mat);
370 
371  G4LogicalVolume *core_logic = new G4LogicalVolume(core_solid, core_mat,
372  G4String(G4String(GetName() + std::string("_fiber_core") + id)), nullptr, nullptr,
374 
375  {
376  GetDisplayAction()->AddVolume(core_logic, "FiberCore");
377  }
378 
379  const bool overlapcheck_fiber = OverlapCheck() and (Verbosity() >= 3);
380  G4PVPlacement *core_physi = new G4PVPlacement(nullptr, G4ThreeVector(), core_logic,
381  G4String(G4String(GetName() + std::string("_fiber_core") + id)), fiber_logic,
382  false, 0, overlapcheck_fiber);
383  fiber_core_vol[core_physi] = 0;
384 
385  return fiber_logic;
386 }
387 
388 void PHG4SpacalDetector::Print(const std::string & /*what*/) const
389 {
390  std::cout << "PHG4SpacalDetector::Print::" << GetName() << " - Print Geometry:" << std::endl;
391  _geom->Print();
392 
393  return;
394 }
395 // This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco.
397 {
398  PHNodeIterator iter(topNode());
399  PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
400  if (!runNode)
401  {
402  std::cout << PHWHERE << "Run Node missing, doing nothing." << std::endl;
403  throw std::runtime_error("Failed to find Run node in PHG4SpacalDetector::AddGeometryNode");
404  }
405 
406  PHNodeIterator runIter(runNode);
407  PHCompositeNode *RunDetNode = dynamic_cast<PHCompositeNode *>(runIter.findFirst("PHCompositeNode", superdetector));
408  if (!RunDetNode)
409  {
410  RunDetNode = new PHCompositeNode(superdetector);
411  runNode->addNode(RunDetNode);
412  }
413 
415 
416  // get the cell geometry and build up the tower geometry object
417  std::string geonodename = "CYLINDERCELLGEOM_" + superdetector;
418  PHG4CylinderCellGeomContainer *cellgeos = findNode::getClass<PHG4CylinderCellGeomContainer>(topNode(), geonodename);
419  if (!cellgeos)
420  {
421  std::cout << PHWHERE << " " << geonodename
422  << " Node missing, doing nothing." << std::endl;
423  throw std::runtime_error(
424  "Failed to find " + geonodename + " node in PHG4SpacalDetector::AddGeometryNode");
425  }
426  m_TowerGeomNodeName = "TOWERGEOM_" + superdetector;
427  m_RawTowerGeomContainer = findNode::getClass<RawTowerGeomContainer>(topNode(), m_TowerGeomNodeName);
429  {
432  RunDetNode->addNode(newNode);
433  }
434  // fill the number of layers in the calorimeter
435  m_NumLayers = cellgeos->get_NLayers();
436 
437  // Create the tower nodes on the tree
440  cellgeos->get_begin_end();
441  int ifirst = 1;
442  int first_layer = -1;
443  PHG4CylinderCellGeom *first_cellgeo = nullptr;
444  double inner_radius = 0;
445  double thickness = 0;
446  for (miter = begin_end.first; miter != begin_end.second; ++miter)
447  {
448  PHG4CylinderCellGeom *cellgeo = miter->second;
449 
450  if (Verbosity())
451  {
452  cellgeo->identify();
453  }
454  thickness += cellgeo->get_thickness();
455  if (ifirst)
456  {
457  first_cellgeo = miter->second;
458  m_CellBinning = cellgeo->get_binning();
459  m_NumPhiBins = cellgeo->get_phibins();
460  m_PhiMin = cellgeo->get_phimin();
461  m_PhiStep = cellgeo->get_phistep();
463  {
464  m_NumEtaBins = cellgeo->get_etabins();
465  m_EtaMin = cellgeo->get_etamin();
466  m_EtaStep = cellgeo->get_etastep();
467  }
469  {
470  m_NumEtaBins = cellgeo->get_zbins(); // bin eta in the same number of z bins
471  }
473  {
474  // use eta definiton for each row of towers
475  m_NumEtaBins = cellgeo->get_etabins();
476  }
477  else
478  {
479  std::cout << "PHG4SpacalDetector::AddGeometryNode::" << GetName()
480  << " - Fatal Error - unsupported cell binning method "
481  << m_CellBinning << std::endl;
482  }
483  inner_radius = cellgeo->get_radius();
484  first_layer = cellgeo->get_layer();
485  ifirst = 0;
486  }
487  else
488  {
489  if (m_CellBinning != cellgeo->get_binning())
490  {
491  std::cout << "inconsistent binning method from " << m_CellBinning
492  << " layer " << cellgeo->get_layer() << ": "
493  << cellgeo->get_binning() << std::endl;
494  exit(1);
495  }
496  if (inner_radius > cellgeo->get_radius())
497  {
498  std::cout << "radius of layer " << cellgeo->get_layer() << " is "
499  << cellgeo->get_radius() << " which smaller than radius "
500  << inner_radius << " of first layer in list " << first_layer
501  << std::endl;
502  }
503  if (m_NumPhiBins != cellgeo->get_phibins())
504  {
505  std::cout << "mixing number of phibins, fisrt layer: " << m_NumPhiBins
506  << " layer " << cellgeo->get_layer() << ": "
507  << cellgeo->get_phibins() << std::endl;
508  exit(1);
509  }
510  if (m_PhiMin != cellgeo->get_phimin())
511  {
512  std::cout << "mixing number of phimin, fisrt layer: " << m_PhiMin
513  << " layer " << cellgeo->get_layer() << ": "
514  << cellgeo->get_phimin() << std::endl;
515  exit(1);
516  }
517  if (m_PhiStep != cellgeo->get_phistep())
518  {
519  std::cout << "mixing phisteps first layer: " << m_PhiStep << " layer "
520  << cellgeo->get_layer() << ": " << cellgeo->get_phistep()
521  << " diff: " << m_PhiStep - cellgeo->get_phistep() << std::endl;
522  exit(1);
523  }
525  {
526  if (m_NumEtaBins != cellgeo->get_etabins())
527  {
528  std::cout << "mixing number of EtaBins , first layer: "
529  << m_NumEtaBins << " layer " << cellgeo->get_layer() << ": "
530  << cellgeo->get_etabins() << std::endl;
531  exit(1);
532  }
533  if (fabs(m_EtaMin - cellgeo->get_etamin()) > 1e-9)
534  {
535  std::cout << "mixing etamin, fisrt layer: " << m_EtaMin << " layer "
536  << cellgeo->get_layer() << ": " << cellgeo->get_etamin()
537  << " diff: " << m_EtaMin - cellgeo->get_etamin() << std::endl;
538  exit(1);
539  }
540  if (fabs(m_EtaStep - cellgeo->get_etastep()) > 1e-9)
541  {
542  std::cout << "mixing eta steps first layer: " << m_EtaStep
543  << " layer " << cellgeo->get_layer() << ": "
544  << cellgeo->get_etastep() << " diff: "
545  << m_EtaStep - cellgeo->get_etastep() << std::endl;
546  exit(1);
547  }
548  }
549 
551  {
552  if (m_NumEtaBins != cellgeo->get_zbins())
553  {
554  std::cout << "mixing number of z bins , first layer: " << m_NumEtaBins
555  << " layer " << cellgeo->get_layer() << ": "
556  << cellgeo->get_zbins() << std::endl;
557  exit(1);
558  }
559  }
560  }
561  }
562  m_RawTowerGeomContainer->set_radius(inner_radius);
565  // m_RawTowerGeomContainer->set_phistep(m_PhiStep);
566  // m_RawTowerGeomContainer->set_phimin(m_PhiMin);
568 
569  if (!first_cellgeo)
570  {
571  std::cout << "PHG4SpacalDetector::AddGeometryNode - ERROR - can not find first layer of cells "
572  << std::endl;
573 
574  exit(1);
575  }
576 
577  for (int ibin = 0; ibin < first_cellgeo->get_phibins(); ibin++)
578  {
579  const std::pair<double, double> range = first_cellgeo->get_phibounds(ibin);
580 
582  }
583 
585  {
586  const double r = inner_radius;
587 
588  for (int ibin = 0; ibin < first_cellgeo->get_etabins(); ibin++)
589  {
590  const std::pair<double, double> range = first_cellgeo->get_etabounds(ibin);
591 
593  }
594 
595  // setup location of all towers
596  for (int iphi = 0; iphi < m_RawTowerGeomContainer->get_phibins(); iphi++)
597  {
598  for (int ieta = 0; ieta < m_RawTowerGeomContainer->get_etabins(); ieta++)
599  {
600  const RawTowerDefs::keytype key =
601  RawTowerDefs::encode_towerid(caloid, ieta, iphi);
602 
603  const double x(r * cos(m_RawTowerGeomContainer->get_phicenter(iphi)));
604  const double y(r * sin(m_RawTowerGeomContainer->get_phicenter(iphi)));
605  const double z(r / tan(PHG4Utils::get_theta(m_RawTowerGeomContainer->get_etacenter(ieta))));
606 
608  if (tg)
609  {
610  if (Verbosity() > 0)
611  {
612  std::cout << "PHG4SpacalDetector::AddGeometryNode - Tower geometry " << key << " already exists" << std::endl;
613  }
614 
615  if (fabs(tg->get_center_x() - x) > 1e-4)
616  {
617  std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x
618  << std::endl;
619 
620  exit(1);
621  }
622  if (fabs(tg->get_center_y() - y) > 1e-4)
623  {
624  std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y
625  << std::endl;
626  exit(1);
627  }
628  if (fabs(tg->get_center_z() - z) > 1e-4)
629  {
630  std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z
631  << std::endl;
632  exit(1);
633  }
634  }
635  else
636  {
637  if (Verbosity() > 0)
638  {
639  std::cout << "PHG4SpacalDetector::AddGeometryNode - building tower geometry " << key << "" << std::endl;
640  }
641 
642  tg = new RawTowerGeomv1(key);
643 
644  tg->set_center_x(x);
645  tg->set_center_y(y);
646  tg->set_center_z(z);
648  }
649  }
650  }
651  }
653  {
654  const double r = inner_radius;
655 
656  for (int ibin = 0; ibin < first_cellgeo->get_zbins(); ibin++)
657  {
658  const std::pair<double, double> z_range = first_cellgeo->get_zbounds(ibin);
659  // const double r = first_cellgeo->get_radius();
660  const double eta1 = -log(tan(atan2(r, z_range.first) / 2.));
661  const double eta2 = -log(tan(atan2(r, z_range.second) / 2.));
662  m_RawTowerGeomContainer->set_etabounds(ibin, std::make_pair(eta1, eta2));
663  }
664 
665  // setup location of all towers
666  for (int iphi = 0; iphi < m_RawTowerGeomContainer->get_phibins(); iphi++)
667  {
668  for (int ibin = 0; ibin < first_cellgeo->get_zbins(); ibin++)
669  {
670  const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(caloid, ibin, iphi);
671 
672  const double x(r * cos(m_RawTowerGeomContainer->get_phicenter(iphi)));
673  const double y(r * sin(m_RawTowerGeomContainer->get_phicenter(iphi)));
674  const double z(first_cellgeo->get_zcenter(ibin));
675 
677  if (tg)
678  {
679  if (Verbosity() > 0)
680  {
681  std::cout << "PHG4SpacalDetector::AddGeometryNode - Tower geometry " << key << " already exists" << std::endl;
682  }
683 
684  if (fabs(tg->get_center_x() - x) > 1e-4)
685  {
686  std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x
687  << std::endl;
688 
689  exit(1);
690  }
691  if (fabs(tg->get_center_y() - y) > 1e-4)
692  {
693  std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y
694  << std::endl;
695  exit(1);
696  }
697  if (fabs(tg->get_center_z() - z) > 1e-4)
698  {
699  std::cout << "PHG4SpacalDetector::AddGeometryNode - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z
700  << std::endl;
701  exit(1);
702  }
703  }
704  else
705  {
706  if (Verbosity() > 0)
707  {
708  std::cout << "PHG4SpacalDetector::AddGeometryNode - building tower geometry " << key << "" << std::endl;
709  }
710 
711  tg = new RawTowerGeomv1(key);
712 
713  tg->set_center_x(x);
714  tg->set_center_y(y);
715  tg->set_center_z(z);
717  }
718  }
719  }
720  }
721  else
722  {
723  std::cout << "PHG4SpacalDetector::AddGeometryNode - ERROR - unsupported cell geometry "
724  << m_CellBinning << std::endl;
725  exit(1);
726  }
727 
728  if (Verbosity() >= 1)
729  {
731  }
732 
733  return;
734 }
735 
737 {
738  PHNodeIterator iter(topNode());
740  // Looking for the DST node
741  PHCompositeNode *dstNode;
742  dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
743  if (!dstNode)
744  {
745  std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
746  exit(1);
747  }
748 
749  std::string geonodename = "CYLINDERGEOM_" + detector;
750  PHG4CylinderGeomContainer *geo = findNode::getClass<PHG4CylinderGeomContainer>(topNode(), geonodename);
751  if (!geo)
752  {
753  std::cout << "PHG4SpacalDetector::AddCellGeometryNode - Could not locate geometry node "
754  << geonodename << std::endl;
755  topNode()->print();
756  exit(1);
757  }
758  if (Verbosity() > 0)
759  {
760  std::cout << "PHG4SpacalDetector::AddCellGeometryNode- incoming geometry:"
761  << std::endl;
762  geo->identify();
763  }
764  std::string seggeonodename = "CYLINDERCELLGEOM_" + detector;
765  PHG4CylinderCellGeomContainer *seggeo = findNode::getClass<PHG4CylinderCellGeomContainer>(topNode(), seggeonodename);
766  if (!seggeo)
767  {
768  seggeo = new PHG4CylinderCellGeomContainer();
769  PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
770  PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(seggeo, seggeonodename, "PHObject");
771  runNode->addNode(newNode);
772  }
773 
774  const PHG4CylinderGeom *layergeom_raw = geo->GetFirstLayerGeom();
775  assert(layergeom_raw);
776 
777  // a special implimentation of PHG4CylinderGeom is required here.
778  const PHG4CylinderGeom_Spacalv3 *layergeom =
779  dynamic_cast<const PHG4CylinderGeom_Spacalv3 *>(layergeom_raw);
780 
781  if (!layergeom)
782  {
783  std::cout << "PHG4SpacalDetector::AddCellGeometryNode- Fatal Error -"
784  << " require to work with a version of SPACAL geometry of PHG4CylinderGeom_Spacalv3 or higher. "
785  << "However the incoming geometry has version "
786  << layergeom_raw->ClassName() << std::endl;
787  exit(1);
788  }
789  if (Verbosity() > 1)
790  {
791  layergeom->identify();
792  }
793 
794  layergeom->subtower_consistency_check();
795 
796  // int layer = layergeom->get_layer();
797 
798  // create geo object and fill with variables common to all binning methods
800  layerseggeo->set_layer(layergeom->get_layer());
801  layerseggeo->set_radius(layergeom->get_radius());
802  layerseggeo->set_thickness(layergeom->get_thickness());
804 
805  // construct a map to convert tower_ID into the older eta bins.
806 
807  const PHG4CylinderGeom_Spacalv3::tower_map_t &tower_map = layergeom->get_sector_tower_map();
808  const PHG4CylinderGeom_Spacalv3::sector_map_t &sector_map = layergeom->get_sector_map();
809  const int nphibin = layergeom->get_azimuthal_n_sec() // sector
810  * layergeom->get_max_phi_bin_in_sec() // blocks per sector
811  * layergeom->get_n_subtower_phi(); // subtower per block
812  const double deltaphi = 2. * M_PI / nphibin;
813 
814  using map_z_tower_z_ID_t = std::map<double, int>;
815  map_z_tower_z_ID_t map_z_tower_z_ID;
816  double phi_min = NAN;
817 
818  for (const auto &tower_pair : tower_map)
819  {
820  const int &tower_ID = tower_pair.first;
821  const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second;
822 
823  // inspect index in sector 0
824  std::pair<int, int> tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0);
825 
826  const int &tower_ID_z = tower_z_phi_ID.first;
827  const int &tower_ID_phi = tower_z_phi_ID.second;
828 
829  if (tower_ID_phi == 0)
830  {
831  // assign phi min according phi bin 0
832  phi_min = M_PI_2 - deltaphi * (layergeom->get_max_phi_bin_in_sec() * layergeom->get_n_subtower_phi() / 2) // shift of first tower in sector
833  + sector_map.begin()->second;
834  }
835 
836  if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2)
837  {
838  // assign eta min according phi bin 0
839  map_z_tower_z_ID[tower.centralZ] = tower_ID_z;
840  }
841  // ...
842  } // const auto &tower_pair: tower_map
843 
844  assert(!std::isnan(phi_min));
845  layerseggeo->set_phimin(phi_min);
846  layerseggeo->set_phistep(deltaphi);
847  layerseggeo->set_phibins(nphibin);
848 
850  int eta_bin = 0;
851  for (auto &z_tower_z_ID : map_z_tower_z_ID)
852  {
853  tower_z_ID_eta_bin_map[z_tower_z_ID.second] = eta_bin;
854  eta_bin++;
855  }
856  layerseggeo->set_tower_z_ID_eta_bin_map(tower_z_ID_eta_bin_map);
857  layerseggeo->set_etabins(eta_bin * layergeom->get_n_subtower_eta());
858  layerseggeo->set_etamin(NAN);
859  layerseggeo->set_etastep(NAN);
860 
861  // build eta bin maps
862  for (const auto &tower_pair : tower_map)
863  {
864  const int &tower_ID = tower_pair.first;
865  const PHG4CylinderGeom_Spacalv3::geom_tower &tower = tower_pair.second;
866 
867  // inspect index in sector 0
868  std::pair<int, int> tower_z_phi_ID = layergeom->get_tower_z_phi_ID(tower_ID, 0);
869  const int &tower_ID_z = tower_z_phi_ID.first;
870  const int &tower_ID_phi = tower_z_phi_ID.second;
871  const int &etabin = tower_z_ID_eta_bin_map[tower_ID_z];
872 
873  if (tower_ID_phi == layergeom->get_max_phi_bin_in_sec() / 2)
874  {
875  // half z-range
876  const double dz = fabs(0.5 * (tower.pDy1 + tower.pDy2) / sin(tower.pRotationAngleX));
877  const double tower_radial = layergeom->get_tower_radial_position(tower);
878 
879  auto z_to_eta = [&tower_radial](const double &z)
880  { return -log(tan(0.5 * atan2(tower_radial, z))); };
881 
882  const double eta_central = z_to_eta(tower.centralZ);
883  // half eta-range
884  const double deta = (z_to_eta(tower.centralZ + dz) - z_to_eta(tower.centralZ - dz)) / 2;
885  assert(deta > 0);
886 
887  for (int sub_tower_ID_y = 0; sub_tower_ID_y < tower.NSubtowerY;
888  ++sub_tower_ID_y)
889  {
890  assert(tower.NSubtowerY <= layergeom->get_n_subtower_eta());
891  // do not overlap to the next bin.
892  const int sub_tower_etabin = etabin * layergeom->get_n_subtower_eta() + sub_tower_ID_y;
893 
894  const std::pair<double, double> etabounds(eta_central - deta + sub_tower_ID_y * 2 * deta / tower.NSubtowerY,
895  eta_central - deta + (sub_tower_ID_y + 1) * 2 * deta / tower.NSubtowerY);
896 
897  const std::pair<double, double> zbounds(tower.centralZ - dz + sub_tower_ID_y * 2 * dz / tower.NSubtowerY,
898  tower.centralZ - dz + (sub_tower_ID_y + 1) * 2 * dz / tower.NSubtowerY);
899 
900  layerseggeo->set_etabounds(sub_tower_etabin, etabounds);
901  layerseggeo->set_zbounds(sub_tower_etabin, zbounds);
902  }
903  }
904  // ...
905  } // const auto &tower_pair: tower_map
906 
907  // add geo object filled by different binning methods
908  seggeo->AddLayerCellGeom(layerseggeo);
909  // save this to the run wise tree to store on DST
910  PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
911  //PHCompositeNode *parNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "PAR"));
912  PHNodeIterator runIter(runNode);
913  PHCompositeNode *RunDetNode = dynamic_cast<PHCompositeNode *>(runIter.findFirst("PHCompositeNode", detector));
914  if (!RunDetNode)
915  {
916  RunDetNode = new PHCompositeNode(detector);
917  runNode->addNode(RunDetNode);
918  }
919  /*
920  std::string paramnodename = "G4CELLPARAM_" + detector;
921  SaveToNodeTree(RunDetNode, paramnodename);
922  save this to the parNode for use
923  PHNodeIterator parIter(parNode);
924  PHCompositeNode *ParDetNode = dynamic_cast<PHCompositeNode *>(parIter.findFirst("PHCompositeNode", detector));
925  if (!ParDetNode)
926  {
927  ParDetNode = new PHCompositeNode(detector);
928  parNode->addNode(ParDetNode);
929  }
930  std::string cellgeonodename = "G4CELLGEO_" + detector;
931  PutOnParNode(ParDetNode, cellgeonodename);
932  */
933  return;
934 }