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 |
< |
|
9 |
> |
#include "l1menu/tools/stringManipulation.h" |
10 |
|
|
11 |
|
l1menu::TriggerMenu::TriggerMenu() : triggerTable_( l1menu::TriggerTable::instance() ) |
12 |
|
{ |
94 |
|
return *triggers_.back(); |
95 |
|
} |
96 |
|
|
97 |
+ |
l1menu::ITrigger& l1menu::TriggerMenu::addTrigger( const l1menu::ITrigger& triggerToCopy ) |
98 |
+ |
{ |
99 |
+ |
std::unique_ptr<l1menu::ITrigger> pNewTrigger=triggerTable_.copyTrigger( triggerToCopy ); |
100 |
+ |
if( pNewTrigger.get()==NULL ) throw std::range_error( "Trigger requested that does not exist" ); |
101 |
+ |
|
102 |
+ |
triggers_.push_back( std::move(pNewTrigger) ); |
103 |
+ |
|
104 |
+ |
// Make sure triggerResults_ is always the same size as triggers_ |
105 |
+ |
triggerResults_.resize( triggers_.size() ); |
106 |
+ |
return *triggers_.back(); |
107 |
+ |
} |
108 |
+ |
|
109 |
|
size_t l1menu::TriggerMenu::numberOfTriggers() const |
110 |
|
{ |
111 |
|
return triggers_.size(); |
132 |
|
return triggerTable_.copyTrigger(*triggers_[position]); |
133 |
|
} |
134 |
|
|
135 |
< |
bool l1menu::TriggerMenu::apply( const l1menu::IEvent& event ) const |
135 |
> |
bool l1menu::TriggerMenu::apply( const l1menu::L1TriggerDPGEvent& event ) const |
136 |
|
{ |
137 |
|
bool atLeastOneTriggerHasFired=false; |
138 |
|
|
167 |
|
file.getline( buffer, bufferSize ); |
168 |
|
|
169 |
|
// split the line by whitespace into columns |
170 |
< |
std::vector<std::string> tableColumns=::splitByWhitespace( buffer ); |
170 |
> |
std::vector<std::string> tableColumns=l1menu::tools::splitByWhitespace( buffer ); |
171 |
|
|
172 |
|
if( tableColumns.size()==1 && tableColumns[0].empty() ) continue; // Allow blank lines without giving a warning |
173 |
|
if( tableColumns.size()!=12 ) throw std::runtime_error( "The line does not have the correct number of columns" ); |
174 |
|
|
175 |
< |
float prescale=::convertStringToFloat( tableColumns[2] ); |
209 |
< |
if( prescale!=0 ) |
210 |
< |
{ |
211 |
< |
std::string triggerName=tableColumns[0]; |
175 |
> |
addTriggerFromOldFormat( tableColumns ); |
176 |
|
|
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 )" |
177 |
|
} // end of try block |
178 |
|
catch( std::runtime_error& exception ) |
179 |
|
{ |
181 |
|
} |
182 |
|
} |
183 |
|
} |
184 |
+ |
|
185 |
+ |
bool l1menu::TriggerMenu::addTriggerFromOldFormat( const std::vector<std::string>& columns ) |
186 |
+ |
{ |
187 |
+ |
bool successful=false; |
188 |
+ |
|
189 |
+ |
if( columns.size()<9 ) throw std::runtime_error( "There are not enough columns" ); |
190 |
+ |
|
191 |
+ |
float prescale=l1menu::tools::convertStringToFloat( columns[2] ); |
192 |
+ |
if( prescale!=0 ) |
193 |
+ |
{ |
194 |
+ |
std::string triggerName=columns[0]; |
195 |
+ |
|
196 |
+ |
try |
197 |
+ |
{ |
198 |
+ |
//std::cout << "Added trigger \"" << columns[0] << "\"" << std::endl; |
199 |
+ |
l1menu::ITrigger& newTrigger=addTrigger( triggerName ); // Try and create a trigger with the name supplied |
200 |
+ |
successful=true; |
201 |
+ |
|
202 |
+ |
// Different triggers will have different numbers of thresholds, and even different names. E.g. Single triggers |
203 |
+ |
// will have "threshold1" whereas a cross trigger will have "leg1threshold1", "leg2threshold1" etcetera. This |
204 |
+ |
// utility function will get the threshold names in the correct order. |
205 |
+ |
const auto& thresholdNames=l1menu::tools::getThresholdNames(newTrigger); |
206 |
+ |
if( thresholdNames.size()>=1 ) newTrigger.parameter(thresholdNames[0])=l1menu::tools::convertStringToFloat( columns[3] ); |
207 |
+ |
if( thresholdNames.size()>=2 ) newTrigger.parameter(thresholdNames[1])=l1menu::tools::convertStringToFloat( columns[4] ); |
208 |
+ |
if( thresholdNames.size()>=3 ) newTrigger.parameter(thresholdNames[2])=l1menu::tools::convertStringToFloat( columns[5] ); |
209 |
+ |
if( thresholdNames.size()>=4 ) newTrigger.parameter(thresholdNames[3])=l1menu::tools::convertStringToFloat( columns[6] ); |
210 |
+ |
|
211 |
+ |
float etaOrRegionCut=l1menu::tools::convertStringToFloat( columns[7] ); |
212 |
+ |
// For most triggers, I can just try and set both the etaCut and regionCut parameters |
213 |
+ |
// with this value. If it doesn't have either of the parameters just catch the exception |
214 |
+ |
// and nothing will happen. Some cross triggers however have both, and need to set them |
215 |
+ |
// both from this value which requires a conversion. Most cross triggers expect this |
216 |
+ |
// value to be the regionCut, except for L1_SingleMu_CJet which expects it as the etaCut. |
217 |
+ |
if( triggerName=="L1_SingleMu_CJet" ) |
218 |
+ |
{ |
219 |
+ |
newTrigger.parameter("leg1etaCut")=etaOrRegionCut; |
220 |
+ |
newTrigger.parameter("leg2regionCut")=l1menu::tools::convertEtaCutToRegionCut( etaOrRegionCut ); |
221 |
+ |
} |
222 |
+ |
else if( triggerName=="L1_isoMu_EG" ) |
223 |
+ |
{ |
224 |
+ |
newTrigger.parameter("leg1etaCut")=l1menu::tools::convertRegionCutToEtaCut( etaOrRegionCut ); |
225 |
+ |
newTrigger.parameter("leg2regionCut")=etaOrRegionCut; |
226 |
+ |
} |
227 |
+ |
else if( triggerName=="L1_isoEG_Mu" ) |
228 |
+ |
{ |
229 |
+ |
newTrigger.parameter("leg1regionCut")=etaOrRegionCut; |
230 |
+ |
newTrigger.parameter("leg2etaCut")=l1menu::tools::convertRegionCutToEtaCut( etaOrRegionCut ); |
231 |
+ |
} |
232 |
+ |
else if( triggerName=="L1_isoMu_Tau" ) |
233 |
+ |
{ |
234 |
+ |
newTrigger.parameter("leg1etaCut")=l1menu::tools::convertRegionCutToEtaCut( etaOrRegionCut ); |
235 |
+ |
newTrigger.parameter("leg2regionCut")=etaOrRegionCut; |
236 |
+ |
} |
237 |
+ |
else |
238 |
+ |
{ |
239 |
+ |
// Any remaining triggers should only have one of these parameters and won't |
240 |
+ |
// need conversion. I'll just try and set them both, not a problem if one fails. |
241 |
+ |
// The cross triggers will have e.g. "leg1" prefixed to the parameter name so I'll |
242 |
+ |
// also try for those. |
243 |
+ |
try{ newTrigger.parameter("etaCut")=etaOrRegionCut; } |
244 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
245 |
+ |
|
246 |
+ |
try{ newTrigger.parameter("regionCut")=etaOrRegionCut; } |
247 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
248 |
+ |
|
249 |
+ |
try{ newTrigger.parameter("leg1etaCut")=etaOrRegionCut; } |
250 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
251 |
+ |
|
252 |
+ |
try{ newTrigger.parameter("leg1regionCut")=etaOrRegionCut; } |
253 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
254 |
+ |
|
255 |
+ |
try{ newTrigger.parameter("leg2etaCut")=etaOrRegionCut; } |
256 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
257 |
+ |
|
258 |
+ |
try{ newTrigger.parameter("leg2regionCut")=etaOrRegionCut; } |
259 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
260 |
+ |
} |
261 |
+ |
|
262 |
+ |
// The trigger may or may not have a muon quality cut. I also don't know if its name |
263 |
+ |
// is prefixed with e.g. "leg1". I'll try setting all combinations, but wrap individually |
264 |
+ |
// in a try block so that it doesn't matter if it fails. |
265 |
+ |
try{ newTrigger.parameter("muonQuality")=l1menu::tools::convertStringToFloat( columns[8] ); } |
266 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
267 |
+ |
|
268 |
+ |
try{ newTrigger.parameter("leg1muonQuality")=l1menu::tools::convertStringToFloat( columns[8] ); } |
269 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
270 |
+ |
|
271 |
+ |
try{ newTrigger.parameter("leg2muonQuality")=l1menu::tools::convertStringToFloat( columns[8] ); } |
272 |
+ |
catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters |
273 |
+ |
|
274 |
+ |
} // end of try block |
275 |
+ |
catch( std::exception& error ) |
276 |
+ |
{ |
277 |
+ |
std::cerr << "Unable to add trigger \"" << columns[0] << "\" because: " << error.what() << std::endl; |
278 |
+ |
} |
279 |
+ |
} // end of "if( prescale!=0 )" |
280 |
+ |
|
281 |
+ |
return successful; |
282 |
+ |
} |