CMS 3D CMS Logo

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