MUON + CheckCompiler
[u/mrichter/AliRoot.git] / FMD / FMDbase / AliFMDDetector.cxx
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 //====================================================================
48 ClassImp(AliFMDDetector)
49 #if 0
50   ; // This is here to keep Emacs for indenting the next line
51 #endif
52
53 //____________________________________________________________________
54 AliFMDDetector::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 //____________________________________________________________________
83 AliFMDDetector::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 //____________________________________________________________________
107 AliFMDDetector&
108 AliFMDDetector::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 //____________________________________________________________________
129 void
130 AliFMDDetector::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 //____________________________________________________________________
144 Bool_t
145 AliFMDDetector::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 //____________________________________________________________________
170 void
171 AliFMDDetector::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 //____________________________________________________________________
336 void
337 AliFMDDetector::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 //____________________________________________________________________
475 AliFMDRing*
476 AliFMDDetector::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 //____________________________________________________________________
492 Double_t
493 AliFMDDetector::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 //____________________________________________________________________
509 TGeoMatrix*
510 AliFMDDetector::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 //____________________________________________________________________
535 void
536 AliFMDDetector::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 //____________________________________________________________________
581 Bool_t
582 AliFMDDetector::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 //