//_HADES_CLASS_DESCRIPTION ///////////////////////////////////////////////////////////// // // HMdcTrbCUnpacker // // Class for unpacking TRB3 data and filling // the MDC Raw category // Adjusted by JAM (September 2024) // // Basic subevent decoding and eventual TDC corrections are // performed by decode function in the base class // see: /base/datasource/htrb3unpacker.h // ///////////////////////////////////////////////////////////// #include "hmdcdataword.h" #include "hevent.h" #include "hldsubevt.h" #include "heventheader.h" #include "hruntimedb.h" #include "hspectrometer.h" #include "hcategory.h" #include "hmessagemgr.h" #include "hmdcdetector.h" #include "hmdcrawstruct.h" #include "hmdclookupgeom.h" #include "hmdcraw.h" #include "hparset.h" #include "hmdcdef.h" #include "htrbnetunpacker.h" #include "hmdcoepaddrcorrpar.h" #include "hmdcoepstatusdata.h" #include "hldsource.h" #include "hspectrometer.h" #include "htime.h" #include "hmdctrbclookup.h" #include "hmdctrbcunpacker.h" #include using namespace std; ClassImp(HMdcTrbCUnpacker) // this is default time unit (in nanoseconds) for values in the HMdcRaw elements. (TODO: clarify relation to MdcCalParRaw) #define MDC_RAW_TIME_UNIT 0.5 // switch on filtering of tdc messages with first time window as defined below //#define MDC_USE_TIME_WINDOW 1 // this will select from each channel only the hit with largest ToT for the calibrater. No multihit evaluation, like in the old FEE procedure //#define MDC_USE_BEST_HIT_ONLY 1 // first time window to filter out some unusable hits. units are nanoseconds relative to trigger (reference time from data header) #define MDC_TIME_MIN -2000.0 #define MDC_TIME_MAX 1200.0 //from TDC_data_format.docx: All hits can be assumed to be in a window between -2000 and +1200 ns relative to the reference time // TODO: optionally put this into some parameter container. Bool_t HMdcTrbCUnpacker::fHasPrintedTDC = kFALSE; HMdcTrbCUnpacker::HMdcTrbCUnpacker(vector& ids) : HTrbCtdcUnpacker(ids), fLookup(0), fLookupOld(0), fTimeRef(kTRUE) , fNoComment(kTRUE), fTimeUnit(1){ // constructor pRawCat = NULL; fTimeShift = 0.; fTimeUnit=1e9; // CLOCKTDC time units s->ns fCompatitbilityShift = 0; } Bool_t HMdcTrbCUnpacker::init(void) { // creates the raw category and gets the pointer to the TRB3 lookup table HMdcDetector* det = (HMdcDetector*) gHades->getSetup()->getDetector("Mdc"); if (!det) { Error("init", "No MDC Detector found."); return kFALSE; } pRawCat = (HCategory*)(((HEvent*)(gHades->getCurrentEvent()))->getCategory(catMdcRaw)); if(!pRawCat) { pRawCat = det->buildCategory(catMdcRaw); if (!pRawCat) return kFALSE; else gHades->getCurrentEvent()->addCategory(catMdcRaw,pRawCat,"Mdc"); } fLoc.set(4, 0, 0, 0); // get Pointer to runtime database HRuntimeDb *rtdb = gHades->getRuntimeDb(); if (!rtdb) { Error("init", "FATAL: No runtime database found. never come here!!"); return kFALSE; } fLookup = (HMdcTrbCLookup*) (rtdb->getContainer("MdcTrbCLookup")); if (!fLookup) { Error("init", "No Pointer to parameter container MdcTrbCLookup."); return kFALSE; } fLookupOld = (HMdcLookupGeom*) (rtdb->getContainer("MdcLookupGeom")); if (!fLookupOld) { Error("init", "No Pointer to parameter container MdcLookupGeom."); return kFALSE; } if (NULL == trbNetUnpacker) { if (gHades->getDataSource()) { HDataSource* source = gHades->getDataSource(); if (source->InheritsFrom("HldSource")) { trbNetUnpacker = ((HldSource *) gHades->getDataSource())->getTrbNetUnpacker(); } else { Warning("init", "DataSource not inherited from HldSource! trbNetUnpacker == 0 "); } } else { Warning("init", "Could not retrieve DataSource! trbNetUnpacker == 0 "); } } if (!trbNetUnpacker->init()) { Error("init()", "Failed to initialize HTrbNetUnpacker!"); return kFALSE; } // ? JAM other parameter containers here: return kTRUE; return kTRUE; } Bool_t HMdcTrbCUnpacker::reinit(void) { // Called in the beginning of each run, used here to initialize TDC unpacker // if TDCs processors are not yet created, use parameter to instantiate them // if auto register TDC feature is used in setup of unpackers (by setting // setMinAddress()+setMaxAddress() manually) if (numTDC() == 0) { // configure the tdcs only the first time we come here (do not if autoregister is used): if (fMinAddress == 0 && fMaxAddress == 0) { // here evaluate which subevents are configured in lookup table: Int_t numTDC = fLookup->getSize(); Int_t offset = fLookup->getArrayOffset(); for (Int_t slot = 0; slot < numTDC; ++slot) { Int_t trbnetaddress = offset + slot; HMdcTrbCLookupBoard *tdc = fLookup->getBoard(trbnetaddress); if (tdc) { Int_t nChan = tdc->getSize(); if (trbnetaddress) { addTDC(trbnetaddress, nChan); //Int_t tindex = addTDC(trbnetaddress,nChan); //Info("reinit", "Added TDC 0x%04x with %d channels from HMdcTrbCLookup to map index %d", // trbnetaddress, nChan,tindex); } } } // set the expected range for the automatic adding of TDC structures: setMinAddress(fLookup->getArrayOffset()); setMaxAddress(fLookup->getArrayOffset() + fLookup->getSize()); fUseTDCFromLookup = kTRUE; // do not use auto register if set in fHasPrintedTDC = kTRUE; } else { Info("reinit", "TDCs will be added in auto register mode between min address 0x%04x and max address 0x%04x!", fMinAddress, fMaxAddress); } } // we do not call reinit of superclass, since we do not use tdc calibration parameters in hydra anymore! return kTRUE; } Int_t HMdcTrbCUnpacker::execute(void) { if (gHades->isCalibration()) { //calibration event return 1; } if (gHades->getCurrentEvent()->getHeader()->getId() == 0xe) { //scaler event return 1; } // if there is no data, do not try to analyze it // pSubEvt - make sure that there is something for decoding if (!pSubEvt) return 1; Int_t nEvt = gHades->getCurrentEvent()->getHeader()->getEventSeqNumber(); // decodes the subevent and fill arrays, see: htrbcunpacker.h if (!decode()) { Error("decode", "subsubevent decoding failed!!! Evt Nr : %i SubEvtId: %x", nEvt, getSubEvtId()); return -1; } // correct for reference time here! // we don't check for proper time reference correction // to avoid event skipping // this must be done better in future but now is a good workaround if (fTimeRef) { correctRefTime(); // also includes TDC overflow correction and long signal suppression } for (UInt_t ntdc = 0; ntdc < numActiveTDC(); ntdc++) { HTrbCtdcUnpacker::TDC* tdc = getActiveTDC(ntdc); if(tdc==nullptr) { Warning("getActiveTDC", "Evt Nr : %i SubEvtId: %x - no active TDC found for index %d", nEvt, getSubEvtId(),ntdc); continue; } // check the lookup table HMdcTrbCLookupBoard *board = fLookup->getBoard(tdc->getTrbAddr()); if (!board) { if (debugFlag > 0) Warning("execute", "Evt Nr : %i SubEvId: %x (%i) unpacked but TDC Board 0x%x not in lookup table", nEvt, getSubEvtId(), getSubEvtId(), tdc->getTrbAddr()); continue; } // fill the raw category for MDC detector for (UInt_t i = 0; i < tdc->numChannels(); i++) { HTrbCtdcUnpacker::ChannelRec& theRecord = tdc->getCh(i); if(theRecord.mult==0) { continue; // no hits in this channel, try the next } HMdcTrbCLookupChan *chan = board->getChannel(i); if (chan == 0) { Warning("execute", "Missing channel %u in lookup table", i); continue; } // here translate new channel address to old localizer for existing raw cat if (!translateAddress(chan)) { Error("translateAddress", "subsubevent address translation for old raw catg failed!!! Evt Nr : %i SubEvtId: %x", nEvt, getSubEvtId()); return -1; } // if channel not connected in lookup-table, ignore it if (fLoc[0] < 0) { // empty slot default is -1 continue; } #ifdef MDC_USE_BEST_HIT_ONLY Double_t tm0_select = 0, tm1_select = 0, tot_select=0; #endif // loop over all hits in this channel record: for (UInt_t hix = 0; hix < theRecord.mult; ++hix) { Double_t tm0 = theRecord.rising_tm[hix] * fTimeUnit; Double_t tm1 = theRecord.falling_tm[hix] * fTimeUnit; // JAM note: times are in nanoseconds from here if (debugFlag > 0){ Warning("execute", "JJJJ current hit channel %d - leading: tm0:%e trailing: tm1:%e, apply time shift:%e", i, tm0, tm1, fTimeShift); } tm0 +=fTimeShift; tm1 +=fTimeShift; #ifdef MDC_USE_TIME_WINDOW // later we may get this from parameter container or other setup file. For the moment fix it Double_t tmin = MDC_TIME_MIN; Double_t tmax = MDC_TIME_MAX; if ((tm0 < tmin) || (tm0 > tmax) || (tm1 < tmin) || (tm1 > tmax)) { if (debugFlag > 0) Warning("execute", "JJJJ Rejecting leading hit outside tmin:%e or tmax:%e", tmin, tmax); continue; // any edge outside the time window, try next hit } #endif //JAM 5-sep-2024: since old calibrater will use first hit of each raw channel only, we may select already here the highest hit of the event and only put this further #ifdef MDC_USE_BEST_HIT_ONLY // use only the hits with highest tot Double_t tot=tm1-tm0; if(tot>tot_select){ tm0_select=tm0; tm1_select=tm1; tot_select=tot; } #else // multihit mode: all hits found in data stream are passed to calibrater // TODO: maybe we need time sorting here later? if (addRawHit(tm0, tm1, chan) != 0) break; // we will skip subsequent hits if this channel is not mapped to detector cell #endif } // for hit index #ifdef MDC_USE_BEST_HIT_ONLY if(tot_select>0) // only add hit if we have found anything good addRawHit(tm0_select, tm1_select, chan); #endif } // loop over TDC channels } // loop over TDC return 1; } Bool_t HMdcTrbCUnpacker::translateAddress(HMdcTrbCLookupChan *chan) { // TODO - JAM 29.08.24: fake for the old raw category that our signal comes from old lookup indices (MBO, TDCs) // otherwise would need to redefine different raw categories for old and new FEE, thus changing also calibrater // this may be done in a next iteration Int_t sector, module, newboard, layer, wire; Char_t side; chan->getAddress(sector, module, newboard, layer, wire, side); HMdcLookupGMod& theModule=(*fLookupOld)[sector][module]; // now find old mbo and tdc that had our mapping for layer, wire and side: Int_t maxmbo=theModule.getSize(); if (getDebugFlag()>0) { fprintf(stderr, "HMdcTrbCUnpacker::translateAddress got indices: sec:%d mod:%d newboard:%d layer:%d wire:%d side:%c \n", sector, module, newboard, layer, wire, side); } Int_t mbo=0, tdc=0; Char_t oldside='X'; Bool_t found=kFALSE; for (mbo=0; ((mbo1) { fprintf(stderr, "HMdcTrbCUnpacker::translateAddress for mbo %d HMdcLookupMoth of size %d\n",mbo, maxtdc); } for (tdc=0; tdc1){ fprintf(stderr, "HMdcTrbCUnpacker::translateAddress for tdc %d searching for layer %d and wire %d ...\n",tdc, layer, wire); } if((layer==theChannelUnit.getNLayer()) && (wire==theChannelUnit.getNCell())) { found=kTRUE; // side information? -do not check, redundant. But update the new table with old side links here: oldside=theChannelUnit.getReadoutSide(); if (getDebugFlag()>1){ fprintf(stderr, "HMdcTrbCUnpacker::translateAddress FOUND layer %d and wire %d ...\n",layer, wire); } if(side!=oldside) { if (getDebugFlag()>1) { fprintf(stderr, "JJJ setting side information from old lookup tables for s:%d m:%d l:%d wire:%d to %c \n",sector, module,layer,wire, oldside); chan->setSide(oldside); } } break; // will only break innermost loop, so need to check the found flag in outer loops as well ;-) } }// tdc }//mbo if(found) { mbo--; // loop index is already one ahead before we come out of it! JAM 11-09-2024 fLoc[0]=sector; fLoc[1]=module; fLoc[2]=mbo; fLoc[3]=tdc; if (getDebugFlag()>0) fprintf(stderr, "JJJ FOUND locator in old lookup tables for sec:%d mod:%d mbo:%d, tdc:%d with lay:%d wire:%d \n", sector, module,mbo,tdc, layer,wire); return kTRUE; } printf("JJJ Could not find information in old lookup tables for sec:%d mod:%d lay:%d wire:%d \n",sector, module,layer,wire); return kFALSE; } // Taken from hmdcunpacker, localization of data in old raw category: JAM HMdcRaw* HMdcTrbCUnpacker::getFreeOrExistingSlot() { // get a free or existing slot from the HMdcRaw category // at the location of HLocation loc // returns the pointer to the (new) HMdcRaw object // NULL if it couldn't be done // set location indexes // JAM done by translatAdress now // fLoc[0] = sector; // fLoc[1] = module; // fLoc[2] = mbo; // fLoc[3] = tdc; Int_t sector=fLoc[0]; Int_t module=fLoc[1]; Int_t mbo=fLoc[2]; Int_t tdc=fLoc[3]; HMdcRaw *pMdcRaw = (HMdcRaw*) pRawCat->getObject(fLoc); if (!pMdcRaw) { pMdcRaw = (HMdcRaw*) pRawCat->getSlot(fLoc); if (pMdcRaw) { pMdcRaw = new (pMdcRaw) HMdcRaw(); pMdcRaw->setTrbC(); //setAddress to sector,module,mbo and tdc pMdcRaw->setAddress(sector, module, mbo, tdc); } else { if (!fNoComment) { gHades->getMsg()->error(10, HMessageMgr::DET_MDC, GetName(), "Event: %i - SubEvtId 0x%x - can't get slot for s: %i m: %i mb: %i tdc: %i", gHades->getCurrentEvent()->getHeader()->getEventSeqNumber(), getSubEvtId(), sector, module, mbo, tdc); gHades->getMsg()->error(10, HMessageMgr::DET_MDC, GetName(), " ...... skipping unpacking of the rest of the subevent!!!"); } if (debugFlag>1) { pSubEvt->dumpIt(); } } } return pMdcRaw; } Bool_t HMdcTrbCUnpacker::addRawHit(Double_t t_leading, Double_t t_trailing, HMdcTrbCLookupChan *chan) { HMdcRaw* raw= getFreeOrExistingSlot(); if(raw==nullptr) return kFALSE; // TODO: may select already here to take only the highest hit (largest ToT pair) only JAM? // for the moment, only the first ToT in channel is used for calibrater step, like for old FEE // we may check if hit is already existing in raw and replace it by the new one if ToT is larger // use raw->setTimeNew as done in old correctBitFlip() // alternatively, such selection is prepared in base class unpacker if (getDebugFlag()>1){ fprintf(stderr, "HMdcTrbCUnpacker::addRawHit(leading=%e ns, trailing=%e ns for sec:%d mod:%d mbo:%d tdc:%d)\n", t_leading, t_trailing, fLoc[0], fLoc[1],fLoc[2],fLoc[3]); } // JAM - here we also need transformation of new time values to old raw category units (0.5 ns lsb ??) Int_t value_leading = fCompatitbilityShift - (t_leading/MDC_RAW_TIME_UNIT); Int_t value_trailing = fCompatitbilityShift - (t_trailing/MDC_RAW_TIME_UNIT); if (!raw->setTime(value_leading, 0, fNoComment)) { if (!fNoComment) { gHades->getMsg()->error(10, HMessageMgr::DET_MDC, GetName(), "Event: %i - SubEvtId 0x%x - error filling leading edge time for sector %d, module %d mbo %d TDC %d-->", gHades->getCurrentEvent()->getHeader()->getEventSeqNumber(), getSubEvtId(), fLoc[0], fLoc[1],fLoc[2], fLoc[3]); gHades->getMsg()->info(1, HMessageMgr::DET_MDC, GetName(), "time1 %d, time2 %d -> time %d", raw->getTime(1), raw->getTime(2), value_leading); } } if (!raw->setTime(value_trailing, 0, fNoComment)) { if (!fNoComment) { gHades->getMsg()->error(10, HMessageMgr::DET_MDC, GetName(), "Event: %i - SubEvtId 0x%x - error filling trailing edge time for sector %d, module %d mbo %d TDC %d-->", gHades->getCurrentEvent()->getHeader()->getEventSeqNumber(), getSubEvtId(), fLoc[0], fLoc[1],fLoc[2], fLoc[3]); gHades->getMsg()->info(1, HMessageMgr::DET_MDC, GetName(), "time1 %d, time2 %d -> time %d", raw->getTime(1), raw->getTime(2), value_trailing); } } if (debugFlag > 0) Warning("addRawHit", "ADDING hit for sec:%d module:%d mbo %d tdcch:%d tm0:%f ns tm1:%f ns", fLoc[0], fLoc[1], fLoc[2], fLoc[3], t_leading, t_trailing); return kTRUE; }