Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:19:16

0001 #include "PHG4IHCalDetector.h"
0002 
0003 #include "PHG4IHCalDisplayAction.h"
0004 
0005 #include <g4detectors/PHG4DetectorSubsystem.h>
0006 #include <g4detectors/PHG4HcalDefs.h>
0007 
0008 #include <phparameter/PHParameters.h>
0009 
0010 #include <g4gdml/PHG4GDMLConfig.hh>
0011 #include <g4gdml/PHG4GDMLUtility.hh>
0012 
0013 #include <calobase/RawTowerDefs.h>           // for convert_name_...
0014 #include <calobase/RawTowerGeom.h>           // for RawTowerGeom
0015 #include <calobase/RawTowerGeomContainer.h>  // for RawTowerGeomC...
0016 #include <calobase/RawTowerGeomContainer_Cylinderv1.h>
0017 #include <calobase/RawTowerGeomv1.h>
0018 
0019 #include <g4main/PHG4Detector.h>
0020 #include <g4main/PHG4DisplayAction.h>
0021 #include <g4main/PHG4Subsystem.h>
0022 #include <g4main/PHG4Utils.h>
0023 
0024 #include <ffamodules/CDBInterface.h>
0025 
0026 #include <phool/PHCompositeNode.h>
0027 #include <phool/PHIODataNode.h>
0028 #include <phool/PHNode.h>  // for PHNode
0029 #include <phool/PHNodeIterator.h>
0030 #include <phool/PHObject.h>  // for PHObject
0031 #include <phool/getClass.h>
0032 #include <phool/phool.h>
0033 #include <phool/recoConsts.h>
0034 
0035 #include <TSystem.h>
0036 
0037 #include <Geant4/G4AssemblyVolume.hh>
0038 #include <Geant4/G4IonisParamMat.hh>
0039 #include <Geant4/G4LogicalVolume.hh>
0040 #include <Geant4/G4Material.hh>
0041 #include <Geant4/G4MaterialTable.hh>
0042 #include <Geant4/G4PVPlacement.hh>
0043 #include <Geant4/G4RotationMatrix.hh>
0044 #include <Geant4/G4String.hh>
0045 #include <Geant4/G4SystemOfUnits.hh>
0046 #include <Geant4/G4ThreeVector.hh>
0047 #include <Geant4/G4Transform3D.hh>
0048 #include <Geant4/G4Tubs.hh>
0049 #include <Geant4/G4VPhysicalVolume.hh>  // for G4VPhysicalVolume
0050 #include <Geant4/G4VSolid.hh>
0051 
0052 #pragma GCC diagnostic push
0053 #pragma GCC diagnostic ignored "-Wshadow"
0054 #pragma GCC diagnostic ignored "-Wpedantic"
0055 #include <Geant4/G4GDMLParser.hh>
0056 #include <Geant4/G4GDMLReadStructure.hh>  // for G4GDMLReadStructure
0057 #pragma GCC diagnostic pop
0058 
0059 #include <boost/lexical_cast.hpp>
0060 #include <boost/tokenizer.hpp>
0061 
0062 #include <cassert>
0063 #include <cstdlib>
0064 #include <cmath>
0065 #include <filesystem>
0066 #include <iostream>
0067 #include <memory>   // for unique_ptr
0068 #include <utility>  // for pair, make_pair
0069 #include <vector>   // for vector, vector<>::iter...
0070 
0071 PHG4IHCalDetector::PHG4IHCalDetector(PHG4Subsystem *subsys, PHCompositeNode *Node, PHParameters *parameters, const std::string &dnam)
0072   : PHG4Detector(subsys, Node, dnam)
0073   , m_DisplayAction(dynamic_cast<PHG4IHCalDisplayAction *>(subsys->GetDisplayAction()))
0074   , m_Params(parameters)
0075   , m_InnerRadius(m_Params->get_double_param("inner_radius") * cm)
0076   , m_OuterRadius(m_Params->get_double_param("outer_radius") * cm)
0077   , m_SizeZ(m_Params->get_double_param("size_z") * cm)
0078   , m_NumScintiPlates(m_Params->get_int_param(PHG4HcalDefs::scipertwr) * m_Params->get_int_param("n_towers"))
0079   , m_Active(m_Params->get_int_param("active"))
0080   , m_AbsorberActive(m_Params->get_int_param("absorberactive"))
0081   , m_GDMPath(m_Params->get_string_param("GDMPath"))
0082 {
0083   gdml_config = PHG4GDMLUtility::GetOrMakeConfigNode(Node);
0084   assert(gdml_config);
0085   // changes in the parameters have to be made here
0086   // otherwise they will not be propagated to the node tree
0087   if (std::filesystem::path(m_GDMPath).extension() != ".gdml")
0088   {
0089     m_GDMPath = CDBInterface::instance()->getUrl(m_GDMPath);
0090     m_Params->set_string_param("GDMPath", m_GDMPath);
0091   }
0092 }
0093 
0094 PHG4IHCalDetector::~PHG4IHCalDetector()
0095 {
0096   delete m_ScintiMotherAssembly;
0097 }
0098 
0099 //_______________________________________________________________
0100 //_______________________________________________________________
0101 int PHG4IHCalDetector::IsInIHCal(G4VPhysicalVolume *volume) const
0102 {
0103   if (m_AbsorberActive)
0104   {
0105     if (m_SteelAbsorberLogVolSet.find(volume->GetLogicalVolume()) != m_SteelAbsorberLogVolSet.end())
0106     {
0107       return -1;
0108     }
0109   }
0110   if (m_Active)
0111   {
0112     if (m_ScintiTileLogVolSet.find(volume->GetLogicalVolume()) != m_ScintiTileLogVolSet.end())
0113     {
0114       return 1;
0115     }
0116   }
0117   return 0;
0118 }
0119 
0120 // Construct the envelope and the call the
0121 // actual inner hcal construction
0122 void PHG4IHCalDetector::ConstructMe(G4LogicalVolume *logicWorld)
0123 {
0124   recoConsts *rc = recoConsts::instance();
0125   G4Material *worldmat = GetDetectorMaterial(rc->get_StringFlag("WorldMaterial"));
0126   G4VSolid *hcal_envelope_cylinder = new G4Tubs("IHCal_envelope_solid", m_InnerRadius, m_OuterRadius, m_SizeZ / 2., 0, 2 * M_PI);
0127   m_VolumeEnvelope = hcal_envelope_cylinder->GetCubicVolume();
0128   G4LogicalVolume *hcal_envelope_log = new G4LogicalVolume(hcal_envelope_cylinder, worldmat, "Hcal_envelope", nullptr, nullptr, nullptr);
0129 
0130   G4RotationMatrix hcal_rotm;
0131   hcal_rotm.rotateX(m_Params->get_double_param("rot_x") * deg);
0132   hcal_rotm.rotateY(m_Params->get_double_param("rot_y") * deg);
0133   hcal_rotm.rotateZ(m_Params->get_double_param("rot_z") * deg);
0134   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());
0135   m_DisplayAction->SetMyTopVolume(mothervol);
0136   ConstructIHCal(hcal_envelope_log);
0137 
0138   // disable GDML export for HCal geometries for memory saving and compatibility issues
0139   assert(gdml_config);
0140   gdml_config->exclude_physical_vol(mothervol);
0141   gdml_config->exclude_logical_vol(hcal_envelope_log);
0142 
0143   const G4MaterialTable *mtable = G4Material::GetMaterialTable();
0144   int nMaterials = G4Material::GetNumberOfMaterials();
0145   for (auto i = 0; i < nMaterials; ++i)
0146   {
0147     const G4Material *mat = (*mtable)[i];
0148     if (mat->GetName() == "Uniplast_scintillator")
0149     {
0150       if ((mat->GetIonisation()->GetBirksConstant()) == 0)
0151       {
0152         mat->GetIonisation()->SetBirksConstant(m_Params->get_double_param("Birk_const"));
0153       }
0154     }
0155   }
0156   if (!m_Params->get_int_param("saveg4hit"))
0157   {
0158     AddGeometryNode();
0159   }
0160   return;
0161 }
0162 
0163 int PHG4IHCalDetector::ConstructIHCal(G4LogicalVolume *hcalenvelope)
0164 {
0165   // import the staves from the geometry file
0166   std::unique_ptr<G4GDMLReadStructure> reader(new G4GDMLReadStructure());
0167   G4GDMLParser gdmlParser(reader.get());
0168   gdmlParser.SetOverlapCheck(OverlapCheck());
0169   if (!std::filesystem::exists(m_GDMPath))
0170   {
0171     std::cout << PHWHERE << " Inner HCal gdml file " << m_GDMPath << " not found" << std::endl;
0172     gSystem->Exit(1);
0173     exit(1);
0174   }
0175   gdmlParser.Read(m_GDMPath, false);
0176 
0177   G4AssemblyVolume *abs_asym = reader->GetAssembly("InnerSector");      // absorber
0178   m_ScintiMotherAssembly = reader->GetAssembly("InnerTileAssembly90");  // scintillator
0179   std::vector<G4VPhysicalVolume *>::iterator it = abs_asym->GetVolumesIterator();
0180   static const unsigned int tilepersec = 24 * 4 * 2;
0181   for (unsigned int isector = 0; isector < abs_asym->TotalImprintedVolumes(); isector++)
0182   {
0183     m_DisplayAction->AddSteelVolume((*it)->GetLogicalVolume());
0184     m_SteelAbsorberLogVolSet.insert((*it)->GetLogicalVolume());
0185     hcalenvelope->AddDaughter((*it));
0186     m_AbsorberPhysVolMap.insert(std::make_pair(*it, isector));
0187     m_VolumeSteel += (*it)->GetLogicalVolume()->GetSolid()->GetCubicVolume();
0188     std::vector<G4VPhysicalVolume *>::iterator its = m_ScintiMotherAssembly->GetVolumesIterator();
0189     unsigned int ioff = isector * tilepersec;
0190     for (unsigned int j = 0; j < ioff; j++)
0191     {
0192       ++its;
0193     }
0194     for (unsigned int j = ioff; j < ioff + tilepersec; j++)
0195     {
0196       m_DisplayAction->AddScintiVolume((*its)->GetLogicalVolume());
0197       m_ScintiTileLogVolSet.insert((*its)->GetLogicalVolume());
0198       hcalenvelope->AddDaughter((*its));
0199       m_ScintiTilePhysVolMap.insert(std::make_pair(*its, ExtractLayerTowerId(isector, *its)));
0200       m_VolumeScintillator += (*its)->GetLogicalVolume()->GetSolid()->GetCubicVolume();
0201       ++its;
0202     }
0203 
0204     ++it;
0205   }
0206   return 0;
0207 }
0208 
0209 int PHG4IHCalDetector::ConsistencyCheck() const
0210 {
0211   // just make sure the parameters make a bit of sense
0212   if (m_InnerRadius >= m_OuterRadius)
0213   {
0214     std::cout << PHWHERE << ": Inner Radius " << m_InnerRadius / cm
0215               << " cm larger than Outer Radius " << m_OuterRadius / cm
0216               << " cm" << std::endl;
0217     gSystem->Exit(1);
0218   }
0219   return 0;
0220 }
0221 
0222 void PHG4IHCalDetector::Print(const std::string &what) const
0223 {
0224   std::cout << "Inner Hcal Detector:" << std::endl;
0225   if (what == "ALL" || what == "VOLUME")
0226   {
0227     std::cout << "Volume Envelope: " << m_VolumeEnvelope / cm3 << " cm^3" << std::endl;
0228     std::cout << "Volume Steel: " << m_VolumeSteel / cm3 << " cm^3" << std::endl;
0229     std::cout << "Volume Scintillator: " << m_VolumeScintillator / cm3 << " cm^3" << std::endl;
0230     std::cout << "Volume Air: " << (m_VolumeEnvelope - m_VolumeSteel - m_VolumeScintillator) / cm3 << " cm^3" << std::endl;
0231   }
0232   return;
0233 }
0234 
0235 std::tuple<int, int, int> PHG4IHCalDetector::GetLayerTowerId(G4VPhysicalVolume *volume) const
0236 {
0237   auto it = m_ScintiTilePhysVolMap.find(volume);
0238   if (it != m_ScintiTilePhysVolMap.end())
0239   {
0240     return it->second;
0241   }
0242   std::cout << "could not locate volume " << volume->GetName()
0243             << " in Inner Hcal scintillator map" << std::endl;
0244   gSystem->Exit(1);
0245   // that's dumb but code checkers do not know that gSystem->Exit()
0246   // terminates, so using the standard exit() makes them happy
0247   exit(1);
0248 }
0249 
0250 int PHG4IHCalDetector::GetSectorId(G4VPhysicalVolume *volume) const
0251 {
0252   auto it = m_AbsorberPhysVolMap.find(volume);
0253   if (it != m_AbsorberPhysVolMap.end())
0254   {
0255     return it->second;
0256   }
0257   std::cout << "could not locate volume " << volume->GetName()
0258             << " in Inner Hcal Absorber map" << std::endl;
0259   gSystem->Exit(1);
0260   // that's dumb but code checkers do not know that gSystem->Exit()
0261   // terminates, so using the standard exit() makes them happy
0262   exit(1);
0263 }
0264 
0265 std::tuple<int, int, int> PHG4IHCalDetector::ExtractLayerTowerId(const unsigned int isector, G4VPhysicalVolume *volume)
0266 {
0267   boost::char_separator<char> sep("_");
0268   boost::tokenizer<boost::char_separator<char>> tok(volume->GetName(), sep);
0269   boost::tokenizer<boost::char_separator<char>>::const_iterator tokeniter;
0270   int layer_id = -1, tower_id = -1;
0271   for (tokeniter = tok.begin(); tokeniter != tok.end(); ++tokeniter)
0272   {
0273     if (*tokeniter == "impr")
0274     {
0275       ++tokeniter;
0276       if (tokeniter != tok.end())
0277       {
0278         layer_id = boost::lexical_cast<int>(*tokeniter) / 2;
0279         layer_id--;
0280         if (layer_id < 0 || layer_id >= m_NumScintiPlates)
0281         {
0282           std::cout << "invalid scintillator row " << layer_id
0283                     << ", valid range 0 < row < " << m_NumScintiPlates << std::endl;
0284           gSystem->Exit(1);
0285         }
0286       }
0287       else
0288       {
0289         std::cout << PHWHERE << " Error parsing " << volume->GetName()
0290                   << " for mother volume number " << std::endl;
0291         gSystem->Exit(1);
0292       }
0293       break;
0294     }
0295   }
0296   for (tokeniter = tok.begin(); tokeniter != tok.end(); ++tokeniter)
0297   {
0298     if (*tokeniter == "pv")
0299     {
0300       ++tokeniter;
0301       if (tokeniter != tok.end())
0302       {
0303         tower_id = boost::lexical_cast<int>(*tokeniter);
0304       }
0305     }
0306   }
0307   int column = map_towerid(tower_id);
0308   int row = map_layerid(layer_id);
0309   return std::make_tuple(isector, row, column);
0310 }
0311 
0312 // map gdml tower ids to our columns
0313 int PHG4IHCalDetector::map_towerid(const int tower_id)
0314 {
0315   // odd id's go in one direction, even id's in the other one
0316   // this is a shortcut to derive the observed dependency
0317   // commented out after this code
0318   int itwr = -1;
0319   int itmp = tower_id / 2;
0320   if (tower_id % 2)
0321   {
0322     itwr = 12 + itmp;
0323   }
0324   else
0325   {
0326     itwr = 11 - itmp;
0327   }
0328   return itwr;
0329   // here is the mapping in long form
0330   // if (tower_id == 23)
0331   // {
0332   //   itwr = 0;
0333   // }
0334   // else if (tower_id == 21)
0335   // {
0336   //   itwr = 1;
0337   // }
0338   // else if (tower_id ==19 )
0339   // {
0340   //   itwr = 2;
0341   // }
0342   // else if (tower_id == 17)
0343   // {
0344   //   itwr = 3;
0345   // }
0346   // else if (tower_id == 15)
0347   // {
0348   //   itwr = 4;
0349   // }
0350   // else if (tower_id == 13)
0351   // {
0352   //   itwr = 5;
0353   // }
0354   // else if (tower_id == 11)
0355   // {
0356   //   itwr = 6;
0357   // }
0358   // else if (tower_id == 9)
0359   // {
0360   //   itwr = 7;
0361   // }
0362   // else if (tower_id == 7)
0363   // {
0364   //   itwr = 8;
0365   // }
0366   // else if (tower_id == 5)
0367   // {
0368   //   itwr = 9;
0369   // }
0370   // else if (tower_id == 3)
0371   // {
0372   //   itwr = 10;
0373   // }
0374   // else if (tower_id == 1)
0375   // {
0376   //   itwr = 11;
0377   // }
0378   // else if (tower_id == 0)
0379   // {
0380   //   itwr = 12;
0381   // }
0382   // else if (tower_id == 2)
0383   // {
0384   //   itwr = 13;
0385   // }
0386   // else if (tower_id == 4)
0387   // {
0388   //   itwr = 14;
0389   // }
0390   // else if (tower_id == 6)
0391   // {
0392   //   itwr = 15;
0393   // }
0394   // else if (tower_id == 8)
0395   // {
0396   //   itwr = 16;
0397   // }
0398   // else if (tower_id == 10)
0399   // {
0400   //   itwr = 17;
0401   // }
0402   // else if (tower_id == 12)
0403   // {
0404   //   itwr = 18;
0405   // }
0406   // else if (tower_id == 14)
0407   // {
0408   //   itwr = 19;
0409   // }
0410   // else if (tower_id == 16)
0411   // {
0412   //   itwr = 20;
0413   // }
0414   // else if (tower_id == 18)
0415   // {
0416   //   itwr = 21;
0417   // }
0418   // else if (tower_id == 20)
0419   // {
0420   //   itwr = 22;
0421   // }
0422   // else if (tower_id == 22)
0423   // {
0424   //   itwr = 23;
0425   // }
0426   // else
0427   // {
0428   //   std::cout << PHWHERE << " cannot map tower " << tower_id << std::endl;
0429   //   gSystem->Exit(1);
0430   //   exit(1);
0431   // }
0432 }
0433 
0434 int PHG4IHCalDetector::map_layerid(const int layer_id)
0435 {
0436   int rowid = -1;
0437 
0438   if (layer_id < 188)
0439   {
0440     rowid = layer_id + 68;
0441   }
0442   else  // (layer_id >= 188)
0443   {
0444     rowid = layer_id - 188;
0445   }
0446   // shift the row index up by 4
0447   rowid += 4;
0448   if (rowid > 255)
0449   {
0450     rowid -= 256;
0451   }
0452 
0453   if (rowid > 255 || rowid < 0)
0454   {
0455     std::cout << PHWHERE << " row id out of range: " << rowid << std::endl;
0456     gSystem->Exit(1);
0457   }
0458   return rowid;
0459 }
0460 
0461 // This is dulplicated code, we can get rid of it when we have the code to make towergeom for real data reco.
0462 void PHG4IHCalDetector::AddGeometryNode()
0463 {
0464   PHNodeIterator iter(topNode());
0465   PHCompositeNode *runNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
0466   if (!runNode)
0467   {
0468     std::cout << PHWHERE << "Run Node missing, exiting." << std::endl;
0469     gSystem->Exit(1);
0470     exit(1);
0471   }
0472   PHNodeIterator runIter(runNode);
0473   PHCompositeNode *RunDetNode = dynamic_cast<PHCompositeNode *>(runIter.findFirst("PHCompositeNode", m_SuperDetector));
0474   if (!RunDetNode)
0475   {
0476     RunDetNode = new PHCompositeNode(m_SuperDetector);
0477     runNode->addNode(RunDetNode);
0478   }
0479   m_TowerGeomNodeName = "TOWERGEOM_" + m_SuperDetector;
0480   m_RawTowerGeom = findNode::getClass<RawTowerGeomContainer>(topNode(), m_TowerGeomNodeName);
0481   if (!m_RawTowerGeom)
0482   {
0483     m_RawTowerGeom = new RawTowerGeomContainer_Cylinderv1(RawTowerDefs::convert_name_to_caloid(m_SuperDetector));
0484     PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(m_RawTowerGeom, m_TowerGeomNodeName, "PHObject");
0485     RunDetNode->addNode(newNode);
0486   }
0487   double innerrad = m_Params->get_double_param(PHG4HcalDefs::innerrad);
0488   double thickness = m_Params->get_double_param(PHG4HcalDefs::outerrad) - innerrad;
0489   m_RawTowerGeom->set_radius(innerrad);
0490   m_RawTowerGeom->set_thickness(thickness);
0491   m_RawTowerGeom->set_phibins(m_Params->get_int_param(PHG4HcalDefs::n_towers));
0492   m_RawTowerGeom->set_etabins(m_Params->get_int_param("etabins"));
0493   double geom_ref_radius = innerrad + thickness / 2.;
0494   double phistart = m_Params->get_double_param("phistart");
0495   if (!std::isfinite(phistart))
0496   {
0497     std::cout << PHWHERE << " phistart is not finite: " << phistart
0498               << ", exiting now (this will crash anyway)" << std::endl;
0499     gSystem->Exit(1);
0500   }
0501   for (int i = 0; i < m_Params->get_int_param(PHG4HcalDefs::n_towers); i++)
0502   {
0503     double phiend = phistart + 2. * M_PI / m_Params->get_int_param(PHG4HcalDefs::n_towers);
0504     std::pair<double, double> range = std::make_pair(phiend, phistart);
0505     phistart = phiend;
0506     int tempi = i + 1;
0507     if (tempi >= m_Params->get_int_param(PHG4HcalDefs::n_towers))
0508     {
0509       tempi -= m_Params->get_int_param(PHG4HcalDefs::n_towers);
0510     }
0511     m_RawTowerGeom->set_phibounds(tempi, range);
0512   }
0513   double etalowbound = -m_Params->get_double_param("scinti_eta_coverage_neg");
0514   for (int i = 0; i < m_Params->get_int_param("etabins"); i++)
0515   {
0516     // double etahibound = etalowbound + 2.2 / get_int_param("etabins");
0517     double etahibound = etalowbound +
0518                         (m_Params->get_double_param("scinti_eta_coverage_neg") + m_Params->get_double_param("scinti_eta_coverage_pos")) / m_Params->get_int_param("etabins");
0519     std::pair<double, double> range = std::make_pair(etalowbound, etahibound);
0520     m_RawTowerGeom->set_etabounds(i, range);
0521     etalowbound = etahibound;
0522   }
0523   for (int iphi = 0; iphi < m_RawTowerGeom->get_phibins(); iphi++)
0524   {
0525     for (int ieta = 0; ieta < m_RawTowerGeom->get_etabins(); ieta++)
0526     {
0527       const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::convert_name_to_caloid(m_SuperDetector), ieta, iphi);
0528 
0529       const double x(geom_ref_radius * std::cos(m_RawTowerGeom->get_phicenter(iphi)));
0530       const double y(geom_ref_radius * std::sin(m_RawTowerGeom->get_phicenter(iphi)));
0531       const double z(geom_ref_radius / std::tan(PHG4Utils::get_theta(m_RawTowerGeom->get_etacenter(ieta))));
0532 
0533       RawTowerGeom *tg = m_RawTowerGeom->get_tower_geometry(key);
0534       if (tg)
0535       {
0536         if (Verbosity() > 0)
0537         {
0538           std::cout << "IHCalDetector::InitRun - Tower geometry " << key << " already exists" << std::endl;
0539         }
0540 
0541         if (std::fabs(tg->get_center_x() - x) > 1e-4)
0542         {
0543           std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing x = " << tg->get_center_x() << " and expected x = " << x
0544                     << std::endl;
0545 
0546           return;
0547         }
0548         if (std::fabs(tg->get_center_y() - y) > 1e-4)
0549         {
0550           std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing y = " << tg->get_center_y() << " and expected y = " << y
0551                     << std::endl;
0552           return;
0553         }
0554         if (std::fabs(tg->get_center_z() - z) > 1e-4)
0555         {
0556           std::cout << "IHCalDetector::InitRun - Fatal Error - duplicated Tower geometry " << key << " with existing z= " << tg->get_center_z() << " and expected z = " << z
0557                     << std::endl;
0558           return;
0559         }
0560       }
0561       else
0562       {
0563         if (Verbosity() > 0)
0564         {
0565           std::cout << "IHCalDetector::InitRun - building tower geometry " << key << "" << std::endl;
0566         }
0567 
0568         tg = new RawTowerGeomv1(key);
0569 
0570         tg->set_center_x(x);
0571         tg->set_center_y(y);
0572         tg->set_center_z(z);
0573         m_RawTowerGeom->add_tower_geometry(tg);
0574       }
0575     }
0576   }
0577   if (Verbosity() > 0)
0578   {
0579     m_RawTowerGeom->identify();
0580   }
0581 }