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 <EtmOrphans.h>
18 #include <GemGeoParData.h>
19 
20 // ---------------------------------------------------------------------------------------
21 
22 GemModule::GemModule( void ):
23  mActiveWindowBottomWidth ( 30.0 * etm::mm),
24  mActiveWindowTopWidth ( 430.0 * etm::mm),
25  mActiveWindowHeight ( 700.0 * etm::mm),
26 
27  // Frame parameters accoring to Kondo's sbsCrossSection.pdf file),
28  mFrameThickness ( 18.0 * etm::mm),
29  mFrameBottomEdgeWidth ( 30.0 * etm::mm),
30  mFrameTopEdgeWidth ( 30.0 * etm::mm),
31  mFrameSideEdgeWidth ( 8.0 * etm::mm),
32 
33  // FIXME: put aluminum layer later as well),
34  mEntranceWindowMaterial ( "GemKapton"),
35  mEntranceWindowThickness ( 50.0 * etm::um),
36 
37  // Use evaristo.pdf p.10 for the foil parameters:
38  // - drift foil : 50um kapton + 3um copper)
39  // - GEM foil : 30um kapton + 3um copper (80% area fraction))
40  // - readout foils : 30um kapton + 3um copper total)
41  mDriftFoilKaptonThickness ( 50.0 * etm::um),
42  mDriftFoilCopperThickness ( 3.0 * etm::um),
43  mGemFoilAreaFraction ( 0.80),
44  mGemFoilKaptonThickness ( 30.0 * etm::um),
45  mGemFoilCopperThickness ( 3.0 * etm::um),
46 
47  mReadoutG10Thickness ( 0.0 * etm::mm),
48  mReadoutKaptonThickness ( 30.0 * etm::um),
49  mReadoutCopperThickness ( 3.0 * etm::um),
50 
51 // 3mm thick Nomex honeycomb for SBS GEMs),
52  mReadoutSupportMaterial ( "GemNomex"),
53  mReadoutSupportThickness ( 3.0 * etm::mm),
54 
55 // FIXME: check on that!),
56  mGasMixture ( "arco27030"),
57 
58  mEntranceRegionLength ( 3.0 * etm::mm),
59  mDriftRegionLength ( 3.0 * etm::mm),
60 // Assume triple GEM layout),
61  mFirstTransferRegionLength ( 2.0 * etm::mm),
62  mSecondTransferRegionLength ( 2.0 * etm::mm),
63  mInductionRegionLength ( 2.0 * etm::mm)
64 {
65 } // GemModule::GemModule()
66 
67 // ---------------------------------------------------------------------------------------
68 
69 int GemGeoParData::ConstructGeometry(bool root, bool gdml, bool check)
70 {
71  const char *detName = mDetName->Name().Data();
72 
73  // Loop through all wheels (or perhaps single modules) independently;
74  for(unsigned wl=0; wl<mWheels.size(); wl++) {
75  GemWheel *wheel = mWheels[wl];
76  GemModule *module = wheel->mModule;
77 
78  // Assume top side is wider;
79  double sideSlope = atan((module->mActiveWindowTopWidth - module->mActiveWindowBottomWidth)/
80  (2*module->mActiveWindowHeight));
81 
82  double moduleContainerHeight;
83  TGeoVolume *vwcontainer, *vmcontainer;
84 
85  // Figure out parameters of the wheel container (air) volume first;
86  {
87  double thickness = (wheel->mModuleNum == 1 ? 1 : 2)*module->mFrameThickness +
89 
90  double minRadius = wheel->mRadius - module->mActiveWindowHeight/2 -
91  module->mFrameBottomEdgeWidth;
92  // Can perfectly be for a configuration with a single module FLYSUB "wheel";
93  if (minRadius < 0.0) minRadius = 0.0;
94 
95  // Assume frame side width is given in a section parallel to the base;
96  double xx = module->mActiveWindowTopWidth/2 + module->mFrameTopEdgeWidth*tan(sideSlope) +
97  module->mFrameSideEdgeWidth;
98  double yy = wheel->mRadius + module->mActiveWindowHeight/2 + module->mFrameTopEdgeWidth;
99  double maxRadius = sqrt(xx*xx + yy*yy);
100 
101  char wheelContainerVolumeName[128];
102  snprintf(wheelContainerVolumeName, 128-1, "%sWheelContainerVolume%02d", detName, wl);
103 
104  TGeoTube *wcontainer = new TGeoTube(wheelContainerVolumeName,
105  minRadius,
106  maxRadius,
107  thickness/2);
108  vwcontainer = new TGeoVolume(wheelContainerVolumeName, wcontainer, GetMedium(_AIR_));
109 
110  GetTopVolume()->AddNode(vwcontainer, 0, wheel->mTransformation);
111  }
112 
113  // Module container (air) volume; here can indeed use TRD1 volume;
114  {
115  char moduleContainerVolumeName[128];
116  snprintf(moduleContainerVolumeName, 128-1, "%sModuleContainerVolume%02d", detName, wl);
117 
118  moduleContainerHeight = module->mFrameTopEdgeWidth + module->mFrameBottomEdgeWidth +
119  module->mActiveWindowHeight;
120 
121  TGeoTrd1 *mcontainer = new TGeoTrd1(moduleContainerVolumeName,
122  module->mActiveWindowBottomWidth/2 + module->mFrameSideEdgeWidth -
123  module->mFrameBottomEdgeWidth*tan(sideSlope),
124  module->mActiveWindowTopWidth/2 + module->mFrameSideEdgeWidth +
125  module->mFrameTopEdgeWidth*tan(sideSlope),
126  module->mFrameThickness/2,
127  moduleContainerHeight/2);
128  vmcontainer = new TGeoVolume(moduleContainerVolumeName, mcontainer, GetMedium(_AIR_));
129 
130  // Place all the modules into the wheel container volume;
131  for(unsigned md=0; md<wheel->mModuleNum; md++) {
132  double effRadius = wheel->mRadius + (module->mFrameTopEdgeWidth - module->mFrameBottomEdgeWidth)/2;
133 
134  TGeoRotation *rw = new TGeoRotation();
135  double degAngle = md*360.0/wheel->mModuleNum;
136  double radAngle = degAngle*TMath::Pi()/180.0;
137  rw->SetAngles(90.0, 0.0 - degAngle, 180.0, 0.0, 90.0, 90.0 - degAngle);
138 
139  double xOffset = effRadius*sin(radAngle);
140  double yOffset = effRadius*cos(radAngle);
141  double zOffset = wheel->mModuleNum == 1 ? 0.0 :
142  (md%2 ? -1.0 : 1.0)*(module->mFrameThickness + mMountingRingBeamLineThickness)/2;
143 
144  vwcontainer->AddNode(vmcontainer, md, new TGeoCombiTrans(xOffset, yOffset, zOffset, rw));
145  } //for md
146  }
147 
148  // And now put the other stuff piece by piece; unfortunately have to cook frame
149  // out of 4 pieces rather than a single TRD1, since otherwise drawing will
150  // become a nightmare (ROOT seems to be not able to draw inner walls at the
151  // border of volume and its subvolume in a reasonable way);
152  {
153  //
154  // A trapezoid shape; indeed could use TRD1 inner volumes and rotate them
155  // accordingly; the trouble is that then I'd have to screw up local
156  // coordinate system of the sensitive volume (so Z will be pointing in
157  // radial direction rather than along the beam line; consider to use
158  // TGeoArb8 shape for this reason; CHECK: is there a performance penalty?;
159  //
160 
161  char bottomFrameEdgeName[128], topFrameEdgeName[128], sideFrameEdgeName[128];
162 
163  // Want them to start with the same name pattern;
164  snprintf(bottomFrameEdgeName, 128-1, "%sFrameEdgeBottom%02d", detName, wl);
165  snprintf(topFrameEdgeName, 128-1, "%sFrameEdgeTop%02d", detName, wl);
166  snprintf(sideFrameEdgeName, 128-1, "%sFrameEdgeSide%02d", detName, wl);
167 
168  // Bottom edge; here I can indeed use TRD1 volume;
169  {
170  TGeoTrd1 *bottom = new TGeoTrd1(bottomFrameEdgeName,
171  module->mActiveWindowBottomWidth/2 -
172  module->mFrameBottomEdgeWidth*tan(sideSlope),
173  module->mActiveWindowBottomWidth/2,
174  module->mFrameThickness/2,
175  module->mFrameBottomEdgeWidth/2);
176  TGeoVolume *vbottom = new TGeoVolume(bottomFrameEdgeName, bottom, GetMedium(mG10Material));
177 
178  double zOffset = -(moduleContainerHeight - module->mFrameBottomEdgeWidth)/2;
179  vmcontainer->AddNode(vbottom, 0, new TGeoCombiTrans(0.0, 0.0, zOffset, 0));
180  }
181  // Top edge; the same;
182  {
183  TGeoTrd1 *top = new TGeoTrd1(topFrameEdgeName,
184  module->mActiveWindowTopWidth/2,
185  module->mActiveWindowTopWidth/2 +
186  module->mFrameTopEdgeWidth*tan(sideSlope),
187  module->mFrameThickness/2,
188  module->mFrameTopEdgeWidth/2);
189  TGeoVolume *vtop = new TGeoVolume(topFrameEdgeName, top, GetMedium(mG10Material));
190 
191  double zOffset = (moduleContainerHeight - module->mFrameTopEdgeWidth)/2;
192  vmcontainer->AddNode(vtop, 0, new TGeoCombiTrans(0.0, 0.0, zOffset, 0));
193  }
194 
195  // A pair of side edges; TGeoPara will do;
196  TGeoPara *side = new TGeoPara(sideFrameEdgeName,
197  module->mFrameSideEdgeWidth/2,
198  module->mFrameThickness/2,
199  moduleContainerHeight/2,
200  0.0, sideSlope*180/TMath::Pi(), 0.0);
201  TGeoVolume *vside = new TGeoVolume(sideFrameEdgeName, side, GetMedium(mG10Material));
202  for(unsigned lr=0; lr<2; lr++) {
203  double xOffset = (lr ? -1.0 : 1.)*
204  (module->mActiveWindowBottomWidth/2 - module->mFrameBottomEdgeWidth*tan(sideSlope) +
205  module->mFrameSideEdgeWidth/2 + (moduleContainerHeight/2)*tan(sideSlope));
206 
207  TGeoRotation *rw = 0;
208  if (lr) {
209  rw = new TGeoRotation();
210  rw->RotateZ(180.0);
211  } //if
212 
213  vmcontainer->AddNode(vside, lr, new TGeoCombiTrans(xOffset, 0.0, 0.0, rw));
214  } //for lr
215 
216  // Eventually populate single layers, one by one;
217  {
218  double yOffset = -module->mFrameThickness/2;// + 0.100;
219 
220  //
221  // XY-projection shape does not change; it's only zOffset, thickness and material;
222  //
223  // Proceed in direction opposite to the incident particles; whatever
224  // is left in thickness will remain air in front of the entrance foil;
225  //
226  // This readout support stuff is optionally present;
227  if (module->mReadoutSupportThickness)
228  PlaceMaterialLayer(detName, "ReadoutSupport", wl, vmcontainer,
229  module->mReadoutSupportMaterial.Data(),
230  module->mReadoutSupportThickness, &yOffset);
231  if (module->mReadoutG10Thickness)
232  PlaceMaterialLayer(detName, "ReadoutG10", wl, vmcontainer,
233  mG10Material.Data(),
234  module->mReadoutG10Thickness, &yOffset);
235 
236  // Readout foil is always there;
237  PlaceMaterialLayer(detName, "ReadoutKapton", wl, vmcontainer,
238  mKaptonMaterial.Data(),
239  module->mReadoutKaptonThickness, &yOffset);
240 
241  // Copper layers are extremely thin -> put one effective layer;
242  {
243  double thickness = module->mReadoutCopperThickness +
244  // 3x kapton layer, double-sided metallization;
245  3*2*module->mGemFoilAreaFraction*module->mGemFoilCopperThickness +
247 
248  PlaceMaterialLayer(detName, "EffectiveCopper", wl, vmcontainer,
249  _COPPER_, thickness, &yOffset);
250  }
251 
252  // Induction region;
253  {
254  PlaceMaterialLayer(detName, "InductionRegionGas", wl, vmcontainer,
255  module->mGasMixture.Data(),
256  module->mInductionRegionLength, &yOffset);
257 
258  PlaceMaterialLayer(detName, "InductionRegionFoil", wl, vmcontainer,
259  mKaptonMaterial.Data(),
261  &yOffset);
262  }
263 
264  // 2-d transfer region;
265  {
266  PlaceMaterialLayer(detName, "SecondTransferRegionGas", wl, vmcontainer,
267  module->mGasMixture.Data(),
268  module->mSecondTransferRegionLength, &yOffset);
269 
270  PlaceMaterialLayer(detName, "SecondTransferRegionFoil", wl, vmcontainer,
271  mKaptonMaterial.Data(),
273  &yOffset);
274  }
275 
276  // 1-st transfer region;
277  {
278  PlaceMaterialLayer(detName, "FirstTransferRegionGas", wl, vmcontainer,
279  module->mGasMixture.Data(),
280  module->mFirstTransferRegionLength, &yOffset);
281 
282  PlaceMaterialLayer(detName, "FirstTransferRegionFoil", wl, vmcontainer,
283  mKaptonMaterial.Data(),
285  &yOffset);
286  }
287 
288  // drift region;
289  {
290  // NB: this is the sensitive volume!;
291  PlaceMaterialLayer(detName, "DriftRegionGas", wl, vmcontainer,
292  module->mGasMixture.Data(),
293  module->mDriftRegionLength, &yOffset);
294 
295  PlaceMaterialLayer(detName, "DriftRegionFoil", wl, vmcontainer,
296  mKaptonMaterial.Data(),
297  module->mDriftFoilKaptonThickness, &yOffset);
298  }
299 
300  // entrance region;
301  {
302  PlaceMaterialLayer(detName, "EntranceRegionGas", wl, vmcontainer,
303  module->mGasMixture.Data(),
304  module->mEntranceRegionLength, &yOffset);
305 
306  PlaceMaterialLayer(detName, "EntranceWindow", wl, vmcontainer,
307  module->mEntranceWindowMaterial.Data(),
308  module->mEntranceWindowThickness, &yOffset);
309  }
310  }
311  } //if
312 
313  {
315  // Yes, carelessly create one map per layer;
316  EicGeoMap *fgmap = CreateNewMap();
317 
318  // FIXME: do it better later;
319  char volumeName[128];
320  snprintf(volumeName, 128-1, "%s%s%02d", detName, "DriftRegionGas", wl);
321  fgmap->AddGeantVolumeLevel(volumeName, 0);
322 
323  fgmap->SetSingleSensorContainerVolume(volumeName);
324 
325  snprintf(volumeName, 128-1, "%sModuleContainerVolume%02d", detName, wl);
326  fgmap->AddGeantVolumeLevel(volumeName, wheel->mModuleNum);
327 
328  for(unsigned md=0; md<wheel->mModuleNum; md++) {
329  UInt_t geant[2] = {0, md}, logical[1] = {md};
330 
331  if (SetMappingTableEntry(fgmap, geant, wl, logical)) {
332  cout << "Failed to set mapping table entry!" << endl;
333  exit(0);
334  } //if
335  } //for md
336  }
337  } //for wl
338 
339  GetColorTable() ->AddPatternMatch("FrameEdge", kGray);
340  GetColorTable() ->AddPatternMatch("EntranceWindow", kOrange);
341  if (mTransparency)
342  GetTransparencyTable()->AddPatternMatch("EntranceWindow", mTransparency);
343  GetColorTable() ->AddPatternMatch("ReadoutSupport", kOrange);
344  if (mTransparency)
345  GetTransparencyTable()->AddPatternMatch("ReadoutSupport", mTransparency);
346 
347  // Place this stuff as a whole into the top volume and write out;
348  FinalizeOutput(root, gdml, check);
349 
350  return 0;
351 } // GemGeoParData::ConstructGeometry()
352 
353 // ---------------------------------------------------------------------------------------
354 
355 void GemGeoParData::PlaceMaterialLayer(const char *detName, const char *volumeNamePrefix,
356  unsigned wheelID,
357  TGeoVolume *moduleContainer, const char *material,
358  double thickness, double *yOffset)
359 {
360  char volumeName[128];
361  GemWheel *wheel = mWheels[wheelID];
362  GemModule *module = wheel->mModule;
363 
364  snprintf(volumeName, 128-1, "%s%s%02d", detName, volumeNamePrefix, wheelID);
365 
366  // Well, be aware that with a switch from Arb8 (which is a problematic shape in
367  // many respects assuming a TGeo -> GDML ->TGeo conversion), this volume can not
368  // be easily used in the native EicRoot tracking since the coordinate system is
369  // kind of wrong (Y & Z flipped);
370  TGeoTrd1 *shape = new TGeoTrd1(volumeName,
371  module->mActiveWindowBottomWidth/2,
372  module->mActiveWindowTopWidth/2,
373  thickness/2,
374  module->mActiveWindowHeight/2);
375  TGeoVolume *vshape = new TGeoVolume(volumeName, shape, GetMedium(material));
376 
377  double zOffset = -(module->mFrameTopEdgeWidth - module->mFrameBottomEdgeWidth)/2;
378  moduleContainer->AddNode(vshape, 0, new TGeoCombiTrans(0.0, (*yOffset + thickness/2),
379  zOffset, 0));
380 
381  *yOffset += thickness;
382 } // GemGeoParData::PlaceMaterialLayer()
383 
384 // ---------------------------------------------------------------------------------------
385