EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MuMegasGeoParData.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MuMegasGeoParData.cxx
1 //
2 // AYK (ayk@bnl.gov), 2015/01/28; July 2020: adapted to EicToyModel environment;
3 //
4 // MuMegas geometry description file;
5 //
6 
7 #include <iostream>
8 using namespace std;
9 
10 #include <TGeoTube.h>
11 #include <TGeoVolume.h>
12 
13 #include <EtmOrphans.h>
14 #include <MuMegasGeoParData.h>
15 
16 // ---------------------------------------------------------------------------------------
17 
18 //
19 // #define's are for newbies :-)
20 //
21 
23  // FIXME: need FR4 here; 320um thick (e-mail from Maxence 2015/01/23);
24  mReadoutPcbMaterial ("MuMegasG10"),
25  mReadoutPcbThickness (0.320 * etm::mm),
26  // FIXME: this is effective thickness I guess?; like 1/4 oz copper;
27  mCopperStripThickness (0.010 * etm::mm),
28 
29  // Let's say, Ar(70)/CO2(30), see Maxence' muMegas.C; 130um amplification region;
30  mGasMixture ("arco27030mmg"),
31  mAmplificationRegionLength(0.130 * etm::mm),
32 
33  // FIXME: will need 'steel' in media.geo;
34  mSteelMeshThickness (0.019 * etm::mm * (19./50.) * (19./50.)),
35 
36  // 3mm conversion gap for now;
37  mConversionRegionLength (3.000 * etm::mm),
38 
39  // Basically a placeholder for now; assume 50um kapton as entrance window;
40  mExitWindowMaterial ("MuMegasKapton"),
41  mExitWindowThickness (0.050 * etm::mm),
42 
43  // FIXME: these parameters need to be checked and made real; the problem is
44  // that they will be sitting in the clear acceptance, so handle with care;
45  // for instance PandaRoot tracker clearly gets confused (provides a bit
46  // biased momentum estimates when these frames are thick;
47  mInnerFrameWidth (10.000 * etm::mm),
48  mInnerFrameThickness ( 5.000 * etm::mm),
49  mOuterFrameWidth (20.000 * etm::mm),
50  mOuterFrameThickness ( 5.000 * etm::mm)
51 {
52 } // MuMegasLayer::MuMegasLayer()
53 
54 // ---------------------------------------------------------------------------------------
55 
56 int MuMegasGeoParData::ConstructGeometry(bool root, bool gdml, bool check)
57 {
58  const char *detName = mDetName->Name().Data();
59 
60  // Loop through all wheels (or perhaps single modules) independently;
61  for(unsigned bl=0; bl<mBarrels.size(); bl++) {
62  MuMegasBarrel *barrel = mBarrels[bl];
63  MuMegasLayer *layer = barrel->mLayer;
64 
65  // Figure out thickness of the sector gas container volume;
66  double gasSectorThickness = layer->mReadoutPcbThickness + layer->mCopperStripThickness +
68  layer->mExitWindowThickness;
69 
70  // Figure out thickness of the overall air container volume;
71  double airContainerThickness = gasSectorThickness < layer->mInnerFrameThickness ?
72  layer->mInnerFrameThickness : gasSectorThickness;
73  if (airContainerThickness < layer->mOuterFrameThickness)
74  airContainerThickness = layer->mOuterFrameThickness;
75 
76  // Define air container volume and place it into the top volume;
77  char barrelContainerVolumeName[128];
78  snprintf(barrelContainerVolumeName, 128-1, "%sBarrelContainerVolume%02d", detName, bl);
79 
80  TGeoTube *bcontainer = new TGeoTube(barrelContainerVolumeName,
81  barrel->mRadius,
82  barrel->mRadius + airContainerThickness,
83  barrel->mLength/2);
84  TGeoVolume *vbcontainer = new TGeoVolume(barrelContainerVolumeName, bcontainer, GetMedium(_AIR_));
85 
86  GetTopVolume()->AddNode(vbcontainer, 0, barrel->mTransformation);
87 
88  // Define and place a pair of outer frame rings;
89  char outerFrameVolumeName[128];
90  snprintf(outerFrameVolumeName, 128-1, "%sOuterFrameVolume%02d", detName, bl);
91 
92  TGeoTube *oframe = new TGeoTube(outerFrameVolumeName,
93  barrel->mRadius,
94  barrel->mRadius + layer->mOuterFrameThickness,
95  layer->mOuterFrameWidth/2);
96  TGeoVolume *voframe = new TGeoVolume(outerFrameVolumeName, oframe, GetMedium("MuMegasCarbonFiber"));
97  double zOffset = (barrel->mLength - layer->mOuterFrameWidth)/2;
98  for(unsigned fb=0; fb<2; fb++)
99  vbcontainer->AddNode(voframe, fb, new TGeoCombiTrans(0.0, 0.0, (fb ? -1.0 : 1.0)*zOffset, 0));
100 
101  // Figure out sector length;
102  double singleSectorLength =
103  (barrel->mLength - 2.0 * layer->mOuterFrameWidth -
104  (barrel->mBeamLineSectionNum-1)*layer->mInnerFrameWidth)/barrel->mBeamLineSectionNum;
105  double singleSectorZspacing = singleSectorLength + layer->mInnerFrameWidth;
106 
107  // Then inner frame rings (in case more than 1 section);
108  {
109  char innerFrameVolumeName[128];
110  snprintf(innerFrameVolumeName, 128-1, "%sInnerFrameVolume%02d", detName, bl);
111 
112  TGeoTube *iframe = new TGeoTube(innerFrameVolumeName,
113  barrel->mRadius,
114  barrel->mRadius + layer->mInnerFrameThickness,
115  layer->mInnerFrameWidth/2);
116  TGeoVolume *viframe = new TGeoVolume(innerFrameVolumeName, iframe, GetMedium("MuMegasCarbonFiber"));
117 
118  for(unsigned iz=0; iz<barrel->mBeamLineSectionNum-1; iz++) {
119  double zOffset = singleSectorZspacing*(iz - (barrel->mBeamLineSectionNum-2)/2.);
120 
121  vbcontainer->AddNode(viframe, iz, new TGeoCombiTrans(0.0, 0.0, zOffset, 0));
122  } //for iz
123  }
124 
125  // Figure out asimuthal "clear acceptance" angular range occupied by each sector;
126  double circumference = 2.0 * TMath::Pi() * barrel->mRadius;
127  double clearAcceptanceFraction =
128  (circumference - barrel->mAsimuthalSectorNum*layer->mInnerFrameWidth)/circumference;
129  double singleSectorAngle = 360.0 * clearAcceptanceFraction / barrel->mAsimuthalSectorNum;
130 
131  // Define single sector gas container volume;
132  char sectorContainerVolumeName[128];
133  snprintf(sectorContainerVolumeName, 128-1, "%sSectorContainerVolume%02d", detName, bl);
134  {
135  // Funny enough, it looks like TGeoTubs has a bug in the navigation methods; but
136  // TGeoCtub, which is more generic, works; see also MuMegasGeoParData::PlaceMaterialLayer();
137  TGeoCtub *sector = new TGeoCtub(sectorContainerVolumeName,
138  barrel->mRadius,
139  barrel->mRadius + gasSectorThickness,
140  singleSectorLength/2,
141  0.0, singleSectorAngle,
142  0, 0, -1, 0, 0, 1);
143  TGeoVolume *vsector = new TGeoVolume(sectorContainerVolumeName, sector, GetMedium(layer->mGasMixture));
144 
145  // Place them all into the air container volume;
146  for(unsigned ir=0; ir<barrel->mAsimuthalSectorNum; ir++) {
147  TGeoRotation *rw = 0;
148  if (ir) {
149  rw = new TGeoRotation();
150  rw->RotateZ(ir*360./barrel->mAsimuthalSectorNum);
151  } //if
152 
153  for(unsigned iz=0; iz<barrel->mBeamLineSectionNum; iz++) {
154  double zOffset = singleSectorZspacing*(iz - (barrel->mBeamLineSectionNum-1)/2.);
155 
156  vbcontainer->AddNode(vsector, ir*barrel->mBeamLineSectionNum+iz,
157  new TGeoCombiTrans(0.0, 0.0, zOffset, rw));
158  } //for iz
159  } //for ir
160 
161  // Populate gas sector with essential material layers;
162  {
163  double rOffset = barrel->mRadius;
164 
165  PlaceMaterialLayer(detName, "ReadoutPcb", bl, vsector,
166  layer->mReadoutPcbMaterial.Data(),
167  singleSectorLength, singleSectorAngle,
168  layer->mReadoutPcbThickness,
169  &rOffset);
170 
171  PlaceMaterialLayer(detName, "ReadoutStrips", bl, vsector,
172  "copper",
173  singleSectorLength, singleSectorAngle,
174  layer->mCopperStripThickness,
175  &rOffset);
176 
177  PlaceMaterialLayer(detName, "AmplificationRegion", bl, vsector,
178  layer->mGasMixture.Data(),
179  singleSectorLength, singleSectorAngle,
181  &rOffset);
182 
183  PlaceMaterialLayer(detName, "SteelMesh", bl, vsector,
184  "iron",
185  singleSectorLength, singleSectorAngle,
186  layer->mSteelMeshThickness,
187  &rOffset);
188 
189  PlaceMaterialLayer(detName, "ConversionRegion", bl, vsector,
190  layer->mGasMixture.Data(),
191  // FIXME: WTH is this?!;
192  singleSectorLength, singleSectorAngle - 1.0,
194  &rOffset);
195 
196  PlaceMaterialLayer(detName, "ExitWindow", bl, vsector,
197  layer->mExitWindowMaterial.Data(),
198  singleSectorLength, singleSectorAngle,
199  layer->mExitWindowThickness,
200  &rOffset);
201  }
202  }
203 
204  // Define and place beam-aligned pieces of support frames;
205  {
206  char sectorFrameVolumeName[128];
207  snprintf(sectorFrameVolumeName, 128-1, "%sSectorFrameVolume%02d", detName, bl);
208  double singleSectorFrameAngle = 360./barrel->mAsimuthalSectorNum - singleSectorAngle;
209  TGeoCtub *sframe = new TGeoCtub(sectorFrameVolumeName,
210  barrel->mRadius,
211  barrel->mRadius + layer->mInnerFrameThickness,
212  singleSectorLength/2,
213  0.0,
214  singleSectorFrameAngle,
215  0, 0, -1, 0, 0, 1);
216  TGeoVolume *vsframe = new TGeoVolume(sectorFrameVolumeName, sframe, GetMedium("MuMegasCarbonFiber"));
217 
218  for(unsigned ir=0; ir<barrel->mAsimuthalSectorNum; ir++) {
219  TGeoRotation *rw = new TGeoRotation();
220  rw->RotateZ(ir*360./barrel->mAsimuthalSectorNum + singleSectorAngle);
221 
222  for(unsigned iz=0; iz<barrel->mBeamLineSectionNum; iz++) {
223  double zOffset = singleSectorZspacing*(iz - (barrel->mBeamLineSectionNum-1)/2.);
224 
225  vbcontainer->AddNode(vsframe, ir*barrel->mBeamLineSectionNum+iz,
226  new TGeoCombiTrans(0.0, 0.0, zOffset, rw));
227  } //for iz
228  } //for ir
229  }
230 
231  // Yes, one map per layer; FIXME: conversion volume name should be calculated once;
232  // also may want to unify with the other [ir..iz] loop;
233  {
235 
236  EicGeoMap *fgmap = CreateNewMap();
237 
238  char conversionVolumeName[128];
239  snprintf(conversionVolumeName, 128-1, "%s%s%02d", detName, "ConversionRegion", bl);
240 
241  fgmap->AddGeantVolumeLevel(conversionVolumeName, 0);
242  fgmap->AddGeantVolumeLevel(sectorContainerVolumeName, barrel->mAsimuthalSectorNum * barrel->mBeamLineSectionNum);
243 
244  fgmap->SetSingleSensorContainerVolume(conversionVolumeName);
245 
246  for(unsigned ir=0; ir<barrel->mAsimuthalSectorNum; ir++)
247  for(unsigned iz=0; iz<barrel->mBeamLineSectionNum; iz++) {
248  UInt_t geant[2] = {0, ir*barrel->mBeamLineSectionNum+iz}, logical[3] = {ir, 0, iz};
249 
250  if (SetMappingTableEntry(fgmap, geant, bl, logical)) {
251  cout << "Failed to set mapping table entry!" << endl;
252  exit(0);
253  } //if
254  } //for ir..iz
255  }
256  } //for bl
257 
258  GetColorTable() ->AddPatternMatch("Frame", kGray);
259  // Make the rest half transparent;
260  GetColorTable() ->AddPatternMatch("ReadoutPcb", kGreen+3);
261  if (mTransparency)
263  GetColorTable() ->AddPatternMatch("ExitWindow", kOrange+2);
264  if (mTransparency)
266 
267  // Place this stuff as a whole into the top volume and write out;
268  FinalizeOutput(root, gdml, check);
269 
270  return 0;
271 } // MuMegasGeoParData::ConstructGeometry()
272 
273 // ---------------------------------------------------------------------------------------
274 
275 void MuMegasGeoParData::PlaceMaterialLayer(const char *detName, const char *volumeNamePrefix,
276  unsigned barrelID,
277  TGeoVolume *sectorContainer, const char *material,
278  double length, double angle,
279  double thickness, double *rOffset)
280 {
281  char volumeName[128];
282 
283  snprintf(volumeName, 128-1, "%s%s%02d", detName, volumeNamePrefix, barrelID);
284  TGeoCtub *shape = new TGeoCtub(volumeName,
285  *rOffset,
286  *rOffset + thickness,
287  length/2,
288  0.0,
289  angle,
290  0, 0, -1, 0, 0, 1);
291  TGeoVolume *vshape = new TGeoVolume(volumeName, shape, GetMedium(material));
292 
293  sectorContainer->AddNode(vshape, 0, new TGeoCombiTrans(0.0, 0.0, 0.0, 0));
294 
295  *rOffset += thickness;
296 } // MuMegasGeoParData::PlaceMaterialLayer()
297 
298 // ---------------------------------------------------------------------------------------
299