1 /**************************************************************************
2 * Copyright(c) 2004, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
18 //////////////////////////////////////////////////////////////////////////////
20 // Utility class to help implement collection of FMD modules into
21 // rings. This is used by AliFMDSubDetector and AliFMD.
23 // The AliFMD object owns the AliFMDRing objects, and the
24 // AliFMDSubDetector objects reference these. That is, the AliFMDRing
25 // objects are share amoung the AliFMDSubDetector objects.
27 // Latest changes by Christian Holm Christensen
29 //////////////////////////////////////////////////////////////////////////////
31 # include "AliFMDRing.h"
42 #ifndef ROOT_TVirtualMC
43 # include <TVirtualMC.h>
46 # include <TVector2.h>
49 # include <TBrowser.h>
57 #ifndef ROOT_TObjArray
58 # include <TObjArray.h>
66 #ifndef ROOT_TRotMatrix
67 # include <TRotMatrix.h>
76 static const char* kRingFormat = "FRG%c";
77 static const char* kVirtualFormat = "FV%c%c";
78 static const char* kActiveFormat = "FAC%c";
79 static const char* kSectorFormat = "FSE%c";
80 static const char* kStripFormat = "FST%c";
81 static const char* kPrintboardFormat = "FP%c%c";
84 //____________________________________________________________________
87 //____________________________________________________________________
88 AliFMDRing::AliFMDRing(Char_t id, Bool_t detailed)
100 // Construct a alifmdring.
102 // id Id of the ring (either 'i' or 'o').
103 // lowr Lower radius of ring (in centimeters).
104 // highr Upper radius of ring (in centimeters).
105 // r Radius of the silicon wafers (in centimeters).
106 // theta Opening angle of the silicon wafers.
107 // strips Number of strips.
111 //____________________________________________________________________
115 // Initialize the ring object.
116 // DebugGuard guard("AliFMDRing::Init");
117 AliDebug(10, "AliFMDRing::Init");
122 //____________________________________________________________________
123 AliFMDRing::~AliFMDRing()
125 // Destructor - deletes shape and rotation matricies
126 if (fShape) delete fShape;
127 if (fRotMatricies) delete fRotMatricies;
131 //____________________________________________________________________
133 AliFMDRing::Browse(TBrowser* /* b */)
135 // DebugGuard guard("AliFMDRing::Browse");
136 AliDebug(10, "AliFMDRing::Browse");
140 //____________________________________________________________________
142 AliFMDRing::SetupCoordinates()
144 // Calculates the parameters of the polygon shape.
146 // DebugGuard guard("AliFMDRing::SetupCoordinates");
147 AliDebug(10, "AliFMDRing::SetupCoordinates");
148 // Get out immediately if we have already done all this
149 if (fPolygon.GetNVerticies() > 1) return;
151 double tan_theta = TMath::Tan(fTheta * TMath::Pi() / 180.);
152 double tan_theta2 = TMath::Power(tan_theta,2);
153 double r2 = TMath::Power(fWaferRadius,2);
154 double y_A = tan_theta * fLowR;
155 double lr2 = TMath::Power(fLowR, 2);
156 double hr2 = TMath::Power(fHighR,2);
157 double x_D = fLowR + TMath::Sqrt(r2 - tan_theta2 * lr2);
158 double x_D2 = TMath::Power(x_D,2);
159 //double x_D_2 = fLowR - TMath::Sqrt(r2 - tan_theta2 * lr2);
160 double y_B = sqrt(r2 - hr2 + 2 * fHighR * x_D - x_D2);
161 double x_C = ((x_D + TMath::Sqrt(-tan_theta2 * x_D2 + r2
164 double y_C = tan_theta * x_C;
166 fPolygon.AddVertex(fLowR, -y_A);
167 fPolygon.AddVertex(x_C, -y_C);
168 fPolygon.AddVertex(fHighR, -y_B);
169 fPolygon.AddVertex(fHighR, y_B);
170 fPolygon.AddVertex(x_C, y_C);
171 fPolygon.AddVertex(fLowR, y_A);
174 //____________________________________________________________________
176 AliFMDRing::IsWithin(size_t moduleNo, double x, double y) const
178 // Checks if a point (x,y) is inside the module with number moduleNo
180 // DebugGuard guard("AliFMDRing::IsWithin");
181 AliDebug(10, "AliFMDRing::IsWithin");
183 double r2 = x * x + y * y;
184 if (r2 < fHighR * fHighR && r2 > fLowR * fLowR) {
185 // double point_angle = TMath::ATan2(y, x);
186 // int n_modules = 360 / Int_t(fTheta * 2);
187 double m_angle = (.5 + moduleNo) * 2 * fTheta;
188 double m_radians = TMath::Pi() * m_angle / 180.;
191 double xr = x * TMath::Cos(-m_radians) - y * TMath::Sin(-m_radians);
192 double yr = x * TMath::Sin(-m_radians) + y * TMath::Cos(-m_radians);
194 ret = fPolygon.Contains(xr,yr);
202 //____________________________________________________________________
204 AliFMDRing::Draw(Option_t* option) const
206 // Draw a the shape of the ring into a 2D histogram. Useful for
207 // superimposing the actual shape of the ring onto a scatter plot of
208 // hits in the detector.
210 // DebugGuard guard("AliFMDRing::Draw");
211 AliDebug(10, "AliFMDRing::Draw");
212 // The unrotated coordinates of the polygon verticies
213 if (fPolygon.GetNVerticies() < 1) return;
216 for (size_t i = 0; i < fPolygon.GetNVerticies(); i++)
217 v[i] = fPolygon.GetVertex(i);
219 Int_t nModules = 360 / Int_t(fTheta * 2);
220 Double_t dTheta = fTheta * 2;
223 if (opt.Contains("B", TString::kIgnoreCase)) {
224 opt.Remove(opt.Index("B", 1, TString::kIgnoreCase),1);
225 TH1* null = new TH2F("null", "Null",
226 100, -fHighR * 1.1, fHighR * 1.1,
227 100, -fHighR * 1.1, fHighR * 1.1);
229 null->Draw(opt.Data());
232 for (int i = 0; i < nModules; i++) {
233 Double_t theta = (i + .5) * dTheta;
235 for (int j = 0; j < 6; j++) {
236 TVector2 vr(v[j].Rotate(TMath::Pi() * theta / 180.));
237 if (!p.AddVertex(vr.X(),vr.Y())) {
238 // std::cerr << "Draw of polygon " << i << " failed" << std::endl;
242 p.Draw(opt.Data(), Form("MOD%c_%d", fId, i));
244 if (opt.Contains("0", TString::kIgnoreCase)) {
245 TArc* arcH = new TArc(0,0, fHighR);
246 arcH->SetLineStyle(2);
247 arcH->SetLineColor(4);
250 TArc* arcL = new TArc(0,0, fLowR);
251 arcL->SetLineStyle(2);
252 arcL->SetLineColor(4);
257 //____________________________________________________________________
259 AliFMDRing::SetupGeometry(Int_t vacuumId, Int_t siId, Int_t pcbId,
260 Int_t pbRotId, Int_t idRotId)
262 // Setup the geometry of the ring. It defines the volumes
263 // RNGI or RNGO which can later be positioned in a sub-detector
266 // The hieracy of the RNGx volume is
268 // FRGx // Ring volume
269 // FVFx // Container of hybrid + legs
270 // FACx // Active volume (si sensor approx)
271 // FSEx // Section division
272 // FSTx // Strip division
273 // FPTx // Print board (bottom)
274 // FPBx // Print board (top)
275 // FLL // Support leg (long version)
276 // FVBx // Container of hybrid + legs
277 // FACx // Active volume (si sensor approx)
278 // FSEx // Section division
279 // FSTx // Strip division
280 // FPTx // Print board (bottom)
281 // FPBx // Print board (top)
282 // FSL // Support leg (long version)
286 // vacuumId Medium of inactive virtual volumes
287 // siId Medium of Silicon sensor (active)
288 // pcbId Medium of print boards
289 // pbRotId Print board rotation matrix
290 // idRotId Identity rotation matrix
292 // DebugGuard guard("AliFMDRing::SetupGeometry");
293 AliDebug(10, "AliFMDRing::SetupGeometry");
295 const TVector2& bCorner = fPolygon.GetVertex(3); // Third corner
296 const TVector2& aCorner = fPolygon.GetVertex(5); // First corner
297 const TVector2& cCorner = fPolygon.GetVertex(4); // Second corner
300 Double_t dStrip = (bCorner.Mod() - aCorner.Mod()) / fNStrips;
301 Double_t stripOff = aCorner.Mod();
302 Double_t rmin = fLowR;
303 Double_t rmax = bCorner.Mod();
305 fRingDepth = (fSiThickness
306 + fPrintboardThickness
310 // Ring virtual volume
313 pars[2] = fRingDepth / 2;
314 name = Form(kRingFormat, fId);
315 fRingId = gMC->Gsvolu(name.Data(), "TUBE", vacuumId, pars, 3);
317 // Virtual volume for modules with long legs
321 name = Form(kVirtualFormat, 'F', fId);
322 fVirtualFrontId = gMC->Gsvolu(name.Data(), "TUBS", vacuumId, pars, 5);
324 // Virtual volume for modules with long legs
325 pars[2] = (fRingDepth - fModuleSpacing) / 2;
326 name = Form(kVirtualFormat, 'B', fId);
327 fVirtualBackId = gMC->Gsvolu(name.Data(), "TUBS", vacuumId, pars, 5);
329 // Virtual mother volume for silicon
330 pars[2] = fSiThickness/2;
332 name = Form(kActiveFormat, fId);
333 fActiveId = gMC->Gsvolu(name.Data(), "TUBS", vacuumId , pars, 5);
336 // Virtual sector volumes
338 name = Form(kSectorFormat, fId);
339 gMC->Gsdvn2(name.Data(), name2.Data(), 2, 2, -fTheta, vacuumId);
340 fSectionId = gMC->VolId(name.Data());
342 // Active strip volumes
344 name = Form(kStripFormat, fId);
345 gMC->Gsdvt2(name.Data(), name2.Data(), dStrip, 1,stripOff, siId, fNStrips);
346 fStripId = gMC->VolId(name.Data());
349 // Print-board on back of module
350 pars[4] = TMath::Tan(TMath::Pi() * fTheta / 180) * fBondingWidth;
351 // Top of the print board
352 pars[0] = cCorner.Y() - pars[4];
353 pars[1] = bCorner.Y() - pars[4];
354 pars[2] = fPrintboardThickness / 2; // PCB half thickness
355 pars[3] = (bCorner.X() - cCorner.X()) / 2;
356 name = Form(kPrintboardFormat, 'T', fId);
357 fPrintboardTopId = gMC->Gsvolu(name.Data(), "TRD1", pcbId, pars, 4);
359 // Bottom of the print board
360 pars[0] = aCorner.Y() - pars[4];
361 pars[1] = cCorner.Y() - pars[4];
362 pars[3] = (cCorner.X() - aCorner.X()) / 2;
363 name = Form(kPrintboardFormat, 'B', fId);
364 fPrintboardBottomId = gMC->Gsvolu(name.Data(), "TRD1", pcbId, pars, 4);
366 // Define rotation matricies
367 Int_t nModules = 360 / Int_t(fTheta * 2);
368 Double_t dTheta = fTheta * 2;
369 fRotations.Set(nModules);
370 for (int i = 0; i < nModules; i++) {
371 Double_t theta = (i + .5) * dTheta;
373 // Rotation matrix for virtual module volumes
374 gMC->Matrix(idrot, 90, theta, 90, fmod(90 + theta, 360), 0, 0);
375 fRotations[i] = idrot;
379 // Int_t nModules = 360 / Int_t(fTheta * 2);
380 // Double_t dTheta = fTheta * 2;
381 Double_t pbTopL = (bCorner.X() - cCorner.X());
382 Double_t pbBotL = (cCorner.X() - aCorner.X());
383 Double_t yoffset = ((TMath::Tan(TMath::Pi() * fTheta / 180)
386 for (int i = 0; i < nModules; i++) {
387 TString name2 = Form(kRingFormat, fId);
390 // Double_t theta = (i + .5) * dTheta;
391 Bool_t isFront = (i % 2 == 1);
393 Double_t w = fRingDepth - (isFront ? 0 : fModuleSpacing);
395 // Place virtual module volume
396 name = Form(kVirtualFormat, (isFront ? 'F' : 'B'), fId);
397 dz = (w - fRingDepth) / 2;
398 gMC->Gspos(name.Data(), id, name2.Data(), 0., 0., dz,fRotations[i]);
400 // We only need to place the children once, they are copied when
401 // we place the other virtual volumes.
405 // Place active silicon wafer - this is put so that the front of
406 // the silicon is on the edge of the virtual volume.
407 name = Form(kActiveFormat, fId);
408 dz = (w - fSiThickness) / 2;
409 gMC->Gspos(name.Data(), id, name2.Data(),0.,0.,dz,idRotId);
411 // Place print board. This is put immediately behind the silicon
412 name = Form(kPrintboardFormat, 'T', fId);
413 dz = w / 2 - fSiThickness - fPrintboardThickness / 2;
414 gMC->Gspos(name.Data(), id, name2.Data(),
415 fLowR + pbBotL + pbTopL / 2, 0, dz, pbRotId, "ONLY");
416 name = Form(kPrintboardFormat, fId);
417 gMC->Gspos(name.Data(), id, name2.Data(),
418 fLowR + pbBotL / 2, 0, dz, pbRotId, "ONLY");
421 // This is put immediately behind the pringboard.
422 dz = (w / 2 - fSiThickness - fPrintboardThickness
423 - (fLegLength + (isFront ? fModuleSpacing : 0)) /2);
424 name = (isFront ? "FLL" : "FSL");
425 gMC->Gspos(name.Data(), id*10 + 1, name2.Data(),
426 aCorner.X() + fLegOffset + fLegRadius, 0., dz, idRotId, "");
427 Double_t y = cCorner.Y() - yoffset - fLegOffset - fLegRadius;
428 gMC->Gspos(name.Data(),id*10+2,name2.Data(),cCorner.X(), y,dz,idRotId,"");
429 gMC->Gspos(name.Data(),id*10+3,name2.Data(),cCorner.X(), -y,dz ,idRotId,"");
432 //____________________________________________________________________
434 AliFMDRing::Geometry(const char* mother, Int_t baseId, Double_t z,
435 Int_t /* pbRotId */, Int_t idRotId)
437 // Positions a RNGx volume inside a mother.
441 // mother Mother volume to position the RNGx volume in
442 // baseId Base copy number
443 // z Z coordinate where the front of the active silicon
444 // should be in the mother volume, so we need to
445 // subtract half the ring width.
446 // idRotId Identity rotation matrix
448 // DebugGuard guard("AliFMDRing::Geometry");
449 AliDebug(10, "AliFMDRing::Geometry");
451 Double_t offsetZ = (fSiThickness
452 + fPrintboardThickness
453 + fLegLength + fModuleSpacing) / 2;
454 name = Form(kRingFormat, fId);
455 gMC->Gspos(name.Data(), baseId, mother, 0., 0., z - offsetZ, idRotId, "");
458 //____________________________________________________________________
460 AliFMDRing::SimpleGeometry(TList* nodes,
466 // Make a simple geometry of the ring for event display.
468 // The simple geometry is made from ROOT TNode and TShape objects.
469 // Note, that we cache the TShape and TRotMatrix objects used for
474 // nodes List of nodes to register all create nodes in
475 // mother Mother node to put the ring in.
476 // colour Colour of the nodes
477 // z Z position of the node in the mother volume
480 // DebugGuard guard("AliFMDRing::SimpleGeometry");
481 AliDebug(10, "AliFMDRing::SimpleGeometry");
484 // If the shape hasn't been defined yet, we define it here.
486 TString name(Form(kActiveFormat, fId));
487 TString title(Form("Shape of modules in %c Rings", fId));
488 Int_t n = fPolygon.GetNVerticies();
489 TXTRU* shape = new TXTRU(name.Data(), title.Data(), "void", n, 2);
490 for (Int_t i = 0; i < n; i++) {
491 const TVector2& v = fPolygon.GetVertex(i);
492 shape->DefineVertex(i, v.X(), v.Y());
494 shape->DefineSection(0, - fSiThickness / 2, 1, 0, 0);
495 shape->DefineSection(1, + fSiThickness / 2, 1, 0, 0);
497 fShape->SetLineColor(colour);
500 Int_t nModules = 360 / Int_t(fTheta * 2);
501 Double_t dTheta = fTheta * 2;
503 // If the roation matricies hasn't been defined yet, we do so here
504 if (!fRotMatricies) {
505 fRotMatricies = new TObjArray(nModules);
506 for (int i = 0; i < nModules; i++) {
507 Double_t theta = (i + .5) * dTheta;
508 TString name(Form("FMD_ring_%c_rot", fId));
509 TString title(Form("FMD Ring %c Rotation", fId));
511 new TRotMatrix(name.Data(), title.Data(),
512 90, theta, 90, fmod(90 + theta, 360), 0, 0);
513 fRotMatricies->AddAt(rot, i);
517 Double_t offsetZ = (fSiThickness
518 + fPrintboardThickness
519 + fLegLength + fModuleSpacing) / 2;
521 // Make all the nodes
522 for (int i = 0; i < nModules; i++) {
523 Bool_t isFront = (i % 2 == 1);
525 TRotMatrix* rot = static_cast<TRotMatrix*>(fRotMatricies->At(i));
526 TString name(Form("FAC%c_%d_%d", fId, n, i));
527 TString title(Form("Active FMD%d volume in %c Ring", n, fId));
528 TNode* node = new TNode(name.Data(), title.Data(), fShape,
530 z - offsetZ + (isFront ? fModuleSpacing : 0),
532 node->SetLineColor(colour);
539 //____________________________________________________________________
543 // Set drawing attributes for the RING
545 // DebugGuard guard("AliFMDRing::Gsatt");
546 AliDebug(10, "AliFMDRing::Gsatt");
548 name = Form(kRingFormat,fId);
549 gMC->Gsatt(name.Data(), "SEEN", 0);
551 name = Form(kVirtualFormat, 'T', fId);
552 gMC->Gsatt(name.Data(), "SEEN", 0);
554 name = Form(kVirtualFormat, 'B', fId);
555 gMC->Gsatt(name.Data(), "SEEN", 0);
557 name = Form(kActiveFormat,fId);
558 gMC->Gsatt(name.Data(), "SEEN", 1);
560 name = Form(kPrintboardFormat, 'T', fId);
561 gMC->Gsatt(name.Data(), "SEEN", 1);
563 name = Form(kPrintboardFormat, 'B',fId);
564 gMC->Gsatt(name.Data(), "SEEN", 1);