Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHG4TpcDetector.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHG4TpcDetector.cc
1 #include "PHG4TpcDetector.h"
2 #include "PHG4TpcDefs.h"
3 #include "PHG4TpcDisplayAction.h"
4 
8 
9 #include <g4main/PHG4Detector.h> // for PHG4Detector
10 #include <g4main/PHG4DisplayAction.h> // for PHG4DisplayAction
11 #include <g4main/PHG4Subsystem.h>
12 
13 #include <phparameter/PHParameters.h>
14 #include <phool/getClass.h>
15 #include <phool/PHCompositeNode.h>
16 #include <phool/PHIODataNode.h>
17 #include <phool/PHNodeIterator.h>
18 #include <phool/recoConsts.h>
19 
20 #include <TSystem.h>
21 
22 #include <Geant4/G4LogicalVolume.hh>
23 #include <Geant4/G4Material.hh>
24 #include <Geant4/G4PVPlacement.hh>
25 #include <Geant4/G4String.hh> // for G4String
26 #include <Geant4/G4SystemOfUnits.hh>
27 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
28 #include <Geant4/G4Tubs.hh>
29 #include <Geant4/G4UserLimits.hh>
30 #include <Geant4/G4VPhysicalVolume.hh> // for G4VPhysicalVolume
31 
32 #include <algorithm> // for max, copy
33 #include <cassert>
34 #include <cmath>
35 #include <cstdlib> // for exit
36 #include <iostream> // for basic_ostream::operator<<
37 #include <map> // for map
38 #include <sstream>
39 
40 class G4VSolid;
41 class PHCompositeNode;
42 
43 //_______________________________________________________________
45  : PHG4Detector(subsys, Node, dnam)
46  , m_DisplayAction(dynamic_cast<PHG4TpcDisplayAction *>(subsys->GetDisplayAction()))
47  , m_Params(parameters)
48  , m_ActiveFlag(m_Params->get_int_param("active"))
49  , m_AbsorberActiveFlag(m_Params->get_int_param("absorberactive"))
50  , m_InnerCageRadius(m_Params->get_double_param("gas_inner_radius") * cm - m_Params->get_double_param("cage_layer_9_thickness") * cm - m_Params->get_double_param("cage_layer_8_thickness") * cm - m_Params->get_double_param("cage_layer_7_thickness") * cm - m_Params->get_double_param("cage_layer_6_thickness") * cm - m_Params->get_double_param("cage_layer_5_thickness") * cm - m_Params->get_double_param("cage_layer_4_thickness") * cm - m_Params->get_double_param("cage_layer_3_thickness") * cm - m_Params->get_double_param("cage_layer_2_thickness") * cm - m_Params->get_double_param("cage_layer_1_thickness") * cm)
51  , m_OuterCageRadius(m_Params->get_double_param("gas_outer_radius") * cm + m_Params->get_double_param("cage_layer_9_thickness") * cm + m_Params->get_double_param("cage_layer_8_thickness") * cm + m_Params->get_double_param("cage_layer_7_thickness") * cm + m_Params->get_double_param("cage_layer_6_thickness") * cm + m_Params->get_double_param("cage_layer_5_thickness") * cm + m_Params->get_double_param("cage_layer_4_thickness") * cm + m_Params->get_double_param("cage_layer_3_thickness") * cm + m_Params->get_double_param("cage_layer_2_thickness") * cm + m_Params->get_double_param("cage_layer_1_thickness") * cm)
52 {
53 }
54 
55 //_______________________________________________________________
57 {
58  if (m_ActiveFlag)
59  {
60  if (m_ActiveVolumeSet.find(volume) != m_ActiveVolumeSet.end())
61  {
62  return 1;
63  }
64  }
66  {
67  if (m_AbsorberVolumeSet.find(volume) != m_AbsorberVolumeSet.end())
68  {
69  return -1;
70  }
71  }
72  return 0;
73 }
74 
75 //_______________________________________________________________
76 void PHG4TpcDetector::ConstructMe(G4LogicalVolume *logicWorld)
77 {
78  // create Tpc envelope
79  // tpc consists of (from inside to gas volume, outside is reversed up to now)
80  // 1st layer cu
81  // 2nd layer FR4
82  // 3rd layer HoneyComb
83  // 4th layer cu
84  // 5th layer FR4
85  // 6th layer Kapton
86  // 7th layer cu
87  // 8th layer Kapton
88  // 9th layer cu
89 
90  double steplimits = m_Params->get_double_param("steplimits") * cm;
91  if (std::isfinite(steplimits))
92  {
93  m_G4UserLimits = new G4UserLimits(steplimits);
94  }
95 
96  G4VSolid *tpc_envelope = new G4Tubs("tpc_envelope", m_InnerCageRadius, m_OuterCageRadius, m_Params->get_double_param("tpc_length") * cm / 2., 0., 2 * M_PI);
97 
99  G4LogicalVolume *tpc_envelope_logic = new G4LogicalVolume(tpc_envelope,
100  GetDetectorMaterial(rc->get_StringFlag("WorldMaterial")),
101  "tpc_envelope");
102  m_DisplayAction->AddVolume(tpc_envelope_logic, "TpcEnvelope");
103 
104  ConstructTpcExternalSupports(logicWorld);
105 
106  ConstructTpcCageVolume(tpc_envelope_logic);
107  ConstructTpcGasVolume(tpc_envelope_logic);
108 
109  new G4PVPlacement(0, 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),
110  tpc_envelope_logic, "tpc_envelope",
111  logicWorld, 0, false, OverlapCheck());
112 
113  // geometry node
115 
116 
117 }
118 
119 int PHG4TpcDetector::ConstructTpcGasVolume(G4LogicalVolume *tpc_envelope)
120 {
121  static std::map<int, std::string> tpcgasvolname =
122  {{PHG4TpcDefs::North, "tpc_gas_north"},
123  {PHG4TpcDefs::South, "tpc_gas_south"}};
124 
125  // Window / central membrane
126  double tpc_window_thickness = m_Params->get_double_param("window_thickness") * cm;
127  double tpc_half_length = (m_Params->get_double_param("tpc_length") * cm - tpc_window_thickness) / 2.;
128 
129  //'window' (modernly called central membrane only) material is ENIG, not Copper:
130  //thickness in this recipe are just a ratio. we set the usual thickness below.
131  std::vector<double> thickness;
132  std::vector<std::string> material;
133  material.push_back("G4_Ni");
134  thickness.push_back(.240 * cm);
135  material.push_back("G4_Au");
136  thickness.push_back(.008 * cm);
137  G4Material *temp = nullptr;
138  temp = GetDetectorMaterial("ENIG", false);
139  if (temp == nullptr)
140  {
141  CreateCompositeMaterial("ENIG", material, thickness); //see new function below
142  }
143 
144  G4VSolid *tpc_window = new G4Tubs("tpc_window", m_Params->get_double_param("gas_inner_radius") * cm, m_Params->get_double_param("gas_outer_radius") * cm, tpc_window_thickness / 2., 0., 2 * M_PI);
145  //we build our CM surface:
146  G4LogicalVolume *tpc_window_logic = new G4LogicalVolume(tpc_window,
147  GetDetectorMaterial("ENIG"),
148  "tpc_window");
149  //previously: GetDetectorMaterial(m_Params->get_string_param("window_surface1_material")),
150 
151  // G4VisAttributes *visatt = new G4VisAttributes();
152  // visatt->SetVisibility(true);
153  // visatt->SetForceSolid(true);
154  // visatt->SetColor(PHG4TPCColorDefs::tpc_cu_color);
155  // tpc_window_logic->SetVisAttributes(visatt);
156 
157  m_DisplayAction->AddVolume(tpc_window_logic, "TpcWindow");
158  G4VPhysicalVolume *tpc_window_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, 0),
159  tpc_window_logic, "tpc_window",
160  tpc_envelope, false, PHG4TpcDefs::Window, OverlapCheck());
161 
162  m_AbsorberVolumeSet.insert(tpc_window_phys);
163 
164  //now build the FR4 layer beneath that:
165  // Window / central membrane core
166  double tpc_window_surface1_thickness = m_Params->get_double_param("window_surface1_thickness") * cm;
167  double tpc_window_surface2_thickness = m_Params->get_double_param("window_surface2_thickness") * cm;
168  double tpc_window_surface2_core_thickness = tpc_window_thickness - 2 * tpc_window_surface1_thickness;
169  double tpc_window_core_thickness = tpc_window_surface2_core_thickness - 2 * (tpc_window_surface2_thickness);
170 
171  G4VSolid *tpc_window_surface2_core =
172  new G4Tubs("tpc_window_surface2_core", m_Params->get_double_param("gas_inner_radius") * cm, m_Params->get_double_param("gas_outer_radius") * cm,
173  tpc_window_surface2_core_thickness / 2., 0., 2 * M_PI);
174  G4LogicalVolume *tpc_window_surface2_core_logic = new G4LogicalVolume(tpc_window_surface2_core,
175  GetDetectorMaterial(m_Params->get_string_param("window_surface2_material")),
176  "tpc_window_surface2_core");
177 
178  m_DisplayAction->AddVolume(tpc_window_surface2_core_logic, "TpcWindow");
179  // visatt = new G4VisAttributes();
180  // visatt->SetVisibility(true);
181  // visatt->SetForceSolid(true);
182  // visatt->SetColor(PHG4TPCColorDefs::tpc_pcb_color);
183  // tpc_window_surface2_core_logic->SetVisAttributes(visatt);
184  G4VPhysicalVolume *tpc_window_surface2_core_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, 0),
185  tpc_window_surface2_core_logic, "tpc_window_surface2_core",
186  tpc_window_logic, false, PHG4TpcDefs::WindowCore, OverlapCheck());
187 
188  m_AbsorberVolumeSet.insert(tpc_window_surface2_core_phys);
189 
190  //and now the honeycomb core:
191  G4VSolid *tpc_window_core =
192  new G4Tubs("tpc_window", m_Params->get_double_param("gas_inner_radius") * cm, m_Params->get_double_param("gas_outer_radius") * cm,
193  tpc_window_core_thickness / 2., 0., 2 * M_PI);
194  G4LogicalVolume *tpc_window_core_logic = new G4LogicalVolume(tpc_window_core,
195  GetDetectorMaterial(m_Params->get_string_param("window_core_material")),
196  "tpc_window_core");
197 
198  m_DisplayAction->AddVolume(tpc_window_core_logic, "TpcHoneyComb");
199  G4VPhysicalVolume *tpc_window_core_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, 0),
200  tpc_window_core_logic, "tpc_window_core",
201  tpc_window_surface2_core_logic, false, PHG4TpcDefs::WindowCore, OverlapCheck());
202 
203  m_AbsorberVolumeSet.insert(tpc_window_core_phys);
204 
205  // Gas
206  G4VSolid *tpc_gas = new G4Tubs("tpc_gas", m_Params->get_double_param("gas_inner_radius") * cm, m_Params->get_double_param("gas_outer_radius") * cm, tpc_half_length / 2., 0., 2 * M_PI);
207 
208  G4LogicalVolume *tpc_gas_logic = new G4LogicalVolume(tpc_gas,
210  "tpc_gas");
211 
212  tpc_gas_logic->SetUserLimits(m_G4UserLimits);
213  m_DisplayAction->AddVolume(tpc_gas_logic, "TpcGas");
214  G4VPhysicalVolume *tpc_gas_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, (tpc_half_length + tpc_window_thickness) / 2.),
215  tpc_gas_logic, tpcgasvolname[PHG4TpcDefs::North],
216  tpc_envelope, false, PHG4TpcDefs::North, OverlapCheck());
217  std::cout << "north copy no: " << tpc_gas_phys->GetCopyNo() << std::endl;
218 
219  m_ActiveVolumeSet.insert(tpc_gas_phys);
220  tpc_gas_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, -(tpc_half_length + tpc_window_thickness) / 2.),
221  tpc_gas_logic, tpcgasvolname[PHG4TpcDefs::South],
222  tpc_envelope, false, PHG4TpcDefs::South, OverlapCheck());
223 
224  std::cout << "south copy no: " << tpc_gas_phys->GetCopyNo() << std::endl;
225  m_ActiveVolumeSet.insert(tpc_gas_phys);
226 
227 #if G4VERSION_NUMBER >= 1033
228  const G4RegionStore *theRegionStore = G4RegionStore::GetInstance();
229  G4Region *tpcregion = theRegionStore->GetRegion("REGION_TPCGAS");
230  tpc_gas_logic->SetRegion(tpcregion);
231  tpcregion->AddRootLogicalVolume(tpc_gas_logic);
232 #endif
233  return 0;
234 }
235 
236 int PHG4TpcDetector::ConstructTpcExternalSupports(G4LogicalVolume *logicWorld)
237 {
238  //note that these elements are outside the tpc logical volume!
239 
240  // Two two-inch diam. 304 Stainless Steel solid 'hanger beams' at 32.05" from beam center
241  // at +/- 41.39 degrees left and right of vertical
242  //stainless steel: 0.695 iron, 0.190 chromium, 0.095 nickel, 0.020 manganese.
243  //if we're being pedantic, that is. But store-bought stainless is probably okay.
244  // G4Material *StainlessSteel = new G4Material("StainlessSteel", density = 8.02*g/cm3, 5);
245  //StainlessSteel->AddMaterial(matman->FindOrBuildMaterial("G4_Si"), 0.01);
246  //StainlessSteel->AddMaterial(matman->FindOrBuildMaterial("G4_Mn"), 0.02);
247  //StainlessSteel->AddMaterial(matman->FindOrBuildMaterial("G4_Cr"), 0.19);
248  //StainlessSteel->AddMaterial(matman->FindOrBuildMaterial("G4_Ni"), 0.10);
249  //StainlessSteel->AddMaterial(matman->FindOrBuildMaterial("G4_Fe"), 0.68);
250  G4Material *stainlessSteel = GetDetectorMaterial("G4_STAINLESS-STEEL");
251  double inch = 2.54 * cm;
252  // double hangerAngle = 41.39 * M_PI / 180.;
253  // double hangerRadius = 32.05 * inch;
254  double hangerX = 21.193 *inch;
255  double hangerY = 24.246* inch;
256  double hangerDiameter = 2. * inch;
257  double extra_length = 0.941*inch;
258 
259 
260 
261 
262  G4VSolid *hangerSupport = new G4Tubs("tpc_hanger_support", 0, hangerDiameter / 2., (6*inch)+extra_length, 0., 2 * M_PI);
263  G4LogicalVolume *hangerSupportLogic = new G4LogicalVolume(hangerSupport,
264  stainlessSteel,
265  "tpc_hanger_support");
266 
267  double tpc_steel_location = (90 * inch) / 2 - 3 *inch - extra_length / 2.0;
268 
269  m_DisplayAction->AddVolume(hangerSupportLogic, "TpcHangerSupport");
270  G4VPhysicalVolume *tpc_hanger_support_phys[4] = {nullptr, nullptr,nullptr,nullptr};
271  tpc_hanger_support_phys[0] = new G4PVPlacement(0, G4ThreeVector(hangerX, hangerY, tpc_steel_location),
272  hangerSupportLogic, "tpc_hanger_support_northleft",
273  logicWorld, false, 0, OverlapCheck());
274  tpc_hanger_support_phys[1] = new G4PVPlacement(0, G4ThreeVector(-hangerX, hangerY, tpc_steel_location),
275  hangerSupportLogic, "tpc_hanger_support_northright",
276  logicWorld, false, 1, OverlapCheck());
277  tpc_hanger_support_phys[2] = new G4PVPlacement(0, G4ThreeVector(hangerX, hangerY, -tpc_steel_location),
278  hangerSupportLogic, "tpc_hanger_support_southleft",
279  logicWorld, false, 2, OverlapCheck());
280  tpc_hanger_support_phys[3] = new G4PVPlacement(0, G4ThreeVector(-hangerX, hangerY, -tpc_steel_location),
281  hangerSupportLogic, "tpc_hanger_support_southright",
282  logicWorld, false, 3, OverlapCheck());
283 
284  m_AbsorberVolumeSet.insert(tpc_hanger_support_phys[0]);
285  m_AbsorberVolumeSet.insert(tpc_hanger_support_phys[1]);
286  m_AbsorberVolumeSet.insert(tpc_hanger_support_phys[2]);
287  m_AbsorberVolumeSet.insert(tpc_hanger_support_phys[3]);
288 
289 
290  G4Material *carbonFiber = GetDetectorMaterial("CFRP_INTT");
291  double hangerBeamInnerDiameter = 2.0 * inch;
292  double hangerBeamOuterDiameter = 2.521 * inch;
293 
294  G4VSolid *hangerBeam = new G4Tubs("tpc_hanger_beam", hangerBeamInnerDiameter / 2., hangerBeamOuterDiameter / 2., (90 * inch) / 2., 0., 2 * M_PI);
295  G4LogicalVolume *hangerBeamLogic = new G4LogicalVolume(hangerBeam,
296  carbonFiber,
297  "tpc_hanger_beam");
298 
299  m_DisplayAction->AddVolume(hangerBeamLogic, "TpcHangerBeam");
300  G4VPhysicalVolume *tpc_hanger_beam_phys[2] = {nullptr, nullptr};
301  tpc_hanger_beam_phys[0] = new G4PVPlacement(0, G4ThreeVector(hangerX, hangerY, 0),
302  hangerBeamLogic, "tpc_hanger_beam_left",
303  logicWorld, false, 0, OverlapCheck());
304  tpc_hanger_beam_phys[1] = new G4PVPlacement(0, G4ThreeVector(-hangerX, hangerY, 0),
305  hangerBeamLogic, "tpc_hanger_beam_right",
306  logicWorld, false, 1, OverlapCheck());
307 
308  m_AbsorberVolumeSet.insert(tpc_hanger_beam_phys[0]);
309  m_AbsorberVolumeSet.insert(tpc_hanger_beam_phys[1]);
310 
311 
312 
313 
314 
315 
316 
317 
318  //Twelve one-inch diam carbon fiber rods of thickness 1/16" at 31.04" from beam center
319  //borrowed from the INTT specification of carbon fiber
320  //note that this defines a clocking!
321  double rodAngleStart = M_PI / 12.;
322  double rodAngularSpacing = 2 * M_PI / 12.;
323  double rodRadius = 31.5 * inch;
324  double rodWallThickness = 1. / 8. * inch;
325  double rodDiameter = 3. / 4. * inch;
326  G4VSolid *tieRod = new G4Tubs("tpc_tie_rod", rodDiameter / 2. - rodWallThickness, rodDiameter / 2., (m_Params->get_double_param("tpc_length") * cm) / 2., 0., 2 * M_PI);
327  G4LogicalVolume *tieRodLogic = new G4LogicalVolume(tieRod,
328  carbonFiber,
329  "tpc_tie_rod");
330 
331  G4VPhysicalVolume *tpc_tie_rod_phys[12] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
332  nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
333 
334  std::ostringstream name;
335  for (int i = 0; i < 12; i++)
336  {
337  double ang = rodAngleStart + rodAngularSpacing * i;
338  name.str("");
339  name << "tpc_tie_rod_" << i;
340  tpc_tie_rod_phys[i] = new G4PVPlacement(0, G4ThreeVector(rodRadius * cos(ang), rodRadius * sin(ang), 0),
341  tieRodLogic, name.str(),
342  logicWorld, false, i, OverlapCheck());
343  m_AbsorberVolumeSet.insert(tpc_tie_rod_phys[i]);
344  }
345 
346  // G4VisAttributes *visatt = new G4VisAttributes();
347  // visatt->SetVisibility(true);
348  // visatt->SetForceSolid(true);
349  // visatt->SetColor(PHG4TPCColorDefs::tpc_cu_color);
350  // tpc_window_logic->SetVisAttributes(visatt);
351 
352  return 0;
353 }
354 
355 int PHG4TpcDetector::ConstructTpcCageVolume(G4LogicalVolume *tpc_envelope)
356 {
357  // 8th layer cu
358  // 9th layer FR4
359  // 10th layer HoneyComb
360  // 11th layer FR4
361  // 12th layer Kapton
362  // 13th layer FR4
363  static const int nlayers = 9;
364  static const double thickness[nlayers] = {m_Params->get_double_param("cage_layer_1_thickness") * cm,
365  m_Params->get_double_param("cage_layer_2_thickness") * cm,
366  m_Params->get_double_param("cage_layer_3_thickness") * cm,
367  m_Params->get_double_param("cage_layer_4_thickness") * cm,
368  m_Params->get_double_param("cage_layer_5_thickness") * cm,
369  m_Params->get_double_param("cage_layer_6_thickness") * cm,
370  m_Params->get_double_param("cage_layer_7_thickness") * cm,
371  m_Params->get_double_param("cage_layer_8_thickness") * cm,
372  m_Params->get_double_param("cage_layer_9_thickness") * cm};
373 
374  static const std::string material[nlayers] = {m_Params->get_string_param("cage_layer_1_material"),
375  m_Params->get_string_param("cage_layer_2_material"),
376  m_Params->get_string_param("cage_layer_3_material"),
377  m_Params->get_string_param("cage_layer_4_material"),
378  m_Params->get_string_param("cage_layer_5_material"),
379  m_Params->get_string_param("cage_layer_6_material"),
380  m_Params->get_string_param("cage_layer_7_material"),
381  m_Params->get_string_param("cage_layer_8_material"),
382  m_Params->get_string_param("cage_layer_9_material")};
383 
384  double tpc_cage_radius = m_InnerCageRadius;
385  std::ostringstream name;
386  for (int i = 0; i < nlayers; i++)
387  {
388  name.str("");
389  int layerno = i + 1;
390  name << "tpc_cage_layer_" << layerno;
391  G4VSolid *tpc_cage_layer = new G4Tubs(name.str(), tpc_cage_radius, tpc_cage_radius + thickness[i], m_Params->get_double_param("tpc_length") * cm / 2., 0., 2 * M_PI);
392  G4LogicalVolume *tpc_cage_layer_logic = new G4LogicalVolume(tpc_cage_layer,
393  GetDetectorMaterial(material[i]),
394  name.str());
395  m_DisplayAction->AddTpcInnerLayer(tpc_cage_layer_logic);
396  G4VPhysicalVolume *tpc_cage_layer_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, 0),
397  tpc_cage_layer_logic, name.str(),
398  tpc_envelope, false, layerno, OverlapCheck());
399  m_AbsorberVolumeSet.insert(tpc_cage_layer_phys);
400  tpc_cage_radius += thickness[i];
401  }
402  // outer cage
403 
404  tpc_cage_radius = m_OuterCageRadius;
405  for (int i = 0; i < nlayers; i++)
406  {
407  tpc_cage_radius -= thickness[i];
408  name.str("");
409  int layerno = 10 + 1 + i; // so the accompanying inner layer is layer - 10
410  name << "tpc_cage_layer_" << layerno;
411  G4VSolid *tpc_cage_layer = new G4Tubs(name.str(), tpc_cage_radius, tpc_cage_radius + thickness[i], m_Params->get_double_param("tpc_length") * cm / 2., 0., 2 * M_PI);
412  G4LogicalVolume *tpc_cage_layer_logic = new G4LogicalVolume(tpc_cage_layer,
413  GetDetectorMaterial(material[i]),
414  name.str());
415  m_DisplayAction->AddTpcOuterLayer(tpc_cage_layer_logic);
416  G4VPhysicalVolume *tpc_cage_layer_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, 0),
417  tpc_cage_layer_logic, name.str(),
418  tpc_envelope, false, layerno, OverlapCheck());
419  m_AbsorberVolumeSet.insert(tpc_cage_layer_phys);
420  }
421 
422  return 0;
423 }
424 
426  std::string compositeName,
427  std::vector<std::string> materialName,
428  std::vector<double> thickness)
429 {
430  //takes in a list of material names known to Geant already, and thicknesses, and creates a new material called compositeName.
431 
432  //check that desired material name doesn't already exist
433  G4Material *tempmat = GetDetectorMaterial(compositeName, false);
434 
435  if (tempmat != nullptr)
436  {
437  std::cout << __PRETTY_FUNCTION__ << " Fatal Error: composite material " << compositeName << " already exists" << std::endl;
438  assert(!tempmat);
439  }
440 
441  //check that both arrays have the same depth
442  assert(materialName.size() == thickness.size());
443 
444  //sum up the areal density and total thickness so we can divvy it out
445  double totalArealDensity = 0, totalThickness = 0;
446  for (std::vector<double>::size_type i = 0; i < thickness.size(); i++)
447  {
448  tempmat = GetDetectorMaterial(materialName[i]);
449  if (tempmat == nullptr)
450  {
451  std::cout << __PRETTY_FUNCTION__ << " Fatal Error: component material " << materialName[i] << " does not exist." << std::endl;
452  gSystem->Exit(1);
453  exit(1);
454  }
455  totalArealDensity += tempmat->GetDensity() * thickness[i];
456  totalThickness += thickness[i];
457  }
458 
459  //register a new material with the average density of the whole:
460  double compositeDensity = totalArealDensity / totalThickness;
461  G4Material *composite = new G4Material(compositeName, compositeDensity, thickness.size());
462 
463  //now calculate the fraction due to each material, and register those
464  for (std::vector<double>::size_type i = 0; i < thickness.size(); i++)
465  {
466  tempmat = GetDetectorMaterial(materialName[i]); //don't need to check this, since we did in the previous loop.
467  composite->AddMaterial(tempmat, thickness[i] * tempmat->GetDensity() / totalArealDensity);
468  }
469 
470  //how to register our finished material?
471  return;
472 }
473 
474 
475 //_______________________________________________________________
477 {
478 
479  // create PHG4TpcCylinderGeomContainer and put on node tree
480  const std::string geonode_name = "CYLINDERCELLGEOM_SVTX";
481  auto geonode = findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode(), geonode_name);
482  if (!geonode)
483  {
484  geonode = new PHG4TpcCylinderGeomContainer;
485  PHNodeIterator iter(topNode());
486  auto runNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "RUN"));
487  auto newNode = new PHIODataNode<PHObject>(geonode, geonode_name, "PHObject");
488  runNode->addNode(newNode);
489  }
490 
491  const std::array<int, 3> NTpcLayers =
492  {{
493  m_Params->get_int_param("ntpc_layers_inner"),
494  m_Params->get_int_param("ntpc_layers_mid"),
495  m_Params->get_int_param("ntpc_layers_outer")
496  }};
497 
498  std::array<double, 3> MinLayer;
499  MinLayer[0] = m_Params->get_int_param("tpc_minlayer_inner");
500  MinLayer[1] = MinLayer[0] + NTpcLayers[0];
501  MinLayer[2] = MinLayer[1] + NTpcLayers[1];
502 
503  const std::array<double, 3> MinRadius =
504  {{
505  m_Params->get_double_param("tpc_minradius_inner"),
506  m_Params->get_double_param("tpc_minradius_mid"),
507  m_Params->get_double_param("tpc_minradius_outer")
508  }};
509 
510  const std::array<double, 3> MaxRadius =
511  {{
512  m_Params->get_double_param("tpc_maxradius_inner"),
513  m_Params->get_double_param("tpc_maxradius_mid"),
514  m_Params->get_double_param("tpc_maxradius_outer"),
515  }};
516 
517  const std::array<double, 5> Thickness =
518  {{
519  0.687,
520  1.012,
521  1.088,
522  0.534,
523  0.595,
524  }};
525 
526  const double drift_velocity = m_Params->get_double_param("drift_velocity");
527  const double tpc_adc_clock = m_Params->get_double_param("tpc_adc_clock");
528  const double MaxZ = m_Params->get_double_param("maxdriftlength");
529  const double TBinWidth = tpc_adc_clock;
530  const double extended_readout_time = m_Params->get_double_param("extended_readout_time");
531  const double MaxT = extended_readout_time + 2.* MaxZ / drift_velocity; // allows for extended time readout
532  const double MinT = 0;
533  const int NTBins = (int) ((MaxT - MinT) / TBinWidth) + 1;
534 
535  std::cout << PHWHERE << "MaxT " << MaxT << " NTBins = " << NTBins << " drift velocity " << drift_velocity << std::endl;
536 
537  const std::array<double, 3> SectorPhi =
538  {{
539  m_Params->get_double_param("tpc_sector_phi_inner"),
540  m_Params->get_double_param("tpc_sector_phi_mid"),
541  m_Params->get_double_param("tpc_sector_phi_outer")
542  }};
543 
544  const std::array<int, 3> NPhiBins =
545  {{
546  m_Params->get_int_param("ntpc_phibins_inner"),
547  m_Params->get_int_param("ntpc_phibins_mid"),
548  m_Params->get_int_param("ntpc_phibins_outer")
549  }};
550 
551  const std::array<double, 3> PhiBinWidth =
552  {{
553  SectorPhi[0] * 12 / (double) NPhiBins[0],
554  SectorPhi[1] * 12 / (double) NPhiBins[1],
555  SectorPhi[2] * 12 / (double) NPhiBins[2]
556  }};
557 
558  // should move to a common file
559  static constexpr int NSides = 2;
560  static constexpr int NSectors = 12;
561 
562  std::array<std::vector<double>, NSides > sector_R_bias;
563  std::array<std::vector<double>, NSides > sector_Phi_bias;
564  std::array<std::vector<double>, NSides > sector_min_Phi;
565  std::array<std::vector<double>, NSides > sector_max_Phi;
566 
567 
568  for (int iregion = 0; iregion < 3; ++iregion)
569  {
570  //int zside = 0;
571  for (int zside = 0; zside < 2;zside++)
572  {
573  sector_R_bias[zside].clear();
574  sector_Phi_bias[zside].clear();
575  sector_min_Phi[zside].clear();
576  sector_max_Phi[zside].clear();
577  //int eff_layer = 0;
578  for (int isector = 0; isector < NSectors; ++isector)//12 sectors
579  {
580 
581  // no bias per default
582  // TODO: confirm with what is in PHG4TpcPadPlane Readout
583  sector_R_bias[zside].push_back(0);
584  sector_Phi_bias[zside].push_back(0);
585 
586  double sec_gap = (2*M_PI - SectorPhi[iregion]*12)/12;
587  double sec_max_phi = M_PI - SectorPhi[iregion]/2 - sec_gap - 2 * M_PI / 12 * isector;// * (isector+1) ;
588  double sec_min_phi = sec_max_phi - SectorPhi[iregion];
589  sector_min_Phi[zside].push_back(sec_min_phi);
590  sector_max_Phi[zside].push_back(sec_max_phi);
591  }// isector
592  }
593 
594  double sum_r = 0;
595  for (int layer = MinLayer[iregion]; layer < MinLayer[iregion] + NTpcLayers[iregion]; ++layer)
596  {
597  double r_length = Thickness[iregion];
598  if(iregion == 0 && layer>0){
599  if(layer%2==0) r_length = Thickness[4];
600  else r_length = Thickness[3];
601  }
602  sum_r += r_length;
603  }
604  const double pad_space = (MaxRadius[iregion] - MinRadius[iregion] - sum_r)/(NTpcLayers[iregion]-1);
605  double current_r = MinRadius[iregion];
606 
607  for (int layer = MinLayer[iregion]; layer < MinLayer[iregion] + NTpcLayers[iregion]; ++layer)
608  {
609  if (Verbosity())
610  {
611  std::cout << " layer " << layer << " MinLayer " << MinLayer[iregion] << " region " << iregion
612  << " radius " << MinRadius[iregion] + ((double) (layer - MinLayer[iregion]) + 0.5) * Thickness[iregion]
613  << " thickness " << Thickness[iregion]
614  << " NTBins " << NTBins << " tmin " << MinT << " tstep " << TBinWidth
615  << " phibins " << NPhiBins[iregion] << " phistep " << PhiBinWidth[iregion] << std::endl;
616  }
617 
618  auto layerseggeo = new PHG4TpcCylinderGeom;
619  layerseggeo->set_layer(layer);
620 
621  double r_length = Thickness[iregion];
622  if(iregion == 0 && layer>0)
623  {
624  if(layer%2==0) r_length = Thickness[4];
625  else r_length = Thickness[3];
626  }
627  layerseggeo->set_thickness(r_length);
628  layerseggeo->set_radius(current_r+r_length/2);
629  layerseggeo->set_binning(PHG4CellDefs::sizebinning);
630  layerseggeo->set_zbins(NTBins);
631  layerseggeo->set_zmin(MinT);
632  layerseggeo->set_zstep(TBinWidth);
633  layerseggeo->set_phibins(NPhiBins[iregion]);
634  layerseggeo->set_phistep(PhiBinWidth[iregion]);
635  layerseggeo->set_r_bias(sector_R_bias);
636  layerseggeo->set_phi_bias(sector_Phi_bias);
637  layerseggeo->set_sector_min_phi(sector_min_Phi);
638  layerseggeo->set_sector_max_phi(sector_max_Phi);
639 
640  // Chris Pinkenburg: greater causes huge memory growth which causes problems
641  // on our farm. If you need to increase this - TALK TO ME first
642  if (NPhiBins[iregion] * NTBins > 5100000)
643  {
644  std::cout << "increase Tpc cellsize, number of cells "
645  << NPhiBins[iregion] * NTBins << " for layer " << layer
646  << " exceed 5.1M limit" << std::endl;
647  gSystem->Exit(1);
648  }
649  geonode->AddLayerCellGeom(layerseggeo);
650 
651  current_r += r_length + pad_space;
652  }
653  }
654  }