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