1 /**************************************************************************
2 * Copyright(c) 2004, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
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
23 //____________________________________________________________________
27 // Base class for concrete FMD detectors, like AliFMD1, AliFMD2,
29 // Utility class to help implement the FMD geometry. This provides
30 // the interface for the concrete geometry implementations of the FMD
33 // The AliFMDGeometry object owns the AliFMDDetector objects
35 // Latest changes by Christian Holm Christensen
38 #include <TGeoManager.h> // ROOT_TGeoManager
39 #include <TGeoPhysicalNode.h> // ROOT_TGeoPhysicalNode
40 #include <TGeoMatrix.h> // ROOT_TGeoMatrix
41 #include <TMath.h> // ROOT_TMath
43 #include "AliFMDDetector.h" // ALIFMDSUBDETECTOR_H
44 #include "AliFMDRing.h" // ALIFMDRING_H
45 #include "AliFMDDebug.h" // ALIFMDDEBUG_H ALILOG_H
47 //====================================================================
48 ClassImp(AliFMDDetector)
50 ; // This is here to keep Emacs for indenting the next line
53 //____________________________________________________________________
54 AliFMDDetector::AliFMDDetector(Int_t id, AliFMDRing* inner, AliFMDRing* outer)
55 : TNamed(Form("FMD%d", id), "Forward multiplicity ring"),
70 // ID Id of detector (1,2, or 3)
71 // INNER Inner ring geometry
72 // OUTER Outer ring geometry (if any)
75 SetInnerHoneyHighR(0);
79 SetOuterHoneyHighR(0);
82 //____________________________________________________________________
83 AliFMDDetector::AliFMDDetector(const AliFMDDetector& other)
94 fInnerTransforms(other.fInnerTransforms),
95 fOuterTransforms(other.fOuterTransforms)
98 SetInnerHoneyLowR(other.GetInnerHoneyLowR());
99 SetInnerHoneyHighR(other.GetInnerHoneyHighR());
100 SetInnerZ(other.GetInnerZ());
101 SetOuterZ(other.GetOuterZ());
102 SetOuterHoneyLowR(other.GetOuterHoneyLowR());
103 SetOuterHoneyHighR(other.GetOuterHoneyHighR());
106 //____________________________________________________________________
108 AliFMDDetector::operator=(const AliFMDDetector& other)
110 // Assignment operator
111 SetName(other.GetName());
112 SetTitle(other.GetTitle());
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());
127 //____________________________________________________________________
129 AliFMDDetector::Init()
133 SetInnerHoneyLowR(fInner->GetLowR() + 1.);
134 SetInnerHoneyHighR(fInner->GetHighR() + 1.);
137 SetOuterHoneyLowR(fOuter->GetLowR() + 1.);
138 SetOuterHoneyHighR(fOuter->GetHighR() + 1.);
142 //____________________________________________________________________
144 AliFMDDetector::HasAllTransforms(Char_t ring) const
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;
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"
168 //____________________________________________________________________
170 AliFMDDetector::InitTransformations()
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));
178 AliFMDDebug(5, ("Initializing transforms for FMD%d", fId));
180 AliFatal("No TGeoManager defined");
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());
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());
197 AliError(Form("Alignable entry for half-detector \"%s\" not found!",
201 TGeoPhysicalNode* pn = entry->GetPhysicalNode();
203 AliWarning(Form("Making physical volume for \"%s\"", path.Data()));
204 pn = gGeoManager->MakeAlignablePN(entry);
206 AliError(Form("No physical node for \"%s\"", path.Data()));
213 for (size_t iring = 0; iring < 2; iring++) {
214 char ring = (iring == 0 ? 'I' : 'O');
215 TObjArray* trans = 0;
218 case 'I': r = fInner; trans = fInnerTransforms; break;
219 case 'O': r = fOuter; trans = fOuterTransforms; break;
221 if (!r || !trans) continue;
223 Int_t nModules = r->GetNModules();
224 if (nModules <= 0) continue;
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);
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());
237 AliError(Form("Alignable entry for sensor \"%s\" not found!",
241 TGeoPhysicalNode* pn = entry->GetPhysicalNode();
243 AliWarning(Form("Making physical volume for \"%s\"", path.Data()));
244 pn = gGeoManager->MakeAlignablePN(entry);
246 AliError(Form("No physical node for \"%s\"", path.Data()));
251 const TGeoMatrix* pm = pn->GetMatrix();
253 AliError(Form("No matrix for path \"%s\"", path.Data()));
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));
263 if (HasAllTransforms('I') && HasAllTransforms('O')) return;
265 // Alternative implementation using TGeoIter.
266 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
268 AliFatal("No top-level volume defined");
272 TGeoIterator next(topVolume);
275 // Find the node corresponding to this detector, and then find the
277 Bool_t thisNodeFound = kFALSE;
278 Bool_t allInners = HasAllTransforms('I');
279 Bool_t allOuters = HasAllTransforms('O');
281 while ((node = static_cast<TGeoNode*>(next()))
282 && !(allInners && allOuters)) {
284 const Char_t* name = node->GetName();
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;
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));
298 Char_t ringid = name[1];
300 // Get the approprate ring
301 AliFMDRing* ring = GetRing(ringid);
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",
313 // Get the approprate container
314 TObjArray* matricies = (ringid == 'i' || ringid == 'I'
315 ? fInnerTransforms : fOuterTransforms);
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",
326 // Get the global transformation matrix, and store it.
327 TGeoMatrix* trans = new TGeoHMatrix(*(next.GetCurrentMatrix()));
328 matricies->AddAt(trans, copy);
334 //____________________________________________________________________
336 AliFMDDetector::SetAlignableVolumes() const
338 // Set alignable volumes.
339 // This will define the alignable volumes.
340 // That is currently, the modules and the half-rings.
342 AliFMDDebug(10, ("Making alignable volumes for FMD%d", fId));
344 AliFatal("No TGeoManager defined");
347 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
349 AliFatal("No top-level volume defined");
354 TGeoIterator next(topVolume);
355 next.Reset(topVolume);
356 next.SetTopName(Form("/%s_1", topVolume->GetName()));
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
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;
371 while ((node = static_cast<TGeoNode*>(next()))
372 && (iInnerSensor < nInnerSensor || iOuterSensor < nOuterSensor
373 || !hasBottom || !hasTop)) {
375 const Char_t* name = node->GetName();
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;
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));
392 // Check if we're done
393 Bool_t done = (thisHalf == 'T' ? hasTop : hasBottom);
395 AliFMDDebug(20, ("Already has all halves for detector %c",name[1]));
400 case 'T': hasTop = true; break;
401 case 'B': hasBottom = true; break;
403 AliWarning(Form("Unknown part '%c' of FMD%d", thisHalf, fId));
404 continue; // because the node is unknown.
409 align = Form(HALF_FORMAT, fId, thisHalf);
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));
417 Char_t ringid = name[1];
419 // check that the ring is valid
420 if (!GetRing(ringid)) {
421 AliWarning(Form("Invalid ring %c for FMD%d", ringid, fId));
425 // Check if we're done
428 case 'I': done = iInnerSensor >= nInnerSensor; break;
429 case 'O': done = iOuterSensor >= nOuterSensor; break;
433 AliFMDDebug(20, ("Already has all sensor volumes for ring %c",ringid));
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();
440 // path.Replace("ALIC", "/ALIC_1");
441 align = Form(SENSOR_FORMAT, fId, thisHalf, ringid, copy);
444 case 'I': iInnerSensor++; break;
445 case 'O': iOuterSensor++; break;
448 if (!align.IsNull() && !path.IsNull()) {
449 AliFMDDebug(20, ("Got %s -> %s", path.Data(), align.Data()));
451 gGeoManager->SetAlignableEntry(align.Data(),path.Data());
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);
459 AliWarning(Form("Physical node entry %s not created. "
460 "Volume path %s not valid",
461 align.Data(),path.Data()));
465 AliFMDDebug(20, ("FMD%d: top: %d bottom: %d Inner: %d/%d Outer %d/%d",
466 fId, hasTop, hasBottom, iInnerSensor, nInnerSensor,
467 iOuterSensor, nOuterSensor));
473 //____________________________________________________________________
475 AliFMDDetector::GetRing(Char_t id) const
477 // Get the specified ring
479 // ID Id of ring ('I' or 'O')
483 case 'I': return GetInner();
485 case 'O': return GetOuter();
490 //____________________________________________________________________
492 AliFMDDetector::GetRingZ(Char_t id) const
494 // Get the z-coordinate specified ring
496 // ID Id of ring ('I' or 'O')
500 case 'I': return GetInnerZ();
502 case 'O': return GetOuterZ();
507 //____________________________________________________________________
509 AliFMDDetector::FindTransform(Char_t ring, UShort_t sector) const
511 // Find the transformation that corresponds to sector sector in ring
513 TObjArray* matricies = 0;
515 case 'i': case 'I': matricies = fInnerTransforms; break;
516 case 'o': case 'O': matricies = fOuterTransforms; break;
519 AliWarning(Form("Unknown ring %c of FMD%d", ring, fId));
522 UInt_t module = sector / 2;
523 TGeoMatrix* m = static_cast<TGeoMatrix*>(matricies->At(module));
525 AliWarning(Form("No matrix found for sector %d in FMD%d%c",
533 //____________________________________________________________________
535 AliFMDDetector::Detector2XYZ(Char_t ring,
542 // Translate detector coordinates (this,ring,sector,strip) into
543 // (x,y,z) coordinates (in global reference frame)
544 AliFMDRing* r = GetRing(ring);
546 AliWarning(Form("No such ring FMD%d%c ", fId, ring));
549 TGeoMatrix* m = FindTransform(ring, sector);
551 AliWarning(Form("No transfrmation found for FMD%d%c[%02d]",
555 Double_t rho = r->GetStripRadius(strip);
556 Double_t phi = ((sector % 2) - .5) * r->GetTheta();
557 Double_t siThick = r->GetSiThickness();
559 Double_t modThick = (siThick
560 + r->GetPrintboardThickness()
561 + r->GetCopperThickness()
562 + r->GetChipThickness()
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 };
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]));
579 //____________________________________________________________________
581 AliFMDDetector::XYZ2Detector(Double_t x,
586 UShort_t& strip) const
588 // Translate (x,y,z) coordinates (in global reference frame) into
589 // detector coordinates (this,ring,sector,strip).
592 for (int j = 0; j < 2; j++) {
593 rng = GetRing(j == 0 ? 'I' : 'O');
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;
601 if (rng && rng->XYZ2Detector(x, y, z - GetRingZ(rng->GetId()),
611 //____________________________________________________________________