First V0 MC Analysis from H.Ricaud
[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
86//____________________________________________________________________
088f8e79 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
137//____________________________________________________________________
1a1fdef7 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
321//____________________________________________________________________
9de78b35 322void
323AliFMDDetector::SetAlignableVolumes() const
324{
97e94238 325 // Set alignable volumes.
326 // This will define the alignable volumes.
327 // That is currently, the modules and the half-rings.
328
f95a63c4 329 AliFMDDebug(10, ("Making alignable volumes for FMD%d", fId));
9de78b35 330 if (!gGeoManager) {
331 AliFatal("No TGeoManager defined");
332 return;
333 }
334 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
335 if (!topVolume) {
336 AliFatal("No top-level volume defined");
337 return;
338 }
339
340 // Make an iterator
341 TGeoIterator next(topVolume);
342 next.Reset(topVolume);
343 next.SetTopName(Form("/%s_1", topVolume->GetName()));
344 TGeoNode* node = 0;
345
346 Int_t nInnerSensor = (fInner ? fInner->GetNModules() : 0);
347 Int_t nOuterSensor = (fOuter ? fOuter->GetNModules() : 0);
348 // Find the node corresponding to this detector, and then find the
349 // sensor volumes
350 Bool_t thisNodeFound = kFALSE;
351 Char_t thisHalf = '\0';
352 Int_t iInnerSensor = 0;
353 Int_t iOuterSensor = 0;
354 Bool_t hasTop = false;
355 Bool_t hasBottom = false;
356
357 TString path, align;
358 while ((node = static_cast<TGeoNode*>(next()))
359 && (iInnerSensor < nInnerSensor || iOuterSensor < nOuterSensor
360 || !hasBottom || !hasTop)) {
361 // Get nodes names
362 const Char_t* name = node->GetName();
363 if (!name) continue;
f95a63c4 364 AliFMDDebug((name[0] == 'F' ? 40 : 50), ("Got volume %s", name));
9de78b35 365 // Check if this node is this detector
366 // The base offset for numbers in the ASCII table is 48
367 if (IS_NODE_THIS(name)) {
f95a63c4 368 AliFMDDebug(20, ("Found detector node '%s' for FMD%d", name, fId));
9de78b35 369 thisNodeFound = kTRUE;
370 }
371
372 // if a half ring is found, then we're on that branch, and we
373 // check if this node represents a half ring on that branch
374 if (thisNodeFound && IS_NODE_HALF(name)) {
f95a63c4 375 AliFMDDebug(30, ("Found half node '%s' for FMD%d", name, fId));
9de78b35 376 // Get the half Id.
377 thisHalf = name[3];
378
379 // Check if we're done
380 Bool_t done = (thisHalf == 'T' ? hasTop : hasBottom);
381 if (done) {
f95a63c4 382 AliFMDDebug(20, ("Already has all halves for detector %c",name[1]));
9de78b35 383 continue;
384 }
385
386 switch (thisHalf) {
387 case 'T': hasTop = true; break;
388 case 'B': hasBottom = true; break;
389 default:
390 AliWarning(Form("Unknown part '%c' of FMD%d", fId));
391 continue; // because the node is unknown.
392 }
393
394 // Get the node path
395 next.GetPath(path);
4445cb1c 396 align = Form(HALF_FORMAT, fId, thisHalf);
9de78b35 397 }
398
399 // if the detector was found, then we're on that branch, and we
400 // check if this node represents a module in that branch.
401 if (thisNodeFound && thisHalf && IS_NODE_SENSOR(name)) {
f95a63c4 402 AliFMDDebug(30, ("Found sensor node '%s' for FMD%d", name, fId));
9de78b35 403 // Get the ring Id.
404 Char_t ringid = name[1];
405
406 // check that the ring is valid
407 if (!GetRing(ringid)) {
408 AliWarning(Form("Invalid ring %c for FMD%d", ringid, fId));
409 continue;
410 }
411
412 // Check if we're done
413 Bool_t done = false;
414 switch (ringid) {
415 case 'I': done = iInnerSensor >= nInnerSensor; break;
416 case 'O': done = iOuterSensor >= nOuterSensor; break;
417 default: continue;
418 }
419 if (done) {
f95a63c4 420 AliFMDDebug(20, ("Already has all sensor volumes for ring %c",ringid));
9de78b35 421 continue;
422 }
423 // Get the copy (module) number, and check that it hasn't
424 // already been added to the container.
425 Int_t copy = node->GetNumber();
426 next.GetPath(path);
427 // path.Replace("ALIC", "/ALIC_1");
4445cb1c 428 align = Form(SENSOR_FORMAT, fId, thisHalf, ringid, copy);
9de78b35 429
430 switch (ringid) {
431 case 'I': iInnerSensor++; break;
432 case 'O': iOuterSensor++; break;
433 }
434 }
435 if (!align.IsNull() && !path.IsNull()) {
f95a63c4 436 AliFMDDebug(20, ("Got %s -> %s", path.Data(), align.Data()));
9de78b35 437 TGeoPNEntry* entry =
438 gGeoManager->SetAlignableEntry(align.Data(),path.Data());
439 if(!entry)
440 AliFatal(Form("Alignable entry %s not created. "
441 "Volume path %s not valid",
442 align.Data(),path.Data()));
443#ifdef MAKE_ALIGNABLE_PHYSICAL
444 TGeoPhysicalNode* phys = gGeoManager->MakeAlignablePN(entry);
445 if (!phys)
446 AliWarning(Form("Physical node entry %s not created. "
447 "Volume path %s not valid",
448 align.Data(),path.Data()));
449#endif
450 align = "";
451 }
f95a63c4 452 AliFMDDebug(20, ("FMD%d: top: %d bottom: %d Inner: %d/%d Outer %d/%d",
9de78b35 453 fId, hasTop, hasBottom, iInnerSensor, nInnerSensor,
454 iOuterSensor, nOuterSensor));
455 }
456}
457
458
459
460//____________________________________________________________________
1a1fdef7 461AliFMDRing*
462AliFMDDetector::GetRing(Char_t id) const
463{
088f8e79 464 // Get the specified ring
465 //
466 // ID Id of ring ('I' or 'O')
467 //
1a1fdef7 468 switch (id) {
469 case 'i':
470 case 'I': return GetInner();
471 case 'o':
472 case 'O': return GetOuter();
473 }
474 return 0;
475}
476
477//____________________________________________________________________
478Double_t
479AliFMDDetector::GetRingZ(Char_t id) const
480{
088f8e79 481 // Get the z-coordinate specified ring
482 //
483 // ID Id of ring ('I' or 'O')
484 //
1a1fdef7 485 switch (id) {
486 case 'i':
487 case 'I': return GetInnerZ();
488 case 'o':
489 case 'O': return GetOuterZ();
490 }
491 return 0;
492}
bf000c32 493
494//____________________________________________________________________
495TGeoMatrix*
496AliFMDDetector::FindTransform(Char_t ring, UShort_t sector) const
497{
498 // Find the transformation that corresponds to sector sector in ring
499 // ring.
500 TObjArray* matricies = 0;
501 switch (ring) {
502 case 'i': case 'I': matricies = fInnerTransforms; break;
503 case 'o': case 'O': matricies = fOuterTransforms; break;
504 }
505 if (!matricies) {
506 AliWarning(Form("Unknown ring %c of FMD%d", ring, fId));
507 return 0;
508 }
509 UInt_t module = sector / 2;
510 TGeoMatrix* m = static_cast<TGeoMatrix*>(matricies->At(module));
511 if (!m) {
512 AliWarning(Form("No matrix found for sector %d in FMD%d%c",
513 sector, fId, ring));
514 return 0;
515 }
516 return m;
517}
518
519
1a1fdef7 520//____________________________________________________________________
521void
bf000c32 522AliFMDDetector::Detector2XYZ(Char_t ring,
1a1fdef7 523 UShort_t sector,
524 UShort_t strip,
525 Double_t& x,
526 Double_t& y,
527 Double_t& z) const
528{
088f8e79 529 // Translate detector coordinates (this,ring,sector,strip) into
530 // (x,y,z) coordinates (in global reference frame)
1a1fdef7 531 AliFMDRing* r = GetRing(ring);
532 if (!r) return;
bf000c32 533 TGeoMatrix* m = FindTransform(ring, sector);
534 if (!m) return;
535 Double_t rho = r->GetStripRadius(strip);
536 Double_t phi = ((sector % 2) - .5) * r->GetTheta();
537 Double_t siThick = r->GetSiThickness();
538 Double_t modThick = (siThick
539 + r->GetPrintboardThickness()
540 + r->GetCopperThickness()
541 + r->GetChipThickness()
542 + r->GetSpacing());
f95a63c4 543 AliFMDDebug(30, ("Rho %7.3f, angle %7.3f", rho, phi));
bf000c32 544# define DEGRAD TMath::Pi() / 180.
545 Double_t local[] = { rho * TMath::Cos(phi * DEGRAD),
546 rho * TMath::Sin(phi * DEGRAD),
547 -modThick + siThick / 2 };
548 Double_t master[3];
f95a63c4 549 AliFMDDebug(30, ("Local (%7.3f,%7.3f,%7.3f)",local[0], local[1], local[2]));
bf000c32 550 m->LocalToMaster(local, master);
f95a63c4 551 AliFMDDebug(30, ("Master (%7.3f,%7.3f,%7.3f)",
bf000c32 552 master[0],master[1],master[2]));
553 x = master[0];
554 y = master[1];
555 z = master[2];
1a1fdef7 556}
557
558//____________________________________________________________________
54e415a8 559Bool_t
560AliFMDDetector::XYZ2Detector(Double_t x,
561 Double_t y,
562 Double_t z,
563 Char_t& ring,
564 UShort_t& sector,
565 UShort_t& strip) const
566{
088f8e79 567 // Translate (x,y,z) coordinates (in global reference frame) into
568 // detector coordinates (this,ring,sector,strip).
54e415a8 569 AliFMDRing* rng = 0;
570 ring = -1;
571 for (int j = 0; j < 2; j++) {
572 rng = GetRing(j == 0 ? 'I' : 'O');
573 if (!rng) continue;
574 Double_t ringZ = GetRingZ(j == 0 ? 'I' : 'O');
575 Double_t modSpace = TMath::Sign(rng->GetModuleSpacing(), ringZ);
576 if (TMath::Abs(z - ringZ) < 0.01 ||
577 TMath::Abs(z - ringZ + modSpace) < 0.01) break;
578 rng = 0;
579 }
580 if (rng && rng->XYZ2Detector(x, y, z - GetRingZ(rng->GetId()),
581 sector, strip)) {
582 ring = rng->GetId();
583 return kTRUE;
584 }
585 return kFALSE;
586}
587
588
589
590//____________________________________________________________________
1a1fdef7 591//
592// EOF
593//