]> git.uio.no Git - u/mrichter/AliRoot.git/blame_incremental - FMD/AliFMDDetector.cxx
Move Monitor event display classes to extra subfolder
[u/mrichter/AliRoot.git] / FMD / AliFMDDetector.cxx
... / ...
CommitLineData
1/**************************************************************************
2 * Copyright(c) 2004, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
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 **************************************************************************/
15/* $Id$ */
16/** @file AliFMDDetector.cxx
17 @author Christian Holm Christensen <cholm@nbi.dk>
18 @date Mon Mar 27 12:36:27 2006
19 @brief Sub-detector base class implementation
20 @ingroup FMD_base
21*/
22
23//____________________________________________________________________
24//
25// AliFMDDetector.
26//
27// Base class for concrete FMD detectors, like AliFMD1, AliFMD2,
28// AliFMD3.
29// Utility class to help implement the FMD geometry. This provides
30// the interface for the concrete geometry implementations of the FMD
31// sub-detectors.
32//
33// The AliFMDGeometry object owns the AliFMDDetector objects
34//
35// Latest changes by Christian Holm Christensen
36//
37
38#include <TGeoManager.h> // ROOT_TGeoManager
39#include <TGeoPhysicalNode.h> // ROOT_TGeoPhysicalNode
40#include <TGeoMatrix.h> // ROOT_TGeoMatrix
41#include <TMath.h> // ROOT_TMath
42
43#include "AliFMDDetector.h" // ALIFMDSUBDETECTOR_H
44#include "AliFMDRing.h" // ALIFMDRING_H
45#include "AliFMDDebug.h" // ALIFMDDEBUG_H ALILOG_H
46
47//====================================================================
48ClassImp(AliFMDDetector)
49#if 0
50 ; // This is here to keep Emacs for indenting the next line
51#endif
52
53//____________________________________________________________________
54AliFMDDetector::AliFMDDetector(Int_t id, AliFMDRing* inner, AliFMDRing* outer)
55 : TNamed(Form("FMD%d", id), "Forward multiplicity ring"),
56 fId(id),
57 fInnerZ(0.),
58 fOuterZ(0.),
59 fInnerHoneyLowR(0.),
60 fInnerHoneyHighR(0.),
61 fOuterHoneyLowR(0.),
62 fOuterHoneyHighR(0.),
63 fInner(inner),
64 fOuter(outer),
65 fInnerTransforms(0),
66 fOuterTransforms(0)
67{
68 // Constructor
69 //
70 // ID Id of detector (1,2, or 3)
71 // INNER Inner ring geometry
72 // OUTER Outer ring geometry (if any)
73 //
74 SetInnerHoneyLowR(0);
75 SetInnerHoneyHighR(0);
76 SetInnerZ(0);
77 SetOuterZ(0);
78 SetOuterHoneyLowR(0);
79 SetOuterHoneyHighR(0);
80}
81
82//____________________________________________________________________
83AliFMDDetector::AliFMDDetector(const AliFMDDetector& other)
84 : TNamed(other),
85 fId(other.fId),
86 fInnerZ(0.),
87 fOuterZ(0.),
88 fInnerHoneyLowR(0.),
89 fInnerHoneyHighR(0.),
90 fOuterHoneyLowR(0.),
91 fOuterHoneyHighR(0.),
92 fInner(other.fInner),
93 fOuter(other.fOuter),
94 fInnerTransforms(other.fInnerTransforms),
95 fOuterTransforms(other.fOuterTransforms)
96{
97 // Copy constructor
98 SetInnerHoneyLowR(other.GetInnerHoneyLowR());
99 SetInnerHoneyHighR(other.GetInnerHoneyHighR());
100 SetInnerZ(other.GetInnerZ());
101 SetOuterZ(other.GetOuterZ());
102 SetOuterHoneyLowR(other.GetOuterHoneyLowR());
103 SetOuterHoneyHighR(other.GetOuterHoneyHighR());
104}
105
106//____________________________________________________________________
107AliFMDDetector&
108AliFMDDetector::operator=(const AliFMDDetector& other)
109{
110 // Assignment operator
111 if (&other == this) return *this;
112 SetName(other.GetName());
113 SetTitle(other.GetTitle());
114 fId = other.fId;
115 fInner = other.fInner;
116 fOuter = other.fOuter;
117 fInnerTransforms = other.fInnerTransforms;
118 fOuterTransforms = other.fOuterTransforms;
119 SetInnerHoneyLowR(other.GetInnerHoneyLowR());
120 SetInnerHoneyHighR(other.GetInnerHoneyHighR());
121 SetInnerZ(other.GetInnerZ());
122 SetOuterZ(other.GetOuterZ());
123 SetOuterHoneyLowR(other.GetOuterHoneyLowR());
124 SetOuterHoneyHighR(other.GetOuterHoneyHighR());
125 return *this;
126}
127
128//____________________________________________________________________
129void
130AliFMDDetector::Init()
131{
132 // Initialize.
133 if (fInner) {
134 SetInnerHoneyLowR(fInner->GetLowR() + 1.);
135 SetInnerHoneyHighR(fInner->GetHighR() + 1.);
136 }
137 if (fOuter) {
138 SetOuterHoneyLowR(fOuter->GetLowR() + 1.);
139 SetOuterHoneyHighR(fOuter->GetHighR() + 1.);
140 }
141}
142
143//____________________________________________________________________
144Bool_t
145AliFMDDetector::HasAllTransforms(Char_t ring) const
146{
147 // Check if we got all transformations for a given ring. Return
148 // true in that case.
149 AliFMDRing* r = GetRing(ring);
150 if (!r) return kTRUE;
151 TObjArray* matricies = (r == fInner ? fInnerTransforms : fOuterTransforms);
152 if (!matricies) return kTRUE;
153 if (matricies->GetEntries() == r->GetNModules()) return kTRUE;
154 return kFALSE;
155}
156
157#define IS_NODE_THIS(name) \
158 (name[0] == 'F' && name[2] == 'M' && name[1] == Char_t(48+fId) && \
159 (name[3] == 'T' || name[3] == 'B'))
160#define IS_NODE_SENSOR(name) \
161 (name[0] == 'F' && (name[2] == 'B' || name[2] == 'F') && name[3] == 'H')
162//#define IS_NODE_SENSOR(name)
163// (name[0] == 'F' && name[2] == 'S' && name[3] == 'E')
164#define IS_NODE_HALF(name) \
165 (name[0] == 'F' && name[2] == 'M' && (name[3] == 'B' || name[3] == 'T'))
166#define HALF_FORMAT "FMD/FMD%d_%c"
167#define SENSOR_FORMAT "FMD/FMD%d_%c/FMD%c_%02d"
168
169//____________________________________________________________________
170void
171AliFMDDetector::InitTransformations()
172{
173 // Find all local<->global transformations for this detector.
174 if ((!fInner || (fInner && fInnerTransforms)) &&
175 (!fOuter || (fOuter && fOuterTransforms))) {
176 AliFMDDebug(5, ("Transforms for FMD%d already registered", fId));
177 return;
178 }
179 AliFMDDebug(5, ("Initializing transforms for FMD%d", fId));
180 if (!gGeoManager) {
181 AliFatal("No TGeoManager defined");
182 return;
183 }
184
185 // Implementation using alignable volume names.
186 // Make container of transforms
187 if (fInner && !fInnerTransforms)
188 fInnerTransforms = new TObjArray(fInner->GetNModules());
189 if (fOuter && !fOuterTransforms)
190 fOuterTransforms = new TObjArray(fOuter->GetNModules());
191
192 // Loop over bottom/top
193 for (size_t ihalf = 0; ihalf < 2; ihalf++) {
194 char half = (ihalf == 0 ? 'T' : 'B');
195 TString path(Form(HALF_FORMAT, fId, half));
196 TGeoPNEntry* entry = gGeoManager->GetAlignableEntry(path.Data());
197 if (!entry) {
198 AliError(Form("Alignable entry for half-detector \"%s\" not found!",
199 path.Data()));
200 continue;
201 }
202 TGeoPhysicalNode* pn = entry->GetPhysicalNode();
203 if (!pn) {
204 AliWarning(Form("Making physical volume for \"%s\"", path.Data()));
205 pn = gGeoManager->MakeAlignablePN(entry);
206 if (!pn) {
207 AliError(Form("No physical node for \"%s\"", path.Data()));
208 continue;
209 }
210 }
211 }
212
213 // Loop over rings
214 for (size_t iring = 0; iring < 2; iring++) {
215 char ring = (iring == 0 ? 'I' : 'O');
216 TObjArray* trans = 0;
217 AliFMDRing* r = 0;
218 switch (ring) {
219 case 'I': r = fInner; trans = fInnerTransforms; break;
220 case 'O': r = fOuter; trans = fOuterTransforms; break;
221 }
222 if (!r || !trans) continue;
223
224 Int_t nModules = r->GetNModules();
225 if (nModules <= 0) continue;
226
227 // Loop over bottom/top
228 for (size_t ihalf = 0; ihalf < 2; ihalf++) {
229 char half = (ihalf == 0 ? 'T' : 'B');
230 Int_t base = (half == 'T' ? 0 : nModules / 2);
231
232 // Loop over modules in this half ring
233 for (Int_t imod = 0; imod < nModules / 2; imod++) {
234 // Find physical node entry
235 TString path(Form(SENSOR_FORMAT, fId, half, ring, base+imod));
236 TGeoPNEntry* entry = gGeoManager->GetAlignableEntry(path.Data());
237 if (!entry) {
238 AliError(Form("Alignable entry for sensor \"%s\" not found!",
239 path.Data()));
240 continue;
241 }
242 TGeoPhysicalNode* pn = entry->GetPhysicalNode();
243 if (!pn) {
244 AliWarning(Form("Making physical volume for \"%s\"", path.Data()));
245 pn = gGeoManager->MakeAlignablePN(entry);
246 if (!pn) {
247 AliError(Form("No physical node for \"%s\"", path.Data()));
248 continue;
249 }
250 }
251
252 const TGeoMatrix* pm = pn->GetMatrix();
253 if (!pm) {
254 AliError(Form("No matrix for path \"%s\"", path.Data()));
255 continue;
256 }
257 // Get transformation matrix for this node, and store it.
258 TGeoMatrix* t = new TGeoHMatrix(*pm);
259 trans->AddAt(t, base+imod);
260 AliFMDDebug(5, ("Found matrix for path \"%s\": %p",path.Data(),pm));
261 }
262 }
263 }
264 if (HasAllTransforms('I') && HasAllTransforms('O')) return;
265
266 // Alternative implementation using TGeoIter.
267 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
268 if (!topVolume) {
269 AliFatal("No top-level volume defined");
270 return;
271 }
272 // Make an iterator
273 TGeoIterator next(topVolume);
274 TGeoNode* node = 0;
275
276 // Find the node corresponding to this detector, and then find the
277 // sensor volumes
278 Bool_t thisNodeFound = kFALSE;
279 Bool_t allInners = HasAllTransforms('I');
280 Bool_t allOuters = HasAllTransforms('O');
281
282 while ((node = static_cast<TGeoNode*>(next()))
283 && !(allInners && allOuters)) {
284 // Get nodes names
285 const Char_t* name = node->GetName();
286 if (!name) continue;
287 AliFMDDebug(50, ("Got volume %s", name));
288 // Check if this node is this detector
289 // The base offset for numbers in the ASCII table is 48
290 if (IS_NODE_THIS(name)) {
291 AliFMDDebug(20, ("Found detector node '%s' for FMD%d", name, fId));
292 thisNodeFound = kTRUE;
293 }
294 // if the detector was found, then we're on that branch, and we
295 // check if this node represents a module in that branch.
296 if (thisNodeFound && IS_NODE_SENSOR(name)) {
297 AliFMDDebug(20, ("Found sensor node '%s' for FMD%d", name, fId));
298 // Get the ring Id.
299 Char_t ringid = name[1];
300
301 // Get the approprate ring
302 AliFMDRing* ring = GetRing(ringid);
303 if (!ring) continue;
304
305 // Check whether we have all the modules we need for this ring,
306 // and if so, go on to the next node.
307 Bool_t& done = (ring == fInner ? allInners : allOuters);
308 if ((done = HasAllTransforms(ringid))) {
309 AliFMDDebug(20, ("Already has all module transforms for ring %c",
310 ringid));
311 continue;
312 }
313
314 // Get the approprate container
315 TObjArray* matricies = (ringid == 'i' || ringid == 'I'
316 ? fInnerTransforms : fOuterTransforms);
317
318 // Get the copy (module) number, and check that it hasn't
319 // already been added to the container.
320 Int_t copy = node->GetNumber();
321 if (matricies->At(copy)) {
322 AliWarning(Form("Have a transformation for module %d in ring %c",
323 copy, ringid));
324 continue;
325 }
326
327 // Get the global transformation matrix, and store it.
328 TGeoMatrix* trans = new TGeoHMatrix(*(next.GetCurrentMatrix()));
329 matricies->AddAt(trans, copy);
330
331 }
332 }
333}
334
335//____________________________________________________________________
336void
337AliFMDDetector::SetAlignableVolumes() const
338{
339 // Set alignable volumes.
340 // This will define the alignable volumes.
341 // That is currently, the modules and the half-rings.
342
343 AliFMDDebug(10, ("Making alignable volumes for FMD%d", fId));
344 if (!gGeoManager) {
345 AliFatal("No TGeoManager defined");
346 return;
347 }
348 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
349 if (!topVolume) {
350 AliFatal("No top-level volume defined");
351 return;
352 }
353
354 // Make an iterator
355 TGeoIterator next(topVolume);
356 next.Reset(topVolume);
357 next.SetTopName(Form("/%s_1", topVolume->GetName()));
358 TGeoNode* node = 0;
359
360 Int_t nInnerSensor = (fInner ? fInner->GetNModules() : 0);
361 Int_t nOuterSensor = (fOuter ? fOuter->GetNModules() : 0);
362 // Find the node corresponding to this detector, and then find the
363 // sensor volumes
364 Bool_t thisNodeFound = kFALSE;
365 Char_t thisHalf = '\0';
366 Int_t iInnerSensor = 0;
367 Int_t iOuterSensor = 0;
368 Bool_t hasTop = false;
369 Bool_t hasBottom = false;
370
371 TString path, align;
372 while ((node = static_cast<TGeoNode*>(next()))
373 && (iInnerSensor < nInnerSensor || iOuterSensor < nOuterSensor
374 || !hasBottom || !hasTop)) {
375 // Get nodes names
376 const Char_t* name = node->GetName();
377 if (!name) continue;
378 AliFMDDebug((name[0] == 'F' ? 40 : 50), ("Got volume %s", name));
379 // Check if this node is this detector
380 // The base offset for numbers in the ASCII table is 48
381 if (IS_NODE_THIS(name)) {
382 AliFMDDebug(20, ("Found detector node '%s' for FMD%d", name, fId));
383 thisNodeFound = kTRUE;
384 }
385
386 // if a half ring is found, then we're on that branch, and we
387 // check if this node represents a half ring on that branch
388 if (thisNodeFound && IS_NODE_HALF(name)) {
389 AliFMDDebug(30, ("Found half node '%s' for FMD%d", name, fId));
390 // Get the half Id.
391 thisHalf = name[3];
392
393 // Check if we're done
394 Bool_t done = (thisHalf == 'T' ? hasTop : hasBottom);
395 if (done) {
396 AliFMDDebug(20, ("Already has all halves for detector %c",name[1]));
397 continue;
398 }
399
400 switch (thisHalf) {
401 case 'T': hasTop = true; break;
402 case 'B': hasBottom = true; break;
403 default:
404 AliWarning(Form("Unknown part '%c' of FMD%d", thisHalf, fId));
405 continue; // because the node is unknown.
406 }
407
408 // Get the node path
409 next.GetPath(path);
410 align = Form(HALF_FORMAT, fId, thisHalf);
411 }
412
413 // if the detector was found, then we're on that branch, and we
414 // check if this node represents a module in that branch.
415 if (thisNodeFound && thisHalf && IS_NODE_SENSOR(name)) {
416 AliFMDDebug(30, ("Found sensor node '%s' for FMD%d", name, fId));
417 // Get the ring Id.
418 Char_t ringid = name[1];
419
420 // check that the ring is valid
421 if (!GetRing(ringid)) {
422 AliWarning(Form("Invalid ring %c for FMD%d", ringid, fId));
423 continue;
424 }
425
426 // Check if we're done
427 Bool_t done = false;
428 switch (ringid) {
429 case 'I': done = iInnerSensor >= nInnerSensor; break;
430 case 'O': done = iOuterSensor >= nOuterSensor; break;
431 default: continue;
432 }
433 if (done) {
434 AliFMDDebug(20, ("Already has all sensor volumes for ring %c",ringid));
435 continue;
436 }
437 // Get the copy (module) number, and check that it hasn't
438 // already been added to the container.
439 Int_t copy = node->GetNumber();
440 next.GetPath(path);
441 // path.Replace("ALIC", "/ALIC_1");
442 align = Form(SENSOR_FORMAT, fId, thisHalf, ringid, copy);
443
444 switch (ringid) {
445 case 'I': iInnerSensor++; break;
446 case 'O': iOuterSensor++; break;
447 }
448 }
449 if (!align.IsNull() && !path.IsNull()) {
450 AliFMDDebug(20, ("Got %s -> %s", path.Data(), align.Data()));
451 TGeoPNEntry* entry =
452 gGeoManager->SetAlignableEntry(align.Data(),path.Data());
453 if(!entry)
454 AliFatal(Form("Alignable entry %s not created. "
455 "Volume path %s not valid",
456 align.Data(),path.Data()));
457#ifdef MAKE_ALIGNABLE_PHYSICAL
458 TGeoPhysicalNode* phys = gGeoManager->MakeAlignablePN(entry);
459 if (!phys)
460 AliWarning(Form("Physical node entry %s not created. "
461 "Volume path %s not valid",
462 align.Data(),path.Data()));
463#endif
464 align = "";
465 }
466 AliFMDDebug(20, ("FMD%d: top: %d bottom: %d Inner: %d/%d Outer %d/%d",
467 fId, hasTop, hasBottom, iInnerSensor, nInnerSensor,
468 iOuterSensor, nOuterSensor));
469 }
470}
471
472
473
474//____________________________________________________________________
475AliFMDRing*
476AliFMDDetector::GetRing(Char_t id) const
477{
478 // Get the specified ring
479 //
480 // ID Id of ring ('I' or 'O')
481 //
482 switch (id) {
483 case 'i':
484 case 'I': return GetInner();
485 case 'o':
486 case 'O': return GetOuter();
487 }
488 return 0;
489}
490
491//____________________________________________________________________
492Double_t
493AliFMDDetector::GetRingZ(Char_t id) const
494{
495 // Get the z-coordinate specified ring
496 //
497 // ID Id of ring ('I' or 'O')
498 //
499 switch (id) {
500 case 'i':
501 case 'I': return GetInnerZ();
502 case 'o':
503 case 'O': return GetOuterZ();
504 }
505 return 0;
506}
507
508//____________________________________________________________________
509TGeoMatrix*
510AliFMDDetector::FindTransform(Char_t ring, UShort_t sector) const
511{
512 // Find the transformation that corresponds to sector sector in ring
513 // ring.
514 TObjArray* matricies = 0;
515 switch (ring) {
516 case 'i': case 'I': matricies = fInnerTransforms; break;
517 case 'o': case 'O': matricies = fOuterTransforms; break;
518 }
519 if (!matricies) {
520 AliWarning(Form("Unknown ring %c of FMD%d", ring, fId));
521 return 0;
522 }
523 UInt_t module = sector / 2;
524 TGeoMatrix* m = static_cast<TGeoMatrix*>(matricies->At(module));
525 if (!m) {
526 AliWarning(Form("No matrix found for sector %d in FMD%d%c",
527 sector, fId, ring));
528 return 0;
529 }
530 return m;
531}
532
533
534//____________________________________________________________________
535void
536AliFMDDetector::Detector2XYZ(Char_t ring,
537 UShort_t sector,
538 UShort_t strip,
539 Double_t& x,
540 Double_t& y,
541 Double_t& z) const
542{
543 // Translate detector coordinates (this,ring,sector,strip) into
544 // (x,y,z) coordinates (in global reference frame)
545 AliFMDRing* r = GetRing(ring);
546 if (!r) {
547 AliWarning(Form("No such ring FMD%d%c ", fId, ring));
548 return;
549 }
550 TGeoMatrix* m = FindTransform(ring, sector);
551 if (!m) {
552 AliWarning(Form("No transfrmation found for FMD%d%c[%02d]",
553 fId, ring, sector));
554 return;
555 }
556 Double_t rho = r->GetStripRadius(strip);
557 Double_t phi = ((sector % 2) - .5) * r->GetTheta();
558 Double_t siThick = r->GetSiThickness();
559#if 0
560 Double_t modThick = (siThick
561 + r->GetPrintboardThickness()
562 + r->GetCopperThickness()
563 + r->GetChipThickness()
564 + r->GetSpacing());
565#endif
566 AliFMDDebug(30, ("Rho %7.3f, angle %7.3f", rho, phi));
567 Double_t local[] = { rho * TMath::Cos(phi * TMath::DegToRad()),
568 rho * TMath::Sin(phi * TMath::DegToRad()),
569 /* -modThick + */ siThick / 2 };
570 Double_t master[3];
571 AliFMDDebug(30, ("Local (%7.3f,%7.3f,%7.3f)",local[0], local[1], local[2]));
572 m->LocalToMaster(local, master);
573 AliFMDDebug(30, ("Master (%7.3f,%7.3f,%7.3f)",
574 master[0],master[1],master[2]));
575 x = master[0];
576 y = master[1];
577 z = master[2];
578}
579
580//____________________________________________________________________
581Bool_t
582AliFMDDetector::XYZ2Detector(Double_t x,
583 Double_t y,
584 Double_t z,
585 Char_t& ring,
586 UShort_t& sector,
587 UShort_t& strip) const
588{
589 // Translate (x,y,z) coordinates (in global reference frame) into
590 // detector coordinates (this,ring,sector,strip).
591 AliFMDRing* rng = 0;
592 ring = -1;
593 for (int j = 0; j < 2; j++) {
594 rng = GetRing(j == 0 ? 'I' : 'O');
595 if (!rng) continue;
596 Double_t ringZ = GetRingZ(j == 0 ? 'I' : 'O');
597 Double_t modSpace = TMath::Sign(rng->GetModuleSpacing(), ringZ);
598 if (TMath::Abs(z - ringZ) < 0.01 ||
599 TMath::Abs(z - ringZ + modSpace) < 0.01) break;
600 rng = 0;
601 }
602 if (rng && rng->XYZ2Detector(x, y, z - GetRingZ(rng->GetId()),
603 sector, strip)) {
604 ring = rng->GetId();
605 return kTRUE;
606 }
607 return kFALSE;
608}
609
610
611
612//____________________________________________________________________
613//
614// EOF
615//