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