MaCh3  2.6.0
Reference Guide
SampleHandlerBase.txx
Go to the documentation of this file.
1 /// @brief HH - a helper function for RegisterFunctionalParameter
2 template <typename EventType, typename SFType>
3 void SampleHandlerBase::RegisterIndividualFunctionalParameter(
4  std::vector<EventType> &ExptEvents,
5  std::vector<std::string> const &par_names, SFType shift_func) {
6 
7  static_assert(
8  std::is_same_v<
9  std::function<void(std::vector<double> const &, EventType &)>,
10  decltype(std::function(shift_func))>,
11  "Function call signature for single parameter Functional shift must be "
12  "void(std::vector<double> const &, EventType &).");
13 
14  // check against all parameters defined on all Samples handled by this
15  // SampleHandler
16  std::vector<std::vector<FunctionalParameter>> all_sample_pars;
17  std::map<int, std::vector<int>> par_applicable_samplenames;
18  for (int iSample = 0; iSample < nSamples; ++iSample) {
19  all_sample_pars.push_back(ParHandler->GetFunctionalParametersFromSampleName(
20  GetSampleName(iSample)));
21  for (auto const &fp : all_sample_pars.back()) {
22  par_applicable_samplenames[fp.index].push_back(iSample);
23  }
24  }
25 
26  std::stringstream ss_pars, ss_miss;
27  std::vector<FunctionalParameter const *> matched_pars;
28  for (auto const &par_name : par_names) {
29  ss_pars << par_name << " ";
30  bool found = false;
31 
32  for (int iSample = 0; iSample < nSamples; ++iSample) {
33  for (auto const &fp : all_sample_pars[iSample]) {
34  if (fp.name == par_name) {
35  matched_pars.push_back(&fp);
36  found = true;
37  break;
38  }
39  }
40  if(found){
41  break;
42  }
43  }
44  if (!found) {
45  ss_miss << par_name;
46  }
47  }
48 
49  // allows experiments to effectively disable functional parameters by not
50  // supplying the YAML defining the parameters
51  if (!matched_pars.size()) {
52  MACH3LOG_INFO("Functional shift consuming parameters: [ {}], found no "
53  "matching parameters for "
54  "sample handler: {}",
55  ss_pars.str(), SampleHandlerName);
56  return;
57  } else if (matched_pars.size() !=
58  par_names.size()) { // not well defined how to procede with
59  // partially defined parameter sets, so don't
60  MACH3LOG_ERROR(
61  "Functional shift consuming parameters: [ {}], only partially "
62  "applys to sample handler: {}, missed parameters: [ {}]",
63  ss_pars.str(), SampleHandlerName, ss_miss.str());
64  throw MaCh3Exception(__FILE__, __LINE__);
65  }
66 
67  if (!functional.event_shifts.size()) {
68  functional.event_shifts.resize(ExptEvents.size());
69  } else if (functional.event_shifts.size() != ExptEvents.size()) {
70  MACH3LOG_ERROR("When registering functional shift consuming parameters: "
71  "[ {}], SampleHandler: {} has an allocated event map of "
72  "size: {}, but passed a vector of experiment events size: "
73  "{}. SampleHandler must have a unique set of event "
74  "indices so this indicates something has gone wrong.",
75  ss_pars.str(), SampleHandlerName,
76  functional.event_shifts.size(), ExptEvents.size());
77  throw MaCh3Exception(__FILE__, __LINE__);
78  }
79 
80  if (ExptEvents.size() != MCEvents.size()) {
81  MACH3LOG_ERROR("When registering functional shift consuming parameters: "
82  "[ {}], SampleHandler: {} knows about {} MCEvents, but "
83  "passed a vector of experiment events size: "
84  "{}. SampleHandler must have a unique set of event "
85  "indices so this indicates something has gone wrong.",
86  ss_pars.str(), SampleHandlerName, MCEvents.size(),
87  ExptEvents.size());
88  throw MaCh3Exception(__FILE__, __LINE__);
89  }
90 
91  // If we've made it here, then this functional shift is correctly
92  // configured for this SampleHandler
93 
94  int iShift = int(functional.shifts.size());
95  M3::detail::Functional::Shift shift;
96 
97  std::vector<int> par_indices;
98  for (auto const &fp : matched_pars) {
99  par_indices.push_back(fp->index);
100  }
101 
102  shift.par_vals.resize(par_indices.size());
103  shift.update_vals = [par_indices,this](std::vector<double> &par_vals) {
104  for (size_t i = 0; i < par_indices.size(); ++i) {
105  auto const &fpi = par_indices[i];
106  par_vals[i] = ParHandler->GetParPropVec()[fpi];
107  }
108  };
109 
110  shift.apply = [shift_func, &ExptEvents](std::vector<double> const &par_vals,
111  int iEvent) {
112  shift_func(par_vals, ExptEvents[iEvent]);
113  };
114 
115  functional.shifts.push_back(std::move(shift));
116 
117  // For each event, make a vector of pointers to the functional parameters
118  int NEvents = GetNEvents();
119  int neventsaffected = 0;
120  for (int iEvent = 0; iEvent < NEvents; ++iEvent) {
121  int nmatch = 0;
122  for (auto const &fp : matched_pars) {
123  const int Mode = static_cast<int>(
124  std::round(ReturnKinematicParameter("Mode", iEvent)));
125  if (!MatchCondition(fp->modes, Mode)) {
126  MACH3LOG_TRACE("Event {}, missed Mode check ({}) for dial {}", iEvent,
127  Mode, fp->name);
128  break;
129  }
130  if (!MatchCondition(par_applicable_samplenames[fp->index],
131  MCEvents[iEvent].NominalSample)) {
132  MACH3LOG_TRACE("Event {}, missed Sample check ({}) for dial {}", iEvent,
133  MCEvents[iEvent].NominalSample, fp->name);
134  break;
135  }
136  if (!PassesSelection((*fp), iEvent)) {
137  MACH3LOG_TRACE("Event {}, missed Kinematic var check for dial {}",
138  iEvent, fp->name);
139  break;
140  }
141  nmatch++;
142  }
143  // check sample name vs event.NominalSample
144  if (!nmatch) {
145  continue;
146  }
147  if (nmatch != static_cast<int>(matched_pars.size())) {
148  MACH3LOG_ERROR(
149  "When determining wether functional shift consuming parameters: "
150  "[ {}], in SampleHandler: {} should apply to event: {}, only {}/{} "
151  "parameters matched. Partially applied shifts are ill-defined.",
152  ss_pars.str(), SampleHandlerName, iEvent, nmatch,
153  matched_pars.size());
154  throw MaCh3Exception(__FILE__, __LINE__);
155  }
156  functional.event_shifts[iEvent].push_back(iShift);
157  neventsaffected++;
158  }
159  MACH3LOG_INFO(
160  "Registered functional shift consuming parameters: "
161  "[ {}] for SampleHandler: {}, with {} par vals affecting {} events.",
162  ss_pars.str(), SampleHandlerName, shift.par_vals.size(), neventsaffected);
163 }
164 
165 template <typename EventType, typename SFType>
166 void SampleHandlerBase::RegisterIndividualFunctionalParameter(
167  std::vector<EventType> &ExptEvents, std::string const &par_name,
168  SFType shift_func) {
169 
170  static_assert(
171  std::is_same_v<std::function<void(double const &, EventType &)>,
172  decltype(std::function(shift_func))>,
173  "Function call signature for single parameter Functional shift must be "
174  "void(double const &, EventType&).");
175 
176  RegisterIndividualFunctionalParameter(
177  ExptEvents,
178  std::vector<std::string>{
179  par_name,
180  },
181  [=](std::vector<double> const &par_vals, EventType &ev) {
182  shift_func(par_vals[0], ev);
183  });
184 }
185 
186 // ***************************************************************************
187 template <typename ParT>
188 bool SampleHandlerBase::PassesSelection(const ParT &Par, std::size_t iEvent) {
189  // ***************************************************************************
190  bool IsSelected = true;
191  if (Par.hasKinBounds) {
192  const auto &kinVars = Par.KinematicVarStr;
193  const auto &selection = Par.Selection;
194 
195  for (std::size_t iKinPar = 0; iKinPar < kinVars.size(); ++iKinPar) {
196  const double kinVal =
197  ReturnKinematicParameter(kinVars[iKinPar], static_cast<int>(iEvent));
198 
199  bool passedAnyBound = false;
200  const auto &boundsList = selection[iKinPar];
201 
202  for (const auto &bounds : boundsList) {
203  if (kinVal > bounds[0] && kinVal <= bounds[1]) {
204  passedAnyBound = true;
205  break;
206  }
207  }
208 
209  if (!passedAnyBound) {
210  MACH3LOG_TRACE("Event {}, missed kinematic check ({}) for dial {}",
211  iEvent, kinVars[iKinPar], Par.name);
212  IsSelected = false;
213  break;
214  }
215  }
216  }
217  return IsSelected;
218 }