EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4TpcEndCapDetector.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4TpcEndCapDetector.cc
2 
4 
5 #include <phparameter/PHParameters.h>
6 
7 #include <g4main/PHG4Detector.h>
8 #include <g4main/PHG4DisplayAction.h> // for PHG4DisplayAction
9 #include <g4main/PHG4Subsystem.h>
10 
11 #include <TSystem.h>
12 
13 #include <Geant4/G4AssemblyVolume.hh>
14 #include <Geant4/G4Box.hh>
15 #include <Geant4/G4ExtrudedSolid.hh>
16 #include <Geant4/G4LogicalVolume.hh>
17 #include <Geant4/G4Material.hh>
18 #include <Geant4/G4RotationMatrix.hh>
19 #include <Geant4/G4String.hh>
20 #include <Geant4/G4SystemOfUnits.hh>
21 #include <Geant4/G4ThreeVector.hh>
22 #include <Geant4/G4Transform3D.hh>
23 #include <Geant4/G4Tubs.hh>
24 #include <Geant4/G4TwoVector.hh>
25 #include <Geant4/G4Types.hh> // for G4double
26 #include <Geant4/G4VPhysicalVolume.hh>
27 
28 #include <CLHEP/Vector/RotationZ.h>
29 
30 #include <boost/format.hpp>
31 
32 #include <algorithm> // for max, copy
33 #include <cassert>
34 #include <cmath>
35 #include <cstdlib> // for exit
36 #include <iostream>
37 
38 class G4VSolid;
39 class PHCompositeNode;
40 
41 //____________________________________________________________________________..
43  PHCompositeNode *Node,
45  const std::string &dnam)
46  : PHG4Detector(subsys, Node, dnam)
47  , m_Params(parameters)
48  , m_DisplayAction(dynamic_cast<PHG4TpcEndCapDisplayAction *>(subsys->GetDisplayAction()))
49 
50 {
51  assert(subsys->GetDisplayAction());
52  assert(m_DisplayAction);
53  Verbosity(m_Params->get_int_param("construction_verbosity"));
54 }
55 
57 {
58  if (m_EndCapAssembly)
59  {
60  if (Verbosity())
61  {
62  std::cout << __PRETTY_FUNCTION__ << " delete m_EndCapAssembly" << std::endl;
63  }
64 
65  delete m_EndCapAssembly;
66  }
67 }
68 
69 //_______________________________________________________________
70 int PHG4TpcEndCapDetector::IsInDetector(G4VPhysicalVolume *volume) const
71 {
72  G4LogicalVolume *logvol = volume->GetLogicalVolume();
73  std::set<G4LogicalVolume *>::const_iterator iter = m_LogicalVolumesSet.find(logvol);
74  if (iter != m_LogicalVolumesSet.end())
75  {
76  return 1;
77  }
78  return 0;
79 }
80 
81 //_______________________________________________________________
82 void PHG4TpcEndCapDetector::ConstructMe(G4LogicalVolume *logicWorld)
83 {
84  assert(m_DisplayAction);
85 
86  assert(m_EndCapAssembly == nullptr);
88  assert(m_EndCapAssembly);
89 
90  G4TranslateZ3D g4vec_front_z(m_Params->get_double_param("envelop_front_surface_z") * cm);
91 
92  G4RotateY3D rotm_otherside(180 * deg);
93 
94  G4ThreeVector g4vec_center(m_Params->get_double_param("place_x") * cm,
95  m_Params->get_double_param("place_y") * cm,
96  m_Params->get_double_param("place_z") * cm);
97  G4RotationMatrix rotm_center;
98  rotm_center.rotateX(m_Params->get_double_param("rot_x") * deg);
99  rotm_center.rotateY(m_Params->get_double_param("rot_y") * deg);
100  rotm_center.rotateZ(m_Params->get_double_param("rot_z") * deg);
101  G4Transform3D transform_center(rotm_center, g4vec_center);
102 
103  int i = 0;
104  // G4Transform3D transform_side1 = g4vec_front_z * transform_center;
105  G4Transform3D transform_side1 = transform_center * g4vec_front_z;
106  m_EndCapAssembly->MakeImprint(logicWorld, transform_side1, i++, OverlapCheck());
107  // the other side
108  G4Transform3D transform_side2 = transform_center * rotm_otherside * g4vec_front_z;
109  m_EndCapAssembly->MakeImprint(logicWorld, transform_side2, i++, OverlapCheck());
110 
111  return;
112 }
113 
115 {
116  G4AssemblyVolume *assemblyvol = new G4AssemblyVolume();
117  G4double starting_z(0);
118 
119  // Internal HBD structure
120  // From doi:10.1016/j.nima.2011.04.015
121  // Component Material X0 (cm) Thickness (cm) Area (%) Rad. Length (%)
122  // Mesh SS 1.67 0.003 11.5 0.021 <- not used for GEMs trackers
123  // AddLayer("Mesh", "Steel",
124  // 0.003 * cm, false, 11.5);
125 
126  // // GEM frames FR4 17.1 0.15x4 6.5 0.228 <- not used for GEMs trackers
127  // AddLayer("Frame0", "G10",
128  // 0.15 * cm, false, 6.5);
129 
130  std::vector<double> thickness;
131  std::vector<std::string> material;
132  material.push_back("G4_Cu");
133  thickness.push_back(0.0005 * 2. * cm);
134  material.push_back("G4_KAPTON");
135  thickness.push_back(0.005 * cm);
136  material.push_back("sPHENIX_TPC_Gas"); // proper gas name, but should be pulled from params to match TpcSubsystem?
137  thickness.push_back(0.2 * cm);
138  G4Material *temp = GetDetectorMaterial("GEMeffective", false);
139  if (temp == nullptr)
140  {
141  CreateCompositeMaterial("GEMeffective", material, thickness); //see new function below
142  }
143  double totalThickness = 0;
144  for (std::vector<double>::size_type i = 0; i < thickness.size(); i++)
145  {
146  totalThickness += thickness[i];
147  }
148 
149  const int n_GEM_layers = m_Params->get_int_param("n_GEM_layers");
150 
151  //instead of building this layer-by-layer, we build a single block corresponding to all the gems that were previously handled in this fashion:
152  totalThickness *= n_GEM_layers;
153  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.
154 
155  // 16 layer readout plane by TTM
156  // https://indico.bnl.gov/event/8307/contributions/36744/attachments/27646/42337/R3-Review.pptx
157  const int n_PCB_layers(16);
158  // 35 um / layer Cu
159  AddLayer(assemblyvol, starting_z, G4String("PCBCu"), "G4_Cu", 0.0035 * cm * n_PCB_layers, 80);
160  // 7 mil / layer board
161  AddLayer(assemblyvol, starting_z, "PCBBase", "FR4", 0.00254 * cm * 7 * n_PCB_layers, 100);
162 
163  ConstructWagonWheel(assemblyvol, starting_z);
164  ConstructElectronics(assemblyvol, starting_z);
165 
166  return assemblyvol;
167 }
168 
170  std::string compositeName,
171  std::vector<std::string> materialName,
172  std::vector<double> thickness)
173 {
174  //takes in a list of material names known to Geant already, and thicknesses, and creates a new material called compositeName.
175 
176  //check that desired material name doesn't already exist
177  //note that this throws a warning.
178  std::cout << __PRETTY_FUNCTION__ << " NOTICE: Checking if material " << compositeName << " exists. This will return a warning if it doesn't, but that is okay." << std::endl;
179  G4Material *tempmat = GetDetectorMaterial(compositeName, false);
180 
181  if (tempmat != nullptr)
182  {
183  std::cout << __PRETTY_FUNCTION__ << " Fatal Error: composite material " << compositeName << " already exists" << std::endl;
184  assert(!tempmat);
185  }
186 
187  //check that both arrays have the same depth
188  assert(materialName.size() == thickness.size());
189 
190  //sum up the areal density and total thickness so we can divvy it out
191  double totalArealDensity = 0, totalThickness = 0;
192  for (std::vector<double>::size_type i = 0; i < thickness.size(); i++)
193  {
194  tempmat = GetDetectorMaterial(materialName[i]);
195  if (tempmat == nullptr)
196  {
197  std::cout << __PRETTY_FUNCTION__ << " Fatal Error: component material " << materialName[i] << " does not exist." << std::endl;
198  gSystem->Exit(1);
199  exit(1);
200  }
201  totalArealDensity += tempmat->GetDensity() * thickness[i];
202  totalThickness += thickness[i];
203  }
204 
205  //register a new material with the average density of the whole:
206  double compositeDensity = totalArealDensity / totalThickness;
207  G4Material *composite = new G4Material(compositeName, compositeDensity, thickness.size());
208 
209  //now calculate the fraction due to each material, and register those
210  for (std::vector<double>::size_type i = 0; i < thickness.size(); i++)
211  {
212  tempmat = GetDetectorMaterial(materialName[i]); //don't need to check this, since we did in the previous loop.
213  composite->AddMaterial(tempmat, thickness[i] * tempmat->GetDensity() / totalArealDensity);
214  }
215 
216  //how to register our finished material?
217  return;
218 }
219 
221  G4AssemblyVolume *assemblyvol,
222  G4double &z_start,
223  std::string _name,
224  std::string _material,
225  G4double _depth,
226  double _percentage_filled
227 )
228 {
229  z_start += _depth / 2.;
230  G4ThreeVector g4vec(0, 0, z_start);
231  z_start += _depth / 2.;
232 
233  std::string name_base = boost::str(boost::format("%1%_Layer_%2%") % GetName() % _name);
234 
235  G4VSolid *solid_layer = new G4Tubs(
236  name_base,
237  m_Params->get_double_param("envelop_r_min") * cm,
238  m_Params->get_double_param("envelop_r_max") * cm,
239  _depth * _percentage_filled / 100. / 2.,
240  0, CLHEP::twopi);
241 
242  auto material = GetDetectorMaterial(_material);
243  if (material == nullptr)
244  {
245  std::cout << __PRETTY_FUNCTION__ << " Fatal Error: missing material " << _material << std::endl;
246  assert(material);
247  }
248 
249  G4LogicalVolume *logical_layer = new G4LogicalVolume(solid_layer, material, name_base);
250  m_LogicalVolumesSet.insert(logical_layer);
251 
252  assemblyvol->AddPlacedVolume(logical_layer, g4vec, nullptr);
253 
254  assert(m_DisplayAction);
255  m_DisplayAction->AddVolume(logical_layer, _material);
256 
257  return;
258 }
259 
260 void PHG4TpcEndCapDetector::ConstructWagonWheel(G4AssemblyVolume *assmeblyvol,
261  G4double &z_start)
262 {
263  const int n_sectors = m_Params->get_int_param("n_sectors");
264  assert(n_sectors >= 1);
265  const int n_radial_modules = m_Params->get_int_param("n_radial_modules");
266  assert(n_radial_modules >= 1);
267 
268  const std::string material_name(m_Params->get_string_param("wagon_wheel_material"));
269  auto material = GetDetectorMaterial(material_name);
270  if (material == nullptr)
271  {
272  std::cout << __PRETTY_FUNCTION__ << " Fatal Error: missing material " << m_Params->get_string_param("wagon_wheel_material") << std::endl;
273  assert(material);
274  }
275  const G4double wagon_wheel_sector_phi_offset = m_Params->get_double_param("wagon_wheel_sector_phi_offset_degree") * degree;
276 
278  // wagon_wheel_front_frame ring
280  if (Verbosity())
281  {
282  std::cout << __PRETTY_FUNCTION__ << " - wagon_wheel_front_frame z_start = " << z_start << std::endl;
283  }
284 
285  const G4double wagon_wheel_front_frame_thickness = m_Params->get_double_param("wagon_wheel_front_frame_thickness") * cm;
286  const G4double wagon_wheel_front_frame_spoke_width = m_Params->get_double_param("wagon_wheel_front_frame_spoke_width") * cm;
287 
288  z_start += wagon_wheel_front_frame_thickness / 2.;
289  G4ThreeVector g4vec_wagon_wheel_front_frame(0, 0, z_start);
290  z_start += wagon_wheel_front_frame_thickness / 2.;
291 
292  const G4double wagon_wheel_front_frame_R_inner = m_Params->get_double_param("wagon_wheel_front_frame_R_inner") * cm;
293  const G4double wagon_wheel_front_frame_R_outer = m_Params->get_double_param("wagon_wheel_front_frame_R_outer") * cm;
294 
295  for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
296  {
297  G4double Rin = wagon_wheel_front_frame_R_inner;
298  G4double Rout = wagon_wheel_front_frame_R_outer;
299 
300  if (ring_id > 0)
301  {
302  Rin = m_Params->get_double_param(
303  boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_outer") % (ring_id))) *
304  cm;
305  }
306  if (ring_id < n_radial_modules)
307  {
308  Rout = m_Params->get_double_param(
309  boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_inner") % (ring_id + 1))) *
310  cm;
311  }
312 
313  std::string name_base = boost::str(boost::format("%1%_%2%_Ring%3%") % GetName() % "wagon_wheel_front_frame" % ring_id);
314 
315  G4VSolid *solid_wagon_wheel_front_frame = new G4Tubs(
316  name_base,
317  Rin,
318  Rout,
319  wagon_wheel_front_frame_thickness / 2.,
320  0, CLHEP::twopi);
321 
322  G4LogicalVolume *log_solid_wagon_wheel_front_frame = new G4LogicalVolume(solid_wagon_wheel_front_frame, material, name_base);
323  m_LogicalVolumesSet.insert(log_solid_wagon_wheel_front_frame);
324 
325  assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel_front_frame,
326  g4vec_wagon_wheel_front_frame,
327  nullptr);
328  assert(m_DisplayAction);
329  m_DisplayAction->AddVolume(log_solid_wagon_wheel_front_frame, "wagon_wheel");
330 
331  } // for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
332 
334  // wagon_wheel_front_frame spoke
336  for (int ring_id = 1; ring_id <= n_radial_modules; ++ring_id)
337  {
338  G4double Rout =
340  boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_outer") % (ring_id))) *
341  cm;
342  G4double Rin =
344  boost::str(boost::format("wagon_wheel_front_frame_R_R%1%_inner") % (ring_id))) *
345  cm;
346 
347  const G4double reduced_height = sqrt(Rout * Rout - wagon_wheel_front_frame_spoke_width / 2 * wagon_wheel_front_frame_spoke_width / 2);
348 
349  std::vector<G4TwoVector> vertexes;
350  vertexes.push_back(G4TwoVector(-wagon_wheel_front_frame_spoke_width / 2, Rin));
351  vertexes.push_back(G4TwoVector(+wagon_wheel_front_frame_spoke_width / 2, Rin));
352  vertexes.push_back(G4TwoVector(+wagon_wheel_front_frame_spoke_width / 2, reduced_height));
353  vertexes.push_back(G4TwoVector(-wagon_wheel_front_frame_spoke_width / 2, reduced_height));
354 
355  G4TwoVector zero(0, 0);
356 
357  std::string name_base_spoke = boost::str(boost::format("%1%_%2%_Ring%3%_spoke") % GetName() % "wagon_wheel_front_frame" % ring_id);
358 
359  G4VSolid *solid_wagon_wheel_front_frame_spoke = new G4ExtrudedSolid(name_base_spoke,
360  vertexes,
361  wagon_wheel_front_frame_thickness / 2.,
362  zero, 1.0,
363  zero, 1.0);
364  G4LogicalVolume *log_solid_wagon_wheel_front_frame_spoke = new G4LogicalVolume(solid_wagon_wheel_front_frame_spoke, material, name_base_spoke);
365  m_LogicalVolumesSet.insert(log_solid_wagon_wheel_front_frame_spoke);
366 
367  const G4double sector_dphi = CLHEP::twopi / n_sectors;
368  for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
369  {
370  G4Transform3D trans_spoke(CLHEP::HepRotationZ(wagon_wheel_sector_phi_offset + sector_dphi * sector_id), g4vec_wagon_wheel_front_frame);
371 
372  assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel_front_frame_spoke,
373  trans_spoke);
374  assert(m_DisplayAction);
375  m_DisplayAction->AddVolume(log_solid_wagon_wheel_front_frame_spoke, "wagon_wheel");
376 
377  } // for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
378 
379  } // for (int ring_id = 0; ring_id < n_radial_modules; ++ring_id)
380 
382  // wagon_wheel_rim_outer
384  if (Verbosity())
385  {
386  std::cout << __PRETTY_FUNCTION__ << " - wagon_wheel_rim_outer z_start = " << z_start << std::endl;
387  }
388 
389  {
390  const G4double wagon_wheel_rim_outer_Rin = m_Params->get_double_param("wagon_wheel_rim_outer_Rin") * cm;
391  const G4double wagon_wheel_rim_outer_Rout = m_Params->get_double_param("wagon_wheel_rim_outer_Rout") * cm;
392  const G4double wagon_wheel_rim_outer_thickness = m_Params->get_double_param("wagon_wheel_rim_outer_thickness") * cm;
393 
394  G4ThreeVector g4vec_wagon_wheel_rim_outer(0, 0, z_start + wagon_wheel_rim_outer_thickness / 2.);
395 
396  std::string name_base = boost::str(boost::format("%1%_wagon_wheel_rim_outer") % GetName());
397 
398  G4VSolid *solid_wagon_wheel = new G4Tubs(
399  name_base,
400  wagon_wheel_rim_outer_Rin,
401  wagon_wheel_rim_outer_Rout,
402  wagon_wheel_rim_outer_thickness / 2.,
403  0, CLHEP::twopi);
404 
405  G4LogicalVolume *log_solid_wagon_wheel = new G4LogicalVolume(solid_wagon_wheel, material, name_base);
406  m_LogicalVolumesSet.insert(log_solid_wagon_wheel);
407 
408  assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel,
409  g4vec_wagon_wheel_rim_outer,
410  nullptr);
411  assert(m_DisplayAction);
412  m_DisplayAction->AddVolume(log_solid_wagon_wheel, "wagon_wheel");
413 
414  } // wagon_wheel_rim_outer
415 
417  // wagon_wheel_spoke
419  {
420  const G4double wagon_wheel_spoke_width = m_Params->get_double_param("wagon_wheel_spoke_width") * cm;
421  const G4double wagon_wheel_spoke_height_inner = m_Params->get_double_param("wagon_wheel_spoke_height_inner") * cm;
422  const G4double wagon_wheel_spoke_height_outer = m_Params->get_double_param("wagon_wheel_spoke_height_outer") * cm;
423  const G4double wagon_wheel_spoke_R_inner = m_Params->get_double_param("wagon_wheel_spoke_R_inner") * cm;
424  const G4double wagon_wheel_spoke_R_outer = m_Params->get_double_param("wagon_wheel_spoke_R_outer") * cm;
425 
426  std::string name_base = boost::str(boost::format("%1%_wagon_wheel_spoke") % GetName());
427 
428  std::vector<G4TwoVector> vertexes;
429  vertexes.push_back(G4TwoVector(0, wagon_wheel_spoke_R_inner));
430  vertexes.push_back(G4TwoVector(0, wagon_wheel_spoke_R_outer));
431  vertexes.push_back(G4TwoVector(wagon_wheel_spoke_height_outer, wagon_wheel_spoke_R_outer));
432  vertexes.push_back(G4TwoVector(wagon_wheel_spoke_height_inner, wagon_wheel_spoke_R_inner));
433  G4TwoVector zero(0, 0);
434 
435  G4VSolid *solid_wagon_wheel_spoke = new G4ExtrudedSolid(name_base,
436  vertexes,
437  wagon_wheel_spoke_width / 2.,
438  zero, 1.0,
439  zero, 1.0);
440  G4LogicalVolume *log_solid_wagon_wheel_spoke = new G4LogicalVolume(solid_wagon_wheel_spoke, material, name_base);
441  m_LogicalVolumesSet.insert(log_solid_wagon_wheel_spoke);
442 
443  G4ThreeVector g4vec_wagon_wheel_spoke(0, 0, z_start + wagon_wheel_spoke_width / 2.);
444 
445  const G4double sector_dphi = CLHEP::twopi / n_sectors;
446  for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
447  {
448  G4RotateY3D rotm_spoke(-90 * deg);
449  G4Transform3D trans_spoke(CLHEP::HepRotationZ(wagon_wheel_sector_phi_offset + sector_dphi * sector_id),
450  g4vec_wagon_wheel_spoke);
451  G4Transform3D trans_spoke_final = trans_spoke * rotm_spoke;
452 
453  assmeblyvol->AddPlacedVolume(log_solid_wagon_wheel_spoke,
454  trans_spoke_final);
455  assert(m_DisplayAction);
456  m_DisplayAction->AddVolume(log_solid_wagon_wheel_spoke, "wagon_wheel");
457 
458  } // for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
459 
460  } // wagon_wheel_rim_outer
461 }
462 
463 void PHG4TpcEndCapDetector::ConstructElectronics(G4AssemblyVolume *assmeblyvol,
464  G4double &z_start)
465 {
466  const int n_sectors = m_Params->get_int_param("n_sectors");
467  assert(n_sectors >= 1);
468 
469  const G4double sector_dphi = CLHEP::twopi / n_sectors;
470 
471  const int n_radial_modules = m_Params->get_int_param("n_radial_modules");
472  assert(n_radial_modules >= 1);
473  const G4double wagon_wheel_sector_phi_offset = m_Params->get_double_param("wagon_wheel_sector_phi_offset_degree") * degree;
474  const G4double wagon_wheel_spoke_width = m_Params->get_double_param("wagon_wheel_spoke_width") * cm;
475 
477  // electronics_cooling_block_material ring
479  const G4double electronics_cooling_block_thickness = m_Params->get_double_param("electronics_cooling_block_thickness") * cm;
480  if (electronics_cooling_block_thickness > 0)
481  {
482  if (Verbosity())
483  {
484  std::cout << __PRETTY_FUNCTION__ << " - electronics_cooling_block_material z_start = " << z_start << std::endl;
485  }
486 
487  const std::string electronics_cooling_block_material_name(m_Params->get_string_param("electronics_cooling_block_material"));
488  auto material = GetDetectorMaterial(electronics_cooling_block_material_name);
489  if (material == nullptr)
490  {
491  std::cout << __PRETTY_FUNCTION__ << " Fatal Error: missing material " << m_Params->get_string_param("electronics_cooling_block_material_name") << std::endl;
492  gSystem->Exit(1);
493  exit(1);
494  }
495 
496  G4ThreeVector g4vec_electronics_cooling_block(0, 0, z_start + electronics_cooling_block_thickness / 2.);
497 
498  const G4double electronics_cooling_block_R_inner = m_Params->get_double_param("electronics_cooling_block_R_inner") * cm;
499  const G4double electronics_cooling_block_R_outer = m_Params->get_double_param("electronics_cooling_block_R_outer") * cm;
500 
501  for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
502  {
503  G4double Rin = electronics_cooling_block_R_inner;
504  G4double Rout = electronics_cooling_block_R_outer;
505 
506  if (ring_id > 0)
507  {
508  Rin = m_Params->get_double_param(
509  boost::str(boost::format("electronics_cooling_block_R_R%1%_outer") % (ring_id))) *
510  cm;
511  }
512  if (ring_id < n_radial_modules)
513  {
514  Rout = m_Params->get_double_param(
515  boost::str(boost::format("electronics_cooling_block_R_R%1%_inner") % (ring_id + 1))) *
516  cm;
517  }
518 
519  std::string name_base = boost::str(boost::format("%1%_%2%_Ring%3%") % GetName() % "electronics_cooling_block" % ring_id);
520 
521  const G4double spoke_phi = atan2(wagon_wheel_spoke_width, Rin);
522 
523  // const G4double sector_dphi = CLHEP::twopi / n_sectors;
524 
525  G4VSolid *solid = new G4Tubs(
526  name_base,
527  Rin,
528  Rout,
529  electronics_cooling_block_thickness / 2.,
530  spoke_phi, sector_dphi - 2 * spoke_phi);
531 
532  if (Verbosity())
533  {
534  std::cout << __PRETTY_FUNCTION__ << " - electronics_cooling_block " << name_base
535  << " Rin = " << Rin << " Rout = " << Rout
536  << " phi = " << spoke_phi << " to " << (sector_dphi - spoke_phi) << std::endl;
537  }
538 
539  //
540  G4LogicalVolume *log_vol = new G4LogicalVolume(solid, material, name_base);
541  m_LogicalVolumesSet.insert(log_vol);
542 
543  for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
544  {
545  G4Transform3D trans(
546  CLHEP::HepRotationZ(wagon_wheel_sector_phi_offset + sector_dphi * sector_id),
547  g4vec_electronics_cooling_block);
548  //
549  assmeblyvol->AddPlacedVolume(log_vol, trans);
550  assert(m_DisplayAction);
551  m_DisplayAction->AddVolume(log_vol, "cooling_block");
552 
553  } // for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
554  } // for (int ring_id = 0; ring_id <= n_radial_modules; ++ring_id)
555  } // electronics_cooling_block_material if (electronics_cooling_block_thickness>0)
556 
558  // electronics
560  const G4double electronics_FEE_depth = m_Params->get_double_param("electronics_FEE_depth") * cm;
561  const G4double electronics_FEE_Cu_thickness = m_Params->get_double_param("electronics_FEE_Cu_thickness") * cm;
562  const G4double electronics_FEE_PCB_thickness = m_Params->get_double_param("electronics_FEE_PCB_thickness") * cm;
563  const G4double electronics_FEE_Al_thickness = m_Params->get_double_param("electronics_FEE_Al_thickness") * cm;
564  const G4double electronics_assemly_thickness = electronics_FEE_Cu_thickness + electronics_FEE_PCB_thickness + electronics_FEE_Al_thickness;
565 
566  if (m_Params->get_int_param("electronics_enable") != 0)
567  {
568  for (int ring_id = 1; ring_id <= n_radial_modules; ++ring_id)
569  {
570  const G4double Rout = m_Params->get_double_param(
571  boost::str(boost::format("electronics_cooling_block_R_R%1%_outer") % (ring_id))) *
572  cm -
573  electronics_assemly_thickness;
574  const G4double Rin = m_Params->get_double_param(
575  boost::str(boost::format("electronics_cooling_block_R_R%1%_inner") % (ring_id))) *
576  cm +
577  electronics_assemly_thickness;
578  const int nFEE = m_Params->get_int_param(boost::str(boost::format("electronics_nFEE_R%1%") % (ring_id)));
579 
580  if (nFEE <= 0)
581  {
582  std::cout << __PRETTY_FUNCTION__ << " warning : ignore FEE construction for module " << ring_id << " as "
583  << boost::str(boost::format("electronics_nFEE_R2%1%") % (ring_id)) << " = " << nFEE << std::endl;
584 
585  continue;
586  }
587 
588  G4AssemblyVolume *assmeblyvol_electronics = new G4AssemblyVolume();
589  G4double starting_electronics(0);
590  std::string name_base = boost::str(boost::format("%1%_%2%_Ring%3%") % GetName() % "electronics" % ring_id);
591 
592  if (Verbosity())
593  {
594  std::cout << __PRETTY_FUNCTION__ << " - electronics G4_PCB z_start = " << z_start
595  << " starting_electronics = " << starting_electronics << std::endl;
596  }
597  starting_electronics -= electronics_FEE_PCB_thickness / 2.;
598  G4ThreeVector g4vec_electronics;
599  g4vec_electronics.set(starting_electronics, (Rout + Rin) * .5, z_start + electronics_FEE_depth / 2.);
600  starting_electronics -= electronics_FEE_PCB_thickness / 2.;
601  G4VSolid *solid_electronics = nullptr;
602  solid_electronics = new G4Box(name_base + "_PCB",
603  electronics_FEE_PCB_thickness / 2.,
604  (Rout - Rin) / 2.,
605  electronics_FEE_depth / 2.);
606 
607  G4LogicalVolume *log_electronics = nullptr;
608  log_electronics = new G4LogicalVolume(solid_electronics, GetDetectorMaterial("FR4"), name_base + "_PCB");
609  m_LogicalVolumesSet.insert(log_electronics);
610 
611  assmeblyvol_electronics->AddPlacedVolume(log_electronics,
612  g4vec_electronics, nullptr);
613  m_DisplayAction->AddVolume(log_electronics, "FR4");
614  if (Verbosity())
615  {
616  std::cout << __PRETTY_FUNCTION__ << " - electronics G4_Cu z_start = " << z_start
617  << " starting_electronics = " << starting_electronics << std::endl;
618  }
619  starting_electronics -= electronics_FEE_Cu_thickness / 2.;
620  g4vec_electronics.set(starting_electronics, (Rout + Rin) * .5, z_start + electronics_FEE_depth / 2.);
621  starting_electronics -= electronics_FEE_Cu_thickness / 2.;
622 
623  solid_electronics = new G4Box(name_base + "_Cu",
624  electronics_FEE_Cu_thickness / 2.,
625  (Rout - Rin) / 2.,
626  electronics_FEE_depth / 2.);
627 
628  log_electronics = new G4LogicalVolume(solid_electronics, GetDetectorMaterial("G4_Cu"), name_base + "_Cu");
629  m_LogicalVolumesSet.insert(log_electronics);
630 
631  assmeblyvol_electronics->AddPlacedVolume(log_electronics,
632  g4vec_electronics, nullptr);
633  m_DisplayAction->AddVolume(log_electronics, "Cu");
634  if (Verbosity())
635  {
636  std::cout << __PRETTY_FUNCTION__ << " - electronics Al z_start = " << z_start
637  << " starting_electronics = " << starting_electronics << std::endl;
638  }
639  starting_electronics -= electronics_FEE_Al_thickness / 2.;
640  g4vec_electronics.set(starting_electronics, (Rout + Rin) * .5, z_start + electronics_FEE_depth / 2.);
641  starting_electronics -= electronics_FEE_Al_thickness / 2.;
642 
643  solid_electronics = new G4Box(name_base + "_Al",
644  electronics_FEE_Al_thickness / 2.,
645  (Rout - Rin) / 2.,
646  electronics_FEE_depth / 2.);
647 
648  log_electronics = new G4LogicalVolume(solid_electronics,
649  GetDetectorMaterial("G4_Al"),
650  name_base + "_Al");
651  m_LogicalVolumesSet.insert(log_electronics);
652 
653  assmeblyvol_electronics->AddPlacedVolume(log_electronics,
654  g4vec_electronics, nullptr);
655  m_DisplayAction->AddVolume(log_electronics, "cooling_block");
656 
657  for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
658  {
659  const G4double sector_phi_shift = wagon_wheel_sector_phi_offset + sector_dphi * sector_id;
660  const G4double spoke_phi = atan2(wagon_wheel_spoke_width, Rin);
661  const G4double board_dphi = (sector_dphi - 2 * spoke_phi) / (nFEE + 1);
662  const G4double board_phi_start = sector_phi_shift + spoke_phi + board_dphi;
663 
664  for (int board_id = 0; board_id < nFEE; ++board_id)
665  {
666  G4Transform3D trans_electronic = G4RotateZ3D(board_phi_start + board_dphi * board_id);
667 
668  assmeblyvol->AddPlacedAssembly(assmeblyvol_electronics, trans_electronic);
669  }
670  } // for (int sector_id = 0; sector_id < n_sectors; ++sector_id)
671 
672  } // for (int ring_id = 0; ring_id < n_radial_modules; ++ring_id)
673  }
674 }
675 
676 //_______________________________________________________________
677 void PHG4TpcEndCapDetector::Print(const std::string &what) const
678 {
679  std::cout << "PHG4TpcEndCap Detector:" << std::endl;
680  if (what == "ALL" || what == "VOLUME")
681  {
682  std::cout << "Version 0.1" << std::endl;
683  std::cout << "Parameters:" << std::endl;
684  m_Params->Print();
685  }
686  return;
687 }