// MuoIndexTrans.cpp // // Purpose: Translator/Adaptor for the MuoIndex container // Converts to/from MuoIndex and values // needed by geometry, electronics, and GEANT // // Created: June 1998 Michael R. Fortner // Revised: December 1998 - M. Fortner - fix geometry for bottom B,C pdts // July 1999 - M. Fortner - updates to geometry and electronic index // September 1999 - D. Hedin. update to latest Note 3537 // June 2000 - M. Fortner - extend getFrontEnd to include module map // July 2000 - D. Hedin. add bottom B hole counters // Jan 2001 - DH. fix 0x56 list and getFrontEnd bugs (from Taka). // Mar 2001 - MF add code for PDT front end id // Mar 2001 - DH add patch for a-phi octant 6 in getFrontEnd // getChannelID, getMuoIndex // Sep 2001 - CR fixes to build with gcc // Oct 2001 - DH semi-kluge to prevent PDT cell=-1 or =21 in // 0-20 cell modules // Oct 2001 - D. Wood - correct orientation of PDT's 115,116,135,136 // 10-2001 DH note. Darien's change will cause problems in MC events. We // will solve this in the future // April 2002 - DH for Juhung. add mdt front end stuff // June 2002 - MF add use of MuoIndexBits // March 2003 - Daniela Bauer -- Added translation for C-Hole counters #include "muon_index/MuoIndexTrans.hpp" #include "muon_index/MuoIndexBits.hpp" #include namespace Muon { // Initialize static data // PDT sections; const MuoIndexTrans::Section MuoIndexTrans::_pdt4 = { 4, 24, 1, 1 }, MuoIndexTrans::_pdt3 = { 3, 24, 1, 1 }, MuoIndexTrans::_pdt3BEF = {3, 16, 1, 1}, MuoIndexTrans::_pdt3Bot = {3, 21, 1, 1}, // MDT sections; MuoIndexTrans::_mdtA = { 4, 32, 1, 8}, MuoIndexTrans::_mdtB = { 3, 44, 1, 8}, MuoIndexTrans::_mdtC = { 3, 48, 1, 8}, MuoIndexTrans::_mdtBCBot = { 3, 30, 1, 8}, // MSC sections; MuoIndexTrans::_cmscA = { 1, 3, 10, 1}, MuoIndexTrans::_cmscABot = { 1, 3, 5, 1}, MuoIndexTrans::_cmscC = { 1, 4, 2, 2}, MuoIndexTrans::_cmscCBot = { 1, 1, 9, 2}, MuoIndexTrans::_cmscCBotH = { 1, 1, 2, 2}, // new section for C-Hole counters MuoIndexTrans::_cmscBBot = { 1, 1, 9, 2}, MuoIndexTrans::_cmscBEFBot = { 1, 1, 8, 2}, MuoIndexTrans::_cmscBSide = { 1, 2, 1, 2}, MuoIndexTrans::_cmscBEFSide = { 1, 1, 1, 2}, MuoIndexTrans::_fmscA = { 1, 12, 10, 1}, MuoIndexTrans::_fmscBC = { 1, 11, 10, 1}; // WAMUS orientation // 0 = local matches global // 1 = flip eta and phi // 2 = flip plane and phi // 3 = flip eta and plane const int MuoIndexTrans::_orientWAMUS[3][8] = { { 0, 0, 1, 1, 1, 0, 1, 0 }, { 3, 3, 2, 2, 3, 0, 1, 2 }, { 0, 0, 1, 1, 0, 0, 1, 1 }}; // FAMUS orientation // 0 = local matches global // 1 = flip phi const int MuoIndexTrans::_orientFAMUS[8] = { 0, 2, 0, 2, 0, 2, 0, 2 }; // forward scintillator map from channel # to index // index is encoded in a byte: // bits 0-3 = phi // bits 4-7 = eta const unsigned char MuoIndexTrans::_fmscChannels[96] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x10, // 0-7 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // 8-15 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, // 16-23 0x28, 0x29, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, // 24-31 0x36, 0x37, 0x38, 0x39, 0x40, 0x41, 0x42, 0x43, // 32-39 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, // 40-47 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, // 48-55 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // 56-63 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, // 64-71 0x76, 0x77, 0x78, 0x79, 0x80, 0x81, 0x82, 0x83, // 72-79 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x94, 0x95, // 80-87 0x96, 0x97, 0x98, 0x99, 0xA7, 0xA8, 0xA9, 0xB9 // 88-95 }; // SFE Modules; const MuoIndexTrans::FEModule MuoIndexTrans::_sfeModule[18] = { {0x50, 9, {0x00, 0x01, 0x0E, 0x0F, 0x1E, 0x20, 0x21, 0x2E, 0x2F, 0,0,0,0,0,0,0}}, {0x51, 4, {0x02, 0x03, 0x22, 0x23, 0,0,0,0,0,0,0,0,0,0,0,0}}, {0x52, 4, {0x04, 0x05, 0x24, 0x25, 0,0,0,0,0,0,0,0,0,0,0,0}}, {0x53, 9, {0x06, 0x07, 0x08, 0x09, 0x18, 0x26, 0x27, 0x28, 0x29, 0,0,0,0,0,0,0}}, {0x55, 5, {0x0A, 0x1A, 0x1B, 0x2A, 0x2B,0,0,0,0,0,0,0,0,0,0,0}}, {0x56, 5, {0x0D, 0x1C, 0x1D, 0x2C, 0x2D,0,0,0,0,0,0,0,0,0,0,0}}, {0x70, 8, {0x80, 0x81, 0x82, 0x83, 0x90, 0x91, 0x92, 0x93, 0,0,0,0,0,0,0,0}}, {0x72, 8, {0x84, 0x85, 0x86, 0x87, 0x94, 0x95, 0x96, 0x97, 0,0,0,0,0,0,0,0}}, {0x74, 8, {0x88, 0x89, 0x8A, 0x8B, 0x98, 0x99, 0x9A, 0x9B, 0,0,0,0,0,0,0,0}}, {0x76, 8, {0x8C, 0x8D, 0x8E, 0x8F, 0x9C, 0x9D, 0x9E, 0x9F, 0,0,0,0,0,0,0,0}}, {0x90, 8, {0xC0, 0xC1, 0xC2, 0xC3, 0xD0, 0xD1, 0xD2, 0xD3, 0,0,0,0,0,0,0,0}}, {0x92, 8, {0xC4, 0xC5, 0xC6, 0xC7, 0xD4, 0xD5, 0xD6, 0xD7, 0,0,0,0,0,0,0,0}}, {0x94, 8, {0xC8, 0xC9, 0xCA, 0xCB, 0xD8, 0xD9, 0xDA, 0xDB, 0,0,0,0,0,0,0,0}}, {0x96, 8, {0xCC, 0xCD, 0xCE, 0xCF, 0xDC, 0xDD, 0xDE, 0xDF, 0,0,0,0,0,0,0,0}}, {0x278, 8, {0xA0, 0xA1, 0xA2, 0xA3, 0xAC, 0xAD, 0xAE, 0xAF, 0,0,0,0,0,0,0,0}}, {0x279, 8, {0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0,0,0,0,0,0,0,0}}, {0x298, 8, {0xE0, 0xE1, 0xE2, 0xE3, 0xEC, 0xED, 0xEE, 0xEF, 0,0,0,0,0,0,0,0}}, {0x299, 8, {0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0,0,0,0,0,0,0,0}} }; // Default constructor and destructor MuoIndexTrans::MuoIndexTrans() {} MuoIndexTrans::~MuoIndexTrans() {} // Access correct section geometry MuoIndexTrans::Section MuoIndexTrans::selectSection(const MuoSectionIndex& ix) const { if (ix.region() == 0) { // WAMUS if (ix.type() == 0) { // pdt switch (ix.layer()) { case 0 : return (ix.isBottom()) ? _pdt3 : _pdt4; case 1 : if (ix.isWamEF()) return (ix.isBottom()) ? _pdt3Bot : _pdt3BEF; else return _pdt3; case 2 : if (ix.isBottom()) return (ix.isWamEF()) ? _pdt3BEF : _pdt3Bot; else return _pdt3; default : return _pdt3; } } else { // cmsc switch (ix.layer()) { case 0 : return (ix.isBottom()) ? _cmscABot : _cmscA; case 1 : if (ix.isWamEF()) return (ix.isBottom()) ? _cmscBEFBot : _cmscBEFSide; else return (ix.isBottom()) ? _cmscBBot : _cmscBSide; case 2 : // return (ix.isBottom()) ? _cmscCBot : _cmscC; // added C-Hole counters if (ix.isBottom()) { if (ix.barrel() == 0 || ix.barrel() == 4) { return _cmscCBot;} else if (ix.barrel() == 1 || ix.barrel() == 3) { return _cmscCBotH;} // hole counters have barrel 1 or 3 else {std::cout << "Error in MuoIndexTrans::selectSection " << std::endl;} } else {return _cmscC;} default : return _cmscC; } } } else { // FAMUS if (ix.type() == 0) { // MDT switch (ix.layer()) { case 1 : return (ix.isBottom()) ? _mdtBCBot : _mdtB; case 2 : return (ix.isBottom()) ? _mdtBCBot : _mdtC; default : return _mdtA; } } else { // fmsc return (ix.layer() == 0) ? _fmscA : _fmscBC; } } } int MuoIndexTrans::getOrientation(const MuoSectionIndex& ix) const { int idir = 0; if (ix.type() != 0 ) return idir; if (ix.region() == 0) { idir = _orientWAMUS[ix.layer()][ix.octant()]; if (ix.isBottom() && ix.layer() == 1 && ix.isWamEF()) idir = idir + 2; } else { idir = _orientFAMUS[ix.octant()]; if (ix.region() == 2) idir = 2 - idir; } return idir; } // // Accessors for all geometry int MuoIndexTrans::getNumPlanes(const MuoSectionIndex& ix) const { return selectSection(ix).planes; } int MuoIndexTrans::getNumPlanes(const MuoIndex& ix) const { return selectSection(ix.section()).planes; } int MuoIndexTrans::getNumEtaCells(const MuoSectionIndex& ix) const { return selectSection(ix).etacells; } int MuoIndexTrans::getNumEtaCells(const MuoIndex& ix) const { return selectSection(ix.section()).etacells; } int MuoIndexTrans::getNumPhiCells(const MuoSectionIndex& ix) const { return selectSection(ix).phicells; } int MuoIndexTrans::getNumPhiCells(const MuoIndex& ix) const { return selectSection(ix.section()).phicells; } int MuoIndexTrans::getNumTubes(const MuoSectionIndex& ix) const { return selectSection(ix).tubes; } int MuoIndexTrans::getNumTubes(const MuoIndex& ix) const { return selectSection(ix.section()).tubes; } // // Adaptors for local geometry int MuoIndexTrans::getLocalWire(const MuoIndex& ix) const { int iwire = ix.eta(); if (ix.type() == 1) return iwire; if (ix.region() == 0) { // WAMUS int idir = getOrientation(ix.section()); if (idir == 1 || idir == 3) { iwire = selectSection(ix.section()).etacells - 1 - iwire; } } else { // FAMUS iwire = iwire * 8 + ix.tube(); } return iwire; } int MuoIndexTrans::getLocalPlane(const MuoIndex& ix) const { int iplane = ix.plane(); if (ix.type() == 1) return iplane; // Scintillator // PDT and MDT int idir = getOrientation(ix.section()); if (idir == 2 || idir == 3) { iplane = selectSection(ix.section()).planes - 1 - iplane; } return iplane; } int MuoIndexTrans::getGlobalWire(const MuoSectionIndex& section, int wire, int tube) const { if (section.type() == 1) return wire; if (section.region() == 0) { // WAMUS int idir = _orientWAMUS[section.layer()][section.octant()]; if (idir == 1 || idir == 3) { wire = selectSection(section).etacells - 1 - wire; } } else { // FAMUS wire = (wire - tube)/8; } return wire; } int MuoIndexTrans::getGlobalPlane(const MuoSectionIndex& section, int plane) const { if (section.type() == 1) return plane; if (section.region() == 0) { // WAMUS int idir = _orientWAMUS[section.layer()][section.octant()]; if (idir == 2 || idir == 3) { plane = selectSection(section).planes - 1 - plane; } } return plane; } // Local to global function, not defined for scintillator MuoIndex MuoIndexTrans::getMuoIndex(const MuoSectionIndex& sect, int plane, int wire) const { if (sect.type() == 1) return MuoIndex(sect, MuoCellIndex()); if (sect.region() == 0) { // WAMUS int pln = plane; int eta = wire; int idir = getOrientation(sect); if (idir == 2 || idir == 3) pln = selectSection(sect).planes - 1 - plane; if (idir == 1 || idir == 3) eta = selectSection(sect).etacells - 1 - wire; return MuoIndex(sect, MuoCellIndex (pln, eta, 0, 0) ); } else { // FAMUS int eta = wire/8; int tube = wire%8; return MuoIndex(sect, MuoCellIndex (plane, eta, 0, tube) ); } } // Adaptors for readout electronics int MuoIndexTrans::getModuleID(const MuoIndex& ix) const { int modid; if (ix.region() == 0) { // WAMUS if (ix.type() == 0) { // pdt modid = MuoIndexBits::putModID(ix.layer(), ix.barrel(), ix.octant()); } else { // cmsc - returns SFE crate number! int sectOct = ix.octant(); if (sectOct == 7) sectOct = 0; if (sectOct == 4) sectOct = 3; modid = MuoIndexBits::putModID(0, 5, sectOct); } } else { //FAMUS int sectReg = 4 + ix.region()*2; int sectOct = ix.octant() & 6; if (ix.type() != 0) { // fmsc if(ix.layer()==2) sectOct = (ix.section().isEast()) ? 8 : 9; sectReg++; } int ilayr = ((ix.layer() == 1) && (ix.type() == 1)) ? 0 : ix.layer(); modid = MuoIndexBits::putModID(ilayr, sectReg, sectOct); } return modid; } int MuoIndexTrans::getFrontEnd(const MuoIndex& ix) const { if (ix.type() == 0) { if (ix.region() == 0) {//pdt int mpln = (getNumPlanes(ix.section()) == 3) ? 8 : 6; if (getNumEtaCells(ix.section()) == 21) mpln = 7; return ((getModuleID(ix)<<4) + (getLocalWire(ix)/mpln)); } else {//mdt int ncoladb = 24 / getNumPlanes(ix.section()); int adb = (getNumPlanes(ix.section())*(ix.eta()%ncoladb) + ix.plane())/4; int mdcid = getModuleID(ix)*100 + (ix.eta()/ncoladb); if((ix.octant()%2) == 1) { // odd octants, special for NB7, NC7, SB7, SC7 mdcid += (ix.octant()==7 && (ix.layer()==1 || ix.layer()==2)) ? 4 : 6; } return (mdcid*10 + adb); } } // msc return MuoIndexBits::putSFE(getSectionID(ix), getSuboctant(ix)); } // get front ends associated with a module ID, return -1 if invalid int MuoIndexTrans::getFrontEnd(const int modID, const int index) const { for (int i=0; i<18; i++) { if (modID == _sfeModule[i].moduleID) { if (index >= 0 && index < _sfeModule[i].numFE) { return _sfeModule[i].FEID[index]; } } } return -1; } // get number of front ends associated with a module ID, return 0 if invalid int MuoIndexTrans::getFECount(const int modID) const { for (int i=0; i<18; i++) { if (modID == _sfeModule[i].moduleID) { return _sfeModule[i].numFE; } } return 0; } int MuoIndexTrans::getChannelID(const MuoIndex& ix) const { if (ix.section().isPDT()) return MuoIndexBits::putPDTChannel(getSectionID(ix), getLocalWire(ix), getLocalPlane(ix)); if (ix.section().isMDT()) return MuoIndexBits::putMDTChannel(getSectionID(ix), ix.eta(), ix.plane()); if (ix.section().isMSC()) return MuoIndexBits::putMSCChannel(getFrontEnd(ix), getPMT(ix)); return 0; } MuoIndex MuoIndexTrans::getMuoIndex(const int modID, const int chanID) const { // get section index MuoSectionIndex sect = getMuoSectionIndex(modID, chanID); // initialize cell index parameters MuoCellIndex cell; int ipln = 0; int ieta = 0; int iphi = 0; int itub = 0; // classify muon detector type if (sect.isPDT()) { cell = getPDTIndex(sect, MuoIndexBits::getPDTPlane(chanID), MuoIndexBits::getPDTWire(chanID)); } if (sect.isMDT()) { cell = MuoCellIndex(MuoIndexBits::getMDTPlane(chanID), MuoIndexBits::getMDTEta(chanID), iphi, itub); } if (sect.isMSC()) { if (sect.isFamus()) { int ifpmt = MuoIndexBits::getPMT(chanID) + 48*MuoIndexBits::getSubOct(chanID); ieta = _fmscChannels[ifpmt] >> 4; iphi = _fmscChannels[ifpmt] & 15; if ((sect.octant()&1)==1) iphi=9-iphi; cell = MuoCellIndex(ipln, ieta, iphi, itub); } else { cell = MuoCellIndex(ipln, MuoIndexBits::getCMSCEta(chanID), MuoIndexBits::getCMSCPhi(chanID), MuoIndexBits::getCMSCTube(chanID)); } } return MuoIndex(sect, cell); } MuoSectionIndex MuoIndexTrans::getMuoSectionIndex(const int modID, const int chanID) const { // initialize section index parameters int ireg = 0; int ityp = 0; int ilyr = 0; int ioct = 0; int ibar = 0; // extract module ID values // classify muon detector type int idlyr = MuoIndexBits::getLayer(modID); int idsec = MuoIndexBits::getBarrel(modID); if (idsec <= 4) { // pdt ilyr = idlyr; ioct = MuoIndexBits::getOctant(modID); ibar = idsec; } else { ityp = MuoIndexBits::getType(modID); ireg = MuoIndexBits::getChanRegion(chanID); ilyr = MuoIndexBits::getChanLayer(chanID); ioct = MuoIndexBits::getChanOctant(chanID); if (idsec == 5) { // cmsc ibar = MuoIndexBits::getCMSCBarrel(chanID); } } return MuoSectionIndex(ireg, ityp, ilyr, ioct, ibar); } int MuoIndexTrans::getSectionID(const MuoIndex& ix) const { if (ix.section().isPDT()) return MuoIndexBits::putPDTSection(ix.layer(), ix.octant(), ix.barrel()); return MuoIndexBits::putSection(ix.type(), ix.region(), ix.layer(), ix.octant()); } int MuoIndexTrans::getSuboctant(const MuoIndex& ix) const { int suboct = 0; if (ix.section().isFamus()) { //fmsc if (ix.eta()>4) { if ((ix.octant()%2)==0 && ix.phi()>1) suboct=1; if ((ix.octant()%2)==1 && (9-ix.phi())>1) suboct=1; if (ix.eta() > 5) suboct=1; } } else { //cmsc if (ix.layer() == 0) { if (ix.phi() >= 5) suboct = 1; if (ix.octant() == 6) suboct = 1; } // A - layer if ((ix.layer() == 2) && !ix.section().isBottom() && (ix.barrel() >= 3)) suboct = 1; // central C top-sides if (ix.section().isBottomBC() && (ix.barrel() >= 3)) { suboct = ((ix.layer()==1&&ix.octant()==5&&ix.barrel()==3&&ix.phi()==8)|| (ix.layer()==1&&ix.octant()==6&&ix.barrel()==3&&ix.phi()==0)) ? 0 : 1; } // 8 new scintillators in the C-Hole have all suboctant == 0 if (ix.type() == 1 && ix.region()==0 && ix.layer()==2 && (ix.octant()==5 || ix.octant()==6) && (ix.barrel() == 1 || ix.barrel() == 3)){ suboct = 0; } } return suboct; } int MuoIndexTrans::getPMT(const MuoIndex& ix) const { int ipmt = 0; if (ix.section().isFamus()) { // fmsc int iphi = ((ix.octant()%2)==0) ? ix.phi() : 9 - ix.phi(); unsigned char temp = (ix.eta()*16) + iphi; int j=-1; for (int i=0;i<96;i++) { if(_fmscChannels[i]==temp) j=i; } if (j>-1) ipmt = j - getSuboctant(ix)*48; } else { // cmsc if (ix.layer() == 0) // A-layer ipmt = (ix.phi()>4) ? (ix.barrel() - 1)*16 + (ix.eta()*5+ix.phi() - 5) : (ix.barrel() - 1)*16 + (ix.eta()*5+ix.phi()); if (ix.layer() == 1) { // B-layer if(ix.section().isBottom()) { ipmt = ix.phi()*2 + ix.tube(); if ((ix.octant()==6) && (ix.barrel()==1 || ix.barrel()==3)) ipmt = ((ix.phi()-1)*2) + ix.tube(); //for hole counters if (ix.barrel()==1 || ix.barrel()==4) ipmt |= 16; // add on 4 hole counters by hand if ((ix.octant()==5) && (ix.phi()==8)) { if (ix.barrel()==1) ipmt = 0x20 + ix.tube(); if (ix.barrel()==3) ipmt = 0x22 + ix.tube(); } if ((ix.octant()==6) && (ix.phi()==0)) { if (ix.barrel()==1) ipmt = 0x20 + ix.tube(); if (ix.barrel()==3) ipmt = 0x22 + ix.tube(); } } if (ix.section().isSideBScint()) { // B-layer sides ipmt = 16 | ((ix.barrel()-1)<<2) | (ix.eta()<<1) | ix.tube(); if(ix.barrel()==0) ipmt = ix.tube(); if(ix.barrel()==4) ipmt = 32 | ix.tube(); } } if (ix.layer() == 2) { // C-layer if (ix.section().isBottom()) { // ipmt = ix.phi()*2 + ix.tube(); // modified to include C-Hole counters if (ix.barrel() == 0 || ix.barrel() == 4) { ipmt = ix.phi()*2 + ix.tube(); } // this is for the new scintillators else if (ix.barrel() == 1){ ipmt = 32 + ix.phi()*2 + ix.tube();} else if (ix.barrel() == 3){ ipmt = 36 + ix.phi()*2 + ix.tube();} // this should really throw an error here else {std::cout << "Layer 2 in Octants 5 and 6 only has 4 posible barrel numbers and " << ix.barrel() << " is not one of them !!!" << std::endl; } } // isBottom() else { if (ix.barrel() < 3) { ipmt = (ix.barrel()<<4) | (ix.eta() << 2) | (ix.phi() << 1) | ix.tube(); } else { ipmt = ((ix.barrel()-3)<<4) | (ix.eta() << 2) | (ix.phi() << 1) | ix.tube(); } } } } return ipmt; } // Convert from PDT local to global // lpln is the local plane number // lwir is the local wire number // returns default for non-PDT sections MuoCellIndex MuoIndexTrans::getPDTIndex(const MuoSectionIndex& ix, int lpln, int lwir) const { if (ix.region() != 0 || ix.type() != 0 ) return MuoCellIndex(); int idir = getOrientation(ix); int ipln = (idir == 2 || idir == 3) ? selectSection(ix).planes - 1 - lpln : lpln; int ieta = (idir == 1 || idir == 3) ? selectSection(ix).etacells - 1 - lwir : lwir; if(ieta<0) ieta=0; // DH 10/01 kluge if(ieta>selectSection(ix).etacells -1) ieta=selectSection(ix).etacells -1; return MuoCellIndex(ipln, ieta, 0, 0); } }