LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
LArMvaHelper.h
Go to the documentation of this file.
1 
8 #ifndef LAR_MVA_HELPER_H
9 #define LAR_MVA_HELPER_H 1
10 
12 
13 #include "Api/PandoraContentApi.h"
14 
15 #include "Helpers/XmlHelper.h"
16 
17 #include "Pandora/Algorithm.h"
18 #include "Pandora/AlgorithmTool.h"
19 #include "Pandora/PandoraInternal.h"
20 #include "Pandora/StatusCodes.h"
21 
22 #include <chrono>
23 #include <ctime>
24 #include <fstream>
25 
26 namespace lar_content
27 {
28 
32 template <typename... Ts>
33 class MvaFeatureTool : public pandora::AlgorithmTool
34 {
35 public:
37  typedef std::map<std::string, MvaFeatureTool<Ts...> *> FeatureToolMap;
38 
42  MvaFeatureTool() = default;
43 
50  virtual void Run(MvaTypes::MvaFeatureVector &featureVector, Ts... args) = 0;
51  virtual void Run(MvaTypes::MvaFeatureMap &featureMap, pandora::StringVector &featureOrder, const std::string &featureToolName, Ts...)
52  {
53  (void)featureMap;
54  (void)featureOrder;
55  (void)featureToolName;
56  return;
57  };
58 };
59 
60 template <typename... Ts>
62 
63 template <typename... Ts>
64 using MvaFeatureToolMap = std::map<std::string, MvaFeatureTool<Ts...> *>;
65 
66 //------------------------------------------------------------------------------------------------------------------------------------------
67 
72 {
73 public:
76  typedef std::map<std::string, double> DoubleMap;
77 
79  typedef std::map<std::string, pandora::AlgorithmTool *> AlgorithmToolMap; // idea would be to put this in PandoraInternal.h at some point in PandoraSDK
80 
89  template <typename TCONTAINER>
90  static pandora::StatusCode ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TCONTAINER &&featureContainer);
91 
101  template <typename TCONTAINER>
102  static pandora::StatusCode ProduceTrainingExample(
103  const std::string &trainingOutputFile, const bool result, const pandora::StringVector &featureOrder, TCONTAINER &&featureContainer);
104 
113  template <typename TCONTAINER>
114  static bool Classify(const MvaInterface &classifier, TCONTAINER &&featureContainer);
115 
125  template <typename TCONTAINER>
126  static bool Classify(const MvaInterface &classifier, const pandora::StringVector &featureOrder, TCONTAINER &&featureContainer);
127 
136  template <typename TCONTAINER>
137  static double CalculateClassificationScore(const MvaInterface &classifier, TCONTAINER &&featureContainer);
138 
147  template <typename TCONTAINER>
148  static double CalculateProbability(const MvaInterface &classifier, TCONTAINER &&featureContainer);
149 
159  template <typename TCONTAINER>
160  static double CalculateProbability(const MvaInterface &classifier, const pandora::StringVector &featureOrder, TCONTAINER &&featureContainer);
161 
170  template <typename... Ts, typename... TARGS>
171  static MvaFeatureVector CalculateFeatures(const MvaFeatureToolVector<Ts...> &featureToolVector, TARGS &&...args);
172 
183  template <typename... Ts, typename... TARGS>
184  static MvaFeatureMap CalculateFeatures(const pandora::StringVector &featureToolOrder, const MvaFeatureToolMap<Ts...> &featureToolMap,
185  pandora::StringVector &featureOrder, TARGS &&...args);
186 
195  template <typename T, typename... Ts, typename... TARGS>
196  static MvaFeatureVector CalculateFeaturesOfType(const MvaFeatureToolVector<Ts...> &featureToolVector, TARGS &&...args);
197 
206  template <typename... Ts>
207  static pandora::StatusCode AddFeatureToolToVector(pandora::AlgorithmTool *const pFeatureTool, MvaFeatureToolVector<Ts...> &featureToolVector);
208 
218  template <typename... Ts>
219  static pandora::StatusCode AddFeatureToolToMap(
220  pandora::AlgorithmTool *const pFeatureTool, std::string pFeatureToolName, MvaFeatureToolMap<Ts...> &featureToolMap);
221 
230  static pandora::StatusCode ProcessAlgorithmToolListToMap(const pandora::Algorithm &algorithm, const pandora::TiXmlHandle &xmlHandle,
231  const std::string &listName, pandora::StringVector &algorithToolNameVector, AlgorithmToolMap &algorithmToolMap);
232 
241  template <typename TLIST, typename... TLISTS>
242  static MvaFeatureVector ConcatenateFeatureLists(TLIST &&featureList, TLISTS &&...featureLists);
243 
247  static MvaFeatureVector ConcatenateFeatureLists();
248 
249 private:
255  static std::string GetTimestampString();
256 
266  template <typename TCONTAINER>
267  static pandora::StatusCode WriteFeaturesToFile(std::ofstream &outfile, const std::string &delimiter, TCONTAINER &&featureContainer);
268 
278  template <typename TCONTAINER>
279  static pandora::StatusCode WriteFeaturesToFileImpl(std::ofstream &outfile, const std::string &delimiter, TCONTAINER &&featureContainer);
280 };
281 
282 //------------------------------------------------------------------------------------------------------------------------------------------
283 
284 template <typename TCONTAINER>
285 pandora::StatusCode LArMvaHelper::ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TCONTAINER &&featureContainer)
286 {
287  std::ofstream outfile;
288  outfile.open(trainingOutputFile, std::ios_base::app); // always append to the output file
289 
290  if (!outfile.is_open())
291  {
292  std::cout << "LArMvaHelper: could not open file for training examples at " << trainingOutputFile << std::endl;
293  return pandora::STATUS_CODE_FAILURE;
294  }
295 
296  std::string delimiter(",");
297  outfile << GetTimestampString() << delimiter;
298 
299  PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, WriteFeaturesToFile(outfile, delimiter, featureContainer));
300  outfile << static_cast<int>(result) << '\n';
301 
302  return pandora::STATUS_CODE_SUCCESS;
303 }
304 
305 //------------------------------------------------------------------------------------------------------------------------------------------
306 
307 template <typename TCONTAINER>
309  const std::string &trainingOutputFile, const bool result, const pandora::StringVector &featureOrder, TCONTAINER &&featureContainer)
310 {
311  // Make a feature vector from the map and calculate the features
312  LArMvaHelper::MvaFeatureVector featureVector;
313 
314  for (auto const &pFeatureToolName : featureOrder)
315  {
316  if (featureContainer.find(pFeatureToolName) == featureContainer.end())
317  {
318  std::cout << "LArMvaHelper::ProduceTrainingExample "
319  << "- Error: feature tool " << pFeatureToolName << " not found." << std::endl;
320  throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_FOUND);
321  }
322  featureVector.push_back(featureContainer.at(pFeatureToolName));
323  }
324 
325  return ProduceTrainingExample(trainingOutputFile, result, featureVector);
326 }
327 
328 //------------------------------------------------------------------------------------------------------------------------------------------
329 
330 template <typename TCONTAINER>
331 bool LArMvaHelper::Classify(const MvaInterface &classifier, TCONTAINER &&featureContainer)
332 {
333  return classifier.Classify(featureContainer);
334 }
335 
336 //------------------------------------------------------------------------------------------------------------------------------------------
337 
338 template <typename TCONTAINER>
339 bool LArMvaHelper::Classify(const MvaInterface &classifier, const pandora::StringVector &featureOrder, TCONTAINER &&featureContainer)
340 {
341  // Make a feature vector from the map and calculate the features
342  LArMvaHelper::MvaFeatureVector featureVector;
343 
344  for (auto const &pFeatureToolName : featureOrder)
345  {
346  if (featureContainer.find(pFeatureToolName) == featureContainer.end())
347  {
348  std::cout << "LArMvaHelper::Classify "
349  << "- Error: feature tool " << pFeatureToolName << " not found." << std::endl;
350  throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_FOUND);
351  }
352  featureVector.push_back(featureContainer.at(pFeatureToolName));
353  }
354 
355  return Classify(classifier, featureVector);
356 }
357 
358 //------------------------------------------------------------------------------------------------------------------------------------------
359 
360 template <typename TCONTAINER>
361 double LArMvaHelper::CalculateClassificationScore(const MvaInterface &classifier, TCONTAINER &&featureContainer)
362 {
363  return classifier.CalculateClassificationScore(featureContainer);
364 }
365 
366 //------------------------------------------------------------------------------------------------------------------------------------------
367 
368 template <typename TCONTAINER>
369 double LArMvaHelper::CalculateProbability(const MvaInterface &classifier, TCONTAINER &&featureContainer)
370 {
371  return classifier.CalculateProbability(featureContainer);
372 }
373 
374 //------------------------------------------------------------------------------------------------------------------------------------------
375 
376 template <typename TCONTAINER>
377 double LArMvaHelper::CalculateProbability(const MvaInterface &classifier, const pandora::StringVector &featureOrder, TCONTAINER &&featureContainer)
378 {
379  // Make a feature vector from the map and calculate the features
380  LArMvaHelper::MvaFeatureVector featureVector;
381 
382  for (auto const &pFeatureToolName : featureOrder)
383  {
384  if (featureContainer.find(pFeatureToolName) == featureContainer.end())
385  {
386  std::cout << "LArMvaHelper::CalculateProbability "
387  << "- Error: feature tool " << pFeatureToolName << " not found." << std::endl;
388  throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_FOUND);
389  }
390  featureVector.push_back(featureContainer.at(pFeatureToolName));
391  }
392 
393  return CalculateProbability(classifier, featureVector);
394 }
395 
396 //------------------------------------------------------------------------------------------------------------------------------------------
397 
398 template <typename... Ts, typename... TARGS>
400 {
401  LArMvaHelper::MvaFeatureVector featureVector;
402 
403  for (MvaFeatureTool<Ts...> *const pFeatureTool : featureToolVector)
404  pFeatureTool->Run(featureVector, std::forward<TARGS>(args)...);
405 
406  return featureVector;
407 }
408 
409 //------------------------------------------------------------------------------------------------------------------------------------------
410 
411 template <typename... Ts, typename... TARGS>
412 LArMvaHelper::MvaFeatureMap LArMvaHelper::CalculateFeatures(const pandora::StringVector &featureToolOrder,
413  const MvaFeatureToolMap<Ts...> &featureToolMap, pandora::StringVector &featureOrder, TARGS &&...args)
414 {
415  LArMvaHelper::MvaFeatureMap featureMap;
416 
417  for (auto const &pFeatureToolName : featureToolOrder)
418  {
419  if (featureToolMap.find(pFeatureToolName) == featureToolMap.end())
420  {
421  std::cout << "LArMvaHelper::CalculateFeatures "
422  << "- Error: feature tool " << pFeatureToolName << " not found." << std::endl;
423  throw pandora::StatusCodeException(pandora::STATUS_CODE_NOT_FOUND);
424  }
425  featureToolMap.at(pFeatureToolName)->Run(featureMap, featureOrder, pFeatureToolName, std::forward<TARGS>(args)...);
426  }
427 
428  return featureMap;
429 }
430 
431 //------------------------------------------------------------------------------------------------------------------------------------------
432 
433 template <typename T, typename... Ts, typename... TARGS>
435 {
436  using TD = typename std::decay<T>::type;
437  LArMvaHelper::MvaFeatureVector featureVector;
438 
439  for (MvaFeatureTool<Ts...> *const pFeatureTool : featureToolVector)
440  {
441  if (TD *const pCastFeatureTool = dynamic_cast<TD *const>(pFeatureTool))
442  pCastFeatureTool->Run(featureVector, std::forward<TARGS>(args)...);
443  }
444 
445  return featureVector;
446 }
447 
448 //------------------------------------------------------------------------------------------------------------------------------------------
449 
450 template <typename... Ts>
451 pandora::StatusCode LArMvaHelper::AddFeatureToolToVector(pandora::AlgorithmTool *const pFeatureTool, MvaFeatureToolVector<Ts...> &featureToolVector)
452 {
453  if (MvaFeatureTool<Ts...> *const pCastFeatureTool = dynamic_cast<MvaFeatureTool<Ts...> *const>(pFeatureTool))
454  {
455  featureToolVector.push_back(pCastFeatureTool);
456  return pandora::STATUS_CODE_SUCCESS;
457  }
458 
459  return pandora::STATUS_CODE_FAILURE;
460 }
461 
462 //------------------------------------------------------------------------------------------------------------------------------------------
463 
464 template <typename... Ts>
466  pandora::AlgorithmTool *const pFeatureTool, std::string pFeatureToolName, MvaFeatureToolMap<Ts...> &featureToolMap)
467 {
468  if (MvaFeatureTool<Ts...> *const pCastFeatureTool = dynamic_cast<MvaFeatureTool<Ts...> *const>(pFeatureTool))
469  {
470  featureToolMap[pFeatureToolName] = pCastFeatureTool;
471  return pandora::STATUS_CODE_SUCCESS;
472  }
473 
474  return pandora::STATUS_CODE_FAILURE;
475 }
476 
477 //------------------------------------------------------------------------------------------------------------------------------------------
478 
480 {
481  std::time_t timestampNow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
482 
483  struct tm *pTimeInfo(NULL);
484  char buffer[80];
485 
486  pTimeInfo = localtime(&timestampNow);
487  strftime(buffer, 80, "%x_%X", pTimeInfo);
488 
489  std::string timeString(buffer);
490 
491  if (!timeString.empty() && timeString.back() == '\n') // last char is always a newline
492  timeString.pop_back();
493 
494  return timeString;
495 }
496 
497 //------------------------------------------------------------------------------------------------------------------------------------------
498 
499 template <typename TCONTAINER>
500 inline pandora::StatusCode LArMvaHelper::WriteFeaturesToFile(std::ofstream &outfile, const std::string &delimiter, TCONTAINER &&featureContainer)
501 {
502  static_assert(std::is_same<typename std::decay<TCONTAINER>::type, LArMvaHelper::MvaFeatureVector>::value,
503  "LArMvaHelper: Could not write training set example because a passed parameter was not a vector of MvaFeatures");
504 
505  PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, WriteFeaturesToFileImpl(outfile, delimiter, featureContainer));
506  return pandora::STATUS_CODE_SUCCESS;
507 }
508 
509 //------------------------------------------------------------------------------------------------------------------------------------------
510 
511 template <typename TCONTAINER>
512 pandora::StatusCode LArMvaHelper::WriteFeaturesToFileImpl(std::ofstream &outfile, const std::string &delimiter, TCONTAINER &&featureContainer)
513 {
514  for (const MvaFeature &feature : featureContainer)
515  outfile << feature.Get() << delimiter;
516 
517  return pandora::STATUS_CODE_SUCCESS;
518 }
519 
520 //------------------------------------------------------------------------------------------------------------------------------------------
521 
522 template <typename TLIST, typename... TLISTS>
523 LArMvaHelper::MvaFeatureVector LArMvaHelper::ConcatenateFeatureLists(TLIST &&featureList, TLISTS &&...featureLists)
524 {
525  static_assert(std::is_same<typename std::decay<TLIST>::type, LArMvaHelper::MvaFeatureVector>::value,
526  "LArMvaHelper: Could not concatenate feature lists because one or more lists was not a vector of MvaFeatures");
527 
528  LArMvaHelper::MvaFeatureVector featureVector;
529 
530  for (const MvaFeature &feature : featureList)
531  featureVector.push_back(feature);
532 
533  LArMvaHelper::MvaFeatureVector newFeatureVector = ConcatenateFeatureLists(std::forward<TLISTS>(featureLists)...);
534  featureVector.insert(featureVector.end(), newFeatureVector.begin(), newFeatureVector.end());
535 
536  return featureVector;
537 }
538 
539 //------------------------------------------------------------------------------------------------------------------------------------------
540 
542 {
544 }
545 
546 } // namespace lar_content
547 
548 #endif // #ifndef LAR_MVA_HELPER_H
static pandora::StatusCode WriteFeaturesToFileImpl(std::ofstream &outfile, const std::string &delimiter, TCONTAINER &&featureContainer)
Write the features of the given list to file (implementation method)
Definition: LArMvaHelper.h:512
static bool Classify(const MvaInterface &classifier, TCONTAINER &&featureContainer)
Use the trained classifier to predict the boolean class of an example.
Definition: LArMvaHelper.h:331
std::map< std::string, pandora::AlgorithmTool * > AlgorithmToolMap
Definition: LArMvaHelper.h:79
MvaTypes::MvaFeatureVector MvaFeatureVector
Definition: LArMvaHelper.h:75
static pandora::StatusCode ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TCONTAINER &&featureContainer)
Produce a training example with the given features and result.
Definition: LArMvaHelper.h:285
MvaFeatureTool()=default
Default constructor.
virtual void Run(MvaTypes::MvaFeatureVector &featureVector, Ts...args)=0
Run the algorithm tool.
static std::string GetTimestampString()
Get a timestamp string for this point in time.
Definition: LArMvaHelper.h:479
MvaInterface class.
std::vector< MvaFeatureTool< Ts... > * > MvaFeatureToolVector
Definition: LArMvaHelper.h:61
MvaTypes::MvaFeatureMap MvaFeatureMap
Definition: LArMvaHelper.h:78
MvaTypes::MvaFeature MvaFeature
Definition: LArMvaHelper.h:74
std::map< std::string, MvaFeatureTool< Ts... > * > FeatureToolMap
Definition: LArMvaHelper.h:37
static pandora::StatusCode WriteFeaturesToFile(std::ofstream &outfile, const std::string &delimiter, TCONTAINER &&featureContainer)
Write the features of the given lists to file.
Definition: LArMvaHelper.h:500
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
virtual bool Classify(const MvaTypes::MvaFeatureVector &features) const =0
Classify the set of input features based on the trained model.
static MvaFeatureVector CalculateFeaturesOfType(const MvaFeatureToolVector< Ts... > &featureToolVector, TARGS &&...args)
Calculate the features of a given derived feature tool type in a feature tool vector.
Definition: LArMvaHelper.h:434
InitializedDouble class used to define mva features.
std::map< std::string, double > DoubleMap
Definition: LArMvaHelper.h:76
std::map< std::string, MvaFeature > MvaFeatureMap
static pandora::StatusCode AddFeatureToolToVector(pandora::AlgorithmTool *const pFeatureTool, MvaFeatureToolVector< Ts... > &featureToolVector)
Add a feature tool to a vector of feature tools.
Definition: LArMvaHelper.h:451
std::map< std::string, MvaFeatureTool< Ts... > * > MvaFeatureToolMap
Definition: LArMvaHelper.h:64
LArMvaHelper class.
Definition: LArMvaHelper.h:71
virtual double CalculateProbability(const MvaTypes::MvaFeatureVector &features) const =0
Calculate the classification probability for a set of input features, based on the trained model...
double value
Definition: spectrum.C:18
virtual void Run(MvaTypes::MvaFeatureMap &featureMap, pandora::StringVector &featureOrder, const std::string &featureToolName, Ts...)
Definition: LArMvaHelper.h:51
std::vector< MvaFeatureTool< Ts... > * > FeatureToolVector
Definition: LArMvaHelper.h:36
virtual double CalculateClassificationScore(const MvaTypes::MvaFeatureVector &features) const =0
Calculate the classification score for a set of input features, based on the trained model...
static MvaFeatureVector CalculateFeatures(const MvaFeatureToolVector< Ts... > &featureToolVector, TARGS &&...args)
Calculate the features in a given feature tool vector.
Definition: LArMvaHelper.h:399
static MvaFeatureVector ConcatenateFeatureLists()
Recursively concatenate vectors of features (terminating method)
Definition: LArMvaHelper.h:541
static double CalculateClassificationScore(const MvaInterface &classifier, TCONTAINER &&featureContainer)
Use the trained classifer to calculate the classification score of an example (>0 means boolean class...
Definition: LArMvaHelper.h:361
static double CalculateProbability(const MvaInterface &classifier, TCONTAINER &&featureContainer)
Use the trained mva to calculate a classification probability for an example.
Definition: LArMvaHelper.h:369
MvaFeatureTool class template.
Definition: LArMvaHelper.h:33
std::vector< MvaFeature > MvaFeatureVector
Header file for the lar multivariate analysis interface class.
static pandora::StatusCode AddFeatureToolToMap(pandora::AlgorithmTool *const pFeatureTool, std::string pFeatureToolName, MvaFeatureToolMap< Ts... > &featureToolMap)
Add a feature tool to a map of feature tools.
Definition: LArMvaHelper.h:465