Bug fix
[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
39#include <TGeoMatrix.h> // ROOT_TGeoMatrix
40#include <TMath.h> // ROOT_TMath
41
1a1fdef7 42#include "AliFMDDetector.h" // ALIFMDSUBDETECTOR_H
43#include "AliFMDRing.h" // ALIFMDRING_H
bf000c32 44#include "AliLog.h" // ALILOG_H
1a1fdef7 45
46//====================================================================
47ClassImp(AliFMDDetector)
48#if 0
49 ; // This is here to keep Emacs for indenting the next line
50#endif
51
52//____________________________________________________________________
53AliFMDDetector::AliFMDDetector(Int_t id, AliFMDRing* inner, AliFMDRing* outer)
54 : TNamed(Form("FMD%d", id), "Forward multiplicity ring"),
55 fId(id),
b5ee4425 56 fInnerZ(0.),
57 fOuterZ(0.),
58 fHoneycombThickness(0.),
59 fAlThickness(0.),
60 fInnerHoneyLowR(0.),
61 fInnerHoneyHighR(0.),
62 fOuterHoneyLowR(0.),
63 fOuterHoneyHighR(0.),
1a1fdef7 64 fInner(inner),
bf000c32 65 fOuter(outer),
66 fInnerTransforms(0),
67 fOuterTransforms(0)
1a1fdef7 68{
088f8e79 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 //
1a1fdef7 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//____________________________________________________________________
088f8e79 86AliFMDDetector::AliFMDDetector(const AliFMDDetector& other)
87 : TNamed(other),
88 fId(other.fId),
b5ee4425 89 fInnerZ(0.),
90 fOuterZ(0.),
91 fHoneycombThickness(0.),
92 fAlThickness(0.),
93 fInnerHoneyLowR(0.),
94 fInnerHoneyHighR(0.),
95 fOuterHoneyLowR(0.),
96 fOuterHoneyHighR(0.),
088f8e79 97 fInner(other.fInner),
bf000c32 98 fOuter(other.fOuter),
99 fInnerTransforms(other.fInnerTransforms),
100 fOuterTransforms(other.fOuterTransforms)
088f8e79 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//____________________________________________________________________
114AliFMDDetector&
115AliFMDDetector::operator=(const AliFMDDetector& other)
116{
117 // Assignment operator
118 SetName(other.GetName());
119 SetTitle(other.GetTitle());
bf000c32 120 fId = other.fId;
121 fInner = other.fInner;
122 fOuter = other.fOuter;
123 fInnerTransforms = other.fInnerTransforms;
124 fOuterTransforms = other.fOuterTransforms;
088f8e79 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//____________________________________________________________________
1a1fdef7 137void
138AliFMDDetector::Init()
139{
088f8e79 140 // Initialize.
1a1fdef7 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.);
bf000c32 148 }
149}
150
151//____________________________________________________________________
152Bool_t
153AliFMDDetector::HasAllTransforms(Char_t ring) const
154{
02a27b50 155 // Check if we got all transformations for a given ring. Return
156 // true in that case.
bf000c32 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')
9de78b35 170#define IS_NODE_HALF(name) \
171 (name[0] == 'F' && name[2] == 'M' && (name[3] == 'B' || name[3] == 'T'))
bf000c32 172
173//____________________________________________________________________
174void
175AliFMDDetector::InitTransformations()
176{
02a27b50 177 // Find all local<->global transformations for this detector.
bf000c32 178 if ((!fInner || (fInner && fInnerTransforms)) &&
179 (!fOuter || (fOuter && fOuterTransforms))) {
180 AliDebug(5, Form("Transforms for FMD%d already registered", fId));
181 return;
182 }
183 AliDebug(5, Form("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 AliDebug(50, Form("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 AliDebug(20, Form("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 AliDebug(20, Form("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 AliDebug(20, Form("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 }
1a1fdef7 259 }
1a1fdef7 260}
261
262//____________________________________________________________________
9de78b35 263void
264AliFMDDetector::SetAlignableVolumes() const
265{
266 AliDebug(10, Form("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 AliDebug((name[0] == 'F' ? 40 : 50), Form("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 AliDebug(20, Form("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 AliDebug(30, Form("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 AliDebug(20,Form("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);
97b4001e 333 align = Form("FMD/FMD%d_%c", fId, thisHalf);
9de78b35 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 AliDebug(30, Form("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 AliDebug(20,Form("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 AliDebug(20, Form("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 AliDebug(20, Form("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//____________________________________________________________________
1a1fdef7 398AliFMDRing*
399AliFMDDetector::GetRing(Char_t id) const
400{
088f8e79 401 // Get the specified ring
402 //
403 // ID Id of ring ('I' or 'O')
404 //
1a1fdef7 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//____________________________________________________________________
415Double_t
416AliFMDDetector::GetRingZ(Char_t id) const
417{
088f8e79 418 // Get the z-coordinate specified ring
419 //
420 // ID Id of ring ('I' or 'O')
421 //
1a1fdef7 422 switch (id) {
423 case 'i':
424 case 'I': return GetInnerZ();
425 case 'o':
426 case 'O': return GetOuterZ();
427 }
428 return 0;
429}
bf000c32 430
431//____________________________________________________________________
432TGeoMatrix*
433AliFMDDetector::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
1a1fdef7 457//____________________________________________________________________
458void
bf000c32 459AliFMDDetector::Detector2XYZ(Char_t ring,
1a1fdef7 460 UShort_t sector,
461 UShort_t strip,
462 Double_t& x,
463 Double_t& y,
464 Double_t& z) const
465{
088f8e79 466 // Translate detector coordinates (this,ring,sector,strip) into
467 // (x,y,z) coordinates (in global reference frame)
1a1fdef7 468 AliFMDRing* r = GetRing(ring);
469 if (!r) return;
bf000c32 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());
15b17c89 480 AliDebug(30,Form("Rho %7.3f, angle %7.3f", rho, phi));
bf000c32 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];
15b17c89 486 AliDebug(30, Form("Local (%7.3f,%7.3f,%7.3f)",local[0], local[1], local[2]));
bf000c32 487 m->LocalToMaster(local, master);
15b17c89 488 AliDebug(30, Form("Master (%7.3f,%7.3f,%7.3f)",
bf000c32 489 master[0],master[1],master[2]));
490 x = master[0];
491 y = master[1];
492 z = master[2];
1a1fdef7 493}
494
495//____________________________________________________________________
54e415a8 496Bool_t
497AliFMDDetector::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{
088f8e79 504 // Translate (x,y,z) coordinates (in global reference frame) into
505 // detector coordinates (this,ring,sector,strip).
54e415a8 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//____________________________________________________________________
1a1fdef7 528//
529// EOF
530//