ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/TriggerMenu.cpp
Revision: 1.10
Committed: Sat Jun 29 16:14:45 2013 UTC (11 years, 10 months ago) by grimes
Branch: MAIN
Changes since 1.9: +4 -4 lines
Log Message:
Added an option to the TriggerRatePlot to scale all thresholds at once for the plot

File Contents

# User Rev Content
1 grimes 1.1 #include "l1menu/TriggerMenu.h"
2    
3     #include <stdexcept>
4     #include <fstream>
5     #include <sstream>
6     #include <iostream>
7     #include "l1menu/ITrigger.h"
8 grimes 1.7 #include "l1menu/tools/tools.h"
9 grimes 1.1
10     namespace // Use the unnamed namespace for things only used in this file
11     {
12 grimes 1.3 /// ASCII codes of characters that are considered whitespace (space, tab, carriage return, line feed).
13 grimes 1.1 const char* whitespace="\x20\x09\x0D\x0A";
14    
15 grimes 1.3 /** @brief Converts the entire string to a float or throws an exception. */
16 grimes 1.1 float convertStringToFloat( const std::string& string )
17     {
18     float returnValue;
19     std::stringstream stringConverter( string );
20     stringConverter >> returnValue;
21     if( stringConverter.fail() || !stringConverter.eof() ) throw std::runtime_error( "Unable to convert \""+string+"\" to a float" );
22     return returnValue;
23     }
24    
25 grimes 1.3 /** @brief Splits a string into individual parts delimited by whitespace. */
26 grimes 1.1 std::vector<std::string> splitByWhitespace( const std::string& stringToSplit )
27     {
28     std::vector<std::string> returnValue;
29    
30     size_t currentPosition=0;
31     size_t nextDelimeter=0;
32     do
33     {
34     // Skip over any leading whitespace
35     size_t nextElementStart=stringToSplit.find_first_not_of( whitespace, currentPosition );
36     if( nextElementStart!=std::string::npos ) currentPosition=nextElementStart;
37    
38 grimes 1.3 // Find the next whitespace and subtract everything up to that point
39 grimes 1.1 nextDelimeter=stringToSplit.find_first_of( whitespace, currentPosition );
40     std::string element=stringToSplit.substr( currentPosition, nextDelimeter-currentPosition );
41     returnValue.push_back(element);
42    
43     // skip over any trailing whitespace
44     nextElementStart=stringToSplit.find_first_not_of( whitespace, nextDelimeter );
45     if( nextElementStart!=std::string::npos ) currentPosition=nextElementStart;
46     else nextDelimeter=std::string::npos;
47    
48     } while( nextDelimeter!=std::string::npos );
49    
50     return returnValue;
51     }
52    
53     } // end of the unnamed namespace
54    
55    
56 grimes 1.3 l1menu::TriggerMenu::TriggerMenu() : triggerTable_( l1menu::TriggerTable::instance() )
57 grimes 1.1 {
58     // No operation besides the initialiser list
59     }
60    
61     l1menu::TriggerMenu::~TriggerMenu()
62     {
63 grimes 1.3 // No operation since I switched from raw pointers to unique_ptr.
64 grimes 1.1 }
65    
66 grimes 1.3 l1menu::TriggerMenu::TriggerMenu( const TriggerMenu& otherTriggerMenu )
67 grimes 1.1 : triggerTable_(otherTriggerMenu.triggerTable_)
68     {
69 grimes 1.3 for( std::vector< std::unique_ptr<l1menu::ITrigger> >::const_iterator iTrigger=otherTriggerMenu.triggers_.begin(); iTrigger!=otherTriggerMenu.triggers_.end(); ++iTrigger )
70 grimes 1.1 {
71     l1menu::ITrigger& sourceTrigger=**iTrigger;
72    
73 grimes 1.3 triggers_.push_back( std::move(triggerTable_.copyTrigger(sourceTrigger)) );
74 grimes 1.1 }
75    
76     // Make sure triggerResults_ is always the same size as triggers_
77     triggerResults_.resize( triggers_.size() );
78     }
79    
80 grimes 1.3 l1menu::TriggerMenu::TriggerMenu( TriggerMenu&& otherTriggerMenu ) noexcept
81     : triggerTable_(otherTriggerMenu.triggerTable_), triggers_( std::move(otherTriggerMenu.triggers_) ),
82     triggerResults_( std::move(otherTriggerMenu.triggerResults_) )
83     {
84     // No operation besides the initialiser list
85     }
86    
87 grimes 1.1 l1menu::TriggerMenu& l1menu::TriggerMenu::operator=( const l1menu::TriggerMenu& otherTriggerMenu )
88     {
89     //
90     // First clean up whatever triggers I had before
91     //
92     triggers_.clear();
93    
94     //
95     // Now copy the triggers from the other menu
96     //
97 grimes 1.3 for( std::vector< std::unique_ptr<l1menu::ITrigger> >::const_iterator iTrigger=otherTriggerMenu.triggers_.begin(); iTrigger!=otherTriggerMenu.triggers_.end(); ++iTrigger )
98 grimes 1.1 {
99     l1menu::ITrigger& sourceTrigger=**iTrigger;
100    
101 grimes 1.3 triggers_.push_back( std::move(triggerTable_.copyTrigger(sourceTrigger)) );
102 grimes 1.1 }
103    
104     // Make sure triggerResults_ is always the same size as triggers_
105     triggerResults_.resize( triggers_.size() );
106    
107     return *this;
108     }
109    
110 grimes 1.3 l1menu::TriggerMenu& l1menu::TriggerMenu::operator=( l1menu::TriggerMenu&& otherTriggerMenu ) noexcept
111     {
112     triggers_=std::move( otherTriggerMenu.triggers_ );
113     triggerResults_=std::move(otherTriggerMenu.triggerResults_);
114    
115     return *this;
116     }
117    
118 grimes 1.5 l1menu::ITrigger& l1menu::TriggerMenu::addTrigger( const std::string& triggerName )
119 grimes 1.1 {
120 grimes 1.3 std::unique_ptr<l1menu::ITrigger> pNewTrigger=triggerTable_.getTrigger( triggerName );
121 grimes 1.5 if( pNewTrigger.get()==NULL ) throw std::range_error( "Trigger requested that does not exist" );
122 grimes 1.1
123 grimes 1.3 triggers_.push_back( std::move(pNewTrigger) );
124 grimes 1.1
125     // Make sure triggerResults_ is always the same size as triggers_
126     triggerResults_.resize( triggers_.size() );
127 grimes 1.5 return *triggers_.back();
128 grimes 1.1 }
129    
130 grimes 1.5 l1menu::ITrigger& l1menu::TriggerMenu::addTrigger( const std::string& triggerName, unsigned int version )
131 grimes 1.1 {
132 grimes 1.3 std::unique_ptr<l1menu::ITrigger> pNewTrigger=triggerTable_.getTrigger( triggerName, version );
133 grimes 1.5 if( pNewTrigger.get()==NULL ) throw std::range_error( "Trigger requested that does not exist" );
134 grimes 1.1
135 grimes 1.3 triggers_.push_back( std::move(pNewTrigger) );
136 grimes 1.1
137     // Make sure triggerResults_ is always the same size as triggers_
138     triggerResults_.resize( triggers_.size() );
139 grimes 1.5 return *triggers_.back();
140 grimes 1.1 }
141    
142 grimes 1.9 l1menu::ITrigger& l1menu::TriggerMenu::addTrigger( const l1menu::ITrigger& triggerToCopy )
143     {
144     std::unique_ptr<l1menu::ITrigger> pNewTrigger=triggerTable_.copyTrigger( triggerToCopy );
145     if( pNewTrigger.get()==NULL ) throw std::range_error( "Trigger requested that does not exist" );
146    
147     triggers_.push_back( std::move(pNewTrigger) );
148    
149     // Make sure triggerResults_ is always the same size as triggers_
150     triggerResults_.resize( triggers_.size() );
151     return *triggers_.back();
152     }
153    
154 grimes 1.1 size_t l1menu::TriggerMenu::numberOfTriggers() const
155     {
156     return triggers_.size();
157     }
158    
159     l1menu::ITrigger& l1menu::TriggerMenu::getTrigger( size_t position )
160     {
161     if( position>triggers_.size() ) throw std::range_error( "Trigger requested that does not exist in the menu" );
162    
163     return *triggers_[position];
164     }
165    
166     const l1menu::ITrigger& l1menu::TriggerMenu::getTrigger( size_t position ) const
167     {
168     if( position>triggers_.size() ) throw std::range_error( "Trigger requested that does not exist in the menu" );
169    
170     return *triggers_[position];
171     }
172    
173 grimes 1.3 std::unique_ptr<l1menu::ITrigger> l1menu::TriggerMenu::getTriggerCopy( size_t position ) const
174     {
175     if( position>triggers_.size() ) throw std::range_error( "Trigger requested that does not exist in the menu" );
176    
177     return triggerTable_.copyTrigger(*triggers_[position]);
178     }
179    
180 grimes 1.9 bool l1menu::TriggerMenu::apply( const l1menu::L1TriggerDPGEvent& event ) const
181 grimes 1.1 {
182     bool atLeastOneTriggerHasFired=false;
183    
184     for( size_t triggerNumber=0; triggerNumber<triggers_.size(); ++triggerNumber )
185     {
186     bool result=triggers_[triggerNumber]->apply(event);
187     // triggerResults_[triggerNumber]=result;
188     if( result ) atLeastOneTriggerHasFired=true;
189     }
190    
191     return atLeastOneTriggerHasFired;
192     }
193    
194     void l1menu::TriggerMenu::loadMenuFromFile( const std::string& filename )
195     {
196 grimes 1.2 std::ifstream file( filename.c_str() );
197 grimes 1.1 if( !file.is_open() ) throw std::runtime_error( "Unable to open file "+filename );
198    
199     loadMenuInOldFormat( file );
200     }
201    
202     void l1menu::TriggerMenu::loadMenuInOldFormat( std::ifstream& file )
203     {
204     const size_t bufferSize=200;
205     char buffer[bufferSize];
206    
207     while( file.good() )
208     {
209     try
210     {
211     // Get one line at a time
212     file.getline( buffer, bufferSize );
213    
214     // split the line by whitespace into columns
215     std::vector<std::string> tableColumns=::splitByWhitespace( buffer );
216    
217     if( tableColumns.size()==1 && tableColumns[0].empty() ) continue; // Allow blank lines without giving a warning
218     if( tableColumns.size()!=12 ) throw std::runtime_error( "The line does not have the correct number of columns" );
219    
220     float prescale=::convertStringToFloat( tableColumns[2] );
221     if( prescale!=0 )
222     {
223 grimes 1.5 std::string triggerName=tableColumns[0];
224    
225     try
226 grimes 1.1 {
227 grimes 1.4 //std::cout << "Added trigger \"" << tableColumns[0] << "\"" << std::endl;
228 grimes 1.5 l1menu::ITrigger& newTrigger=addTrigger( triggerName ); // Try and create a trigger with the name supplied
229 grimes 1.1
230 grimes 1.8 // Different triggers will have different numbers of thresholds, and even different names. E.g. Single triggers
231     // will have "threshold1" whereas a cross trigger will have "leg1threshold1", "leg2threshold1" etcetera. This
232     // utility function will get the threshold names in the correct order.
233     const auto& thresholdNames=l1menu::tools::getThresholdNames(newTrigger);
234 grimes 1.10 if( thresholdNames.size()>=1 ) newTrigger.parameter(thresholdNames[0])=::convertStringToFloat( tableColumns[3] );
235     if( thresholdNames.size()>=2 ) newTrigger.parameter(thresholdNames[1])=::convertStringToFloat( tableColumns[4] );
236     if( thresholdNames.size()>=3 ) newTrigger.parameter(thresholdNames[2])=::convertStringToFloat( tableColumns[5] );
237     if( thresholdNames.size()>=4 ) newTrigger.parameter(thresholdNames[3])=::convertStringToFloat( tableColumns[6] );
238 grimes 1.1
239 grimes 1.5 float etaOrRegionCut=::convertStringToFloat( tableColumns[7] );
240     // For most triggers, I can just try and set both the etaCut and regionCut parameters
241     // with this value. If it doesn't have either of the parameters just catch the exception
242     // and nothing will happen. Some cross triggers however have both, and need to set them
243     // both from this value which requires a conversion. Most cross triggers expect this
244     // value to be the regionCut, except for L1_SingleMu_CJet which expects it as the etaCut.
245     if( triggerName=="L1_SingleMu_CJet" )
246     {
247 grimes 1.6 newTrigger.parameter("leg1etaCut")=etaOrRegionCut;
248 grimes 1.7 newTrigger.parameter("leg2regionCut")=l1menu::tools::convertEtaCutToRegionCut( etaOrRegionCut );
249 grimes 1.5 }
250 grimes 1.8 else if( triggerName=="L1_isoMu_EG" )
251     {
252     newTrigger.parameter("leg1etaCut")=l1menu::tools::convertRegionCutToEtaCut( etaOrRegionCut );
253     newTrigger.parameter("leg2regionCut")=etaOrRegionCut;
254     }
255     else if( triggerName=="L1_isoEG_Mu" )
256 grimes 1.5 {
257 grimes 1.6 newTrigger.parameter("leg1regionCut")=etaOrRegionCut;
258 grimes 1.8 newTrigger.parameter("leg2etaCut")=l1menu::tools::convertRegionCutToEtaCut( etaOrRegionCut );
259     }
260     else if( triggerName=="L1_isoMu_Tau" )
261     {
262     newTrigger.parameter("leg1etaCut")=l1menu::tools::convertRegionCutToEtaCut( etaOrRegionCut );
263 grimes 1.6 newTrigger.parameter("leg2regionCut")=etaOrRegionCut;
264 grimes 1.5 }
265     else
266     {
267     // Any remaining triggers should only have one of these parameters and won't
268     // need conversion. I'll just try and set them both, not a problem if one fails.
269 grimes 1.8 // The cross triggers will have e.g. "leg1" prefixed to the parameter name so I'll
270     // also try for those.
271 grimes 1.5 try{ newTrigger.parameter("etaCut")=etaOrRegionCut; }
272     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
273    
274     try{ newTrigger.parameter("regionCut")=etaOrRegionCut; }
275     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
276 grimes 1.8
277     try{ newTrigger.parameter("leg1etaCut")=etaOrRegionCut; }
278     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
279    
280     try{ newTrigger.parameter("leg1regionCut")=etaOrRegionCut; }
281     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
282    
283     try{ newTrigger.parameter("leg2etaCut")=etaOrRegionCut; }
284     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
285    
286     try{ newTrigger.parameter("leg2regionCut")=etaOrRegionCut; }
287     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
288 grimes 1.5 }
289 grimes 1.1
290 grimes 1.8 // The trigger may or may not have a muon quality cut. I also don't know if its name
291     // is prefixed with e.g. "leg1". I'll try setting all combinations, but wrap individually
292     // in a try block so that it doesn't matter if it fails.
293 grimes 1.1 try{ newTrigger.parameter("muonQuality")=::convertStringToFloat( tableColumns[8] ); }
294     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
295    
296 grimes 1.8 try{ newTrigger.parameter("leg1muonQuality")=::convertStringToFloat( tableColumns[8] ); }
297     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
298    
299     try{ newTrigger.parameter("leg2muonQuality")=::convertStringToFloat( tableColumns[8] ); }
300     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
301    
302     } // end of try block
303 grimes 1.5 catch( std::exception& error )
304     {
305     std::cerr << "Unable to add trigger \"" << tableColumns[0] << "\" because: " << error.what() << std::endl;
306     }
307 grimes 1.1 } // end of "if( prescale!=0 )"
308     } // end of try block
309     catch( std::runtime_error& exception )
310     {
311     std::cout << "Some error occured while processing the line \"" << buffer << "\":" << exception.what() << std::endl;
312     }
313     }
314     }