]> git.uio.no Git - u/mrichter/AliRoot.git/blame - FMD/AliFMDDetector.cxx
Bug fix in treatment of the vertex finder covariance matrix (Andrea)
[u/mrichter/AliRoot.git] / FMD / AliFMDDetector.cxx
CommitLineData
1a1fdef7 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 **************************************************************************/
1a1fdef7 15/* $Id$ */
c2fc1258 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
02a27b50 20 @ingroup FMD_base
c2fc1258 21*/
1a1fdef7 22
23//____________________________________________________________________
24//
6169f936 25// AliFMDDetector.
26//
27// Base class for concrete FMD detectors, like AliFMD1, AliFMD2,
28// AliFMD3.
1a1fdef7 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//
090026bf 37
38#include <TGeoManager.h> // ROOT_TGeoManager
4445cb1c 39#include <TGeoPhysicalNode.h> // ROOT_TGeoPhysicalNode
090026bf 40#include <TGeoMatrix.h> // ROOT_TGeoMatrix
41#include <TMath.h> // ROOT_TMath
42
1a1fdef7 43#include "AliFMDDetector.h" // ALIFMDSUBDETECTOR_H
44#include "AliFMDRing.h" // ALIFMDRING_H
f95a63c4 45#include "AliFMDDebug.h" // ALIFMDDEBUG_H ALILOG_H
1a1fdef7 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),
b5ee4425 57 fInnerZ(0.),
58 fOuterZ(0.),
59 fHoneycombThickness(0.),
60 fAlThickness(0.),
61 fInnerHoneyLowR(0.),
62 fInnerHoneyHighR(0.),
63 fOuterHoneyLowR(0.),
64 fOuterHoneyHighR(0.),
1a1fdef7 65 fInner(inner),
bf000c32 66 fOuter(outer),
67 fInnerTransforms(0),
68 fOuterTransforms(0)
1a1fdef7 69{
088f8e79 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 //
1a1fdef7 76 SetHoneycombThickness();
77 SetAlThickness();
78 SetInnerHoneyLowR(0);
79 SetInnerHoneyHighR(0);
80 SetInnerZ(0);
81 SetOuterZ(0);
82 SetOuterHoneyLowR(0);
83 SetOuterHoneyHighR(0);
84}
85
088f8e79 86//____________________________________________________________________
87AliFMDDetector::AliFMDDetector(const AliFMDDetector& other)
88 : TNamed(other),
89 fId(other.fId),
b5ee4425 90 fInnerZ(0.),
91 fOuterZ(0.),
92 fHoneycombThickness(0.),
93 fAlThickness(0.),
94 fInnerHoneyLowR(0.),
95 fInnerHoneyHighR(0.),
96 fOuterHoneyLowR(0.),
97 fOuterHoneyHighR(0.),
088f8e79 98 fInner(other.fInner),
bf000c32 99 fOuter(other.fOuter),
100 fInnerTransforms(other.fInnerTransforms),
101 fOuterTransforms(other.fOuterTransforms)
088f8e79 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//____________________________________________________________________
115AliFMDDetector&
116AliFMDDetector::operator=(const AliFMDDetector& other)
117{
118 // Assignment operator
119 SetName(other.GetName());
120 SetTitle(other.GetTitle());
bf000c32 121 fId = other.fId;
122 fInner = other.fInner;
123 fOuter = other.fOuter;
124 fInnerTransforms = other.fInnerTransforms;
125 fOuterTransforms = other.fOuterTransforms;
088f8e79 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
1a1fdef7 137//____________________________________________________________________
138void
139AliFMDDetector::Init()
140{
088f8e79 141 // Initialize.
1a1fdef7 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.);
bf000c32 149 }
150}
151
152//____________________________________________________________________
153Bool_t
154AliFMDDetector::HasAllTransforms(Char_t ring) const
155{
02a27b50 156 // Check if we got all transformations for a given ring. Return
157 // true in that case.
bf000c32 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')
9de78b35 171#define IS_NODE_HALF(name) \
172 (name[0] == 'F' && name[2] == 'M' && (name[3] == 'B' || name[3] == 'T'))
4445cb1c 173#define HALF_FORMAT "FMD/FMD%d_%c"
174#define SENSOR_FORMAT "FMD/FMD%d_%c/FMD%c_%02d"
bf000c32 175
176//____________________________________________________________________
177void
178AliFMDDetector::InitTransformations()
179{
02a27b50 180 // Find all local<->global transformations for this detector.
bf000c32 181 if ((!fInner || (fInner && fInnerTransforms)) &&
182 (!fOuter || (fOuter && fOuterTransforms))) {
f95a63c4 183 AliFMDDebug(5, ("Transforms for FMD%d already registered", fId));
bf000c32 184 return;
185 }
f95a63c4 186 AliFMDDebug(5, ("Initializing transforms for FMD%d", fId));
bf000c32 187 if (!gGeoManager) {
188 AliFatal("No TGeoManager defined");
189 return;
190 }
4445cb1c 191
192 // Implementation using alignable volume names.
bf000c32 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
4445cb1c 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 }
bf000c32 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;
f95a63c4 273 AliFMDDebug(50, ("Got volume %s", name));
bf000c32 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)) {
f95a63c4 277 AliFMDDebug(20, ("Found detector node '%s' for FMD%d", name, fId));
bf000c32 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)) {
f95a63c4 283 AliFMDDebug(20, ("Found sensor node '%s' for FMD%d", name, fId));
bf000c32 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))) {
f95a63c4 295 AliFMDDebug(20, ("Already has all module transforms for ring %c",
bf000c32 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 }
1a1fdef7 318 }
1a1fdef7 319}
320
9de78b35 321//____________________________________________________________________
322void
323AliFMDDetector::SetAlignableVolumes() const
324{
f95a63c4 325 AliFMDDebug(10, ("Making alignable volumes for FMD%d", fId));
9de78b35 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;
f95a63c4 360 AliFMDDebug((name[0] == 'F' ? 40 : 50), ("Got volume %s", name));
9de78b35 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)) {
f95a63c4 364 AliFMDDebug(20, ("Found detector node '%s' for FMD%d", name, fId));
9de78b35 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)) {
f95a63c4 371 AliFMDDebug(30, ("Found half node '%s' for FMD%d", name, fId));
9de78b35 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) {
f95a63c4 378 AliFMDDebug(20, ("Already has all halves for detector %c",name[1]));
9de78b35 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);
4445cb1c 392 align = Form(HALF_FORMAT, fId, thisHalf);
9de78b35 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)) {
f95a63c4 398 AliFMDDebug(30, ("Found sensor node '%s' for FMD%d", name, fId));
9de78b35 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) {
f95a63c4 416 AliFMDDebug(20, ("Already has all sensor volumes for ring %c",ringid));
9de78b35 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");
4445cb1c 424 align = Form(SENSOR_FORMAT, fId, thisHalf, ringid, copy);
9de78b35 425
426 switch (ringid) {
427 case 'I': iInnerSensor++; break;
428 case 'O': iOuterSensor++; break;
429 }
430 }
431 if (!align.IsNull() && !path.IsNull()) {
f95a63c4 432 AliFMDDebug(20, ("Got %s -> %s", path.Data(), align.Data()));
9de78b35 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 }
f95a63c4 448 AliFMDDebug(20, ("FMD%d: top: %d bottom: %d Inner: %d/%d Outer %d/%d",
9de78b35 449 fId, hasTop, hasBottom, iInnerSensor, nInnerSensor,
450 iOuterSensor, nOuterSensor));
451 }
452}
453
454
455
1a1fdef7 456//____________________________________________________________________
457AliFMDRing*
458AliFMDDetector::GetRing(Char_t id) const
459{
088f8e79 460 // Get the specified ring
461 //
462 // ID Id of ring ('I' or 'O')
463 //
1a1fdef7 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//____________________________________________________________________
474Double_t
475AliFMDDetector::GetRingZ(Char_t id) const
476{
088f8e79 477 // Get the z-coordinate specified ring
478 //
479 // ID Id of ring ('I' or 'O')
480 //
1a1fdef7 481 switch (id) {
482 case 'i':
483 case 'I': return GetInnerZ();
484 case 'o':
485 case 'O': return GetOuterZ();
486 }
487 return 0;
488}
bf000c32 489
490//____________________________________________________________________
491TGeoMatrix*
492AliFMDDetector::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
1a1fdef7 516//____________________________________________________________________
517void
bf000c32 518AliFMDDetector::Detector2XYZ(Char_t ring,
1a1fdef7 519 UShort_t sector,
520 UShort_t strip,
521 Double_t& x,
522 Double_t& y,
523 Double_t& z) const
524{
088f8e79 525 // Translate detector coordinates (this,ring,sector,strip) into
526 // (x,y,z) coordinates (in global reference frame)
1a1fdef7 527 AliFMDRing* r = GetRing(ring);
528 if (!r) return;
bf000c32 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());
f95a63c4 539 AliFMDDebug(30, ("Rho %7.3f, angle %7.3f", rho, phi));
bf000c32 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];
f95a63c4 545 AliFMDDebug(30, ("Local (%7.3f,%7.3f,%7.3f)",local[0], local[1], local[2]));
bf000c32 546 m->LocalToMaster(local, master);
f95a63c4 547 AliFMDDebug(30, ("Master (%7.3f,%7.3f,%7.3f)",
bf000c32 548 master[0],master[1],master[2]));
549 x = master[0];
550 y = master[1];
551 z = master[2];
1a1fdef7 552}
553
54e415a8 554//____________________________________________________________________
555Bool_t
556AliFMDDetector::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{
088f8e79 563 // Translate (x,y,z) coordinates (in global reference frame) into
564 // detector coordinates (this,ring,sector,strip).
54e415a8 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
1a1fdef7 586//____________________________________________________________________
587//
588// EOF
589//