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;
}