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

# User Rev Content
1 grimes 1.1 #include "l1menu/ReducedMenuSample.h"
2    
3     #include <vector>
4 grimes 1.2 #include <stdexcept>
5     #include <fstream>
6 grimes 1.1 #include "l1menu/IReducedEvent.h"
7     #include "l1menu/MenuSample.h"
8     #include "l1menu/TriggerMenu.h"
9 grimes 1.2 #include "l1menu/ITrigger.h"
10 grimes 1.1 #include "l1menu/tools.h"
11 grimes 1.2 #include "protobuf/l1menu.pb.h"
12 grimes 1.1
13     namespace // unnamed namespace
14     {
15     class ReducedEventImplementation : public l1menu::IReducedEvent
16     {
17     public:
18     virtual ~ReducedEventImplementation() {}
19 grimes 1.4 virtual float parameterValue( size_t parameterNumber ) const { return pThresholdValues->at(parameterNumber); }
20 grimes 1.2 virtual float weight() const { return *pWeight; }
21     void setWeight( float newWeight ) { *pWeight=newWeight; }
22 grimes 1.1 std::vector<float>* pThresholdValues;
23 grimes 1.2 float* pWeight;
24 grimes 1.1 };
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 grimes 1.2 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 grimes 1.1 {
41 grimes 1.2 // Run through every event and default every weight to 1.
42     for( auto& eventWeight : weights )
43     {
44     eventWeight=1;
45     }
46 grimes 1.1 }
47     std::vector< std::vector<float> > thresholdsForAllEvents;
48 grimes 1.2 std::vector<float> weights;
49 grimes 1.1 ::ReducedEventImplementation event;
50     size_t numberOfEvents;
51 grimes 1.2 const l1menu::TriggerMenu triggerMenu;
52 grimes 1.1 };
53     }
54    
55 grimes 1.3 #include <iostream>
56 grimes 1.1 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 grimes 1.2 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 grimes 1.4 // many there are so that I can initialise the buffer that holds the event data.
152 grimes 1.2 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 grimes 1.4 // 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 grimes 1.2 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 grimes 1.4 // Make a note of the names of the parameters that are recorded for each event.
202 grimes 1.2 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 grimes 1.1 }
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 grimes 1.2 pImple_->event.pWeight=&pImple_->weights[eventNumber];
251 grimes 1.1 return pImple_->event;
252     }
253 grimes 1.2
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 grimes 1.4 std::vector<std::string> thresholdNames=l1menu::getThresholdNames(triggerInMenu);
336 grimes 1.2 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     }