ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/ReducedMenuSample.cpp
Revision: 1.12
Committed: Mon Jun 24 17:09:05 2013 UTC (11 years, 10 months ago) by grimes
Branch: MAIN
Changes since 1.11: +35 -20 lines
Log Message:
Change to the ReducedSample fileformat so that the magic number and fileformat identifier are uncompressed

File Contents

# Content
1 #include "l1menu/ReducedMenuSample.h"
2
3 #include <vector>
4 #include <stdexcept>
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/IMenuRate.h"
13 #include "l1menu/ITriggerRate.h"
14 #include "l1menu/tools/tools.h"
15 #include "protobuf/l1menu.pb.h"
16 #include <google/protobuf/io/zero_copy_stream_impl.h>
17 #include <google/protobuf/io/gzip_stream.h>
18
19 namespace // unnamed namespace
20 {
21 class ReducedEventImplementation : public l1menu::IReducedEvent
22 {
23 public:
24 virtual ~ReducedEventImplementation() {}
25 virtual float parameterValue( size_t parameterNumber ) const { return pProtobufEvent->threshold(parameterNumber); }
26 virtual float weight() const { if( pProtobufEvent->has_weight() ) return pProtobufEvent->weight(); else return 1; }
27 void setWeight( float newWeight ) { pProtobufEvent->set_weight(newWeight); }
28 l1menuprotobuf::Event* pProtobufEvent;
29 };
30
31 /** @brief Sentry that closes a Unix file descriptor when it goes out of scope.
32 * @author Mark Grimes (mark.grimes@bristol.ac.uk)
33 * @date 07/Jun/2013
34 */
35 class UnixFileSentry
36 {
37 public:
38 UnixFileSentry( int fileDescriptor ) : fileDescriptor_(fileDescriptor) {}
39 ~UnixFileSentry() { close(fileDescriptor_); }
40 private:
41 int fileDescriptor_;
42 };
43
44 class MenuRateImplementation;
45
46 class TriggerRateImplementation : public l1menu::ITriggerRate
47 {
48 public:
49 TriggerRateImplementation( const l1menu::ITrigger& trigger, float fraction, const MenuRateImplementation& menuRate );
50 TriggerRateImplementation& operator=( TriggerRateImplementation&& otherTriggerRate ); // Move assignment
51 virtual ~TriggerRateImplementation();
52
53 // Methods required by the l1menu::ITriggerRate interface
54 virtual const l1menu::ITrigger& trigger() const;
55 virtual float fraction() const;
56 virtual float rate() const;
57 protected:
58 std::unique_ptr<l1menu::ITrigger> pTrigger_;
59 float fraction_;
60 const MenuRateImplementation& menuRate_;
61 };
62
63 class MenuRateImplementation : public l1menu::IMenuRate
64 {
65 public:
66 void setTotalFraction( float fraction ) { totalFraction_=fraction; }
67 void setScaling( float scaling ) { scaling_=scaling; }
68 float scaling() const { return scaling_; }
69 void addTriggerRate( const l1menu::ITrigger& trigger, float fraction ) { triggerRates_.push_back( std::move(TriggerRateImplementation(trigger,fraction,*this)) ); }
70 // Methods required by the l1menu::IMenuRate interface
71 virtual float totalFraction() const { return totalFraction_; }
72 virtual float totalRate() const { return totalFraction_*scaling_; }
73 virtual const std::vector<const l1menu::ITriggerRate*>& triggerRates() const
74 {
75 // If the sizes are the same I'll assume nothing has changed and the references
76 // are still valid. I don't expect this method to be called until the triggerRates_
77 // vector is complete anyway.
78 if( triggerRates_.size()!=baseClassReferences_.size() )
79 {
80 baseClassReferences_.clear();
81 for( const auto& triggerRate : triggerRates_ )
82 {
83 baseClassReferences_.push_back( &triggerRate );
84 }
85 }
86
87 return baseClassReferences_;
88 }
89
90 protected:
91 float totalFraction_;
92 float scaling_;
93 std::vector<TriggerRateImplementation> triggerRates_;
94 mutable std::vector<const l1menu::ITriggerRate*> baseClassReferences_;
95 };
96
97 TriggerRateImplementation::TriggerRateImplementation( const l1menu::ITrigger& trigger, float fraction, const MenuRateImplementation& menuRate )
98 : fraction_(fraction), menuRate_(menuRate)
99 {
100 pTrigger_=std::move( l1menu::TriggerTable::instance().copyTrigger(trigger) );
101 }
102 TriggerRateImplementation& TriggerRateImplementation::operator=( TriggerRateImplementation&& otherTriggerRate )
103 {
104 pTrigger_=std::move( otherTriggerRate.pTrigger_ );
105 fraction_=otherTriggerRate.fraction_;
106 // I can't change the menuRate_ reference, but that should already be set to the right one anyway.
107 return *this;
108 }
109 TriggerRateImplementation::~TriggerRateImplementation() {}
110 const l1menu::ITrigger& TriggerRateImplementation::trigger() const { return *pTrigger_; }
111 float TriggerRateImplementation::fraction() const { return fraction_; }
112 float TriggerRateImplementation::rate() const { return fraction_*menuRate_.scaling(); }
113
114 }
115
116 namespace l1menu
117 {
118 /** @brief Private members for the ReducedMenuSample class
119 *
120 * @author Mark Grimes (mark.grimes@bristol.ac.uk)
121 * @date 28/May/2013
122 */
123 class ReducedMenuSamplePrivateMembers
124 {
125 private:
126 l1menu::TriggerMenu mutableTriggerMenu_;
127 public:
128 ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu );
129 ReducedMenuSamplePrivateMembers( const std::string& filename );
130 void copyMenuToProtobufSample();
131 ::ReducedEventImplementation event;
132 const l1menu::TriggerMenu& triggerMenu; // External const access to mutableTriggerMenu_
133 float eventRate;
134 l1menuprotobuf::SampleHeader protobufSampleHeader;
135 // Protobuf doesn't implement move semantics so I'll use pointers
136 std::vector<std::unique_ptr<l1menuprotobuf::Run> > protobufRuns;
137 const static int EVENTS_PER_RUN;
138 const static char PROTOBUF_MESSAGE_DELIMETER;
139 const static std::string FILE_FORMAT_MAGIC_NUMBER;
140 };
141
142 const int ReducedMenuSamplePrivateMembers::EVENTS_PER_RUN=20000;
143 const char ReducedMenuSamplePrivateMembers::PROTOBUF_MESSAGE_DELIMETER='\n';
144 const std::string ReducedMenuSamplePrivateMembers::FILE_FORMAT_MAGIC_NUMBER="l1menuReducedMenuSample";
145 }
146
147 l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu )
148 : mutableTriggerMenu_( newTriggerMenu ), triggerMenu( mutableTriggerMenu_ ), eventRate(1)
149 {
150 GOOGLE_PROTOBUF_VERIFY_VERSION;
151
152 // I need to copy the details of the trigger menu into the protobuf storage.
153 // This means I'm holding a duplicate, but I need it to write the sample to a
154 // protobuf file, so I might as well do it now.
155 for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
156 {
157 const l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
158
159 l1menuprotobuf::Trigger* pProtobufTrigger=protobufSampleHeader.add_trigger();
160 pProtobufTrigger->set_name( trigger.name() );
161 pProtobufTrigger->set_version( trigger.version() );
162
163 // Record all of the parameters. It's not strictly necessary to record the values
164 // of the parameters that are recorded for each event, but I might as well so that
165 // the trigger menu is loaded exactly as it was saved.
166 const auto parameterNames=trigger.parameterNames();
167 for( const auto& parameterName : parameterNames )
168 {
169 l1menuprotobuf::Trigger_TriggerParameter* pProtobufParameter=pProtobufTrigger->add_parameter();
170 pProtobufParameter->set_name(parameterName);
171 pProtobufParameter->set_value( trigger.parameter(parameterName) );
172 }
173
174 // Make a note of the names of the parameters that are recorded for each event. For this
175 // I'm just recording the parameters that refer to the thresholds.
176 const auto thresholdNames=l1menu::tools::getThresholdNames(trigger);
177 for( const auto& thresholdName : thresholdNames ) pProtobufTrigger->add_varying_parameter(thresholdName);
178
179 } // end of loop over triggers
180
181 // Always make sure there is at least one Run ready to be added to
182 std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
183 protobufRuns.push_back( std::move( pNewRun ) );
184
185 }
186
187 l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const std::string& filename )
188 : triggerMenu(mutableTriggerMenu_)
189 {
190 GOOGLE_PROTOBUF_VERIFY_VERSION;
191
192 // Open the file with read ability
193 int fileDescriptor = open( filename.c_str(), O_RDONLY );
194 if( fileDescriptor==0 ) throw std::runtime_error( "ReducedMenuSample initialise from file - couldn't open file" );
195 ::UnixFileSentry fileSentry( fileDescriptor ); // Use this as an exception safe way of closing the input file
196 google::protobuf::io::FileInputStream fileInput( fileDescriptor );
197
198 // First read the magic number at the start of the file and make sure it
199 // matches what I expect. This is uncompressed so I'll wrap it in a block
200 // to make sure the CodedInputStream is destructed before creating a new
201 // one with gzip input.
202 {
203 google::protobuf::io::CodedInputStream codedInput( &fileInput );
204
205 // As a read buffer, I'll create a string the correct size (filled with an arbitrary
206 // character) and read straight into that.
207 std::string readMagicNumber;
208 if( !codedInput.ReadString( &readMagicNumber, FILE_FORMAT_MAGIC_NUMBER.size() ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading magic number" );
209 if( readMagicNumber!=FILE_FORMAT_MAGIC_NUMBER ) throw std::runtime_error( "ReducedMenuSample - tried to initialise with a file that is not the correct format" );
210
211 google::protobuf::uint32 fileformatVersion;
212 if( !codedInput.ReadVarint32( &fileformatVersion ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading file format version" );
213 // So far I only have (and ever expect to have) one version of the file
214 // format, imaginatively versioned "1". You never know though...
215 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;
216 }
217
218 google::protobuf::io::GzipInputStream gzipInput( &fileInput );
219 google::protobuf::io::CodedInputStream codedInput( &gzipInput );
220
221 // Disable warnings on this input stream (second parameter, -1). The
222 // first parameter is the default. I'll change this if necessary in
223 // the loop later.
224 size_t totalBytesLimit=67108864;
225 codedInput.SetTotalBytesLimit( totalBytesLimit, -1 );
226
227 google::protobuf::uint64 messageSize;
228
229 // Read the size of the header message
230 if( !codedInput.ReadVarint64( &messageSize ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading message size for header" );
231 google::protobuf::io::CodedInputStream::Limit readLimit=codedInput.PushLimit(messageSize);
232 if( !protobufSampleHeader.ParseFromCodedStream( &codedInput ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - some unknown error while reading header" );
233 codedInput.PopLimit(readLimit);
234
235 // Keep looping until there is nothing more to be read from the file.
236 while( codedInput.ReadVarint64( &messageSize ) )
237 {
238 readLimit=codedInput.PushLimit(messageSize);
239
240 // Make sure the CodedInputStream doesn't refuse to read the message because it's
241 // read too much already. I'll also add an arbitrary 50 on to always make sure
242 // I can read the next messageSize if there is one.
243 if( gzipInput.ByteCount()+messageSize+50 > totalBytesLimit )
244 {
245 totalBytesLimit+=messageSize*5; // Might as well set it a little higher than necessary while I'm at it.
246 codedInput.SetTotalBytesLimit( totalBytesLimit, -1 );
247 }
248 std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
249 if( !pNewRun->ParseFromCodedStream( &codedInput ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - some unknown error while reading run" );
250 protobufRuns.push_back( std::move( pNewRun ) );
251
252 codedInput.PopLimit(readLimit);
253 }
254
255
256 // Always make sure there is at least one Run ready to be added to. Later
257 // code assumes there is already a run there.
258 if( protobufRuns.empty() )
259 {
260 std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
261 protobufRuns.push_back( std::move( pNewRun ) );
262 }
263
264 // I have all of the information in the protobuf members, but I also need the trigger information
265 // in the form of l1menu::TriggerMenu. Copy out the required information.
266 for( int triggerNumber=0; triggerNumber<protobufSampleHeader.trigger_size(); ++triggerNumber )
267 {
268 const l1menuprotobuf::Trigger& inputTrigger=protobufSampleHeader.trigger(triggerNumber);
269
270 mutableTriggerMenu_.addTrigger( inputTrigger.name(), inputTrigger.version() );
271 // Get a reference to the trigger I just created
272 l1menu::ITrigger& trigger=mutableTriggerMenu_.getTrigger(triggerNumber);
273
274 // Run through all of the parameters and set them to what they were
275 // when the sample was made.
276 for( int parameterNumber=0; parameterNumber<inputTrigger.parameter_size(); ++parameterNumber )
277 {
278 const auto& inputParameter=inputTrigger.parameter(parameterNumber);
279 trigger.parameter(inputParameter.name())=inputParameter.value();
280 }
281
282 // I should probably check the threshold names exist. I'll do it another time.
283 }
284
285 }
286
287 l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
288 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
289 {
290 addSample( originalSample );
291 }
292
293 l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::TriggerMenu& triggerMenu )
294 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
295 {
296 // No operation besides the initialiser list
297 }
298
299 l1menu::ReducedMenuSample::~ReducedMenuSample()
300 {
301 // No operation. Just need one defined otherwise the default one messes up
302 // the unique_ptr deletion because ReducedMenuSamplePrivateMembers isn't
303 // defined elsewhere.
304 }
305
306 void l1menu::ReducedMenuSample::addSample( const l1menu::MenuSample& originalSample )
307 {
308 l1menuprotobuf::Run* pCurrentRun=pImple_->protobufRuns.back().get();
309
310 for( size_t eventNumber=0; eventNumber<originalSample.numberOfEvents(); ++eventNumber )
311 {
312 // Split the events up into groups in arbitrary numbers. This is to get around
313 // a protobuf aversion to long messages.
314 if( pCurrentRun->event_size() >= pImple_->EVENTS_PER_RUN )
315 {
316 // Gone over the arbitrary limit, so create a new protobuf Run and start
317 // using that instead.
318 std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
319 pImple_->protobufRuns.push_back( std::move( pNewRun ) );
320 pCurrentRun=pImple_->protobufRuns.back().get();
321 }
322
323 const l1menu::IEvent& event=originalSample.getEvent( eventNumber );
324 l1menuprotobuf::Event* pProtobufEvent=pCurrentRun->add_event();
325
326 // Loop over all of the triggers
327 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
328 {
329 std::unique_ptr<l1menu::ITrigger> pTrigger=pImple_->triggerMenu.getTriggerCopy(triggerNumber);
330 std::vector<std::string> thresholdNames=l1menu::tools::getThresholdNames(*pTrigger);
331
332 try
333 {
334 l1menu::tools::setTriggerThresholdsAsTightAsPossible( event, *pTrigger, 0.001 );
335 // Set all of the parameters to match the thresholds in the trigger
336 for( const auto& thresholdName : thresholdNames )
337 {
338 pProtobufEvent->add_threshold( pTrigger->parameter(thresholdName) );
339 }
340 }
341 catch( std::exception& error )
342 {
343 // setTriggerThresholdsAsTightAsPossible() couldn't find thresholds so record
344 // -1 for everything.
345 // Range based for loop gives me a warning because I don't use the thresholdName.
346 for( size_t index=0; index<thresholdNames.size(); ++index ) pProtobufEvent->add_threshold(-1);
347 } // end of try block that sets the trigger thresholds
348
349 } // end of loop over triggers
350
351 } // end of loop over events
352 }
353
354 l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
355 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( filename ) )
356 {
357 // No operation except the initialiser list
358 }
359
360 void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
361 {
362 // Open the file. Parameters are filename, write ability and create, rw-r--r-- permissions.
363 int fileDescriptor = open( filename.c_str(), O_WRONLY | O_CREAT, 0644 );
364 if( fileDescriptor==0 ) throw std::runtime_error( "ReducedMenuSample save to file - couldn't open file" );
365 ::UnixFileSentry fileSentry( fileDescriptor ); // Use this as an exception safe way of closing the output file
366
367 // Setup the protobuf file handlers
368 google::protobuf::io::FileOutputStream fileOutput( fileDescriptor );
369
370 // I want the magic number and file format identifier uncompressed, so
371 // I'll write those before switching to using gzipped output.
372 { // Block to make sure codedOutput is destructed before the gzip version is created
373 google::protobuf::io::CodedOutputStream codedOutput( &fileOutput );
374
375 // Write a magic number at the start of all files
376 codedOutput.WriteString( pImple_->FILE_FORMAT_MAGIC_NUMBER );
377 // Write an integer that specifies what version of the file format I'm using. I
378 // have no intention of changing the format but I might as well keep the option
379 // open.
380 codedOutput.WriteVarint32( 1 );
381 }
382
383 google::protobuf::io::GzipOutputStream gzipOutput( &fileOutput );
384 google::protobuf::io::CodedOutputStream codedOutput( &gzipOutput );
385
386 // Write the size of the header message into the file...
387 codedOutput.WriteVarint64( pImple_->protobufSampleHeader.ByteSize() );
388 // ...and then write the header
389 pImple_->protobufSampleHeader.SerializeToCodedStream( &codedOutput );
390
391 // Now go through each of the runs and do the same for those
392 for( const auto& pRun : pImple_->protobufRuns )
393 {
394 codedOutput.WriteVarint64( pRun->ByteSize() );
395 pRun->SerializeToCodedStream( &codedOutput );
396 }
397
398 }
399
400 size_t l1menu::ReducedMenuSample::numberOfEvents() const
401 {
402 size_t numberOfEvents=0;
403 for( const auto& pRun : pImple_->protobufRuns ) numberOfEvents+=pRun->event_size();
404 return numberOfEvents;
405 }
406
407 const l1menu::IReducedEvent& l1menu::ReducedMenuSample::getEvent( size_t eventNumber ) const
408 {
409 for( const auto& pRun : pImple_->protobufRuns )
410 {
411 if( eventNumber<static_cast<size_t>(pRun->event_size()) )
412 {
413 pImple_->event.pProtobufEvent=pRun->mutable_event(eventNumber);
414 return pImple_->event;
415 }
416 // Event must be in a later run, so reduce the number by how many events
417 // were in this run and look again.
418 eventNumber-=pRun->event_size();
419 }
420
421 // Should always find the event before getting to this point, so throw an
422 // exception if this happens.
423 throw std::runtime_error( "ReducedMenuSample::getEvent(eventNumber) was asked for an invalid eventNumber" );
424 }
425
426 const l1menu::TriggerMenu& l1menu::ReducedMenuSample::getTriggerMenu() const
427 {
428 return pImple_->triggerMenu;
429 }
430
431 bool l1menu::ReducedMenuSample::containsTrigger( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
432 {
433 // Loop over all of the triggers in the menu, and see if there is one
434 // where the name and version match.
435 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
436 {
437 const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
438 if( triggerInMenu.name()!=trigger.name() ) continue;
439 if( allowOlderVersion )
440 {
441 if( triggerInMenu.version()>trigger.version() ) continue;
442 }
443 else
444 {
445 if( triggerInMenu.version()!=trigger.version() ) continue;
446 }
447
448 // If control got this far then there is a trigger with the required name
449 // and sufficient version. I now need to check all of the non threshold parameters
450 // to make sure they match, i.e. make sure the ReducedSample was made with the same
451 // eta cuts or whatever.
452 // I don't care if the thresholds don't match because that's what's stored in the
453 // ReducedMenuSample.
454 std::vector<std::string> parameterNames=l1menu::tools::getNonThresholdParameterNames( trigger );
455 bool allParametersMatch=true;
456 for( const auto& parameterName : parameterNames )
457 {
458 if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) allParametersMatch=false;
459 }
460
461 if( allParametersMatch ) return true;
462 } // end of loop over triggers
463
464 // If control got this far then no trigger was found that matched
465 return false;
466 }
467
468 const std::map<std::string,size_t> l1menu::ReducedMenuSample::getTriggerParameterIdentifiers( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
469 {
470 std::map<std::string,size_t> returnValue;
471
472 // Need to find out how many parameters there are for each event. Basically the sum
473 // of the number of thresholds for all triggers.
474 size_t parameterNumber=0;
475 bool triggerWasFound=true;
476 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
477 {
478 const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
479
480 triggerWasFound=true; // Set to true, then back to false if any of the tests fail
481 // See if this trigger in the menu is the same as the one passed as a parameter
482 if( triggerInMenu.name()!=trigger.name() ) triggerWasFound=false;
483 if( allowOlderVersion )
484 {
485 if( triggerInMenu.version()>trigger.version() ) triggerWasFound=false;
486 }
487 else
488 {
489 if( triggerInMenu.version()!=trigger.version() ) triggerWasFound=false;
490 }
491
492 // If control got this far then there is a trigger with the required name
493 // and sufficient version. I now need to check all of the non threshold parameters
494 // to make sure they match, i.e. make sure the ReducedSample was made with the same
495 // eta cuts or whatever.
496 // I don't care if the thresholds don't match because that's what's stored in the
497 // ReducedMenuSample.
498 if( triggerWasFound ) // Trigger can still fail, but no point doing this check if it already has
499 {
500 std::vector<std::string> parameterNames=l1menu::tools::getNonThresholdParameterNames( trigger );
501 for( const auto& parameterName : parameterNames )
502 {
503 if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) triggerWasFound=false;
504 }
505 }
506
507 std::vector<std::string> thresholdNames=l1menu::tools::getThresholdNames(triggerInMenu);
508 if( triggerWasFound )
509 {
510 for( const auto& thresholdName : thresholdNames )
511 {
512 returnValue[thresholdName]=parameterNumber;
513 ++parameterNumber;
514 }
515 break;
516 }
517 else parameterNumber+=thresholdNames.size();
518 }
519
520 // There could conceivably be a trigger that was found but has no thresholds
521 // (I guess - it would be a pretty pointless trigger though). To indicate the
522 // difference between that and a trigger that wasn't found I'll respectively
523 // return the empty vector or throw an exception.
524 if( !triggerWasFound ) throw std::runtime_error( "l1menu::ReducedMenuSample::getTriggerParameterIdentifiers() called for a trigger that was not used to create the sample - "+trigger.name() );
525
526 return returnValue;
527 }
528
529 float l1menu::ReducedMenuSample::eventRate() const
530 {
531 return pImple_->eventRate;
532 }
533
534 void l1menu::ReducedMenuSample::setEventRate( float rate ) const
535 {
536 pImple_->eventRate=rate;
537 }
538
539 std::unique_ptr<const l1menu::IMenuRate> l1menu::ReducedMenuSample::rate( const l1menu::TriggerMenu& menu ) const
540 {
541 // TODO make sure the TriggerMenu is valid for this sample
542
543 // I need a non-const menu, so make a copy
544 l1menu::TriggerMenu mutableMenu( menu );
545
546 // The number of events that pass each trigger
547 std::vector<size_t> numberOfEventsPassed( menu.numberOfTriggers() );
548 float numberOfEventsPassingAnyTrigger;
549
550 for( size_t triggerNumber=0; triggerNumber<menu.numberOfTriggers(); ++triggerNumber )
551 {
552 mutableMenu.getTrigger( triggerNumber ).initiateForReducedSample( *this );
553 }
554
555 for( size_t eventNumber=0; eventNumber<numberOfEvents(); ++eventNumber )
556 {
557 const l1menu::IReducedEvent& event=getEvent(eventNumber);
558 bool anyTriggerPassed=false;
559
560 for( size_t triggerNumber=0; triggerNumber<menu.numberOfTriggers(); ++triggerNumber )
561 {
562 if( mutableMenu.getTrigger( triggerNumber ).apply( event ) )
563 {
564 // If the event passes the trigger, increment the counter
565 ++numberOfEventsPassed[triggerNumber];
566 anyTriggerPassed=true;
567 }
568 }
569
570 if( anyTriggerPassed ) ++numberOfEventsPassingAnyTrigger;
571 }
572
573 ::MenuRateImplementation* pRates=new ::MenuRateImplementation;
574 pRates->setScaling( pImple_->eventRate );
575 // This is the value I want to return, but I still need access to the extended attributes of the subclass
576 std::unique_ptr<const l1menu::IMenuRate> pReturnValue( pRates );
577
578 pRates->setTotalFraction( static_cast<float>(numberOfEventsPassingAnyTrigger)/static_cast<float>(numberOfEvents()) );
579
580 for( size_t triggerNumber=0; triggerNumber<numberOfEventsPassed.size(); ++triggerNumber )
581 {
582 float fraction=static_cast<float>(numberOfEventsPassed[triggerNumber])/static_cast<float>(numberOfEvents());
583 pRates->addTriggerRate( mutableMenu.getTrigger(triggerNumber), fraction );
584 }
585
586 return pReturnValue;
587 }