EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
femc-lib.C
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file femc-lib.C
1 
2 //
3 // Think twice before changing anything here; and always check overlaps in GEANT
4 // geometry after doing modifications;
5 //
6 
7 // May want to fix X- and/or Y-spacings to a fixed value (June'2013 5x5cm^2 design);
8 #define _FIBER_X_SPACING_ (0.0376 * 25.4)
9 #define _FIBER_Y_SPACING_ (0.0328 * 25.4)
10 
11 // May want to move outer fiber inwards; this value determines min. distance
12 // from fiber *center* to the mesh edge in either X or Y; June'2013 design:
13 // 0.0220" diameter holes and min. metal width 0.0108" at the edge;
14 #define _MIN_DISTANCE_TO_EDGE_ ((0.0110 + 0.0108)*25.4)
15 
16 // Towers will be put individually in the geometry; however if only 2-tower
17 // assemblies are produces (or 2x2 ones), one does not need to move inwards
18 // holes on the "right" tower side; see also an extra 180 degree Z-rotation
19 // for odd in X towers in the code;
20 #define _ASSUME_TWO_TOWER_ASSEMBLIES_
21 
22 // Again, do this pointer passing better later;
23 void *define_basic_parameters(const char *detName, int version, int subVersion)
24 {
25  // NB: number of maps will be defined later (depending on tower segmentation);
26  FemcGeoParData *gpar = new FemcGeoParData(detName, version, subVersion);
27 
29 
30  //
31  // For automatic mesh parameters calculation assume that a small difference
32  // between 26*U = 26.00 units (X) and 30*sqrt(3)/2*U ~ 25.98 units (Y) does
33  // not matter, so one can still cook towers with square cross-section
34  // without destroying honeycomb pattern too much;
35  //
36  // Indeed the parameters can also be fixed to some predefined numbers
37  // (like mesh spacing in X & Y rounded to 0.0001");
38  //
39 
40  // Present Oleg's design of a 5x5cm^2 mesh shared between 2x2 towers;
41  gpar->mCellFaceSizeX = 1.9684 * 25.4 / 2;
42  // Yes, assume square section and just use gpar->mCellFaceSizeX in all 'critical'
43  // places like radius calculation; NB: code modifications will be needed if XY-sizes
44  // ever become different!;
45  gpar->mCellFaceSizeY = gpar->mCellFaceSizeX;
46 
47  // Well, assume no-gap packing;
48  gpar->mInterCellGap = 0.0;
49 
50 #ifndef _NO_STRUCTURE_GEOMETRY_
51  FiberParData *fptr = gpar->mFiber = new FiberParData();
52 
53  // Triangular honeycomb grid;
54  fptr->mFiberNumPerRow = 26;
55  fptr->mFiberRowNum = 30;
56  // Fiber parameters; 470um core diameter;
57  fptr->mFiberCoreDiameter = 0.47;
58  fptr->mFiberCladdingThickness = 0.03/2;
60 
61 #ifdef _FIBER_X_SPACING_
63 #else
64  fptr->mFiberSpacingX = gpar->mCellFaceSizeX / fptr->mFiberNumPerRow;
65 #endif
66  // NB: want a ~honeycomb structure -> even and odd rows fill be offset
67  // by fptr->mFiberSpacingX/2;
68  fptr->mFiberX0offset = -gpar->mCellFaceSizeX/2 +
69  (gpar->mCellFaceSizeX - (fptr->mFiberSpacingX/2)*(2*fptr->mFiberNumPerRow - 1))/2;
70 
71 #ifdef _FIBER_Y_SPACING_
73 #else
74  fptr->mFiberSpacingY = fptr->mFiberSpacingX*sqrt(3.)/2;
75 #endif
76  fptr->mFiberY0offset = -gpar->mCellFaceSizeY/2 +
77  (gpar->mCellFaceSizeY - fptr->mFiberSpacingY*(fptr->mFiberRowNum - 1))/2;
78 #endif
79 
80  TowerParData *tptr = gpar->mTower = new TowerParData();
81 
82  tptr->mLightGuideUpstreamWidth = 13.0;
83  tptr->mLightGuideLength = 25.4;
84  // This should sort of match the internal structure as well as the alu box (for T1018 case);
85  tptr->mTowerShellLength = 202.0;//200.0;
86  tptr->mSiliconPadThickness = 1.7;
87 
88  tptr->mSensorWidth = 3.0;
89  // Sensor thickness should nto matter here I guess?;
90  tptr->mSensorThickness = 0.1;
91  tptr->mSensorToSensorDistance = 0.275 * 25.4;
92 
93  tptr->mG10Thickness = 1.6;
94  tptr->mG10Width = 0.787 * 25.4;
95 
96  return gpar;
97 } // define_basic_parameters()
98 
99 
100 TGeoVolume *make_single_tower(void *qpar)
101 {
102  // FIXME: do it better than passing "void*" later; in fact should not hurt as long
103  // as dereference the same class;
104  FemcGeoParData *gpar = (FemcGeoParData*) qpar;
105  //EicGeoParDataHelper *helper = (EicGeoParDataHelper*)qelper;
106  const TString& cname = gpar->GetDetName()->Name();
107 
108  //
109  // So try to build a precise composition; this includes several tiny volumes, so
110  // it totally inappropriate for a real physics simulation; but there it should
111  // not matter, since most likely dummy volumes will be used anyway + fast digi of
112  // whatever sort;
113  //
114 
115  TowerParData *tptr = gpar->mTower;
116 
117 #ifdef _NO_STRUCTURE_GEOMETRY_
118  // Yes, prefer to fix cell length in this case;
119  gpar->mCellLength = 200.0;
120 #else
121  FiberParData *fptr = gpar->mFiber;
122 
123  // Do not be completely pedantic; assume outer brass meshes are right at the
124  // epoxy-to-absorber border; thickness is 0.012" ~ 300um; also assume, that
125  // exact locations of meshes inside the tower do not matter, but I should arrive
126  // at at total length of 3.4+165+2.6 = 171mm; since brass mesh thickness and
127  // two pure epoxy layer thickness is given correctly, this should give correct
128  // rad.length which is the only thing which matters;
129  fptr->AddLayer(3.40, "Epoxy");
130 #ifdef _IGNORE_BRASS_LAYERS_
131  // Just a single WEpoxyMix layer with the overall length matching real setup;
132  fptr->AddLayer(6.498 * 25.4, "WEpoxyMix");
133 #else
134  fptr->AddLayer(0.012 * 25.4, "brass");
135  fptr->AddLayer(1.690 * 25.4, "WEpoxyMix");
136  fptr->AddLayer(0.012 * 25.4, "brass");
137  fptr->AddLayer(3.380 * 25.4, "WEpoxyMix");
138  fptr->AddLayer(0.012 * 25.4, "brass");
139  fptr->AddLayer(1.380 * 25.4, "WEpoxyMix");
140  fptr->AddLayer(0.012 * 25.4, "brass");
141  // Add these two layers to become ~200mm thick (?);
142  //fptr->AddLayer(1.328 * 25.4, "WEpoxyMix");
143  //fptr->AddLayer(0.012 * 25.4, "brass");
144 #endif
145  fptr->AddLayer(2.60, "Epoxy");
146 
147  // Calculate layer offsets; this gives overall cell length at the end;
148  for(unsigned iq=0; iq<fptr->GetLayerNum(); iq++) {
149  FiberTowerLayer *layer = fptr->GetLayer(iq);
150 
151  layer->mOffset = gpar->mCellLength;
152  gpar->mCellLength += layer->mThickness;
153  } //for iq
154 #endif
155  printf("Cell length: %7.1f mm\n", gpar->mCellLength);
156 
157  // Single tower, filled with layers of material with fibers;
158  TGeoBBox *tower = new TGeoBBox(cname + "Tower",
159  0.1 * gpar->mCellFaceSizeX/2,
160  0.1 * gpar->mCellFaceSizeY/2,
161  0.1 * gpar->mCellLength/2);
162 
163  // Unless a dummy geometry wanted, populate tower with material layers and fibers;
164  // NB: optical photon propagation does not make much sense for spaghetti calorimeter
165  // (attenuation length and average photon yield per GeV are *measured*, the rest
166  // can be simulated on energy deposit level), so cutting fibers in pieces does not hurt;
167  // NB: light guide optical simulation indeed makes sense, but one can do it with
168  // a last short fiber piece as a light source;
169  TGeoVolume *vtower =
170 #ifdef _NO_STRUCTURE_GEOMETRY_
171  // Explicitely put SciFiber/W/epoxy mix with approximately correct density;
172  new TGeoVolume(cname + "Tower", tower, gpar->GetMedium("WEpoxySciMix"));
173 #else
174  // Material does not really matter here (the whole volume will be filled
175  // by other stuff anyway); prefer to put just air for clarity;
176  new TGeoVolume(cname + "Tower", tower, gpar->GetMedium("air"));
177 
178  for(unsigned iq=0; iq<fptr->GetLayerNum(); iq++) {
179  FiberTowerLayer *layer = fptr->GetLayer(iq);
180 
181  char layerName[128], claddingName[128], coreName[128];
182 
183  sprintf(layerName, "%sTowerLayer%02d", cname.Data(), iq);
184  sprintf(claddingName, "%sFiberCladding%02d", cname.Data(), iq);
185  sprintf(coreName, "%sFiberCore%02d", cname.Data(), iq);
186 
187  layer->SetLayerNames(layerName, claddingName, coreName);
188 
189  // Indeed assume holes in brass layers are equal to fiber diameter;
190  TGeoBBox *ltower = new TGeoBBox(layerName,
191  0.1 * gpar->mCellFaceSizeX/2,
192  0.1 * gpar->mCellFaceSizeY/2,
193  0.1 * layer->mThickness/2);
194  TGeoVolume *vltower =
195  new TGeoVolume(layerName, ltower, gpar->GetMedium(layer->mMedia.Data()));
196 
197  vtower->AddNode(vltower, 0,
198  new TGeoCombiTrans(0.0, 0.0,
199  0.1 * (layer->mOffset + layer->mThickness/2 - gpar->mCellLength/2), 0));
200 
201  TGeoTube *fiber = new TGeoTube(claddingName, 0.0, 0.1 * fptr->mOuterDiameter/2,
202  0.1 * layer->mThickness/2);
203  TGeoVolume *vfiber = new TGeoVolume(claddingName, fiber, gpar->GetMedium("PMMA"));
204 
205  for(int ix=0; ix<fptr->mFiberNumPerRow; ix++)
206  for(int iy=0; iy<fptr->mFiberRowNum; iy++) {
207  double xx = fptr->mFiberX0offset + (ix+(iy%2)/2.)*fptr->mFiberSpacingX;
208  double yy = fptr->mFiberY0offset + iy*fptr->mFiberSpacingY;
209 
210  // In fact would not hurt to always do this check and correct edge fiber locations;
211 #ifdef _MIN_DISTANCE_TO_EDGE_
212  double x2edge = gpar->mCellFaceSizeX/2 - fabs(xx), y2edge = gpar->mCellFaceSizeY/2 - fabs(yy);
213 #ifdef _ASSUME_TWO_TOWER_ASSEMBLIES_
214  // In this case fix "left" side only;
215  if (x2edge < _MIN_DISTANCE_TO_EDGE_ && xx < 0.0)
216 #else
217  if (x2edge < _MIN_DISTANCE_TO_EDGE_)
218 #endif
219  xx = (xx < 0. ? -1. : 1.)*(gpar->mCellFaceSizeX/2 - _MIN_DISTANCE_TO_EDGE_);
220  if (y2edge < _MIN_DISTANCE_TO_EDGE_)
221  yy = (yy < 0. ? -1. : 1.)*(gpar->mCellFaceSizeY/2 - _MIN_DISTANCE_TO_EDGE_);
222 #endif
223  //printf("%02d, %02d -> %8.4f %8.4f ... %8.4f %8.4f ... %8.4f %8.4f\n", ix, iy, xx, yy,
224  // (xx + gpar->cellFaceSize/2)/25.4,
225  // (yy + gpar->cellFaceSize/2)/25.4,
226  // (xx - gpar->cellFaceSize/2)/25.4,
227  // (yy - gpar->cellFaceSize/2)/25.4);
228 
229  vltower->AddNode(vfiber, ix*fptr->mFiberRowNum + iy,
230  new TGeoCombiTrans(0.1 * xx, 0.1 * yy, 0.0, new TGeoRotation()));
231  } //for ix..iy
232 
233  TGeoTube *fcore = new TGeoTube(coreName, 0.0, 0.1 * fptr->mFiberCoreDiameter/2,
234  0.1 * layer->mThickness/2);
235  TGeoVolume *vfcore = new TGeoVolume(coreName, fcore, gpar->GetMedium("polystyrene"));
236  vfiber->AddNode(vfcore, 0, new TGeoCombiTrans(0.0, 0.0, 0.0, new TGeoRotation()));
237  } //for iq
238 #endif
239 
240  // And a container shell which also includes lucite pyramid, PCB with sensors, etc;
241  {
242  // Single tower, filled with layers of material with fibers;
243  TGeoBBox *shell = new TGeoBBox(cname + "TowerShell",
244  0.1 * gpar->mCellFaceSizeX/2,
245  0.1 * gpar->mCellFaceSizeY/2,
246  0.1 * tptr->mTowerShellLength/2);
247  TGeoVolume *vshell = new TGeoVolume(cname + "TowerShell", shell, gpar->GetMedium("air"));
248 
249 #ifndef _NO_STRUCTURE_GEOMETRY_
250  double lightGuideOffset, siliconPadOffset, sensorOffset, g10Offset;
251 
252  // Add light guide;
253  {
254  TGeoTrd2 *guide = new TGeoTrd2(cname + "TowerLightGuide",
255  0.1 * tptr->mLightGuideUpstreamWidth/2,
256  0.1 * gpar->mCellFaceSizeX/2,
257  0.1 * tptr->mLightGuideUpstreamWidth/2,
258  0.1 * gpar->mCellFaceSizeY/2,
259  0.1 * tptr->mLightGuideLength/2);
260 
261  TGeoVolume *vguide = new TGeoVolume(cname + "TowerLightGuide", guide, gpar->GetMedium("lucite"));
262 
263  lightGuideOffset = (tptr->mTowerShellLength - 2 * gpar->mCellLength - tptr->mLightGuideLength)/2;
264 
265  vshell->AddNode(vguide, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * lightGuideOffset, 0));
266  }
267 
268  // Silicon layer between light guide and sensors;
269  {
270  // Single tower, filled with layers of material with fibers;
271  TGeoBBox *spad = new TGeoBBox(cname + "TowerSiliconPad",
272  0.1 * tptr->mLightGuideUpstreamWidth/2,
273  0.1 * tptr->mLightGuideUpstreamWidth/2,
274  0.1 * tptr->mSiliconPadThickness/2);
275  TGeoVolume *vspad =
276  new TGeoVolume(cname + "TowerSiliconPad", spad, gpar->GetMedium("SiliconeResinD"));
277 
278  siliconPadOffset = lightGuideOffset - tptr->mLightGuideLength/2 - tptr->mSiliconPadThickness/2;
279 
280  vshell->AddNode(vspad, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * siliconPadOffset, 0));
281  }
282 
283  // 2x2 sensor volumes (in case somebody wants to do optical calculations later :-);
284  {
285  // Single tower, filled with layers of material with fibers;
286  TGeoBBox *sensor = new TGeoBBox(cname + "SiliconSensor",
287  0.1 * tptr->mSensorWidth/2,
288  0.1 * tptr->mSensorWidth/2,
289  0.1 * tptr->mSensorThickness/2);
290  TGeoVolume *vsensor =
291  new TGeoVolume(cname + "SiliconSensor", sensor, gpar->GetMedium("silicon"));
292 
293  sensorOffset = siliconPadOffset - tptr->mSiliconPadThickness/2 - tptr->mSensorThickness/2;
294 
295  for(unsigned iqx=0; iqx<2; iqx++) {
296  double xOffset = (iqx ? -1.0 : 1.0) * tptr->mSensorToSensorDistance/2;
297 
298  for(unsigned iqy=0; iqy<2; iqy++) {
299  double yOffset = (iqy ? -1.0 : 1.0) * tptr->mSensorToSensorDistance/2;
300 
301  vshell->AddNode(vsensor, iqx*2+iqy,
302  new TGeoCombiTrans(0.1 * xOffset, 0.1 * yOffset, 0.1 * sensorOffset, 0));
303  } //for iqy
304  } //for iqx
305  }
306 
307  // Add G10 assembly (sort of equivalent thickness);
308  {
309  // Single tower, filled with layers of material with fibers;
310  TGeoBBox *g10 = new TGeoBBox(cname + "SiliconSensorG10",
311  0.1 * tptr->mG10Width/2,
312  0.1 * tptr->mG10Width/2,
313  0.1 * tptr->mG10Thickness/2);
314  TGeoVolume *vg10 =
315  new TGeoVolume(cname + "SiliconSensorG10", g10, gpar->GetMedium("G10"));
316 
317  g10Offset = sensorOffset - tptr->mSensorThickness/2 - tptr->mG10Thickness/2;
318 
319  vshell->AddNode(vg10, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * g10Offset, 0));
320  }
321 #endif
322 
323  // Add tower itself;
324  double towerOffset = (tptr->mTowerShellLength - gpar->mCellLength)/2;
325  vshell->AddNode(vtower, 0, new TGeoCombiTrans(0.0, 0.0, 0.1 * towerOffset, 0));
326  }
327 
328  return vshell;
329 } // make_single_tower()