CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC2/src/L1Trigger/CSCTriggerPrimitives/src/CSCAnodeLCTProcessor.cc

Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 //
00003 //   Class: CSCAnodeLCTProcessor
00004 //
00005 //   Description: 
00006 //     This is the simulation for the Anode LCT Processor for the Level-1
00007 //     Trigger.  This processor consists of several stages:
00008 //
00009 //       1. Pulse extension of signals coming from wires.
00010 //       2. Pretrigger for each key-wire.
00011 //       3. Pattern detector if a pretrigger is found for the given key-wire.
00012 //       4. Ghost Cancellation Logic (GCL).
00013 //       5. Best track search and promotion.
00014 //       6. Second best track search and promotion.
00015 //
00016 //     The inputs to the ALCT Processor are wire digis.
00017 //     The output is up to two ALCT digi words.
00018 //
00019 //   Author List: Benn Tannenbaum (1999), Jason Mumford (2002), Slava Valuev.
00020 //                Porting from ORCA by S. Valuev (Slava.Valuev@cern.ch),
00021 //                May 2006.
00022 //
00023 //   $Id: CSCAnodeLCTProcessor.cc,v 1.43 2012/12/05 21:14:22 khotilov Exp $
00024 //
00025 //   Modifications: 
00026 //
00027 //-----------------------------------------------------------------------------
00028 
00029 #include <L1Trigger/CSCTriggerPrimitives/src/CSCAnodeLCTProcessor.h>
00030 #include <L1Trigger/CSCCommonTrigger/interface/CSCTriggerGeometry.h>
00031 #include <DataFormats/MuonDetId/interface/CSCTriggerNumbering.h>
00032 
00033 #include <FWCore/MessageLogger/interface/MessageLogger.h>
00034 
00035 #include <set>
00036 
00037 //-----------------
00038 // Static variables
00039 //-----------------
00040 
00041 /* This is the pattern envelope, which is used to define the collision
00042    patterns A and B.
00043    pattern_envelope[0][i]=layer;
00044    pattern_envelope[1+MEposition][i]=key_wire offset. */
00045 const int CSCAnodeLCTProcessor::pattern_envelope[CSCConstants::NUM_ALCT_PATTERNS][NUM_PATTERN_WIRES] = {
00046   //Layer
00047   { 0,  0,  0,
00048         1,  1,
00049             2,
00050             3,  3,
00051             4,  4,  4,
00052             5,  5,  5},
00053 
00054   //Keywire offset for ME1 and ME2
00055   {-2, -1,  0,
00056        -1,  0,
00057             0,
00058             0,  1,
00059             0,  1,  2,
00060             0,  1,  2},
00061 
00062   //Keywire offset for ME3 and ME4
00063   {2,  1,  0,
00064        1,  0,
00065            0,
00066            0, -1,
00067            0, -1, -2,
00068            0, -1, -2}
00069 };
00070 
00071 // time averaging weights for pattern (used for SLHC version)
00072 const int CSCAnodeLCTProcessor::time_weights[NUM_PATTERN_WIRES] =
00073   //Layer
00074   { 0,  1,  1,
00075         1,  2,
00076             2,
00077             2,  1,
00078             2,  1,  0,
00079             1,  1,  0};
00080 
00081 
00082 // These mask the pattern envelope to give the desired accelerator pattern
00083 // and collision patterns A and B.  These masks were meant to be the default
00084 // ones in early 200X, but were never implemented because of limited FPGA
00085 // resources.
00086 const int CSCAnodeLCTProcessor::pattern_mask_slim[CSCConstants::NUM_ALCT_PATTERNS][NUM_PATTERN_WIRES] = {
00087   // Accelerator pattern
00088   {0,  0,  1,
00089        0,  1,
00090            1,
00091            1,  0,
00092            1,  0,  0,
00093            1,  0,  0},
00094 
00095   // Collision pattern A
00096   {0,  1,  0,
00097        1,  1,
00098            1,
00099            1,  0,
00100            0,  1,  0,
00101            0,  1,  0},
00102 
00103   // Collision pattern B
00104   {1,  1,  0,
00105        1,  1,
00106            1,
00107            1,  1,
00108            0,  1,  1,
00109            0,  0,  1}
00110 };
00111 
00112 // Since the test beams in 2003, both collision patterns are "completely
00113 // open".  This is our current default.
00114 const int CSCAnodeLCTProcessor::pattern_mask_open[CSCConstants::NUM_ALCT_PATTERNS][NUM_PATTERN_WIRES] = {
00115   // Accelerator pattern
00116   {0,  0,  1,
00117        0,  1,
00118            1,
00119            1,  0,
00120            1,  0,  0,
00121            1,  0,  0},
00122 
00123   // Collision pattern A
00124   {1,  1,  1,
00125        1,  1,
00126            1,
00127            1,  1,
00128            1,  1,  1,
00129            1,  1,  1},
00130 
00131   // Collision pattern B
00132   {1,  1,  1,
00133        1,  1,
00134            1,
00135            1,  1,
00136            1,  1,  1,
00137            1,  1,  1}
00138 };
00139 
00140 // Special option for narrow pattern for ring 1 stations
00141 const int CSCAnodeLCTProcessor::pattern_mask_r1[CSCConstants::NUM_ALCT_PATTERNS][NUM_PATTERN_WIRES] = {
00142   // Accelerator pattern
00143   {0,  0,  1,
00144        0,  1,
00145            1,
00146            1,  0,
00147            1,  0,  0,
00148            1,  0,  0},
00149 
00150   // Collision pattern A
00151   {0,  1,  1,
00152        1,  1,
00153            1,
00154            1,  0,
00155            1,  1,  0,
00156            1,  1,  0},
00157 
00158   // Collision pattern B
00159   {0,  1,  1,
00160        1,  1,
00161            1,
00162            1,  0,
00163            1,  1,  0,
00164            1,  1,  0}
00165 };
00166 
00167 
00168 
00169 // Default values of configuration parameters.
00170 const unsigned int CSCAnodeLCTProcessor::def_fifo_tbins   = 16;
00171 const unsigned int CSCAnodeLCTProcessor::def_fifo_pretrig = 10;
00172 const unsigned int CSCAnodeLCTProcessor::def_drift_delay  =  2;
00173 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_pretrig =  2;
00174 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_pattern =  4;
00175 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_accel_pretrig =  2;
00176 const unsigned int CSCAnodeLCTProcessor::def_nplanes_hit_accel_pattern =  4;
00177 const unsigned int CSCAnodeLCTProcessor::def_trig_mode        =  2;  // 3?
00178 const unsigned int CSCAnodeLCTProcessor::def_accel_mode       =  0;  // 1?
00179 const unsigned int CSCAnodeLCTProcessor::def_l1a_window_width =  7;  // 5?
00180 
00181 //----------------
00182 // Constructors --
00183 //----------------
00184 
00185 CSCAnodeLCTProcessor::CSCAnodeLCTProcessor(unsigned endcap, unsigned station,
00186                                            unsigned sector, unsigned subsector,
00187                                            unsigned chamber,
00188                                            const edm::ParameterSet& conf,
00189                                            const edm::ParameterSet& comm) : 
00190                      theEndcap(endcap), theStation(station), theSector(sector),
00191                      theSubsector(subsector), theTrigChamber(chamber) {
00192   static bool config_dumped = false;
00193 
00194   // ALCT configuration parameters.
00195   fifo_tbins   = conf.getParameter<unsigned int>("alctFifoTbins");
00196   fifo_pretrig = conf.getParameter<unsigned int>("alctFifoPretrig");
00197   drift_delay  = conf.getParameter<unsigned int>("alctDriftDelay");
00198   nplanes_hit_pretrig =
00199     conf.getParameter<unsigned int>("alctNplanesHitPretrig");
00200   nplanes_hit_pattern =
00201     conf.getParameter<unsigned int>("alctNplanesHitPattern");
00202   nplanes_hit_accel_pretrig =
00203     conf.getParameter<unsigned int>("alctNplanesHitAccelPretrig");
00204   nplanes_hit_accel_pattern =
00205     conf.getParameter<unsigned int>("alctNplanesHitAccelPattern");
00206   trig_mode        = conf.getParameter<unsigned int>("alctTrigMode");
00207   accel_mode       = conf.getParameter<unsigned int>("alctAccelMode");
00208   l1a_window_width = conf.getParameter<unsigned int>("alctL1aWindowWidth");
00209 
00210   hit_persist  = conf.getUntrackedParameter<unsigned int>("alctHitPersist", 6);
00211 
00212   // Verbosity level, set to 0 (no print) by default.
00213   infoV        = conf.getUntrackedParameter<int>("verbosity", 0);
00214 
00215   // Other parameters.
00216   // Use open pattern instead of more restrictive (slim) ones.
00217   isMTCC       = comm.getParameter<bool>("isMTCC");
00218   // Use TMB07 flag for DAQ-2006 firmware version (implemented in late 2007).
00219   isTMB07      = comm.getParameter<bool>("isTMB07");
00220 
00221   // Flag for SLHC studies
00222   isSLHC       = comm.getUntrackedParameter<bool>("isSLHC", false);
00223 
00224   // special configuration parameters for ME11 treatment
00225   disableME1a = comm.getUntrackedParameter<bool>("disableME1a", false);
00226 
00227   // separate handle for early time bins
00228   early_tbins = conf.getUntrackedParameter<int>("alctEarlyTbins",-1);
00229   int fpga_latency = 6;
00230   if (early_tbins<0) early_tbins  = fifo_pretrig - fpga_latency;
00231 
00232   // delta BX time depth for ghostCancellationLogic
00233   ghost_cancellation_bx_depth = conf.getUntrackedParameter<int>("alctGhostCancellationBxDepth", 4);
00234 
00235   // whether to consider ALCT candidates' qualities while doing ghostCancellationLogic on +-1 wire groups
00236   ghost_cancellation_side_quality = conf.getUntrackedParameter<bool>("alctGhostCancellationSideQuality", false);
00237 
00238   // deadtime clocks after pretrigger (extra in addition to drift_delay)
00239   pretrig_extra_deadtime = conf.getUntrackedParameter<unsigned int>("alctPretrigDeadtime", 4);
00240 
00241   // whether to use narrow pattern mask for the rings close to the beam
00242   narrow_mask_r1 = conf.getUntrackedParameter<bool>("alctNarrowMaskForR1", false);
00243 
00244   // Check and print configuration parameters.
00245   checkConfigParameters();
00246   if ((infoV > 0 || isSLHC) && !config_dumped) {
00247     //std::cout<<"**** ALCT constructor parameters dump ****"<<std::endl;
00248     dumpConfigParams();
00249     config_dumped = true;
00250     if (isSLHC) std::cout<<"disableME1a = "<<disableME1a<<std::endl;
00251   }
00252 
00253   numWireGroups = 0;  // Will be set later.
00254   MESelection   = (theStation < 3) ? 0 : 1;
00255 
00256   theRing = CSCTriggerNumbering::ringFromTriggerLabels(theStation, theTrigChamber);
00257 
00258   theChamber = CSCTriggerNumbering::chamberFromTriggerLabels(theSector, theSubsector,
00259                                                              theStation, theTrigChamber);
00260 
00261   // trigger numbering doesn't distinguish between ME1a and ME1b chambers:
00262   isME11 = (theStation == 1 && theRing == 1);
00263 
00264   // whether to calculate bx as corrected_bx instead of pretrigger one
00265   use_corrected_bx = false;
00266   if (isSLHC && isME11) {
00267     use_corrected_bx = conf.getUntrackedParameter<bool>("alctUseCorrectedBx", false);
00268   }
00269 
00270   //if (theStation==1 && theRing==2) infoV = 3;
00271 
00272   // Load appropriate pattern mask.
00273   loadPatternMask();
00274 }
00275 
00276 CSCAnodeLCTProcessor::CSCAnodeLCTProcessor() :
00277                        theEndcap(1), theStation(1), theSector(1),
00278                      theSubsector(1), theTrigChamber(1) {
00279   // Used for debugging. -JM
00280   static bool config_dumped = false;
00281 
00282   // ALCT parameters.
00283   setDefaultConfigParameters();
00284   infoV = 2;
00285   isMTCC  = false;
00286   isTMB07 = true;
00287 
00288   isSLHC = false;
00289   disableME1a = false;
00290 
00291   early_tbins = 4;
00292 
00293   // Check and print configuration parameters.
00294   checkConfigParameters();
00295   if (!config_dumped) {
00296     //std::cout<<"**** ALCT default constructor parameters dump ****"<<std::endl;
00297     dumpConfigParams();
00298     config_dumped = true;
00299   }
00300 
00301   numWireGroups = CSCConstants::MAX_NUM_WIRES;
00302   MESelection   = (theStation < 3) ? 0 : 1;
00303 
00304   theRing = CSCTriggerNumbering::ringFromTriggerLabels(theStation, theTrigChamber);
00305   theChamber = CSCTriggerNumbering::chamberFromTriggerLabels(theSector, theSubsector,
00306                                                              theStation, theTrigChamber);
00307   isME11 = (theStation == 1 && theRing == 1);
00308 
00309   // Load pattern mask.
00310   loadPatternMask();
00311 }
00312 
00313 
00314 void CSCAnodeLCTProcessor::loadPatternMask() {
00315   // Load appropriate pattern mask.
00316   for (int i_patt = 0; i_patt < CSCConstants::NUM_ALCT_PATTERNS; i_patt++) {
00317     for (int i_wire = 0; i_wire < NUM_PATTERN_WIRES; i_wire++) {
00318       if (isMTCC || isTMB07) {
00319         pattern_mask[i_patt][i_wire] = pattern_mask_open[i_patt][i_wire];
00320         if (narrow_mask_r1 && (theRing == 1 || theRing == 4))
00321           pattern_mask[i_patt][i_wire] = pattern_mask_r1[i_patt][i_wire];
00322       }
00323       else {
00324         pattern_mask[i_patt][i_wire] = pattern_mask_slim[i_patt][i_wire];
00325       }
00326     }
00327   }
00328 }
00329 
00330 
00331 void CSCAnodeLCTProcessor::setDefaultConfigParameters() {
00332   // Set default values for configuration parameters.
00333   fifo_tbins   = def_fifo_tbins;
00334   fifo_pretrig = def_fifo_pretrig;
00335   drift_delay  = def_drift_delay;
00336   nplanes_hit_pretrig = def_nplanes_hit_pretrig;
00337   nplanes_hit_pattern = def_nplanes_hit_pattern;
00338   nplanes_hit_accel_pretrig = def_nplanes_hit_accel_pretrig;
00339   nplanes_hit_accel_pattern = def_nplanes_hit_accel_pattern;
00340   trig_mode        = def_trig_mode;
00341   accel_mode       = def_accel_mode;
00342   l1a_window_width = def_l1a_window_width;
00343 }
00344 
00345 // Set configuration parameters obtained via EventSetup mechanism.
00346 void CSCAnodeLCTProcessor::setConfigParameters(const CSCDBL1TPParameters* conf) {
00347   static bool config_dumped = false;
00348 
00349   fifo_tbins   = conf->alctFifoTbins();
00350   fifo_pretrig = conf->alctFifoPretrig();
00351   drift_delay  = conf->alctDriftDelay();
00352   nplanes_hit_pretrig = conf->alctNplanesHitPretrig();
00353   nplanes_hit_pattern = conf->alctNplanesHitPattern();
00354   nplanes_hit_accel_pretrig = conf->alctNplanesHitAccelPretrig();
00355   nplanes_hit_accel_pattern = conf->alctNplanesHitAccelPattern();
00356   trig_mode        = conf->alctTrigMode();
00357   accel_mode       = conf->alctAccelMode();
00358   l1a_window_width = conf->alctL1aWindowWidth();
00359 
00360   // Check and print configuration parameters.
00361   checkConfigParameters();
00362   if (!config_dumped) {
00363     //std::cout<<"**** ALCT setConfigParam parameters dump ****"<<std::endl;
00364     dumpConfigParams();
00365     config_dumped = true;
00366   }
00367 }
00368 
00369 void CSCAnodeLCTProcessor::checkConfigParameters() {
00370   // Make sure that the parameter values are within the allowed range.
00371 
00372   // Max expected values.
00373   static const unsigned int max_fifo_tbins   = 1 << 5;
00374   static const unsigned int max_fifo_pretrig = 1 << 5;
00375   static const unsigned int max_drift_delay  = 1 << 2;
00376   static const unsigned int max_nplanes_hit_pretrig = 1 << 3;
00377   static const unsigned int max_nplanes_hit_pattern = 1 << 3;
00378   static const unsigned int max_nplanes_hit_accel_pretrig = 1 << 3;
00379   static const unsigned int max_nplanes_hit_accel_pattern = 1 << 3;
00380   static const unsigned int max_trig_mode        = 1 << 2;
00381   static const unsigned int max_accel_mode       = 1 << 2;
00382   static const unsigned int max_l1a_window_width = MAX_ALCT_BINS; // 4 bits
00383 
00384   // Checks.
00385   if (fifo_tbins >= max_fifo_tbins) {
00386     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00387       << "+++ Value of fifo_tbins, " << fifo_tbins
00388       << ", exceeds max allowed, " << max_fifo_tbins-1 << " +++\n"
00389       << "+++ Try to proceed with the default value, fifo_tbins="
00390       << def_fifo_tbins << " +++\n";
00391     fifo_tbins = def_fifo_tbins;
00392   }
00393   if (fifo_pretrig >= max_fifo_pretrig) {
00394     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00395       << "+++ Value of fifo_pretrig, " << fifo_pretrig
00396       << ", exceeds max allowed, " << max_fifo_pretrig-1 << " +++\n"
00397       << "+++ Try to proceed with the default value, fifo_pretrig="
00398       << def_fifo_pretrig << " +++\n";
00399     fifo_pretrig = def_fifo_pretrig;
00400   }
00401   if (drift_delay >= max_drift_delay) {
00402     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00403       << "+++ Value of drift_delay, " << drift_delay
00404       << ", exceeds max allowed, " << max_drift_delay-1 << " +++\n"
00405       << "+++ Try to proceed with the default value, drift_delay="
00406       << def_drift_delay << " +++\n";
00407     drift_delay = def_drift_delay;
00408   }
00409   if (nplanes_hit_pretrig >= max_nplanes_hit_pretrig) {
00410     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00411       << "+++ Value of nplanes_hit_pretrig, " << nplanes_hit_pretrig
00412       << ", exceeds max allowed, " << max_nplanes_hit_pretrig-1 << " +++\n"
00413       << "+++ Try to proceed with the default value, nplanes_hit_pretrig="
00414       << nplanes_hit_pretrig << " +++\n";
00415     nplanes_hit_pretrig = def_nplanes_hit_pretrig;
00416   }
00417   if (nplanes_hit_pattern >= max_nplanes_hit_pattern) {
00418     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00419       << "+++ Value of nplanes_hit_pattern, " << nplanes_hit_pattern
00420       << ", exceeds max allowed, " << max_nplanes_hit_pattern-1 << " +++\n"
00421       << "+++ Try to proceed with the default value, nplanes_hit_pattern="
00422       << nplanes_hit_pattern << " +++\n";
00423     nplanes_hit_pattern = def_nplanes_hit_pattern;
00424   }
00425   if (nplanes_hit_accel_pretrig >= max_nplanes_hit_accel_pretrig) {
00426     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00427       << "+++ Value of nplanes_hit_accel_pretrig, "
00428       << nplanes_hit_accel_pretrig << ", exceeds max allowed, "
00429       << max_nplanes_hit_accel_pretrig-1 << " +++\n"
00430       << "+++ Try to proceed with the default value, "
00431       << "nplanes_hit_accel_pretrig=" << nplanes_hit_accel_pretrig << " +++\n";
00432     nplanes_hit_accel_pretrig = def_nplanes_hit_accel_pretrig;
00433   }
00434   if (nplanes_hit_accel_pattern >= max_nplanes_hit_accel_pattern) {
00435     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00436       << "+++ Value of nplanes_hit_accel_pattern, "
00437       << nplanes_hit_accel_pattern << ", exceeds max allowed, "
00438       << max_nplanes_hit_accel_pattern-1 << " +++\n"
00439       << "+++ Try to proceed with the default value, "
00440       << "nplanes_hit_accel_pattern=" << nplanes_hit_accel_pattern << " +++\n";
00441     nplanes_hit_accel_pattern = def_nplanes_hit_accel_pattern;
00442   }
00443   if (trig_mode >= max_trig_mode) {
00444     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00445       << "+++ Value of trig_mode, " << trig_mode
00446       << ", exceeds max allowed, " << max_trig_mode-1 << " +++\n"
00447       << "+++ Try to proceed with the default value, trig_mode="
00448       << trig_mode << " +++\n";
00449     trig_mode = def_trig_mode;
00450   }
00451   if (accel_mode >= max_accel_mode) {
00452     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00453       << "+++ Value of accel_mode, " << accel_mode
00454       << ", exceeds max allowed, " << max_accel_mode-1 << " +++\n"
00455       << "+++ Try to proceed with the default value, accel_mode="
00456       << accel_mode << " +++\n";
00457     accel_mode = def_accel_mode;
00458   }
00459   if (l1a_window_width >= max_l1a_window_width) {
00460     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorConfigError")
00461       << "+++ Value of l1a_window_width, " << l1a_window_width
00462       << ", exceeds max allowed, " << max_l1a_window_width-1 << " +++\n"
00463       << "+++ Try to proceed with the default value, l1a_window_width="
00464       << l1a_window_width << " +++\n";
00465     l1a_window_width = def_l1a_window_width;
00466   }
00467 }
00468 
00469 void CSCAnodeLCTProcessor::clear() {
00470   for (int bx = 0; bx < MAX_ALCT_BINS; bx++) {
00471     bestALCT[bx].clear();
00472     secondALCT[bx].clear();
00473   }
00474 }
00475 
00476 void CSCAnodeLCTProcessor::clear(const int wire, const int pattern) {
00477   /* Clear the data off of selected pattern */
00478   if (pattern == 0) quality[wire][0] = -999;
00479   else {
00480     quality[wire][1] = -999;
00481     quality[wire][2] = -999;
00482   }
00483 }
00484 
00485 std::vector<CSCALCTDigi>
00486 CSCAnodeLCTProcessor::run(const CSCWireDigiCollection* wiredc) {
00487   // This is the main routine for normal running.  It gets wire times
00488   // from the wire digis and then passes them on to another run() function.
00489 
00490   // clear(); // redundant; called by L1MuCSCMotherboard.
00491 
00492   static bool config_dumped = false;
00493   if ((infoV > 0 || isSLHC) && !config_dumped) {
00494     //std::cout<<"**** ALCT run parameters dump ****"<<std::endl;
00495     dumpConfigParams();
00496     config_dumped = true;
00497   }
00498 
00499 
00500   // Get the number of wire groups for the given chamber.  Do it only once
00501   // per chamber.
00502   if (numWireGroups == 0) {
00503     CSCTriggerGeomManager* theGeom = CSCTriggerGeometry::get();
00504     CSCChamber* chamber = theGeom->chamber(theEndcap, theStation, theSector,
00505                                            theSubsector, theTrigChamber);
00506     if (chamber) {
00507       numWireGroups = chamber->layer(1)->geometry()->numberOfWireGroups();
00508       if (numWireGroups > CSCConstants::MAX_NUM_WIRES) {
00509         if (infoV >= 0) edm::LogError("L1CSCTPEmulatorSetupError")
00510           << "+++ Number of wire groups, " << numWireGroups
00511           << " found in ME" << ((theEndcap == 1) ? "+" : "-")
00512           << theStation << "/" << theRing << "/" << theChamber
00513           << " (sector " << theSector << " subsector " << theSubsector
00514           << " trig id. " << theTrigChamber << ")"
00515           << " exceeds max expected, " << CSCConstants::MAX_NUM_WIRES
00516           << " +++\n" 
00517           << "+++ CSC geometry looks garbled; no emulation possible +++\n";
00518         numWireGroups = -1;
00519       }
00520     }
00521     else {
00522       if (infoV >= 0) edm::LogError("L1CSCTPEmulatorSetupError")
00523         << "+++ ME" << ((theEndcap == 1) ? "+" : "-")
00524         << theStation << "/" << theRing << "/" << theChamber
00525         << " (sector " << theSector << " subsector " << theSubsector
00526         << " trig id. " << theTrigChamber << ")"
00527         << " is not defined in current geometry! +++\n"
00528         << "+++ CSC geometry looks garbled; no emulation possible +++\n";
00529       numWireGroups = -1;
00530     }
00531   }
00532 
00533   if (numWireGroups < 0) {
00534     if (infoV >= 0) edm::LogError("L1CSCTPEmulatorSetupError")
00535       << "+++ ME" << ((theEndcap == 1) ? "+" : "-")
00536       << theStation << "/" << theRing << "/" << theChamber
00537       << " (sector " << theSector << " subsector " << theSubsector
00538       << " trig id. " << theTrigChamber << "):"
00539       << " numWireGroups = " << numWireGroups
00540       << "; ALCT emulation skipped! +++";
00541     std::vector<CSCALCTDigi> emptyV;
00542     return emptyV;
00543   }
00544 
00545   // Get wire digis in this chamber from wire digi collection.
00546   bool noDigis = getDigis(wiredc);
00547 
00548   if (!noDigis) {
00549     // First get wire times from the wire digis.
00550     std::vector<int>
00551       wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIRES];
00552     readWireDigis(wire);
00553 
00554     // Pass an array of wire times on to another run() doing the LCT search.
00555     // If the number of layers containing digis is smaller than that
00556     // required to trigger, quit right away.
00557     const unsigned int min_layers =
00558       (nplanes_hit_accel_pattern == 0) ? 
00559         nplanes_hit_pattern :
00560         ((nplanes_hit_pattern <= nplanes_hit_accel_pattern) ?
00561            nplanes_hit_pattern :
00562            nplanes_hit_accel_pattern
00563         );
00564 
00565     unsigned int layersHit = 0;
00566     for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
00567       for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
00568         if (!wire[i_layer][i_wire].empty()) {layersHit++; break;}
00569       }
00570     }
00571     if (layersHit >= min_layers) run(wire);
00572   }
00573 
00574   // Return vector of all found ALCTs.
00575   std::vector<CSCALCTDigi> tmpV = getALCTs();
00576   return tmpV;
00577 }
00578 
00579 void CSCAnodeLCTProcessor::run(const std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIRES]) {
00580   // This version of the run() function can either be called in a standalone
00581   // test, being passed the time array, or called by the run() function above.
00582   // It gets wire times from an input array and then loops over the keywires.
00583   // All found LCT candidates are sorted and the best two are retained.
00584 
00585   bool trigger = false;
00586 
00587   // Check if there are any in-time hits and do the pulse extension.
00588   bool chamber_empty = pulseExtension(wire);
00589 
00590   // Only do the rest of the processing if chamber is not empty.
00591   // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
00592   // not have a full set of hits to start pattern search anyway.
00593   unsigned int stop_bx = fifo_tbins - drift_delay;
00594   if (!chamber_empty) {
00595     for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
00596       unsigned int start_bx = 0;
00597       // Allow for more than one pass over the hits in the time window.
00598       while (start_bx < stop_bx) {
00599         if (preTrigger(i_wire, start_bx)) {
00600           if (infoV > 2) showPatterns(i_wire);
00601           if (patternDetection(i_wire)) {
00602             trigger = true;
00603             break;
00604           }
00605           else {
00606             // Assume that the earliest time when another pre-trigger can
00607             // occur in case pattern detection failed is bx_pretrigger+4:
00608             // this seems to match the data.
00609             start_bx = first_bx[i_wire] + drift_delay + pretrig_extra_deadtime;
00610           }
00611         }
00612         else {
00613           break;
00614         }
00615       }
00616     }
00617   }
00618 
00619   // Do the rest only if there is at least one trigger candidate.
00620   if (trigger) {
00621     if (isSLHC) ghostCancellationLogicSLHC();
00622     else ghostCancellationLogic();
00623     lctSearch();
00624   }
00625 }
00626 
00627 bool CSCAnodeLCTProcessor::getDigis(const CSCWireDigiCollection* wiredc) {
00628   // Routine for getting digis and filling digiV vector.
00629   bool noDigis = true;
00630 
00631   // Loop over layers and save wire digis on each one into digiV[layer].
00632   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
00633     digiV[i_layer].clear();
00634 
00635     CSCDetId detid(theEndcap, theStation, theRing, theChamber, i_layer+1);
00636     getDigis(wiredc, detid);
00637 
00638     // If this is ME1/1, fetch digis in corresponding ME1/A (ring=4) as well.
00639     if (isME11 && !disableME1a) {
00640       CSCDetId detid_me1a(theEndcap, theStation, 4, theChamber, i_layer+1);
00641       getDigis(wiredc, detid_me1a);
00642     }
00643 
00644     if (!digiV[i_layer].empty()) {
00645       noDigis = false;
00646       if (infoV > 1) {
00647         LogTrace("CSCAnodeLCTProcessor")
00648           << "found " << digiV[i_layer].size()
00649           << " wire digi(s) in layer " << i_layer << " of ME"
00650           << ((theEndcap == 1) ? "+" : "-") << theStation << "/" << theRing
00651           << "/" << theChamber << " (trig. sector " << theSector
00652           << " subsector " << theSubsector << " id " << theTrigChamber << ")";
00653         for (std::vector<CSCWireDigi>::iterator pld = digiV[i_layer].begin();
00654              pld != digiV[i_layer].end(); pld++) {
00655           LogTrace("CSCAnodeLCTProcessor") << "   " << (*pld);
00656         }
00657       }
00658     }
00659   }
00660 
00661   return noDigis;
00662 }
00663 
00664 void CSCAnodeLCTProcessor::getDigis(const CSCWireDigiCollection* wiredc,
00665                                     const CSCDetId& id) {
00666   const CSCWireDigiCollection::Range rwired = wiredc->get(id);
00667   for (CSCWireDigiCollection::const_iterator digiIt = rwired.first;
00668        digiIt != rwired.second; ++digiIt) {
00669     digiV[id.layer()-1].push_back(*digiIt);
00670   }
00671 }
00672 
00673 void CSCAnodeLCTProcessor::readWireDigis(std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIRES]) {
00674   /* Gets wire times from the wire digis and fills wire[][] vector */
00675 
00676   // Loop over all 6 layers.
00677   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
00678     // Loop over all digis in the layer and find the wireGroup and bx
00679     // time for each.
00680     for (std::vector<CSCWireDigi>::iterator pld = digiV[i_layer].begin();
00681          pld != digiV[i_layer].end(); pld++) {
00682       int i_wire  = pld->getWireGroup()-1;
00683       std::vector<int> bx_times = pld->getTimeBinsOn();
00684 
00685       // Check that the wires and times are appropriate.
00686       if (i_wire < 0 || i_wire >= numWireGroups) {
00687         if (infoV >= 0) edm::LogWarning("L1CSCTPEmulatorWrongInput")
00688           << "+++ Found wire digi with wrong wire number = " << i_wire
00689           << " (max wires = " << numWireGroups << "); skipping it... +++\n";
00690         continue;
00691       }
00692       // Accept digis in expected time window.  Total number of time
00693       // bins in DAQ readout is given by fifo_tbins, which thus
00694       // determines the maximum length of time interval.  Anode raw
00695       // hits in DAQ readout start (fifo_pretrig - 6) clocks before
00696       // L1Accept.  If times earlier than L1Accept were recorded, we
00697       // use them since they can modify the ALCTs found later, via
00698       // ghost-cancellation logic.
00699       int last_time = -999;
00700       if (bx_times.size() == fifo_tbins) {
00701         wire[i_layer][i_wire].push_back(0);        
00702         wire[i_layer][i_wire].push_back(6);
00703       }
00704       else {
00705         for (unsigned int i = 0; i < bx_times.size(); i++) {
00706           // Find rising edge change
00707           if (i > 0 && bx_times[i] == (bx_times[i-1]+1)) continue;
00708           if (bx_times[i] < static_cast<int>(fifo_tbins)) {
00709             if (infoV > 2) LogTrace("CSCAnodeLCTProcessor")
00710                              << "Digi on layer " << i_layer << " wire " << i_wire
00711                              << " at time " << bx_times[i];
00712 
00713             // Finally save times of hit wires.  One shot module will
00714             // not restart if a new pulse comes before the expiration
00715             // of the 6-bx period.
00716             if (last_time < 0 || ((bx_times[i]-last_time) >= 6) ) {
00717               wire[i_layer][i_wire].push_back(bx_times[i]);
00718               last_time = bx_times[i];
00719             }
00720           }
00721           else {
00722             if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
00723                              << "+++ Skipping wire digi: wire = " << i_wire
00724                              << " layer = " << i_layer << ", bx = " << bx_times[i] << " +++";
00725           }
00726         }
00727       }
00728     }
00729   }
00730 }
00731 
00732 bool CSCAnodeLCTProcessor::pulseExtension(const std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIRES]){
00733   /* A pulse array will be used as a bit representation of hit times.
00734      For example: if a keywire has a bx_time of 3, then 1 shifted
00735      left 3 will be bit pattern 0000000000001000.  Bits are then added to
00736      signify the duration of a signal (hit_persist, formerly bx_width).  So
00737      for the pulse with a hit_persist of 6 will look like 0000000111111000. */
00738 
00739   bool chamber_empty = true;
00740   int i_wire, i_layer, digi_num;
00741   static unsigned int bits_in_pulse = 8*sizeof(pulse[0][0]);
00742 
00743   for (i_wire = 0; i_wire < numWireGroups; i_wire++) {
00744     for (i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
00745       pulse[i_layer][i_wire] = 0;
00746     }
00747     first_bx[i_wire] = -999;
00748     first_bx_corrected[i_wire] = -999;
00749     for (int j = 0; j < 3; j++) quality[i_wire][j] = -999;
00750   }
00751 
00752   for (i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++){
00753     digi_num = 0;
00754     for (i_wire = 0; i_wire < numWireGroups; i_wire++) {
00755       if (wire[i_layer][i_wire].size() > 0) {
00756         std::vector<int> bx_times = wire[i_layer][i_wire];
00757         for (unsigned int i = 0; i < bx_times.size(); i++) {
00758           // Check that min and max times are within the allowed range.
00759           if (bx_times[i] < 0 || bx_times[i] + hit_persist >= bits_in_pulse) {
00760             if (infoV > 0) edm::LogWarning("L1CSCTPEmulatorOutOfTimeDigi")
00761               << "+++ BX time of wire digi (wire = " << i_wire
00762               << " layer = " << i_layer << ") bx = " << bx_times[i]
00763               << " is not within the range (0-" << bits_in_pulse
00764               << "] allowed for pulse extension.  Skip this digi! +++\n";
00765             continue;
00766           }
00767 
00768           // Found at least one in-time digi; set chamber_empty to false
00769           if (chamber_empty) chamber_empty = false;
00770 
00771           // make the pulse
00772           for (unsigned int bx = bx_times[i];
00773                bx < (bx_times[i] + hit_persist); bx++)
00774           pulse[i_layer][i_wire] = pulse[i_layer][i_wire] | (1 << bx);
00775 
00776           // Debug information.
00777           if (infoV > 1) {
00778             LogTrace("CSCAnodeLCTProcessor")
00779               << "Wire digi: layer " << i_layer
00780               << " digi #" << ++digi_num << " wire group " << i_wire
00781               << " time " << bx_times[i];
00782             if (infoV > 2) {
00783               std::ostringstream strstrm;
00784               for (int i = 1; i <= 32; i++) {
00785                 strstrm << ((pulse[i_layer][i_wire]>>(32-i)) & 1);
00786               }
00787               LogTrace("CSCAnodeLCTProcessor") << "  Pulse: " << strstrm.str();
00788             }
00789           }
00790         }
00791       }
00792     }
00793   }
00794 
00795   if (infoV > 1 && !chamber_empty) {
00796     dumpDigis(wire);
00797   }
00798 
00799   return chamber_empty;
00800 }
00801 
00802 bool CSCAnodeLCTProcessor::preTrigger(const int key_wire, const int start_bx) {
00803   /* Check that there are nplanes_hit_pretrig or more layers hit in collision
00804      or accelerator patterns for a particular key_wire.  If so, return
00805      true and the PatternDetection process will start. */
00806 
00807   unsigned int layers_hit;
00808   bool hit_layer[CSCConstants::NUM_LAYERS];
00809   int this_layer, this_wire;
00810   // If nplanes_hit_accel_pretrig is 0, the firmware uses the value
00811   // of nplanes_hit_pretrig instead.
00812   const unsigned int nplanes_hit_pretrig_acc =
00813     (nplanes_hit_accel_pretrig != 0) ? nplanes_hit_accel_pretrig :
00814     nplanes_hit_pretrig;
00815   const unsigned int pretrig_thresh[CSCConstants::NUM_ALCT_PATTERNS] = {
00816     nplanes_hit_pretrig_acc, nplanes_hit_pretrig, nplanes_hit_pretrig
00817   };
00818 
00819   // Loop over bx times, accelerator and collision patterns to 
00820   // look for pretrigger.
00821   // Stop drift_delay bx's short of fifo_tbins since at later bx's we will
00822   // not have a full set of hits to start pattern search anyway.
00823   unsigned int stop_bx = fifo_tbins - drift_delay;
00824   for (unsigned int bx_time = start_bx; bx_time < stop_bx; bx_time++) {
00825     for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++) {
00826       for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++)
00827         hit_layer[i_layer] = false;
00828       layers_hit = 0;
00829 
00830       for (int i_wire = 0; i_wire < NUM_PATTERN_WIRES; i_wire++){
00831         if (pattern_mask[i_pattern][i_wire] != 0){
00832           this_layer = pattern_envelope[0][i_wire];
00833           this_wire  = pattern_envelope[1+MESelection][i_wire]+key_wire;
00834           if ((this_wire >= 0) && (this_wire < numWireGroups)){
00835             // Perform bit operation to see if pulse is 1 at a certain bx_time.
00836             if (((pulse[this_layer][this_wire] >> bx_time) & 1) == 1) {
00837               // Store number of layers hit.
00838               if (hit_layer[this_layer] == false){
00839                 hit_layer[this_layer] = true;
00840                 layers_hit++;
00841               }
00842 
00843               // See if number of layers hit is greater than or equal to
00844               // pretrig_thresh.
00845               if (layers_hit >= pretrig_thresh[i_pattern]) {
00846                 first_bx[key_wire] = bx_time;
00847                 if (infoV > 1) {
00848                   LogTrace("CSCAnodeLCTProcessor")
00849                     << "Pretrigger was satisfied for wire: " << key_wire
00850                     << " pattern: " << i_pattern
00851                     << " bx_time: " << bx_time;
00852                 }
00853                 return true;
00854               }
00855             }
00856           }
00857         }
00858       }
00859     }
00860   }
00861   // If the pretrigger was never satisfied, then return false.
00862   return false;
00863 }
00864 
00865 bool CSCAnodeLCTProcessor::patternDetection(const int key_wire) {
00866   /* See if there is a pattern that satisfies nplanes_hit_pattern number of
00867      layers hit for either the accelerator or collision patterns.  Use
00868      the pattern with the best quality. */
00869 
00870   bool trigger = false;
00871   bool hit_layer[CSCConstants::NUM_LAYERS];
00872   unsigned int temp_quality;
00873   int this_layer, this_wire, delta_wire;
00874   // If nplanes_hit_accel_pattern is 0, the firmware uses the value
00875   // of nplanes_hit_pattern instead.
00876   const unsigned int nplanes_hit_pattern_acc =
00877     (nplanes_hit_accel_pattern != 0) ? nplanes_hit_accel_pattern :
00878     nplanes_hit_pattern;
00879   const unsigned int pattern_thresh[CSCConstants::NUM_ALCT_PATTERNS] = {
00880     nplanes_hit_pattern_acc, nplanes_hit_pattern, nplanes_hit_pattern
00881   };
00882   const std::string ptn_label[] = {"Accelerator", "CollisionA", "CollisionB"};
00883 
00884   for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS; i_pattern++){
00885     temp_quality = 0;
00886     for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++)
00887       hit_layer[i_layer] = false;
00888 
00889     double num_pattern_hits=0., times_sum=0.;
00890     std::multiset<int> mset_for_median;
00891     mset_for_median.clear();
00892 
00893     for (int i_wire = 0; i_wire < NUM_PATTERN_WIRES; i_wire++){
00894       if (pattern_mask[i_pattern][i_wire] != 0){
00895         this_layer = pattern_envelope[0][i_wire];
00896         delta_wire = pattern_envelope[1+MESelection][i_wire];
00897         this_wire  = delta_wire + key_wire;
00898         if ((this_wire >= 0) && (this_wire < numWireGroups)){
00899 
00900           // Wait a drift_delay time later and look for layers hit in
00901           // the pattern.
00902           if ( ( (pulse[this_layer][this_wire] >> 
00903                  (first_bx[key_wire] + drift_delay)) & 1) == 1) {
00904 
00905             // If layer has never had a hit before, then increment number
00906             // of layer hits.
00907             if (hit_layer[this_layer] == false){
00908               temp_quality++;
00909               // keep track of which layers already had hits.
00910               hit_layer[this_layer] = true;
00911               if (infoV > 1)
00912                 LogTrace("CSCAnodeLCTProcessor")
00913                   << "bx_time: " << first_bx[key_wire]
00914                   << " pattern: " << i_pattern << " keywire: " << key_wire
00915                   << " layer: "     << this_layer
00916                   << " quality: "   << temp_quality;
00917             }
00918             
00919             // for averaged time use only the closest WGs around the key WG
00920             if (abs(delta_wire)<2) {
00921               // find at what bx did pulse on this wire&layer start
00922               // use hit_pesrist constraint on how far back we can go
00923               int first_bx_layer = first_bx[key_wire] + drift_delay;
00924               for (unsigned int dbx=0; dbx<hit_persist; dbx++) {
00925                 if (((pulse[this_layer][this_wire] >> (first_bx_layer-1)) & 1) == 1) first_bx_layer--;
00926                 else break;
00927               }
00928               times_sum += (double)first_bx_layer;
00929               num_pattern_hits += 1.;
00930               mset_for_median.insert(first_bx_layer);
00931               if (infoV > 2) 
00932                 LogTrace("CSCAnodeLCTProcessor")
00933                   <<" 1st bx in layer: "<<first_bx_layer
00934                   <<" sum bx: "<<times_sum
00935                   <<" #pat. hits: "<<num_pattern_hits;
00936             }
00937           }
00938         }
00939       }
00940     }
00941 
00942     // calculate median
00943     const int sz = mset_for_median.size();
00944     if (sz > 0) {
00945       std::multiset<int>::iterator im = mset_for_median.begin();
00946       if (sz > 1) std::advance(im,sz/2-1);
00947       if (sz == 1) first_bx_corrected[key_wire] = *im;
00948       else if ((sz % 2) == 1) first_bx_corrected[key_wire] = *(++im);
00949       else first_bx_corrected[key_wire] = ((*im) + (*(++im)))/2;
00950     
00951       if (infoV > 1) {
00952         char bxs[300]="";
00953         for (im = mset_for_median.begin(); im != mset_for_median.end(); im++) 
00954           sprintf(bxs,"%s %d", bxs, *im);
00955         LogTrace("CSCAnodeLCTProcessor")
00956           <<"bx="<<first_bx[key_wire]<<" bx_cor="<< first_bx_corrected[key_wire]<<"  bxset="<<bxs;
00957       }
00958     }
00959 
00960     if (temp_quality >= pattern_thresh[i_pattern]) {
00961       trigger = true;
00962 
00963       if (!isTMB07) {
00964         // Quality reported by the pattern detector is defined as the number
00965         // of the layers hit in a pattern minus (pattern_thresh-1) value.
00966         temp_quality -= (pattern_thresh[i_pattern]-1);
00967       }
00968       else {
00969         // Quality definition changed on 22 June 2007: it no longer depends
00970         // on pattern_thresh.
00971         if (temp_quality > 3) temp_quality -= 3;
00972         else                  temp_quality  = 0; // quality code 0 is valid!
00973       }
00974 
00975       if (i_pattern == 0) {
00976         // Accelerator pattern
00977         quality[key_wire][0] = temp_quality;
00978       }
00979       else {
00980         // Only one collision pattern (of the best quality) is reported
00981         if (static_cast<int>(temp_quality) > quality[key_wire][1]) {
00982           quality[key_wire][1] = temp_quality;
00983           quality[key_wire][2] = i_pattern-1;
00984         }
00985       }
00986       if (infoV > 1) {
00987         LogTrace("CSCAnodeLCTProcessor")
00988           << "Pattern found; keywire: "  << key_wire
00989           << " type: " << ptn_label[i_pattern]
00990           << " quality: " << temp_quality << "\n";
00991       }
00992     }
00993   }
00994   if (infoV > 1 && quality[key_wire][1] > 0) {
00995     if (quality[key_wire][2] == 0)
00996       LogTrace("CSCAnodeLCTProcessor")
00997         << "Collision Pattern A is chosen" << "\n";
00998     else if (quality[key_wire][2] == 1)
00999       LogTrace("CSCAnodeLCTProcessor")
01000         << "Collision Pattern B is chosen" << "\n";
01001   }
01002   return trigger;
01003 }
01004 
01005 void CSCAnodeLCTProcessor::ghostCancellationLogic() {
01006   /* This function looks for LCTs on the previous and next wires.  If one
01007      exists and it has a better quality and a bx_time up to 4 clocks earlier
01008      than the present, then the present LCT is cancelled.  The present LCT
01009      also gets cancelled if it has the same quality as the one on the
01010      previous wire (this has not been done in 2003 test beam).  The
01011      cancellation is done separately for collision and accelerator patterns. */
01012 
01013   int ghost_cleared[CSCConstants::MAX_NUM_WIRES][2];
01014 
01015   for (int key_wire = 0; key_wire < numWireGroups; key_wire++) {
01016     for (int i_pattern = 0; i_pattern < 2; i_pattern++) {
01017       ghost_cleared[key_wire][i_pattern] = 0;
01018 
01019       // Non-empty wire group.
01020       int qual_this = quality[key_wire][i_pattern];
01021       if (qual_this > 0) {
01022 
01023         // Previous wire.
01024         int qual_prev = (key_wire > 0) ? quality[key_wire-1][i_pattern] : 0;
01025         if (qual_prev > 0) {
01026           int dt = first_bx[key_wire] - first_bx[key_wire-1];
01027           // Cancel this wire
01028           //   1) If the candidate at the previous wire is at the same bx
01029           //      clock and has better quality (or equal quality - this has
01030           //      been implemented only in 2004).
01031           //   2) If the candidate at the previous wire is up to 4 clocks
01032           //      earlier, regardless of quality.
01033           if (dt == 0) {
01034             if (qual_prev >= qual_this) ghost_cleared[key_wire][i_pattern] = 1;
01035           }
01036           else if (dt > 0 && dt <= ghost_cancellation_bx_depth ) {
01037             // Next "if" check accounts for firmware bug and should be
01038             // removed once the next firmware version is used.
01039             // The bug is fixed in 5/5/2008 version of ALCT firmware,
01040             // which is used in all chambers starting with 26/05/2008.
01042             if ((!ghost_cancellation_side_quality) ||
01043                 (qual_prev > qual_this) )
01044               ghost_cleared[key_wire][i_pattern] = 1;
01045           }
01046         }
01047 
01048         // Next wire.
01049         // Skip this step if this wire is already declared "ghost".
01050         if (ghost_cleared[key_wire][i_pattern] == 1) {
01051           if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01052             << ((i_pattern == 0) ? "Accelerator" : "Collision")
01053             << " pattern ghost cancelled on key_wire " << key_wire <<" q="<<qual_this
01054             << "  by wire " << key_wire-1<<" q="<<qual_prev;
01055           continue;
01056         }
01057 
01058         int qual_next =
01059           (key_wire < numWireGroups-1) ? quality[key_wire+1][i_pattern] : 0;
01060         if (qual_next > 0) {
01061           int dt = first_bx[key_wire] - first_bx[key_wire+1];
01062           // Same cancellation logic as for the previous wire.
01063           if (dt == 0) {
01064             if (qual_next > qual_this) ghost_cleared[key_wire][i_pattern] = 1;
01065           }
01066           else if (dt > 0 && dt <= ghost_cancellation_bx_depth ) {
01067             // Next "if" check accounts for firmware bug and should be
01068             // removed once the next firmware version is used.
01069             // The bug is fixed in 5/5/2008 version of ALCT firmware,
01070             // which is used in all chambers starting with 26/05/2008.
01072             if ((!ghost_cancellation_side_quality) ||
01073                 (qual_next >= qual_this) )
01074               ghost_cleared[key_wire][i_pattern] = 1;
01075           }
01076         }
01077         if (ghost_cleared[key_wire][i_pattern] == 1) {
01078           if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01079             << ((i_pattern == 0) ? "Accelerator" : "Collision")
01080             << " pattern ghost cancelled on key_wire " << key_wire <<" q="<<qual_this
01081             << "  by wire " << key_wire+1<<" q="<<qual_next;
01082           continue;
01083         }
01084       }
01085     }
01086   }
01087 
01088   // All cancellation is done in parallel, so wiregroups do not know what
01089   // their neighbors are cancelling.
01090   for (int key_wire = 0; key_wire < numWireGroups; key_wire++) {
01091     for (int i_pattern = 0; i_pattern < 2; i_pattern++) {
01092       if (ghost_cleared[key_wire][i_pattern] > 0) {
01093         clear(key_wire, i_pattern);
01094       }
01095     }
01096   }
01097 }
01098 
01099 
01100 void CSCAnodeLCTProcessor::ghostCancellationLogicSLHC() {
01101   /* This function looks for LCTs on the previous and next wires.  If one
01102      exists and it has a better quality and a bx_time up to
01103      ghost_cancellation_bx_depth clocks earlier than the present,
01104      then the present LCT is cancelled.  The present LCT
01105      also gets cancelled if it has the same quality as the one on the
01106      previous wire (this has not been done in 2003 test beam).  The
01107      cancellation is done separately for collision and accelerator patterns. */
01108 
01109   int ghost_cleared[CSCConstants::MAX_NUM_WIRES][2];
01110 
01111   for (int key_wire = 0; key_wire < numWireGroups; key_wire++) {
01112     for (int i_pattern = 0; i_pattern < 2; i_pattern++) {
01113       ghost_cleared[key_wire][i_pattern] = 0;
01114 
01115       // Non-empty wire group.
01116       int qual_this = quality[key_wire][i_pattern];
01117       if (qual_this > 0) {
01118 
01119         // Previous wire.
01120         int dt = -1;
01121         int qual_prev = (key_wire > 0) ? quality[key_wire-1][i_pattern] : 0;
01122         if (qual_prev > 0) {
01123           if (use_corrected_bx)
01124             dt = first_bx_corrected[key_wire] - first_bx_corrected[key_wire-1];
01125           else
01126             dt = first_bx[key_wire] - first_bx[key_wire-1];
01127           // Cancel this wire
01128           //   1) If the candidate at the previous wire is at the same bx
01129           //      clock and has better quality (or equal? quality - this has
01130           //      been implemented only in 2004).
01131           //   2) If the candidate at the previous wire is up to 4 clocks
01132           //      earlier, regardless of quality.
01133           if (dt == 0) {
01134             if (qual_prev > qual_this) ghost_cleared[key_wire][i_pattern] = 1;
01135           }
01136           else if (dt > 0 && dt <= ghost_cancellation_bx_depth ) {
01137             // Next "if" check accounts for firmware bug and should be
01138             // removed once the next firmware version is used.
01139             // The bug is fixed in 5/5/2008 version of ALCT firmware,
01140             // which is used in all chambers starting with 26/05/2008.
01142             if ((!ghost_cancellation_side_quality) ||
01143                 (qual_prev > qual_this) )
01144               ghost_cleared[key_wire][i_pattern] = 1;
01145           }
01146         }
01147 
01148         // Next wire.
01149         // Skip this step if this wire is already declared "ghost".
01150         if (ghost_cleared[key_wire][i_pattern] == 1) {
01151           if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01152             << ((i_pattern == 0) ? "Accelerator" : "Collision")
01153             << " pattern ghost cancelled on key_wire " << key_wire <<" q="<<qual_this
01154             << "  by wire " << key_wire-1<<" q="<<qual_prev<<"  dt="<<dt;
01155           continue;
01156         }
01157 
01158         dt = -1;
01159         int qual_next =
01160           (key_wire < numWireGroups-1) ? quality[key_wire+1][i_pattern] : 0;
01161         if (qual_next > 0) {
01162           if (use_corrected_bx)
01163             dt = first_bx_corrected[key_wire] - first_bx_corrected[key_wire+1];
01164           else
01165             dt = first_bx[key_wire] - first_bx[key_wire+1];
01166           // Same cancellation logic as for the previous wire.
01167           if (dt == 0) {
01168             if (qual_next >= qual_this) ghost_cleared[key_wire][i_pattern] = 1;
01169           }
01170           else if (dt > 0 && dt <= ghost_cancellation_bx_depth ) {
01171             // Next "if" check accounts for firmware bug and should be
01172             // removed once the next firmware version is used.
01173             // The bug is fixed in 5/5/2008 version of ALCT firmware,
01174             // which is used in all chambers starting with 26/05/2008.
01176             if ((!ghost_cancellation_side_quality) ||
01177                 (qual_next >= qual_this) )
01178               ghost_cleared[key_wire][i_pattern] = 1;
01179           }
01180         }
01181         if (ghost_cleared[key_wire][i_pattern] == 1) {
01182           if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01183             << ((i_pattern == 0) ? "Accelerator" : "Collision")
01184             << " pattern ghost cancelled on key_wire " << key_wire <<" q="<<qual_this
01185             << "  by wire " << key_wire+1<<" q="<<qual_next<<"  dt="<<dt;
01186           continue;
01187         }
01188       }
01189     }
01190   }
01191 
01192   // All cancellation is done in parallel, so wiregroups do not know what
01193   // their neighbors are cancelling.
01194   for (int key_wire = 0; key_wire < numWireGroups; key_wire++) {
01195     for (int i_pattern = 0; i_pattern < 2; i_pattern++) {
01196       if (ghost_cleared[key_wire][i_pattern] > 0) {
01197         clear(key_wire, i_pattern);
01198       }
01199     }
01200   }
01201 }
01202 
01203 
01204 void CSCAnodeLCTProcessor::lctSearch() {
01205   // First modify the quality according accel_mode, then store all
01206   // of the valid LCTs in an array.
01207   std::vector<CSCALCTDigi> lct_list;
01208 
01209   for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
01210     // If there is either accelerator or collision, perform trigMode
01211     // function before storing and sorting.
01212     if (quality[i_wire][0] > 0 || quality[i_wire][1] > 0) {
01213       trigMode(i_wire);
01214 
01215       int bx  = first_bx[i_wire];
01216       int fbx = first_bx_corrected[i_wire];
01217       if (infoV>1) LogTrace("CSCAnodeLCTProcessor")<<" bx="<<bx<<" fbx="<<fbx;
01218       if (use_corrected_bx) {
01219         bx  = fbx;
01220         fbx = first_bx[i_wire];
01221       }
01222       if (infoV>1) LogTrace("CSCAnodeLCTProcessor")<<" bx="<<bx<<" fbx="<<fbx;
01223       // Store any valid accelerator pattern LCTs.
01224       if (quality[i_wire][0] > 0) {
01225         int qual = (quality[i_wire][0] & 0x03); // 2 LSBs
01226         CSCALCTDigi lct_info(1, qual, 1, 0, i_wire, bx);
01227         lct_info.setFullBX(fbx);
01228         lct_list.push_back(lct_info);
01229       }
01230 
01231       // Store any valid collision pattern LCTs.
01232       if (quality[i_wire][1] > 0) {
01233         int qual = (quality[i_wire][1] & 0x03); // 2 LSBs
01234         CSCALCTDigi lct_info(1, qual, 0, quality[i_wire][2], i_wire, bx);
01235         //lct_info.setFullBX(fbx); // uncomment if one wants, e.g., to keep corrected time here
01236         lct_list.push_back(lct_info);
01237         if (infoV>1) LogTrace("CSCAnodeLCTProcessor")<<" got lct_info: "<<lct_info;
01238       }
01239 
01240       // Modify qualities according to accel_mode parameter.
01241       accelMode(i_wire);
01242     }
01243   }
01244 
01245   // Best track selector selects two collision and two accelerator ALCTs
01246   // with the best quality per time bin.
01247   std::vector<CSCALCTDigi> fourBest = bestTrackSelector(lct_list);
01248 
01249   if (infoV > 0) {
01250     int n_alct_all=0, n_alct=0;
01251     for (std::vector <CSCALCTDigi>::const_iterator plct = lct_list.begin(); plct != lct_list.end(); plct++)
01252       if (plct->isValid() && plct->getBX()==6) n_alct_all++;
01253     for (std::vector <CSCALCTDigi>::const_iterator plct = fourBest.begin(); plct != fourBest.end(); plct++)
01254       if (plct->isValid() && plct->getBX()==6) n_alct++;
01255 
01256     LogTrace("CSCAnodeLCTProcessor")<<"alct_count E:"<<theEndcap<<"S:"<<theStation<<"R:"<<theRing<<"C:"<<theChamber
01257       <<"  all "<<n_alct_all<<"  found "<<n_alct;
01258   }
01259   
01260   // Select two best of four per time bin, based on quality and
01261   // accel_mode parameter.
01262   for (std::vector<CSCALCTDigi>::const_iterator plct = fourBest.begin();
01263        plct != fourBest.end(); plct++) {
01264 
01265     int bx = plct->getBX();
01266     if (bx >= MAX_ALCT_BINS) {
01267       if (infoV > 0) edm::LogWarning("L1CSCTPEmulatorOutOfTimeALCT")
01268         << "+++ Bx of ALCT candidate, " << bx << ", exceeds max allowed, "
01269         << MAX_ALCT_BINS-1 << "; skipping it... +++\n";
01270       continue;
01271     }
01272 
01273     if (isBetterALCT(*plct, bestALCT[bx])) {
01274       if (isBetterALCT(bestALCT[bx], secondALCT[bx])) {
01275         secondALCT[bx] = bestALCT[bx];
01276       }
01277       bestALCT[bx] = *plct;
01278     }
01279     else if (isBetterALCT(*plct, secondALCT[bx])) {
01280       secondALCT[bx] = *plct;
01281     }
01282   }
01283 
01284   if (!isTMB07) {
01285     // Prior to DAQ-2006 format, only ALCTs at the earliest bx were reported.
01286     int first_bx = MAX_ALCT_BINS;
01287     for (int bx = 0; bx < MAX_ALCT_BINS; bx++) {
01288       if (bestALCT[bx].isValid()) {
01289         first_bx = bx;
01290         break;
01291       }
01292     }
01293     if (first_bx < MAX_ALCT_BINS) {
01294       for (int bx = first_bx + 1; bx < MAX_ALCT_BINS; bx++) {
01295         if (bestALCT[bx].isValid())   bestALCT[bx].clear();
01296         if (secondALCT[bx].isValid()) secondALCT[bx].clear();
01297       }
01298     }
01299   }
01300 
01301   for (int bx = 0; bx < MAX_ALCT_BINS; bx++) {
01302     if (bestALCT[bx].isValid()) {
01303       bestALCT[bx].setTrknmb(1);
01304       if (infoV > 0) {
01305         LogDebug("CSCAnodeLCTProcessor")
01306           << "\n" << bestALCT[bx] << " fullBX = "<<bestALCT[bx].getFullBX()
01307           << " found in ME"
01308           << ((theEndcap == 1) ? "+" : "-")
01309           << theStation << "/" << theRing << "/" << theChamber
01310           << " (sector " << theSector << " subsector " << theSubsector
01311           << " trig id. " << theTrigChamber << ")" << "\n";
01312       }
01313       if (secondALCT[bx].isValid()) {
01314         secondALCT[bx].setTrknmb(2);
01315         if (infoV > 0) {
01316           LogDebug("CSCAnodeLCTProcessor")
01317             << secondALCT[bx] << " fullBX = "<<secondALCT[bx].getFullBX()
01318             << " found in ME"
01319             << ((theEndcap == 1) ? "+" : "-")
01320             << theStation << "/" << theRing << "/" << theChamber
01321             << " (sector " << theSector << " subsector " << theSubsector
01322             << " trig id. " << theTrigChamber << ")" << "\n";
01323         }
01324       }
01325     }
01326   }
01327 }
01328 
01329 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::bestTrackSelector(
01330                                  const std::vector<CSCALCTDigi>& all_alcts) {
01331   /* Selects two collision and two accelerator ALCTs per time bin with
01332      the best quality. */
01333   CSCALCTDigi bestALCTs[MAX_ALCT_BINS][2], secondALCTs[MAX_ALCT_BINS][2];
01334 
01335   if (infoV > 1) {
01336     LogTrace("CSCAnodeLCTProcessor") << all_alcts.size() <<
01337       " ALCTs at the input of best-track selector: ";
01338     for (std::vector <CSCALCTDigi>::const_iterator plct = all_alcts.begin();
01339          plct != all_alcts.end(); plct++) {
01340       if (!plct->isValid()) continue;
01341       LogTrace("CSCAnodeLCTProcessor") << (*plct);
01342     }
01343   }
01344 
01345   CSCALCTDigi tA[MAX_ALCT_BINS][2], tB[MAX_ALCT_BINS][2];
01346   for (std::vector <CSCALCTDigi>::const_iterator plct = all_alcts.begin();
01347        plct != all_alcts.end(); plct++) {
01348     if (!plct->isValid()) continue;
01349 
01350     // Select two collision and two accelerator ALCTs with the highest
01351     // quality at every bx.  The search for best ALCTs is done in parallel
01352     // for collision and accelerator patterns, and simultaneously for
01353     // two ALCTs, tA and tB.  If two or more ALCTs have equal qualities,
01354     // the priority is given to the ALCT with larger wiregroup number
01355     // in the search for tA (collision and accelerator), and to the ALCT
01356     // with smaller wiregroup number in the search for tB.
01357     int bx    = (*plct).getBX();
01358     int accel = (*plct).getAccelerator();
01359     int qual  = (*plct).getQuality();
01360     int wire  = (*plct).getKeyWG();
01361     bool vA = tA[bx][accel].isValid();
01362     bool vB = tB[bx][accel].isValid();
01363     int qA  = tA[bx][accel].getQuality();
01364     int qB  = tB[bx][accel].getQuality();
01365     int wA  = tA[bx][accel].getKeyWG();
01366     int wB  = tB[bx][accel].getKeyWG();
01367     if (!vA || qual > qA || (qual == qA && wire > wA)) {
01368       tA[bx][accel] = *plct;
01369     }
01370     if (!vB || qual > qB || (qual == qB && wire < wB)) {
01371       tB[bx][accel] = *plct;
01372     }
01373   }
01374 
01375   for (int bx = 0; bx < MAX_ALCT_BINS; bx++) {
01376     for (int accel = 0; accel <= 1; accel++) {
01377       // Best ALCT is always tA.
01378       if (tA[bx][accel].isValid()) {
01379         if (infoV > 2) {
01380           LogTrace("CSCAnodeLCTProcessor") << "tA: " << tA[bx][accel];
01381           LogTrace("CSCAnodeLCTProcessor") << "tB: " << tB[bx][accel];
01382         }
01383         bestALCTs[bx][accel] = tA[bx][accel];
01384 
01385         // If tA exists, tB exists too.
01386         if (tA[bx][accel] != tB[bx][accel] &&
01387             tA[bx][accel].getQuality() == tB[bx][accel].getQuality()) {
01388           secondALCTs[bx][accel] = tB[bx][accel];
01389         }
01390         else {
01391           // Funny part: if tA and tB are the same, or the quality of tB
01392           // is inferior to the quality of tA, the second best ALCT is
01393           // not tB.  Instead it is the largest-wiregroup ALCT among those
01394           // ALCT whose qualities are lower than the quality of the best one.
01395           for (std::vector <CSCALCTDigi>::const_iterator plct =
01396                  all_alcts.begin(); plct != all_alcts.end(); plct++) {
01397             if ((*plct).isValid() && 
01398                 (*plct).getAccelerator() == accel && (*plct).getBX() == bx &&
01399                 (*plct).getQuality() <  bestALCTs[bx][accel].getQuality() && 
01400                 (*plct).getQuality() >= secondALCTs[bx][accel].getQuality() &&
01401                 (*plct).getKeyWG()   >= secondALCTs[bx][accel].getKeyWG()) {
01402               secondALCTs[bx][accel] = *plct;
01403             }
01404           }
01405         }
01406       }
01407     }
01408   }
01409 
01410   // Fill the vector with up to four best ALCTs per bx and return it.
01411   std::vector<CSCALCTDigi> fourBest;
01412   for (int bx = 0; bx < MAX_ALCT_BINS; bx++) {
01413     for (int i = 0; i < 2; i++) {
01414       if (bestALCTs[bx][i].isValid())   fourBest.push_back(bestALCTs[bx][i]);
01415     }
01416     for (int i = 0; i < 2; i++) {
01417       if (secondALCTs[bx][i].isValid()) fourBest.push_back(secondALCTs[bx][i]);
01418     }
01419   }
01420 
01421   if (infoV > 1) {
01422     LogTrace("CSCAnodeLCTProcessor") << fourBest.size() << " ALCTs selected: ";
01423     for (std::vector<CSCALCTDigi>::const_iterator plct = fourBest.begin();
01424          plct != fourBest.end(); plct++) {
01425       LogTrace("CSCAnodeLCTProcessor") << (*plct);
01426     }
01427   }
01428 
01429   return fourBest;
01430 }
01431 
01432 bool CSCAnodeLCTProcessor::isBetterALCT(const CSCALCTDigi& lhsALCT,
01433                                         const CSCALCTDigi& rhsALCT) {
01434   /* This method should have been an overloaded > operator, but we
01435      have to keep it here since need to check values in quality[][]
01436      array modified according to accel_mode parameter. */
01437   bool returnValue = false;
01438 
01439   if (lhsALCT.isValid() && !rhsALCT.isValid()) {return true;}
01440 
01441   // ALCTs found at earlier bx times are ranked higher than ALCTs found at
01442   // later bx times regardless of the quality.
01443   if (lhsALCT.getBX()  < rhsALCT.getBX()) {returnValue = true;}
01444   if (lhsALCT.getBX() != rhsALCT.getBX()) {return returnValue;}
01445 
01446   // First check the quality of ALCTs.
01447   int qual1 = lhsALCT.getQuality();
01448   int qual2 = rhsALCT.getQuality();
01449   if (qual1 >  qual2) {returnValue = true;}
01450   // If qualities are the same, check accelerator bits of both ALCTs.
01451   // If they are not the same, rank according to accel_mode value.
01452   // If they are the same, keep the track selector assignment.
01453   else if (qual1 == qual2 && 
01454            lhsALCT.getAccelerator() != rhsALCT.getAccelerator() &&
01455            quality[lhsALCT.getKeyWG()][1-lhsALCT.getAccelerator()] >
01456            quality[rhsALCT.getKeyWG()][1-rhsALCT.getAccelerator()])
01457     {returnValue = true;}
01458 
01459   return returnValue;
01460 }
01461 
01462 void CSCAnodeLCTProcessor::trigMode(const int key_wire) {
01463   /* Function which enables/disables either collision or accelerator tracks.
01464      The function uses the trig_mode parameter to decide. */
01465 
01466   switch(trig_mode) {
01467   default:
01468   case 0:
01469     // Enables both collision and accelerator tracks
01470     break;
01471   case 1:
01472     // Disables collision tracks
01473     if (quality[key_wire][1] > 0) {
01474       quality[key_wire][1] = 0;
01475       if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01476         << "trigMode(): collision track " << key_wire << " disabled" << "\n";
01477     }
01478     break;
01479   case 2:
01480     // Disables accelerator tracks
01481     if (quality[key_wire][0] > 0) {
01482       quality[key_wire][0] = 0;
01483       if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01484         << "trigMode(): accelerator track " << key_wire << " disabled" << "\n";
01485     }
01486     break;
01487   case 3:
01488     // Disables collision track if there is an accelerator track found
01489     // in the same wire group at the same time
01490     if (quality[key_wire][0] > 0 && quality[key_wire][1] > 0) {
01491       quality[key_wire][1] = 0;
01492       if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01493         << "trigMode(): collision track " << key_wire << " disabled" << "\n";
01494     }
01495     break;
01496   }
01497 }
01498 
01499 void CSCAnodeLCTProcessor::accelMode(const int key_wire) {
01500   /* Function which gives a preference either to the collision patterns
01501      or accelerator patterns.  The function uses the accel_mode parameter
01502      to decide. */
01503   int promotionBit = 1 << 2;
01504 
01505   switch(accel_mode) {
01506   default:
01507   case 0:
01508     // Ignore accelerator muons.
01509     if (quality[key_wire][0] > 0) {
01510       quality[key_wire][0] = 0;
01511       if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01512         << "alctMode(): accelerator track " << key_wire << " ignored" << "\n";
01513     }
01514     break;
01515   case 1:
01516     // Prefer collision muons by adding promotion bit.
01517     if (quality[key_wire][1] > 0) {
01518       quality[key_wire][1] += promotionBit;
01519       if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01520         << "alctMode(): collision track " << key_wire << " promoted" << "\n";
01521     }
01522     break;
01523   case 2:
01524     // Prefer accelerator muons by adding promotion bit.
01525     if (quality[key_wire][0] > 0) {
01526       quality[key_wire][0] += promotionBit;
01527       if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01528         << "alctMode(): accelerator track " << key_wire << " promoted"<< "\n";
01529     }
01530     break;
01531   case 3:
01532     // Ignore collision muons.
01533     if (quality[key_wire][1] > 0) {
01534       quality[key_wire][1] = 0;
01535       if (infoV > 1) LogTrace("CSCAnodeLCTProcessor")
01536         << "alctMode(): collision track " << key_wire << " ignored" << "\n";
01537     }
01538     break;
01539   }
01540 }
01541 
01542 // Dump of configuration parameters.
01543 void CSCAnodeLCTProcessor::dumpConfigParams() const {
01544   std::ostringstream strm;
01545   strm << "\n";
01546   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
01547   strm << "+                  ALCT configuration parameters:                  +\n";
01548   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
01549   strm << " fifo_tbins   [total number of time bins in DAQ readout] = "
01550        << fifo_tbins << "\n";
01551   strm << " fifo_pretrig [start time of anode raw hits in DAQ readout] = "
01552        << fifo_pretrig << "\n";
01553   strm << " drift_delay  [drift delay after pre-trigger, in 25 ns bins] = "
01554        << drift_delay << "\n";
01555   strm << " nplanes_hit_pretrig [min. number of layers hit for pre-trigger] = "
01556        << nplanes_hit_pretrig << "\n";
01557   strm << " nplanes_hit_pattern [min. number of layers hit for trigger] = "
01558        << nplanes_hit_pattern << "\n";
01559   strm << " nplanes_hit_accel_pretrig [min. number of layers hit for accel."
01560        << " pre-trig.] = " << nplanes_hit_accel_pretrig << "\n";
01561   strm << " nplanes_hit_accel_pattern [min. number of layers hit for accel."
01562        << " trigger] = "   << nplanes_hit_accel_pattern << "\n";
01563   strm << " trig_mode  [enabling/disabling collision/accelerator tracks] = "
01564        << trig_mode << "\n";
01565   strm << " accel_mode [preference to collision/accelerator tracks] = "
01566        << accel_mode << "\n";
01567   strm << " l1a_window_width [L1Accept window width, in 25 ns bins] = "
01568        << l1a_window_width << "\n";
01569   strm << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n";
01570   LogDebug("CSCAnodeLCTProcessor") << strm.str();
01571   //std::cout<<strm.str()<<std::endl;
01572 }
01573 
01574 // Dump of digis on wire groups.
01575 void CSCAnodeLCTProcessor::dumpDigis(const std::vector<int> wire[CSCConstants::NUM_LAYERS][CSCConstants::MAX_NUM_WIRES]) const {
01576   LogDebug("CSCAnodeLCTProcessor")
01577     << "ME" << ((theEndcap == 1) ? "+" : "-")
01578     << theStation << "/" << theRing << "/" << theChamber
01579     << " nWiregroups " << numWireGroups;
01580 
01581   std::ostringstream strstrm;
01582   for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
01583     if (i_wire%10 == 0) {
01584       if (i_wire < 100) strstrm << i_wire/10;
01585       else              strstrm << (i_wire-100)/10;
01586     }
01587     else                strstrm << " ";
01588   }
01589   strstrm << "\n";
01590   for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
01591     strstrm << i_wire%10;
01592   }
01593   for (int i_layer = 0; i_layer < CSCConstants::NUM_LAYERS; i_layer++) {
01594     strstrm << "\n";
01595     for (int i_wire = 0; i_wire < numWireGroups; i_wire++) {
01596       if (wire[i_layer][i_wire].size() > 0) {
01597         std::vector<int> bx_times = wire[i_layer][i_wire];
01598         strstrm << std::hex << bx_times[0] << std::dec;
01599       }
01600       else {
01601         strstrm << ".";
01602       }
01603     }
01604   }
01605   LogTrace("CSCAnodeLCTProcessor") << strstrm.str();
01606 }
01607 
01608 // Returns vector of read-out ALCTs, if any.  Starts with the vector of
01609 // all found ALCTs and selects the ones in the read-out time window.
01610 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::readoutALCTs() {
01611   std::vector<CSCALCTDigi> tmpV;
01612 
01613   // The number of LCT bins in the read-out is given by the
01614   // l1a_window_width parameter, but made even by setting the LSB of
01615   // l1a_window_width to 0.
01616   static int lct_bins   = 
01617     //    (l1a_window_width%2 == 0) ? l1a_window_width : l1a_window_width-1;
01618     l1a_window_width;
01619   static int late_tbins = early_tbins + lct_bins;
01620 
01621   static int ifois = 0;
01622   if (ifois == 0) {
01623 
01624     //std::cout<<"ALCT early_tbins="<<early_tbins<<"  lct_bins="<<lct_bins<<"  l1a_window_width="<<l1a_window_width<<"  late_tbins="<<late_tbins<<std::endl;
01625     //std::cout<<"**** ALCT readoutALCTs config dump ****"<<std::endl;
01626     //dumpConfigParams();
01627 
01628     if (infoV >= 0 && early_tbins < 0) {
01629       edm::LogWarning("L1CSCTPEmulatorSuspiciousParameters")
01630         << "+++ fifo_pretrig = " << fifo_pretrig
01631         << "; in-time ALCTs are not getting read-out!!! +++" << "\n";
01632     }
01633 
01634     if (late_tbins > MAX_ALCT_BINS-1) {
01635       if (infoV >= 0) edm::LogWarning("L1CSCTPEmulatorSuspiciousParameters")
01636         << "+++ Allowed range of time bins, [0-" << late_tbins
01637         << "] exceeds max allowed, " << MAX_ALCT_BINS-1 << " +++\n"
01638         << "+++ Set late_tbins to max allowed +++\n";
01639       late_tbins = MAX_ALCT_BINS-1;
01640     }
01641     ifois = 1;
01642   }
01643 
01644   // Start from the vector of all found ALCTs and select those within
01645   // the ALCT*L1A coincidence window.
01646   std::vector<CSCALCTDigi> all_alcts = getALCTs();
01647   for (std::vector <CSCALCTDigi>::const_iterator plct = all_alcts.begin();
01648        plct != all_alcts.end(); plct++) {
01649     if (!plct->isValid()) continue;
01650 
01651     int bx = (*plct).getBX();
01652     // Skip ALCTs found too early relative to L1Accept.
01653     if (bx <= early_tbins) {
01654       if (infoV > 1) LogDebug("CSCAnodeLCTProcessor")
01655         << " Do not report ALCT on keywire " << plct->getKeyWG()
01656         << ": found at bx " << bx << ", whereas the earliest allowed bx is "
01657         << early_tbins+1;
01658       continue;
01659     }
01660 
01661     // Skip ALCTs found too late relative to L1Accept.
01662     if (bx > late_tbins) {
01663       if (infoV > 1) LogDebug("CSCAnodeLCTProcessor")
01664         << " Do not report ALCT on keywire " << plct->getKeyWG()
01665         << ": found at bx " << bx << ", whereas the latest allowed bx is "
01666         << late_tbins;
01667       continue;
01668     }
01669 
01670     tmpV.push_back(*plct);
01671   }
01672   return tmpV;
01673 }
01674 
01675 // Returns vector of all found ALCTs, if any.  Used in ALCT-CLCT matching.
01676 std::vector<CSCALCTDigi> CSCAnodeLCTProcessor::getALCTs() {
01677   std::vector<CSCALCTDigi> tmpV;
01678   for (int bx = 0; bx < MAX_ALCT_BINS; bx++) {
01679     if (bestALCT[bx].isValid())   tmpV.push_back(bestALCT[bx]);
01680     if (secondALCT[bx].isValid()) tmpV.push_back(secondALCT[bx]);
01681   }
01682   return tmpV;
01683 }
01684 
01687 
01688 void CSCAnodeLCTProcessor::showPatterns(const int key_wire) {
01689   /* Method to test the pretrigger */
01690   for (int i_pattern = 0; i_pattern < CSCConstants::NUM_ALCT_PATTERNS;
01691        i_pattern++) {
01692     std::ostringstream strstrm_header;
01693     LogTrace("CSCAnodeLCTProcessor")
01694       << "\n" << "Pattern: " << i_pattern << " Key wire: " << key_wire;
01695     for (int i = 1; i <= 32; i++) {
01696       strstrm_header << ((32-i)%10);
01697     }
01698     LogTrace("CSCAnodeLCTProcessor") << strstrm_header.str();
01699     for (int i_wire = 0; i_wire < NUM_PATTERN_WIRES; i_wire++) {
01700       if (pattern_mask[i_pattern][i_wire] != 0) {
01701         std::ostringstream strstrm_pulse;
01702         int this_layer = pattern_envelope[0][i_wire];
01703         int this_wire  = pattern_envelope[1+MESelection][i_wire]+key_wire;
01704         if (this_wire >= 0 && this_wire < numWireGroups) {
01705           for (int i = 1; i <= 32; i++) {
01706             strstrm_pulse << ((pulse[this_layer][this_wire]>>(32-i)) & 1);
01707           }
01708           LogTrace("CSCAnodeLCTProcessor")
01709             << strstrm_pulse.str() << " on layer " << this_layer;
01710         }
01711       }
01712     }
01713     LogTrace("CSCAnodeLCTProcessor")
01714       << "-------------------------------------------";
01715   }
01716 }