ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/grimes/L1Menu/src/tools.cpp
Revision: 1.2
Committed: Fri May 31 01:29:10 2013 UTC (11 years, 11 months ago) by grimes
Branch: MAIN
Changes since 1.1: +21 -0 lines
Log Message:
Various improvements, including protobuf input and output for ReducedMenuSamples.

File Contents

# Content
1 #include "l1menu/tools.h"
2
3 #include <sstream>
4 #include <exception>
5 #include <map>
6 #include <stdexcept>
7 #include <algorithm>
8 #include "l1menu/ITrigger.h"
9 #include "l1menu/IEvent.h"
10 #include "l1menu/TriggerTable.h"
11
12 std::vector<std::string> l1menu::getThresholdNames( const l1menu::ITrigger& trigger )
13 {
14 std::vector<std::string> returnValue;
15
16 //
17 // I don't know how many thresholds there are, so I'll try and get every possible one and catch
18 // the exception when I eventually hit a threshold that doesn't exist.
19 //
20
21 std::stringstream stringConverter;
22 // I plan in the future to implement cross triggers with "leg1threshold1", "leg2threshold1" etcetera,
23 // so I'll loop over those possible prefixes.
24 for( size_t legNumber=0; true; ++legNumber ) // Loop continuously until the exception handler calls "break"
25 {
26 size_t thresholdNumber;
27 try
28 {
29 // Loop over all possible numbers of thresholds
30 for( thresholdNumber=1; true; ++thresholdNumber ) // Loop continuously until I hit an exception
31 {
32 stringConverter.str("");
33 if( legNumber!=0 ) stringConverter << "leg" << legNumber; // For triggers with only one leg I don't want to prefix anything.
34
35 stringConverter << "threshold" << thresholdNumber;
36 trigger.parameter(stringConverter.str());
37 // If the threshold doesn't exist the statement above will throw an exception, so
38 // I've reached this far then the threshold name must exist.
39 returnValue.push_back( stringConverter.str() );
40 }
41
42 }
43 catch( std::exception& error )
44 {
45 // If this exception is from the first threshold tried then the prefix (e.g. "leg1") does not
46 // exist, so I know I've finished. If it isn't from the first threshold then there could be
47 // other prefixes (e.g. "leg2") that have thresholds that can be modified, in which case I
48 // need to continue.
49 if( thresholdNumber==1 ) break;
50 }
51 }
52
53 return returnValue;
54 }
55
56 std::vector<std::string> l1menu::getNonThresholdParameterNames( const l1menu::ITrigger& trigger )
57 {
58 std::vector<std::string> returnValue;
59
60 // It'll be easier to get the threshold names and then copy
61 // everything that's not in there to the return value.
62 std::vector<std::string> allParameterNames=trigger.parameterNames();
63 std::vector<std::string> thresholdNames=getThresholdNames(trigger);
64
65 for( const auto& parameterName : allParameterNames )
66 {
67 const auto& iFindResult=std::find( thresholdNames.begin(), thresholdNames.end(), parameterName );
68 // If the current parameter name isn't one of the thresholds add
69 // it the vector which I'm going to return.
70 if( iFindResult==thresholdNames.end() ) returnValue.push_back(parameterName);
71 }
72
73 return returnValue;
74 }
75
76 void l1menu::setTriggerThresholdsAsTightAsPossible( const l1menu::IEvent& event, l1menu::ITrigger& trigger, float tolerance )
77 {
78 std::vector<std::string> thresholdNames=l1menu::getThresholdNames( trigger );
79 std::map<std::string,float> tightestPossibleThresholds;
80
81 // First set all of the thresholds to zero
82 for( const auto& thresholdName : thresholdNames ) trigger.parameter(thresholdName)=0;
83
84 // Now run through each threshold at a time and figure out how low it can be and still
85 // pass the event.
86 for( const auto& thresholdName : thresholdNames )
87 {
88 // Note that this is a reference, so when this is changed the trigger is modified
89 float& threshold=trigger.parameter(thresholdName);
90
91 float lowThreshold=0;
92 float highThreshold=500;
93 // See if an indication of the range of the trigger has been set
94 try // These calls will throw an exception if no suggestion has been set
95 {
96 lowThreshold=l1menu::TriggerTable::instance().getSuggestedLowerEdge( trigger.name(), thresholdName );
97 highThreshold=l1menu::TriggerTable::instance().getSuggestedUpperEdge( trigger.name(), thresholdName );
98 }
99 catch( std::exception& error ) { /* No indication set. Do nothing and just use the defaults I set previously. */ }
100
101 threshold=lowThreshold;
102 bool lowTest=trigger.apply( event );
103
104 threshold=highThreshold;
105 bool highTest=trigger.apply( event );
106
107 if( lowTest==highTest ) std::runtime_error( "l1menu::setTriggerThresholdsAsTightAsPossible() - couldn't find a set of thresholds to pass the given event.");
108
109 // Try and find the turn on point by bisection
110 while( highThreshold-lowThreshold > tolerance )
111 {
112 threshold=(highThreshold+lowThreshold)/2;
113 bool midTest=trigger.apply(event);
114
115 if( lowTest==midTest && highTest!=midTest ) lowThreshold=threshold;
116 else if( highTest==midTest ) highThreshold=threshold;
117 else throw std::runtime_error( std::string("Something fucked up while testing ")+trigger.name() );
118 }
119
120 // Record what this value was for the parameter named
121 tightestPossibleThresholds[thresholdName]=highThreshold;
122 // Then set back to zero ready to test the other thresholds
123 threshold=0;
124 }
125
126 //
127 // Now that I've figured out what all of the thresholds need to be, run
128 // through and set the trigger up with these thresholds.
129 //
130 for( const auto& parameterValuePair : tightestPossibleThresholds )
131 {
132 trigger.parameter(parameterValuePair.first)=parameterValuePair.second;
133 }
134 }