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