ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/ReducedMenuSample.cpp
Revision: 1.7
Committed: Thu Jun 6 15:05:04 2013 UTC (11 years, 11 months ago) by grimes
Branch: MAIN
Changes since 1.6: +87 -219 lines
Log Message:
Improved memory performance. Had to copy L1UpgradeNtuple.C into this package to fix some leaks.

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.7 #include <algorithm>
7 grimes 1.1 #include "l1menu/IReducedEvent.h"
8     #include "l1menu/MenuSample.h"
9     #include "l1menu/TriggerMenu.h"
10 grimes 1.2 #include "l1menu/ITrigger.h"
11 grimes 1.1 #include "l1menu/tools.h"
12 grimes 1.2 #include "protobuf/l1menu.pb.h"
13 grimes 1.1
14     namespace // unnamed namespace
15     {
16     class ReducedEventImplementation : public l1menu::IReducedEvent
17     {
18     public:
19     virtual ~ReducedEventImplementation() {}
20 grimes 1.7 virtual float parameterValue( size_t parameterNumber ) const { return pProtobufEvent->threshold(parameterNumber); }
21     virtual float weight() const { if( pProtobufEvent->has_weight() ) return pProtobufEvent->weight(); else return 1; }
22     void setWeight( float newWeight ) { pProtobufEvent->set_weight(newWeight); }
23     l1menuprotobuf::Event* pProtobufEvent;
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 grimes 1.7 private:
37     l1menu::TriggerMenu mutableTriggerMenu_;
38 grimes 1.1 public:
39 grimes 1.7 ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu );
40     ReducedMenuSamplePrivateMembers( const std::string& filename );
41     void copyMenuToProtobufSample();
42 grimes 1.1 ::ReducedEventImplementation event;
43 grimes 1.7 const l1menu::TriggerMenu& triggerMenu;
44     l1menuprotobuf::Sample protobufSample;
45 grimes 1.1 };
46     }
47    
48 grimes 1.7 l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu )
49     : mutableTriggerMenu_( newTriggerMenu ), triggerMenu( mutableTriggerMenu_ )
50 grimes 1.1 {
51 grimes 1.7 GOOGLE_PROTOBUF_VERIFY_VERSION;
52    
53     // I need to copy the details of the trigger menu into the protobuf storage.
54     // This means I'm holding a duplicate, but I need it to write the Sample message
55     // so I might as well do it now.
56 grimes 1.1 for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
57     {
58     const l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
59 grimes 1.7
60     l1menuprotobuf::Trigger* pProtobufTrigger=protobufSample.add_trigger();
61     pProtobufTrigger->set_name( trigger.name() );
62     pProtobufTrigger->set_version( trigger.version() );
63    
64     // Record all of the parameters. It's not strictly necessary to record the values
65     // of the parameters that are recorded for each event, but I might as well so that
66     // the trigger menu is loaded exactly as it was saved.
67     const auto parameterNames=trigger.parameterNames();
68     for( const auto& parameterName : parameterNames )
69     {
70     l1menuprotobuf::Trigger_TriggerParameter* pProtobufParameter=pProtobufTrigger->add_parameter();
71     pProtobufParameter->set_name(parameterName);
72     pProtobufParameter->set_value( trigger.parameter(parameterName) );
73     }
74    
75     // Make a note of the names of the parameters that are recorded for each event. For this
76     // I'm just recording the parameters that refer to the thresholds.
77     const auto thresholdNames=l1menu::getThresholdNames(trigger);
78     for( const auto& thresholdName : thresholdNames ) pProtobufTrigger->add_threshold(thresholdName);
79    
80     } // end of loop over triggers
81    
82     }
83    
84     l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const std::string& filename )
85     : triggerMenu(mutableTriggerMenu_)
86     {
87     GOOGLE_PROTOBUF_VERIFY_VERSION;
88    
89     { // new block to limit scope of variables, so that the file is closed immediately after reading
90     std::ifstream inputFile( filename );
91     protobufSample.ParseFromIstream( &inputFile );
92 grimes 1.1 }
93    
94 grimes 1.7
95     // I have all of the information in the protobuf Sample, but I also need the trigger information
96     // in the form of l1menu::TriggerMenu. Copy out the required information.
97     for( int triggerNumber=0; triggerNumber<protobufSample.trigger_size(); ++triggerNumber )
98 grimes 1.2 {
99 grimes 1.7 const l1menuprotobuf::Trigger& inputTrigger=protobufSample.trigger(triggerNumber);
100    
101     mutableTriggerMenu_.addTrigger( inputTrigger.name(), inputTrigger.version() );
102     // Get a reference to the trigger I just created
103     l1menu::ITrigger& trigger=mutableTriggerMenu_.getTrigger(triggerNumber);
104 grimes 1.2
105 grimes 1.7 // Run through all of the parameters and set them to what they were
106     // when the sample was made.
107     for( int parameterNumber=0; parameterNumber<inputTrigger.parameter_size(); ++parameterNumber )
108 grimes 1.2 {
109 grimes 1.7 const auto& inputParameter=inputTrigger.parameter(parameterNumber);
110     trigger.parameter(inputParameter.name())=inputParameter.value();
111     }
112    
113     // I should probably check the threshold names exist. I'll do it another time.
114     }
115 grimes 1.2
116 grimes 1.7 }
117 grimes 1.2
118 grimes 1.7 l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
119     : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
120     {
121     addSample( originalSample );
122 grimes 1.2 }
123    
124 grimes 1.5 l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::TriggerMenu& triggerMenu )
125 grimes 1.7 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
126 grimes 1.5 {
127 grimes 1.7 // No operation besides the initialiser list
128 grimes 1.5 }
129    
130 grimes 1.2 l1menu::ReducedMenuSample::~ReducedMenuSample()
131     {
132     // No operation. Just need one defined otherwise the default one messes up
133     // the unique_ptr deletion because ReducedMenuSamplePrivateMembers isn't
134     // defined elsewhere.
135     }
136    
137 grimes 1.5 void l1menu::ReducedMenuSample::addSample( const l1menu::MenuSample& originalSample )
138     {
139     for( size_t eventNumber=0; eventNumber<originalSample.numberOfEvents(); ++eventNumber )
140     {
141     const l1menu::IEvent& event=originalSample.getEvent( eventNumber );
142 grimes 1.7 l1menuprotobuf::Event* pProtobufEvent=pImple_->protobufSample.add_event();
143 grimes 1.5
144     // Loop over all of the triggers
145     for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
146     {
147     std::unique_ptr<l1menu::ITrigger> pTrigger=pImple_->triggerMenu.getTriggerCopy(triggerNumber);
148     std::vector<std::string> thresholdNames=getThresholdNames(*pTrigger);
149    
150     try
151     {
152     setTriggerThresholdsAsTightAsPossible( event, *pTrigger, 0.001 );
153     // Set all of the parameters to match the thresholds in the trigger
154     for( const auto& thresholdName : thresholdNames )
155     {
156 grimes 1.7 pProtobufEvent->add_threshold( pTrigger->parameter(thresholdName) );
157 grimes 1.5 }
158     }
159     catch( std::exception& error )
160     {
161     // setTriggerThresholdsAsTightAsPossible() couldn't find thresholds so record
162     // -1 for everything.
163 grimes 1.7 // Range based for loop gives me a warning because I don't use the thresholdName.
164     for( size_t index=0; index<thresholdNames.size(); ++index ) pProtobufEvent->add_threshold(-1);
165 grimes 1.5 } // end of try block that sets the trigger thresholds
166    
167     } // end of loop over triggers
168 grimes 1.7
169 grimes 1.5 } // end of loop over events
170     }
171    
172 grimes 1.2 l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
173 grimes 1.7 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( filename ) )
174 grimes 1.2 {
175 grimes 1.7 // No operation except the initialiser list
176 grimes 1.2 }
177    
178     void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
179     {
180     std::ofstream outputFile( filename );
181 grimes 1.7 pImple_->protobufSample.SerializeToOstream( &outputFile );
182 grimes 1.1 }
183    
184     size_t l1menu::ReducedMenuSample::numberOfEvents() const
185     {
186 grimes 1.7 return pImple_->protobufSample.event_size();
187 grimes 1.1 }
188    
189     const l1menu::IReducedEvent& l1menu::ReducedMenuSample::getEvent( size_t eventNumber ) const
190     {
191 grimes 1.7 pImple_->event.pProtobufEvent=pImple_->protobufSample.mutable_event(eventNumber);
192 grimes 1.1 return pImple_->event;
193     }
194 grimes 1.2
195     const l1menu::TriggerMenu& l1menu::ReducedMenuSample::getTriggerMenu() const
196     {
197     return pImple_->triggerMenu;
198     }
199    
200     bool l1menu::ReducedMenuSample::containsTrigger( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
201     {
202     // Loop over all of the triggers in the menu, and see if there is one
203     // where the name and version match.
204     for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
205     {
206     const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
207     if( triggerInMenu.name()!=trigger.name() ) continue;
208     if( allowOlderVersion )
209     {
210     if( triggerInMenu.version()>trigger.version() ) continue;
211     }
212     else
213     {
214     if( triggerInMenu.version()!=trigger.version() ) continue;
215     }
216    
217     // If control got this far then there is a trigger with the required name
218     // and sufficient version. I now need to check all of the non threshold parameters
219     // to make sure they match, i.e. make sure the ReducedSample was made with the same
220     // eta cuts or whatever.
221     // I don't care if the thresholds don't match because that's what's stored in the
222     // ReducedMenuSample.
223     std::vector<std::string> parameterNames=getNonThresholdParameterNames( trigger );
224     bool allParametersMatch=true;
225     for( const auto& parameterName : parameterNames )
226     {
227     if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) allParametersMatch=false;
228     }
229    
230     if( allParametersMatch ) return true;
231     } // end of loop over triggers
232    
233     // If control got this far then no trigger was found that matched
234     return false;
235     }
236    
237     const std::map<std::string,size_t> l1menu::ReducedMenuSample::getTriggerParameterIdentifiers( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
238     {
239     std::map<std::string,size_t> returnValue;
240    
241     // Need to find out how many parameters there are for each event. Basically the sum
242     // of the number of thresholds for all triggers.
243     size_t parameterNumber=0;
244     bool triggerWasFound=true;
245     for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
246     {
247     const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
248    
249     triggerWasFound=true; // Set to true, then back to false if any of the tests fail
250     // See if this trigger in the menu is the same as the one passed as a parameter
251     if( triggerInMenu.name()!=trigger.name() ) triggerWasFound=false;
252     if( allowOlderVersion )
253     {
254     if( triggerInMenu.version()>trigger.version() ) triggerWasFound=false;
255     }
256     else
257     {
258     if( triggerInMenu.version()!=trigger.version() ) triggerWasFound=false;
259     }
260    
261     // If control got this far then there is a trigger with the required name
262     // and sufficient version. I now need to check all of the non threshold parameters
263     // to make sure they match, i.e. make sure the ReducedSample was made with the same
264     // eta cuts or whatever.
265     // I don't care if the thresholds don't match because that's what's stored in the
266     // ReducedMenuSample.
267     if( triggerWasFound ) // Trigger can still fail, but no point doing this check if it already has
268     {
269     std::vector<std::string> parameterNames=getNonThresholdParameterNames( trigger );
270     for( const auto& parameterName : parameterNames )
271     {
272     if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) triggerWasFound=false;
273     }
274     }
275    
276 grimes 1.4 std::vector<std::string> thresholdNames=l1menu::getThresholdNames(triggerInMenu);
277 grimes 1.2 if( triggerWasFound )
278     {
279     for( const auto& thresholdName : thresholdNames )
280     {
281     returnValue[thresholdName]=parameterNumber;
282     ++parameterNumber;
283     }
284     break;
285     }
286     else parameterNumber+=thresholdNames.size();
287     }
288    
289     // There could conceivably be a trigger that was found but has no thresholds
290     // (I guess - it would be a pretty pointless trigger though). To indicate the
291     // difference between that and a trigger that wasn't found I'll respectively
292     // return the empty vector or throw an exception.
293     if( !triggerWasFound ) throw std::runtime_error( "l1menu::ReducedMenuSample::getTriggerParameterIdentifiers() called for a trigger that was not used to create the sample" );
294    
295     return returnValue;
296     }