ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/ReducedMenuSample.cpp
Revision: 1.3
Committed: Sun Jun 2 22:40:57 2013 UTC (11 years, 11 months ago) by grimes
Branch: MAIN
Changes since 1.2: +4 -0 lines
Log Message:
A few changes, and added skeleton files for all of the triggers.

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