00001 #include "ROsFeeReadoutTool.h"
00002 #include "ROsFadcReadoutTool.h"
00003
00004 #include "Conventions/Detectors.h"
00005 #include "Conventions/Electronics.h"
00006 #include "Conventions/Trigger.h"
00007 #include "Conventions/Site.h"
00008
00009 #include "Event/SimReadoutHeader.h"
00010 #include "Event/ReadoutPmtCrate.h"
00011 #include "Event/ReadoutTriggerDataPkg.h"
00012
00013 #include "Event/ElecCrateHeader.h"
00014 #include "Event/ElecFeeCrate.h"
00015 #include "Event/ElecFeeChannel.h"
00016
00017 #include "Event/SimTrigCommand.h"
00018 #include "Event/SimTrigCommandHeader.h"
00019 #include "Event/SimTrigCommandCollection.h"
00020
00021 #include "DataSvc/ICalibDataSvc.h"
00022
00023 #include <set>
00024 #include <vector>
00025
00026 ROsFeeReadoutTool::ROsFeeReadoutTool(const std::string& type,
00027 const std::string& name,
00028 const IInterface* parent)
00029 : GaudiTool(type,name,parent)
00030 {
00031 declareInterface< IROsReadoutTool >(this) ;
00032
00033 m_detectorsToProcess.push_back("DayaBayAD1");
00034 m_detectorsToProcess.push_back("DayaBayAD2");
00035 m_detectorsToProcess.push_back("DayaBayIWS");
00036 m_detectorsToProcess.push_back("DayaBayOWS");
00037 m_detectorsToProcess.push_back("LingAoAD1");
00038 m_detectorsToProcess.push_back("LingAoAD2");
00039 m_detectorsToProcess.push_back("LingAoIWS");
00040 m_detectorsToProcess.push_back("LingAoOWS");
00041 m_detectorsToProcess.push_back("FarAD1");
00042 m_detectorsToProcess.push_back("FarAD2");
00043 m_detectorsToProcess.push_back("FarAD3");
00044 m_detectorsToProcess.push_back("FarAD4");
00045 m_detectorsToProcess.push_back("FarIWS");
00046 m_detectorsToProcess.push_back("FarOWS");
00047
00048 declareProperty("SimDataSvcName",m_simDataSvcName="StaticSimDataSvc",
00049 "Name of service to provide FEE channel properties for simulation");
00050 declareProperty("DetectorsToProcess",m_detectorsToProcess,
00051 "List of detectors to process with this tool");
00052 declareProperty("EnablePeakReadout",m_enablePeakReadout=true,
00053 "Switch on/off peak readout mode");
00054 declareProperty("EnableWaveformReadout",m_enableWaveformReadout=false,
00055 "Switch on/off waveform readout mode");
00056 declareProperty("EnableFadcReadout", m_enableFadcReadout=false,
00057 "Switch on/off FADC readout mode");
00058 declareProperty("WaveformTool", m_waveformToolName="ROsFeeAdcMultiTool",
00059 "Name of waveform readout tool");
00060 declareProperty("TdcTool", m_tdcToolName="ROsFeeTdcTool",
00061 "Name of tdc readout tool");
00062 declareProperty("FadcTool", m_fadcToolName="ROsFadcReadoutTool",
00063 "Name of fadc readout tool");
00064
00065
00066 declareProperty("ReadoutLength",m_readoutLength=768,
00067 "Length of readout window in 640Mhz clock cycles");
00068
00069 declareProperty("TriggerLatency",m_triggerLatency=980,
00070 "Trigger latency in 640Mhz clock cycles");
00071
00072 declareProperty("ReadoutOffset",m_readoutOffset=128,
00073 "Offset of readout window from trigger tdc in 640Mhz clock cycles");
00074
00075
00076 declareProperty("PeakFindingLength",m_peakFindingLength=12,
00077 "Length of peak finding window in 40Mhz clock cycles");
00078 declareProperty("PeakFindingOffset",m_peakFindingOffset=0,
00079 "Offset of peak finding window from corresponding hit in 40Mhz clock cycles");
00080 declareProperty("PeakFindingOverlap",m_peakFindingOverlap=true,
00081 "Allow overlapping peakfinding for consecutive hits");
00082 declareProperty("PreAdcOffset",m_preAdcOffset=3,
00083 "Offset of first PreADC cycle from start of ADC peak finding window in 40Mhz clock cycles");
00084 declareProperty("NhitCycles", m_nhitCycles = DayaBay::NhitCycles, "Nhit cycles");
00085 declareProperty("EsumCycles", m_eSumCycles = DayaBay::EsumCycles, "Esum cycles");
00086 declareProperty("FADCOffset", m_fadcOffset = 100, "FADC offset");
00087 declareProperty("FADCLength", m_fadcLength = 400, "FADC readout window legth");
00088 declareProperty("MaxFineAdc",m_maxFineAdc=3500,
00089 "Maximum fine-range ADC value before using the coarse range");
00090 }
00091
00092 ROsFeeReadoutTool::~ROsFeeReadoutTool(){}
00093
00094 StatusCode ROsFeeReadoutTool::initialize()
00095 {
00096 std::vector<std::string>::iterator it;
00097 for(it=m_detectorsToProcess.begin();it!=m_detectorsToProcess.end();++it){
00098 short int detId = DayaBay::Detector::siteDetPackedFromString(*it);
00099 DayaBay::Detector det(detId);
00100 m_detectors.insert(det);
00101 }
00102
00103 try {
00104 m_waveformTool = tool<IROsFeeWaveformTool>(m_waveformToolName) ;
00105 debug() << "Using \"" << m_waveformToolName
00106 << "\" for waveform readout " << endreq;
00107 }
00108 catch(const GaudiException& exg) {
00109 fatal() << "Failed to get Readout Tool: \""
00110 << m_waveformToolName << "\"" << endreq;
00111 return StatusCode::FAILURE;
00112 }
00113 try {
00114 m_tdcTool = tool<IROsFeeTdcTool>(m_tdcToolName) ;
00115 debug() << "Using \"" << m_tdcToolName
00116 << "\" for TDC readout " << endreq;
00117 }
00118 catch(const GaudiException& exg) {
00119 fatal() << "Failed to get Readout Tool: \"" << m_tdcToolName << "\"" << endreq;
00120 return StatusCode::FAILURE;
00121 }
00122 try {
00123 m_fadcTool = tool<IROsFadcReadoutTool>(m_fadcToolName) ;
00124 debug() << "Using \"" << m_fadcToolName
00125 << "\" for fadc readout " << endreq;
00126 }
00127 catch(const GaudiException& exg) {
00128 fatal() << "Failed to get Readout Tool: \""
00129 << m_waveformToolName << "\"" << endreq;
00130 return StatusCode::FAILURE;
00131 }
00132
00133
00134 m_simDataSvc = svc<ISimDataSvc>(m_simDataSvcName,true);
00135
00136 if( !m_enablePeakReadout && !m_enableWaveformReadout ) {
00137 error() << "All readout modes switched off" << endreq;
00138 return StatusCode::FAILURE;
00139 }
00140 if( m_enablePeakReadout )
00141 info() << "Peak readout mode enabled" << endreq;
00142 if( m_enableWaveformReadout )
00143 info() << "Waveform readout mode enabled" << endreq;
00144
00145 return StatusCode::SUCCESS;
00146 }
00147
00148 StatusCode ROsFeeReadoutTool::finalize()
00149 {
00150 return StatusCode::SUCCESS;
00151 }
00152
00153 StatusCode ROsFeeReadoutTool::makeReadouts(DayaBay::SimReadoutHeader* roHeader,
00154 std::vector<DayaBay::ReadoutTriggerDataPkg*>& trigDataPkg,
00155 const DayaBay::ElecHeader& elecHeader)
00156 {
00157 debug() << "running makeReadouts() in FeeReadoutTool" << endreq;
00158
00159 DayaBay::SimReadoutHeader::SimReadoutContainer& outputReadouts
00160 = roHeader->readouts();
00161
00162 Context context = roHeader->context();
00163
00164 const DayaBay::ElecCrateHeader *ech = elecHeader.crateHeader();
00165 const DayaBay::ElecCrateHeader::CrateMap crMap = ech->crates();
00166 DayaBay::ElecCrateHeader::CrateMap::const_iterator crIt;
00167
00168 std::vector<DayaBay::ReadoutTriggerDataPkg*>::iterator pkgIt;
00169
00170
00171 for(pkgIt = trigDataPkg.begin(); pkgIt != trigDataPkg.end(); ++pkgIt)
00172 {
00173 DayaBay::Detector det((*pkgIt)->detector());
00174 if(m_detectors.find(det) != m_detectors.end()){
00175 crIt = crMap.find(det);
00176 const DayaBay::ElecFeeCrate *crate;
00177 if(crIt == crMap.end()){
00178 if((*pkgIt)->frames().size()==0){
00179 fatal() << "Trying to process a trigger for " << det.detName()
00180 << " But Package Has No Frames" << endreq;
00181 return StatusCode::FAILURE;
00182 }else{
00183 fatal() << "Trying to process a trigger for " << det.detName()
00184 << " But no crate exists -- skipping" << endreq;
00185 return StatusCode::FAILURE;
00186 }
00187 crate = 0;
00188 }else{
00189 crate = dynamic_cast<const DayaBay::ElecFeeCrate*>(crIt->second);
00190 debug() << "Processing a trigger for " << det.detName()
00191 << " found crate at " << crate << endreq;
00192 }
00193 if(crate != 0){
00194 debug()<<"Reading out 1 trigger with: "
00195 <<((*pkgIt)->frames().size())-1
00196 <<" masked triggers."<<endreq;
00197
00198 const DayaBay::ReadoutTriggerDataFrame *tdf = (*pkgIt)->frames().at(0);
00199
00200 DayaBay::ReadoutPmtCrate *crateReadout = readoutCrate(tdf,crate,context);
00201
00202 outputReadouts.push_back(new DayaBay::SimReadout(crateReadout,
00203 roHeader));
00204
00206 (*pkgIt)->setReadout(crateReadout);
00207 crateReadout->setTriggerDataPkg(*pkgIt);
00208
00209 verbose() << "set readout:\n" << (**pkgIt) << endreq;
00210
00211 if( m_enableFadcReadout )
00212 {
00213 debug() << " Trying FADC Readout " << endreq;
00214
00215 unsigned int triggerCycle = tdf->cycle();
00216
00217 int start = int((triggerCycle*m_eSumCycles)/m_nhitCycles)+m_fadcOffset;
00218
00219 int stop = start+m_fadcLength;
00220
00221 m_fadcTool->readoutFADC(crate,crateReadout,start,stop);
00222 debug() << "readout map size: " << (crateReadout->fadcReadout()).size() << endreq;
00223
00224 debug() << " Done reading out FADC" << endreq;
00225 }
00226 }
00227 }else{
00228 verbose() << "Found Trigger For " << det.detName()
00229 << "but this tool is not supposed "
00230 << "to process that detector type "
00231 << "check properties to configure."
00232 << endreq;
00233 }
00234 }
00235 return StatusCode::SUCCESS;
00236 }
00237
00238 DayaBay::ReadoutPmtCrate* ROsFeeReadoutTool::readoutCrate(const DayaBay::ReadoutTriggerDataFrame *tdf,
00239 const DayaBay::ElecFeeCrate *cr, Context context)
00240 {
00241 TimeStamp triggerTime(cr->header()->header()->earliest());
00242 triggerTime.Add( tdf->cycle() / double(DayaBay::NhitFrequencyHz) );
00243 DayaBay::ReadoutPmtCrate *out_readout
00244 = new DayaBay::ReadoutPmtCrate(cr->detector(),0, triggerTime, tdf->triggerType());
00245
00246 DayaBay::ReadoutPmtCrate::PmtChannelReadouts ro_chMap;
00247
00248 const DayaBay::ElecFeeCrate::ChannelData& chmap = cr->channelData();
00249 DayaBay::ElecFeeCrate::ChannelData::const_iterator chIt;
00250
00251 for(chIt = chmap.begin(); chIt != chmap.end() ; ++chIt){
00252 DayaBay::ReadoutPmtChannel *ro_ch = readoutChannel(tdf,&(chIt->second),
00253 chIt->first,context);
00254 if (ro_ch == 0) continue;
00255 ro_ch->setChannelId(chIt->first);
00256 ro_ch->setReadout(out_readout);
00257 ro_chMap[chIt->first] = *ro_ch;
00258 ro_ch->setReadout(0);
00259 delete ro_ch;
00260 }
00261
00262 out_readout->setChannelReadout(ro_chMap);
00263 return out_readout;
00264 }
00265
00266 DayaBay::ReadoutPmtChannel* ROsFeeReadoutTool::readoutChannel(
00267 const DayaBay::ReadoutTriggerDataFrame *tdf,
00268 const DayaBay::ElecFeeChannel *feeChannel,
00269 DayaBay::FeeChannelId channelId,
00270 Context context)
00271 {
00272
00273 int task = 0;
00274 ServiceMode svcMode(context, task);
00275 const DayaBay::FeeSimData* feeSimData =
00276 m_simDataSvc->feeSimData(channelId, svcMode);
00277 if(!feeSimData){
00278 error() << "No Simulation input properties for FEE channel: "
00279 << channelId << endreq;
00280 }
00281
00282
00283 DayaBay::ReadoutPmtChannel *ro_ch = new DayaBay::ReadoutPmtChannel();
00284 int nHitTrigCycle = tdf->cycle();
00285 int tdcTrigCyc = (int)(double(nHitTrigCycle) *
00286 double(DayaBay::TdcCycles)/double(DayaBay::NhitCycles) + 0.5);
00287 verbose() << "Conv TDC Clock Cycle: " << tdcTrigCyc << endreq;
00288 std::vector<int> hit = feeChannel->hit();
00289 int tdcSize = hit.size() *(1+int(DayaBay::TdcCycles/DayaBay::NhitCycles));
00290
00291
00292 int tdcFirst;
00293 if( (int)tdcTrigCyc - m_readoutOffset < 0){
00294 verbose() << "Invalid Readout TDC Start Cycle "
00295 << (int)tdcTrigCyc - m_readoutOffset
00296 << " Using 0" << endreq;
00297 tdcFirst = 0;
00298 } else tdcFirst = tdcTrigCyc - m_readoutOffset;
00299 verbose() << "TDC First in ns: " << tdcFirst *1.5625 << endreq;
00300
00301 int tdcLast;
00302 if( tdcTrigCyc - m_readoutOffset + m_readoutLength > tdcSize){
00303 verbose() << "Invalid Readout TDC Last Cycle "
00304 << tdcTrigCyc - m_readoutOffset + m_readoutLength
00305 << " Using " << tdcSize << endreq;
00306 tdcLast = tdcSize;
00307 } else tdcLast = tdcTrigCyc - m_readoutOffset + m_readoutLength;
00308 verbose() << "TDC Last in ns: " << tdcLast *1.5625 << endreq;
00309 verbose() << "reading out tdc window [ "
00310 << tdcFirst << "," << tdcLast << " )" << endreq;
00311
00312
00313 int tdcStopCycle = tdcTrigCyc + m_triggerLatency;
00314 const DayaBay::DigitalSignal* adc;
00315 int adcFirst;
00316 int adcLast;
00317 int adcPedFirst;
00318
00319
00320 if ( m_enablePeakReadout ){
00321
00322 const std::vector<int>& tdcOrg = feeChannel->tdc();
00323 std::vector<int> tdc_vec;
00324 StatusCode sc = m_tdcTool->readoutTdc(tdcOrg,tdcFirst,tdcLast,tdc_vec);
00325 if( !sc.isSuccess() || tdc_vec.empty() ) {
00326 delete ro_ch;
00327 return 0;
00328 }
00329
00330
00331 int nTdc = tdc_vec.size();
00332 std::vector<int> tdc_out(nTdc);
00333 std::vector<int> tdcHitCount_out(nTdc);
00334 std::vector<int> adc_out(nTdc);
00335 std::vector<int> adcCycle_out(nTdc);
00336 std::vector<int> adcRange_out(nTdc);
00337 std::vector<int> preAdc_out(nTdc);
00338
00339 DayaBay::FeeGain::FeeGain_t gain;
00340 int currentAdc;
00341
00342 int currentTdc = -1000;
00343
00344 for ( int i = 0; i < nTdc; i++ ){
00345
00346 if ( tdc_vec[i] - currentTdc > m_peakFindingLength * 16 || m_peakFindingOverlap == true){
00347
00348
00349 adc = &(feeChannel->adcHigh());
00350 gain = DayaBay::FeeGain::kHigh;
00351 verbose() << "Maximum available ADC window [ " << 0 << "," << adc->size()
00352 << " )" << endreq;
00353
00354
00355 currentTdc = tdc_vec[i];
00356 currentAdc = (int) (double(currentTdc) * double(DayaBay::AdcCycles)/double(DayaBay::TdcCycles) );
00357
00358 if( currentAdc - m_peakFindingOffset < 0){
00359 verbose() << "Invalid ADC Peak Finding Start Cycle "
00360 << currentAdc - m_peakFindingOffset
00361 << " Using 0" << endreq;
00362 adcFirst = 0;
00363 }
00364 else adcFirst = currentAdc - m_peakFindingOffset;
00365 verbose() << "ADC First in ns: " << adcFirst * 25. << endreq;
00366
00367 if( currentAdc - m_peakFindingOffset + m_peakFindingLength > adc->size() ){
00368 verbose() << "Invalid ATDC Peak Finding Last Cycle "
00369 << currentAdc - m_peakFindingOffset + m_peakFindingLength
00370 << " Using " << adc->size() -1 << endreq;
00371 adcLast = adc->size() -1;
00372 }
00373 else adcLast = currentAdc - m_peakFindingOffset + m_peakFindingLength;
00374 verbose() << "ADC Last in ns: " << adcLast * 25. << endreq;
00375
00376 verbose() << "Reading out peak finding window [ "
00377 << adcFirst << "," << adcLast +1 << ")" << endreq;
00378
00379
00380 for( int j = adcFirst; j < adcLast; ++j ){
00381 if( adc->at(j) >= m_maxFineAdc ){
00382 gain = DayaBay::FeeGain::kLow;
00383 adc = &(feeChannel->adcLow());
00384 debug() << "Switching to Low gain ADC since High was saturated"
00385 << endreq;
00386 break;
00387 }
00388 }
00389
00390 verbose() << "Ready to readout ADC's" << endreq;
00391
00392
00393 int adcPeak = -1;
00394 int adcPeakCycle = 0;
00395 for(int adcCycle = (int)adcFirst; adcCycle < (int)adcLast; ++adcCycle){
00396 if( adc->at(adcCycle) > adcPeak ){
00397
00398 adcPeak = adc->at(adcCycle);
00399 adcPeakCycle = adcCycle-adcFirst;
00400 verbose() << "Found New Max ADC at " << adcPeakCycle << endreq;
00401 }
00402 }
00403
00404
00405 int preAdc = 0;
00406 adcPedFirst = adcFirst - m_preAdcOffset;
00407 for(int adcCycle = adcPedFirst; adcCycle<adcPedFirst + 4; adcCycle++){
00408 if(adcCycle < 0) {
00409 verbose() << "Invalid PreADC Cycle "
00410 << adcCycle
00411 << " Using standard baseline value" << endreq;
00412 if(gain == DayaBay::FeeGain::kHigh) preAdc += int(feeSimData->m_adcBaselineHigh);
00413 if(gain == DayaBay::FeeGain::kLow) preAdc += int(feeSimData->m_adcBaselineLow);
00414 }
00415 else preAdc += adc->at(adcCycle);
00416 }
00417 verbose() << "First PreADC cycle in ns: " << adcPedFirst * 25. << endreq;
00418 preAdc /= 4;
00419 verbose() << "Reading out adc " << adcPeak
00420 << " at cycle " << adcPeakCycle << endreq;
00421 verbose() << "Reading out preADC " << preAdc << endreq;
00422
00423 adc_out[i] = adcPeak;
00424 adcCycle_out[i] = adcPeakCycle;
00425 adcRange_out[i] = gain;
00426 preAdc_out[i] = preAdc;
00427
00428 }
00429 else {
00430 verbose() << "No peak finding (previous not finished)" << endreq;
00431
00432 adc_out[i] = 0;
00433 adcCycle_out[i] = 0;
00434 adcRange_out[i] = 0;
00435 preAdc_out[i] = 0;
00436 }
00437
00438
00439 tdc_out[i] = tdcStopCycle - tdc_vec[i];
00440 tdcHitCount_out[i] = nTdc - i;
00441 }
00442
00443
00444 ro_ch->setTdc(tdc_out);
00445 ro_ch->setTdcHitCount(tdcHitCount_out);
00446 ro_ch->setAdc(adc_out);
00447 ro_ch->setAdcCycle(adcCycle_out);
00448 ro_ch->setAdcRange(adcRange_out);
00449 ro_ch->setPedestal(preAdc_out);
00450 }
00451
00452
00453 if ( m_enableWaveformReadout ){
00454 adcFirst = (int) (double(tdcFirst) * double(DayaBay::AdcCycles)/double(DayaBay::TdcCycles) + 0.5);
00455 adcLast = (int) (double(tdcLast) * double(DayaBay::AdcCycles)/double(DayaBay::TdcCycles) + 0.5);
00456 int adcStopCycle = (int) (double(tdcStopCycle) * double(DayaBay::AdcCycles)/double(DayaBay::TdcCycles) + 0.5);
00457
00458 std::vector<int> waveAdcLow_out;
00459 std::vector<int> waveAdcHigh_out;
00460 std::vector<int> waveAdcCycle_out;
00461
00462
00463 adc = &(feeChannel->adcLow());
00464 StatusCode sc = m_waveformTool->readoutWaveform(*adc, adcFirst, adcLast, adcStopCycle, waveAdcLow_out, waveAdcCycle_out);
00465 if( !sc.isSuccess() || waveAdcLow_out.empty() ) {
00466 delete ro_ch;
00467 return 0;
00468 }
00469 waveAdcCycle_out.clear();
00470
00471
00472 adc = &(feeChannel->adcHigh());
00473 sc = m_waveformTool->readoutWaveform(*adc, adcFirst, adcLast, adcStopCycle, waveAdcHigh_out, waveAdcCycle_out);
00474 if( !sc.isSuccess() || waveAdcHigh_out.empty() ){
00475 delete ro_ch;
00476 return 0;
00477 }
00478
00479
00480 ro_ch->setWaveAdcLow(waveAdcLow_out);
00481 ro_ch->setWaveAdcHigh(waveAdcHigh_out);
00482 ro_ch->setWaveAdcCycle(waveAdcCycle_out);
00483 }
00484 return ro_ch;
00485 }
00486
00487
00488 StatusCode ROsFeeReadoutTool::mutate(DayaBay::SimReadoutHeader* roHeader,
00489 std::vector<DayaBay::ReadoutTriggerDataPkg*>& trigDataPkg,
00490 const DayaBay::ElecHeader& elecHeader)
00491 {
00492 verbose() << "calling ROsFeeReadoutTool.mutate()" << endreq;
00493 return makeReadouts(roHeader,trigDataPkg,elecHeader);
00494 }