EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MapsGeoParData.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MapsGeoParData.cxx
1 //
2 // AYK (ayk@bnl.gov), 2014/08/07
3 //
4 // MAPS geometry description file;
5 //
6 
7 #include <iostream>
8 using namespace std;
9 
10 #include <assert.h>
11 
12 #include <MapsGeoParData.h>
13 
14 #include <TMath.h>
15 #include <TGeoTrd1.h>
16 #include <TGeoArb8.h>
17 #include <TGeoTube.h>
18 #include <TGeoTorus.h>
19 #include <TGeoCompositeShape.h>
20 
21 #include <MapsGeoParData.h>
22 #include <MapsMimosaAssembly.h>
23 
24 // ---------------------------------------------------------------------------------------
25 
27 {
28  const char *detName = mDetName->Name().Data();
29 
30  // Do not mind to create different names for each layer, even if some layers
31  // have the same building blocks;
32  char flexName[128], aluStripName[128], flatRoofName[128], roofSideBeamName[128];
33  char waterPipeName[128], waterName[128], apexEnforcementBeamName[128];
34  char coldPlateName[128], sideWallName[128], baseEnforcementBeamName[128];
35 
36  snprintf(flexName, 128-1, "%sCellFlexLayer%02d", detName, id);
37  snprintf(aluStripName, 128-1, "%sAluStrips%02d", detName, id);
38  snprintf(coldPlateName, 128-1, "%sColdPlate%02d", detName, id);
39  snprintf(mMimosaShellName, 128-1, "%sMimosaShell%02d", detName, id);
40  snprintf(mMimosaCoreName, 128-1, "%sMimosaCore%02d", detName, id);
41  snprintf(waterPipeName, 128-1, "%sWaterPipe%02d", detName, id);
42  snprintf(waterName, 128-1, "%sWater%02d", detName, id);
43  snprintf(apexEnforcementBeamName, 128-1, "%sEnforcementBeamApex%02d", detName, id);
44  snprintf(baseEnforcementBeamName, 128-1, "%sEnforcementBeamBase%02d", detName, id);
45  snprintf(sideWallName, 128-1, "%sSideWall%02d", detName, id);
46  snprintf(flatRoofName, 128-1, "%sFlatRoof%02d", detName, id);
47  snprintf(roofSideBeamName, 128-1, "%sRoofSideBeam%02d", detName, id);
48  snprintf(mCellAssemblyName, 128-1, "%sChipAssembly%02d", detName, id);
49 
50  // Used throughout the code;
51  //mAssemblyHeight = (mcell->mAssemblyBaseWidth/2)*
52  //tan(mcell->mAssemblySideSlope*TMath::Pi()/180.);
53  mAssemblyHeight = mcell->GetAssemblyHeight();
54  mAssemblyLength = mcell->GetAssemblyLength();
55 
56  // Compose elementary cell volume with the Mimosa 34 chip inside;
57  TGeoVolume *vcell;
58  if (UseTriangularAssemblies()) {
59  // This is fine for the VST;
60  TGeoTrd1 *trd1 = new TGeoTrd1(mCellAssemblyName,
61  0.1 * mcell->mAssemblyBaseWidth/2,
62  0.0,
63  0.1 * mAssemblyLength/2,
64  0.1 * mAssemblyHeight/2);
65 
66  vcell = new TGeoVolume(mCellAssemblyName, trd1, GetMedium(_AIR_));
67  }
68  else {
69  char tmp1Name[128], tmp2Name[128];
70 
71  snprintf(tmp1Name, 128-1, "%sTmp1Volume%02d", detName, id);
72  snprintf(tmp2Name, 128-1, "%sTmp2Volume%02d", detName, id);
73 
74  assert(0);
75  // For FST/BST have to cut triangular cell edges, otherwise can not come close enough
76  // to the beam pipe; TGeoCompositeShape has problems with drawing of course, but
77  // I set it invisible in eventDisplay.C anyway; NB: one could arrange Arb8 shape with
78  // only one edge cut, but then I'd have to re-orient all the subvolumes because Z axis
79  // would be oriented differently -> forget it;
80  TGeoTrd1 *tmp1 = new TGeoTrd1(tmp1Name,
81  0.1 * mcell->mAssemblyBaseWidth/2,
82  0.0,
83  0.1 * mAssemblyLength/2,
84  0.1 * mAssemblyHeight/2);
85  TGeoBBox *tmp2 = new TGeoBBox(tmp2Name,
86  0.1 * mcell->mAssemblyBaseWidth/2,
87  //0.1 * mcell->mAssemblyDeadMaterialWidth/2,
88  0.1 * mAssemblyLength/2,
89  0.1 * mAssemblyHeight/2);
90  TGeoCompositeShape *cs = new TGeoCompositeShape(mCellAssemblyName, TString(tmp1Name) + "*" + TString(tmp2Name));
91 
92  vcell = new TGeoVolume(mCellAssemblyName, cs, GetMedium(_AIR_));
93  } //if
94 
95  double aluThickness = 0.0, kaptonThickness = 0.0, carbonThickness = 0.0, waterThickness = 0.0;
96 
97  // A running variable (accumulated offset);
98  double zOffset = -mAssemblyHeight/2;
99 
100  // Create internal chip assembly cell structure;
101  {
102  //
103  // FIXME: make a routine to add a single Z-layer;
104  //
105 
106  // Flex Printed Circuit;
107  {
108 
109  if (GetGeometryType() == MapsGeoParData::NoStructure)
110  kaptonThickness += mcell->mFlexCableKaptonThickness;
111  else {
112  TGeoBBox *flex = new TGeoBBox(flexName,
113  0.1 * mcell->mAssemblyDeadMaterialWidth/2,
114  0.1 * mAssemblyLength/2,
115  0.1 * mcell->mFlexCableKaptonThickness/2);
116  TGeoVolume *vflex = new TGeoVolume(flexName, flex, GetMedium(mKaptonMaterial));
117 
118  vcell->AddNode(vflex, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * (zOffset + mcell->mFlexCableKaptonThickness/2), 0));
119  } //if
120 
121  // Yes, want to keep precise track on the silicon chip final offset, so it is the same in
122  // all three "fs", "ss", "ns" geometries;
123  zOffset += mcell->mFlexCableKaptonThickness;
124  }
125 
126  // Alu strips;
127  {
128  if (GetGeometryType() == MapsGeoParData::NoStructure)
129  aluThickness += mcell->mFlexCableAluThickness;
130  else {
131  TGeoBBox *alu = new TGeoBBox(aluStripName,
132  0.1 * mcell->mAssemblyDeadMaterialWidth/2,
133  0.1 * mAssemblyLength/2,
134  0.1 * mcell->mFlexCableAluThickness/2);
135  TGeoVolume *valu = new TGeoVolume(aluStripName, alu, GetMedium(_ALUMINUM_));
136 
137  vcell->AddNode(valu, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * (zOffset + mcell->mFlexCableAluThickness/2), 0));
138  } //if
139 
140  zOffset += mcell->mFlexCableAluThickness;
141  }
142 
143  // Mimosa chips; keep this structure in all theree geometry versions;
144  {
145  TGeoBBox *mimosa = new TGeoBBox(mMimosaShellName,
146  0.1 * mcell->mChipWidth/2,
147  0.1 * mcell->mChipLength/2,
148  0.1 * mcell->mChipThickness/2);
149  TGeoVolume *vmimosa = new TGeoVolume(mMimosaShellName, mimosa, GetMedium(_SILICON_));
150 
151  mMimosaOffset = zOffset;
152  vcell->AddNode(vmimosa, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * (zOffset + mcell->mChipThickness/2), 0));
153 
154  zOffset += mcell->mChipThickness;
155 
156  // Mimosa chips sensitive layer;
157  {
158  TGeoBBox *micore = new TGeoBBox(mMimosaCoreName,
159  0.1 * (mcell->mChipWidth - mcell->mChipDeadAreaWidth)/2,
160  0.1 * mcell->mChipLength/2,
161  0.1 * mcell->mChipActiveZoneThickness/2);
162  TGeoVolume *vmicore = new TGeoVolume(mMimosaCoreName, micore, GetMedium(_SILICON_));
163 
164  // NB: shift active area to the side in local X direction; NB: don't change '-' here,
165  // otherwise will need to modify rotations in FST/BST in order to bring chips more close
166  // to the beam line;
167  vmimosa->AddNode(vmicore, 0, new TGeoCombiTrans(0.1 * (-mcell->mChipDeadAreaWidth/2), 0.0, 0.0, 0));
168  }
169  }
170 
171  // Cold plate;
172  {
173  if (GetGeometryType() == MapsGeoParData::NoStructure)
174  carbonThickness += mcell->mColdPlateThickness;
175  else {
176  TGeoBBox *cold = new TGeoBBox(coldPlateName,
177  0.1 * mcell->mAssemblyDeadMaterialWidth/2,
178  0.1 * mAssemblyLength/2,
179  0.1 * mcell->mColdPlateThickness/2);
180  TGeoVolume *vcold = new TGeoVolume(coldPlateName, cold, GetMedium(mCarbonFiberMaterial));
181 
182  vcell->AddNode(vcold, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * (zOffset + mcell->mColdPlateThickness/2), 0));
183  } //if
184 
185  zOffset += mcell->mColdPlateThickness;
186  }
187 
188  // Water pipes;
189  {
190  double waterPipeOuterDiameter = mcell->mWaterPipeInnerDiameter + 2*mcell->mWaterPipeWallThickness;
191 
192  if (GetGeometryType() == MapsGeoParData::NoStructure)
193  {
194  // FIXME: make a function call;
195  double effectiveWaterThickness =
196  (TMath::Pi()*(mcell->mWaterPipeInnerDiameter * mcell->mWaterPipeInnerDiameter)/4.)/
198 
199  // NB: 2 pipes ...;
200  waterThickness += 2*effectiveWaterThickness;
201 
202  double effectiveKaptonThickness =
203  (TMath::Pi()*(waterPipeOuterDiameter * waterPipeOuterDiameter)/4.)/
205  // NB: 2 pipes ...;
206  kaptonThickness += 2*(effectiveKaptonThickness - effectiveWaterThickness);
207  }
208  else {
209  TGeoTube *wpipe = new TGeoTube(waterPipeName,
210  0.1 * mcell->mWaterPipeInnerDiameter/2,
211  0.1 * waterPipeOuterDiameter/2,
212  0.1 * mAssemblyLength/2);
213  TGeoVolume *vwpipe = new TGeoVolume(waterPipeName, wpipe, GetMedium(mKaptonMaterial));
214 
215  // Water itself;
216  TGeoTube *water = new TGeoTube(waterName,
217  0.0,
218  0.1 * mcell->mWaterPipeInnerDiameter/2,
219  0.1 * mAssemblyLength/2);
220  TGeoVolume *vwater = new TGeoVolume(waterName, water, GetMedium(_WATER_));
221 
222  TGeoRotation *rw = new TGeoRotation();
223  rw->RotateX(90);
224 
225  // Yes, 15mm split in 5+5+5mm distances according to ALICE TRD;
226  mWaterPipeXoffset = mcell->mChipWidth/(2*3);
227  mWaterPipeZoffset = zOffset + waterPipeOuterDiameter/2;
228 
229  for(unsigned lr=0; lr<2; lr++) {
230  double xOffset = (lr ? -1.0 : 1.0)*mWaterPipeXoffset;
231 
232  vcell->AddNode(vwpipe, lr, new TGeoCombiTrans(0.1 * xOffset, 0.0, 0.1 * mWaterPipeZoffset, rw));
233  vcell->AddNode(vwater, lr, new TGeoCombiTrans(0.1 * xOffset, 0.0, 0.1 * mWaterPipeZoffset, rw));
234  } //for lr
235  } //if
236  }
237 
238  // Base and apex enforcement beams;
239  if (GetGeometryType() == MapsGeoParData::NoStructure)
240  {
241  double slope = mcell->mAssemblySideSlope*TMath::Pi()/180.;
242 
243  carbonThickness +=
244  // Apex beam (as two halves);
245  (TMath::Pi()*(mcell->mApexEnforcementBeamDiameter * mcell->mApexEnforcementBeamDiameter)/4. +
246  // 2x base triangular beams;
247  2*(mcell->mBaseEnforcementBeamWidth*mcell->mBaseEnforcementBeamWidth*tan(slope)/2))/
249  }
250  else
251  {
252  double slope = mcell->mAssemblySideSlope*TMath::Pi()/180.;
253 
254  // Apex beam;
255  TGeoTube *abeam = new TGeoTube(apexEnforcementBeamName,
256  0.0,
257  0.1 * mcell->mApexEnforcementBeamDiameter/2,
258  0.1 * mAssemblyLength/2);
259  TGeoVolume *vabeam = new TGeoVolume(apexEnforcementBeamName, abeam, GetMedium(mCarbonFiberMaterial));
260 
261  TGeoRotation *rw = new TGeoRotation();
262  rw->RotateX(90);
263 
264  {
265  double hOffset = zOffset +
266  (mcell->mAssemblyDeadMaterialWidth/2)*tan(slope) - (mcell->mApexEnforcementBeamDiameter/2)/cos(slope);
267  vcell->AddNode(vabeam, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * hOffset, rw));
268  }
269 
270  // Base beams; have to resort to Arb8 shape, sorry;
271  double width = 0.1 * mcell->mBaseEnforcementBeamWidth;
272  double length = 0.1 * mAssemblyLength;
273 
274  double vert[8][2] = {
275  {-width, -length/2},
276  {-width, length/2},
277  { 0, length/2},
278  { 0, -length/2},
279  { 0, -length/2},
280  { 0, length/2},
281  { 0, length/2},
282  { 0, -length/2}
283  };
284 
285  double baseBeamHeight = mcell->mBaseEnforcementBeamWidth*tan(slope);
286  TGeoArb8 *bbeam = new TGeoArb8(baseEnforcementBeamName, 0.1 * baseBeamHeight/2, (double*)vert);
287  TGeoVolume *vbbeam = new TGeoVolume(baseEnforcementBeamName, bbeam, GetMedium(mCarbonFiberMaterial));
288  {
289  double hOffset = zOffset + baseBeamHeight/2;
290 
291  for(unsigned lr=0; lr<2; lr++) {
292  double xOffset = (lr ? 1.0 : -1.0)*(mcell->mAssemblyDeadMaterialWidth/2 - mcell->mBaseEnforcementBeamWidth);
293 
294  TGeoRotation *rw = new TGeoRotation();
295  if (lr) rw->RotateZ(180);
296 
297  vcell->AddNode(vbbeam, lr, new TGeoCombiTrans(0.1 * xOffset, 0.0, 0.1 * hOffset, rw));
298  } //for lr
299  }
300  } //if
301 
302  // Side walls; it looks like those are present in ALICE design;
303  {
304  double radangle = mcell->mAssemblySideSlope*TMath::Pi()/180.;
305 
306  double sideWallWidth = (mcell->mAssemblyDeadMaterialWidth/2)/cos(mcell->mAssemblySideSlope*TMath::Pi()/180.);
307 
308  // Do not be pedantic, finally; place rectangular beams; assume, that 1) available width
309  // in any of those 4 slots is "1/4 of the total cell length - beam width" and beam is
310  // aligned along the diagonal of this space;
311  double slotWidth = mAssemblyLength/4 - mcell->mEnforcementStripWidth;
312  double slotHeight = sideWallWidth;
313 
314  double radSlope = atan(slotWidth/slotHeight);
315  double degSlope = radSlope*180./TMath::Pi();
316 
317  double beamLength = sqrt(slotWidth*slotWidth + slotHeight*slotHeight) -
318  2*(mcell->mEnforcementStripWidth/2)/tan(radSlope);
319 
320  double fullThickness;
321  if (GetGeometryType() == MapsGeoParData::FullStructure)
322  fullThickness = mcell->mSideWallThickness + mcell->mEnforcementStripThickness;
323  else
324  fullThickness = mcell->mSideWallThickness +
325  mcell->mEnforcementStripThickness*(4*beamLength*mcell->mEnforcementStripWidth)/(mAssemblyLength*sideWallWidth);
326 
327  if (GetGeometryType() == MapsGeoParData::NoStructure)
328  // NB: 2 sides ...;
329  carbonThickness += fullThickness*(2*sideWallWidth/mcell->mAssemblyDeadMaterialWidth);
330  else {
331  // Side wall volume; air container in case of full geometry; a single thin carbon layer
332  // in case of beam-line-uniform geometry;
333  TGeoBBox *side = new TGeoBBox(sideWallName,
334  0.1 * sideWallWidth/2,
335  0.1 * mAssemblyLength/2,
336  0.1 * fullThickness/2);
337  TGeoVolume *vside;
338  if (GetGeometryType() == MapsGeoParData::SimpleStructure)
339  vside = new TGeoVolume(sideWallName, side, GetMedium(mCarbonFiberMaterial));
340  else {
341  vside = new TGeoVolume(sideWallName, side, GetMedium(_AIR_));
342 
343  // Side wall solid thin layer (roof);
344  {
345  TGeoBBox *flat = new TGeoBBox(flatRoofName,
346  0.1 * sideWallWidth/2,
347  0.1 * mAssemblyLength/2,
348  0.1 * mcell->mSideWallThickness/2);
349  TGeoVolume *vflat = new TGeoVolume(flatRoofName, flat, GetMedium(mCarbonFiberMaterial));
350 
351  vside->AddNode(vflat, 2, new TGeoCombiTrans(0.0, 0.0, 0.1 * mcell->mEnforcementStripThickness/2, 0));
352  }
353 
354  // 4x roof enforcement beams;
355  {
356 
357  TGeoBBox *beam = new TGeoBBox(roofSideBeamName,
358  0.1 * beamLength/2,
359  0.1 * mcell->mEnforcementStripWidth/2,
360  0.1 * mcell->mEnforcementStripThickness/2);
361  TGeoVolume *vbeam = new TGeoVolume(roofSideBeamName, beam, GetMedium(mCarbonFiberMaterial));
362 
363  for(unsigned iq=0; iq<4; iq++) {
364  double qOffset = (mAssemblyLength/4)*(iq - 1.5);
365 
366  TGeoRotation *rw = new TGeoRotation();
367  rw->RotateZ((iq%2 ? -1. : 1.)*degSlope);
368 
369  vside->AddNode(vbeam, iq, new TGeoCombiTrans(0.0, 0.1 * qOffset, -0.1 * mcell->mSideWallThickness/2, rw));
370  } //for iq
371  }
372  } //if
373 
374  // Place both side walls into the assembly;
375  {
376  double hOffset = zOffset + (fullThickness/2)*cos(radangle) + (sideWallWidth/2)*sin(radangle);
377 
378  for(unsigned lr=0; lr<2; lr++) {
379  double xOffset = (lr ? -1.0 : 1.0)*(mcell->mAssemblyDeadMaterialWidth/2 +
380  (fullThickness/2)*sin(radangle) -
381  (sideWallWidth/2)*cos(radangle));
382 
383  TGeoRotation *rw = new TGeoRotation();
384  if (lr)
385  rw->SetAngles(90.0 + mcell->mAssemblySideSlope, 0.0 + 180.0, 90.0, 90.0 + 180.0, 0.0 - mcell->mAssemblySideSlope, 0.0);
386  else
387  rw->SetAngles(90.0 + mcell->mAssemblySideSlope, 0.0, 90.0, 90.0, 0.0 + mcell->mAssemblySideSlope, 0.0);
388 
389  vcell->AddNode(vside, lr, new TGeoCombiTrans(0.1 *xOffset, 0.0, 0.1 * hOffset, rw));
390  } //for lr
391  }
392  } //if
393  }
394  }
395 
396  //cout << GetMedium(mCarbonFiberMaterial)->GetMaterial()->GetRadLen() << endl; exit(0);
397 
398  // Place a single equivalent thickness layer parallel to the assembly base;
399  if (GetGeometryType() == MapsGeoParData::NoStructure)
400  {
401  // FIXME: may want to re-write this stuff in a better way once get rid of CINT (so that
402  // at least std::vector is available);
403  double aluRadLen, kaptonRadLen, carbonRadLen, waterRadLen;
404 
405  //printf("%f %f %f %f\n", aluThickness, kaptonThickness, carbonThickness, waterThickness);
406 
407  aluRadLen = 0.1 * aluThickness / GetMedium(_ALUMINUM_)->GetMaterial()->GetRadLen();
408  kaptonRadLen = 0.1 * kaptonThickness / GetMedium(mKaptonMaterial)->GetMaterial()->GetRadLen();
409  carbonRadLen = 0.1 * carbonThickness / GetMedium(mCarbonFiberMaterial)->GetMaterial()->GetRadLen();
410  waterRadLen = 0.1 * waterThickness / GetMedium(_WATER_)->GetMaterial()->GetRadLen();
411  //printf("%f %f %f %f\n", 100*aluRadLen, 100*kaptonRadLen, 100*carbonRadLen, 100*waterRadLen);
412 
413  // Effective carbon fiber layer thickness;
414  double equivalentCarbonThickness = 10. * (aluRadLen + kaptonRadLen + carbonRadLen + waterRadLen)*
415  GetMedium(mCarbonFiberMaterial)->GetMaterial()->GetRadLen();
416  //printf("%f\n", equivalentCarbonThickness);
417 
418  // NB: full thickness may not fit into the triangular profile above the silicon chip layer ->
419  // split into two; first layer goes below silicon chip, second one (if needed) - above it;
420  {
421  double offsetFromBottomSide = mMimosaOffset + mAssemblyHeight/2;
422  // Let first layer mask itself as a flex cable;
423  double equivalentFlexThickness =
424  equivalentCarbonThickness < offsetFromBottomSide ? equivalentCarbonThickness : offsetFromBottomSide;
425 
426  TGeoBBox *flex = new TGeoBBox(flexName,
427  0.1 * mcell->mAssemblyDeadMaterialWidth/2,
428  0.1 * mAssemblyLength/2,
429  0.1 * equivalentFlexThickness/2);
430  TGeoVolume *vflex = new TGeoVolume(flexName, flex, GetMedium(mCarbonFiberMaterial));
431 
432  vcell->AddNode(vflex, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * (equivalentFlexThickness - mAssemblyHeight)/2, 0));
433 
434  double equivalentColdThickness = equivalentCarbonThickness - equivalentFlexThickness;
435 
436  if (equivalentColdThickness > 0.0) {
437  // Let it be called cold plate;
438  TGeoBBox *cold = new TGeoBBox(coldPlateName,
439  0.1 * mcell->mAssemblyDeadMaterialWidth/2,
440  0.1 * mAssemblyLength/2,
441  0.1 * equivalentColdThickness/2);
442  TGeoVolume *vcold = new TGeoVolume(coldPlateName, cold, GetMedium(mCarbonFiberMaterial));
443 
444  // Yes, zOffset is still a valid current variable here; there will be a gap because of
445  // missing pipes; ignore;
446  vcell->AddNode(vcold, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * (zOffset + equivalentColdThickness/2), 0));
447  } //if
448  }
449  } //if
450 
451  return vcell;
452 } // MapsGeoParData::ConstructMimosaCell()
453 
454 // ---------------------------------------------------------------------------------------
455 
456 MapsStave *MapsGeoParData::ConstructStave(unsigned chipNum, unsigned id,
457  MapsMimosaAssembly *mcell)
458 {
459  const char *detName = mDetName->Name().Data();
460 
461  TGeoVolume *vcell = ConstructMimosaCell(mcell, id);
462 
463  char staveName[128], waterPipeName[128], waterName[128];
464  char bracketName[128], waterTorusPipeName[128], waterTorusName[128];
465 
466  snprintf(staveName, 128-1, "%sStave%02d", detName, id);
467  snprintf(bracketName, 128-1, "%sStaveBracket%02d", detName, id);
468  snprintf(waterTorusPipeName, 128-1, "%sStaveWaterPipeTorus%02d", detName, id);
469  snprintf(waterTorusName, 128-1, "%sStaveWaterTorus%02d", detName, id);
470  snprintf(waterPipeName, 128-1, "%sStaveWaterPipe%02d", detName, id);
471  snprintf(waterName, 128-1, "%sStaveWater%02d", detName, id);
472 
473  MapsStave *stave = new MapsStave(staveName);
474  //stave->SetName(staveName);
475 
476  //
477  // Compose stave volume; yes, for VST they are simple TRD1 volumes; for now just
478  // take it of exactly N time chip assembly size + a bracket and pipes;
479  //
480 
481  // NB: for now do not mind to do stave setup front/back symmetric
482  // in terms of elementary cell location;
483  //stave->mLength = chipNum * mAssemblyLength + 2*mEnforcementBracketThickness +
484  //2*mWaterPipeExtensionLength;
485  stave->mLength = GetExpectedStaveLength(chipNum, mcell);
486 
487  if (UseTriangularAssemblies()) {
488  TGeoTrd1 *qstave = new TGeoTrd1(staveName,
489  0.1 * mcell->mAssemblyBaseWidth/2,
490  0.0,
491  0.1 * stave->mLength/2,
492  0.1 * mAssemblyHeight/2);
493  stave->mVolume = new TGeoVolume(staveName, qstave, GetMedium(_AIR_));
494  }
495  else {
496  char tmp1Name[128], tmp2Name[128];
497 
498  snprintf(tmp1Name, 128-1, "%sTmp1Volume%02d", detName, id);
499  snprintf(tmp2Name, 128-1, "%sTmp2Volume%02d", detName, id);
500 
501  assert(0);
502  // Same stuff as in MapsGeoParData::ConstructMimosaCell();
503  TGeoTrd1 *tmp1 = new TGeoTrd1(tmp1Name,
504  0.1 * mcell->mAssemblyBaseWidth/2,
505  0.0,
506  0.1 * stave->mLength/2,
507  0.1 * mAssemblyHeight/2);
508  TGeoBBox *tmp2 = new TGeoBBox(tmp2Name,
509  0.1 * mcell->mAssemblyBaseWidth/2,
510  //0.1 * mcell->mAssemblyDeadMaterialWidth/2,
511  0.1 * stave->mLength/2,
512  0.1 * mAssemblyHeight/2);
513  TGeoCompositeShape *cs = new TGeoCompositeShape(staveName, TString(tmp1Name) + "*" + TString(tmp2Name));
514 
515  stave->mVolume = new TGeoVolume(staveName, cs, GetMedium(_AIR_));
516  } //if
517 
518  // Place chip assemblies into the stave volume;
519  for(unsigned nn=0; nn<chipNum; nn++) {
520  double yOffset = (nn - 0.5*(chipNum-1))*mAssemblyLength;
521 
522  stave->mVolume->AddNode(vcell, nn, new TGeoCombiTrans(0.0, 0.1 * yOffset, 0.0, 0));
523  } //for nn
524 
525  // Place two brackets at the end of assembly; let them be always present, for all geometry types;
526  if (WithEnforcementBrackets()) {
527  TGeoTrd1 *bracket = new TGeoTrd1(bracketName,
528  0.1 * mcell->mAssemblyDeadMaterialWidth/2,
529  0.0,
530  0.1 * mEnforcementBracketThickness/2,
531  0.1 * mAssemblyHeight/2);
532  TGeoVolume *vbracket = new TGeoVolume(bracketName, bracket, GetMedium(mCarbonFiberMaterial));
533 
534  for(unsigned ud=0; ud<2; ud++) {
535  double yOffset = (ud ? -1.0 : 1.0)*(chipNum * mAssemblyLength + mEnforcementBracketThickness)/2;
536 
537  stave->mVolume->AddNode(vbracket, ud, new TGeoCombiTrans(0.0, 0.1 * yOffset, 0.0, 0));
538  } //for ud
539  } //if
540 
541  if (WithExternalPipes() &&
542  GetGeometryType() == MapsGeoParData::FullStructure) {
543  double waterPipeOuterDiameter = mcell->mWaterPipeInnerDiameter + 2*mcell->mWaterPipeWallThickness;
544 
545  // Place straight water pipe pieces at the upstream end; FIXME: unify with maps-lib.C later;
546  {
547  TGeoTube *wpipe = new TGeoTube(waterPipeName,
548  0.1 * mcell->mWaterPipeInnerDiameter/2,
549  0.1 * waterPipeOuterDiameter/2,
550  0.1 * mWaterPipeExtensionLength/2);
551  TGeoVolume *vwpipe = new TGeoVolume(waterPipeName, wpipe, GetMedium(mKaptonMaterial));
552 
553  // Water itself;
554  TGeoTube *water = new TGeoTube(waterName,
555  0.0,
556  0.1 * mcell->mWaterPipeInnerDiameter/2,
557  0.1 * mWaterPipeExtensionLength/2);
558  TGeoVolume *vwater = new TGeoVolume(waterName, water, GetMedium(_WATER_));
559 
560  TGeoRotation *rw = new TGeoRotation();
561  rw->RotateX(90);
562 
563  for(unsigned lr=0; lr<2; lr++) {
564  double xOffset = (lr ? -1.0 : 1.0)*mWaterPipeXoffset;
565  double yOffset = (stave->mLength - mWaterPipeExtensionLength)/2;
566 
567  stave->mVolume->AddNode(vwpipe, lr, new TGeoCombiTrans(0.1 * xOffset, 0.1 * yOffset, 0.1 * mWaterPipeZoffset, rw));
568  stave->mVolume->AddNode(vwater, lr, new TGeoCombiTrans(0.1 * xOffset, 0.1 * yOffset, 0.1 * mWaterPipeZoffset, rw));
569  } //for lr
570  }
571 
572  // Place round U-pieces at the downstream end;
573  {
574  TGeoTorus *wtpipe = new TGeoTorus(waterTorusPipeName,
575  0.1 * mWaterPipeXoffset,
576  0.1 * mcell->mWaterPipeInnerDiameter/2,
577  0.1 * waterPipeOuterDiameter/2,
578  180.0, 180.);
579  TGeoVolume *vwtpipe = new TGeoVolume(waterTorusPipeName, wtpipe, GetMedium(mKaptonMaterial));
580 
581 
582  // Water itself;
583  TGeoTorus *twater = new TGeoTorus(waterTorusName,
584  0.1 * mWaterPipeXoffset,
585  0.0,
586  0.1 * mcell->mWaterPipeInnerDiameter/2,
587  180.0, 180.);
588  TGeoVolume *vtwater = new TGeoVolume(waterTorusName, twater, GetMedium(_WATER_));
589 
590  double qyOffset = chipNum * mAssemblyLength/2 + mEnforcementBracketThickness;
591  stave->mVolume->AddNode(vwtpipe, 0, new TGeoCombiTrans(0.0, -0.1 * qyOffset, 0.1 * mWaterPipeZoffset, 0));
592  stave->mVolume->AddNode(vtwater, 0, new TGeoCombiTrans(0.0, -0.1 * qyOffset, 0.1 * mWaterPipeZoffset, 0));
593  }
594  } //if
595 
596  return stave;
597 } // MapsGeoParData::ConstructStave()
598 
599 // ---------------------------------------------------------------------------------------
600 
601 MapsStave *MapsGeoParData::ConstructStaveWithMapping(unsigned chipNum, unsigned id,
602  MapsMimosaAssembly *mcell)
603 {
604  MapsStave *stave = ConstructStave(chipNum, id, mcell);
605 
606  // Well, disks can be rotated, so does not make sense to assume, that chips are
607  // numbered in vertical (Y) direction -> just use the first available index (X);
608  AddLogicalVolumeGroup(chipNum);
609 
610  // NB: this implementation is really dumb and does not give anything like XY-location
611  // of chips in a disk; so just help the simulation code to identify chips and
612  // reconstruction code to get access to 3D transformation matrices;
613  EicGeoMap *fgmap = CreateNewMap();
614  fgmap->AddGeantVolumeLevel(mMimosaCoreName, 0);
615  fgmap->AddGeantVolumeLevel(mMimosaShellName, 0);
616  fgmap->AddGeantVolumeLevel(mCellAssemblyName, chipNum);
617  // Right, all the staves are unique for now;
618  fgmap->AddGeantVolumeLevel(stave->GetName(), 0);
619 
620  fgmap->SetSingleSensorContainerVolume(mMimosaCoreName);
621 
622  for(unsigned nn=0; nn<chipNum; nn++) {
623  UInt_t geant[4] = {0, 0, nn, 0}, logical[1] = {nn};
624 
625  if (SetMappingTableEntry(fgmap, geant, id, logical)) {
626  cout << "Failed to set mapping table entry!" << endl;
627  exit(0);
628  } //if
629  } //for nn
630 
631  return stave;
632 } // MapsGeoParData::ConstructStaveWithMapping()
633 
634 // ---------------------------------------------------------------------------------------
635