Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:18:17

0001 #include "PHG4TpcEndCapDetector.h"
0002 
0003 #include "PHG4TpcEndCapDisplayAction.h"
0004 
0005 #include <phparameter/PHParameters.h>
0006 
0007 #include <g4main/PHG4Detector.h>
0008 #include <g4main/PHG4DisplayAction.h>  // for PHG4DisplayAction
0009 #include <g4main/PHG4Subsystem.h>
0010 
0011 #include <TSystem.h>
0012 
0013 #include <Geant4/G4AssemblyVolume.hh>
0014 #include <Geant4/G4Box.hh>
0015 #include <Geant4/G4ExtrudedSolid.hh>
0016 #include <Geant4/G4LogicalVolume.hh>
0017 #include <Geant4/G4Material.hh>
0018 #include <Geant4/G4RotationMatrix.hh>
0019 #include <Geant4/G4String.hh>
0020 #include <Geant4/G4SystemOfUnits.hh>
0021 #include <Geant4/G4ThreeVector.hh>
0022 #include <Geant4/G4Transform3D.hh>
0023 #include <Geant4/G4Tubs.hh>
0024 #include <Geant4/G4TwoVector.hh>
0025 #include <Geant4/G4Types.hh>  // for G4double
0026 #include <Geant4/G4VPhysicalVolume.hh>
0027 
0028 #include <CLHEP/Vector/RotationZ.h>
0029 
0030 #pragma GCC diagnostic push
0031 #pragma GCC diagnostic ignored "-Wshadow"
0032 #include <boost/format.hpp>
0033 #pragma GCC diagnostic pop
0034 
0035 #include <algorithm>  // for max, copy
0036 #include <cassert>
0037 #include <cmath>
0038 #include <cstdlib>  // for exit
0039 #include <iostream>
0040 
0041 class G4VSolid;
0042 class PHCompositeNode;
0043 
0044 //____________________________________________________________________________..
0045 PHG4TpcEndCapDetector::PHG4TpcEndCapDetector(PHG4Subsystem *subsys,
0046                                              PHCompositeNode *Node,
0047                                              PHParameters *parameters,
0048                                              const std::string &dnam)
0049   : PHG4Detector(subsys, Node, dnam)
0050   , m_Params(parameters)
0051   , m_DisplayAction(dynamic_cast<PHG4TpcEndCapDisplayAction *>(subsys->GetDisplayAction()))
0052 
0053 {
0054   assert(subsys->GetDisplayAction());
0055   assert(m_DisplayAction);
0056   Verbosity(m_Params->get_int_param("construction_verbosity"));
0057 }
0058 
0059 PHG4TpcEndCapDetector::~PHG4TpcEndCapDetector()
0060 {
0061   if (m_EndCapAssembly)
0062   {
0063     if (Verbosity())
0064     {
0065       std::cout << __PRETTY_FUNCTION__ << " delete m_EndCapAssembly" << std::endl;
0066     }
0067 
0068     delete m_EndCapAssembly;
0069   }
0070 }
0071 
0072 //_______________________________________________________________
0073 int PHG4TpcEndCapDetector::IsInDetector(G4VPhysicalVolume *volume) const
0074 {
0075   G4LogicalVolume *logvol = volume->GetLogicalVolume();
0076   std::set<G4LogicalVolume *>::const_iterator iter = m_LogicalVolumesSet.find(logvol);
0077   if (iter != m_LogicalVolumesSet.end())
0078   {
0079     return 1;
0080   }
0081   return 0;
0082 }
0083 
0084 //_______________________________________________________________
0085 void PHG4TpcEndCapDetector::ConstructMe(G4LogicalVolume *logicWorld)
0086 {
0087   assert(m_DisplayAction);
0088 
0089   assert(m_EndCapAssembly == nullptr);
0090   m_EndCapAssembly = ConstructEndCapAssembly();
0091   assert(m_EndCapAssembly);
0092 
0093   G4TranslateZ3D g4vec_front_z(m_Params->get_double_param("envelop_front_surface_z") * cm);
0094 
0095   G4RotateY3D rotm_otherside(180 * deg);
0096 
0097   G4ThreeVector g4vec_center(m_Params->get_double_param("place_x") * cm,
0098                              m_Params->get_double_param("place_y") * cm,
0099                              m_Params->get_double_param("place_z") * cm);
0100   G4RotationMatrix rotm_center;
0101   rotm_center.rotateX(m_Params->get_double_param("rot_x") * deg);
0102   rotm_center.rotateY(m_Params->get_double_param("rot_y") * deg);
0103   rotm_center.rotateZ(m_Params->get_double_param("rot_z") * deg);
0104   G4Transform3D transform_center(rotm_center, g4vec_center);
0105 
0106   int i = 0;
0107   //  G4Transform3D transform_side1 = g4vec_front_z * transform_center;
0108   G4Transform3D transform_side1 = transform_center * g4vec_front_z;
0109   m_EndCapAssembly->MakeImprint(logicWorld, transform_side1, i++, OverlapCheck());
0110   // the other side
0111   G4Transform3D transform_side2 = transform_center * rotm_otherside * g4vec_front_z;
0112   m_EndCapAssembly->MakeImprint(logicWorld, transform_side2, i++, OverlapCheck());
0113 
0114   return;
0115 }
0116 
0117 G4AssemblyVolume *PHG4TpcEndCapDetector::ConstructEndCapAssembly()
0118 {
0119   G4AssemblyVolume *assemblyvol = new G4AssemblyVolume();
0120   G4double starting_z(0);
0121 
0122   // Internal HBD structure
0123   // From doi:10.1016/j.nima.2011.04.015
0124   // Component Material X0 (cm) Thickness (cm) Area (%) Rad. Length (%)
0125   //  Mesh SS 1.67 0.003 11.5 0.021  <- not used for GEMs trackers
0126   //  AddLayer("Mesh", "Steel",
0127   //          0.003 * cm, false, 11.5);
0128 
0129   //  //  GEM frames FR4 17.1 0.15x4 6.5 0.228 <- not used for GEMs trackers
0130   //  AddLayer("Frame0", "G10",
0131   //          0.15 * cm, false, 6.5);
0132 
0133   std::vector<double> thickness;
0134   std::vector<std::string> material;
0135   material.emplace_back("G4_Cu");
0136   thickness.push_back(0.0005 * 2. * cm);
0137   material.emplace_back("G4_KAPTON");
0138   thickness.push_back(0.005 * cm);
0139   material.emplace_back("sPHENIX_TPC_Gas");  // proper gas name, but should be pulled from params to match TpcSubsystem?
0140   thickness.push_back(0.2 * cm);
0141   G4Material *temp = GetDetectorMaterial("GEMeffective", false);
0142   if (temp == nullptr)
0143   {
0144     CreateCompositeMaterial("GEMeffective", material, thickness);  // see new function below
0145   }
0146   double totalThickness = 0;
0147   for (double thicknes : thickness)
0148   {
0149     totalThickness += thicknes;
0150   }
0151 
0152   const int n_GEM_layers = m_Params->get_int_param("n_GEM_layers");
0153 
0154   // instead of building this layer-by-layer, we build a single block corresponding to all the gems that were previously handled in this fashion:
0155   totalThickness *= n_GEM_layers;
0156   AddLayer(assemblyvol, starting_z, G4String("GEMAllParts"), "GEMeffective", totalThickness, 64);  // note this slightly undercounts the gas because the gas fill should be 100%, and slightly mispositions the inner edge of the material because the way it is made <100% in AddLayer is by making it thinner than nominally requested but centering it in the region it would have occupied.
0157 
0158   // 16 layer readout plane by TTM
0159   // https://indico.bnl.gov/event/8307/contributions/36744/attachments/27646/42337/R3-Review.pptx
0160   const int n_PCB_layers(16);
0161   // 35 um / layer Cu
0162   AddLayer(assemblyvol, starting_z, G4String("PCBCu"), "G4_Cu", 0.0035 * cm * n_PCB_layers, 80);
0163   // 7 mil / layer board
0164   AddLayer(assemblyvol, starting_z, "PCBBase", "FR4", 0.00254 * cm * 7 * n_PCB_layers, 100);
0165 
0166   ConstructWagonWheel(assemblyvol, starting_z);
0167   ConstructElectronics(assemblyvol, starting_z);
0168 
0169   return assemblyvol;
0170 }
0171 
0172 void PHG4TpcEndCapDetector::CreateCompositeMaterial(
0173     const std::string &compositeName,
0174     std::vector<std::string> materialName,
0175     const std::vector<double> &thickness)
0176 {
0177   // takes in a list of material names known to Geant already, and thicknesses, and creates a new material called compositeName.
0178 
0179   // check that desired material name doesn't already exist
0180   G4Material *tempmat = GetDetectorMaterial(compositeName, false);
0181 
0182   if (tempmat != nullptr)
0183   {
0184     std::cout << __PRETTY_FUNCTION__ << " Fatal Error: composite material " << compositeName << " already exists" << std::endl;
0185     assert(!tempmat);
0186   }
0187 
0188   // check that both arrays have the same depth
0189   assert(materialName.size() == thickness.size());
0190 
0191   // sum up the areal density and total thickness so we can divvy it out
0192   double totalArealDensity = 0, totalThickness = 0;
0193   for (std::vector<double>::size_type i = 0; i < thickness.size(); i++)
0194   {
0195     tempmat = GetDetectorMaterial(materialName[i]);
0196     if (tempmat == nullptr)
0197     {
0198       std::cout << __PRETTY_FUNCTION__ << " Fatal Error: component material " << materialName[i] << " does not exist." << std::endl;
0199       gSystem->Exit(1);
0200       exit(1);
0201     }
0202     totalArealDensity += tempmat->GetDensity() * thickness[i];
0203     totalThickness += thickness[i];
0204   }
0205 
0206   // register a new material with the average density of the whole:
0207   double compositeDensity = totalArealDensity / totalThickness;
0208   G4Material *composite = new G4Material(compositeName, compositeDensity, thickness.size());
0209 
0210   // now calculate the fraction due to each material, and register those
0211   for (std::vector<double>::size_type i = 0; i < thickness.size(); i++)
0212   {
0213     tempmat = GetDetectorMaterial(materialName[i]);  // don't need to check this, since we did in the previous loop.
0214     composite->AddMaterial(tempmat, thickness[i] * tempmat->GetDensity() / totalArealDensity);
0215   }
0216 
0217   // how to register our finished material?
0218   return;
0219 }
0220 
0221 void PHG4TpcEndCapDetector ::AddLayer(  //
0222     G4AssemblyVolume *assemblyvol,
0223     G4double &z_start,
0224     const std::string &_name,      //! name base for this layer
0225     const std::string &_material,  //! material name in G4
0226     G4double _depth,               //! depth in G4 units
0227     double _percentage_filled      //! percentage filled//
0228 )
0229 {
0230   z_start += _depth / 2.;
0231   G4ThreeVector g4vec(0, 0, z_start);
0232   z_start += _depth / 2.;
0233 
0234   std::string name_base = boost::str(boost::format("%1%_Layer_%2%") % GetName() % _name);
0235 
0236   G4VSolid *solid_layer = new G4Tubs(
0237       name_base,
0238       m_Params->get_double_param("envelop_r_min") * cm,
0239       m_Params->get_double_param("envelop_r_max") * cm,
0240       _depth * _percentage_filled / 100. / 2.,
0241       0, CLHEP::twopi);
0242 
0243   auto material = GetDetectorMaterial(_material);
0244   if (material == nullptr)
0245   {
0246     std::cout << __PRETTY_FUNCTION__ << " Fatal Error: missing material " << _material << std::endl;
0247     assert(material);
0248   }
0249 
0250   G4LogicalVolume *logical_layer = new G4LogicalVolume(solid_layer, material, name_base);
0251   m_LogicalVolumesSet.insert(logical_layer);
0252 
0253   assemblyvol->AddPlacedVolume(logical_layer, g4vec, nullptr);
0254 
0255   assert(m_DisplayAction);
0256   m_DisplayAction->AddVolume(logical_layer, _material);
0257 
0258   return;
0259 }
0260 
0261 void PHG4TpcEndCapDetector::ConstructWagonWheel(G4AssemblyVolume *assmeblyvol,
0262                                                 G4double &z_start)  // careful z_start is modified and being used later
0263 {
0264   const int n_sectors = m_Params->get_int_param("n_sectors");
0265   assert(n_sectors >= 1);
0266   const int n_radial_modules = m_Params->get_int_param("n_radial_modules");
0267   assert(n_radial_modules >= 1);
0268 
0269   const std::string material_name(m_Params->get_string_param("wagon_wheel_material"));
0270   auto material = GetDetectorMaterial(material_name);
0271   if (material == nullptr)
0272   {
0273     std::cout << __PRETTY_FUNCTION__ << " Fatal Error: missing material " << m_Params->get_string_param("wagon_wheel_material") << std::endl;
0274     assert(material);
0275   }
0276   const G4double wagon_wheel_sector_phi_offset = m_Params->get_double_param("wagon_wheel_sector_phi_offset_degree") * degree;
0277 
0278   ///////////////////////////////////////////////
0279   // wagon_wheel_front_frame ring
0280   ///////////////////////////////////////////////
0281   if (Verbosity())
0282   {
0283     std::cout << __PRETTY_FUNCTION__ << " - wagon_wheel_front_frame z_start = " << z_start << std::endl;
0284   }
0285 
0286   const G4double wagon_wheel_front_frame_thickness = m_Params->get_double_param("wagon_wheel_front_frame_thickness") * cm;
0287   const G4double wagon_wheel_front_frame_spoke_width = m_Params->get_double_param("wagon_wheel_front_frame_spoke_width") * cm;
0288 
0289   z_start += wagon_wheel_front_frame_thickness / 2.;
0290   G4ThreeVector g4vec_wagon_wheel_front_frame(0, 0, z_start);
0291   z_start += wagon_wheel_front_frame_thickness / 2.;
0292 
0293   const G4double wagon_wheel_front_frame_R_inner = m_Params->get_double_param("wagon_wheel_front_frame_R_inner") * cm;
0294   const G4double wagon_wheel_front_frame_R_outer = m_Params->get_double_param("wagon_wheel_front_frame_R_outer") * cm;
0295 
0296   for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
0297   {
0298     G4double Rin = wagon_wheel_front_frame_R_inner;
0299     G4double Rout = wagon_wheel_front_frame_R_outer;
0300 
0301     if (ring_id > 0)
0302     {
0303       Rin = m_Params->get_double_param(
0304                 boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_outer") % (ring_id))) *
0305             cm;
0306     }
0307     if (ring_id < n_radial_modules)
0308     {
0309       Rout = m_Params->get_double_param(
0310                  boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_inner") % (ring_id + 1))) *
0311              cm;
0312     }
0313 
0314     std::string name_base = boost::str(boost::format("%1%_%2%_Ring%3%") % GetName() % "wagon_wheel_front_frame" % ring_id);
0315 
0316     G4VSolid *solid_wagon_wheel_front_frame = new G4Tubs(
0317         name_base,
0318         Rin,
0319         Rout,
0320         wagon_wheel_front_frame_thickness / 2.,
0321         0, CLHEP::twopi);
0322 
0323     G4LogicalVolume *log_solid_wagon_wheel_front_frame = new G4LogicalVolume(solid_wagon_wheel_front_frame, material, name_base);
0324     m_LogicalVolumesSet.insert(log_solid_wagon_wheel_front_frame);
0325 
0326     assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel_front_frame,
0327                                  g4vec_wagon_wheel_front_frame,
0328                                  nullptr);
0329     assert(m_DisplayAction);
0330     m_DisplayAction->AddVolume(log_solid_wagon_wheel_front_frame, "wagon_wheel");
0331 
0332   }  // for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
0333 
0334   ///////////////////////////////////////////////
0335   // wagon_wheel_front_frame spoke
0336   ///////////////////////////////////////////////
0337   for (int ring_id = 1; ring_id <= n_radial_modules; ++ring_id)
0338   {
0339     G4double Rout =
0340         m_Params->get_double_param(
0341             boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_outer") % (ring_id))) *
0342         cm;
0343     G4double Rin =
0344         m_Params->get_double_param(
0345             boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_inner") % (ring_id))) *
0346         cm;
0347 
0348     const G4double reduced_height = sqrt(Rout * Rout - wagon_wheel_front_frame_spoke_width / 2 * wagon_wheel_front_frame_spoke_width / 2);
0349 
0350     std::vector<G4TwoVector> vertexes;
0351     vertexes.emplace_back(-wagon_wheel_front_frame_spoke_width / 2, Rin);
0352     vertexes.emplace_back(+wagon_wheel_front_frame_spoke_width / 2, Rin);
0353     vertexes.emplace_back(+wagon_wheel_front_frame_spoke_width / 2, reduced_height);
0354     vertexes.emplace_back(-wagon_wheel_front_frame_spoke_width / 2, reduced_height);
0355 
0356     G4TwoVector zero(0, 0);
0357 
0358     std::string name_base_spoke = boost::str(boost::format("%1%_%2%_Ring%3%_spoke") % GetName() % "wagon_wheel_front_frame" % ring_id);
0359 
0360     G4VSolid *solid_wagon_wheel_front_frame_spoke = new G4ExtrudedSolid(name_base_spoke,
0361                                                                         vertexes,
0362                                                                         wagon_wheel_front_frame_thickness / 2.,
0363                                                                         zero, 1.0,
0364                                                                         zero, 1.0);
0365     G4LogicalVolume *log_solid_wagon_wheel_front_frame_spoke = new G4LogicalVolume(solid_wagon_wheel_front_frame_spoke, material, name_base_spoke);
0366     m_LogicalVolumesSet.insert(log_solid_wagon_wheel_front_frame_spoke);
0367 
0368     const G4double sector_dphi = CLHEP::twopi / n_sectors;
0369     for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0370     {
0371       G4Transform3D trans_spoke(CLHEP::HepRotationZ(wagon_wheel_sector_phi_offset + sector_dphi * sector_id), g4vec_wagon_wheel_front_frame);
0372 
0373       assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel_front_frame_spoke,
0374                                    trans_spoke);
0375       assert(m_DisplayAction);
0376       m_DisplayAction->AddVolume(log_solid_wagon_wheel_front_frame_spoke, "wagon_wheel");
0377 
0378     }  //     for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0379 
0380   }  //  for (int ring_id = 0; ring_id < n_radial_modules; ++ring_id)
0381 
0382   ///////////////////////////////////////////////
0383   // wagon_wheel_rim_outer
0384   ///////////////////////////////////////////////
0385   if (Verbosity())
0386   {
0387     std::cout << __PRETTY_FUNCTION__ << " - wagon_wheel_rim_outer z_start = " << z_start << std::endl;
0388   }
0389 
0390   {
0391     const G4double wagon_wheel_rim_outer_Rin = m_Params->get_double_param("wagon_wheel_rim_outer_Rin") * cm;
0392     const G4double wagon_wheel_rim_outer_Rout = m_Params->get_double_param("wagon_wheel_rim_outer_Rout") * cm;
0393     const G4double wagon_wheel_rim_outer_thickness = m_Params->get_double_param("wagon_wheel_rim_outer_thickness") * cm;
0394 
0395     G4ThreeVector g4vec_wagon_wheel_rim_outer(0, 0, z_start + wagon_wheel_rim_outer_thickness / 2.);
0396 
0397     std::string name_base = boost::str(boost::format("%1%_wagon_wheel_rim_outer") % GetName());
0398 
0399     G4VSolid *solid_wagon_wheel = new G4Tubs(
0400         name_base,
0401         wagon_wheel_rim_outer_Rin,
0402         wagon_wheel_rim_outer_Rout,
0403         wagon_wheel_rim_outer_thickness / 2.,
0404         0, CLHEP::twopi);
0405 
0406     G4LogicalVolume *log_solid_wagon_wheel = new G4LogicalVolume(solid_wagon_wheel, material, name_base);
0407     m_LogicalVolumesSet.insert(log_solid_wagon_wheel);
0408 
0409     assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel,
0410                                  g4vec_wagon_wheel_rim_outer,
0411                                  nullptr);
0412     assert(m_DisplayAction);
0413     m_DisplayAction->AddVolume(log_solid_wagon_wheel, "wagon_wheel");
0414 
0415   }  // wagon_wheel_rim_outer
0416 
0417   ///////////////////////////////////////////////
0418   // wagon_wheel_spoke
0419   ///////////////////////////////////////////////
0420   {
0421     const G4double wagon_wheel_spoke_width = m_Params->get_double_param("wagon_wheel_spoke_width") * cm;
0422     const G4double wagon_wheel_spoke_height_inner = m_Params->get_double_param("wagon_wheel_spoke_height_inner") * cm;
0423     const G4double wagon_wheel_spoke_height_outer = m_Params->get_double_param("wagon_wheel_spoke_height_outer") * cm;
0424     const G4double wagon_wheel_spoke_R_inner = m_Params->get_double_param("wagon_wheel_spoke_R_inner") * cm;
0425     const G4double wagon_wheel_spoke_R_outer = m_Params->get_double_param("wagon_wheel_spoke_R_outer") * cm;
0426 
0427     std::string name_base = boost::str(boost::format("%1%_wagon_wheel_spoke") % GetName());
0428 
0429     std::vector<G4TwoVector> vertexes;
0430     vertexes.emplace_back(0, wagon_wheel_spoke_R_inner);
0431     vertexes.emplace_back(0, wagon_wheel_spoke_R_outer);
0432     vertexes.emplace_back(wagon_wheel_spoke_height_outer, wagon_wheel_spoke_R_outer);
0433     vertexes.emplace_back(wagon_wheel_spoke_height_inner, wagon_wheel_spoke_R_inner);
0434     G4TwoVector zero(0, 0);
0435 
0436     G4VSolid *solid_wagon_wheel_spoke = new G4ExtrudedSolid(name_base,
0437                                                             vertexes,
0438                                                             wagon_wheel_spoke_width / 2.,
0439                                                             zero, 1.0,
0440                                                             zero, 1.0);
0441     G4LogicalVolume *log_solid_wagon_wheel_spoke = new G4LogicalVolume(solid_wagon_wheel_spoke, material, name_base);
0442     m_LogicalVolumesSet.insert(log_solid_wagon_wheel_spoke);
0443 
0444     G4ThreeVector g4vec_wagon_wheel_spoke(0, 0, z_start + wagon_wheel_spoke_width / 2.);
0445 
0446     const G4double sector_dphi = CLHEP::twopi / n_sectors;
0447     for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0448     {
0449       G4RotateY3D rotm_spoke(-90 * deg);
0450       G4Transform3D trans_spoke(CLHEP::HepRotationZ(wagon_wheel_sector_phi_offset + sector_dphi * sector_id),
0451                                 g4vec_wagon_wheel_spoke);
0452       G4Transform3D trans_spoke_final = trans_spoke * rotm_spoke;
0453 
0454       assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel_spoke,
0455                                    trans_spoke_final);
0456       assert(m_DisplayAction);
0457       m_DisplayAction->AddVolume(log_solid_wagon_wheel_spoke, "wagon_wheel");
0458 
0459     }  //     for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0460 
0461   }  // wagon_wheel_rim_outer
0462 }
0463 
0464 void PHG4TpcEndCapDetector::ConstructElectronics(G4AssemblyVolume *assmeblyvol,
0465                                                  G4double z_start)
0466 {
0467   const int n_sectors = m_Params->get_int_param("n_sectors");
0468   assert(n_sectors >= 1);
0469 
0470   const G4double sector_dphi = CLHEP::twopi / n_sectors;
0471 
0472   const int n_radial_modules = m_Params->get_int_param("n_radial_modules");
0473   assert(n_radial_modules >= 1);
0474   const G4double wagon_wheel_sector_phi_offset = m_Params->get_double_param("wagon_wheel_sector_phi_offset_degree") * degree;
0475   const G4double wagon_wheel_spoke_width = m_Params->get_double_param("wagon_wheel_spoke_width") * cm;
0476 
0477   ///////////////////////////////////////////////
0478   // electronics_cooling_block_material ring
0479   ///////////////////////////////////////////////
0480   const G4double electronics_cooling_block_thickness = m_Params->get_double_param("electronics_cooling_block_thickness") * cm;
0481   if (electronics_cooling_block_thickness > 0)
0482   {
0483     if (Verbosity())
0484     {
0485       std::cout << __PRETTY_FUNCTION__ << " - electronics_cooling_block_material z_start = " << z_start << std::endl;
0486     }
0487 
0488     const std::string electronics_cooling_block_material_name(m_Params->get_string_param("electronics_cooling_block_material"));
0489     auto material = GetDetectorMaterial(electronics_cooling_block_material_name);
0490     if (material == nullptr)
0491     {
0492       std::cout << __PRETTY_FUNCTION__ << " Fatal Error: missing material " << m_Params->get_string_param("electronics_cooling_block_material_name") << std::endl;
0493       gSystem->Exit(1);
0494       exit(1);
0495     }
0496 
0497     G4ThreeVector g4vec_electronics_cooling_block(0, 0, z_start + electronics_cooling_block_thickness / 2.);
0498 
0499     const G4double electronics_cooling_block_R_inner = m_Params->get_double_param("electronics_cooling_block_R_inner") * cm;
0500     const G4double electronics_cooling_block_R_outer = m_Params->get_double_param("electronics_cooling_block_R_outer") * cm;
0501 
0502     for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
0503     {
0504       G4double Rin = electronics_cooling_block_R_inner;
0505       G4double Rout = electronics_cooling_block_R_outer;
0506 
0507       if (ring_id > 0)
0508       {
0509         Rin = m_Params->get_double_param(
0510                   boost::str(boost::format("electronics_cooling_block_R_R%1%_outer") % (ring_id))) *
0511               cm;
0512       }
0513       if (ring_id < n_radial_modules)
0514       {
0515         Rout = m_Params->get_double_param(
0516                    boost::str(boost::format("electronics_cooling_block_R_R%1%_inner") % (ring_id + 1))) *
0517                cm;
0518       }
0519 
0520       std::string name_base = boost::str(boost::format("%1%_%2%_Ring%3%") % GetName() % "electronics_cooling_block" % ring_id);
0521 
0522       const G4double spoke_phi = atan2(wagon_wheel_spoke_width, Rin);
0523 
0524       //      const G4double sector_dphi = CLHEP::twopi / n_sectors;
0525 
0526       G4VSolid *solid = new G4Tubs(
0527           name_base,
0528           Rin,
0529           Rout,
0530           electronics_cooling_block_thickness / 2.,
0531           spoke_phi, sector_dphi - 2 * spoke_phi);
0532 
0533       if (Verbosity())
0534       {
0535         std::cout << __PRETTY_FUNCTION__ << " - electronics_cooling_block " << name_base
0536                   << " Rin = " << Rin << " Rout = " << Rout
0537                   << " phi = " << spoke_phi << " to " << (sector_dphi - spoke_phi) << std::endl;
0538       }
0539 
0540       //
0541       G4LogicalVolume *log_vol = new G4LogicalVolume(solid, material, name_base);
0542       m_LogicalVolumesSet.insert(log_vol);
0543 
0544       for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0545       {
0546         G4Transform3D trans(
0547             CLHEP::HepRotationZ(wagon_wheel_sector_phi_offset + sector_dphi * sector_id),
0548             g4vec_electronics_cooling_block);
0549         //
0550         assmeblyvol->AddPlacedVolume(log_vol, trans);
0551         assert(m_DisplayAction);
0552         m_DisplayAction->AddVolume(log_vol, "cooling_block");
0553 
0554       }  //     for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0555     }    // for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
0556   }      // electronics_cooling_block_material  if (electronics_cooling_block_thickness>0)
0557 
0558   ///////////////////////////////////////////////
0559   // electronics
0560   ///////////////////////////////////////////////
0561   const G4double electronics_FEE_depth = m_Params->get_double_param("electronics_FEE_depth") * cm;
0562   const G4double electronics_FEE_Cu_thickness = m_Params->get_double_param("electronics_FEE_Cu_thickness") * cm;
0563   const G4double electronics_FEE_PCB_thickness = m_Params->get_double_param("electronics_FEE_PCB_thickness") * cm;
0564   const G4double electronics_FEE_Al_thickness = m_Params->get_double_param("electronics_FEE_Al_thickness") * cm;
0565   const G4double electronics_assemly_thickness = electronics_FEE_Cu_thickness + electronics_FEE_PCB_thickness + electronics_FEE_Al_thickness;
0566 
0567   if (m_Params->get_int_param("electronics_enable") != 0)
0568   {
0569     for (int ring_id = 1; ring_id <= n_radial_modules; ++ring_id)
0570     {
0571       const G4double Rout = m_Params->get_double_param(
0572                                 boost::str(boost::format("electronics_cooling_block_R_R%1%_outer") % (ring_id))) *
0573                                 cm -
0574                             electronics_assemly_thickness;
0575       const G4double Rin = m_Params->get_double_param(
0576                                boost::str(boost::format("electronics_cooling_block_R_R%1%_inner") % (ring_id))) *
0577                                cm +
0578                            electronics_assemly_thickness;
0579       const int nFEE = m_Params->get_int_param(boost::str(boost::format("electronics_nFEE_R%1%") % (ring_id)));
0580 
0581       if (nFEE <= 0)
0582       {
0583         std::cout << __PRETTY_FUNCTION__ << " warning : ignore FEE construction for module " << ring_id << " as "
0584                   << boost::str(boost::format("electronics_nFEE_R2%1%") % (ring_id)) << " = " << nFEE << std::endl;
0585 
0586         continue;
0587       }
0588 
0589       G4AssemblyVolume *assmeblyvol_electronics = new G4AssemblyVolume();
0590       G4double starting_electronics(0);
0591       std::string name_base = boost::str(boost::format("%1%_%2%_Ring%3%") % GetName() % "electronics" % ring_id);
0592 
0593       if (Verbosity())
0594       {
0595         std::cout << __PRETTY_FUNCTION__ << " - electronics G4_PCB z_start = " << z_start
0596                   << " starting_electronics = " << starting_electronics << std::endl;
0597       }
0598       starting_electronics -= electronics_FEE_PCB_thickness / 2.;
0599       G4ThreeVector g4vec_electronics;
0600       g4vec_electronics.set(starting_electronics, (Rout + Rin) * .5, z_start + electronics_FEE_depth / 2.);
0601       starting_electronics -= electronics_FEE_PCB_thickness / 2.;
0602       G4VSolid *solid_electronics = nullptr;
0603       solid_electronics = new G4Box(name_base + "_PCB",
0604                                     electronics_FEE_PCB_thickness / 2.,
0605                                     (Rout - Rin) / 2.,
0606                                     electronics_FEE_depth / 2.);
0607 
0608       G4LogicalVolume *log_electronics = nullptr;
0609       log_electronics = new G4LogicalVolume(solid_electronics, GetDetectorMaterial("FR4"), name_base + "_PCB");
0610       m_LogicalVolumesSet.insert(log_electronics);
0611 
0612       assmeblyvol_electronics->AddPlacedVolume(log_electronics,
0613                                                g4vec_electronics, nullptr);
0614       m_DisplayAction->AddVolume(log_electronics, "FR4");
0615       if (Verbosity())
0616       {
0617         std::cout << __PRETTY_FUNCTION__ << " - electronics G4_Cu z_start = " << z_start
0618                   << " starting_electronics = " << starting_electronics << std::endl;
0619       }
0620       starting_electronics -= electronics_FEE_Cu_thickness / 2.;
0621       g4vec_electronics.set(starting_electronics, (Rout + Rin) * .5, z_start + electronics_FEE_depth / 2.);
0622       starting_electronics -= electronics_FEE_Cu_thickness / 2.;
0623 
0624       solid_electronics = new G4Box(name_base + "_Cu",
0625                                     electronics_FEE_Cu_thickness / 2.,
0626                                     (Rout - Rin) / 2.,
0627                                     electronics_FEE_depth / 2.);
0628 
0629       log_electronics = new G4LogicalVolume(solid_electronics, GetDetectorMaterial("G4_Cu"), name_base + "_Cu");
0630       m_LogicalVolumesSet.insert(log_electronics);
0631 
0632       assmeblyvol_electronics->AddPlacedVolume(log_electronics,
0633                                                g4vec_electronics, nullptr);
0634       m_DisplayAction->AddVolume(log_electronics, "Cu");
0635       if (Verbosity())
0636       {
0637         std::cout << __PRETTY_FUNCTION__ << " - electronics Al z_start = " << z_start
0638                   << " starting_electronics = " << starting_electronics << std::endl;
0639       }
0640       starting_electronics -= electronics_FEE_Al_thickness / 2.;
0641       g4vec_electronics.set(starting_electronics, (Rout + Rin) * .5, z_start + electronics_FEE_depth / 2.);
0642       starting_electronics -= electronics_FEE_Al_thickness / 2.;
0643 
0644       solid_electronics = new G4Box(name_base + "_Al",
0645                                     electronics_FEE_Al_thickness / 2.,
0646                                     (Rout - Rin) / 2.,
0647                                     electronics_FEE_depth / 2.);
0648 
0649       log_electronics = new G4LogicalVolume(solid_electronics,
0650                                             GetDetectorMaterial("G4_Al"),
0651                                             name_base + "_Al");
0652       m_LogicalVolumesSet.insert(log_electronics);
0653 
0654       assmeblyvol_electronics->AddPlacedVolume(log_electronics,
0655                                                g4vec_electronics, nullptr);
0656       m_DisplayAction->AddVolume(log_electronics, "cooling_block");
0657 
0658       for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0659       {
0660         const G4double sector_phi_shift = wagon_wheel_sector_phi_offset + sector_dphi * sector_id;
0661         const G4double spoke_phi = atan2(wagon_wheel_spoke_width, Rin);
0662         const G4double board_dphi = (sector_dphi - 2 * spoke_phi) / (nFEE + 1);
0663         const G4double board_phi_start = sector_phi_shift + spoke_phi + board_dphi;
0664 
0665         for (int board_id = 0; board_id < nFEE; ++board_id)
0666         {
0667           G4Transform3D trans_electronic = G4RotateZ3D(board_phi_start + board_dphi * board_id);
0668 
0669           assmeblyvol->AddPlacedAssembly(assmeblyvol_electronics, trans_electronic);
0670         }
0671       }  //     for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
0672 
0673     }  //  for (int ring_id = 0; ring_id < n_radial_modules; ++ring_id)
0674   }
0675 }
0676 
0677 //_______________________________________________________________
0678 void PHG4TpcEndCapDetector::Print(const std::string &what) const
0679 {
0680   std::cout << "PHG4TpcEndCap Detector:" << std::endl;
0681   if (what == "ALL" || what == "VOLUME")
0682   {
0683     std::cout << "Version 0.1" << std::endl;
0684     std::cout << "Parameters:" << std::endl;
0685     m_Params->Print();
0686   }
0687   return;
0688 }