Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

Coroner.cxx

Go to the documentation of this file.
00001 
00002 // $Id: Coroner.cxx,v 1.7 2007/11/11 06:00:01 rhatcher Exp $
00003 //
00004 // FILL_IN: [Document your code!!]
00005 //
00006 // n.tagg1@physics.ox.ac.uk
00008 #include "Morgue/Coroner.h"
00009 #include "Morgue/Morgue.h"
00010 #include "MessageService/MsgService.h"
00011 #include "MinosObjectMap/MomNavigator.h"
00012 #include "JobControl/JobCModuleRegistry.h" // For JOBMODULE macro
00013 #include "Plex/PlexHandle.h"
00014 #include "CandData/CandRecord.h"
00015 #include "CandDigit/CandDigitListHandle.h"
00016 #include "CandDigit/CandDigitHandle.h"
00017 #include "Conventions/Munits.h"
00018 #include "DataUtil/GetRawBlock.h"
00019 #include "DataUtil/GetRawHeader.h"
00020 #include "RawData/RawLiTpmtDigitsBlock.h"
00021 #include "RawData/RawHeader.h"
00022 #include "RawData/RawDigit.h"
00023 #include "Calibrator/Calibrator.h"
00024 #include <algorithm>
00025 #include <cmath>
00026 
00027 JOBMODULE(Coroner, "Coroner",
00028           "Coroner");
00029 CVSID("$Id: Coroner.cxx,v 1.7 2007/11/11 06:00:01 rhatcher Exp $");
00030 //......................................................................
00031 
00032 Coroner::Coroner()
00033 {
00034 }
00035 
00036 //......................................................................
00037 
00038 Coroner::~Coroner()
00039 {
00040   ClearTables();
00041 }
00042 
00043 //......................................................................
00044 
00045 JobCResult Coroner::Ana(const MomNavigator* mom)
00046 {
00047   // 
00048   // Quick module to look at Morgue
00049   //
00050 
00051   const Morgue& morgue = Morgue::GetMorgue(mom);
00052   morgue.Print("a");
00053 
00054   return JobCResult::kPassed; // kNoDecision, kFailed, etc.
00055 }
00056 
00057 //......................................................................
00058 
00059 JobCResult Coroner::Reco(MomNavigator* mom)
00060 {
00061   //
00062   // Creates and fills a Morgue object with all the relevant info about an event.
00063   //
00064   
00065   // Look for TPMT hits and record them.
00066   UpdateLiHitList(mom);
00067 
00068   JobCResult result;
00069   VldContext context;
00070 
00071   // Find PrimaryCandidateRecord fragment in MOM.
00072   CandRecord *candrec = dynamic_cast<CandRecord *>
00073     (mom->GetFragment("CandRecord", "PrimaryCandidateRecord"));
00074   if (candrec == 0) {
00075     MSG("Morgue", Msg::kWarning) << "No PrimaryCandidateRecord in  MOM."
00076                                  << endl;
00077     result.SetWarning().SetFailed();
00078     return result;
00079   }
00080 
00081   // Find vld.
00082   context = *(candrec->GetVldContext());
00083 
00084   // Make new Morgue.
00085   Morgue* morgue = new Morgue;
00086   
00087   // Give it dead strips.
00088   result |= RecordDeadStrips(morgue,candrec);
00089   
00090   // Give it bad strips.
00091   result |= RecordBadStrips(morgue,context);
00092 
00093   // Find relevant LI hit.
00094   result |= RecordLiHits(morgue,context);
00095   
00096   // Add the morgue to the cand record.
00097   if(candrec)
00098     candrec->AdoptTemporary(morgue);
00099 
00100   return result; // kNoDecision, kFailed, etc.
00101 }
00102 
00103 
00104 JobCResult Coroner::RecordDeadStrips(Morgue* morgue, 
00105                                      const CandRecord* candrec)
00106 {
00107   //
00108   // Loop over digits in the snarl
00109   // and use them to figure out when strips are dead.
00110   //
00111 
00112    // Get CandDigits.
00113   CandDigitListHandle* cdlh = dynamic_cast<CandDigitListHandle *>
00114     (candrec->FindCandHandle("CandDigitListHandle", "canddigitlist"));
00115 
00116   if(!cdlh) {
00117     MSG("Morgue", Msg::kWarning) << "No CandDigitList in  MOM."
00118                                  << endl;
00119     return JobCResult::kFailed;
00120   }
00121 
00122   VldContext context = *(cdlh->GetVldContext());
00123   morgue->SetTriggerTime((context.GetTimeStamp().GetNanoSec())*Munits::ns);
00124 
00125   // FIXME: Are we in ND spill mode? If so, skip the dead chip step.
00126   
00127   // Look for fired PMTs, build up a deadness map.
00128   // This contorted logic is to get a list of PMTs that fired, with only 
00129   // one entry per PMT fire, but allowing a PMT to fire more than once.
00130   std::map<PlexPixelSpotId, std::vector<Double_t> > firedPmts;
00131   std::map<PlexPixelSpotId, std::vector<Double_t> >::iterator pmtItr;
00132 
00133   CandDigitHandleItr cdhItr(cdlh->GetDaughterIterator());
00134   while(CandDigitHandle *cdh = cdhItr()) {
00135     const PlexSEIdAltL& altl = cdh->GetPlexSEIdAltL();
00136     if(altl.size()>0) {
00137       PlexPixelSpotId tube = altl.GetBestItem().GetPixelSpotId();
00138       tube.SetSpot(1);
00139       tube.SetPixel(1);
00140       Double_t t = cdh->GetTime(); // Uncalibrated time.
00141       std::vector<Double_t>& v = firedPmts[tube];
00142     
00143       // See if this fire has already been recorded.
00144       bool isnew = true;
00145       for(UInt_t i=0;i<v.size();i++) { if (t==v[i])  isnew=false; };
00146       
00147       if(isnew) v.push_back(t); // Record the mother.
00148     }
00149   }
00150 
00151   // Dead time definitions.
00152   const double kVA_1chip_FD = ( 300. * Munits::ns  // Shaping delay
00153                                 +22. * (1.0/5.e6)  // Readout 22 channels @ 5MHz/channel
00154                                 +100.* Munits::ns ); // Veto region around chip recovery
00155 
00156   const double kVA_6chip_FD = ( 300. * Munits::ns  // Shaping delay
00157                                 +6.0 * 22. * (1.0/5.e6)  // Readout 6 chips on a VMM at 22 channels @ 5MHz/channel
00158                                 +100.* Munits::ns ); // Veto region around chip recovery
00159  
00160   // For most caldet runs, the readout speed was less (the wait delay was 4 instead of 2)
00161   const double kVA_1chip_CalDet = ( 300. * Munits::ns  // Shaping delay
00162                                     +22. * (1.0/2.5e6)  // Readout 22 channels @ 5MHz/channel
00163                                     +100.* Munits::ns ); // Veto region around chip recovery
00164   
00165   const double kVA_6chip_CalDet = ( 300. * Munits::ns  // Shaping delay
00166                                     +6.0 * 22. * (1.0/2.5e6)  // Readout 6 chips on a VMM at 22 channels @ 5MHz/channel
00167                                     +100.* Munits::ns ); // Veto region around chip recovery
00168   
00169   // ND:
00170   // Dave R. sez: It takes 2 clock ticks per channel per bucket to read out, so..
00171   // Dead time is 32 x livetime. Livetime is 8 x 53MHz buckets
00172   const double kQIE_1pmt = 32. * 8. * (1.0/53.1e6); 
00173   
00174 
00175   PlexHandle plex(context);
00176   
00177   // Finally, we can fill the Morgue.
00178   for(pmtItr = firedPmts.begin(); pmtItr!=firedPmts.end(); pmtItr++) {
00179     PlexPixelSpotId tube = pmtItr->first;
00180     std::vector<Double_t>& v = pmtItr->second; 
00181     for(UInt_t i=0;i<v.size();i++) {
00182       double t_fired = v[i];
00183       double t_maybe = t_fired;
00184       double t_recover= t_fired;
00185 
00186       switch(tube.GetElecType()) {
00187         case ElecType::kVA:
00188           t_maybe   = t_fired + kVA_1chip_FD;
00189           t_recover = t_fired + kVA_6chip_FD;
00190           if(tube.GetDetector()==Detector::kCalDet) {
00191             t_maybe   = t_fired + kVA_1chip_CalDet;
00192             t_recover = t_fired + kVA_6chip_CalDet;
00193           }
00194         break;
00195       case ElecType::kQIE:
00196         t_maybe   = t_fired + kQIE_1pmt; 
00197         t_recover = t_fired + kQIE_1pmt; 
00198         break;
00199       default:
00200         MSG("Morgue",Msg::kWarning) << "Unknown ElecType on PMT: " << tube.AsString() << endl;
00201       }
00202       
00203       int npix = 16;
00204       int nspot = 8;
00205       if(tube.GetElecType()==ElecType::kQIE) {
00206         npix = 64;
00207         nspot= 1;
00208       }
00209       PlexPixelSpotId pixel = tube;
00210 
00211       for(int ipix = 0; ipix<npix; ipix++) {
00212         for(int ispot=1; ispot<=nspot; ispot++) {
00213           pixel.SetPixel(ipix);
00214           pixel.SetSpot(ispot);
00215           PlexStripEndId seid = plex.GetStripEndId(pixel);
00216           if(seid.IsValid()) {
00217             morgue->AddDeadStrip(seid,t_fired,t_maybe,t_recover);
00218           }
00219         }
00220       }
00221 
00222     }    
00223   }
00224 
00225   return JobCResult::kPassed;
00226 }
00227 
00228 //......................................................................
00229 
00230 JobCResult Coroner::RecordBadStrips(Morgue* morgue, 
00231                                     const VldContext& context)
00232 {
00233   // Consult all available databases.
00234   PlexHandle plex(context);
00235 
00236   for(UInt_t itask=0;itask<fBadHardwareTasks.size();itask++) {
00237     fBadHardwareTables[itask]->NewQuery(context,fBadHardwareTasks[itask]);
00238   
00239     // Check all entries in all tables.
00240     for(UInt_t irow=0;irow <  fBadHardwareTables[itask]->GetNumRows(); irow++) {
00241       const BadHardware* row = fBadHardwareTables[itask]->GetRow(irow);
00242       if(row) {
00243         if(row->IsInEffect(context.GetTimeStamp())) {
00244           vector<PlexStripEndId> strips = row->GetComponent().GetStripEnds(plex);
00245           for(UInt_t istrip = 0; istrip < strips.size(); istrip++) {
00246             morgue->AddBadStrip(strips[istrip], row->GetComponent(), (Morgue::Badness_t)(row->GetBadness()), row->GetReason().c_str() );
00247           }
00248         }
00249       }
00250     }
00251   }
00252 
00253 
00254   return JobCResult::kPassed;
00255 }
00256 
00257 
00258 JobCResult Coroner::RecordLiHits(Morgue* morgue, 
00259                                  const VldContext& context)
00260 {
00261   VldTimeStamp eventtime = context.GetTimeStamp();
00262   // find the closest.
00263   double smallest_dt = 1e0;
00264   VldTimeStamp closest;
00265   LiHitList_t::iterator it = fRecentLiHits.begin();
00266   for(; it!= fRecentLiHits.end(); it++) {
00267     double dt = fabs((*it) - eventtime);
00268     if(dt <= smallest_dt) {
00269       smallest_dt = dt;
00270       closest = *it;
00271     }
00272   }
00273   // Don't bother if the nearest one is more than 100ms away.. that's good enough.
00274   if(smallest_dt > 0.1*Munits::second) return JobCResult::kPassed;
00275 
00276   double time = Munits::ns*closest.GetNanoSec();
00277   int del_secs = closest.GetSec() - eventtime.GetSec();
00278   time += (del_secs)*Munits::second;
00279   morgue->SetNearestLiTime(time);
00280   MSG("Morgue",Msg::kInfo) << "Set nearest LI time. Dt from trigger is "  
00281                            << morgue->GetNearestLiTime() - morgue->GetTriggerTime()
00282                            << endl;
00283   return JobCResult::kPassed;
00284 }
00285                
00286 
00287 
00288 
00289 
00290 void Coroner::UpdateLiHitList( const MomNavigator* mom )
00291 {
00295   const RawHeader* header = DataUtil::GetRawHeader<RawHeader>(mom);
00296   if(header) {
00297     VldTimeStamp curtime = header->GetVldContext().GetTimeStamp();
00298 
00299     // This little snippet clips out the 
00300     LiHitList_t::iterator it = fRecentLiHits.begin();
00301     for( ; it!= fRecentLiHits.end(); it++) {
00302       if( fabs((*it)-curtime) < 3.0 ) break;
00303     }
00304     if(it!=fRecentLiHits.begin()) {
00305       fRecentLiHits.erase(fRecentLiHits.begin(),(it));
00306     }
00307     
00308   }
00309 
00310   const RawLiTpmtDigitsBlock* tpmt_block =
00311     DataUtil::GetRawBlock<RawLiTpmtDigitsBlock>(mom);
00312 
00313 
00314   if(tpmt_block) {
00315     MSG("Morgue",Msg::kInfo) << "Found TPMT block time "
00316                              << tpmt_block->GetTimeStamp().AsString()
00317                              <<"  with " 
00318                              << tpmt_block->GetNumberOfDigits()
00319                              << " digits. " << endl;
00320     for(int i=0;i< tpmt_block->GetNumberOfDigits(); i++) {
00321       const RawDigit* digit = tpmt_block->At(i);
00322       double digtime = Calibrator::Instance().GetTimeFromTDC(digit->GetTDC(),
00323                                                              digit->GetChannel());
00324 
00325       VldTimeStamp ts = tpmt_block->GetTimeStamp();
00326       ts.Add(digtime);
00327       fRecentLiHits.push_back(ts);
00328     }
00329     std::sort(fRecentLiHits.begin(),fRecentLiHits.end());
00330   }
00331 
00332 }
00333 
00334 
00335 
00336 //......................................................................
00337 
00338 const Registry& Coroner::DefaultConfig() const
00339 {
00340 //======================================================================
00341 // Supply the default configuration for the module
00342 //======================================================================
00343   static Registry r; // Default configuration for module
00344 
00345   // Set name of config
00346   std::string name = this->GetName();
00347   name += ".config.default";
00348   r.SetName(name.c_str());
00349 
00350   // Set values in configuration
00351   r.UnLockValues();
00352   r.Set("BadHardwareTasks","1,2");
00353   r.LockValues();
00354 
00355   return r;
00356 }
00357 
00358 //......................................................................
00359 
00360 void Coroner::Config(const Registry& r)
00361 {
00362 //======================================================================
00363 // Configure the module given the Registry r
00364 //======================================================================
00365   
00366   int task;
00367   if(r.Get("BadHardwareTasks",task) ) {
00368     ClearTables();
00369     fBadHardwareTasks.push_back(task);
00370     fBadHardwareTables.push_back( new DbiResultPtr<BadHardware> ); 
00371     MSG("Morgue",Msg::kInfo) << "Configured to use BadHardware task " << task << endl;
00372   }
00373 
00374   const char* taskstr;
00375   if(r.Get("BadHardwareTasks",taskstr) ) {
00376     ClearTables();
00377     const char* s = taskstr;
00378     int task;
00379     int n;
00380     while( sscanf(s,"%d%n",&task,&n) > 0) {
00381       s += n+1;
00382       fBadHardwareTasks.push_back(task);
00383       fBadHardwareTables.push_back( new DbiResultPtr<BadHardware> );
00384 
00385       MSG("Morgue",Msg::kInfo) << "Configured to use BadHardware task " << task << endl;
00386     }
00387   }
00388 
00389  
00390 }
00391 
00392 
00393 void Coroner::ClearTables()
00394 {
00395   for(UInt_t itask=0;itask<fBadHardwareTasks.size();itask++) {
00396     delete fBadHardwareTables[itask];
00397   }
00398   fBadHardwareTasks.clear();
00399   fBadHardwareTables.clear();
00400 
00401 }
00402 

Generated on Mon Feb 15 11:06:33 2010 for loon by  doxygen 1.3.9.1