ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/ReducedMenuSample.cpp
Revision: 1.11
Committed: Mon Jun 24 14:47:38 2013 UTC (11 years, 10 months ago) by grimes
Branch: MAIN
Changes since 1.10: +108 -25 lines
Log Message:
Changes to the way trigger rates are returned

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 google::protobuf::io::GzipInputStream gzipInput( &fileInput );
198 google::protobuf::io::CodedInputStream codedInput( &gzipInput );
199
200 // Disable warnings on this input stream (second parameter, -1). The
201 // first parameter is the default. I'll change this if necessary in
202 // the loop later.
203 size_t totalBytesLimit=67108864;
204 codedInput.SetTotalBytesLimit( totalBytesLimit, -1 );
205
206 // First read the magic number at the start of the file and make sure it
207 // matches what I expect. As a read buffer, I'll create a string the correct
208 // size (filled with an arbitrary character) and read straight into that.
209 std::string readMagicNumber;
210 if( !codedInput.ReadString( &readMagicNumber, FILE_FORMAT_MAGIC_NUMBER.size() ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading magic number" );
211 if( readMagicNumber!=FILE_FORMAT_MAGIC_NUMBER ) throw std::runtime_error( "ReducedMenuSample - tried to initialise with a file that is not the correct format" );
212
213 google::protobuf::uint32 fileformatVersion;
214 if( !codedInput.ReadVarint32( &fileformatVersion ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading file format version" );
215 // So far I only have (and ever expect to have) one version of the file
216 // format, imaginatively versioned "1". You never know though...
217 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;
218
219 google::protobuf::uint64 messageSize;
220
221 // Read the size of the header message
222 if( !codedInput.ReadVarint64( &messageSize ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading message size for header" );
223 google::protobuf::io::CodedInputStream::Limit readLimit=codedInput.PushLimit(messageSize);
224 if( !protobufSampleHeader.ParseFromCodedStream( &codedInput ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - some unknown error while reading header" );
225 codedInput.PopLimit(readLimit);
226
227 // Keep looping until there is nothing more to be read from the file.
228 while( codedInput.ReadVarint64( &messageSize ) )
229 {
230 readLimit=codedInput.PushLimit(messageSize);
231
232 // Make sure the CodedInputStream doesn't refuse to read the message because it's
233 // read too much already. I'll also add an arbitrary 50 on to always make sure
234 // I can read the next messageSize if there is one.
235 if( gzipInput.ByteCount()+messageSize+50 > totalBytesLimit )
236 {
237 totalBytesLimit+=messageSize*5; // Might as well set it a little higher than necessary while I'm at it.
238 codedInput.SetTotalBytesLimit( totalBytesLimit, -1 );
239 }
240 std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
241 if( !pNewRun->ParseFromCodedStream( &codedInput ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - some unknown error while reading run" );
242 protobufRuns.push_back( std::move( pNewRun ) );
243
244 codedInput.PopLimit(readLimit);
245 }
246
247
248 // Always make sure there is at least one Run ready to be added to. Later
249 // code assumes there is already a run there.
250 if( protobufRuns.empty() )
251 {
252 std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
253 protobufRuns.push_back( std::move( pNewRun ) );
254 }
255
256 // I have all of the information in the protobuf members, but I also need the trigger information
257 // in the form of l1menu::TriggerMenu. Copy out the required information.
258 for( int triggerNumber=0; triggerNumber<protobufSampleHeader.trigger_size(); ++triggerNumber )
259 {
260 const l1menuprotobuf::Trigger& inputTrigger=protobufSampleHeader.trigger(triggerNumber);
261
262 mutableTriggerMenu_.addTrigger( inputTrigger.name(), inputTrigger.version() );
263 // Get a reference to the trigger I just created
264 l1menu::ITrigger& trigger=mutableTriggerMenu_.getTrigger(triggerNumber);
265
266 // Run through all of the parameters and set them to what they were
267 // when the sample was made.
268 for( int parameterNumber=0; parameterNumber<inputTrigger.parameter_size(); ++parameterNumber )
269 {
270 const auto& inputParameter=inputTrigger.parameter(parameterNumber);
271 trigger.parameter(inputParameter.name())=inputParameter.value();
272 }
273
274 // I should probably check the threshold names exist. I'll do it another time.
275 }
276
277 }
278
279 l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
280 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
281 {
282 addSample( originalSample );
283 }
284
285 l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::TriggerMenu& triggerMenu )
286 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
287 {
288 // No operation besides the initialiser list
289 }
290
291 l1menu::ReducedMenuSample::~ReducedMenuSample()
292 {
293 // No operation. Just need one defined otherwise the default one messes up
294 // the unique_ptr deletion because ReducedMenuSamplePrivateMembers isn't
295 // defined elsewhere.
296 }
297
298 void l1menu::ReducedMenuSample::addSample( const l1menu::MenuSample& originalSample )
299 {
300 l1menuprotobuf::Run* pCurrentRun=pImple_->protobufRuns.back().get();
301
302 for( size_t eventNumber=0; eventNumber<originalSample.numberOfEvents(); ++eventNumber )
303 {
304 // Split the events up into groups in arbitrary numbers. This is to get around
305 // a protobuf aversion to long messages.
306 if( pCurrentRun->event_size() >= pImple_->EVENTS_PER_RUN )
307 {
308 // Gone over the arbitrary limit, so create a new protobuf Run and start
309 // using that instead.
310 std::unique_ptr<l1menuprotobuf::Run> pNewRun( new l1menuprotobuf::Run );
311 pImple_->protobufRuns.push_back( std::move( pNewRun ) );
312 pCurrentRun=pImple_->protobufRuns.back().get();
313 }
314
315 const l1menu::IEvent& event=originalSample.getEvent( eventNumber );
316 l1menuprotobuf::Event* pProtobufEvent=pCurrentRun->add_event();
317
318 // Loop over all of the triggers
319 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
320 {
321 std::unique_ptr<l1menu::ITrigger> pTrigger=pImple_->triggerMenu.getTriggerCopy(triggerNumber);
322 std::vector<std::string> thresholdNames=l1menu::tools::getThresholdNames(*pTrigger);
323
324 try
325 {
326 l1menu::tools::setTriggerThresholdsAsTightAsPossible( event, *pTrigger, 0.001 );
327 // Set all of the parameters to match the thresholds in the trigger
328 for( const auto& thresholdName : thresholdNames )
329 {
330 pProtobufEvent->add_threshold( pTrigger->parameter(thresholdName) );
331 }
332 }
333 catch( std::exception& error )
334 {
335 // setTriggerThresholdsAsTightAsPossible() couldn't find thresholds so record
336 // -1 for everything.
337 // Range based for loop gives me a warning because I don't use the thresholdName.
338 for( size_t index=0; index<thresholdNames.size(); ++index ) pProtobufEvent->add_threshold(-1);
339 } // end of try block that sets the trigger thresholds
340
341 } // end of loop over triggers
342
343 } // end of loop over events
344 }
345
346 l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
347 : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( filename ) )
348 {
349 // No operation except the initialiser list
350 }
351
352 void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
353 {
354 // Open the file. Parameters are filename, write ability and create, rw-r--r-- permissions.
355 int fileDescriptor = open( filename.c_str(), O_WRONLY | O_CREAT, 0644 );
356 if( fileDescriptor==0 ) throw std::runtime_error( "ReducedMenuSample save to file - couldn't open file" );
357 ::UnixFileSentry fileSentry( fileDescriptor ); // Use this as an exception safe way of closing the output file
358
359 // Setup the protobuf file handlers
360 google::protobuf::io::FileOutputStream fileOutput( fileDescriptor );
361 google::protobuf::io::GzipOutputStream gzipOutput( &fileOutput );
362 google::protobuf::io::CodedOutputStream codedOutput( &gzipOutput );
363
364 // Write a magic number at the start of all files
365 codedOutput.WriteString( pImple_->FILE_FORMAT_MAGIC_NUMBER );
366 // Write an integer that specifies what version of the file format I'm using. I
367 // have no intention of changing the format but I might as well keep the option
368 // open.
369 codedOutput.WriteVarint32( 1 );
370
371 // Write the size of the header message into the file...
372 codedOutput.WriteVarint64( pImple_->protobufSampleHeader.ByteSize() );
373 // ...and then write the header
374 pImple_->protobufSampleHeader.SerializeToCodedStream( &codedOutput );
375
376 // Now go through each of the runs and do the same for those
377 for( const auto& pRun : pImple_->protobufRuns )
378 {
379 codedOutput.WriteVarint64( pRun->ByteSize() );
380 pRun->SerializeToCodedStream( &codedOutput );
381 }
382
383 }
384
385 size_t l1menu::ReducedMenuSample::numberOfEvents() const
386 {
387 size_t numberOfEvents=0;
388 for( const auto& pRun : pImple_->protobufRuns ) numberOfEvents+=pRun->event_size();
389 return numberOfEvents;
390 }
391
392 const l1menu::IReducedEvent& l1menu::ReducedMenuSample::getEvent( size_t eventNumber ) const
393 {
394 for( const auto& pRun : pImple_->protobufRuns )
395 {
396 if( eventNumber<static_cast<size_t>(pRun->event_size()) )
397 {
398 pImple_->event.pProtobufEvent=pRun->mutable_event(eventNumber);
399 return pImple_->event;
400 }
401 // Event must be in a later run, so reduce the number by how many events
402 // were in this run and look again.
403 eventNumber-=pRun->event_size();
404 }
405
406 // Should always find the event before getting to this point, so throw an
407 // exception if this happens.
408 throw std::runtime_error( "ReducedMenuSample::getEvent(eventNumber) was asked for an invalid eventNumber" );
409 }
410
411 const l1menu::TriggerMenu& l1menu::ReducedMenuSample::getTriggerMenu() const
412 {
413 return pImple_->triggerMenu;
414 }
415
416 bool l1menu::ReducedMenuSample::containsTrigger( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
417 {
418 // Loop over all of the triggers in the menu, and see if there is one
419 // where the name and version match.
420 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
421 {
422 const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
423 if( triggerInMenu.name()!=trigger.name() ) continue;
424 if( allowOlderVersion )
425 {
426 if( triggerInMenu.version()>trigger.version() ) continue;
427 }
428 else
429 {
430 if( triggerInMenu.version()!=trigger.version() ) continue;
431 }
432
433 // If control got this far then there is a trigger with the required name
434 // and sufficient version. I now need to check all of the non threshold parameters
435 // to make sure they match, i.e. make sure the ReducedSample was made with the same
436 // eta cuts or whatever.
437 // I don't care if the thresholds don't match because that's what's stored in the
438 // ReducedMenuSample.
439 std::vector<std::string> parameterNames=l1menu::tools::getNonThresholdParameterNames( trigger );
440 bool allParametersMatch=true;
441 for( const auto& parameterName : parameterNames )
442 {
443 if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) allParametersMatch=false;
444 }
445
446 if( allParametersMatch ) return true;
447 } // end of loop over triggers
448
449 // If control got this far then no trigger was found that matched
450 return false;
451 }
452
453 const std::map<std::string,size_t> l1menu::ReducedMenuSample::getTriggerParameterIdentifiers( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
454 {
455 std::map<std::string,size_t> returnValue;
456
457 // Need to find out how many parameters there are for each event. Basically the sum
458 // of the number of thresholds for all triggers.
459 size_t parameterNumber=0;
460 bool triggerWasFound=true;
461 for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
462 {
463 const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
464
465 triggerWasFound=true; // Set to true, then back to false if any of the tests fail
466 // See if this trigger in the menu is the same as the one passed as a parameter
467 if( triggerInMenu.name()!=trigger.name() ) triggerWasFound=false;
468 if( allowOlderVersion )
469 {
470 if( triggerInMenu.version()>trigger.version() ) triggerWasFound=false;
471 }
472 else
473 {
474 if( triggerInMenu.version()!=trigger.version() ) triggerWasFound=false;
475 }
476
477 // If control got this far then there is a trigger with the required name
478 // and sufficient version. I now need to check all of the non threshold parameters
479 // to make sure they match, i.e. make sure the ReducedSample was made with the same
480 // eta cuts or whatever.
481 // I don't care if the thresholds don't match because that's what's stored in the
482 // ReducedMenuSample.
483 if( triggerWasFound ) // Trigger can still fail, but no point doing this check if it already has
484 {
485 std::vector<std::string> parameterNames=l1menu::tools::getNonThresholdParameterNames( trigger );
486 for( const auto& parameterName : parameterNames )
487 {
488 if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) triggerWasFound=false;
489 }
490 }
491
492 std::vector<std::string> thresholdNames=l1menu::tools::getThresholdNames(triggerInMenu);
493 if( triggerWasFound )
494 {
495 for( const auto& thresholdName : thresholdNames )
496 {
497 returnValue[thresholdName]=parameterNumber;
498 ++parameterNumber;
499 }
500 break;
501 }
502 else parameterNumber+=thresholdNames.size();
503 }
504
505 // There could conceivably be a trigger that was found but has no thresholds
506 // (I guess - it would be a pretty pointless trigger though). To indicate the
507 // difference between that and a trigger that wasn't found I'll respectively
508 // return the empty vector or throw an exception.
509 if( !triggerWasFound ) throw std::runtime_error( "l1menu::ReducedMenuSample::getTriggerParameterIdentifiers() called for a trigger that was not used to create the sample - "+trigger.name() );
510
511 return returnValue;
512 }
513
514 float l1menu::ReducedMenuSample::eventRate() const
515 {
516 return pImple_->eventRate;
517 }
518
519 void l1menu::ReducedMenuSample::setEventRate( float rate ) const
520 {
521 pImple_->eventRate=rate;
522 }
523
524 std::unique_ptr<const l1menu::IMenuRate> l1menu::ReducedMenuSample::rate( const l1menu::TriggerMenu& menu ) const
525 {
526 // TODO make sure the TriggerMenu is valid for this sample
527
528 // I need a non-const menu, so make a copy
529 l1menu::TriggerMenu mutableMenu( menu );
530
531 // The number of events that pass each trigger
532 std::vector<size_t> numberOfEventsPassed( menu.numberOfTriggers() );
533 float numberOfEventsPassingAnyTrigger;
534
535 for( size_t triggerNumber=0; triggerNumber<menu.numberOfTriggers(); ++triggerNumber )
536 {
537 mutableMenu.getTrigger( triggerNumber ).initiateForReducedSample( *this );
538 }
539
540 for( size_t eventNumber=0; eventNumber<numberOfEvents(); ++eventNumber )
541 {
542 const l1menu::IReducedEvent& event=getEvent(eventNumber);
543 bool anyTriggerPassed=false;
544
545 for( size_t triggerNumber=0; triggerNumber<menu.numberOfTriggers(); ++triggerNumber )
546 {
547 if( mutableMenu.getTrigger( triggerNumber ).apply( event ) )
548 {
549 // If the event passes the trigger, increment the counter
550 ++numberOfEventsPassed[triggerNumber];
551 anyTriggerPassed=true;
552 }
553 }
554
555 if( anyTriggerPassed ) ++numberOfEventsPassingAnyTrigger;
556 }
557
558 ::MenuRateImplementation* pRates=new ::MenuRateImplementation;
559 pRates->setScaling( pImple_->eventRate );
560 // This is the value I want to return, but I still need access to the extended attributes of the subclass
561 std::unique_ptr<const l1menu::IMenuRate> pReturnValue( pRates );
562
563 pRates->setTotalFraction( static_cast<float>(numberOfEventsPassingAnyTrigger)/static_cast<float>(numberOfEvents()) );
564
565 for( size_t triggerNumber=0; triggerNumber<numberOfEventsPassed.size(); ++triggerNumber )
566 {
567 float fraction=static_cast<float>(numberOfEventsPassed[triggerNumber])/static_cast<float>(numberOfEvents());
568 pRates->addTriggerRate( mutableMenu.getTrigger(triggerNumber), fraction );
569 }
570
571 return pReturnValue;
572 }