ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/TriggerMenu.cpp
Revision: 1.8
Committed: Mon Jun 24 16:25:26 2013 UTC (11 years, 10 months ago) by grimes
Branch: MAIN
Changes since 1.7: +43 -15 lines
Log Message:
Fixes to the menu loading

File Contents

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