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
30 # include "AliFMDRing.h"
41 #ifndef ROOT_TVirtualMC
42 # include <TVirtualMC.h>
45 # include <TVector2.h>
48 # include <TBrowser.h>
56 #ifndef ROOT_TObjArray
57 # include <TObjArray.h>
65 #ifndef ROOT_TRotMatrix
66 # include <TRotMatrix.h>
75 const Char_t* AliFMDRing::fgkRingFormat = "FRG%c";
76 const Char_t* AliFMDRing::fgkVirtualFormat = "FV%c%c";
77 const Char_t* AliFMDRing::fgkActiveFormat = "FAC%c";
78 const Char_t* AliFMDRing::fgkSectorFormat = "FSE%c";
79 const Char_t* AliFMDRing::fgkStripFormat = "FST%c";
80 const Char_t* AliFMDRing::fgkPrintboardFormat = "FP%c%c";
83 //____________________________________________________________________
86 //____________________________________________________________________
87 AliFMDRing::AliFMDRing(Char_t id, Bool_t detailed)
91 fPrintboardBottomId(0),
110 fPrintboardThickness(0),
114 // Construct a alifmdring.
116 // id Id of the ring (either 'i' or 'o').
117 // detailed Whether the strips are made or not.
121 //____________________________________________________________________
122 AliFMDRing::AliFMDRing(const AliFMDRing& other)
125 fDetailed(other.fDetailed),
126 fActiveId(other.fActiveId),
127 fPrintboardBottomId(other.fPrintboardBottomId),
128 fPrintboardTopId(other.fPrintboardTopId),
129 fRingId(other.fRingId),
130 fSectionId(other.fSectionId),
131 fStripId(other.fStripId),
132 fVirtualBackId(other.fVirtualBackId),
133 fVirtualFrontId(other.fVirtualFrontId),
134 fBondingWidth(other.fBondingWidth),
135 fWaferRadius(other.fWaferRadius),
136 fSiThickness(other.fSiThickness),
138 fHighR(other.fHighR),
139 fTheta(other.fTheta),
140 fNStrips(other.fNStrips),
141 fRingDepth(other.fRingDepth),
142 fLegRadius(other.fLegRadius),
143 fLegLength(other.fLegLength),
144 fLegOffset(other.fLegOffset),
145 fModuleSpacing(other.fModuleSpacing),
146 fPrintboardThickness(other.fPrintboardThickness),
147 fRotations(other.fRotations),
148 fShape(other.fShape),
149 fRotMatricies(other.fRotMatricies)
151 // Copy constructor of a AliFMDRing.
154 //____________________________________________________________________
156 AliFMDRing::operator=(const AliFMDRing& other)
158 // Assignment operator
161 fDetailed = other.fDetailed;
162 fActiveId = other.fActiveId;
163 fPrintboardBottomId = other.fPrintboardBottomId;
164 fPrintboardTopId = other.fPrintboardTopId;
165 fRingId = other.fRingId;
166 fSectionId = other.fSectionId;
167 fStripId = other.fStripId;
168 fVirtualBackId = other.fVirtualBackId;
169 fVirtualFrontId = other.fVirtualFrontId;
170 fBondingWidth = other.fBondingWidth;
171 fWaferRadius = other.fWaferRadius;
172 fSiThickness = other.fSiThickness;
174 fHighR = other.fHighR;
175 fTheta = other.fTheta;
176 fNStrips = other.fNStrips;
177 fRingDepth = other.fRingDepth;
178 fLegRadius = other.fLegRadius;
179 fLegLength = other.fLegLength;
180 fLegOffset = other.fLegOffset;
181 fModuleSpacing = other.fModuleSpacing;
182 fPrintboardThickness = other.fPrintboardThickness;
183 fRotations = other.fRotations;
185 if (other.fShape->IsA() == TXTRU::Class())
186 ((TXTRU*)other.fShape)->Copy(*fShape);
190 if (other.fRotMatricies) {
191 Int_t n = other.fRotMatricies->GetEntries();
192 if (!fRotMatricies) fRotMatricies = new TObjArray(n);
193 else fRotMatricies->Expand(n);
194 TIter next(other.fRotMatricies);
196 while ((o = next())) fRotMatricies->Add(o);
203 //____________________________________________________________________
207 // Initialize the ring object.
208 // DebugGuard guard("AliFMDRing::Init");
209 AliDebug(10, "AliFMDRing::Init");
214 //____________________________________________________________________
215 AliFMDRing::~AliFMDRing()
217 // Destructor - deletes shape and rotation matricies
218 if (fShape) delete fShape;
219 if (fRotMatricies) delete fRotMatricies;
223 //____________________________________________________________________
225 AliFMDRing::Browse(TBrowser* /* b */)
227 // DebugGuard guard("AliFMDRing::Browse");
228 AliDebug(10, "AliFMDRing::Browse");
232 //____________________________________________________________________
234 AliFMDRing::SetupCoordinates()
236 // Calculates the parameters of the polygon shape.
238 // DebugGuard guard("AliFMDRing::SetupCoordinates");
239 AliDebug(10, "AliFMDRing::SetupCoordinates");
240 // Get out immediately if we have already done all this
241 if (fPolygon.GetNVerticies() > 1) return;
243 double tanTheta = TMath::Tan(fTheta * TMath::Pi() / 180.);
244 double tanTheta2 = TMath::Power(tanTheta,2);
245 double r2 = TMath::Power(fWaferRadius,2);
246 double yA = tanTheta * fLowR;
247 double lr2 = TMath::Power(fLowR, 2);
248 double hr2 = TMath::Power(fHighR,2);
249 double xD = fLowR + TMath::Sqrt(r2 - tanTheta2 * lr2);
250 double xD2 = TMath::Power(xD,2);
251 //double xD_2 = fLowR - TMath::Sqrt(r2 - tanTheta2 * lr2);
252 double yB = sqrt(r2 - hr2 + 2 * fHighR * xD - xD2);
253 double xC = ((xD + TMath::Sqrt(-tanTheta2 * xD2 + r2
256 double yC = tanTheta * xC;
258 fPolygon.AddVertex(fLowR, -yA);
259 fPolygon.AddVertex(xC, -yC);
260 fPolygon.AddVertex(fHighR, -yB);
261 fPolygon.AddVertex(fHighR, yB);
262 fPolygon.AddVertex(xC, yC);
263 fPolygon.AddVertex(fLowR, yA);
266 //____________________________________________________________________
268 AliFMDRing::IsWithin(size_t moduleNo, double x, double y) const
270 // Checks if a point (x,y) is inside the module with number moduleNo
272 // DebugGuard guard("AliFMDRing::IsWithin");
273 AliDebug(10, "AliFMDRing::IsWithin");
275 double r2 = x * x + y * y;
276 if (r2 < fHighR * fHighR && r2 > fLowR * fLowR) {
277 // double point_angle = TMath::ATan2(y, x);
278 // int n_modules = 360 / Int_t(fTheta * 2);
279 double m_angle = (.5 + moduleNo) * 2 * fTheta;
280 double m_radians = TMath::Pi() * m_angle / 180.;
283 double xr = x * TMath::Cos(-m_radians) - y * TMath::Sin(-m_radians);
284 double yr = x * TMath::Sin(-m_radians) + y * TMath::Cos(-m_radians);
286 ret = fPolygon.Contains(xr,yr);
294 //____________________________________________________________________
296 AliFMDRing::Draw(Option_t* option) const
298 // Draw a the shape of the ring into a 2D histogram. Useful for
299 // superimposing the actual shape of the ring onto a scatter plot of
300 // hits in the detector.
302 // DebugGuard guard("AliFMDRing::Draw");
303 AliDebug(10, "AliFMDRing::Draw");
304 // The unrotated coordinates of the polygon verticies
305 if (fPolygon.GetNVerticies() < 1) return;
308 for (size_t i = 0; i < fPolygon.GetNVerticies(); i++)
309 v[i] = fPolygon.GetVertex(i);
311 Int_t nModules = 360 / Int_t(fTheta * 2);
312 Double_t dTheta = fTheta * 2;
315 if (opt.Contains("B", TString::kIgnoreCase)) {
316 opt.Remove(opt.Index("B", 1, TString::kIgnoreCase),1);
317 TH1* null = new TH2F("null", "Null",
318 100, -fHighR * 1.1, fHighR * 1.1,
319 100, -fHighR * 1.1, fHighR * 1.1);
321 null->Draw(opt.Data());
324 for (int i = 0; i < nModules; i++) {
325 Double_t theta = (i + .5) * dTheta;
327 for (int j = 0; j < 6; j++) {
328 TVector2 vr(v[j].Rotate(TMath::Pi() * theta / 180.));
329 if (!p.AddVertex(vr.X(),vr.Y())) {
330 // std::cerr << "Draw of polygon " << i << " failed" << std::endl;
334 p.Draw(opt.Data(), Form("MOD%c_%d", fId, i));
336 if (opt.Contains("0", TString::kIgnoreCase)) {
337 TArc* arcH = new TArc(0,0, fHighR);
338 arcH->SetLineStyle(2);
339 arcH->SetLineColor(4);
342 TArc* arcL = new TArc(0,0, fLowR);
343 arcL->SetLineStyle(2);
344 arcL->SetLineColor(4);
349 //____________________________________________________________________
351 AliFMDRing::SetupGeometry(Int_t vacuumId, Int_t siId, Int_t pcbId,
352 Int_t pbRotId, Int_t idRotId)
354 // Setup the geometry of the ring. It defines the volumes
355 // RNGI or RNGO which can later be positioned in a sub-detector
358 // The hieracy of the RNGx volume is
360 // FRGx // Ring volume
361 // FVFx // Container of hybrid + legs
362 // FACx // Active volume (si sensor approx)
363 // FSEx // Section division
364 // FSTx // Strip division
365 // FPTx // Print board (bottom)
366 // FPBx // Print board (top)
367 // FLL // Support leg (long version)
368 // FVBx // Container of hybrid + legs
369 // FACx // Active volume (si sensor approx)
370 // FSEx // Section division
371 // FSTx // Strip division
372 // FPTx // Print board (bottom)
373 // FPBx // Print board (top)
374 // FSL // Support leg (long version)
378 // vacuumId Medium of inactive virtual volumes
379 // siId Medium of Silicon sensor (active)
380 // pcbId Medium of print boards
381 // pbRotId Print board rotation matrix
382 // idRotId Identity rotation matrix
384 // DebugGuard guard("AliFMDRing::SetupGeometry");
385 AliDebug(10, "AliFMDRing::SetupGeometry");
387 const TVector2& bCorner = fPolygon.GetVertex(3); // Third corner
388 const TVector2& aCorner = fPolygon.GetVertex(5); // First corner
389 const TVector2& cCorner = fPolygon.GetVertex(4); // Second corner
392 Double_t dStrip = (bCorner.Mod() - aCorner.Mod()) / fNStrips;
393 Double_t stripOff = aCorner.Mod();
394 Double_t rmin = fLowR;
395 Double_t rmax = bCorner.Mod();
397 fRingDepth = (fSiThickness
398 + fPrintboardThickness
402 // Ring virtual volume
405 pars[2] = fRingDepth / 2;
406 name = Form(fgkRingFormat, fId);
407 fRingId = gMC->Gsvolu(name.Data(), "TUBE", vacuumId, pars, 3);
409 // Virtual volume for modules with long legs
413 name = Form(fgkVirtualFormat, 'F', fId);
414 fVirtualFrontId = gMC->Gsvolu(name.Data(), "TUBS", vacuumId, pars, 5);
416 // Virtual volume for modules with long legs
417 pars[2] = (fRingDepth - fModuleSpacing) / 2;
418 name = Form(fgkVirtualFormat, 'B', fId);
419 fVirtualBackId = gMC->Gsvolu(name.Data(), "TUBS", vacuumId, pars, 5);
421 // Virtual mother volume for silicon
422 pars[2] = fSiThickness/2;
424 name = Form(fgkActiveFormat, fId);
425 fActiveId = gMC->Gsvolu(name.Data(), "TUBS", vacuumId , pars, 5);
428 // Virtual sector volumes
430 name = Form(fgkSectorFormat, fId);
431 gMC->Gsdvn2(name.Data(), name2.Data(), 2, 2, -fTheta, vacuumId);
432 fSectionId = gMC->VolId(name.Data());
434 // Active strip volumes
436 name = Form(fgkStripFormat, fId);
437 gMC->Gsdvt2(name.Data(), name2.Data(), dStrip, 1,stripOff, siId, fNStrips);
438 fStripId = gMC->VolId(name.Data());
441 // Print-board on back of module
442 pars[4] = TMath::Tan(TMath::Pi() * fTheta / 180) * fBondingWidth;
443 // Top of the print board
444 pars[0] = cCorner.Y() - pars[4];
445 pars[1] = bCorner.Y() - pars[4];
446 pars[2] = fPrintboardThickness / 2; // PCB half thickness
447 pars[3] = (bCorner.X() - cCorner.X()) / 2;
448 name = Form(fgkPrintboardFormat, 'T', fId);
449 fPrintboardTopId = gMC->Gsvolu(name.Data(), "TRD1", pcbId, pars, 4);
451 // Bottom of the print board
452 pars[0] = aCorner.Y() - pars[4];
453 pars[1] = cCorner.Y() - pars[4];
454 pars[3] = (cCorner.X() - aCorner.X()) / 2;
455 name = Form(fgkPrintboardFormat, 'B', fId);
456 fPrintboardBottomId = gMC->Gsvolu(name.Data(), "TRD1", pcbId, pars, 4);
458 // Define rotation matricies
459 Int_t nModules = 360 / Int_t(fTheta * 2);
460 Double_t dTheta = fTheta * 2;
461 fRotations.Set(nModules);
462 for (int i = 0; i < nModules; i++) {
463 Double_t theta = (i + .5) * dTheta;
465 // Rotation matrix for virtual module volumes
466 gMC->Matrix(idrot, 90, theta, 90, fmod(90 + theta, 360), 0, 0);
467 fRotations[i] = idrot;
471 // Int_t nModules = 360 / Int_t(fTheta * 2);
472 // Double_t dTheta = fTheta * 2;
473 Double_t pbTopL = (bCorner.X() - cCorner.X());
474 Double_t pbBotL = (cCorner.X() - aCorner.X());
475 Double_t yoffset = ((TMath::Tan(TMath::Pi() * fTheta / 180)
478 for (int i = 0; i < nModules; i++) {
479 TString name2 = Form(fgkRingFormat, fId);
482 // Double_t theta = (i + .5) * dTheta;
483 Bool_t isFront = (i % 2 == 1);
485 Double_t w = fRingDepth - (isFront ? 0 : fModuleSpacing);
487 // Place virtual module volume
488 name = Form(fgkVirtualFormat, (isFront ? 'F' : 'B'), fId);
489 dz = (w - fRingDepth) / 2;
490 gMC->Gspos(name.Data(), id, name2.Data(), 0., 0., dz,fRotations[i]);
492 // We only need to place the children once, they are copied when
493 // we place the other virtual volumes.
497 // Place active silicon wafer - this is put so that the front of
498 // the silicon is on the edge of the virtual volume.
499 name = Form(fgkActiveFormat, fId);
500 dz = (w - fSiThickness) / 2;
501 gMC->Gspos(name.Data(), id, name2.Data(),0.,0.,dz,idRotId);
503 // Place print board. This is put immediately behind the silicon
504 name = Form(fgkPrintboardFormat, 'T', fId);
505 dz = w / 2 - fSiThickness - fPrintboardThickness / 2;
506 gMC->Gspos(name.Data(), id, name2.Data(),
507 fLowR + pbBotL + pbTopL / 2, 0, dz, pbRotId, "ONLY");
508 name = Form(fgkPrintboardFormat, 'B', fId);
509 gMC->Gspos(name.Data(), id, name2.Data(),
510 fLowR + pbBotL / 2, 0, dz, pbRotId, "ONLY");
513 // This is put immediately behind the pringboard.
514 dz = (w / 2 - fSiThickness - fPrintboardThickness
515 - (fLegLength + (isFront ? fModuleSpacing : 0)) /2);
516 name = (isFront ? "FLL" : "FSL");
517 gMC->Gspos(name.Data(), id*10 + 1, name2.Data(),
518 aCorner.X() + fLegOffset + fLegRadius, 0., dz, idRotId, "");
519 Double_t y = cCorner.Y() - yoffset - fLegOffset - fLegRadius;
520 gMC->Gspos(name.Data(),id*10+2,name2.Data(),cCorner.X(), y,dz,idRotId,"");
521 gMC->Gspos(name.Data(),id*10+3,name2.Data(),cCorner.X(), -y,dz,idRotId,"");
524 //____________________________________________________________________
526 AliFMDRing::Geometry(const char* mother, Int_t baseId, Double_t z,
527 Int_t /* pbRotId */, Int_t idRotId)
529 // Positions a RNGx volume inside a mother.
533 // mother Mother volume to position the RNGx volume in
534 // baseId Base copy number
535 // z Z coordinate where the front of the active silicon
536 // should be in the mother volume, so we need to
537 // subtract half the ring width.
538 // idRotId Identity rotation matrix
540 // DebugGuard guard("AliFMDRing::Geometry");
541 AliDebug(10, "AliFMDRing::Geometry");
543 Double_t offsetZ = (fSiThickness
544 + fPrintboardThickness
545 + fLegLength + fModuleSpacing) / 2;
546 name = Form(fgkRingFormat, fId);
547 gMC->Gspos(name.Data(), baseId, mother, 0., 0., z - offsetZ, idRotId, "");
550 //____________________________________________________________________
552 AliFMDRing::SimpleGeometry(TList* nodes,
558 // Make a simple geometry of the ring for event display.
560 // The simple geometry is made from ROOT TNode and TShape objects.
561 // Note, that we cache the TShape and TRotMatrix objects used for
566 // nodes List of nodes to register all create nodes in
567 // mother Mother node to put the ring in.
568 // colour Colour of the nodes
569 // z Z position of the node in the mother volume
572 // DebugGuard guard("AliFMDRing::SimpleGeometry");
573 AliDebug(10, "AliFMDRing::SimpleGeometry");
576 // If the shape hasn't been defined yet, we define it here.
578 TString name(Form(fgkActiveFormat, fId));
579 TString title(Form("Shape of modules in %c Rings", fId));
580 Int_t n = fPolygon.GetNVerticies();
581 TXTRU* shape = new TXTRU(name.Data(), title.Data(), "void", n, 2);
582 for (Int_t i = 0; i < n; i++) {
583 const TVector2& v = fPolygon.GetVertex(i);
584 shape->DefineVertex(i, v.X(), v.Y());
586 shape->DefineSection(0, - fSiThickness / 2, 1, 0, 0);
587 shape->DefineSection(1, + fSiThickness / 2, 1, 0, 0);
589 fShape->SetLineColor(colour);
592 Int_t nModules = 360 / Int_t(fTheta * 2);
593 Double_t dTheta = fTheta * 2;
595 // If the roation matricies hasn't been defined yet, we do so here
596 if (!fRotMatricies) {
597 fRotMatricies = new TObjArray(nModules);
598 for (int i = 0; i < nModules; i++) {
599 Double_t theta = (i + .5) * dTheta;
600 TString name(Form("FMD_ring_%c_rot", fId));
601 TString title(Form("FMD Ring %c Rotation", fId));
603 new TRotMatrix(name.Data(), title.Data(),
604 90, theta, 90, fmod(90 + theta, 360), 0, 0);
605 fRotMatricies->AddAt(rot, i);
609 Double_t offsetZ = (fSiThickness
610 + fPrintboardThickness
611 + fLegLength + fModuleSpacing) / 2;
613 // Make all the nodes
614 for (int i = 0; i < nModules; i++) {
615 Bool_t isFront = (i % 2 == 1);
617 TRotMatrix* rot = static_cast<TRotMatrix*>(fRotMatricies->At(i));
618 TString name(Form("FAC%c_%d_%d", fId, n, i));
619 TString title(Form("Active FMD%d volume in %c Ring", n, fId));
620 TNode* node = new TNode(name.Data(), title.Data(), fShape,
622 z - offsetZ + (isFront ? fModuleSpacing : 0),
624 node->SetLineColor(colour);
631 //____________________________________________________________________
635 // Set drawing attributes for the RING
637 // DebugGuard guard("AliFMDRing::Gsatt");
638 AliDebug(10, "AliFMDRing::Gsatt");
640 name = Form(fgkRingFormat,fId);
641 gMC->Gsatt(name.Data(), "SEEN", 0);
643 name = Form(fgkVirtualFormat, 'T', fId);
644 gMC->Gsatt(name.Data(), "SEEN", 0);
646 name = Form(fgkVirtualFormat, 'B', fId);
647 gMC->Gsatt(name.Data(), "SEEN", 0);
649 name = Form(fgkActiveFormat,fId);
650 gMC->Gsatt(name.Data(), "SEEN", 1);
652 name = Form(fgkPrintboardFormat, 'T', fId);
653 gMC->Gsatt(name.Data(), "SEEN", 1);
655 name = Form(fgkPrintboardFormat, 'B',fId);
656 gMC->Gsatt(name.Data(), "SEEN", 1);