ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/ReducedMenuSample.cpp
(Generate patch)

Comparing UserCode/grimes/L1Menu/src/ReducedMenuSample.cpp (file contents):
Revision 1.4 by grimes, Tue Jun 4 08:17:37 2013 UTC vs.
Revision 1.9 by grimes, Sat Jun 8 09:31:25 2013 UTC

# Line 2 | Line 2
2  
3   #include <vector>
4   #include <stdexcept>
5 < #include <fstream>
5 > #include <fcntl.h>
6 > #include <algorithm>
7 > #include <iostream>
8   #include "l1menu/IReducedEvent.h"
9   #include "l1menu/MenuSample.h"
10   #include "l1menu/TriggerMenu.h"
11   #include "l1menu/ITrigger.h"
12   #include "l1menu/tools.h"
13   #include "protobuf/l1menu.pb.h"
14 + #include <google/protobuf/io/zero_copy_stream_impl.h>
15 + #include <google/protobuf/io/gzip_stream.h>
16  
17   namespace // unnamed namespace
18   {
# Line 16 | Line 20 | namespace // unnamed namespace
20          {
21          public:
22                  virtual ~ReducedEventImplementation() {}
23 <                virtual float parameterValue( size_t parameterNumber ) const {  return pThresholdValues->at(parameterNumber); }
24 <                virtual float weight() const { return *pWeight; }
25 <                void setWeight( float newWeight ) { *pWeight=newWeight; }
26 <                std::vector<float>* pThresholdValues;
27 <                float* pWeight;
23 >                virtual float parameterValue( size_t parameterNumber ) const {  return pProtobufEvent->threshold(parameterNumber); }
24 >                virtual float weight() const { if( pProtobufEvent->has_weight() ) return pProtobufEvent->weight(); else return 1; }
25 >                void setWeight( float newWeight ) { pProtobufEvent->set_weight(newWeight); }
26 >                l1menuprotobuf::Event* pProtobufEvent;
27 >        };
28 >
29 >        /** @brief Sentry that closes a Unix file descriptor when it goes out of scope.
30 >         * @author Mark Grimes (mark.grimes@bristol.ac.uk)
31 >         * @date 07/Jun/2013
32 >         */
33 >        class UnixFileSentry
34 >        {
35 >        public:
36 >                UnixFileSentry( int fileDescriptor ) : fileDescriptor_(fileDescriptor) {}
37 >                ~UnixFileSentry() { close(fileDescriptor_); }
38 >        private:
39 >                int fileDescriptor_;
40          };
41   }
42  
# Line 33 | Line 49 | namespace l1menu
49           */
50          class ReducedMenuSamplePrivateMembers
51          {
52 +        private:
53 +                l1menu::TriggerMenu mutableTriggerMenu_;
54          public:
55 <                ReducedMenuSamplePrivateMembers( size_t newNumberOfEvents, size_t numberOfParameters, const l1menu::TriggerMenu newTriggerMenu )
56 <                        : thresholdsForAllEvents( newNumberOfEvents, std::vector<float>(numberOfParameters) ),
57 <                          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;
55 >                ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu );
56 >                ReducedMenuSamplePrivateMembers( const std::string& filename );
57 >                void copyMenuToProtobufSample();
58                  ::ReducedEventImplementation event;
59 <                size_t numberOfEvents;
60 <                const l1menu::TriggerMenu triggerMenu;
59 >                const l1menu::TriggerMenu& triggerMenu;
60 >                l1menuprotobuf::SampleHeader protobufSampleHeader;
61 >                // Protobuf doesn't implement move semantics so I'll use pointers
62 >                std::vector<std::unique_ptr<l1menuprotobuf::Run> > protobufRuns;
63 >                const static int EVENTS_PER_RUN;
64 >                const static char PROTOBUF_MESSAGE_DELIMETER;
65 >                const static std::string FILE_FORMAT_MAGIC_NUMBER;
66          };
67 +
68 +        const int ReducedMenuSamplePrivateMembers::EVENTS_PER_RUN=20000;
69 +        const char ReducedMenuSamplePrivateMembers::PROTOBUF_MESSAGE_DELIMETER='\n';
70 +        const std::string ReducedMenuSamplePrivateMembers::FILE_FORMAT_MAGIC_NUMBER="l1menuReducedMenuSample";
71   }
72  
73 < #include <iostream>
74 < l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
73 > l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu )
74 >        : mutableTriggerMenu_( newTriggerMenu ), triggerMenu( mutableTriggerMenu_ )
75   {
76 <        size_t numberOfEvents=originalSample.numberOfEvents();
77 <        // Need to find out how many parameters there are for each event. Basically the sum
78 <        // of the number of thresholds for all triggers.
79 <        size_t numberOfParameters=0;
76 >        GOOGLE_PROTOBUF_VERIFY_VERSION;
77 >
78 >        // I need to copy the details of the trigger menu into the protobuf storage.
79 >        // This means I'm holding a duplicate, but I need it to write the sample to a
80 >        // protobuf file, so I might as well do it now.
81          for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
82          {
83                  const l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
65                numberOfParameters+=l1menu::getThresholdNames(trigger).size();
66        }
84  
85 <        // Now I know how many events there are and how many parameters, I can create the pimple
86 <        // with the correct parameters.
87 <        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];
85 >                l1menuprotobuf::Trigger* pProtobufTrigger=protobufSampleHeader.add_trigger();
86 >                pProtobufTrigger->set_name( trigger.name() );
87 >                pProtobufTrigger->set_version( trigger.version() );
88  
89 <                size_t parameterNumber=0;
90 <                // Loop over all of the triggers
91 <                for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
89 >                // Record all of the parameters. It's not strictly necessary to record the values
90 >                // of the parameters that are recorded for each event, but I might as well so that
91 >                // the trigger menu is loaded exactly as it was saved.
92 >                const auto parameterNames=trigger.parameterNames();
93 >                for( const auto& parameterName : parameterNames )
94                  {
95 <                        std::unique_ptr<l1menu::ITrigger> pTrigger=triggerMenu.getTriggerCopy(triggerNumber);
96 <                        std::vector<std::string> thresholdNames=getThresholdNames(*pTrigger);
95 >                        l1menuprotobuf::Trigger_TriggerParameter* pProtobufParameter=pProtobufTrigger->add_parameter();
96 >                        pProtobufParameter->set_name(parameterName);
97 >                        pProtobufParameter->set_value( trigger.parameter(parameterName) );
98 >                }
99  
100 <                        try
101 <                        {
102 <                                setTriggerThresholdsAsTightAsPossible( event, *pTrigger, 0.001 );
103 <                                // 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
100 >                // Make a note of the names of the parameters that are recorded for each event. For this
101 >                // I'm just recording the parameters that refer to the thresholds.
102 >                const auto thresholdNames=l1menu::getThresholdNames(trigger);
103 >                for( const auto& thresholdName : thresholdNames ) pProtobufTrigger->add_varying_parameter(thresholdName);
104  
105 <                } // end of loop over triggers
106 <        } // end of loop over events
107 < }
105 >        } // end of loop over triggers
106 >
107 >        // Always make sure there is at least one Run ready to be added to
108 >        std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
109 >        protobufRuns.push_back( std::move( pNewRun ) );
110  
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.
111   }
112  
113 < l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
113 > l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const std::string& filename )
114 >        : triggerMenu(mutableTriggerMenu_)
115   {
116          GOOGLE_PROTOBUF_VERIFY_VERSION;
117  
118 <        l1menuprotobuf::Sample inputSample;
119 <        { // new block to limit scope of variables
120 <                std::ifstream inputFile( filename );
121 <                inputSample.ParseFromIstream( &inputFile );
118 >        // Open the file with read ability
119 >        int fileDescriptor = open( filename.c_str(), O_RDONLY );
120 >        if( fileDescriptor==0 ) throw std::runtime_error( "ReducedMenuSample initialise from file - couldn't open file" );
121 >        ::UnixFileSentry fileSentry( fileDescriptor ); // Use this as an exception safe way of closing the input file
122 >        google::protobuf::io::FileInputStream fileInput( fileDescriptor );
123 >        google::protobuf::io::GzipInputStream gzipInput( &fileInput );
124 >        google::protobuf::io::CodedInputStream codedInput( &gzipInput );
125 >
126 >        // Disable warnings on this input stream (second parameter, -1). The
127 >        // first parameter is the default. I'll change this if necessary in
128 >        // the loop later.
129 >        size_t totalBytesLimit=67108864;
130 >        codedInput.SetTotalBytesLimit( totalBytesLimit, -1 );
131 >
132 >        // First read the magic number at the start of the file and make sure it
133 >        // matches what I expect. As a read buffer, I'll create a string the correct
134 >        // size (filled with an arbitrary character) and read straight into that.
135 >        std::string readMagicNumber;
136 >        if( !codedInput.ReadString( &readMagicNumber, FILE_FORMAT_MAGIC_NUMBER.size() ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading magic number" );
137 >        if( readMagicNumber!=FILE_FORMAT_MAGIC_NUMBER ) throw std::runtime_error( "ReducedMenuSample - tried to initialise with a file that is not the correct format" );
138 >
139 >        google::protobuf::uint32 fileformatVersion;
140 >        if( !codedInput.ReadVarint32( &fileformatVersion ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading file format version" );
141 >        // So far I only have (and ever expect to have) one version of the file
142 >        // format, imaginatively versioned "1". You never know though...
143 >        if( fileformatVersion>1 ) std::cerr << "Warning: Attempting to read a ReducedMenuSample with version " << fileformatVersion << " with code that only knows up to version 1." << std::endl;
144 >
145 >        google::protobuf::uint64 messageSize;
146 >
147 >        // Read the size of the header message
148 >        if( !codedInput.ReadVarint64( &messageSize ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading message size for header" );
149 >        google::protobuf::io::CodedInputStream::Limit readLimit=codedInput.PushLimit(messageSize);
150 >        if( !protobufSampleHeader.ParseFromCodedStream( &codedInput ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - some unknown error while reading header" );
151 >        codedInput.PopLimit(readLimit);
152 >
153 >        // Keep looping until there is nothing more to be read from the file.
154 >        while( codedInput.ReadVarint64( &messageSize ) )
155 >        {
156 >                readLimit=codedInput.PushLimit(messageSize);
157 >
158 >                // Make sure the CodedInputStream doesn't refuse to read the message because it's
159 >                // read too much already. I'll also add an arbitrary 50 on to always make sure
160 >                // I can read the next messageSize if there is one.
161 >                if( gzipInput.ByteCount()+messageSize+50 > totalBytesLimit )
162 >                {
163 >                        totalBytesLimit+=messageSize*5; // Might as well set it a little higher than necessary while I'm at it.
164 >                        codedInput.SetTotalBytesLimit( totalBytesLimit, -1 );
165 >                }
166 >                std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
167 >                if( !pNewRun->ParseFromCodedStream( &codedInput ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - some unknown error while reading run" );
168 >                protobufRuns.push_back( std::move( pNewRun ) );
169 >
170 >                codedInput.PopLimit(readLimit);
171          }
172  
130        l1menu::TriggerMenu triggerMenu;
173  
174 <        size_t totalNumberOfThresholds=0;
174 >        // Always make sure there is at least one Run ready to be added to. Later
175 >        // code assumes there is already a run there.
176 >        if( protobufRuns.empty() )
177 >        {
178 >                std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
179 >                protobufRuns.push_back( std::move( pNewRun ) );
180 >        }
181  
182 <        for( int triggerNumber=0; triggerNumber<inputSample.trigger_size(); ++triggerNumber )
182 >        // I have all of the information in the protobuf members, but I also need the trigger information
183 >        // in the form of l1menu::TriggerMenu. Copy out the required information.
184 >        for( int triggerNumber=0; triggerNumber<protobufSampleHeader.trigger_size(); ++triggerNumber )
185          {
186 <                const l1menuprotobuf::Trigger& inputTrigger=inputSample.trigger(triggerNumber);
186 >                const l1menuprotobuf::Trigger& inputTrigger=protobufSampleHeader.trigger(triggerNumber);
187  
188 <                triggerMenu.addTrigger( inputTrigger.name(), inputTrigger.version() );
188 >                mutableTriggerMenu_.addTrigger( inputTrigger.name(), inputTrigger.version() );
189                  // Get a reference to the trigger I just created
190 <                l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
190 >                l1menu::ITrigger& trigger=mutableTriggerMenu_.getTrigger(triggerNumber);
191  
192                  // Run through all of the parameters and set them to what they were
193                  // when the sample was made.
# Line 147 | Line 197 | l1menu::ReducedMenuSample::ReducedMenuSa
197                          trigger.parameter(inputParameter.name())=inputParameter.value();
198                  }
199  
200 <                // 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();
200 >                // I should probably check the threshold names exist. I'll do it another time.
201          }
202  
203 <        // 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);
203 > }
204  
205 <                for( int thresholdNumber=0; thresholdNumber<inputEvent.threshold_size(); ++thresholdNumber )
206 <                {
207 <                        thresholdsForEvent[thresholdNumber]=inputEvent.threshold(thresholdNumber);
208 <                }
205 > l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
206 >        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
207 > {
208 >        addSample( originalSample );
209 > }
210  
211 <                // See if the weight was stored and set it if it has
212 <                if( inputEvent.has_weight() ) pImple_->weights[eventNumber]=inputEvent.weight();
213 <        }
211 > l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::TriggerMenu& triggerMenu )
212 >        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
213 > {
214 >        // No operation besides the initialiser list
215   }
216  
217 < void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
217 > l1menu::ReducedMenuSample::~ReducedMenuSample()
218   {
219 <        GOOGLE_PROTOBUF_VERIFY_VERSION;
219 >        // No operation. Just need one defined otherwise the default one messes up
220 >        // the unique_ptr deletion because ReducedMenuSamplePrivateMembers isn't
221 >        // defined elsewhere.
222 > }
223  
224 <        l1menuprotobuf::Sample outputSample;
224 > void l1menu::ReducedMenuSample::addSample( const l1menu::MenuSample& originalSample )
225 > {
226 >        l1menuprotobuf::Run* pCurrentRun=pImple_->protobufRuns.back().get();
227  
228 <        for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
228 >        for( size_t eventNumber=0; eventNumber<originalSample.numberOfEvents(); ++eventNumber )
229          {
230 <                const l1menu::ITrigger& trigger=pImple_->triggerMenu.getTrigger(triggerNumber);
230 >                // Split the events up into groups in arbitrary numbers. This is to get around
231 >                // a protobuf aversion to long messages.
232 >                if( pCurrentRun->event_size() >= pImple_->EVENTS_PER_RUN )
233 >                {
234 >                        // Gone over the arbitrary limit, so create a new protobuf Run and start
235 >                        // using that instead.
236 >                        std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
237 >                        pImple_->protobufRuns.push_back( std::move( pNewRun ) );
238 >                        pCurrentRun=pImple_->protobufRuns.back().get();
239 >                }
240  
241 <                l1menuprotobuf::Trigger* pOutputTrigger=outputSample.add_trigger();
242 <                pOutputTrigger->set_name( trigger.name() );
188 <                pOutputTrigger->set_version( trigger.version() );
241 >                const l1menu::IEvent& event=originalSample.getEvent( eventNumber );
242 >                l1menuprotobuf::Event* pProtobufEvent=pCurrentRun->add_event();
243  
244 <                // Record all of the parameters. It's not strictly necessary to record the values
245 <                // 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 )
244 >                // Loop over all of the triggers
245 >                for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
246                  {
247 <                        l1menuprotobuf::Trigger_TriggerParameter* pOutputParameter=pOutputTrigger->add_parameter();
248 <                        pOutputParameter->set_name(parameterName);
198 <                        pOutputParameter->set_value( trigger.parameter(parameterName) );
199 <                }
247 >                        std::unique_ptr<l1menu::ITrigger> pTrigger=pImple_->triggerMenu.getTriggerCopy(triggerNumber);
248 >                        std::vector<std::string> thresholdNames=getThresholdNames(*pTrigger);
249  
250 <                // Make a note of the names of the parameters that are recorded for each event.
251 <                const auto thresholdNames=l1menu::getThresholdNames(trigger);
252 <                for( const auto& thresholdName : thresholdNames ) pOutputTrigger->add_threshold(thresholdName);
250 >                        try
251 >                        {
252 >                                setTriggerThresholdsAsTightAsPossible( event, *pTrigger, 0.001 );
253 >                                // Set all of the parameters to match the thresholds in the trigger
254 >                                for( const auto& thresholdName : thresholdNames )
255 >                                {
256 >                                        pProtobufEvent->add_threshold( pTrigger->parameter(thresholdName) );
257 >                                }
258 >                        }
259 >                        catch( std::exception& error )
260 >                        {
261 >                                // setTriggerThresholdsAsTightAsPossible() couldn't find thresholds so record
262 >                                // -1 for everything.
263 >                                // Range based for loop gives me a warning because I don't use the thresholdName.
264 >                                for( size_t index=0; index<thresholdNames.size(); ++index ) pProtobufEvent->add_threshold(-1);
265 >                        } // end of try block that sets the trigger thresholds
266  
267 <        } // end of loop over triggers
267 >                } // end of loop over triggers
268  
269 <        //
270 <        // I've done everything for what is effectively the header. I now need
271 <        // to run through each event and record the thresholds for each one.
272 <        //
273 <        for( const auto& thresholdsForEvent : pImple_->thresholdsForAllEvents )
274 <        {
275 <                l1menuprotobuf::Event* pOutputEvent=outputSample.add_event();
276 <                for( const auto& threshold : thresholdsForEvent )
277 <                {
278 <                        pOutputEvent->add_threshold( threshold );
279 <                }
280 <        }
269 >        } // end of loop over events
270 > }
271 >
272 > l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
273 >        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( filename ) )
274 > {
275 >        // No operation except the initialiser list
276 > }
277 >
278 > void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
279 > {
280 >        // Open the file. Parameters are filename, write ability and create, rw-r--r-- permissions.
281 >        int fileDescriptor = open( filename.c_str(), O_WRONLY | O_CREAT, 0644 );
282 >        if( fileDescriptor==0 ) throw std::runtime_error( "ReducedMenuSample save to file - couldn't open file" );
283 >        ::UnixFileSentry fileSentry( fileDescriptor ); // Use this as an exception safe way of closing the output file
284 >
285 >        // Setup the protobuf file handlers
286 >        google::protobuf::io::FileOutputStream fileOutput( fileDescriptor );
287 >        google::protobuf::io::GzipOutputStream gzipOutput( &fileOutput );
288 >        google::protobuf::io::CodedOutputStream codedOutput( &gzipOutput );
289 >
290 >        // Write a magic number at the start of all files
291 >        codedOutput.WriteString( pImple_->FILE_FORMAT_MAGIC_NUMBER );
292 >        // Write an integer that specifies what version of the file format I'm using. I
293 >        // have no intention of changing the format but I might as well keep the option
294 >        // open.
295 >        codedOutput.WriteVarint32( 1 );
296 >
297 >        // Write the size of the header message into the file...
298 >        codedOutput.WriteVarint64( pImple_->protobufSampleHeader.ByteSize() );
299 >        // ...and then write the header
300 >        pImple_->protobufSampleHeader.SerializeToCodedStream( &codedOutput );
301  
302 <        // I should have the correct number of events in the protobuf version of
303 <        // 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 )
302 >        // Now go through each of the runs and do the same for those
303 >        for( const auto& pRun : pImple_->protobufRuns )
304          {
305 <                if( pImple_->weights[eventNumber]!=1 )
306 <                {
228 <                        l1menuprotobuf::Event* pOutputEvent=outputSample.mutable_event(eventNumber);
229 <                        pOutputEvent->set_weight( pImple_->weights[eventNumber] );
230 <                }
305 >                codedOutput.WriteVarint64( pRun->ByteSize() );
306 >                pRun->SerializeToCodedStream( &codedOutput );
307          }
308  
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 );
309   }
310  
311   size_t l1menu::ReducedMenuSample::numberOfEvents() const
312   {
313 <        return pImple_->numberOfEvents;
313 >        size_t numberOfEvents=0;
314 >        for( const auto& pRun : pImple_->protobufRuns ) numberOfEvents+=pRun->event_size();
315 >        return numberOfEvents;
316   }
317  
318   const l1menu::IReducedEvent& l1menu::ReducedMenuSample::getEvent( size_t eventNumber ) const
319   {
320 <        pImple_->event.pThresholdValues=&pImple_->thresholdsForAllEvents[eventNumber];
321 <        pImple_->event.pWeight=&pImple_->weights[eventNumber];
322 <        return pImple_->event;
320 >        for( const auto& pRun : pImple_->protobufRuns )
321 >        {
322 >                if( eventNumber<static_cast<size_t>(pRun->event_size()) )
323 >                {
324 >                        pImple_->event.pProtobufEvent=pRun->mutable_event(eventNumber);
325 >                        return pImple_->event;
326 >                }
327 >                // Event must be in a later run, so reduce the number by how many events
328 >                // were in this run and look again.
329 >                eventNumber-=pRun->event_size();
330 >        }
331 >
332 >        // Should always find the event before getting to this point, so throw an
333 >        // exception if this happens.
334 >        throw std::runtime_error( "ReducedMenuSample::getEvent(eventNumber) was asked for an invalid eventNumber" );
335   }
336  
337   const l1menu::TriggerMenu& l1menu::ReducedMenuSample::getTriggerMenu() const

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines