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
37 #include "AliFMDDetector.h" // ALIFMDSUBDETECTOR_H
38 #include "AliFMDRing.h" // ALIFMDRING_H
39 #include "AliLog.h" // ALILOG_H
40 #include <TGeoManager.h> // ROOT_TGeoManager
41 #include <TGeoMatrix.h> // ROOT_TGeoMatrix
42 // #include <TMath.h> // ROOT_TMath
44 //====================================================================
45 ClassImp(AliFMDDetector)
47 ; // This is here to keep Emacs for indenting the next line
50 //____________________________________________________________________
51 AliFMDDetector::AliFMDDetector(Int_t id, AliFMDRing* inner, AliFMDRing* outer)
52 : TNamed(Form("FMD%d", id), "Forward multiplicity ring"),
56 fHoneycombThickness(0.),
69 // ID Id of detector (1,2, or 3)
70 // INNER Inner ring geometry
71 // OUTER Outer ring geometry (if any)
73 SetHoneycombThickness();
76 SetInnerHoneyHighR(0);
80 SetOuterHoneyHighR(0);
83 //____________________________________________________________________
84 AliFMDDetector::AliFMDDetector(const AliFMDDetector& other)
89 fHoneycombThickness(0.),
97 fInnerTransforms(other.fInnerTransforms),
98 fOuterTransforms(other.fOuterTransforms)
101 SetHoneycombThickness(other.GetHoneycombThickness());
102 SetAlThickness(other.GetAlThickness());
103 SetInnerHoneyLowR(other.GetInnerHoneyLowR());
104 SetInnerHoneyHighR(other.GetInnerHoneyHighR());
105 SetInnerZ(other.GetInnerZ());
106 SetOuterZ(other.GetOuterZ());
107 SetOuterHoneyLowR(other.GetOuterHoneyLowR());
108 SetOuterHoneyHighR(other.GetOuterHoneyHighR());
111 //____________________________________________________________________
113 AliFMDDetector::operator=(const AliFMDDetector& other)
115 // Assignment operator
116 SetName(other.GetName());
117 SetTitle(other.GetTitle());
119 fInner = other.fInner;
120 fOuter = other.fOuter;
121 fInnerTransforms = other.fInnerTransforms;
122 fOuterTransforms = other.fOuterTransforms;
123 SetHoneycombThickness(other.GetHoneycombThickness());
124 SetAlThickness(other.GetAlThickness());
125 SetInnerHoneyLowR(other.GetInnerHoneyLowR());
126 SetInnerHoneyHighR(other.GetInnerHoneyHighR());
127 SetInnerZ(other.GetInnerZ());
128 SetOuterZ(other.GetOuterZ());
129 SetOuterHoneyLowR(other.GetOuterHoneyLowR());
130 SetOuterHoneyHighR(other.GetOuterHoneyHighR());
134 //____________________________________________________________________
136 AliFMDDetector::Init()
140 SetInnerHoneyLowR(fInner->GetLowR() + 1.);
141 SetInnerHoneyHighR(fInner->GetHighR() + 1.);
144 SetOuterHoneyLowR(fOuter->GetLowR() + 1.);
145 SetOuterHoneyHighR(fOuter->GetHighR() + 1.);
149 //____________________________________________________________________
151 AliFMDDetector::HasAllTransforms(Char_t ring) const
153 // Check if we got all transformations for a given ring. Return
154 // true in that case.
155 AliFMDRing* r = GetRing(ring);
156 if (!r) return kTRUE;
157 TObjArray* matricies = (r == fInner ? fInnerTransforms : fOuterTransforms);
158 if (!matricies) return kTRUE;
159 if (matricies->GetEntries() == r->GetNModules()) return kTRUE;
163 #define IS_NODE_THIS(name) \
164 (name[0] == 'F' && name[2] == 'M' && name[1] == Char_t(48+fId) && \
165 (name[3] == 'T' || name[3] == 'B'))
166 #define IS_NODE_SENSOR(name) \
167 (name[0] == 'F' && name[2] == 'S' && name[3] == 'E')
168 #define IS_NODE_HALF(name) \
169 (name[0] == 'F' && name[2] == 'M' && (name[3] == 'B' || name[3] == 'T'))
171 //____________________________________________________________________
173 AliFMDDetector::InitTransformations()
175 // Find all local<->global transformations for this detector.
176 if ((!fInner || (fInner && fInnerTransforms)) &&
177 (!fOuter || (fOuter && fOuterTransforms))) {
178 AliDebug(5, Form("Transforms for FMD%d already registered", fId));
181 AliDebug(5, Form("Initializing transforms for FMD%d", fId));
183 AliFatal("No TGeoManager defined");
186 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
188 AliFatal("No top-level volume defined");
191 // Make container of transforms
192 if (fInner && !fInnerTransforms)
193 fInnerTransforms = new TObjArray(fInner->GetNModules());
194 if (fOuter && !fOuterTransforms)
195 fOuterTransforms = new TObjArray(fOuter->GetNModules());
198 TGeoIterator next(topVolume);
201 // Find the node corresponding to this detector, and then find the
203 Bool_t thisNodeFound = kFALSE;
204 Bool_t allInners = HasAllTransforms('I');
205 Bool_t allOuters = HasAllTransforms('O');
207 while ((node = static_cast<TGeoNode*>(next()))
208 && !(allInners && allOuters)) {
210 const Char_t* name = node->GetName();
212 AliDebug(50, Form("Got volume %s", name));
213 // Check if this node is this detector
214 // The base offset for numbers in the ASCII table is 48
215 if (IS_NODE_THIS(name)) {
216 AliDebug(20, Form("Found detector node '%s' for FMD%d", name, fId));
217 thisNodeFound = kTRUE;
219 // if the detector was found, then we're on that branch, and we
220 // check if this node represents a module in that branch.
221 if (thisNodeFound && IS_NODE_SENSOR(name)) {
222 AliDebug(20, Form("Found sensor node '%s' for FMD%d", name, fId));
224 Char_t ringid = name[1];
226 // Get the approprate ring
227 AliFMDRing* ring = GetRing(ringid);
230 // Check whether we have all the modules we need for this ring,
231 // and if so, go on to the next node.
232 Bool_t& done = (ring == fInner ? allInners : allOuters);
233 if ((done = HasAllTransforms(ringid))) {
234 AliDebug(20, Form("Already has all module transforms for ring %c",
239 // Get the approprate container
240 TObjArray* matricies = (ringid == 'i' || ringid == 'I'
241 ? fInnerTransforms : fOuterTransforms);
243 // Get the copy (module) number, and check that it hasn't
244 // already been added to the container.
245 Int_t copy = node->GetNumber();
246 if (matricies->At(copy)) {
247 AliWarning(Form("Have a transformation for module %d in ring %c",
252 // Get the global transformation matrix, and store it.
253 TGeoMatrix* trans = new TGeoHMatrix(*(next.GetCurrentMatrix()));
254 matricies->AddAt(trans, copy);
260 //____________________________________________________________________
262 AliFMDDetector::SetAlignableVolumes() const
264 AliDebug(10, Form("Making alignable volumes for FMD%d", fId));
266 AliFatal("No TGeoManager defined");
269 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
271 AliFatal("No top-level volume defined");
276 TGeoIterator next(topVolume);
277 next.Reset(topVolume);
278 next.SetTopName(Form("/%s_1", topVolume->GetName()));
281 Int_t nInnerSensor = (fInner ? fInner->GetNModules() : 0);
282 Int_t nOuterSensor = (fOuter ? fOuter->GetNModules() : 0);
283 // Find the node corresponding to this detector, and then find the
285 Bool_t thisNodeFound = kFALSE;
286 Char_t thisHalf = '\0';
287 Int_t iInnerSensor = 0;
288 Int_t iOuterSensor = 0;
289 Bool_t hasTop = false;
290 Bool_t hasBottom = false;
293 while ((node = static_cast<TGeoNode*>(next()))
294 && (iInnerSensor < nInnerSensor || iOuterSensor < nOuterSensor
295 || !hasBottom || !hasTop)) {
297 const Char_t* name = node->GetName();
299 AliDebug((name[0] == 'F' ? 40 : 50), Form("Got volume %s", name));
300 // Check if this node is this detector
301 // The base offset for numbers in the ASCII table is 48
302 if (IS_NODE_THIS(name)) {
303 AliDebug(20, Form("Found detector node '%s' for FMD%d", name, fId));
304 thisNodeFound = kTRUE;
307 // if a half ring is found, then we're on that branch, and we
308 // check if this node represents a half ring on that branch
309 if (thisNodeFound && IS_NODE_HALF(name)) {
310 AliDebug(30, Form("Found half node '%s' for FMD%d", name, fId));
314 // Check if we're done
315 Bool_t done = (thisHalf == 'T' ? hasTop : hasBottom);
317 AliDebug(20,Form("Already has all halves for detector %c",name[1]));
322 case 'T': hasTop = true; break;
323 case 'B': hasBottom = true; break;
325 AliWarning(Form("Unknown part '%c' of FMD%d", fId));
326 continue; // because the node is unknown.
331 align = Form("FMD/FMD%d%c", fId, thisHalf);
334 // if the detector was found, then we're on that branch, and we
335 // check if this node represents a module in that branch.
336 if (thisNodeFound && thisHalf && IS_NODE_SENSOR(name)) {
337 AliDebug(30, Form("Found sensor node '%s' for FMD%d", name, fId));
339 Char_t ringid = name[1];
341 // check that the ring is valid
342 if (!GetRing(ringid)) {
343 AliWarning(Form("Invalid ring %c for FMD%d", ringid, fId));
347 // Check if we're done
350 case 'I': done = iInnerSensor >= nInnerSensor; break;
351 case 'O': done = iOuterSensor >= nOuterSensor; break;
355 AliDebug(20,Form("Already has all sensor volumes for ring %c",ringid));
358 // Get the copy (module) number, and check that it hasn't
359 // already been added to the container.
360 Int_t copy = node->GetNumber();
362 // path.Replace("ALIC", "/ALIC_1");
363 align = Form("FMD/FMD%d_%c/FMD%c_%02d", fId, thisHalf, ringid, copy);
366 case 'I': iInnerSensor++; break;
367 case 'O': iOuterSensor++; break;
370 if (!align.IsNull() && !path.IsNull()) {
371 AliDebug(20, Form("Got %s -> %s", path.Data(), align.Data()));
373 gGeoManager->SetAlignableEntry(align.Data(),path.Data());
375 AliFatal(Form("Alignable entry %s not created. "
376 "Volume path %s not valid",
377 align.Data(),path.Data()));
378 #ifdef MAKE_ALIGNABLE_PHYSICAL
379 TGeoPhysicalNode* phys = gGeoManager->MakeAlignablePN(entry);
381 AliWarning(Form("Physical node entry %s not created. "
382 "Volume path %s not valid",
383 align.Data(),path.Data()));
387 AliDebug(20, Form("FMD%d: top: %d bottom: %d Inner: %d/%d Outer %d/%d",
388 fId, hasTop, hasBottom, iInnerSensor, nInnerSensor,
389 iOuterSensor, nOuterSensor));
395 //____________________________________________________________________
397 AliFMDDetector::GetRing(Char_t id) const
399 // Get the specified ring
401 // ID Id of ring ('I' or 'O')
405 case 'I': return GetInner();
407 case 'O': return GetOuter();
412 //____________________________________________________________________
414 AliFMDDetector::GetRingZ(Char_t id) const
416 // Get the z-coordinate specified ring
418 // ID Id of ring ('I' or 'O')
422 case 'I': return GetInnerZ();
424 case 'O': return GetOuterZ();
429 //____________________________________________________________________
431 AliFMDDetector::FindTransform(Char_t ring, UShort_t sector) const
433 // Find the transformation that corresponds to sector sector in ring
435 TObjArray* matricies = 0;
437 case 'i': case 'I': matricies = fInnerTransforms; break;
438 case 'o': case 'O': matricies = fOuterTransforms; break;
441 AliWarning(Form("Unknown ring %c of FMD%d", ring, fId));
444 UInt_t module = sector / 2;
445 TGeoMatrix* m = static_cast<TGeoMatrix*>(matricies->At(module));
447 AliWarning(Form("No matrix found for sector %d in FMD%d%c",
455 //____________________________________________________________________
457 AliFMDDetector::Detector2XYZ(Char_t ring,
464 // Translate detector coordinates (this,ring,sector,strip) into
465 // (x,y,z) coordinates (in global reference frame)
466 AliFMDRing* r = GetRing(ring);
468 TGeoMatrix* m = FindTransform(ring, sector);
470 Double_t rho = r->GetStripRadius(strip);
471 Double_t phi = ((sector % 2) - .5) * r->GetTheta();
472 Double_t siThick = r->GetSiThickness();
473 Double_t modThick = (siThick
474 + r->GetPrintboardThickness()
475 + r->GetCopperThickness()
476 + r->GetChipThickness()
478 AliDebug(30,Form("Rho %7.3f, angle %7.3f", rho, phi));
479 # define DEGRAD TMath::Pi() / 180.
480 Double_t local[] = { rho * TMath::Cos(phi * DEGRAD),
481 rho * TMath::Sin(phi * DEGRAD),
482 -modThick + siThick / 2 };
484 AliDebug(30, Form("Local (%7.3f,%7.3f,%7.3f)",local[0], local[1], local[2]));
485 m->LocalToMaster(local, master);
486 AliDebug(30, Form("Master (%7.3f,%7.3f,%7.3f)",
487 master[0],master[1],master[2]));
493 //____________________________________________________________________
495 AliFMDDetector::XYZ2Detector(Double_t x,
500 UShort_t& strip) const
502 // Translate (x,y,z) coordinates (in global reference frame) into
503 // detector coordinates (this,ring,sector,strip).
506 for (int j = 0; j < 2; j++) {
507 rng = GetRing(j == 0 ? 'I' : 'O');
509 Double_t ringZ = GetRingZ(j == 0 ? 'I' : 'O');
510 Double_t modSpace = TMath::Sign(rng->GetModuleSpacing(), ringZ);
511 if (TMath::Abs(z - ringZ) < 0.01 ||
512 TMath::Abs(z - ringZ + modSpace) < 0.01) break;
515 if (rng && rng->XYZ2Detector(x, y, z - GetRingZ(rng->GetId()),
525 //____________________________________________________________________