void l1menu::implementation::OldL1MenuFile::add( const l1menu::TriggerMenu& object ) { if( pOutputStream_==nullptr ) throw std::runtime_error( "OldL1MenuFile add is trying to add a TriggerMenu but the output stream pointer is null" ); for( size_t index=0; index<object.numberOfTriggers(); ++index ) { const l1menu::ITriggerDescription& trigger=object.getTrigger(index); const l1menu::TriggerConstraint& triggerConstraint=object.getTriggerConstraint(index); std::vector<float> thresholds; { // Block to limit scope of temporary variables std::vector<std::string> thresholdNames=l1menu::tools::getThresholdNames( trigger ); for( size_t thresholdIndex=0; thresholdIndex<4; ++thresholdIndex ) { // Output "-1" if this trigger has fewer than 4 thresholds if( thresholdIndex>=thresholdNames.size() ) thresholds.push_back(-1); else thresholds.push_back( trigger.parameter(thresholdNames[thresholdIndex]) ); } } float etaOrRegionCut; // // Some of the cross triggers have this set for both legs, and I need to hard code which // to take (the calo region or the absolute eta). This is purely convention to match the // way the menu is loaded. For the other triggers I'll just try all of the parameter names // and see which call is successful. // if( trigger.name()=="L1_SingleMu_CJet" ) etaOrRegionCut=trigger.parameter("leg1etaCut"); else if( trigger.name()=="L1_TkMu_TkJet" ) etaOrRegionCut=trigger.parameter("leg1etaCut"); else if( trigger.name()=="L1_isoMu_EG" ) etaOrRegionCut=trigger.parameter("leg2regionCut"); else if( trigger.name()=="L1_isoEG_Mu" ) etaOrRegionCut=trigger.parameter("leg1regionCut"); else if( trigger.name()=="L1_TkEle_Mu" ) etaOrRegionCut=trigger.parameter("leg1regionCut"); else if( trigger.name()=="L1_TkTau_Mu" ) etaOrRegionCut=trigger.parameter("leg1regionCut"); else if( trigger.name()=="L1_isoMu_Tau" ) etaOrRegionCut=trigger.parameter("leg2regionCut"); else { try{ etaOrRegionCut=trigger.parameter("etaCut"); } catch( std::logic_error& exception ) { try{ etaOrRegionCut=trigger.parameter("regionCut"); } catch( std::logic_error& exception ) { try{ etaOrRegionCut=trigger.parameter("leg1etaCut"); } catch( std::logic_error& exception ) { try{ etaOrRegionCut=trigger.parameter("leg1regionCut"); } catch( std::logic_error& exception ) { try{ etaOrRegionCut=trigger.parameter("leg2etaCut"); } catch( std::logic_error& exception ) { try{ etaOrRegionCut=trigger.parameter("leg2regionCut"); } catch( std::logic_error& exception ) { etaOrRegionCut=-1; } } } } } } } float muonQuality; try{ muonQuality=trigger.parameter("muonQuality"); } catch( std::logic_error& exception ) { try{ muonQuality=trigger.parameter("leg1muonQuality"); } catch( std::logic_error& exception ) { try{ muonQuality=trigger.parameter("leg2muonQuality"); } catch( std::logic_error& exception ) { muonQuality=-1; } } } float allocatedBandwidth; int scaleBandwidth; int fixThresholds; if( triggerConstraint.type()==l1menu::TriggerConstraint::Type::FIXED_THRESHOLDS ) { allocatedBandwidth=10; // Dummy value. It won't be used if fixThresholds is 1. scaleBandwidth=0; fixThresholds=1; } else if( triggerConstraint.type()==l1menu::TriggerConstraint::Type::FIXED_RATE ) { allocatedBandwidth=triggerConstraint.value(); scaleBandwidth=0; fixThresholds=0; } else if( triggerConstraint.type()==l1menu::TriggerConstraint::Type::FRACTION_OF_BANDWIDTH ) { // For FRACTION_OF_BANDWIDTH, the value() is the fraction of the total bandwidth. // The file format expects it in an absolute rate though. I can scale the fraction by // an arbitrary amount and it will be converted back to a fraction when the menu // is loaded back in. Scaling by 100 should make the table look tidier. allocatedBandwidth=triggerConstraint.value()*100; scaleBandwidth=1; fixThresholds=0; } // Note that: // - The second column is the trigger bit, which is unused in all of this code. // I'll just put in a dummy "00" for now. // - The third column is the prescale, which is currently not supported. I'll // just put in "1" for everything for now. (*pOutputStream_) << std::right << std::setw(23) << trigger.name() << " 00 1 " // Second and third column are dummy values as described above << std::setw(7) << thresholds[0] << " " << std::setw(7) << thresholds[1] << " " << std::setw(7) << thresholds[2] << " " << std::setw(7) << thresholds[3] << " " << std::setw(5) << etaOrRegionCut << " " << std::setw(5) << muonQuality << " " << std::setw(5) << allocatedBandwidth << " " << std::setw(2) << scaleBandwidth << " " << std::setw(2) << fixThresholds << " " << std::endl; } // end of loop over triggers }
l1menu::implementation::MenuRateImplementation::MenuRateImplementation( const l1menu::TriggerMenu& menu, const l1menu::ISample& sample ) { // The sum of event weights that pass each trigger std::vector<float> weightOfEventsPassed( menu.numberOfTriggers() ); // The sume of weights squared that pass each trigger. Used to calculate the error. std::vector<float> weightSquaredOfEventsPassed( menu.numberOfTriggers() ); // The number of events that only pass the given trigger std::vector<float> weightOfEventsPure( menu.numberOfTriggers() ); std::vector<float> weightSquaredOfEventsPure( menu.numberOfTriggers() ); float weightOfEventsPassingAnyTrigger=0; float weightSquaredOfEventsPassingAnyTrigger=0; float weightOfAllEvents=0; // Using cached triggers significantly increases speed for ReducedSample // because it cuts out expensive string comparisons when querying the trigger // parameters. std::vector< std::unique_ptr<l1menu::ICachedTrigger> > cachedTriggers; for( size_t triggerNumber=0; triggerNumber<menu.numberOfTriggers(); ++triggerNumber ) { cachedTriggers.push_back( sample.createCachedTrigger( menu.getTrigger( triggerNumber ) ) ); } size_t numberOfLastPassedTrigger=0; // This is just so I can work out the pure rate for( size_t eventNumber=0; eventNumber<sample.numberOfEvents(); ++eventNumber ) { const l1menu::IEvent& event=sample.getEvent(eventNumber); float weight=event.weight(); weightOfAllEvents+=weight; size_t numberOfTriggersPassed=0; for( size_t triggerNumber=0; triggerNumber<cachedTriggers.size(); ++triggerNumber ) { if( cachedTriggers[triggerNumber]->apply(event) ) { // If the event passes the trigger, increment the counters ++numberOfTriggersPassed; weightOfEventsPassed[triggerNumber]+=weight; weightSquaredOfEventsPassed[triggerNumber]+=(weight*weight); numberOfLastPassedTrigger=triggerNumber; // If only one event passes, this is used to increment the pure counter } } // See if I should increment any of the pure or total counters if( numberOfTriggersPassed==1 ) { weightOfEventsPure[numberOfLastPassedTrigger]+=weight; weightSquaredOfEventsPure[numberOfLastPassedTrigger]+=(weight*weight); } if( numberOfTriggersPassed>0 ) { weightOfEventsPassingAnyTrigger+=weight; weightSquaredOfEventsPassingAnyTrigger+=(weight*weight); } } float scaling=sample.eventRate(); for( size_t triggerNumber=0; triggerNumber<cachedTriggers.size(); ++triggerNumber ) { float fraction=weightOfEventsPassed[triggerNumber]/weightOfAllEvents; float fractionError=std::sqrt(weightSquaredOfEventsPassed[triggerNumber])/weightOfAllEvents; float pureFraction=weightOfEventsPure[triggerNumber]/weightOfAllEvents; float pureFractionError=std::sqrt(weightSquaredOfEventsPure[triggerNumber])/weightOfAllEvents; triggerRates_.push_back( std::move(TriggerRateImplementation(menu.getTrigger(triggerNumber),fraction,fractionError,fraction*scaling,fractionError*scaling,pureFraction,pureFractionError,pureFraction*scaling,pureFractionError*scaling) ) ); //triggerRates_.push_back( std::move(TriggerRateImplementation(menu.getTrigger(triggerNumber),weightOfEventsPassed[triggerNumber],weightSquaredOfEventsPassed[triggerNumber],weightOfEventsPure[triggerNumber],weightSquaredOfEventsPure[triggerNumber],*this)) ); } // // Now I have everything I need to calculate all of the values required by the interface // totalFraction_=weightOfEventsPassingAnyTrigger/weightOfAllEvents; totalFractionError_=std::sqrt(weightSquaredOfEventsPassingAnyTrigger)/weightOfAllEvents; totalRate_=totalFraction_*scaling; totalRateError_=totalFractionError_*scaling; }