CMFGridPointsBestFit_plugin.cc
Go to the documentation of this file.
1 //
2 // Plugin to determine the best fit at each grid point in a space from library
3 // predictions.
4 // Pass the art job a list of input library prediction files for the space
5 // along with a best fit file and a file of random universes
6 //
7 // Created by Brian Rebel on 3/22/21.
8 //
9 
10 #include <string>
11 #include <set>
12 #include <map>
13 #include <memory>
14 #include <sstream>
15 
16 //#include "TStopwatch.h"
17 #include "TMath.h"
18 #include "TGraph2D.h"
19 
20 // Framework includes
26 #include "art_root_io/TFileService.h"
27 #include "art_root_io/TFileDirectory.h"
28 #include "fhiclcpp/ParameterSet.h"
30 #include "cetlib_except/exception.h"
31 
32 // NOvA includes
41 
42 namespace cmf{
43 
45  public:
46  explicit GridPointsBestFit(fhicl::ParameterSet const& pset);
47 
48  ~GridPointsBestFit() override = default;
49 
50  void readResults(art::Results const& r) override;
51 
52  void writeResults(art::Results& r) override;
53 
54  void reconfigure(fhicl::ParameterSet const& p);
55 
56  void clear() override;
57  void endJob() override;
58 
59  private:
60 
62  cmf::PointSpectra const& pointSpectra);
63 
64  void MakeAndStorePlots(std::string const& baseName,
65  cmf::Spectrum const& randomUSpectrum,
66  cmf::Spectrum const& asimovUSpectrum,
67  std::vector<cmf::PointBestFit> const& randomUBestFit,
68  std::vector<cmf::PointBestFit> const& asimovUBestFit);
69 
70  void BestFitPlots(std::string const& baseName,
71  art::TFileDirectory & curDir,
72  std::vector<cmf::PointBestFit> const& universeBestFits);
73 
74  float fNDFHCExposureScale; ///< how much the ND FHC bins in the prediction libraries should be scaled by
75  float fNDRHCExposureScale; ///< how much the ND RHC bins in the prediction libraries should be scaled by
76  float fFDFHCExposureScale; ///< how much the FD FHC bins in the prediction libraries should be scaled by
77  float fFDRHCExposureScale; ///< how much the FD RHC bins in the prediction libraries should be scaled by
78  std::string fPredictionModule; ///< label for module containing the prediction point library
79  std::string fInputUniverseLabel; ///< label for module containing the prediction point library
80  cmf::ChiSqrCalc_t fChiSqrToUse; ///< which calculator to use
81  cmf::OscParm_t fXParamEnum; ///< enumerated value of the parameter from CovarianceMatrixFit/dataProducts/Constants.h
82  cmf::OscParm_t fYParamEnum; ///< enumerated value of the parameter from CovarianceMatrixFit/dataProducts/Constants.h
83  fhicl::ParameterSet fPlotConfig; ///< configuration for the plot utilities
84  bool fLogXAxis; ///< are parameters on a log scale on the X axis
85  bool fLogYAxis; ///< are parameters on a log scale on the Y axis
86  bool fScaleExposure; ///< should the exposure of the prediction libraries be scaled?
87  size_t fNumUniverses; ///< number of universes to use when making contours
88  size_t fStartUniverse; ///< which universe to start with in the fake universe file
89  cmf::FakeUniColl fFakeUniverses; ///< the input fake universes
90  float fXParamMin; ///< minimum and maximum ranges to consider for XY parameters
91  float fXParamMax;
92  float fYParamMin;
93  float fYParamMax;
94  std::vector<cmf::PointSpectra> fPointSpectraVec; ///< the point spectra for all the oscillation points
95  std::map<cmf::DetBeamPair, float> fDBScaleMap; ///< how do we want to scale our exposure?
96 
97  };
98 
99  //......................................................................
103  , fPlotConfig(pset.get<fhicl::ParameterSet>("PlotUtilities"))
104  {
105  this->reconfigure(pset);
106 
107  produces< std::vector<cmf::UniversePointBestFits> >();
108  }
109 
110  //......................................................................
112  {
115  cmf::ParameterUtility::Instance() ->Initialize(pset.get< fhicl::ParameterSet >("ParametersToUse" ));
116  cmf::ChiSqrCalculator::Instance() ->InitializeCovarianceMatrix(pset.get<fhicl::ParameterSet>("ChiSqrCalculationParameters" ));
117 
118  fChiSqrToUse = cmf::StringToChiSqrType(pset.get<std::string>("ChiSqrCalcToUse"));
119 
120  fNDFHCExposureScale = pset.get< float >("NDFHCExposureScale", 1.0 );
121  fFDFHCExposureScale = pset.get< float >("FDFHCExposureScale", 1.0 );
122  fNDRHCExposureScale = pset.get< float >("NDRHCExposureScale", 1.0 );
123  fFDRHCExposureScale = pset.get< float >("FDRHCExposureScale", 1.0 );
124  fInputUniverseLabel = pset.get<std::string >("InputUniverseModule" );
125  fLogXAxis = pset.get< bool >("LogXAxis", false);
126  fLogYAxis = pset.get< bool >("LogYAxis", false);
127  fNumUniverses = pset.get<unsigned int>("NumberOfUniverses", 0 );
128  fPredictionModule = pset.get<std::string >("PredictionLibraryModule" );
129  fStartUniverse = pset.get<unsigned int>("StartUniverse", 0 );
130  fXParamMin = pset.get< float >("XParamMin", 1.e-4);
131  fXParamMax = pset.get< float >("XParamMax", 1. );
132  fYParamMin = pset.get< float >("YParamMin", 1.e-4);
133  fYParamMax = pset.get< float >("YParamMax", 1. );
134 
135  if(fNDFHCExposureScale != 1 ||
136  fFDFHCExposureScale != 1 ||
137  fNDRHCExposureScale != 1 ||
138  fFDRHCExposureScale != 1 ){
139  fScaleExposure = true;
140 
142  fDBScaleMap.emplace(std::make_pair(cmf::kFARDET, cmf::kFHC), fFDFHCExposureScale);
143  fDBScaleMap.emplace(std::make_pair(cmf::kNEARDET, cmf::kRHC), fNDRHCExposureScale);
144  fDBScaleMap.emplace(std::make_pair(cmf::kFARDET, cmf::kRHC), fFDRHCExposureScale);
145  }
146 
149  }
150 
151  //......................................................................
152  // Method to clear out the collections of data products after the
153  // writeResults method is called.
155  {}
156 
157  //......................................................................
158  // We need to read in several types of files - the best fit,
159  // prediction library and random universe files. The latter is what we
160  // want if we are making median sensitivities and also has the Asimov
161  // predictions for the fake data.
163  {
164 
166  if( r.getByLabel(fInputUniverseLabel, universes) &&
167  universes.isValid() ){
168 
169  for(auto const& itr : *universes) fFakeUniverses.emplace_back(itr);
170  MF_LOG_VERBATIM("FitFeldmanCousinsPoint")
171  << "Valid handle to std::vector<cmf::FakeUniverse> "
172  << "objects found in "
174  << " vector size "
175  << fFakeUniverses.size();
176  r.removeCachedProduct(universes);
177  }
178 
180  if( r.getByLabel(fPredictionModule, predLib) &&
181  predLib.isValid() ){
182  MF_LOG_VERBATIM("CovarianceMatrixFitter")
183  << "Valid handle to std::vector<cmf::OscParamPoint> "
184  << "objects found in "
186  << " "
187  << " vector size "
188  << predLib->size();
189 
190  auto useTrig = fPlotConfig.get<bool>("UseTrig");
191  auto psvItr = fPointSpectraVec.begin();
192  float xVal;
193  float yVal;
194 
195  // maybe we should first figure out how many grid points we need in the space
196  // and how many entries we need for the hidden parameter combinations at each
197  // point and reserve that space
198  auto const& dbBinsVec = cmf::CovarianceBinUtility::Instance()->DetectorBeamBins();
199 
200  for(auto const& itrUnscaled : *predLib){
201 
202  // only worry about the spectra corresponding to the points we
203  // are testing in this module.
204  xVal = (useTrig && cmf::IsAngleParameter(fXParamEnum)) ? std::pow(std::sin(itrUnscaled.OscPoint().find(fXParamEnum)->second), 2.) : itrUnscaled.OscPoint().find(fXParamEnum)->second;
205  yVal = (useTrig && cmf::IsAngleParameter(fYParamEnum)) ? std::pow(std::sin(itrUnscaled.OscPoint().find(fYParamEnum)->second), 2.) : itrUnscaled.OscPoint().find(fYParamEnum)->second;
206 
207  if(xVal < fXParamMin ||
208  xVal > fXParamMax ||
209  yVal < fYParamMin ||
210  yVal > fYParamMax) continue;
211 
212  cmf::OscParamPoint itr = (fScaleExposure) ? itrUnscaled.ScaleSpectra(dbBinsVec, fDBScaleMap) : itrUnscaled;
213 
214  MF_LOG_DEBUG("CMFGridPointsBestFit")
215  << itr;
216 
217  auto gridPoint = cmf::GridPoint(xVal,
218  yVal,
219  fXParamEnum,
220  fYParamEnum);
221  psvItr = std::find(fPointSpectraVec.begin(),
222  fPointSpectraVec.end(),
223  PointSpectra(gridPoint));
224  if (psvItr == fPointSpectraVec.end()){
225  fPointSpectraVec.emplace_back(gridPoint);
226  fPointSpectraVec.back().oscPoints.emplace_back(itr);
227  }
228  else
229  psvItr->oscPoints.emplace_back(itr);
230  }
231 
232  // release space needed to read in the prediction library
233  r.removeCachedProduct(predLib);
234  }
235 
236  // for(auto const& itr : fPointSpectraVec)
237  // MF_LOG_VERBATIM("GridPointsBestFit")
238  // << itr.point
239  // << " has "
240  // << itr.oscPoints.size()
241  // << " spectra associated with it";
242 
243  }
244 
245  //......................................................................
247  cmf::PointSpectra const& pointSpectra)
248  {
249  // set the MC spectrum to the input Asimov spectrum to find the chi^2 for this universe
250  // compared to the known input values
251  cmf::ChiSqrCalculator::Instance()->SetSpectrum(dataSpectrum, true);
252 
253  double chiSqr;
254  double minChiSqr = cmf::kGarbageDouble;
255  cmf::Spectrum bestFitSpectrum;
256  cmf::OscillationParameterMap bestFitVals;
257 
258  for(auto const& oppItr : pointSpectra.oscPoints){
259  cmf::ChiSqrCalculator::Instance()->SetSpectrum(oppItr.PredictedSpectrum(),
260  false);
262  oppItr.OscPoint());
263 
264  if(chiSqr < minChiSqr){
265  minChiSqr = chiSqr;
266  bestFitSpectrum = cmf::Spectrum(oppItr.PredictedSpectrum());
267  bestFitVals = cmf::OscillationParameterMap(oppItr.OscPoint());
268  }
269  }
270 
271  MF_LOG_VERBATIM("GridPointsBestFit")
272  << pointSpectra
273  << " has min chi^2: "
274  << minChiSqr
275  << " at "
276  << cmf::OscParMapToString(bestFitVals);
277 
278  return cmf::PointBestFit(pointSpectra,
279  minChiSqr,
280  dataSpectrum,
281  bestFitSpectrum,
282  bestFitVals);
283  }
284 
285  //----------------------------------------------------------------------------
287  {
288  }
289 
290  //----------------------------------------------------------------------------
292  art::TFileDirectory & curDir,
293  std::vector<cmf::PointBestFit> const& universeBestFits)
294  {
295  // 2D histograms for the best fit hidden parameter values at each point in space
296  std::map<cmf::OscParm_t, cmf::PointMap> pointMaps;
297  cmf::PointMap chiSqrMap;
298 
299  size_t idx = 0;
300  size_t bestFitIdx;
301  double minChiSqr = cmf::kGarbageDouble;
302 
303  for(auto const& itr : universeBestFits){
304  chiSqrMap[itr] = itr.MinChiSqr();
305  for(auto const& opItr : itr.BestFitOscPars()){
306  if(opItr.first == fXParamEnum ||
307  opItr.second == fYParamEnum ) continue;
308  if(cmf::IsAngleParameter(opItr.first))
309  pointMaps[opItr.first][itr] = std::pow(std::sin(opItr.second), 2.);
310  else
311  pointMaps[opItr.first][itr] = opItr.second * cmf::cOscParams_Scales[opItr.first];
312  }
313  if(itr.MinChiSqr() < minChiSqr){
314  bestFitIdx = idx;
315  minChiSqr = itr.MinChiSqr();
316  }
317  ++idx;
318  }
319 
321  baseName + "BestFitSpectrum",
322  ";Bin;Events",
323  universeBestFits[bestFitIdx].BestFitSpectrum());
324 
325  // the chi^2 values aren't really hidden parameters, but this function
326  // does the trick
328  (baseName + "ChiSqr"),
329  chiSqrMap);
330 
331 
332  for(auto const& itr : pointMaps)
334  (baseName + cmf::cOscParams_Strings[itr.first]),
335  itr.second);
336 
337 
338  }
339 
340  //----------------------------------------------------------------------------
342  cmf::Spectrum const& randomUSpectrum,
343  cmf::Spectrum const& asimovUSpectrum,
344  std::vector<cmf::PointBestFit> const& randomUBestFit,
345  std::vector<cmf::PointBestFit> const& asimovUBestFit)
346  {
348 
349  // make a TFileDirectory to store the histograms for this calculation
350  art::TFileDirectory curDir = tfs->mkdir(baseName);
351 
352  // histograms for the random universe and asimov fake data spectra
354  "Random" + baseName + "Spectrum",
355  ";Bin;Events",
356  randomUSpectrum);
357 
358  this->BestFitPlots("Random" + baseName,
359  curDir,
360  randomUBestFit);
361 
363  "Asimov" + baseName + "Spectrum",
364  ";Bin;Events",
365  asimovUSpectrum);
366  this->BestFitPlots("Asimov" + baseName,
367  curDir,
368  asimovUBestFit);
369 
370  }
371 
372  //----------------------------------------------------------------------------
374  {
375  // make sure we aren't taking up too much space
376  fPointSpectraVec.shrink_to_fit();
377  fFakeUniverses.shrink_to_fit();
378 
379  std::set<float> xPoints;
380  std::set<float> yPoints;
381 
382  // do the same for the osc points in the vector
383  // sort the vector of OscParamPoints for the first universe
384  // figure out how many different points we have for each parameter.
385  for(auto & itr : fPointSpectraVec){
386  itr.oscPoints.shrink_to_fit();
387  std::sort(itr.oscPoints.begin(), itr.oscPoints.end());
388  xPoints.insert(itr.X());
389  yPoints.insert(itr.Y());
390  }
391 
392  MF_LOG_VERBATIM("GridPointsBestFit")
393  << " There are "
394  << fPointSpectraVec.size()
395  << " library points in the space with "
396  << fPointSpectraVec.front().oscPoints.size()
397  << " predictions at each point\n There are "
398  << fFakeUniverses.size()
399  << " fake universes";
400 
401  // if we ever wanted to downsample the number of spectra we use
402  // from the library, the call to do so should come here
403 
404  // now sort the universe point results in the library points vector
405  std::sort(fPointSpectraVec.begin(), fPointSpectraVec.end());
406 
407  // find the extrema in the space
408  std::pair<float, float> parXExtrema = std::make_pair(fPointSpectraVec.front().X(),
409  fPointSpectraVec.back() .X());
410  std::pair<float, float> parYExtrema = std::make_pair(fPointSpectraVec.front().Y(),
411  fPointSpectraVec.back() .Y());
412 
413  MF_LOG_DEBUG("GridPointsBestFit")
415  << " range is "
416  << parXExtrema.first
417  << " - "
418  << parXExtrema.second
419  << " "
421  << " range is "
422  << parYExtrema.first
423  << " - "
424  << parYExtrema.second;
425 
426 
427  // if NumUniverses is still set to 0, then the user did not specify a number so
428  // loop over all the fake universes
429  if(fNumUniverses < 1) fNumUniverses = fFakeUniverses.size();
430 
431  MF_LOG_VERBATIM("GridPointsBestFit")
432  << "Find chi^2 values for "
433  << fNumUniverses
434  << " universes starting with number "
435  << fStartUniverse;
436 
437  std::unique_ptr<std::vector<cmf::UniversePointBestFits>> bestFits = std::make_unique<std::vector<cmf::UniversePointBestFits>>();
438 
439  for(size_t u = fStartUniverse; u < fStartUniverse + fNumUniverses; ++u){
440 
441  MF_LOG_VERBATIM("GridPointsBestFit")
442  << "Universe "
443  << u
444  << " of "
445  << fNumUniverses;
446 
447  std::vector<cmf::PointBestFit> randomPBF;
448  std::vector<cmf::PointBestFit> asimovPBF;
449 
450  for(auto & itr : fPointSpectraVec){
451 
452  MF_LOG_DEBUG("GridPointsBestFit")
453  << itr;
454 
455  MF_LOG_VERBATIM("GridPointsBestFit")
456  << "Random universe";
457 
458  randomPBF.emplace_back(this->FindChiSqrForPoint(fFakeUniverses[u].PoissonSpectrum(), itr));
459 
460  MF_LOG_VERBATIM("GridPointsBestFit")
461  << "Asimov universe";
462 
463  asimovPBF.emplace_back(this->FindChiSqrForPoint(fFakeUniverses[u].AsimovSpectrum(), itr));
464 
465  } // end loop over points in the space
466 
467  // add this universe to the collection
468  bestFits->emplace_back(randomPBF,
469  asimovPBF);
470  } // end loop over universes
471 
472  MF_LOG_DEBUG("GridPointsBestFit")
473  << "There are "
474  << xPoints.size()
475  << " points in "
477  << " and "
478  << yPoints.size()
479  << " points in "
481 
483  fXParamEnum,
484  fYParamEnum,
485  xPoints.size() - 1,
486  yPoints.size() - 1,
487  parXExtrema,
488  parYExtrema,
489  fLogXAxis,
490  fLogYAxis);
491 
492  for(size_t u = 0; u < fNumUniverses; ++u){
493  this->MakeAndStorePlots("Universe_" + std::to_string(u) + "_",
494  fFakeUniverses[u + fStartUniverse].PoissonSpectrum(),
495  fFakeUniverses[u + fStartUniverse].AsimovSpectrum(),
496  (*bestFits)[u].RandomUniversePBF(),
497  (*bestFits)[u].AsimovUniversePBF());
498  }
499 
500  r.put(std::move(bestFits));
501  }
502 
504 
505 } // end namespace
float fNDFHCExposureScale
how much the ND FHC bins in the prediction libraries should be scaled by
std::string fPredictionModule
label for module containing the prediction point library
enum cmf::osc_params OscParm_t
void InitializeCovarianceMatrix(fhicl::ParameterSet const &pset)
std::vector< cmf::FakeUniverse > FakeUniColl
Definition: FakeUniverse.h:14
size_t fStartUniverse
which universe to start with in the fake universe file
static std::string OscParMapToString(cmf::OscillationParameterMap const &opm)
Definition: StaticFuncs.h:419
void Initialize(fhicl::ParameterSet const &pset)
std::vector< cmf::OscParamPoint > oscPoints
all the OscParamPoints for the XY location
void BestFitPlots(std::string const &baseName, art::TFileDirectory &curDir, std::vector< cmf::PointBestFit > const &universeBestFits)
const char * p
Definition: xmltok.h:285
static const double kGarbageDouble
Definition: Constants.h:18
float fFDFHCExposureScale
how much the FD FHC bins in the prediction libraries should be scaled by
constexpr T pow(T x)
Definition: pow.h:72
static SelectionUtility * Instance()
std::vector< double > Spectrum
Definition: Constants.h:746
bool fLogYAxis
are parameters on a log scale on the Y axis
std::vector< cmf::DetBeamBins > const & DetectorBeamBins()
TH1F * MakeSpectrumHistogram(art::TFileDirectory &tfd, std::string const &baseName, std::string const &baseTitle, cmf::Spectrum const &spectrum)
std::pair< Spectrum *, CheatDecomp * > make_pair(SpectrumLoaderBase &loader_data, SpectrumLoaderBase &loader_mc, HistAxis *axis, Cut *cut, const SystShifts &shift, const Var &wei)
Definition: DataMCLoad.C:336
std::map< cmf::DetBeamPair, float > fDBScaleMap
how do we want to scale our exposure?
fhicl::ParameterSet fPlotConfig
configuration for the plot utilities
static bool IsAngleParameter(cmf::OscParm_t const &par)
Definition: StaticFuncs.h:354
std::vector< cmf::PointSpectra > fPointSpectraVec
the point spectra for all the oscillation points
cmf::ChiSqrCalc_t fChiSqrToUse
which calculator to use
float fFDRHCExposureScale
how much the FD RHC bins in the prediction libraries should be scaled by
~GridPointsBestFit() override=default
cmf::OscParamPoint ScaleSpectra(std::vector< cmf::DetBeamBins > const &dbBinsVec, std::map< cmf::DetBeamPair, float > const &dBScaleMap) const
bool isValid() const
Definition: Handle.h:183
static ParameterUtility * Instance()
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:446
void reconfigure(fhicl::ParameterSet const &p)
std::map< cmf::OscParm_t, float > OscillationParameterMap
Definition: Constants.h:748
std::string fInputUniverseLabel
label for module containing the prediction point library
#define DEFINE_ART_RESULTS_PLUGIN(klass)
T get(std::string const &key) const
Definition: ParameterSet.h:231
void Initialize(fhicl::ParameterSet const &pset)
cmf::FakeUniColl fFakeUniverses
the input fake universes
cmf::OscParm_t fXParamEnum
enumerated value of the parameter from CovarianceMatrixFit/dataProducts/Constants.h
void Initialize(fhicl::ParameterSet const &plottingPars)
cmf::OscParm_t fYParamEnum
enumerated value of the parameter from CovarianceMatrixFit/dataProducts/Constants.h
bool removeCachedProduct(Handle< PROD > &) const
Definition: DataViewImpl.h:971
bool fScaleExposure
should the exposure of the prediction libraries be scaled?
static cmf::ChiSqrCalculator * Instance()
double ChiSqr(cmf::ChiSqrCalc_t const &chiSqrCalc, std::vector< std::string > const &pars, const double *vals)
static cmf::ChiSqrCalc_t StringToChiSqrType(std::string const &str)
Module to combine a set of results into a single file currently only does one data product type at a ...
Definition: Event.cxx:24
float fNDRHCExposureScale
how much the ND RHC bins in the prediction libraries should be scaled by
cmf::PointBestFit FindChiSqrForPoint(cmf::Spectrum const &dataSpectrum, cmf::PointSpectra const &pointSpectra)
T sin(T number)
Definition: d0nt_math.hpp:132
bool fLogXAxis
are parameters on a log scale on the X axis
std::map< cmf::GridPoint, double > PointMap
float fXParamMin
minimum and maximum ranges to consider for XY parameters
void MakeAndStorePlots(std::string const &baseName, cmf::Spectrum const &randomUSpectrum, cmf::Spectrum const &asimovUSpectrum, std::vector< cmf::PointBestFit > const &randomUBestFit, std::vector< cmf::PointBestFit > const &asimovUBestFit)
#define MF_LOG_VERBATIM(category)
void readResults(art::Results const &r) override
#define MF_LOG_DEBUG(id)
static PlotUtilities * Instance()
TRandom3 r(0)
const std::vector< double > cOscParams_Scales({1., 1., 1.e5, 1.e3, 1., 1., 1., 1./3.14159, 1., 1., 1., 1., 1./3.14159, 1., 1., 1., 1., 1., 1., 1., 1., 1.})
void Initialize(fhicl::ParameterSet const &pset)
ProductID put(std::unique_ptr< PROD > &&edp, FullSemantic< Level::Run > const semantic)
Definition: DataViewImpl.h:730
void writeResults(art::Results &r) override
GridPointsBestFit(fhicl::ParameterSet const &pset)
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
size_t fNumUniverses
number of universes to use when making contours
static cmf::OscParm_t StringToOscParmType(std::string const &str)
void Make2DHiddenParHistogram(art::TFileDirectory &tfd, std::string const &baseName, cmf::PointMap const &parVals)
enum cmf::chisqr_type ChiSqrCalc_t
void SetSpectrum(cmf::Spectrum const &spectrum, bool isData)
static CovarianceBinUtility * Instance()
const std::vector< std::string > cOscParams_Strings({"L","Rho","Dmsq21","Dmsq32","Th12","Th13","Th23","dCP","Th14","Th24","Th34","Dmsq41","d24","Eps_ee","Eps_emu","Eps_etau","Eps_mumu","Eps_mutau","Eps_tautau","Delta_emu","Delta_etau","Delta_mutau"})
enum BeamMode string