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