// File: DTranslationTable.cc // Created: Thu Jun 27 16:07:11 EDT 2013 // Creator: davidl (on Darwin harriet.jlab.org 11.4.2 i386) // Modified for standalone use: Michael Staib Oct. 2014 #include "DTranslationTable.h" #include #include using namespace std; static bool tt_initialized = false; static map TT; string ROCID_MAP_FILENAME; static map rocid_map; // (see ReadOptionalROCidTranslation() for details) static map rocid_inv_map; // (see ReadOptionalROCidTranslation() for details) //................................... // Less than operator for csc_t data types. This is used by // the map to order the entires by key bool operator<(const DTranslationTable::csc_t &a, const DTranslationTable::csc_t &b) { if (a.rocid < b.rocid) return true; if (a.rocid > b.rocid) return false; if (a.slot < b.slot) return true; if (a.slot > b.slot) return false; if (a.channel < b.channel) return true; return false; } //--------------------------------- // DTranslationTable (Constructor) //--------------------------------- DTranslationTable::DTranslationTable() { // Default is to just read translation table from CCDB. If this fails, // then an attempt will be made to read from a file on the local disk. // The filename can be specified to be anything, but if the user specifies // this, then we assume that they want to use it and skip using the CCDB. // They may also specify that they want to skip checking the CCDB via // the "TT:NO_CCDB" parameter. This would only be useful if they want to // force the use of a local file named "tt.xml". char* RateHomePath; RateHomePath = getenv("TESTBENCH_HOME"); if(RateHomePath == NULL) cout << " TESTBENCH_HOME env variable not set!!!!!" << endl; XML_FILENAME = Form("%s/src/tt.xml", RateHomePath); ROCID_MAP_FILENAME = "rocid.map"; // Look for and read in an optional rocid <-> rocid translation table ReadOptionalROCidTranslation(); // Read in Translation table. This will create DChannelInfo objects // and store them in the "TT" map, indexed by csc_t objects ReadTranslationTable(); } //--------------------------------- // ~DTranslationTable (Destructor) //--------------------------------- DTranslationTable::~DTranslationTable() { } //--------------------------------- // ReadOptionalROCidTranslation //--------------------------------- void DTranslationTable::ReadOptionalROCidTranslation(void) { // Some data may be taken with the ROC ID value set // incorrectly in CODA. For CODA 3.0 data, there is // actually no way to set it so it can be different // for every CODA configuration. A simple work-around // for this is to use a map file to list the translation // from the crate numbers used in the evio file to those // stored in the TT. Check here if a local file exists // with the name specified by the TT:ROCID_MAP_FILENAME // config parameter (default is "rocid.map"). If so, // read it in. The format is just 2 values per line. // The first is the rocid in the evio file, and the // second, what the rocid is in the TT. Note that the // value of the crate copied into the data objects // will be what is in the EVIO file. ifstream ifs(ROCID_MAP_FILENAME.c_str()); if (!ifs.is_open()) return; std::cout << "Opened ROC id translation map: " << ROCID_MAP_FILENAME << std::endl; while (ifs.good()) { char line[256]; ifs.getline(line, 256); if (ifs.gcount() < 1) break; if (line[0] == '#') continue; stringstream ss(line); uint32_t from=10000, to=10000; ss >> from >> to; // from=evio to=TT if ( to == 10000 ) { if ( from != 10000) { std::cout << "unable to convert line:" << std::endl; std::cout << " " << line; } }else{ rocid_map[from] = to; rocid_inv_map[to] = from; } } ifs.close(); if (rocid_map.size() == rocid_inv_map.size()) { std::cout << " Read " << rocid_map.size() << " entries" << std::endl; map::iterator iter; for (iter=rocid_map.begin(); iter != rocid_map.end(); iter++) { std::cout << " rocid " << iter->first << " -> rocid " << iter->second << std::endl; } }else{ std::cout << "Entries not unique! This can happen if there are" << std::endl; std::cout << "more than one entry with the same value (either" << std::endl; std::cout << "two keys or two vals the same.)" << std::endl; std::cout << "Please fix the file \"" << ROCID_MAP_FILENAME << "\"." << std::endl; exit(-1); } } //--------------------------------- // GetDAQIndex //--------------------------------- const DTranslationTable::csc_t &DTranslationTable::GetDAQIndex(const DChannelInfo &in_channel) const { map::const_iterator tt_itr = TT.begin(); // search through the whole Table to find the key that corresponds to our detector channel // this is not terribly efficient - linear in the size of the table bool found = false; for (; tt_itr != TT.end(); tt_itr++) { const DTranslationTable::DChannelInfo &det_channel = tt_itr->second; if ( det_channel.det_sys == in_channel.det_sys ) { switch ( in_channel.det_sys ) { case DTranslationTable::BCAL: if ( det_channel.bcal == in_channel.bcal ) found = true; break; case DTranslationTable::CDC: if ( det_channel.cdc == in_channel.cdc ) found = true; break; case DTranslationTable::FCAL: if ( det_channel.fcal == in_channel.fcal ) found = true; break; case DTranslationTable::FDC_CATHODES: if ( det_channel.fdc_cathodes == in_channel.fdc_cathodes ) found = true; break; case DTranslationTable::FDC_WIRES: if ( det_channel.fdc_wires == in_channel.fdc_wires ) found = true; break; case DTranslationTable::PS: if ( det_channel.ps == in_channel.ps ) found = true; break; case DTranslationTable::PSC: if ( det_channel.psc == in_channel.psc ) found = true; break; case DTranslationTable::SC: if ( det_channel.sc == in_channel.sc ) found = true; break; case DTranslationTable::TAGH: if ( det_channel.tagh == in_channel.tagh ) found = true; break; case DTranslationTable::TAGM: if ( det_channel.tagm == in_channel.tagm ) found = true; break; case DTranslationTable::TOF: if ( det_channel.tof == in_channel.tof ) found = true; break; default: cerr << "DTranslationTable::GetDAQIndex(): " << "Invalid detector type = " << in_channel.det_sys << std::endl; } } if (found) break; } if (tt_itr == TT.end()) { stringstream ss_err; ss_err << "Could not find DAQ channel in Translaton Table: " << Channel2Str(in_channel) << std::endl; } return tt_itr->first; } //---------------- // Channel2Str //---------------- string DTranslationTable::Channel2Str(const DChannelInfo &in_channel) const { stringstream ss; switch ( in_channel.det_sys ) { case DTranslationTable::BCAL: ss << "module = " << in_channel.bcal.module << " layer = " << in_channel.bcal.layer << " sector = " << in_channel.bcal.sector << " end = " << in_channel.bcal.end; break; case DTranslationTable::CDC: ss << "ring = " << in_channel.cdc.ring << " straw = " << in_channel.cdc.straw; break; case DTranslationTable::FCAL: ss << "row = " << in_channel.fcal.row << " column = " << in_channel.fcal.col; break; case DTranslationTable::FDC_CATHODES: ss << "package = " << in_channel.fdc_cathodes.package << " chamber = " << in_channel.fdc_cathodes.chamber << " view = " << in_channel.fdc_cathodes.view << " strip = " << in_channel.fdc_cathodes.strip << " strip type = " << in_channel.fdc_cathodes.strip_type; break; case DTranslationTable::FDC_WIRES: ss << "package = " << in_channel.fdc_wires.package << " chamber = " << in_channel.fdc_wires.chamber << " wire = " << in_channel.fdc_wires.wire; break; case DTranslationTable::PS: ss << "side = " << in_channel.ps.side << " id = " << in_channel.ps.id; break; case DTranslationTable::PSC: ss << "id = " << in_channel.psc.id; break; case DTranslationTable::SC: ss << "sector = " << in_channel.sc.sector; break; case DTranslationTable::TAGH: ss << "id = " << in_channel.tagh.id; break; case DTranslationTable::TAGM: ss << "row = " << in_channel.tagm.row << " column = " << in_channel.tagm.col; break; case DTranslationTable::TOF: ss << "plane = " << in_channel.tof.plane << " bar = " << in_channel.tof.bar << " end = " << in_channel.tof.end; break; default: ss << "Unknown detector type" << std::endl; } return ss.str(); } //------------ // GetDetectorIndex //------------ const DTranslationTable::DChannelInfo &DTranslationTable::GetDetectorIndex(const csc_t &in_daq_index) const { map ::const_iterator detector_index_itr = TT.find(in_daq_index); if (detector_index_itr == TT.end()) { cout << "Could not find detector channel in Translation Table: "; cout << " rocid = " << in_daq_index.rocid; cout << " slot = " << in_daq_index.slot; cout << " channel = " << in_daq_index.channel << endl; } return detector_index_itr->second; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // The following routines access the translation table //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- static DTranslationTable::Detector_t DetectorStr2DetID(string &type); static void StartElement(void *userData, const char *xmlname, const char **atts); static void EndElement(void *userData, const char *xmlname); //--------------------------------- // ReadTranslationTable //--------------------------------- void DTranslationTable::ReadTranslationTable() { // It seems expat is not thread safe so we lock a mutex here and // read in the translation table just once // String to hold entire XML translation table string tt_xml; // We won't try getting it from the CCDB, Instead reading from the tt.xml file will be good enough if (tt_xml.size() == 0) { cout << "Will try reading TT from local file: " << XML_FILENAME.Data() << std::endl; // Open file ifstream ifs(XML_FILENAME.Data()); if (! ifs.is_open()) { cerr << " Error: Cannot open file! Translation table unavailable." << std::endl; return; } // read lines into stringstream object stringstream ss; while (ifs.good()) { char line[4096]; ifs.getline(line, 4096); ss << line; } // Close file ifs.close(); // Copy from stringstream to tt tt_xml = ss.str(); } // create parser and specify element handlers XML_Parser xmlParser = XML_ParserCreate(NULL); if (xmlParser == NULL) { cerr << "readTranslationTable...unable to create parser" << std::endl; exit(EXIT_FAILURE); } XML_SetElementHandler(xmlParser,StartElement,EndElement); XML_SetUserData(xmlParser, &TT); // Parse XML string int status=XML_Parse(xmlParser, tt_xml.c_str(), tt_xml.size(), 1); // "1" indicates this is the final piece of XML if (status == 0) { cerr << " ?readTranslationTable...parseXMLFile parse error for " << XML_FILENAME.Data() << std::endl; cerr << XML_ErrorString(XML_GetErrorCode(xmlParser)) << std::endl; } cout << TT.size() << " channels defined in translation table" << std::endl; XML_ParserFree(xmlParser); tt_initialized = true; } //--------------------------------- // DetectorStr2DetID //--------------------------------- DTranslationTable::Detector_t DetectorStr2DetID(string &type) { if ( type == "fdc_cathodes" ) { return DTranslationTable::FDC_CATHODES; } else if ( type == "fdc_wires" ) { return DTranslationTable::FDC_WIRES; } else if ( type == "bcal" ) { return DTranslationTable::BCAL; } else if ( type == "cdc" ) { return DTranslationTable::CDC; } else if ( type == "fcal" ) { return DTranslationTable::FCAL; } else if ( type == "ps" ) { return DTranslationTable::PS; } else if ( type == "psc" ) { return DTranslationTable::PSC; } else if ( type == "st" ) { // The start counter is labelled by "ST" in the translation table // but we stick with the "SC" label in this plugin for consistency // with the rest of the reconstruction software return DTranslationTable::SC; } else if ( type == "tagh" ) { return DTranslationTable::TAGH; } else if ( type == "tagm" ) { return DTranslationTable::TAGM; } else if ( type == "tof" ) { return DTranslationTable::TOF; } else { return DTranslationTable::UNKNOWN_DETECTOR; } } //--------------------------------- // StartElement //--------------------------------- void StartElement(void *userData, const char *xmlname, const char **atts) { static int crate=0, slot=0; static string type,Type; int channel = 0; string Detector; int end=0; int row=0,column=0,module=0,sector=0,layer=0,chan=0; int ring=0,straw=0,plane=0,bar=0,gPlane=0,element=0; int package=0,chamber=0,view=0,strip=0,wire=0; int id=0, strip_type=0; // This complicated line just recasts the userData pointer into // a reference to the "TT" member of the DTranslationTable object // that called us. map &TT = *((map*)userData); // store crate summary info, fill both maps if (strcasecmp(xmlname,"halld_online_translation_table") == 0) { // do nothing } else if (strcasecmp(xmlname,"crate") == 0) { for (int i=0; atts[i]; i+=2) { if (strcasecmp(atts[i],"number") == 0) { crate = atoi(atts[i+1]); break; } } } else if (strcasecmp(xmlname,"slot") == 0) { for (int i=0; atts[i]; i+=2) { if (strcasecmp(atts[i],"number") == 0) { slot = atoi(atts[i+1]); } else if (strcasecmp(atts[i],"type") == 0) { Type = string(atts[i+1]); type = string(atts[i+1]); std::transform(type.begin(), type.end(), type.begin(), (int(*)(int)) tolower); } } // The detID value set here shows up in the header of the Data Block Bank // of the output file. It should be set to one if this crate has JLab // made modules that output in the standard format (see document: // "VME Data Format Standards for JLAB Modules"). These would include // f250ADC, f125ADC, F1TDC, .... Slots containing other types of modules // (e.g. CAEN1290) should have their own unique detID. We use detID of // zero for non-digitizing modules like CPUs nd TIDs even though potentially, // one could read data from these. } else if (strcasecmp(xmlname,"channel") == 0) { for (int i=0; atts[i]; i+=2) { string tag(atts[i+0]); string sval(atts[i+1]); int ival = atoi(atts[i+1]); if (tag == "number") channel = ival; else if (tag == "detector") Detector = sval; else if (tag == "row") row = ival; else if (tag == "column") column = ival; else if (tag == "col") column = ival; else if (tag == "module") module = ival; else if (tag == "sector") sector = ival; else if (tag == "layer") layer = ival; else if (tag == "chan") chan = ival; else if (tag == "ring") ring = ival; else if (tag == "straw") straw = ival; else if (tag == "gPlane") gPlane = ival; else if (tag == "element") element = ival; else if (tag == "plane") plane = ival; else if (tag == "bar") bar = ival; else if (tag == "package") package = ival; else if (tag == "chamber") chamber = ival; else if (tag == "view") { if (sval == "U") view=1; else if (sval == "D") view=3; } else if (tag == "strip") strip = ival; else if (tag == "wire") wire = ival; else if (tag == "id") id = ival; else if (tag == "end") { if (sval == "U") { end = 0; view=1; } else if (sval == "D") { end = 1; view=3; } else if (sval == "N") end = 0; // TOF north else if (sval == "S") end = 1; // TOF south else if (sval == "UP") end = 0; // TOF up else if (sval == "DW") end = 1; // TOF down } else if (tag == "strip_type") { if (sval == "full") strip_type = 1; else if (sval == "A") strip_type = 2; else if (sval == "B") strip_type = 3; } } // ignore certain module types if (type == "disc") return; if (type == "ctp") return; if (type == "sd") return; if (type == "a1535sn") return; // // Data integrity check // if (crate < 0 || crate >= MAXDCRATE) { // jerr << " Crate value of " << crate // << " is not in range 0 <= crate < " << MAXDCRATE << std::endl; // exit(-1); // } // // if (slot < 0 || slot >= MAXDSLOT) { // jerr << " Slot value of " << slot // << " is not in range 0 <= slot < " << MAXDSLOT << std::endl; // exit(-1); // } // // if (channel < 0 || channel >= MAXDCHANNEL) { // jerr << " Crate value of " << channel // << " is not in range 0 <= channel < " << MAXDCHANNEL << std::endl; // exit(-1); // } // fill maps DTranslationTable::csc_t csc = {crate,slot,channel}; string detector = Detector; std::transform(detector.begin(), detector.end(), detector.begin(), (int(*)(int)) tolower); //string s="unknown::"; // Common indexes DTranslationTable::DChannelInfo &ci = TT[csc]; ci.CSC = csc; ci.det_sys = DetectorStr2DetID(detector); // detector-specific indexes switch (ci.det_sys) { case DTranslationTable::BCAL: ci.bcal.module = module; ci.bcal.layer = layer; ci.bcal.sector = sector; ci.bcal.end = end; break; case DTranslationTable::CDC: ci.cdc.ring = ring; ci.cdc.straw = straw; break; case DTranslationTable::FCAL: ci.fcal.row = row; ci.fcal.col = column; break; case DTranslationTable::FDC_CATHODES: ci.fdc_cathodes.package = package; ci.fdc_cathodes.chamber = chamber; ci.fdc_cathodes.view = view; ci.fdc_cathodes.strip = strip; ci.fdc_cathodes.strip_type = strip_type; break; case DTranslationTable::FDC_WIRES: ci.fdc_wires.package = package; ci.fdc_wires.chamber = chamber; ci.fdc_wires.wire = wire; break; case DTranslationTable::SC: ci.sc.sector = sector; break; case DTranslationTable::TAGH: ci.tagh.id = id; break; case DTranslationTable::TAGM: ci.tagm.col = column; ci.tagm.row = row; break; case DTranslationTable::TOF: ci.tof.plane = plane; ci.tof.bar = bar; ci.tof.end = end; break; case DTranslationTable::PS: case DTranslationTable::PSC: case DTranslationTable::UNKNOWN_DETECTOR: break; } } else { cerr << std::endl << std::endl << "?startElement...unknown xml tag " << xmlname << std::endl << std::endl; } } //-------------------------------------------------------------------------- void EndElement(void *userData, const char *xmlname) { // nothing to do yet... } //--------------------------------------------------------------------------