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