CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_2_7_hltpatch2/src/L1Trigger/CSCTriggerPrimitives/src/CSCMotherboard.cc

Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 //
00003 //   Class: CSCMotherboard
00004 //
00005 //   Description: 
00006 //    When the Trigger MotherBoard is instantiated it instantiates an ALCT
00007 //    and CLCT board.  The Motherboard takes up to two LCTs from each anode
00008 //    and cathode LCT card and combines them into a single Correlated LCT.
00009 //    The output is up to two Correlated LCTs.
00010 //
00011 //    It can be run in either a test mode, where the arguments are a collection
00012 //    of wire times and arrays of halfstrip and distrip times, or
00013 //    for general use, with with wire digi and comparator digi collections as
00014 //    arguments.  In the latter mode, the wire & strip info is passed on the
00015 //    LCTProcessors, where it is decoded and converted into a convenient form.
00016 //    After running the anode and cathode LCTProcessors, TMB correlates the
00017 //    anode and cathode LCTs.  At present, it simply matches the best CLCT
00018 //    with the best ALCT; perhaps a better algorithm will be determined in
00019 //    the future.  The MotherBoard then determines a few more numbers (such as
00020 //    quality and pattern) from the ALCT and CLCT information, and constructs
00021 //    two correlated LCTs.
00022 //
00023 //    correlateLCTs() may need to be modified to take into account a
00024 //    possibility of ALCTs and CLCTs arriving at different bx times.
00025 //
00026 //   Author List: Benn Tannenbaum 28 August 1999 benn@physics.ucla.edu
00027 //                Based on code by Nick Wisniewski (nw@its.caltech.edu)
00028 //                and a framework by Darin Acosta (acosta@phys.ufl.edu).
00029 //
00030 //   $Date: 2010/08/04 14:50:11 $
00031 //   $Revision: 1.33 $
00032 //
00033 //   Modifications: Numerous later improvements by Jason Mumford and
00034 //                  Slava Valuev (see cvs in ORCA).
00035 //   Porting from ORCA by S. Valuev (Slava.Valuev@cern.ch), May 2006.
00036 //
00037 //-----------------------------------------------------------------------------
00038 
00039 #include <L1Trigger/CSCTriggerPrimitives/src/CSCMotherboard.h>
00040 #include <FWCore/MessageLogger/interface/MessageLogger.h>
00041 #include <DataFormats/MuonDetId/interface/CSCTriggerNumbering.h>
00042 
00043 // Default values of configuration parameters.
00044 const unsigned int CSCMotherboard::def_mpc_block_me1a      = 1;
00045 const unsigned int CSCMotherboard::def_alct_trig_enable    = 0;
00046 const unsigned int CSCMotherboard::def_clct_trig_enable    = 0;
00047 const unsigned int CSCMotherboard::def_match_trig_enable   = 1;
00048 const unsigned int CSCMotherboard::def_match_trig_window_size = 7;
00049 const unsigned int CSCMotherboard::def_tmb_l1a_window_size = 7;
00050 
00051 CSCMotherboard::CSCMotherboard(unsigned endcap, unsigned station,
00052                                unsigned sector, unsigned subsector,
00053                                unsigned chamber,
00054                                const edm::ParameterSet& conf) :
00055                    theEndcap(endcap), theStation(station), theSector(sector),
00056                    theSubsector(subsector), theTrigChamber(chamber) {
00057   // Normal constructor.  -JM
00058   // Pass ALCT, CLCT, and common parameters on to ALCT and CLCT processors.
00059   static bool config_dumped = false;
00060 
00061   // Some configuration parameters and some details of the emulator
00062   // algorithms depend on whether we want to emulate the trigger logic
00063   // used in TB/MTCC or its idealized version (the latter was used in MC
00064   // studies since early ORCA days until (and including) CMSSW_2_1_X).
00065   edm::ParameterSet commonParams =
00066     conf.getParameter<edm::ParameterSet>("commonParam");
00067   isMTCC = commonParams.getParameter<bool>("isMTCC");
00068 
00069   // Switch for a new (2007) version of the TMB firmware.
00070   isTMB07 = commonParams.getParameter<bool>("isTMB07");
00071 
00072   // Choose the appropriate set of configuration parameters depending on
00073   // isTMB07 and isMTCC flags.
00074   // Starting with CMSSW_3_1_X, these settings are overwritten by the
00075   // ones delivered by the EventSetup mechanism.
00076   edm::ParameterSet alctParams, clctParams;
00077   if (isTMB07) {
00078     alctParams = conf.getParameter<edm::ParameterSet>("alctParam07");
00079     clctParams = conf.getParameter<edm::ParameterSet>("clctParam07");
00080   }
00081   else if (isMTCC) {
00082     alctParams = conf.getParameter<edm::ParameterSet>("alctParamMTCC");
00083     clctParams = conf.getParameter<edm::ParameterSet>("clctParamMTCC");
00084   }
00085   else {
00086     alctParams = conf.getParameter<edm::ParameterSet>("alctParamOldMC");
00087     clctParams = conf.getParameter<edm::ParameterSet>("clctParamOldMC");
00088   }
00089   alct = new CSCAnodeLCTProcessor(endcap, station, sector, subsector,
00090                                   chamber, alctParams, commonParams);
00091   clct = new CSCCathodeLCTProcessor(endcap, station, sector, subsector,
00092                                     chamber, clctParams, commonParams);
00093 
00094   // Motherboard parameters: common for all configurations.
00095   edm::ParameterSet tmbParams  =
00096     conf.getParameter<edm::ParameterSet>("tmbParam");
00097   mpc_block_me1a    = tmbParams.getParameter<unsigned int>("mpcBlockMe1a");
00098   alct_trig_enable  = tmbParams.getParameter<unsigned int>("alctTrigEnable");
00099   clct_trig_enable  = tmbParams.getParameter<unsigned int>("clctTrigEnable");
00100   match_trig_enable = tmbParams.getParameter<unsigned int>("matchTrigEnable");
00101   match_trig_window_size =
00102     tmbParams.getParameter<unsigned int>("matchTrigWindowSize");
00103   tmb_l1a_window_size = // Common to CLCT and TMB
00104     tmbParams.getParameter<unsigned int>("tmbL1aWindowSize");
00105 
00106   infoV = tmbParams.getUntrackedParameter<int>("verbosity", 0);
00107 
00108   // Check and print configuration parameters.
00109   checkConfigParameters();
00110   if (infoV > 0 && !config_dumped) {
00111     dumpConfigParams();
00112     config_dumped = true;
00113   }
00114 
00115   // test to make sure that what goes into a correlated LCT is also what
00116   // comes back out.
00117   // testLCT();
00118 }
00119 
00120 CSCMotherboard::CSCMotherboard() :
00121                    theEndcap(1), theStation(1), theSector(1),
00122                    theSubsector(1), theTrigChamber(1) {
00123   // Constructor used only for testing.  -JM
00124   static bool config_dumped = false;
00125 
00126   isMTCC  = false;
00127   isTMB07 = true;
00128 
00129   alct = new CSCAnodeLCTProcessor();
00130   clct = new CSCCathodeLCTProcessor();
00131   mpc_block_me1a      = def_mpc_block_me1a;
00132   alct_trig_enable    = def_alct_trig_enable;
00133   clct_trig_enable    = def_clct_trig_enable;
00134   match_trig_enable   = def_match_trig_enable;
00135   match_trig_window_size = def_match_trig_window_size;
00136   tmb_l1a_window_size = def_tmb_l1a_window_size;
00137 
00138   infoV = 2;
00139 
00140   // Check and print configuration parameters.
00141   checkConfigParameters();
00142   if (infoV > 0 && !config_dumped) {
00143     dumpConfigParams();
00144     config_dumped = true;
00145   }
00146 }
00147 
00148 CSCMotherboard::~CSCMotherboard() {
00149   if (alct) delete alct;
00150   if (clct) delete clct;
00151 }
00152 
00153 void CSCMotherboard::clear() {
00154   if (alct) alct->clear();
00155   if (clct) clct->clear();
00156   for (int bx = 0; bx < MAX_LCT_BINS; bx++) {
00157     firstLCT[bx].clear();
00158     secondLCT[bx].clear();
00159   }
00160 }
00161 
00162 // Set configuration parameters obtained via EventSetup mechanism.
00163 void CSCMotherboard::setConfigParameters(const CSCDBL1TPParameters* conf) {
00164   static bool config_dumped = false;
00165 
00166   // Config. parameters for the TMB itself.
00167   mpc_block_me1a         = conf->tmbMpcBlockMe1a();
00168   alct_trig_enable       = conf->tmbAlctTrigEnable();
00169   clct_trig_enable       = conf->tmbClctTrigEnable();
00170   match_trig_enable      = conf->tmbMatchTrigEnable();
00171   match_trig_window_size = conf->tmbMatchTrigWindowSize();
00172   tmb_l1a_window_size    = conf->tmbTmbL1aWindowSize();
00173 
00174   // Config. paramteres for ALCT and CLCT processors.
00175   alct->setConfigParameters(conf);
00176   clct->setConfigParameters(conf);
00177 
00178   // Check and print configuration parameters.
00179   checkConfigParameters();
00180   if (!config_dumped) {
00181     dumpConfigParams();
00182     config_dumped = true;
00183   }
00184 }
00185 
00186 void CSCMotherboard::checkConfigParameters() {
00187   // Make sure that the parameter values are within the allowed range.
00188 
00189   // Max expected values.
00190   static const unsigned int max_mpc_block_me1a      = 1 << 1;
00191   static const unsigned int max_alct_trig_enable    = 1 << 1;
00192   static const unsigned int max_clct_trig_enable    = 1 << 1;
00193   static const unsigned int max_match_trig_enable   = 1 << 1;
00194   static const unsigned int max_match_trig_window_size = 1 << 4;
00195   static const unsigned int max_tmb_l1a_window_size = 1 << 4;
00196 
00197   // Checks.
00198   if (mpc_block_me1a >= max_mpc_block_me1a) {
00199     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00200       << "+++ Value of mpc_block_me1a, " << mpc_block_me1a
00201       << ", exceeds max allowed, " << max_mpc_block_me1a-1 << " +++\n"
00202       << "+++ Try to proceed with the default value, mpc_block_me1a="
00203       << def_mpc_block_me1a << " +++\n";
00204     mpc_block_me1a = def_mpc_block_me1a;
00205   }
00206   if (alct_trig_enable >= max_alct_trig_enable) {
00207     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00208       << "+++ Value of alct_trig_enable, " << alct_trig_enable
00209       << ", exceeds max allowed, " << max_alct_trig_enable-1 << " +++\n"
00210       << "+++ Try to proceed with the default value, alct_trig_enable="
00211       << def_alct_trig_enable << " +++\n";
00212     alct_trig_enable = def_alct_trig_enable;
00213   }
00214   if (clct_trig_enable >= max_clct_trig_enable) {
00215     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00216       << "+++ Value of clct_trig_enable, " << clct_trig_enable
00217       << ", exceeds max allowed, " << max_clct_trig_enable-1 << " +++\n"
00218       << "+++ Try to proceed with the default value, clct_trig_enable="
00219       << def_clct_trig_enable << " +++\n";
00220     clct_trig_enable = def_clct_trig_enable;
00221   }
00222   if (match_trig_enable >= max_match_trig_enable) {
00223     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00224       << "+++ Value of match_trig_enable, " << match_trig_enable
00225       << ", exceeds max allowed, " << max_match_trig_enable-1 << " +++\n"
00226       << "+++ Try to proceed with the default value, match_trig_enable="
00227       << def_match_trig_enable << " +++\n";
00228     match_trig_enable = def_match_trig_enable;
00229   }
00230   if (match_trig_window_size >= max_match_trig_window_size) {
00231     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00232       << "+++ Value of match_trig_window_size, " << match_trig_window_size
00233       << ", exceeds max allowed, " << max_match_trig_window_size-1 << " +++\n"
00234       << "+++ Try to proceed with the default value, match_trig_window_size="
00235       << def_match_trig_window_size << " +++\n";
00236     match_trig_window_size = def_match_trig_window_size;
00237   }
00238   if (tmb_l1a_window_size >= max_tmb_l1a_window_size) {
00239     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00240       << "+++ Value of tmb_l1a_window_size, " << tmb_l1a_window_size
00241       << ", exceeds max allowed, " << max_tmb_l1a_window_size-1 << " +++\n"
00242       << "+++ Try to proceed with the default value, tmb_l1a_window_size="
00243       << def_tmb_l1a_window_size << " +++\n";
00244     tmb_l1a_window_size = def_tmb_l1a_window_size;
00245   }
00246 }
00247 
00248 void CSCMotherboard::run(
00249  const std::vector<int> w_times[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIRES],
00250  const std::vector<int> hs_times[CSCConstants::NUM_LAYERS][CSCConstants::NUM_HALF_STRIPS],
00251  const std::vector<int> ds_times[CSCConstants::NUM_LAYERS][CSCConstants::NUM_HALF_STRIPS]) {
00252   // Debug version.  -JM
00253   clear();
00254   alct->run(w_times);            // run anode LCT
00255   clct->run(hs_times, ds_times); // run cathodeLCT
00256 
00257   int bx_alct_matched = 0;
00258   for (int bx_clct = 0; bx_clct < CSCCathodeLCTProcessor::MAX_CLCT_BINS;
00259        bx_clct++) {
00260     if (clct->bestCLCT[bx_clct].isValid()) {
00261       bool is_matched = false;
00262       int bx_alct_start = bx_clct - match_trig_window_size/2;
00263       // int bx_alct_stop  = bx_clct + match_trig_window_size/2;
00264       // Empirical correction to match 2009 collision data (firmware change?)
00265       int bx_alct_stop  = bx_clct + match_trig_window_size/2 + 
00266         match_trig_window_size%2;
00267       for (int bx_alct = bx_alct_start; bx_alct <= bx_alct_stop; bx_alct++) {
00268         if (bx_alct < 0 || bx_alct >= CSCAnodeLCTProcessor::MAX_ALCT_BINS)
00269           continue;
00270         if (alct->bestALCT[bx_alct].isValid()) {
00271           correlateLCTs(alct->bestALCT[bx_alct], alct->secondALCT[bx_alct],
00272                         clct->bestCLCT[bx_clct], clct->secondCLCT[bx_clct]);
00273           is_matched = true;
00274           bx_alct_matched = bx_alct;
00275           break;
00276         }
00277       }
00278       // No ALCT within the match time interval found: report CLCT-only LCT
00279       // (use dummy ALCTs).
00280       if (!is_matched) {
00281         correlateLCTs(alct->bestALCT[bx_clct], alct->secondALCT[bx_clct],
00282                       clct->bestCLCT[bx_clct], clct->secondCLCT[bx_clct]);
00283       }
00284     }
00285     // No valid CLCTs; attempt to make ALCT-only LCT (use dummy CLCTs).
00286     else {
00287       int bx_alct = bx_clct - match_trig_window_size/2;
00288       if (bx_alct >= 0 && bx_alct > bx_alct_matched) {
00289         if (alct->bestALCT[bx_alct].isValid()) {
00290           correlateLCTs(alct->bestALCT[bx_alct], alct->secondALCT[bx_alct],
00291                         clct->bestCLCT[bx_clct], clct->secondCLCT[bx_clct]);
00292         }
00293       }
00294     }
00295   }
00296 }
00297 
00298 std::vector<CSCCorrelatedLCTDigi>
00299 CSCMotherboard::run(const CSCWireDigiCollection* wiredc,
00300                     const CSCComparatorDigiCollection* compdc) {
00301   clear();
00302   if (alct && clct) {
00303     {
00304       std::vector<CSCALCTDigi> alctV = alct->run(wiredc); // run anodeLCT
00305     }
00306     {
00307       std::vector<CSCCLCTDigi> clctV = clct->run(compdc); // run cathodeLCT
00308     }
00309 
00310     int bx_alct_matched = 0; // bx of last matched ALCT
00311     for (int bx_clct = 0; bx_clct < CSCCathodeLCTProcessor::MAX_CLCT_BINS;
00312          bx_clct++) {
00313       // There should be at least one valid ALCT or CLCT for a
00314       // correlated LCT to be formed.  Decision on whether to reject
00315       // non-complete LCTs (and if yes of which type) is made further
00316       // upstream.
00317       if (clct->bestCLCT[bx_clct].isValid()) {
00318         // Look for ALCTs within the match-time window.  The window is
00319         // centered at the CLCT bx; therefore, we make an assumption
00320         // that anode and cathode hits are perfectly synchronized.  This
00321         // is always true for MC, but only an approximation when the
00322         // data is analyzed (which works fairly good as long as wide
00323         // windows are used).  To get rid of this assumption, one would
00324         // need to access "full BX" words, which are not readily
00325         // available.
00326         bool is_matched = false;
00327         int bx_alct_start = bx_clct - match_trig_window_size/2;
00328         // int bx_alct_stop  = bx_clct + match_trig_window_size/2;
00329         // Empirical correction to match 2009 collision data (firmware change?)
00330         int bx_alct_stop  = bx_clct + match_trig_window_size/2 +
00331           match_trig_window_size%2;
00332         for (int bx_alct = bx_alct_start; bx_alct <= bx_alct_stop; bx_alct++) {
00333           if (bx_alct < 0 || bx_alct >= CSCAnodeLCTProcessor::MAX_ALCT_BINS)
00334             continue;
00335           if (alct->bestALCT[bx_alct].isValid()) {
00336             if (infoV > 1) LogTrace("CSCMotherboard")
00337               << "Successful ALCT-CLCT match: bx_clct = " << bx_clct
00338               << "; match window: [" << bx_alct_start << "; " << bx_alct_stop
00339               << "]; bx_alct = " << bx_alct;
00340             correlateLCTs(alct->bestALCT[bx_alct], alct->secondALCT[bx_alct],
00341                           clct->bestCLCT[bx_clct], clct->secondCLCT[bx_clct]);
00342             is_matched = true;
00343             bx_alct_matched = bx_alct;
00344             break;
00345           }
00346         }
00347         // No ALCT within the match time interval found: report CLCT-only LCT
00348         // (use dummy ALCTs).
00349         if (!is_matched) {
00350           if (infoV > 1) LogTrace("CSCMotherboard")
00351             << "Unsuccessful ALCT-CLCT match (CLCT only): bx_clct = "
00352             << bx_clct << "; match window: [" << bx_alct_start
00353             << "; " << bx_alct_stop << "]";
00354           correlateLCTs(alct->bestALCT[bx_clct], alct->secondALCT[bx_clct],
00355                         clct->bestCLCT[bx_clct], clct->secondCLCT[bx_clct]);
00356         }
00357       }
00358       // No valid CLCTs; attempt to make ALCT-only LCT.  Use only ALCTs
00359       // which have zeroth chance to be matched at later cathode times.
00360       // (I am not entirely sure this perfectly matches the firmware logic.)
00361       // Use dummy CLCTs.
00362       else {
00363         int bx_alct = bx_clct - match_trig_window_size/2;
00364         if (bx_alct >= 0 && bx_alct > bx_alct_matched) {
00365           if (alct->bestALCT[bx_alct].isValid()) {
00366             if (infoV > 1) LogTrace("CSCMotherboard")
00367               << "Unsuccessful ALCT-CLCT match (ALCT only): bx_alct = "
00368               << bx_alct;
00369             correlateLCTs(alct->bestALCT[bx_alct], alct->secondALCT[bx_alct],
00370                           clct->bestCLCT[bx_clct], clct->secondCLCT[bx_clct]);
00371           }
00372         }
00373       }
00374     }
00375 
00376     if (infoV > 0) {
00377       for (int bx = 0; bx < MAX_LCT_BINS; bx++) {
00378         if (firstLCT[bx].isValid())
00379           LogDebug("CSCMotherboard") << firstLCT[bx];
00380         if (secondLCT[bx].isValid())
00381           LogDebug("CSCMotherboard") << secondLCT[bx];
00382       }
00383     }
00384   }
00385   else {
00386     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorSetupError")
00387       << "+++ run() called for non-existing ALCT/CLCT processor! +++ \n";
00388   }
00389 
00390   std::vector<CSCCorrelatedLCTDigi> tmpV = readoutLCTs();
00391   return tmpV;
00392 }
00393 
00394 // Returns vector of read-out correlated LCTs, if any.  Starts with
00395 // the vector of all found LCTs and selects the ones in the read-out
00396 // time window.
00397 std::vector<CSCCorrelatedLCTDigi> CSCMotherboard::readoutLCTs() {
00398   std::vector<CSCCorrelatedLCTDigi> tmpV;
00399 
00400   // The start time of the L1A*LCT coincidence window should be related
00401   // to the fifo_pretrig parameter, but I am not completely sure how.
00402   // Just choose it such that the window is centered at bx=7.  This may
00403   // need further tweaking if the value of tmb_l1a_window_size changes.
00404   static int early_tbins = 4;
00405   // The number of LCT bins in the read-out is given by the
00406   // tmb_l1a_window_size parameter, but made even by setting the LSB
00407   // of tmb_l1a_window_size to 0.
00408   // static int lct_bins =
00409   //   (tmb_l1a_window_size%2 == 0) ? tmb_l1a_window_size : tmb_l1a_window_size-1;
00410   // Empirical correction to match 2009 collision data (firmware change?)
00411   static int lct_bins   = tmb_l1a_window_size;
00412   static int late_tbins = early_tbins + lct_bins;
00413 
00414   static int ifois = 0;
00415   if (ifois == 0) {
00416     if (infoV >= 0 && early_tbins < 0) {
00417       edm::LogWarning("L1CSCTPEmulatorSuspiciousParameters")
00418         << "+++ early_tbins = " << early_tbins
00419         << "; in-time LCTs are not getting read-out!!! +++" << "\n";
00420     }
00421 
00422     if (late_tbins > MAX_LCT_BINS-1) {
00423       if (infoV >= 0) edm::LogWarning("L1CSCTPEmulatorSuspiciousParameters")
00424         << "+++ Allowed range of time bins, [0-" << late_tbins
00425         << "] exceeds max allowed, " << MAX_LCT_BINS-1 << " +++\n"
00426         << "+++ Set late_tbins to max allowed +++\n";
00427       late_tbins = MAX_LCT_BINS-1;
00428     }
00429     ifois = 1;
00430   }
00431 
00432   // Start from the vector of all found correlated LCTs and select
00433   // those within the LCT*L1A coincidence window.
00434   int bx_readout = -1;
00435   std::vector<CSCCorrelatedLCTDigi> all_lcts = getLCTs();
00436   for (std::vector <CSCCorrelatedLCTDigi>::const_iterator plct =
00437          all_lcts.begin(); plct != all_lcts.end(); plct++) {
00438     if (!plct->isValid()) continue;
00439 
00440     int bx = (*plct).getBX();
00441     // Skip LCTs found too early relative to L1Accept.
00442     if (bx <= early_tbins) {
00443       if (infoV > 1) LogDebug("CSCMotherboard")
00444         << " Do not report correlated LCT on key halfstrip "
00445         << plct->getStrip() << " and key wire " << plct->getKeyWG()
00446         << ": found at bx " << bx << ", whereas the earliest allowed bx is "
00447         << early_tbins+1;
00448       continue;
00449     }
00450 
00451     // Skip LCTs found too late relative to L1Accept.
00452     if (bx > late_tbins) {
00453       if (infoV > 1) LogDebug("CSCMotherboard")
00454         << " Do not report correlated LCT on key halfstrip "
00455         << plct->getStrip() << " and key wire " << plct->getKeyWG()
00456         << ": found at bx " << bx << ", whereas the latest allowed bx is "
00457         << late_tbins;
00458       continue;
00459     }
00460 
00461     // For now, take only LCTs in the earliest bx in the read-out window:
00462     // in digi->raw step, LCTs have to be packed into the TMB header, and
00463     // there is room just for two.
00464     if (bx_readout == -1 || bx == bx_readout) {
00465       tmpV.push_back(*plct);
00466       if (bx_readout == -1) bx_readout = bx;
00467     }
00468   }
00469   return tmpV;
00470 }
00471 
00472 // Returns vector of all found correlated LCTs, if any.
00473 std::vector<CSCCorrelatedLCTDigi> CSCMotherboard::getLCTs() {
00474   std::vector<CSCCorrelatedLCTDigi> tmpV;
00475 
00476   bool me11 = (theStation == 1 &&
00477                CSCTriggerNumbering::ringFromTriggerLabels(theStation,
00478                                                           theTrigChamber)==1);
00479 
00480   // Do not report LCTs found in ME1/A if mpc_block_me1/a is set.
00481   for (int bx = 0; bx < MAX_LCT_BINS; bx++) {
00482     if (firstLCT[bx].isValid())
00483       if (!mpc_block_me1a || (!me11 || firstLCT[bx].getStrip() <= 127))
00484         tmpV.push_back(firstLCT[bx]);
00485     if (secondLCT[bx].isValid())
00486       if (!mpc_block_me1a || (!me11 || secondLCT[bx].getStrip() <= 127))
00487         tmpV.push_back(secondLCT[bx]);
00488   }
00489   return tmpV;
00490 }
00491 
00492 void CSCMotherboard::correlateLCTs(CSCALCTDigi bestALCT,
00493                                    CSCALCTDigi secondALCT,
00494                                    CSCCLCTDigi bestCLCT,
00495                                    CSCCLCTDigi secondCLCT) {
00496 
00497   bool anodeBestValid     = bestALCT.isValid();
00498   bool anodeSecondValid   = secondALCT.isValid();
00499   bool cathodeBestValid   = bestCLCT.isValid();
00500   bool cathodeSecondValid = secondCLCT.isValid();
00501 
00502   if (anodeBestValid && !anodeSecondValid)     secondALCT = bestALCT;
00503   if (!anodeBestValid && anodeSecondValid)     bestALCT   = secondALCT;
00504   if (cathodeBestValid && !cathodeSecondValid) secondCLCT = bestCLCT;
00505   if (!cathodeBestValid && cathodeSecondValid) bestCLCT   = secondCLCT;
00506 
00507   // ALCT-CLCT matching conditions are defined by "trig_enable" configuration
00508   // parameters.
00509   if ((alct_trig_enable  && bestALCT.isValid()) ||
00510       (clct_trig_enable  && bestCLCT.isValid()) ||
00511       (match_trig_enable && bestALCT.isValid() && bestCLCT.isValid())) {
00512     CSCCorrelatedLCTDigi lct = constructLCTs(bestALCT, bestCLCT);
00513     int bx = lct.getBX();
00514     if (bx >= 0 && bx < MAX_LCT_BINS) {
00515       firstLCT[bx] = lct;
00516       firstLCT[bx].setTrknmb(1);
00517     }
00518     else {
00519       if (infoV > 0) edm::LogWarning("L1CSCTPEmulatorOutOfTimeLCT")
00520         << "+++ Bx of first LCT candidate, " << bx
00521         << ", is not within the allowed range, [0-" << MAX_LCT_BINS-1
00522         << "); skipping it... +++\n";
00523     }
00524   }
00525 
00526   if (((secondALCT != bestALCT) || (secondCLCT != bestCLCT)) &&
00527       ((alct_trig_enable  && secondALCT.isValid()) ||
00528        (clct_trig_enable  && secondCLCT.isValid()) ||
00529        (match_trig_enable && secondALCT.isValid() && secondCLCT.isValid()))) {
00530     CSCCorrelatedLCTDigi lct = constructLCTs(secondALCT, secondCLCT);
00531     int bx = lct.getBX();
00532     if (bx >= 0 && bx < MAX_LCT_BINS) {
00533       secondLCT[bx] = lct;
00534       secondLCT[bx].setTrknmb(2);
00535     }
00536     else {
00537       if (infoV > 0) edm::LogWarning("L1CSCTPEmulatorOutOfTimeLCT")
00538         << "+++ Bx of second LCT candidate, " << bx
00539         << ", is not within the allowed range, [0-" << MAX_LCT_BINS-1
00540         << "); skipping it... +++\n";
00541     }
00542   }
00543 }
00544 
00545 // This method calculates all the TMB words and then passes them to the
00546 // constructor of correlated LCTs.
00547 CSCCorrelatedLCTDigi CSCMotherboard::constructLCTs(const CSCALCTDigi& aLCT,
00548                                                    const CSCCLCTDigi& cLCT) {
00549   // CLCT pattern number
00550   unsigned int pattern = encodePattern(cLCT.getPattern(), cLCT.getStripType());
00551 
00552   // LCT quality number
00553   unsigned int quality = findQuality(aLCT, cLCT);
00554 
00555   // Bunch crossing: get it from cathode LCT if anode LCT is not there.
00556   int bx = aLCT.isValid() ? aLCT.getBX() : cLCT.getBX();
00557 
00558   // construct correlated LCT; temporarily assign track number of 0.
00559   int trknmb = 0;
00560   CSCCorrelatedLCTDigi thisLCT(trknmb, 1, quality, aLCT.getKeyWG(),
00561                                cLCT.getKeyStrip(), pattern, cLCT.getBend(),
00562                                bx, 0, 0, 0, theTrigChamber);
00563   return thisLCT;
00564 }
00565 
00566 // CLCT pattern number: encodes the pattern number itself and
00567 // whether the pattern consists of half-strips or di-strips.
00568 unsigned int CSCMotherboard::encodePattern(const int ptn,
00569                                            const int stripType) {
00570   const int kPatternBitWidth = 4;
00571   unsigned int pattern;
00572 
00573   if (!isTMB07) {
00574     // Cathode pattern number is a kPatternBitWidth-1 bit word.
00575     pattern = (abs(ptn) & ((1<<(kPatternBitWidth-1))-1));
00576 
00577     // The pattern has the MSB (4th bit in the default version) set if it
00578     // consists of half-strips.
00579     if (stripType) {
00580       pattern = pattern | (1<<(kPatternBitWidth-1));
00581     }
00582   }
00583   else {
00584     // In the TMB07 firmware, LCT pattern is just a 4-bit CLCT pattern.
00585     pattern = (abs(ptn) & ((1<<kPatternBitWidth)-1));
00586   }
00587 
00588   return pattern;
00589 }
00590 
00591 // 4-bit LCT quality number.  Definition can be found in
00592 // https://www.phys.ufl.edu/~acosta/tb/tmb_quality.txt.  Made by TMB lookup
00593 // tables and used for MPC sorting.
00594 unsigned int CSCMotherboard::findQuality(const CSCALCTDigi& aLCT,
00595                                          const CSCCLCTDigi& cLCT) {
00596   unsigned int quality = 0;
00597 
00598   if (!isTMB07) {
00599     bool isDistrip = (cLCT.getStripType() == 0);
00600 
00601     if (aLCT.isValid() && !(cLCT.isValid())) {    // no CLCT
00602       if (aLCT.getAccelerator()) {quality =  1;}
00603       else                       {quality =  3;}
00604     }
00605     else if (!(aLCT.isValid()) && cLCT.isValid()) { // no ALCT
00606       if (isDistrip)             {quality =  4;}
00607       else                       {quality =  5;}
00608     }
00609     else if (aLCT.isValid() && cLCT.isValid()) { // both ALCT and CLCT
00610       if (aLCT.getAccelerator()) {quality =  2;} // accelerator muon
00611       else {                                     // collision muon
00612         // CLCT quality is, in fact, the number of layers hit, so subtract 3
00613         // to get quality analogous to ALCT one.
00614         int sumQual = aLCT.getQuality() + (cLCT.getQuality()-3);
00615         if (sumQual < 1 || sumQual > 6) {
00616           if (infoV >= 0) edm::LogWarning("L1CSCTPEmulatorWrongValues")
00617             << "+++ findQuality: sumQual = " << sumQual << "+++ \n";
00618         }
00619         if (isDistrip) { // distrip pattern
00620           if (sumQual == 2)      {quality =  6;}
00621           else if (sumQual == 3) {quality =  7;}
00622           else if (sumQual == 4) {quality =  8;}
00623           else if (sumQual == 5) {quality =  9;}
00624           else if (sumQual == 6) {quality = 10;}
00625         }
00626         else {            // halfstrip pattern
00627           if (sumQual == 2)      {quality = 11;}
00628           else if (sumQual == 3) {quality = 12;}
00629           else if (sumQual == 4) {quality = 13;}
00630           else if (sumQual == 5) {quality = 14;}
00631           else if (sumQual == 6) {quality = 15;}
00632         }
00633       }
00634     }
00635   }
00636 #ifdef OLD
00637   else {
00638     // Temporary definition, used until July 2008.
00639     // First if statement is fictitious, just to help the CSC TF emulator
00640     // handle such cases (one needs to make sure they will be accounted for
00641     // in the new quality definition.
00642     if (!(aLCT.isValid()) || !(cLCT.isValid())) {
00643       if (aLCT.isValid() && !(cLCT.isValid()))      quality = 1; // no CLCT
00644       else if (!(aLCT.isValid()) && cLCT.isValid()) quality = 2; // no ALCT
00645       else quality = 0; // both absent; should never happen.
00646     }
00647     else {
00648       // Sum of ALCT and CLCT quality bits.  CLCT quality is, in fact, the
00649       // number of layers hit, so subtract 3 to put it to the same footing as
00650       // the ALCT quality.
00651       int sumQual = aLCT.getQuality() + (cLCT.getQuality()-3);
00652       if (sumQual < 1 || sumQual > 6) {
00653         if (infoV >= 0) edm::LogWarning("L1CSCTPEmulatorWrongValues")
00654           << "+++ findQuality: Unexpected sumQual = " << sumQual << "+++\n";
00655       }
00656 
00657       // LCT quality is basically the sum of ALCT and CLCT qualities, but split
00658       // in two groups depending on the CLCT pattern id (higher quality for
00659       // straighter patterns).
00660       int offset = 0;
00661       if (cLCT.getPattern() <= 7) offset = 4;
00662       else                        offset = 9;
00663       quality = offset + sumQual;
00664     }
00665   }
00666 #endif
00667   else {
00668     // 2008 definition.
00669     if (!(aLCT.isValid()) || !(cLCT.isValid())) {
00670       if (aLCT.isValid() && !(cLCT.isValid()))      quality = 1; // no CLCT
00671       else if (!(aLCT.isValid()) && cLCT.isValid()) quality = 2; // no ALCT
00672       else quality = 0; // both absent; should never happen.
00673     }
00674     else {
00675       int pattern = cLCT.getPattern();
00676       if (pattern == 1) quality = 3; // layer-trigger in CLCT
00677       else {
00678         // CLCT quality is the number of layers hit minus 3.
00679         // CLCT quality is the number of layers hit.
00680         bool a4 = (aLCT.getQuality() >= 1);
00681         bool c4 = (cLCT.getQuality() >= 4);
00682         //              quality = 4; "reserved for low-quality muons in future"
00683         if      (!a4 && !c4) quality = 5; // marginal anode and cathode
00684         else if ( a4 && !c4) quality = 6; // HQ anode, but marginal cathode
00685         else if (!a4 &&  c4) quality = 7; // HQ cathode, but marginal anode
00686         else if ( a4 &&  c4) {
00687           if (aLCT.getAccelerator()) quality = 8; // HQ muon, but accel ALCT
00688           else {
00689             // quality =  9; "reserved for HQ muons with future patterns
00690             // quality = 10; "reserved for HQ muons with future patterns
00691             if (pattern == 2 || pattern == 3)      quality = 11;
00692             else if (pattern == 4 || pattern == 5) quality = 12;
00693             else if (pattern == 6 || pattern == 7) quality = 13;
00694             else if (pattern == 8 || pattern == 9) quality = 14;
00695             else if (pattern == 10)                quality = 15;
00696             else {
00697               if (infoV >= 0) edm::LogWarning("L1CSCTPEmulatorWrongValues")
00698                 << "+++ findQuality: Unexpected CLCT pattern id = "
00699                 << pattern << "+++\n";
00700             }
00701           }
00702         }
00703       }
00704     }
00705   }
00706   return quality;
00707 }
00708 
00709 void CSCMotherboard::testLCT() {
00710   unsigned int lctPattern, lctQuality;
00711   for (int pattern = 0; pattern < 8; pattern++) {
00712     for (int bend = 0; bend < 2; bend++) {
00713       for (int cfeb = 0; cfeb < 5; cfeb++) {
00714         for (int strip = 0; strip < 32; strip++) {
00715           for (int bx = 0; bx < 7; bx++) {
00716             for (int stripType = 0; stripType < 2; stripType++) {
00717               for (int quality = 3; quality < 7; quality++) {
00718                 CSCCLCTDigi cLCT(1, quality, pattern, stripType, bend,
00719                                  strip, cfeb, bx);
00720                 lctPattern = encodePattern(cLCT.getPattern(),
00721                                            cLCT.getStripType());
00722                 for (int aQuality = 0; aQuality < 4; aQuality++) {
00723                   for (int wireGroup = 0; wireGroup < 120; wireGroup++) {
00724                     for (int abx = 0; abx < 7; abx++) {
00725                       CSCALCTDigi aLCT(1, aQuality, 0, 1, wireGroup, abx);
00726                       lctQuality = findQuality(aLCT, cLCT);
00727                       CSCCorrelatedLCTDigi
00728                         thisLCT(0, 1, lctQuality, aLCT.getKeyWG(),
00729                                 cLCT.getKeyStrip(), lctPattern, cLCT.getBend(),
00730                                 aLCT.getBX());
00731                       if (lctPattern != static_cast<unsigned int>(thisLCT.getPattern()) )
00732                         LogTrace("CSCMotherboard")
00733                           << "pattern mismatch: " << lctPattern
00734                           << " " << thisLCT.getPattern();
00735                       if (bend != thisLCT.getBend()) 
00736                         LogTrace("CSCMotherboard")
00737                           << "bend mismatch: " << bend
00738                           << " " << thisLCT.getBend();
00739                       int key_strip = 32*cfeb + strip;
00740                       if (key_strip != thisLCT.getStrip()) 
00741                         LogTrace("CSCMotherboard")
00742                           << "strip mismatch: " << key_strip
00743                           << " " << thisLCT.getStrip();
00744                       if (wireGroup != thisLCT.getKeyWG()) 
00745                         LogTrace("CSCMotherboard")
00746                           << "wire group mismatch: " << wireGroup
00747                           << " " << thisLCT.getKeyWG();
00748                       if (abx != thisLCT.getBX()) 
00749                         LogTrace("CSCMotherboard")
00750                           << "bx mismatch: " << abx << " " << thisLCT.getBX();
00751                       if (lctQuality != static_cast<unsigned int>(thisLCT.getQuality())) 
00752                         LogTrace("CSCMotherboard")
00753                           << "quality mismatch: " << lctQuality
00754                           << " " << thisLCT.getQuality();
00755                     }
00756                   }
00757                 }
00758               }
00759             }
00760           }
00761         }
00762       }
00763     }
00764   }
00765 }
00766 
00767 void CSCMotherboard::dumpConfigParams() const {
00768   std::ostringstream strm;
00769   strm << "\n";
00770   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
00771   strm << "+                   TMB configuration parameters:                  +\n";
00772   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
00773   strm << " mpc_block_me1a [block/not block triggers which come from ME1/A] = "
00774        << mpc_block_me1a << "\n";
00775   strm << " alct_trig_enable [allow ALCT-only triggers] = "
00776        << alct_trig_enable << "\n";
00777   strm << " clct_trig_enable [allow CLCT-only triggers] = "
00778        << clct_trig_enable << "\n";
00779   strm << " match_trig_enable [allow matched ALCT-CLCT triggers] = "
00780        << match_trig_enable << "\n";
00781   strm << " match_trig_window_size [ALCT-CLCT match window width, in 25 ns] = "
00782        << match_trig_window_size << "\n";
00783   strm << " tmb_l1a_window_size [L1Accept window width, in 25 ns bins] = "
00784        << tmb_l1a_window_size << "\n";
00785   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
00786   LogDebug("CSCMotherboard") << strm.str();
00787 }