EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GemGeoParData.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file GemGeoParData.cxx
1 //
2 // AYK (ayk@bnl.gov), 2014/08/06
3 //
4 // GEM geometry description file;
5 //
6 
7 #include <iostream>
8 using namespace std;
9 
10 #include <TGeoTube.h>
11 #include <TGeoVolume.h>
12 #include <TGeoMatrix.h>
13 #include <TGeoTrd1.h>
14 #include <TGeoArb8.h>
15 #include <TGeoPara.h>
16 
17 #include <GemGeoParData.h>
18 
19 // ---------------------------------------------------------------------------------------
20 
21 int GemGeoParData::ConstructGeometry(bool root, bool gdml, bool check)
22 {
23  const char *detName = mDetName->Name().Data();
24 
25  // Loop through all wheels (or perhaps single modules) independently;
26  for(unsigned wl=0; wl<mWheels.size(); wl++) {
27  GemWheel *wheel = mWheels[wl];
28  GemModule *module = wheel->mModule;
29 
30  // Assume top side is wider;
31  double sideSlope = atan((module->mActiveWindowTopWidth - module->mActiveWindowBottomWidth)/
32  (2*module->mActiveWindowHeight));
33 
34  double moduleContainerHeight;
35  TGeoVolume *vwcontainer, *vmcontainer;
36 
37  // Figure out parameters of the wheel container (air) volume first;
38  {
39  double thickness = (wheel->mModuleNum == 1 ? 1 : 2)*module->mFrameThickness +
40  mMountingRingBeamLineThickness;
41 
42  double minRadius = wheel->mRadius - module->mActiveWindowHeight/2 -
43  module->mFrameBottomEdgeWidth;
44  // Can perfectly be for a configuration with a single module FLYSUB "wheel";
45  if (minRadius < 0.0) minRadius = 0.0;
46 
47  // Assume frame side width is given in a section parallel to the base;
48  double xx = module->mActiveWindowTopWidth/2 + module->mFrameTopEdgeWidth*tan(sideSlope) +
49  module->mFrameSideEdgeWidth;
50  double yy = wheel->mRadius + module->mActiveWindowHeight/2 + module->mFrameTopEdgeWidth;
51  double maxRadius = sqrt(xx*xx + yy*yy);
52 
53  char wheelContainerVolumeName[128];
54  snprintf(wheelContainerVolumeName, 128-1, "%sWheelContainerVolume%02d", detName, wl);
55 
56  TGeoTube *wcontainer = new TGeoTube(wheelContainerVolumeName,
57  0.1 * minRadius,
58  0.1 * maxRadius,
59  0.1 * thickness/2);
60  vwcontainer = new TGeoVolume(wheelContainerVolumeName, wcontainer, GetMedium(_AIR_));
61 
62  GetTopVolume()->AddNode(vwcontainer, 0, wheel->mTransformation);
63  }
64 
65  // Module container (air) volume; here can indeed use TRD1 volume;
66  {
67  char moduleContainerVolumeName[128];
68  snprintf(moduleContainerVolumeName, 128-1, "%sModuleContainerVolume%02d", detName, wl);
69 
70  moduleContainerHeight = module->mFrameTopEdgeWidth + module->mFrameBottomEdgeWidth +
71  module->mActiveWindowHeight;
72 
73  TGeoTrd1 *mcontainer = new TGeoTrd1(moduleContainerVolumeName,
74  0.1 * (module->mActiveWindowBottomWidth/2 + module->mFrameSideEdgeWidth -
75  module->mFrameBottomEdgeWidth*tan(sideSlope)),
76  0.1 * (module->mActiveWindowTopWidth/2 + module->mFrameSideEdgeWidth +
77  module->mFrameTopEdgeWidth*tan(sideSlope)),
78  0.1 * module->mFrameThickness/2,
79  0.1 * moduleContainerHeight/2);
80  vmcontainer = new TGeoVolume(moduleContainerVolumeName, mcontainer, GetMedium(_AIR_));
81 
82  // Place all the modules into the wheel container volume;
83  for(unsigned md=0; md<wheel->mModuleNum; md++) {
84  double effRadius = wheel->mRadius + (module->mFrameTopEdgeWidth - module->mFrameBottomEdgeWidth)/2;
85 
86  TGeoRotation *rw = new TGeoRotation();
87  double degAngle = md*360.0/wheel->mModuleNum;
88  double radAngle = degAngle*TMath::Pi()/180.0;
89  rw->SetAngles(90.0, 0.0 - degAngle, 180.0, 0.0, 90.0, 90.0 - degAngle);
90 
91  double xOffset = effRadius*sin(radAngle);
92  double yOffset = effRadius*cos(radAngle);
93  double zOffset = wheel->mModuleNum == 1 ? 0.0 :
94  (md%2 ? -1.0 : 1.0)*(module->mFrameThickness + mMountingRingBeamLineThickness)/2;
95 
96  vwcontainer->AddNode(vmcontainer, md, new TGeoCombiTrans(0.1 *xOffset, 0.1 * yOffset, 0.1 * zOffset, rw));
97  } //for md
98  }
99 
100  // And now put the other stuff piece by piece; unfortunately have to cook frame
101  // out of 4 pieces rather than a single TRD1, since otherwise drawing will
102  // become a nightmare (ROOT seems to be not able to draw inner walls at the
103  // border of volume and its subvolume in a reasonable way);
104 #if _LATER_
105  if (module->mActiveWindowTopWidth == module->mActiveWindowBottomWidth) {
106  // An easy (square shape) frame and other volumes;
107  assert(0);
108 
109  }
110  else
111 #endif
112  {
113  //
114  // A trapezoid shape; indeed could use TRD1 inner volumes and rotate them
115  // accordingly; the trouble is that then I'd have to screw up local
116  // coordinate system of the sensitive volume (so Z will be pointing in
117  // radial direction rather than along the beam line; consider to use
118  // TGeoArb8 shape for this reason; CHECK: is there a performance penalty?;
119  //
120 
121  char bottomFrameEdgeName[128], topFrameEdgeName[128], sideFrameEdgeName[128];
122 
123  // Want them to start with the same name pattern;
124  snprintf(bottomFrameEdgeName, 128-1, "%sFrameEdgeBottom%02d", detName, wl);
125  snprintf(topFrameEdgeName, 128-1, "%sFrameEdgeTop%02d", detName, wl);
126  snprintf(sideFrameEdgeName, 128-1, "%sFrameEdgeSide%02d", detName, wl);
127 
128  // Bottom edge; here I can indeed use TRD1 volume;
129  {
130  TGeoTrd1 *bottom = new TGeoTrd1(bottomFrameEdgeName,
131  0.1 * (module->mActiveWindowBottomWidth/2 -
132  module->mFrameBottomEdgeWidth*tan(sideSlope)),
133  0.1 * module->mActiveWindowBottomWidth/2,
134  0.1 * module->mFrameThickness/2,
135  0.1 * module->mFrameBottomEdgeWidth/2);
136  TGeoVolume *vbottom = new TGeoVolume(bottomFrameEdgeName, bottom, GetMedium(mG10Material));
137 
138  double zOffset = -(moduleContainerHeight - module->mFrameBottomEdgeWidth)/2;
139  vmcontainer->AddNode(vbottom, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * zOffset, 0));
140  }
141 
142  // Top edge; the same;
143  {
144  TGeoTrd1 *top = new TGeoTrd1(topFrameEdgeName,
145  0.1 * module->mActiveWindowTopWidth/2,
146  0.1 * (module->mActiveWindowTopWidth/2 +
147  module->mFrameTopEdgeWidth*tan(sideSlope)),
148  0.1 * module->mFrameThickness/2,
149  0.1 * module->mFrameTopEdgeWidth/2);
150  TGeoVolume *vtop = new TGeoVolume(topFrameEdgeName, top, GetMedium(mG10Material));
151 
152  double zOffset = (moduleContainerHeight - module->mFrameTopEdgeWidth)/2;
153  vmcontainer->AddNode(vtop, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * zOffset, 0));
154  }
155 
156  // A pair of side edges; TGeoPara will do;
157  TGeoPara *side = new TGeoPara(sideFrameEdgeName,
158  0.1 * module->mFrameSideEdgeWidth/2,
159  0.1 * module->mFrameThickness/2,
160  0.1 * moduleContainerHeight/2,
161  0.0, sideSlope*180/TMath::Pi(), 0.0);
162  TGeoVolume *vside = new TGeoVolume(sideFrameEdgeName, side, GetMedium(mG10Material));
163  for(unsigned lr=0; lr<2; lr++) {
164  double xOffset = (lr ? -1.0 : 1.)*
165  (module->mActiveWindowBottomWidth/2 - module->mFrameBottomEdgeWidth*tan(sideSlope) +
166  module->mFrameSideEdgeWidth/2 + (moduleContainerHeight/2)*tan(sideSlope));
167 
168  TGeoRotation *rw = 0;
169  if (lr) {
170  rw = new TGeoRotation();
171  rw->RotateZ(180.0);
172  } //if
173 
174  vmcontainer->AddNode(vside, lr, new TGeoCombiTrans(0.1 * xOffset, 0.0, 0.0, rw));
175  } //for lr
176 
177  // Eventually populate single layers, one by one;
178  {
179  double yOffset = -module->mFrameThickness/2;
180 
181  // XY-projection shape does not change; it's only zOffset and thickness;
182  double wdt = 0.1 * module->mActiveWindowTopWidth;
183  double wdb = 0.1 * module->mActiveWindowBottomWidth;
184  double ht = 0.1 * module->mActiveWindowHeight;
185 
186  double vert[8][2] = {
187  {-wdb/2, -ht/2},
188  {-wdt/2, ht/2},
189  { wdt/2, ht/2},
190  { wdb/2, -ht/2},
191  {-wdb/2, -ht/2},
192  {-wdt/2, ht/2},
193  { wdt/2, ht/2},
194  { wdb/2, -ht/2}
195  };
196 
197  //
198  // Proceed in direction opposite to the incident particles; whatever
199  // is left in thickness will remain air in front of the entrance foil;
200  //
201 
202  // This readout support stuff is optionally present;
203  if (module->mReadoutSupportThickness)
204  PlaceMaterialLayer(detName, "ReadoutSupport", wl, vmcontainer,
205  module->mReadoutSupportMaterial.Data(), (double*)vert,
206  module->mReadoutSupportThickness, &yOffset);
207  if (module->mReadoutG10Thickness)
208  PlaceMaterialLayer(detName, "ReadoutG10", wl, vmcontainer,
209  mG10Material.Data(), (double*)vert,
210  module->mReadoutG10Thickness, &yOffset);
211 
212  // Readout foil is always there;
213  PlaceMaterialLayer(detName, "ReadoutKapton", wl, vmcontainer,
214  mKaptonMaterial.Data(), (double*)vert,
215  module->mReadoutKaptonThickness, &yOffset);
216 
217  // Cooper layers are extremely thin -> put one effective layer;
218  {
219  double thickness = module->mReadoutCopperThickness +
220  // 3x kapton layer, double-sided metallization;
221  3*2*module->mGemFoilAreaFraction*module->mGemFoilCopperThickness +
223 
224  PlaceMaterialLayer(detName, "EffectiveCopper", wl, vmcontainer,
225  _COPPER_, (double*)vert,
226  thickness, &yOffset);
227  }
228 
229  // Induction region;
230  {
231  PlaceMaterialLayer(detName, "InductionRegionGas", wl, vmcontainer,
232  module->mGasMixture.Data(), (double*)vert,
233  module->mInductionRegionLength, &yOffset);
234 
235  PlaceMaterialLayer(detName, "InductionRegionFoil", wl, vmcontainer,
236  mKaptonMaterial.Data(), (double*)vert,
238  &yOffset);
239  }
240 
241  // 2-d transfer region;
242  {
243  PlaceMaterialLayer(detName, "SecondTransferRegionGas", wl, vmcontainer,
244  module->mGasMixture.Data(), (double*)vert,
245  module->mSecondTransferRegionLength, &yOffset);
246 
247  PlaceMaterialLayer(detName, "SecondTransferRegionFoil", wl, vmcontainer,
248  mKaptonMaterial.Data(), (double*)vert,
250  &yOffset);
251  }
252 
253  // 1-st transfer region;
254  {
255  PlaceMaterialLayer(detName, "FirstTransferRegionGas", wl, vmcontainer,
256  module->mGasMixture.Data(), (double*)vert,
257  module->mFirstTransferRegionLength, &yOffset);
258 
259  PlaceMaterialLayer(detName, "FirstTransferRegionFoil", wl, vmcontainer,
260  mKaptonMaterial.Data(), (double*)vert,
262  &yOffset);
263  }
264 
265  // drift region;
266  {
267  // NB: this is the sensitive volume!;
268  PlaceMaterialLayer(detName, "DriftRegionGas", wl, vmcontainer,
269  module->mGasMixture.Data(), (double*)vert,
270  module->mDriftRegionLength, &yOffset);
271 
272  PlaceMaterialLayer(detName, "DriftRegionFoil", wl, vmcontainer,
273  mKaptonMaterial.Data(), (double*)vert,
274  module->mDriftFoilKaptonThickness, &yOffset);
275  }
276 
277  // entrance region;
278  {
279  PlaceMaterialLayer(detName, "EntranceRegionGas", wl, vmcontainer,
280  module->mGasMixture.Data(), (double*)vert,
281  module->mEntranceRegionLength, &yOffset);
282 
283  PlaceMaterialLayer(detName, "EntranceWindow", wl, vmcontainer,
284  module->mEntranceWindowMaterial.Data(), (double*)vert,
285  module->mEntranceWindowThickness, &yOffset);
286  }
287 
288  printf("-> %f\n", yOffset);
289  }
290  } //if
291 
292  {
294  // Yes, carelessly create one map per layer;
295  EicGeoMap *fgmap = CreateNewMap();
296 
297  // FIXME: do it better later;
298  char volumeName[128];
299  snprintf(volumeName, 128-1, "%s%s%02d", detName, "DriftRegionGas", wl);
300  fgmap->AddGeantVolumeLevel(volumeName, 0);
301 
302  fgmap->SetSingleSensorContainerVolume(volumeName);
303 
304  snprintf(volumeName, 128-1, "%sModuleContainerVolume%02d", detName, wl);
305  fgmap->AddGeantVolumeLevel(volumeName, wheel->mModuleNum);
306 
307  for(unsigned md=0; md<wheel->mModuleNum; md++) {
308  UInt_t geant[2] = {0, md}, logical[1] = {md};
309 
310  if (SetMappingTableEntry(fgmap, geant, wl, logical)) {
311  cout << "Failed to set mapping table entry!" << endl;
312  exit(0);
313  } //if
314  } //for md
315  }
316  } //for wl
317 
318  // Place this stuff as a whole into the top volume and write out;
319  FinalizeOutput(root, gdml, check);
320 
321  return 0;
322 } // GemGeoParData::ConstructGeometry()
323 
324 // ---------------------------------------------------------------------------------------
325 
326 void GemGeoParData::PlaceMaterialLayer(const char *detName, const char *volumeNamePrefix,
327  unsigned wheelID,
328  TGeoVolume *moduleContainer, const char *material,
329  double *vert, double thickness, double *yOffset)
330 {
331  char volumeName[128];
332  GemWheel *wheel = mWheels[wheelID];
333  GemModule *module = wheel->mModule;
334 
335  snprintf(volumeName, 128-1, "%s%s%02d", detName, volumeNamePrefix, wheelID);
336 
337  TGeoArb8 *shape = new TGeoArb8(volumeName, 0.1 * thickness/2, vert);
338 
339  TGeoVolume *vshape = new TGeoVolume(volumeName, shape, GetMedium(material));
340 
341  double zOffset = -(module->mFrameTopEdgeWidth - module->mFrameBottomEdgeWidth)/2;
342  TGeoRotation *rw = new TGeoRotation();
343  rw->RotateX(90.0);
344  moduleContainer->AddNode(vshape, 0, new TGeoCombiTrans(0.0, 0.1 * (*yOffset + thickness/2),
345  0.1 * zOffset, rw));
346 
347  *yOffset += thickness;
348 } // GemGeoParData::PlaceMaterialLayer()
349 
350 // ---------------------------------------------------------------------------------------
351