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.11 by grimes, Mon Jun 24 14:47:38 2013 UTC vs.
Revision 1.15 by grimes, Tue Jul 2 23:30:37 2013 UTC

# Line 5 | Line 5
5   #include <fcntl.h>
6   #include <algorithm>
7   #include <iostream>
8 < #include "l1menu/IReducedEvent.h"
8 > #include <sstream>
9 > #include "l1menu/ReducedEvent.h"
10   #include "l1menu/MenuSample.h"
11   #include "l1menu/TriggerMenu.h"
12   #include "l1menu/ITrigger.h"
13 + #include "l1menu/ICachedTrigger.h"
14 + #include "l1menu/L1TriggerDPGEvent.h"
15 + #include "l1menu/IEvent.h"
16   #include "l1menu/IMenuRate.h"
17   #include "l1menu/ITriggerRate.h"
18   #include "l1menu/tools/tools.h"
19 + #include "l1menu/implementation/MenuRateImplementation.h"
20   #include "protobuf/l1menu.pb.h"
21   #include <google/protobuf/io/zero_copy_stream_impl.h>
22   #include <google/protobuf/io/gzip_stream.h>
23  
24   namespace // unnamed namespace
25   {
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
26          /** @brief Sentry that closes a Unix file descriptor when it goes out of scope.
27           * @author Mark Grimes (mark.grimes@bristol.ac.uk)
28           * @date 07/Jun/2013
# Line 41 | Line 36 | namespace // unnamed namespace
36                  int fileDescriptor_;
37          };
38  
39 <        class MenuRateImplementation;
40 <
41 <        class TriggerRateImplementation : public l1menu::ITriggerRate
39 >        /** @brief An object that stores pointers to trigger parameters to avoid costly string comparisons.
40 >         *
41 >         * @author Mark Grimes (mark.grimes@bristol.ac.uk)
42 >         * @date 26/Jun/2013
43 >         */
44 >        class CachedTriggerImplementation : public l1menu::ICachedTrigger
45          {
46          public:
47 <                TriggerRateImplementation( const l1menu::ITrigger& trigger, float fraction, const MenuRateImplementation& menuRate );
48 <                TriggerRateImplementation& operator=( TriggerRateImplementation&& otherTriggerRate ); // Move assignment
49 <                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 <        };
47 >                CachedTriggerImplementation( const l1menu::ReducedMenuSample& sample, const l1menu::ITrigger& trigger )
48 >                {
49 >                        const auto& parameterIdentifiers=sample.getTriggerParameterIdentifiers(trigger);
50  
51 <        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() )
51 >                        for( const auto& identifier : parameterIdentifiers )
52                          {
53 <                                baseClassReferences_.clear();
81 <                                for( const auto& triggerRate : triggerRates_ )
82 <                                {
83 <                                        baseClassReferences_.push_back( &triggerRate );
84 <                                }
53 >                                identifiers_.push_back( std::make_pair( identifier.second, &trigger.parameter(identifier.first) ) );
54                          }
86
87                        return baseClassReferences_;
55                  }
56 +                virtual bool apply( const l1menu::IEvent& event )
57 +                {
58 +                        // Not happy using a static_cast, but this method is called in many, many loops.
59 +                        // I should probably find out how much faster this is than a dynamic_cast, maybe
60 +                        // it's not even worth it. Anyway, I'm banking that no one will ever pass an
61 +                        // event that wasn't created with the same sample that this proxy was created
62 +                        // with.
63 +                        const l1menu::ReducedEvent* pEvent=static_cast<const l1menu::ReducedEvent*>(&event);
64 +                        for( const auto& identifier : identifiers_ )
65 +                        {
66 +                                if( pEvent->parameterValue(identifier.first) < *identifier.second ) return false;
67 +                        }
68  
69 +                        // If control got this far then all of the thresholds passed, and
70 +                        // I can pass the event.
71 +                        return true;
72 +                }
73          protected:
74 <                float totalFraction_;
75 <                float scaling_;
93 <                std::vector<TriggerRateImplementation> triggerRates_;
94 <                mutable std::vector<const l1menu::ITriggerRate*> baseClassReferences_;
95 <        };
74 >                std::vector< std::pair<l1menu::ReducedEvent::ParameterID,const float*> > identifiers_;
75 >        }; // end of class ReducedSampleCachedTrigger
76  
77 <        TriggerRateImplementation::TriggerRateImplementation( const l1menu::ITrigger& trigger, float fraction, const MenuRateImplementation& menuRate )
98 <                : fraction_(fraction), menuRate_(menuRate)
77 >        float sumWeights( const l1menuprotobuf::Run& run )
78          {
79 <                pTrigger_=std::move( l1menu::TriggerTable::instance().copyTrigger(trigger) );
79 >                float returnValue=0;
80 >                for( const auto& event : run.event() )
81 >                {
82 >                        if( event.has_weight() ) returnValue+=event.weight();
83 >                        else returnValue+=1;
84 >                }
85 >                return returnValue;
86          }
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
87   }
88  
89   namespace l1menu
# Line 125 | Line 98 | namespace l1menu
98          private:
99                  l1menu::TriggerMenu mutableTriggerMenu_;
100          public:
101 <                ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu );
102 <                ReducedMenuSamplePrivateMembers( const std::string& filename );
103 <                void copyMenuToProtobufSample();
104 <                ::ReducedEventImplementation event;
101 >                ReducedMenuSamplePrivateMembers( const l1menu::ReducedMenuSample& thisObject, const l1menu::TriggerMenu& newTriggerMenu );
102 >                ReducedMenuSamplePrivateMembers( const l1menu::ReducedMenuSample& thisObject, const std::string& filename );
103 >                //void copyMenuToProtobufSample();
104 >                l1menu::ReducedEvent event;
105                  const l1menu::TriggerMenu& triggerMenu; // External const access to mutableTriggerMenu_
106                  float eventRate;
107 +                float sumOfWeights;
108                  l1menuprotobuf::SampleHeader protobufSampleHeader;
109                  // Protobuf doesn't implement move semantics so I'll use pointers
110                  std::vector<std::unique_ptr<l1menuprotobuf::Run> > protobufRuns;
# Line 144 | Line 118 | namespace l1menu
118          const std::string ReducedMenuSamplePrivateMembers::FILE_FORMAT_MAGIC_NUMBER="l1menuReducedMenuSample";
119   }
120  
121 < l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const l1menu::TriggerMenu& newTriggerMenu )
122 <        : mutableTriggerMenu_( newTriggerMenu ), triggerMenu( mutableTriggerMenu_ ), eventRate(1)
121 > l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const l1menu::ReducedMenuSample& thisObject, const l1menu::TriggerMenu& newTriggerMenu )
122 >        : mutableTriggerMenu_( newTriggerMenu ), event(thisObject), triggerMenu( mutableTriggerMenu_ ), eventRate(1), sumOfWeights(0)
123   {
124          GOOGLE_PROTOBUF_VERIFY_VERSION;
125  
# Line 184 | Line 158 | l1menu::ReducedMenuSamplePrivateMembers:
158  
159   }
160  
161 < l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const std::string& filename )
162 <        : triggerMenu(mutableTriggerMenu_)
161 > l1menu::ReducedMenuSamplePrivateMembers::ReducedMenuSamplePrivateMembers( const l1menu::ReducedMenuSample& thisObject, const std::string& filename )
162 >        : event(thisObject), triggerMenu(mutableTriggerMenu_), eventRate(1), sumOfWeights(0)
163   {
164          GOOGLE_PROTOBUF_VERIFY_VERSION;
165  
# Line 194 | Line 168 | l1menu::ReducedMenuSamplePrivateMembers:
168          if( fileDescriptor==0 ) throw std::runtime_error( "ReducedMenuSample initialise from file - couldn't open file" );
169          ::UnixFileSentry fileSentry( fileDescriptor ); // Use this as an exception safe way of closing the input file
170          google::protobuf::io::FileInputStream fileInput( fileDescriptor );
171 +
172 +        // First read the magic number at the start of the file and make sure it
173 +        // matches what I expect. This is uncompressed so I'll wrap it in a block
174 +        // to make sure the CodedInputStream is destructed before creating a new
175 +        // one with gzip input.
176 +        {
177 +                google::protobuf::io::CodedInputStream codedInput( &fileInput );
178 +
179 +                // As a read buffer, I'll create a string the correct size (filled with an arbitrary
180 +                // character) and read straight into that.
181 +                std::string readMagicNumber;
182 +                if( !codedInput.ReadString( &readMagicNumber, FILE_FORMAT_MAGIC_NUMBER.size() ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading magic number" );
183 +                if( readMagicNumber!=FILE_FORMAT_MAGIC_NUMBER ) throw std::runtime_error( "ReducedMenuSample - tried to initialise with a file that is not the correct format" );
184 +
185 +                google::protobuf::uint32 fileformatVersion;
186 +                if( !codedInput.ReadVarint32( &fileformatVersion ) ) throw std::runtime_error( "ReducedMenuSample initialise from file - error reading file format version" );
187 +                // So far I only have (and ever expect to have) one version of the file
188 +                // format, imaginatively versioned "1". You never know though...
189 +                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;
190 +        }
191 +
192          google::protobuf::io::GzipInputStream gzipInput( &fileInput );
193          google::protobuf::io::CodedInputStream codedInput( &gzipInput );
194  
# Line 203 | Line 198 | l1menu::ReducedMenuSamplePrivateMembers:
198          size_t totalBytesLimit=67108864;
199          codedInput.SetTotalBytesLimit( totalBytesLimit, -1 );
200  
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
201          google::protobuf::uint64 messageSize;
202  
203          // Read the size of the header message
# Line 253 | Line 235 | l1menu::ReducedMenuSamplePrivateMembers:
235                  protobufRuns.push_back( std::move( pNewRun ) );
236          }
237  
238 +        // Count up the sum of the weights of all events
239 +        for( const auto& pRun : protobufRuns )
240 +        {
241 +                sumOfWeights+=sumWeights( *pRun );
242 +        }
243 +
244          // I have all of the information in the protobuf members, but I also need the trigger information
245          // in the form of l1menu::TriggerMenu. Copy out the required information.
246          for( int triggerNumber=0; triggerNumber<protobufSampleHeader.trigger_size(); ++triggerNumber )
# Line 277 | Line 265 | l1menu::ReducedMenuSamplePrivateMembers:
265   }
266  
267   l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
268 <        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
268 >        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( *this, triggerMenu ) )
269   {
270          addSample( originalSample );
271   }
272  
273   l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::TriggerMenu& triggerMenu )
274 <        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( triggerMenu ) )
274 >        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( *this, triggerMenu ) )
275   {
276          // No operation besides the initialiser list
277   }
278  
279 + l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
280 +        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( *this, filename ) )
281 + {
282 +        // No operation except the initialiser list
283 + }
284 +
285   l1menu::ReducedMenuSample::~ReducedMenuSample()
286   {
287          // No operation. Just need one defined otherwise the default one messes up
# Line 312 | Line 306 | void l1menu::ReducedMenuSample::addSampl
306                          pCurrentRun=pImple_->protobufRuns.back().get();
307                  }
308  
309 <                const l1menu::IEvent& event=originalSample.getEvent( eventNumber );
309 >                const l1menu::L1TriggerDPGEvent& event=originalSample.getFullEvent( eventNumber );
310                  l1menuprotobuf::Event* pProtobufEvent=pCurrentRun->add_event();
311 +                if( event.weight()!=1 ) pProtobufEvent->set_weight( event.weight() );
312  
313                  // Loop over all of the triggers
314                  for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
# Line 333 | Line 328 | void l1menu::ReducedMenuSample::addSampl
328                          catch( std::exception& error )
329                          {
330                                  // setTriggerThresholdsAsTightAsPossible() couldn't find thresholds so record
331 <                                // -1 for everything.
331 >                                // a default for everything.
332                                  // Range based for loop gives me a warning because I don't use the thresholdName.
333 <                                for( size_t index=0; index<thresholdNames.size(); ++index ) pProtobufEvent->add_threshold(-1);
333 >                                for( size_t index=0; index<thresholdNames.size(); ++index ) pProtobufEvent->add_threshold(100000);
334                          } // end of try block that sets the trigger thresholds
335  
336                  } // end of loop over triggers
337  
338 +                pImple_->sumOfWeights+=event.weight();
339          } // end of loop over events
340   }
341  
346 l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
347        : pImple_( new l1menu::ReducedMenuSamplePrivateMembers( filename ) )
348 {
349        // No operation except the initialiser list
350 }
351
342   void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
343   {
344          // Open the file. Parameters are filename, write ability and create, rw-r--r-- permissions.
# Line 358 | Line 348 | void l1menu::ReducedMenuSample::saveToFi
348  
349          // Setup the protobuf file handlers
350          google::protobuf::io::FileOutputStream fileOutput( fileDescriptor );
351 +
352 +        // I want the magic number and file format identifier uncompressed, so
353 +        // I'll write those before switching to using gzipped output.
354 +        { // Block to make sure codedOutput is destructed before the gzip version is created
355 +                google::protobuf::io::CodedOutputStream codedOutput( &fileOutput );
356 +
357 +                // Write a magic number at the start of all files
358 +                codedOutput.WriteString( pImple_->FILE_FORMAT_MAGIC_NUMBER );
359 +                // Write an integer that specifies what version of the file format I'm using. I
360 +                // have no intention of changing the format but I might as well keep the option
361 +                // open.
362 +                codedOutput.WriteVarint32( 1 );
363 +        }
364 +
365          google::protobuf::io::GzipOutputStream gzipOutput( &fileOutput );
366          google::protobuf::io::CodedOutputStream codedOutput( &gzipOutput );
367  
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
368          // Write the size of the header message into the file...
369          codedOutput.WriteVarint64( pImple_->protobufSampleHeader.ByteSize() );
370          // ...and then write the header
# Line 389 | Line 386 | size_t l1menu::ReducedMenuSample::number
386          return numberOfEvents;
387   }
388  
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
389   const l1menu::TriggerMenu& l1menu::ReducedMenuSample::getTriggerMenu() const
390   {
391          return pImple_->triggerMenu;
# Line 511 | Line 489 | const std::map<std::string,size_t> l1men
489          return returnValue;
490   }
491  
492 + const l1menu::IEvent& l1menu::ReducedMenuSample::getEvent( size_t eventNumber ) const
493 + {
494 +        for( const auto& pRun : pImple_->protobufRuns )
495 +        {
496 +                if( eventNumber<static_cast<size_t>(pRun->event_size()) )
497 +                {
498 +                        pImple_->event.pProtobufEvent_=pRun->mutable_event(eventNumber);
499 +                        return pImple_->event;
500 +                }
501 +                // Event must be in a later run, so reduce the number by how many events
502 +                // were in this run and look again.
503 +                eventNumber-=pRun->event_size();
504 +        }
505 +
506 +        // Should always find the event before getting to this point, so throw an
507 +        // exception if this happens.
508 +        throw std::runtime_error( "ReducedMenuSample::getEvent(eventNumber) was asked for an invalid eventNumber" );
509 + }
510 +
511 + std::unique_ptr<l1menu::ICachedTrigger> l1menu::ReducedMenuSample::createCachedTrigger( const l1menu::ITrigger& trigger ) const
512 + {
513 +        return std::unique_ptr<l1menu::ICachedTrigger>( new CachedTriggerImplementation(*this,trigger) );
514 + }
515 +
516   float l1menu::ReducedMenuSample::eventRate() const
517   {
518          return pImple_->eventRate;
519   }
520  
521 < void l1menu::ReducedMenuSample::setEventRate( float rate ) const
521 > void l1menu::ReducedMenuSample::setEventRate( float rate )
522   {
523          pImple_->eventRate=rate;
524   }
525  
526 + float l1menu::ReducedMenuSample::sumOfWeights() const
527 + {
528 +        return pImple_->sumOfWeights;
529 + }
530 +
531   std::unique_ptr<const l1menu::IMenuRate> l1menu::ReducedMenuSample::rate( const l1menu::TriggerMenu& menu ) const
532   {
533          // TODO make sure the TriggerMenu is valid for this sample
534  
528        // I need a non-const menu, so make a copy
529        l1menu::TriggerMenu mutableMenu( menu );
530
535          // The number of events that pass each trigger
536          std::vector<size_t> numberOfEventsPassed( menu.numberOfTriggers() );
537          float numberOfEventsPassingAnyTrigger;
538  
539 +        // Using cached triggers significantly increases speed for ReducedMenuSample
540 +        // because it cuts out expensive string comparisons when querying the trigger
541 +        // parameters.
542 +        std::vector< std::unique_ptr<l1menu::ICachedTrigger> > cachedTriggers;
543          for( size_t triggerNumber=0; triggerNumber<menu.numberOfTriggers(); ++triggerNumber )
544          {
545 <                mutableMenu.getTrigger( triggerNumber ).initiateForReducedSample( *this );
545 >                cachedTriggers.push_back( createCachedTrigger( menu.getTrigger( triggerNumber ) ) );
546          }
547  
548          for( size_t eventNumber=0; eventNumber<numberOfEvents(); ++eventNumber )
549          {
550 <                const l1menu::IReducedEvent& event=getEvent(eventNumber);
550 >                const l1menu::IEvent& event=getEvent(eventNumber);
551                  bool anyTriggerPassed=false;
552  
553 <                for( size_t triggerNumber=0; triggerNumber<menu.numberOfTriggers(); ++triggerNumber )
553 >                for( size_t triggerNumber=0; triggerNumber<cachedTriggers.size(); ++triggerNumber )
554                  {
555 <                        if( mutableMenu.getTrigger( triggerNumber ).apply( event ) )
555 >                        if( cachedTriggers[triggerNumber]->apply(event) )
556                          {
557                                  // If the event passes the trigger, increment the counter
558                                  ++numberOfEventsPassed[triggerNumber];
# Line 555 | Line 563 | std::unique_ptr<const l1menu::IMenuRate>
563                  if( anyTriggerPassed ) ++numberOfEventsPassingAnyTrigger;
564          }
565  
566 <        ::MenuRateImplementation* pRates=new ::MenuRateImplementation;
559 <        pRates->setScaling( pImple_->eventRate );
566 >        l1menu::implementation::MenuRateImplementation* pRates=new l1menu::implementation::MenuRateImplementation;
567          // This is the value I want to return, but I still need access to the extended attributes of the subclass
568          std::unique_ptr<const l1menu::IMenuRate> pReturnValue( pRates );
569  
570 +        pRates->setScaling( pImple_->eventRate );
571 +
572          pRates->setTotalFraction( static_cast<float>(numberOfEventsPassingAnyTrigger)/static_cast<float>(numberOfEvents()) );
573  
574          for( size_t triggerNumber=0; triggerNumber<numberOfEventsPassed.size(); ++triggerNumber )
575          {
576                  float fraction=static_cast<float>(numberOfEventsPassed[triggerNumber])/static_cast<float>(numberOfEvents());
577 <                pRates->addTriggerRate( mutableMenu.getTrigger(triggerNumber), fraction );
577 >                pRates->addTriggerRate( menu.getTrigger(triggerNumber), fraction );
578          }
579  
580          return pReturnValue;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines