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

# 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     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 grimes 1.3 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 grimes 1.1 {
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 grimes 1.2 std::ifstream file( filename.c_str() );
185 grimes 1.1 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 grimes 1.5 std::string triggerName=tableColumns[0];
212    
213     try
214 grimes 1.1 {
215 grimes 1.4 //std::cout << "Added trigger \"" << tableColumns[0] << "\"" << std::endl;
216 grimes 1.5 l1menu::ITrigger& newTrigger=addTrigger( triggerName ); // Try and create a trigger with the name supplied
217 grimes 1.1
218 grimes 1.8 // 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 grimes 1.1
227 grimes 1.5 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 grimes 1.6 newTrigger.parameter("leg1etaCut")=etaOrRegionCut;
236 grimes 1.7 newTrigger.parameter("leg2regionCut")=l1menu::tools::convertEtaCutToRegionCut( etaOrRegionCut );
237 grimes 1.5 }
238 grimes 1.8 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 grimes 1.5 {
245 grimes 1.6 newTrigger.parameter("leg1regionCut")=etaOrRegionCut;
246 grimes 1.8 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 grimes 1.6 newTrigger.parameter("leg2regionCut")=etaOrRegionCut;
252 grimes 1.5 }
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 grimes 1.8 // The cross triggers will have e.g. "leg1" prefixed to the parameter name so I'll
258     // also try for those.
259 grimes 1.5 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 grimes 1.8
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 grimes 1.5 }
277 grimes 1.1
278 grimes 1.8 // 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 grimes 1.1 try{ newTrigger.parameter("muonQuality")=::convertStringToFloat( tableColumns[8] ); }
282     catch( std::exception& error ) { } // Do nothing, just try and convert the other parameters
283    
284 grimes 1.8 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 grimes 1.5 catch( std::exception& error )
292     {
293     std::cerr << "Unable to add trigger \"" << tableColumns[0] << "\" because: " << error.what() << std::endl;
294     }
295 grimes 1.1 } // 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     }