1 |
grimes |
1.1 |
#include "l1menu/ReducedMenuSample.h"
|
2 |
|
|
|
3 |
|
|
#include <vector>
|
4 |
grimes |
1.2 |
#include <stdexcept>
|
5 |
|
|
#include <fstream>
|
6 |
grimes |
1.1 |
#include "l1menu/IReducedEvent.h"
|
7 |
|
|
#include "l1menu/MenuSample.h"
|
8 |
|
|
#include "l1menu/TriggerMenu.h"
|
9 |
grimes |
1.2 |
#include "l1menu/ITrigger.h"
|
10 |
grimes |
1.1 |
#include "l1menu/tools.h"
|
11 |
grimes |
1.2 |
#include "protobuf/l1menu.pb.h"
|
12 |
grimes |
1.1 |
|
13 |
|
|
namespace // unnamed namespace
|
14 |
|
|
{
|
15 |
|
|
class ReducedEventImplementation : public l1menu::IReducedEvent
|
16 |
|
|
{
|
17 |
|
|
public:
|
18 |
|
|
virtual ~ReducedEventImplementation() {}
|
19 |
grimes |
1.2 |
virtual float parameterValue( size_t parameterNumber ) const { return pThresholdValues->at(parameterNumber); }
|
20 |
|
|
virtual float weight() const { return *pWeight; }
|
21 |
|
|
void setWeight( float newWeight ) { *pWeight=newWeight; }
|
22 |
grimes |
1.1 |
std::vector<float>* pThresholdValues;
|
23 |
grimes |
1.2 |
float* pWeight;
|
24 |
grimes |
1.1 |
};
|
25 |
|
|
}
|
26 |
|
|
|
27 |
|
|
namespace l1menu
|
28 |
|
|
{
|
29 |
|
|
/** @brief Private members for the ReducedMenuSample class
|
30 |
|
|
*
|
31 |
|
|
* @author Mark Grimes (mark.grimes@bristol.ac.uk)
|
32 |
|
|
* @date 28/May/2013
|
33 |
|
|
*/
|
34 |
|
|
class ReducedMenuSamplePrivateMembers
|
35 |
|
|
{
|
36 |
|
|
public:
|
37 |
grimes |
1.2 |
ReducedMenuSamplePrivateMembers( size_t newNumberOfEvents, size_t numberOfParameters, const l1menu::TriggerMenu newTriggerMenu )
|
38 |
|
|
: thresholdsForAllEvents( newNumberOfEvents, std::vector<float>(numberOfParameters) ),
|
39 |
|
|
weights( newNumberOfEvents ), numberOfEvents( newNumberOfEvents ), triggerMenu( newTriggerMenu )
|
40 |
grimes |
1.1 |
{
|
41 |
grimes |
1.2 |
// Run through every event and default every weight to 1.
|
42 |
|
|
for( auto& eventWeight : weights )
|
43 |
|
|
{
|
44 |
|
|
eventWeight=1;
|
45 |
|
|
}
|
46 |
grimes |
1.1 |
}
|
47 |
|
|
std::vector< std::vector<float> > thresholdsForAllEvents;
|
48 |
grimes |
1.2 |
std::vector<float> weights;
|
49 |
grimes |
1.1 |
::ReducedEventImplementation event;
|
50 |
|
|
size_t numberOfEvents;
|
51 |
grimes |
1.2 |
const l1menu::TriggerMenu triggerMenu;
|
52 |
grimes |
1.1 |
};
|
53 |
|
|
}
|
54 |
|
|
|
55 |
grimes |
1.3 |
#include <iostream>
|
56 |
grimes |
1.1 |
l1menu::ReducedMenuSample::ReducedMenuSample( const l1menu::MenuSample& originalSample, const l1menu::TriggerMenu& triggerMenu )
|
57 |
|
|
{
|
58 |
|
|
size_t numberOfEvents=originalSample.numberOfEvents();
|
59 |
|
|
// Need to find out how many parameters there are for each event. Basically the sum
|
60 |
|
|
// of the number of thresholds for all triggers.
|
61 |
|
|
size_t numberOfParameters=0;
|
62 |
grimes |
1.3 |
std::cout << "Creating sample" << std::endl;
|
63 |
grimes |
1.1 |
for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
|
64 |
|
|
{
|
65 |
|
|
const l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
|
66 |
grimes |
1.3 |
std::cout << "Trigger. " << trigger.name() << std::endl;
|
67 |
grimes |
1.1 |
numberOfParameters+=l1menu::getThresholdNames(trigger).size();
|
68 |
|
|
}
|
69 |
grimes |
1.3 |
std::cout << "Done. " << numberOfParameters << std::endl;
|
70 |
grimes |
1.1 |
|
71 |
|
|
// Now I know how many events there are and how many parameters, I can create the pimple
|
72 |
|
|
// with the correct parameters.
|
73 |
grimes |
1.2 |
pImple_.reset( new l1menu::ReducedMenuSamplePrivateMembers( numberOfEvents, numberOfParameters, triggerMenu ) );
|
74 |
|
|
|
75 |
|
|
//
|
76 |
|
|
// Now I've set the storage to the correct size, run through each event
|
77 |
|
|
// and fill with the correct values.
|
78 |
|
|
//
|
79 |
|
|
for( size_t eventNumber=0; eventNumber<numberOfEvents; ++eventNumber )
|
80 |
|
|
{
|
81 |
|
|
const l1menu::IEvent& event=originalSample.getEvent( eventNumber );
|
82 |
|
|
std::vector<float>& parameters=pImple_->thresholdsForAllEvents[eventNumber];
|
83 |
|
|
|
84 |
|
|
size_t parameterNumber=0;
|
85 |
|
|
// Loop over all of the triggers
|
86 |
|
|
for( size_t triggerNumber=0; triggerNumber<triggerMenu.numberOfTriggers(); ++triggerNumber )
|
87 |
|
|
{
|
88 |
|
|
std::unique_ptr<l1menu::ITrigger> pTrigger=triggerMenu.getTriggerCopy(triggerNumber);
|
89 |
|
|
std::vector<std::string> thresholdNames=getThresholdNames(*pTrigger);
|
90 |
|
|
|
91 |
|
|
try
|
92 |
|
|
{
|
93 |
|
|
setTriggerThresholdsAsTightAsPossible( event, *pTrigger, 0.001 );
|
94 |
|
|
// Set all of the parameters to match the thresholds in the trigger
|
95 |
|
|
for( const auto& thresholdName : thresholdNames )
|
96 |
|
|
{
|
97 |
|
|
parameters[parameterNumber]=pTrigger->parameter(thresholdName);
|
98 |
|
|
++parameterNumber;
|
99 |
|
|
}
|
100 |
|
|
}
|
101 |
|
|
catch( std::exception& error )
|
102 |
|
|
{
|
103 |
|
|
// setTriggerThresholdsAsTightAsPossible() couldn't find thresholds so record
|
104 |
|
|
// -1 for everything.
|
105 |
|
|
for( size_t index=0; index<thresholdNames.size(); ++index )
|
106 |
|
|
{
|
107 |
|
|
parameters[parameterNumber]=-1;
|
108 |
|
|
++parameterNumber;
|
109 |
|
|
}
|
110 |
|
|
} // end of try block that sets the trigger thresholds
|
111 |
|
|
|
112 |
|
|
} // end of loop over triggers
|
113 |
|
|
} // end of loop over events
|
114 |
|
|
}
|
115 |
|
|
|
116 |
|
|
l1menu::ReducedMenuSample::~ReducedMenuSample()
|
117 |
|
|
{
|
118 |
|
|
// No operation. Just need one defined otherwise the default one messes up
|
119 |
|
|
// the unique_ptr deletion because ReducedMenuSamplePrivateMembers isn't
|
120 |
|
|
// defined elsewhere.
|
121 |
|
|
}
|
122 |
|
|
|
123 |
|
|
l1menu::ReducedMenuSample::ReducedMenuSample( const std::string& filename )
|
124 |
|
|
{
|
125 |
|
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
126 |
|
|
|
127 |
|
|
l1menuprotobuf::Sample inputSample;
|
128 |
|
|
{ // new block to limit scope of variables
|
129 |
|
|
std::ifstream inputFile( filename );
|
130 |
|
|
inputSample.ParseFromIstream( &inputFile );
|
131 |
|
|
}
|
132 |
|
|
|
133 |
|
|
l1menu::TriggerMenu triggerMenu;
|
134 |
|
|
|
135 |
|
|
size_t totalNumberOfThresholds=0;
|
136 |
|
|
|
137 |
|
|
for( int triggerNumber=0; triggerNumber<inputSample.trigger_size(); ++triggerNumber )
|
138 |
|
|
{
|
139 |
|
|
const l1menuprotobuf::Trigger& inputTrigger=inputSample.trigger(triggerNumber);
|
140 |
|
|
|
141 |
|
|
triggerMenu.addTrigger( inputTrigger.name(), inputTrigger.version() );
|
142 |
|
|
// Get a reference to the trigger I just created
|
143 |
|
|
l1menu::ITrigger& trigger=triggerMenu.getTrigger(triggerNumber);
|
144 |
|
|
|
145 |
|
|
// Run through all of the parameters and set them to what they were
|
146 |
|
|
// when the sample was made.
|
147 |
|
|
for( int parameterNumber=0; parameterNumber<inputTrigger.parameter_size(); ++parameterNumber )
|
148 |
|
|
{
|
149 |
|
|
const auto& inputParameter=inputTrigger.parameter(parameterNumber);
|
150 |
|
|
trigger.parameter(inputParameter.name())=inputParameter.value();
|
151 |
|
|
}
|
152 |
|
|
|
153 |
|
|
// I should probably check the threshold names exist. At the moment I just see how
|
154 |
|
|
// many there are so that can initialise the buffer that holds the event data.
|
155 |
|
|
totalNumberOfThresholds+=inputTrigger.threshold_size();
|
156 |
|
|
}
|
157 |
|
|
|
158 |
|
|
// Now I have the menu set up as much as I need it (thresholds aren't set
|
159 |
|
|
// but I don't care about those). I can initialise the ReducedMenuSamplePrivateMembers
|
160 |
|
|
// pImple_ with the menu and the correct sizes for the data buffer.
|
161 |
|
|
pImple_.reset( new l1menu::ReducedMenuSamplePrivateMembers( inputSample.event_size(), totalNumberOfThresholds, triggerMenu ) );
|
162 |
|
|
|
163 |
|
|
// Now run over each event from the input file
|
164 |
|
|
for( int eventNumber=0; eventNumber<inputSample.event_size(); ++eventNumber )
|
165 |
|
|
{
|
166 |
|
|
auto& thresholdsForEvent=pImple_->thresholdsForAllEvents[eventNumber];
|
167 |
|
|
const auto& inputEvent=inputSample.event(eventNumber);
|
168 |
|
|
|
169 |
|
|
for( int thresholdNumber=0; thresholdNumber<inputEvent.threshold_size(); ++thresholdNumber )
|
170 |
|
|
{
|
171 |
|
|
thresholdsForEvent[thresholdNumber]=inputEvent.threshold(thresholdNumber);
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
// See if the weight was stored and set it if it has
|
175 |
|
|
if( inputEvent.has_weight() ) pImple_->weights[eventNumber]=inputEvent.weight();
|
176 |
|
|
}
|
177 |
|
|
}
|
178 |
|
|
|
179 |
|
|
void l1menu::ReducedMenuSample::saveToFile( const std::string& filename ) const
|
180 |
|
|
{
|
181 |
|
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
182 |
|
|
|
183 |
|
|
l1menuprotobuf::Sample outputSample;
|
184 |
|
|
|
185 |
|
|
for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
|
186 |
|
|
{
|
187 |
|
|
const l1menu::ITrigger& trigger=pImple_->triggerMenu.getTrigger(triggerNumber);
|
188 |
|
|
|
189 |
|
|
l1menuprotobuf::Trigger* pOutputTrigger=outputSample.add_trigger();
|
190 |
|
|
pOutputTrigger->set_name( trigger.name() );
|
191 |
|
|
pOutputTrigger->set_version( trigger.version() );
|
192 |
|
|
|
193 |
|
|
// For the parameters that aren't thresholds, record the name and value.
|
194 |
|
|
const auto parameterNames=l1menu::getNonThresholdParameterNames(trigger);
|
195 |
|
|
for( const auto& parameterName : parameterNames )
|
196 |
|
|
{
|
197 |
|
|
l1menuprotobuf::Trigger_TriggerParameter* pOutputParameter=pOutputTrigger->add_parameter();
|
198 |
|
|
pOutputParameter->set_name(parameterName);
|
199 |
|
|
pOutputParameter->set_value( trigger.parameter(parameterName) );
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
// For the parameters that are thresholds, just record the name. The value is
|
203 |
|
|
// recorded in each event.
|
204 |
|
|
const auto thresholdNames=l1menu::getThresholdNames(trigger);
|
205 |
|
|
for( const auto& thresholdName : thresholdNames ) pOutputTrigger->add_threshold(thresholdName);
|
206 |
|
|
|
207 |
|
|
} // end of loop over triggers
|
208 |
|
|
|
209 |
|
|
//
|
210 |
|
|
// I've done everything for what is effectively the header. I now need
|
211 |
|
|
// to run through each event and record the thresholds for each one.
|
212 |
|
|
//
|
213 |
|
|
for( const auto& thresholdsForEvent : pImple_->thresholdsForAllEvents )
|
214 |
|
|
{
|
215 |
|
|
l1menuprotobuf::Event* pOutputEvent=outputSample.add_event();
|
216 |
|
|
for( const auto& threshold : thresholdsForEvent )
|
217 |
|
|
{
|
218 |
|
|
pOutputEvent->add_threshold( threshold );
|
219 |
|
|
}
|
220 |
|
|
}
|
221 |
|
|
|
222 |
|
|
// I should have the correct number of events in the protobuf version of
|
223 |
|
|
// the sample now. I'll run through and set the event weights as well, but
|
224 |
|
|
// I'll only add it if it's different to 1. I think this saves space in
|
225 |
|
|
// the file.
|
226 |
|
|
for( int eventNumber=0; eventNumber<outputSample.event_size(); ++eventNumber )
|
227 |
|
|
{
|
228 |
|
|
if( pImple_->weights[eventNumber]!=1 )
|
229 |
|
|
{
|
230 |
|
|
l1menuprotobuf::Event* pOutputEvent=outputSample.mutable_event(eventNumber);
|
231 |
|
|
pOutputEvent->set_weight( pImple_->weights[eventNumber] );
|
232 |
|
|
}
|
233 |
|
|
}
|
234 |
|
|
|
235 |
|
|
|
236 |
|
|
//
|
237 |
|
|
// Everything should be set up in the class now, so I can open the
|
238 |
|
|
// output file and write to it.
|
239 |
|
|
//
|
240 |
|
|
std::ofstream outputFile( filename );
|
241 |
|
|
outputSample.SerializeToOstream( &outputFile );
|
242 |
grimes |
1.1 |
}
|
243 |
|
|
|
244 |
|
|
size_t l1menu::ReducedMenuSample::numberOfEvents() const
|
245 |
|
|
{
|
246 |
|
|
return pImple_->numberOfEvents;
|
247 |
|
|
}
|
248 |
|
|
|
249 |
|
|
const l1menu::IReducedEvent& l1menu::ReducedMenuSample::getEvent( size_t eventNumber ) const
|
250 |
|
|
{
|
251 |
|
|
pImple_->event.pThresholdValues=&pImple_->thresholdsForAllEvents[eventNumber];
|
252 |
grimes |
1.2 |
pImple_->event.pWeight=&pImple_->weights[eventNumber];
|
253 |
grimes |
1.1 |
return pImple_->event;
|
254 |
|
|
}
|
255 |
grimes |
1.2 |
|
256 |
|
|
const l1menu::TriggerMenu& l1menu::ReducedMenuSample::getTriggerMenu() const
|
257 |
|
|
{
|
258 |
|
|
return pImple_->triggerMenu;
|
259 |
|
|
}
|
260 |
|
|
|
261 |
|
|
bool l1menu::ReducedMenuSample::containsTrigger( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
|
262 |
|
|
{
|
263 |
|
|
// Loop over all of the triggers in the menu, and see if there is one
|
264 |
|
|
// where the name and version match.
|
265 |
|
|
for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
|
266 |
|
|
{
|
267 |
|
|
const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
|
268 |
|
|
if( triggerInMenu.name()!=trigger.name() ) continue;
|
269 |
|
|
if( allowOlderVersion )
|
270 |
|
|
{
|
271 |
|
|
if( triggerInMenu.version()>trigger.version() ) continue;
|
272 |
|
|
}
|
273 |
|
|
else
|
274 |
|
|
{
|
275 |
|
|
if( triggerInMenu.version()!=trigger.version() ) continue;
|
276 |
|
|
}
|
277 |
|
|
|
278 |
|
|
// If control got this far then there is a trigger with the required name
|
279 |
|
|
// and sufficient version. I now need to check all of the non threshold parameters
|
280 |
|
|
// to make sure they match, i.e. make sure the ReducedSample was made with the same
|
281 |
|
|
// eta cuts or whatever.
|
282 |
|
|
// I don't care if the thresholds don't match because that's what's stored in the
|
283 |
|
|
// ReducedMenuSample.
|
284 |
|
|
std::vector<std::string> parameterNames=getNonThresholdParameterNames( trigger );
|
285 |
|
|
bool allParametersMatch=true;
|
286 |
|
|
for( const auto& parameterName : parameterNames )
|
287 |
|
|
{
|
288 |
|
|
if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) allParametersMatch=false;
|
289 |
|
|
}
|
290 |
|
|
|
291 |
|
|
if( allParametersMatch ) return true;
|
292 |
|
|
} // end of loop over triggers
|
293 |
|
|
|
294 |
|
|
// If control got this far then no trigger was found that matched
|
295 |
|
|
return false;
|
296 |
|
|
}
|
297 |
|
|
|
298 |
|
|
const std::map<std::string,size_t> l1menu::ReducedMenuSample::getTriggerParameterIdentifiers( const l1menu::ITrigger& trigger, bool allowOlderVersion ) const
|
299 |
|
|
{
|
300 |
|
|
std::map<std::string,size_t> returnValue;
|
301 |
|
|
|
302 |
|
|
// Need to find out how many parameters there are for each event. Basically the sum
|
303 |
|
|
// of the number of thresholds for all triggers.
|
304 |
|
|
size_t parameterNumber=0;
|
305 |
|
|
bool triggerWasFound=true;
|
306 |
|
|
for( size_t triggerNumber=0; triggerNumber<pImple_->triggerMenu.numberOfTriggers(); ++triggerNumber )
|
307 |
|
|
{
|
308 |
|
|
const l1menu::ITrigger& triggerInMenu=pImple_->triggerMenu.getTrigger(triggerNumber);
|
309 |
|
|
|
310 |
|
|
triggerWasFound=true; // Set to true, then back to false if any of the tests fail
|
311 |
|
|
// See if this trigger in the menu is the same as the one passed as a parameter
|
312 |
|
|
if( triggerInMenu.name()!=trigger.name() ) triggerWasFound=false;
|
313 |
|
|
if( allowOlderVersion )
|
314 |
|
|
{
|
315 |
|
|
if( triggerInMenu.version()>trigger.version() ) triggerWasFound=false;
|
316 |
|
|
}
|
317 |
|
|
else
|
318 |
|
|
{
|
319 |
|
|
if( triggerInMenu.version()!=trigger.version() ) triggerWasFound=false;
|
320 |
|
|
}
|
321 |
|
|
|
322 |
|
|
// If control got this far then there is a trigger with the required name
|
323 |
|
|
// and sufficient version. I now need to check all of the non threshold parameters
|
324 |
|
|
// to make sure they match, i.e. make sure the ReducedSample was made with the same
|
325 |
|
|
// eta cuts or whatever.
|
326 |
|
|
// I don't care if the thresholds don't match because that's what's stored in the
|
327 |
|
|
// ReducedMenuSample.
|
328 |
|
|
if( triggerWasFound ) // Trigger can still fail, but no point doing this check if it already has
|
329 |
|
|
{
|
330 |
|
|
std::vector<std::string> parameterNames=getNonThresholdParameterNames( trigger );
|
331 |
|
|
for( const auto& parameterName : parameterNames )
|
332 |
|
|
{
|
333 |
|
|
if( trigger.parameter(parameterName)!=triggerInMenu.parameter(parameterName) ) triggerWasFound=false;
|
334 |
|
|
}
|
335 |
|
|
}
|
336 |
|
|
|
337 |
|
|
std::vector<std::string> thresholdNames=l1menu::getThresholdNames(trigger);
|
338 |
|
|
if( triggerWasFound )
|
339 |
|
|
{
|
340 |
|
|
for( const auto& thresholdName : thresholdNames )
|
341 |
|
|
{
|
342 |
|
|
returnValue[thresholdName]=parameterNumber;
|
343 |
|
|
++parameterNumber;
|
344 |
|
|
}
|
345 |
|
|
break;
|
346 |
|
|
}
|
347 |
|
|
else parameterNumber+=thresholdNames.size();
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
// There could conceivably be a trigger that was found but has no thresholds
|
351 |
|
|
// (I guess - it would be a pretty pointless trigger though). To indicate the
|
352 |
|
|
// difference between that and a trigger that wasn't found I'll respectively
|
353 |
|
|
// return the empty vector or throw an exception.
|
354 |
|
|
if( !triggerWasFound ) throw std::runtime_error( "l1menu::ReducedMenuSample::getTriggerParameterIdentifiers() called for a trigger that was not used to create the sample" );
|
355 |
|
|
|
356 |
|
|
return returnValue;
|
357 |
|
|
}
|