ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/ReducedMenuSample.cpp
Revision: 1.4
Committed: Tue Jun 4 08:17:37 2013 UTC (11 years, 11 months ago) by grimes
Branch: MAIN
Changes since 1.3: +8 -10 lines
Log Message:
Multiple changes. Implemented all required triggers, removed the ones not needed and changed some names.

File Contents

# Content
1 #include "l1menu/ReducedMenuSample.h"
2
3 #include <vector>
4 #include <stdexcept>
5 #include <fstream>
6 #include "l1menu/IReducedEvent.h"
7 #include "l1menu/MenuSample.h"
8 #include "l1menu/TriggerMenu.h"
9 #include "l1menu/ITrigger.h"
10 #include "l1menu/tools.h"
11 #include "protobuf/l1menu.pb.h"
12
13 namespace // unnamed namespace
14 {
15 class ReducedEventImplementation : public l1menu::IReducedEvent
16 {
17 public:
18 virtual ~ReducedEventImplementation() {}
19 virtual float parameterValue( size_t parameterNumber ) const { return pThresholdValues->at(parameterNumber); }
20 virtual float weight() const { return *pWeight; }
21 void setWeight( float newWeight ) { *pWeight=newWeight; }
22 std::vector<float>* pThresholdValues;
23 float* pWeight;
24 };
25 }
26
27 namespace l1menu
28 {
29 /** @brief Private members for the ReducedMenuSample class
30 *
31 * @author Mark Grimes (mark.grimes@bristol.ac.uk)
32 * @date 28/May/2013
33 */
34 class ReducedMenuSamplePrivateMembers
35 {
36 public:
37 ReducedMenuSamplePrivateMembers( size_t newNumberOfEvents, size_t numberOfParameters, const l1menu::TriggerMenu newTriggerMenu )
38 : thresholdsForAllEvents( newNumberOfEvents, std::vector<float>(numberOfParameters) ),
39 weights( newNumberOfEvents ), numberOfEvents( newNumberOfEvents ), triggerMenu( newTriggerMenu )
40 {
41 // Run through every event and default every weight to 1.
42 for( auto& eventWeight : weights )
43 {
44 eventWeight=1;
45 }
46 }
47 std::vector< std::vector<float> > thresholdsForAllEvents;
48 std::vector<float> weights;
49 ::ReducedEventImplementation event;
50 size_t numberOfEvents;
51 const l1menu::TriggerMenu triggerMenu;
52 };
53 }
54
55 #include <iostream>
56 l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
57 {
58 size_t numberOfEvents=originalSample.numberOfEvents();
59 // Need to find out how many parameters there are for each event. Basically the sum
60 // of the number of thresholds for all triggers.
61 size_t numberOfParameters=0;
62 for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
63 {
64 const l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
65 numberOfParameters+=l1menu::getThresholdNames(trigger).size();
66 }
67
68 // Now I know how many events there are and how many parameters, I can create the pimple
69 // with the correct parameters.
70 pImple_.reset( new l1menu::ReducedMenuSamplePrivateMembers( numberOfEvents, numberOfParameters, triggerMenu ) );
71
72 //
73 // Now I've set the storage to the correct size, run through each event
74 // and fill with the correct values.
75 //
76 for( size_t eventNumber=0; eventNumber<numberOfEvents; ++eventNumber )
77 {
78 const l1menu::IEvent& event=originalSample.getEvent( eventNumber );
79 std::vector<float>& parameters=pImple_->thresholdsForAllEvents[eventNumber];
80
81 size_t parameterNumber=0;
82 // Loop over all of the triggers
83 for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
84 {
85 std::unique_ptr<l1menu::ITrigger> pTrigger=triggerMenu.getTriggerCopy(triggerNumber);
86 std::vector<std::string> thresholdNames=getThresholdNames(*pTrigger);
87
88 try
89 {
90 setTriggerThresholdsAsTightAsPossible( event, *pTrigger, 0.001 );
91 // Set all of the parameters to match the thresholds in the trigger
92 for( const auto& thresholdName : thresholdNames )
93 {
94 parameters[parameterNumber]=pTrigger->parameter(thresholdName);
95 ++parameterNumber;
96 }
97 }
98 catch( std::exception& error )
99 {
100 // setTriggerThresholdsAsTightAsPossible() couldn't find thresholds so record
101 // -1 for everything.
102 for( size_t index=0; index<thresholdNames.size(); ++index )
103 {
104 parameters[parameterNumber]=-1;
105 ++parameterNumber;
106 }
107 } // end of try block that sets the trigger thresholds
108
109 } // end of loop over triggers
110 } // end of loop over events
111 }
112
113 l1menu::ReducedMenuSample::~ReducedMenuSample()
114 {
115 // No operation. Just need one defined otherwise the default one messes up
116 // the unique_ptr deletion because ReducedMenuSamplePrivateMembers isn't
117 // defined elsewhere.
118 }
119
120 l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
121 {
122 GOOGLE_PROTOBUF_VERIFY_VERSION;
123
124 l1menuprotobuf::Sample inputSample;
125 { // new block to limit scope of variables
126 std::ifstream inputFile( filename );
127 inputSample.ParseFromIstream( &inputFile );
128 }
129
130 l1menu::TriggerMenu triggerMenu;
131
132 size_t totalNumberOfThresholds=0;
133
134 for( int triggerNumber=0; triggerNumber<inputSample.trigger_size(); ++triggerNumber )
135 {
136 const l1menuprotobuf::Trigger& inputTrigger=inputSample.trigger(triggerNumber);
137
138 triggerMenu.addTrigger( inputTrigger.name(), inputTrigger.version() );
139 // Get a reference to the trigger I just created
140 l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
141
142 // Run through all of the parameters and set them to what they were
143 // when the sample was made.
144 for( int parameterNumber=0; parameterNumber<inputTrigger.parameter_size(); ++parameterNumber )
145 {
146 const auto& inputParameter=inputTrigger.parameter(parameterNumber);
147 trigger.parameter(inputParameter.name())=inputParameter.value();
148 }
149
150 // I should probably check the threshold names exist. At the moment I just see how
151 // many there are so that I can initialise the buffer that holds the event data.
152 totalNumberOfThresholds+=inputTrigger.threshold_size();
153 }
154
155 // Now I have the menu set up as much as I need it (thresholds aren't set
156 // but I don't care about those). I can initialise the ReducedMenuSamplePrivateMembers
157 // pImple_ with the menu and the correct sizes for the data buffer.
158 pImple_.reset( new l1menu::ReducedMenuSamplePrivateMembers( inputSample.event_size(), totalNumberOfThresholds, triggerMenu ) );
159
160 // Now run over each event from the input file
161 for( int eventNumber=0; eventNumber<inputSample.event_size(); ++eventNumber )
162 {
163 auto& thresholdsForEvent=pImple_->thresholdsForAllEvents[eventNumber];
164 const auto& inputEvent=inputSample.event(eventNumber);
165
166 for( int thresholdNumber=0; thresholdNumber<inputEvent.threshold_size(); ++thresholdNumber )
167 {
168 thresholdsForEvent[thresholdNumber]=inputEvent.threshold(thresholdNumber);
169 }
170
171 // See if the weight was stored and set it if it has
172 if( inputEvent.has_weight() ) pImple_->weights[eventNumber]=inputEvent.weight();
173 }
174 }
175
176 void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
177 {
178 GOOGLE_PROTOBUF_VERIFY_VERSION;
179
180 l1menuprotobuf::Sample outputSample;
181
182 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
183 {
184 const l1menu::ITrigger& trigger=pImple_->triggerMenu.getTrigger(triggerNumber);
185
186 l1menuprotobuf::Trigger* pOutputTrigger=outputSample.add_trigger();
187 pOutputTrigger->set_name( trigger.name() );
188 pOutputTrigger->set_version( trigger.version() );
189
190 // Record all of the parameters. It's not strictly necessary to record the values
191 // of the parameters that are recorded for each event, but I might as well so that
192 // the trigger menu is loaded exactly as it was saved.
193 const auto parameterNames=trigger.parameterNames();
194 for( const auto& parameterName : parameterNames )
195 {
196 l1menuprotobuf::Trigger_TriggerParameter* pOutputParameter=pOutputTrigger->add_parameter();
197 pOutputParameter->set_name(parameterName);
198 pOutputParameter->set_value( trigger.parameter(parameterName) );
199 }
200
201 // Make a note of the names of the parameters that are recorded for each event.
202 const auto thresholdNames=l1menu::getThresholdNames(trigger);
203 for( const auto& thresholdName : thresholdNames ) pOutputTrigger->add_threshold(thresholdName);
204
205 } // end of loop over triggers
206
207 //
208 // I've done everything for what is effectively the header. I now need
209 // to run through each event and record the thresholds for each one.
210 //
211 for( const auto& thresholdsForEvent : pImple_->thresholdsForAllEvents )
212 {
213 l1menuprotobuf::Event* pOutputEvent=outputSample.add_event();
214 for( const auto& threshold : thresholdsForEvent )
215 {
216 pOutputEvent->add_threshold( threshold );
217 }
218 }
219
220 // I should have the correct number of events in the protobuf version of
221 // the sample now. I'll run through and set the event weights as well, but
222 // I'll only add it if it's different to 1. I think this saves space in
223 // the file.
224 for( int eventNumber=0; eventNumber<outputSample.event_size(); ++eventNumber )
225 {
226 if( pImple_->weights[eventNumber]!=1 )
227 {
228 l1menuprotobuf::Event* pOutputEvent=outputSample.mutable_event(eventNumber);
229 pOutputEvent->set_weight( pImple_->weights[eventNumber] );
230 }
231 }
232
233
234 //
235 // Everything should be set up in the class now, so I can open the
236 // output file and write to it.
237 //
238 std::ofstream outputFile( filename );
239 outputSample.SerializeToOstream( &outputFile );
240 }
241
242 size_t l1menu::ReducedMenuSample::numberOfEvents() const
243 {
244 return pImple_->numberOfEvents;
245 }
246
247 const l1menu::IReducedEvent& l1menu::ReducedMenuSample::getEvent( size_t eventNumber ) const
248 {
249 pImple_->event.pThresholdValues=&pImple_->thresholdsForAllEvents[eventNumber];
250 pImple_->event.pWeight=&pImple_->weights[eventNumber];
251 return pImple_->event;
252 }
253
254 const l1menu::TriggerMenu& l1menu::ReducedMenuSample::getTriggerMenu() const
255 {
256 return pImple_->triggerMenu;
257 }
258
259 bool l1menu::ReducedMenuSample::containsTrigger( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
260 {
261 // Loop over all of the triggers in the menu, and see if there is one
262 // where the name and version match.
263 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
264 {
265 const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
266 if( triggerInMenu.name()!=trigger.name() ) continue;
267 if( allowOlderVersion )
268 {
269 if( triggerInMenu.version()>trigger.version() ) continue;
270 }
271 else
272 {
273 if( triggerInMenu.version()!=trigger.version() ) continue;
274 }
275
276 // If control got this far then there is a trigger with the required name
277 // and sufficient version. I now need to check all of the non threshold parameters
278 // to make sure they match, i.e. make sure the ReducedSample was made with the same
279 // eta cuts or whatever.
280 // I don't care if the thresholds don't match because that's what's stored in the
281 // ReducedMenuSample.
282 std::vector<std::string> parameterNames=getNonThresholdParameterNames( trigger );
283 bool allParametersMatch=true;
284 for( const auto& parameterName : parameterNames )
285 {
286 if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) allParametersMatch=false;
287 }
288
289 if( allParametersMatch ) return true;
290 } // end of loop over triggers
291
292 // If control got this far then no trigger was found that matched
293 return false;
294 }
295
296 const std::map<std::string,size_t> l1menu::ReducedMenuSample::getTriggerParameterIdentifiers( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
297 {
298 std::map<std::string,size_t> returnValue;
299
300 // Need to find out how many parameters there are for each event. Basically the sum
301 // of the number of thresholds for all triggers.
302 size_t parameterNumber=0;
303 bool triggerWasFound=true;
304 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
305 {
306 const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
307
308 triggerWasFound=true; // Set to true, then back to false if any of the tests fail
309 // See if this trigger in the menu is the same as the one passed as a parameter
310 if( triggerInMenu.name()!=trigger.name() ) triggerWasFound=false;
311 if( allowOlderVersion )
312 {
313 if( triggerInMenu.version()>trigger.version() ) triggerWasFound=false;
314 }
315 else
316 {
317 if( triggerInMenu.version()!=trigger.version() ) triggerWasFound=false;
318 }
319
320 // If control got this far then there is a trigger with the required name
321 // and sufficient version. I now need to check all of the non threshold parameters
322 // to make sure they match, i.e. make sure the ReducedSample was made with the same
323 // eta cuts or whatever.
324 // I don't care if the thresholds don't match because that's what's stored in the
325 // ReducedMenuSample.
326 if( triggerWasFound ) // Trigger can still fail, but no point doing this check if it already has
327 {
328 std::vector<std::string> parameterNames=getNonThresholdParameterNames( trigger );
329 for( const auto& parameterName : parameterNames )
330 {
331 if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) triggerWasFound=false;
332 }
333 }
334
335 std::vector<std::string> thresholdNames=l1menu::getThresholdNames(triggerInMenu);
336 if( triggerWasFound )
337 {
338 for( const auto& thresholdName : thresholdNames )
339 {
340 returnValue[thresholdName]=parameterNumber;
341 ++parameterNumber;
342 }
343 break;
344 }
345 else parameterNumber+=thresholdNames.size();
346 }
347
348 // There could conceivably be a trigger that was found but has no thresholds
349 // (I guess - it would be a pretty pointless trigger though). To indicate the
350 // difference between that and a trigger that wasn't found I'll respectively
351 // return the empty vector or throw an exception.
352 if( !triggerWasFound ) throw std::runtime_error( "l1menu::ReducedMenuSample::getTriggerParameterIdentifiers() called for a trigger that was not used to create the sample" );
353
354 return returnValue;
355 }