#include <TGeoManager.h> // ROOT_TGeoManager
#include <TGeoPhysicalNode.h> // ROOT_TGeoPhysicalNode
#include <TGeoMatrix.h> // ROOT_TGeoMatrix
#include <TMath.h> // ROOT_TMath
#include "AliFMDDetector.h"
#include "AliFMDRing.h"
#include "AliFMDDebug.h"
ClassImp(AliFMDDetector)
#if 0
;
#endif
AliFMDDetector::AliFMDDetector(Int_t id, AliFMDRing* inner, AliFMDRing* outer)
: TNamed(Form("FMD%d", id), "Forward multiplicity ring"),
fId(id),
fInnerZ(0.),
fOuterZ(0.),
fInnerHoneyLowR(0.),
fInnerHoneyHighR(0.),
fOuterHoneyLowR(0.),
fOuterHoneyHighR(0.),
fInner(inner),
fOuter(outer),
fInnerTransforms(0),
fOuterTransforms(0)
{
SetInnerHoneyLowR(0);
SetInnerHoneyHighR(0);
SetInnerZ(0);
SetOuterZ(0);
SetOuterHoneyLowR(0);
SetOuterHoneyHighR(0);
}
AliFMDDetector::AliFMDDetector(const AliFMDDetector& other)
: TNamed(other),
fId(other.fId),
fInnerZ(0.),
fOuterZ(0.),
fInnerHoneyLowR(0.),
fInnerHoneyHighR(0.),
fOuterHoneyLowR(0.),
fOuterHoneyHighR(0.),
fInner(other.fInner),
fOuter(other.fOuter),
fInnerTransforms(other.fInnerTransforms),
fOuterTransforms(other.fOuterTransforms)
{
SetInnerHoneyLowR(other.GetInnerHoneyLowR());
SetInnerHoneyHighR(other.GetInnerHoneyHighR());
SetInnerZ(other.GetInnerZ());
SetOuterZ(other.GetOuterZ());
SetOuterHoneyLowR(other.GetOuterHoneyLowR());
SetOuterHoneyHighR(other.GetOuterHoneyHighR());
}
AliFMDDetector&
AliFMDDetector::operator=(const AliFMDDetector& other)
{
if (&other == this) return *this;
SetName(other.GetName());
SetTitle(other.GetTitle());
fId = other.fId;
fInner = other.fInner;
fOuter = other.fOuter;
fInnerTransforms = other.fInnerTransforms;
fOuterTransforms = other.fOuterTransforms;
SetInnerHoneyLowR(other.GetInnerHoneyLowR());
SetInnerHoneyHighR(other.GetInnerHoneyHighR());
SetInnerZ(other.GetInnerZ());
SetOuterZ(other.GetOuterZ());
SetOuterHoneyLowR(other.GetOuterHoneyLowR());
SetOuterHoneyHighR(other.GetOuterHoneyHighR());
return *this;
}
void
AliFMDDetector::Init()
{
if (fInner) {
SetInnerHoneyLowR(fInner->GetLowR() + 1.);
SetInnerHoneyHighR(fInner->GetHighR() + 1.);
}
if (fOuter) {
SetOuterHoneyLowR(fOuter->GetLowR() + 1.);
SetOuterHoneyHighR(fOuter->GetHighR() + 1.);
}
}
Bool_t
AliFMDDetector::HasAllTransforms(Char_t ring) const
{
AliFMDRing* r = GetRing(ring);
if (!r) return kTRUE;
TObjArray* matricies = (r == fInner ? fInnerTransforms : fOuterTransforms);
if (!matricies) return kTRUE;
if (matricies->GetEntries() == r->GetNModules()) return kTRUE;
return kFALSE;
}
#define IS_NODE_THIS(name) \
(name[0] == 'F' && name[2] == 'M' && name[1] == Char_t(48+fId) && \
(name[3] == 'T' || name[3] == 'B'))
#define IS_NODE_SENSOR(name) \
(name[0] == 'F' && (name[2] == 'B' || name[2] == 'F') && name[3] == 'H')
#define IS_NODE_HALF(name) \
(name[0] == 'F' && name[2] == 'M' && (name[3] == 'B' || name[3] == 'T'))
#define HALF_FORMAT "FMD/FMD%d_%c"
#define SENSOR_FORMAT "FMD/FMD%d_%c/FMD%c_%02d"
void
AliFMDDetector::InitTransformations()
{
if ((!fInner || (fInner && fInnerTransforms)) &&
(!fOuter || (fOuter && fOuterTransforms))) {
AliFMDDebug(5, ("Transforms for FMD%d already registered", fId));
return;
}
AliFMDDebug(5, ("Initializing transforms for FMD%d", fId));
if (!gGeoManager) {
AliFatal("No TGeoManager defined");
return;
}
if (fInner && !fInnerTransforms)
fInnerTransforms = new TObjArray(fInner->GetNModules());
if (fOuter && !fOuterTransforms)
fOuterTransforms = new TObjArray(fOuter->GetNModules());
for (size_t ihalf = 0; ihalf < 2; ihalf++) {
char half = (ihalf == 0 ? 'T' : 'B');
TString path(Form(HALF_FORMAT, fId, half));
TGeoPNEntry* entry = gGeoManager->GetAlignableEntry(path.Data());
if (!entry) {
AliError(Form("Alignable entry for half-detector \"%s\" not found!",
path.Data()));
continue;
}
TGeoPhysicalNode* pn = entry->GetPhysicalNode();
if (!pn) {
AliWarning(Form("Making physical volume for \"%s\"", path.Data()));
pn = gGeoManager->MakeAlignablePN(entry);
if (!pn) {
AliError(Form("No physical node for \"%s\"", path.Data()));
continue;
}
}
}
for (size_t iring = 0; iring < 2; iring++) {
char ring = (iring == 0 ? 'I' : 'O');
TObjArray* trans = 0;
AliFMDRing* r = 0;
switch (ring) {
case 'I': r = fInner; trans = fInnerTransforms; break;
case 'O': r = fOuter; trans = fOuterTransforms; break;
}
if (!r || !trans) continue;
Int_t nModules = r->GetNModules();
if (nModules <= 0) continue;
for (size_t ihalf = 0; ihalf < 2; ihalf++) {
char half = (ihalf == 0 ? 'T' : 'B');
Int_t base = (half == 'T' ? 0 : nModules / 2);
for (Int_t imod = 0; imod < nModules / 2; imod++) {
TString path(Form(SENSOR_FORMAT, fId, half, ring, base+imod));
TGeoPNEntry* entry = gGeoManager->GetAlignableEntry(path.Data());
if (!entry) {
AliError(Form("Alignable entry for sensor \"%s\" not found!",
path.Data()));
continue;
}
TGeoPhysicalNode* pn = entry->GetPhysicalNode();
if (!pn) {
AliWarning(Form("Making physical volume for \"%s\"", path.Data()));
pn = gGeoManager->MakeAlignablePN(entry);
if (!pn) {
AliError(Form("No physical node for \"%s\"", path.Data()));
continue;
}
}
const TGeoMatrix* pm = pn->GetMatrix();
if (!pm) {
AliError(Form("No matrix for path \"%s\"", path.Data()));
continue;
}
TGeoMatrix* t = new TGeoHMatrix(*pm);
trans->AddAt(t, base+imod);
AliFMDDebug(5, ("Found matrix for path \"%s\": %p",path.Data(),pm));
}
}
}
if (HasAllTransforms('I') && HasAllTransforms('O')) return;
TGeoVolume* topVolume = gGeoManager->GetTopVolume();
if (!topVolume) {
AliFatal("No top-level volume defined");
return;
}
TGeoIterator next(topVolume);
TGeoNode* node = 0;
Bool_t thisNodeFound = kFALSE;
Bool_t allInners = HasAllTransforms('I');
Bool_t allOuters = HasAllTransforms('O');
while ((node = static_cast<TGeoNode*>(next()))
&& !(allInners && allOuters)) {
const Char_t* name = node->GetName();
if (!name) continue;
AliFMDDebug(50, ("Got volume %s", name));
if (IS_NODE_THIS(name)) {
AliFMDDebug(20, ("Found detector node '%s' for FMD%d", name, fId));
thisNodeFound = kTRUE;
}
if (thisNodeFound && IS_NODE_SENSOR(name)) {
AliFMDDebug(20, ("Found sensor node '%s' for FMD%d", name, fId));
Char_t ringid = name[1];
AliFMDRing* ring = GetRing(ringid);
if (!ring) continue;
Bool_t& done = (ring == fInner ? allInners : allOuters);
if ((done = HasAllTransforms(ringid))) {
AliFMDDebug(20, ("Already has all module transforms for ring %c",
ringid));
continue;
}
TObjArray* matricies = (ringid == 'i' || ringid == 'I'
? fInnerTransforms : fOuterTransforms);
Int_t copy = node->GetNumber();
if (matricies->At(copy)) {
AliWarning(Form("Have a transformation for module %d in ring %c",
copy, ringid));
continue;
}
TGeoMatrix* trans = new TGeoHMatrix(*(next.GetCurrentMatrix()));
matricies->AddAt(trans, copy);
}
}
}
void
AliFMDDetector::SetAlignableVolumes() const
{
AliFMDDebug(10, ("Making alignable volumes for FMD%d", fId));
if (!gGeoManager) {
AliFatal("No TGeoManager defined");
return;
}
TGeoVolume* topVolume = gGeoManager->GetTopVolume();
if (!topVolume) {
AliFatal("No top-level volume defined");
return;
}
TGeoIterator next(topVolume);
next.Reset(topVolume);
next.SetTopName(Form("/%s_1", topVolume->GetName()));
TGeoNode* node = 0;
Int_t nInnerSensor = (fInner ? fInner->GetNModules() : 0);
Int_t nOuterSensor = (fOuter ? fOuter->GetNModules() : 0);
Bool_t thisNodeFound = kFALSE;
Char_t thisHalf = '\0';
Int_t iInnerSensor = 0;
Int_t iOuterSensor = 0;
Bool_t hasTop = false;
Bool_t hasBottom = false;
TString path, align;
while ((node = static_cast<TGeoNode*>(next()))
&& (iInnerSensor < nInnerSensor || iOuterSensor < nOuterSensor
|| !hasBottom || !hasTop)) {
const Char_t* name = node->GetName();
if (!name) continue;
AliFMDDebug((name[0] == 'F' ? 40 : 50), ("Got volume %s", name));
if (IS_NODE_THIS(name)) {
AliFMDDebug(20, ("Found detector node '%s' for FMD%d", name, fId));
thisNodeFound = kTRUE;
}
if (thisNodeFound && IS_NODE_HALF(name)) {
AliFMDDebug(30, ("Found half node '%s' for FMD%d", name, fId));
thisHalf = name[3];
Bool_t done = (thisHalf == 'T' ? hasTop : hasBottom);
if (done) {
AliFMDDebug(20, ("Already has all halves for detector %c",name[1]));
continue;
}
switch (thisHalf) {
case 'T': hasTop = true; break;
case 'B': hasBottom = true; break;
default:
AliWarning(Form("Unknown part '%c' of FMD%d", thisHalf, fId));
continue;
}
next.GetPath(path);
align = Form(HALF_FORMAT, fId, thisHalf);
}
if (thisNodeFound && thisHalf && IS_NODE_SENSOR(name)) {
AliFMDDebug(30, ("Found sensor node '%s' for FMD%d", name, fId));
Char_t ringid = name[1];
if (!GetRing(ringid)) {
AliWarning(Form("Invalid ring %c for FMD%d", ringid, fId));
continue;
}
Bool_t done = false;
switch (ringid) {
case 'I': done = iInnerSensor >= nInnerSensor; break;
case 'O': done = iOuterSensor >= nOuterSensor; break;
default: continue;
}
if (done) {
AliFMDDebug(20, ("Already has all sensor volumes for ring %c",ringid));
continue;
}
Int_t copy = node->GetNumber();
next.GetPath(path);
align = Form(SENSOR_FORMAT, fId, thisHalf, ringid, copy);
switch (ringid) {
case 'I': iInnerSensor++; break;
case 'O': iOuterSensor++; break;
}
}
if (!align.IsNull() && !path.IsNull()) {
AliFMDDebug(20, ("Got %s -> %s", path.Data(), align.Data()));
TGeoPNEntry* entry =
gGeoManager->SetAlignableEntry(align.Data(),path.Data());
if(!entry)
AliFatal(Form("Alignable entry %s not created. "
"Volume path %s not valid",
align.Data(),path.Data()));
#ifdef MAKE_ALIGNABLE_PHYSICAL
TGeoPhysicalNode* phys = gGeoManager->MakeAlignablePN(entry);
if (!phys)
AliWarning(Form("Physical node entry %s not created. "
"Volume path %s not valid",
align.Data(),path.Data()));
#endif
align = "";
}
AliFMDDebug(20, ("FMD%d: top: %d bottom: %d Inner: %d/%d Outer %d/%d",
fId, hasTop, hasBottom, iInnerSensor, nInnerSensor,
iOuterSensor, nOuterSensor));
}
}
AliFMDRing*
AliFMDDetector::GetRing(Char_t id) const
{
switch (id) {
case 'i':
case 'I': return GetInner();
case 'o':
case 'O': return GetOuter();
}
return 0;
}
Double_t
AliFMDDetector::GetRingZ(Char_t id) const
{
switch (id) {
case 'i':
case 'I': return GetInnerZ();
case 'o':
case 'O': return GetOuterZ();
}
return 0;
}
TGeoMatrix*
AliFMDDetector::FindTransform(Char_t ring, UShort_t sector) const
{
TObjArray* matricies = 0;
switch (ring) {
case 'i': case 'I': matricies = fInnerTransforms; break;
case 'o': case 'O': matricies = fOuterTransforms; break;
}
if (!matricies) {
AliWarning(Form("Unknown ring %c of FMD%d", ring, fId));
return 0;
}
UInt_t module = sector / 2;
TGeoMatrix* m = static_cast<TGeoMatrix*>(matricies->At(module));
if (!m) {
AliWarning(Form("No matrix found for sector %d in FMD%d%c",
sector, fId, ring));
return 0;
}
return m;
}
void
AliFMDDetector::Detector2XYZ(Char_t ring,
UShort_t sector,
UShort_t strip,
Double_t& x,
Double_t& y,
Double_t& z) const
{
AliFMDRing* r = GetRing(ring);
if (!r) {
AliWarning(Form("No such ring FMD%d%c ", fId, ring));
return;
}
TGeoMatrix* m = FindTransform(ring, sector);
if (!m) {
AliWarning(Form("No transfrmation found for FMD%d%c[%02d]",
fId, ring, sector));
return;
}
Double_t rho = r->GetStripRadius(strip);
Double_t phi = ((sector % 2) - .5) * r->GetTheta();
Double_t siThick = r->GetSiThickness();
#if 0
Double_t modThick = (siThick
+ r->GetPrintboardThickness()
+ r->GetCopperThickness()
+ r->GetChipThickness()
+ r->GetSpacing());
#endif
AliFMDDebug(30, ("Rho %7.3f, angle %7.3f", rho, phi));
Double_t local[] = { rho * TMath::Cos(phi * TMath::DegToRad()),
rho * TMath::Sin(phi * TMath::DegToRad()),
siThick / 2 };
Double_t master[3];
AliFMDDebug(30, ("Local (%7.3f,%7.3f,%7.3f)",local[0], local[1], local[2]));
m->LocalToMaster(local, master);
AliFMDDebug(30, ("Master (%7.3f,%7.3f,%7.3f)",
master[0],master[1],master[2]));
x = master[0];
y = master[1];
z = master[2];
}
Bool_t
AliFMDDetector::XYZ2Detector(Double_t x,
Double_t y,
Double_t z,
Char_t& ring,
UShort_t& sector,
UShort_t& strip) const
{
AliFMDRing* rng = 0;
ring = -1;
for (int j = 0; j < 2; j++) {
rng = GetRing(j == 0 ? 'I' : 'O');
if (!rng) continue;
Double_t ringZ = GetRingZ(j == 0 ? 'I' : 'O');
Double_t modSpace = TMath::Sign(rng->GetModuleSpacing(), ringZ);
if (TMath::Abs(z - ringZ) < 0.01 ||
TMath::Abs(z - ringZ + modSpace) < 0.01) break;
rng = 0;
}
if (rng && rng->XYZ2Detector(x, y, z - GetRingZ(rng->GetId()),
sector, strip)) {
ring = rng->GetId();
return kTRUE;
}
return kFALSE;
}