ND_DataMC_Comp_Systs_header.h
Go to the documentation of this file.
3 #include "CAFAna/Core/Binning.h"
4 #include "CAFAna/Core/Spectrum.h"
5 #include "CAFAna/Core/Var.h"
7 #include "CAFAna/Vars/HistAxes.h"
10 #include "Utilities/rootlogon.C"
11 
12 #include "TCanvas.h"
13 #include "TGraph.h"
14 #include "TGaxis.h"
15 #include "TLegend.h"
16 #include "TLegendEntry.h"
18 
19 #include <iostream>
20 #include <string>
21 #include <sstream>
22 #include <fstream>
23 #include <iomanip>
24 
25 using namespace ana;
26 
27 const int DataCol = kBlack;
28 const int DataMar = kFullCircle;
29 
30 const int FullPred = kViolet - 5;
31 const int PredErr = kViolet - 9;
32 const int WrongSi = kGreen - 6;
33 const int TotalBkg = kGray + 1;
34 
35 // ******************** Weight bins by bin width for neutrino energy plots ********************
36 const Var kBinWidthWeight([](const caf::SRProxy *sr){
37  const double Enu = kCCE(sr); // If want bin normalized
38  //const double Enu = 6; // If don't want bin normalized.
39  if(Enu < 0.75) return 0.1 / 0.75;
40  if(Enu >= 0.75 && Enu < 1) return 0.1 / 0.25;
41  if(Enu >= 1 && Enu < 2) return 0.1 / 0.1;
42  if(Enu >= 2 && Enu < 3) return 0.1 / 0.25;
43  if(Enu >= 3 && Enu < 4) return 0.1 / 0.5;
44  if(Enu >= 4 && Enu < 5) return 0.1 / 1;
45  else return 1.;
46  });
47 
48 // ******************** Function to centre axis titles ********************
49 void CenterTitles() {
50  for(const auto& obj:*(gPad->GetListOfPrimitives())) {
51 
52  if(obj->InheritsFrom("TH1")) CenterTitles((TH1*)obj);
53  }
54 }
55 /*
56 // ******************** Function to write preliminary ********************
57 void Preliminary()
58 {
59  TLatex* prelim = new TLatex(.9, .95, "NOvA Preliminary");
60  prelim->SetTextColor(kBlue);
61  prelim->SetNDC();
62  prelim->SetTextSize(2/30.);
63  prelim->SetTextAlign(32);
64  prelim->Draw();
65 }
66 */
67 // ******************** A custom made class ********************
68 template<class T> class Tangible
69 {
70 
71  public:
72  Tangible(const T& obj, const std::string& shortName,
73  const std::string& blurb ):
74  fObj(obj),
75  fShortName(shortName),
76  fBlurb(blurb)
77  {};
78 
79  T fObj;
82 
83 };
84 
85 // ******************** Some typedefs ********************
88 
89 
90 // ******************** A very large custom made class ********************
91 class DataMCPair
92 {
93  public:
94 
95  DataMCPair(Selection sel, TangibleAxis tanAxis,
96  SpectrumLoader& loaderData, SpectrumLoader& loaderMC,
97  std::vector<const ISyst*> systs, const Var BinWeight, const Cut& bkg=kNoCut, const Cut& wrs=kNoCut ):
98  fSel(sel),
99  fAxis(tanAxis),
100  fData (loaderData, fAxis.fObj, fSel.fObj , kNoShift, BinWeight),
101  fMC (loaderMC , fAxis.fObj, fSel.fObj , kNoShift, BinWeight),
102  fWrong(loaderMC , fAxis.fObj, fSel.fObj && wrs, kNoShift, BinWeight),
103  fMCBkg(loaderMC , fAxis.fObj, fSel.fObj && bkg, kNoShift, BinWeight),
104  fShortName(fAxis.fShortName + "_" + fSel.fShortName)
105  {
106  fUps.reserve(systs.size());
107  fDowns.reserve(systs.size());
108  for(const auto& syst:systs){
109  fUps .emplace_back(loaderMC, fAxis.fObj, fSel.fObj, SystShifts(syst, +1), BinWeight);
110  fDowns.emplace_back(loaderMC, fAxis.fObj, fSel.fObj, SystShifts(syst, -1), BinWeight);
111  }
112  };
113 
115  {return fShortName;};
116 
117  // ******************** Function used to draw POT Normalized plots ********************
118  void OverlayDataMCSyst(const int iSyst = -1) const {
119 
120  TH1D* hDummy = fData.ToTH1(fData.POT());
121  hDummy->SetMarkerColor(DataCol);
122  hDummy->SetMarkerStyle(DataMar);
123  hDummy->SetLineColor (DataCol);
124  hDummy->Draw();
125 
126  DrawMCSyst(iSyst);
127  DrawMCBkg();
128  DrawWrong();
129  DrawData();
130  hDummy -> Draw( "axis same" );
131  TLegend* leg = DrawLegend();
132  CenterTitles();
133  RedrawAxes();
134  AddExposure( true );
135  };
136 
137  // ******************** Function used to draw area normalized plots ********************
138  void OverlayDataMCSystNorm(const int iSyst = -1) const {
139 
140  TH1D* hDummy = fData.ToTH1(fData.POT());
141  hDummy->SetMarkerColor(DataCol);
142  hDummy->SetMarkerStyle(DataMar);
143  hDummy->SetLineColor (DataCol);
144  hDummy->Draw();
145 
146  DrawMCNormSyst(iSyst);
147  DrawMCBkg();
148  DrawWrong();
149  DrawData();
150  hDummy->Draw( "axis same" );
151  TLegend* leg = DrawLegend();
152  CenterTitles();
153  RedrawAxes();
154  AddExposure( false );
155  };
156 
157 
158  // ******************** Simple function to draw the systematics ********************
159  void DrawMCSyst(const int iSyst = -1) const
160  {
161  TH1* hNom = fMC.ToTH1(fData.POT(), kBlack, kSolid, kPOT);
162  if ( ShortName().find("NuMuE") != std::string::npos ) hNom -> Scale(0.1,"width");
163  hNom -> Scale( 1e-3 );
164  std::vector <TH1*> hUps, hDos;
165  for (const auto& Up:fUps) {
166  // Ups.
167  TH1* hTempUp = Up.ToTH1( fData.POT(), kBlack, kSolid, kPOT );
168  if ( ShortName().find("NuMuE") != std::string::npos ) hTempUp -> Scale(0.1,"width");
169  hTempUp -> Scale( 1e-3 );
170  hUps.push_back( hTempUp );
171  }
172  for (const auto& Do:fDowns) {
173  // Dos.
174  TH1* hTempDo = Do.ToTH1( fData.POT(), kBlack, kSolid, kPOT );
175  if ( ShortName().find("NuMuE") != std::string::npos ) hTempDo -> Scale(0.1,"width");
176  hTempDo -> Scale( 1e-3 );
177  hDos.push_back( hTempDo );
178  }
179 
180  PlotWithSystErrorBand( hNom, hUps, hDos, FullPred, PredErr, 1.5, true );
181  }
182 
183  // ******************** Function to draw area normalized systematics ********************
184  void DrawMCNormSyst(const int iSyst = -1) const {
185  // New vectors for area normalized systs
186  std::vector<Spectrum> normUps;
187  std::vector<Spectrum> normDowns;
188 
189  Spectrum tempMC(fMC.ToTH1(fMC.POT()),fMC.POT(),fMC.Livetime());
190  tempMC.OverridePOT( fMC.POT() * fMC.ToTH1(fData.POT())->GetSumOfWeights() / fData.ToTH1(fData.POT())->GetSumOfWeights() );
191 
192  TH1* hNom = tempMC.ToTH1( fData.POT(), kBlack, kSolid, kPOT );
193  if ( ShortName().find("NuMuE") != std::string::npos ) hNom -> Scale(0.1,"width");
194  hNom -> Scale( 1e-3 );
195 
196  if (iSyst >= 0) {
197  // We'll have one entry if there's just one syst to plot.
198  normUps.reserve(1);
199  normDowns.reserve(1);
200  } else {
201  // Otherwise we need all systs.
202  normUps.reserve(fUps.size());
203  normDowns.reserve(fUps.size());
204  }
205 
206  for(size_t i = 0; i < fUps.size(); ++i) {
207  // bail if we want a particular syst and it's not the one we want.
208  if(iSyst >= 0 && (int)i != iSyst) continue;
209  normUps.emplace_back(fUps[i]);
210  Spectrum& norm = normUps.back();
211  norm.OverridePOT(norm.POT() * norm.Integral(1) / tempMC.Integral(1));
212  }
213 
214  for ( size_t i = 0; i < fDowns.size(); ++i)
215  {
216  // bail if we want a particular syst and it's not the one we want.
217  if(iSyst >= 0 && (int)i != iSyst) continue;
218  normDowns.emplace_back(fDowns[i]);
219  Spectrum& norm = normDowns.back();
220  norm.OverridePOT(norm.POT() * norm.Integral(1) / tempMC.Integral(1));
221  }
222 
223  std::vector <TH1*> hUps, hDos;
224  for (const auto& Up:normUps) {
225  // Ups.
226  TH1* hTempUp = Up.ToTH1( fData.POT(), kBlack, kSolid, kPOT );
227  if ( ShortName().find("NuMuE") != std::string::npos ) hTempUp -> Scale(0.1,"width");
228  hTempUp -> Scale( 1e-3 );
229  hUps.push_back( hTempUp );
230  }
231  for (const auto& Do:normDowns) {
232  // Dos.
233  TH1* hTempDo = Do.ToTH1( fData.POT(), kBlack, kSolid, kPOT );
234  if ( ShortName().find("NuMuE") != std::string::npos ) hTempDo -> Scale(0.1,"width");
235  hTempDo -> Scale( 1e-3 );
236  hDos.push_back( hTempDo );
237  }
238  PlotWithSystErrorBand( hNom, hUps, hDos, FullPred, PredErr, 1.5, true );
239  }
240 
241  TLegend* DrawLegend() const {
242 
243  TLegend* leg = AutoPlaceLegend(0.25, 0.19, 0.68);
244 
245  TH1F* colMC = new TH1F();
246  colMC ->SetLineColor ( FullPred );
247  TH1F* colWrong = new TH1F();
248  colWrong->SetLineColor ( WrongSi );
249  colWrong->SetFillColor ( WrongSi );
250  TH1F* colMCBkg = new TH1F();
251  colMCBkg->SetLineColor ( TotalBkg );
252  colMCBkg->SetFillColor ( TotalBkg );
253  TH1F* colData = new TH1F();
254  colData->SetLineColor ( DataCol );
255  colData->SetMarkerColor( DataCol );
256  colData->SetMarkerStyle( DataMar ) ;
257 
258  leg->AddEntry((TObject*)colData , "Data" , "ple");
259  leg->AddEntry((TObject*)colMC , "Simulation", "l" );
260  TLegendEntry *entryns1=leg->AddEntry("error","1-#sigma syst. range","f");
261  if (IsFHC) leg->AddEntry((TObject*)colWrong, "Wrong Sign: #bar{#nu_{#mu}} CC", "f" );
262  else leg->AddEntry((TObject*)colWrong, "Wrong Sign: #nu_{#mu} CC" , "f" );
263  leg->AddEntry((TObject*)colMCBkg, "Total Background", "f" );
264  entryns1->SetLineColor( PredErr );
265  entryns1->SetFillStyle( 1001 );
266  entryns1->SetFillColor( PredErr );
267  leg->SetTextSize(0.04);
268 
269  leg->SetFillColor(0);
270  leg->SetFillStyle(0);
271 
272  for(const auto& obj:*leg->GetListOfPrimitives())
273  {
274  if(obj->InheritsFrom("TAttFill")){
275  ((TAttFill*)obj)->SetFillStyle(0);
276  //((TAttFill*)obj)->SetFillColor(0);
277  }
278 
279  }
280  leg->Draw();
281  return leg;
282  }
283 
284  void AddExposure( bool IsPOT ) const
285  {
286  // Format Latex and text placement
287  TLatex text;
288  text.SetTextAlign(22);
289  text.SetTextSize(0.04);
290  // Figure out means and integrals.
291  std::stringstream expo;
292  std::stringstream expoData;
293  std::stringstream expoMC;
294  float pot = fData.POT();
295  float dataMean = (fData.ToTH1(pot)) -> GetMean();
296  float dataMeanError = (fData.ToTH1(pot)) -> GetMeanError();
297  float dataIntegral = (fData.ToTH1(pot)) -> Integral( 0, (fData.ToTH1(pot))->GetNbinsX() );
298  float MCMean = (fMC .ToTH1(pot)) -> GetMean();
299  float MCMeanError = (fMC .ToTH1(pot)) -> GetMeanError();
300  float MCIntegral = (fMC .ToTH1(pot)) -> Integral();
301  // Decide my stringsteams.
302  expoData << fixed << setprecision(3) << "Data mean: " << dataMean << ", Integral: " << dataIntegral;
303  expoMC << fixed << setprecision(3) << "Mont mean: " << MCMean << ", Integral: " << MCIntegral;
304 
305  // Figure out my character strings.
306  std::string sFHC = (IsFHC == true ? "Neutrino beam":"Antineutrino beam");
307  std::string sPOT = (IsPOT == true ? "POT":"Area");
308  // Figure out which quartile I'm looking at.
309  std::string sQnt = "";
310  if ( ShortName().find("Quant1") != std::string::npos) sQnt = "Quartile 1";
311  else if ( ShortName().find("Quant2") != std::string::npos) sQnt = "Quartile 2";
312  else if ( ShortName().find("Quant3") != std::string::npos) sQnt = "Quartile 3";
313  else if ( ShortName().find("Quant4") != std::string::npos) sQnt = "Quartile 4";
314 
315  TLegend* place = AutoPlaceLegend(0.0001, 0.0001, 0.54);
316  if ( !Bless || sQnt != "" ) {
317  place = AutoPlaceLegend(0.0001, 0.0001, 0.525);
318  } else if ( !Bless && sQnt != "" ) {
319  place = AutoPlaceLegend(0.0001, 0.0001, 0.50);
320  }
321  // Print stuff out to the screen...
322  std::cout << "\n\t Looking at " << ShortName() << ", " << sFHC << ", " << sPOT
323  << "\n\t Data Mean / Integral are; " << dataMean << ", " << dataIntegral
324  << "\n\t Mont Mean / Integral are; " << MCMean << ", " << MCIntegral
325  << std::endl;
326 
327  // Decide what I'm putting in the legend
328  std::string Descrip = sPOT+" Normalized";
329  if ( sQnt != "" ) Descrip = "#splitline{"+sPOT+" Normalized}{"+sQnt+"}";
330  if ( !Bless ) {
331  Descrip = "#splitline{"+sPOT+" Normalized}{#splitline{"+expoData.str()+"}{"+expoMC.str()+"}}";
332  if ( sQnt != "" )
333  Descrip = "#splitline{"+sPOT+" Normalized}{#splitline{"+sQnt+"}{#splitline{"+expoData.str()+"}{"+expoMC.str()+"}}}";
334  }
335  // Print the legend
336  text.DrawLatexNDC( place->GetX1(), place->GetY1(), Descrip.c_str() );
337  }
338 
339  void RedrawAxes() const
340  {
341  // --- Loop through the objects in the pad.
342  for(const auto& obj:*(gPad->GetListOfPrimitives())) {
343  // --- Want to repaint all TH1's.
344  if(obj->InheritsFrom("TH1")) {
345  // --- Check if I have the Reco Energy canvas?
346  std::string XTitle = ((TH1*)obj)->GetXaxis()->GetTitle();
347  std::stringstream YAxisStr;
348  YAxisStr << "10^{3} Events / " << Form("%.2f#times10^{20} POT",fData.POT()/1e20);
349  if ( XTitle.find("Reconstructed Neutrino Energ") != std::string::npos ) {
350  YAxisStr << " / 0.1 GeV";
351  }
352  ((TH1*)obj)->GetYaxis()->SetTitle( YAxisStr.str().c_str() );
353  // Repaint the axes.
354  ((TH1*)obj)->GetXaxis()->Paint();
355  //((TH1*)obj)->GetYaxis()->SetTitleOffset(1.1);
356  ((TH1*)obj)->GetYaxis()->Paint();
357  ((TH1*)obj)->GetZaxis()->Paint();
358  }
359  }
360  }
361 
362  void DrawData() const {
363 
364  TH1D* hData = fData.ToTH1(fData.POT());
365  std::cout << "\t Data integral is " << hData->Integral() << ", mean is " << hData->GetMean() << std::endl;
366 
367  if (ShortName().find("NuMuE") != std::string::npos) {
368  hData -> Scale(0.1,"width");
369  }
370  hData -> Scale( 1e-3 );
371  hData->SetMarkerColor( DataCol );
372  hData->SetMarkerStyle( DataMar );
373  hData->SetLineColor ( DataCol );
374  hData->Draw("same");
375  };
376 
377  void DrawMCBkg() const
378  {
379  TH1D* hMCBkg = fMCBkg.ToTH1(fData.POT());
380  std::cout << "\t MCBkg integral is " << hMCBkg->Integral() << ", mean is " << hMCBkg->GetMean() << std::endl;
381 
382  if (ShortName().find("NuMuE") != std::string::npos) {
383  hMCBkg -> Scale(0.1,"width");
384  }
385  hMCBkg->Scale( 1e-3 );
386  hMCBkg->SetLineColor( TotalBkg );
387  hMCBkg->SetFillColor( TotalBkg );
388  hMCBkg->Draw("hist same");
389  };
390 
391  void DrawWrong() const
392  {
393  TH1D* hWrong = fWrong.ToTH1(fData.POT());
394  std::cout << "\t hWrong integral is " << hWrong->Integral() << ", mean is " << hWrong->GetMean() << std::endl;
395 
396  if (ShortName().find("NuMuE") != std::string::npos) {
397  hWrong -> Scale(0.1,"width");
398  }
399  hWrong->Scale( 1e-3 );
400  hWrong->SetLineColor( WrongSi );
401  hWrong->SetFillColor( WrongSi );
402  hWrong->Draw("hist same");
403  };
404 
405 
406 
407  float Purity() const
408  {
409  return 1 - fMCBkg.ToTH1(fData.POT())->GetEntries() /
410  fMC.ToTH1(fData.POT())->GetEntries();
411  }
412 
413  Selection fSel;
414  TangibleAxis fAxis;
415  Spectrum fData;
416  Spectrum fMC;
417  Spectrum fMCBkg;
419  std::vector<Spectrum> fUps;
420  std::vector<Spectrum> fDowns;
422 
423 };
424 
425 // ******************** A function to return keys ********************
426 /// Return an iterator if all keys are found in only one entry
427 //std::vector<DataMCPair>::iterator findPair(std::vector<DataMCPair>& list,
428 DataMCPair* findPair(std::vector<DataMCPair>& list,
429  std::vector<std::string> keys)
430 {
431  int nFound = 0;
432 
433  std::vector<DataMCPair>::iterator it = list.end();
434 
435  for(std::vector<DataMCPair>::iterator entry = list.begin();
436  entry != list.end();
437  ++entry)
438  {
439  /// Assume we're going to find it, innocent until guilty
440  bool found = true;
441  for(const auto& key:keys)
442  {
443  std::cout << entry->ShortName() << " " << key << " " << found << std::endl;
444  std::cout << (entry->ShortName().find(key) == std::string::npos) << " " << entry->ShortName().find(key) << " " << std::string::npos << std::endl;
445  // If any key is not present, this isn't the one.
446  if(entry->ShortName().find(key) == std::string::npos)
447  {
448 
449  found = false;
450  std::cout << entry->ShortName() << " " << key << " " << found << " " <<entry->ShortName().find(key) << std::endl;
451  break;
452 
453  }
454 
455  }
456  if(found)
457  {
458  it = entry;
459  nFound += 1;
460  }
461 
462  }
463  std::cout << "nFound: "<< nFound << std::endl;
464  if(nFound == 0) throw "Failed to find match.";
465  if(nFound > 1) throw "Found too many matches.";
466 
467  return &(*it);
468 }
469 
470 // ******************** A function to write a blurb ********************
472  std::string extra = "", std::string beginning = "")
473 {
474  std::ofstream out(dir + name);
475  out << pair.fAxis.fBlurb << pair.fSel.fBlurb << extra;
476 }
const XML_Char * name
Definition: expat.h:151
tree Draw("slc.nhit")
keys
Reco plots.
Definition: caf_analysis.py:46
Cuts and Vars for the 2020 FD DiF Study.
Definition: vars.h:6
set< int >::iterator it
std::vector< SystGroupDef > systs
Definition: syst_header.h:385
DataMCPair * findPair(std::vector< DataMCPair > &list, std::vector< std::string > keys)
Return an iterator if all keys are found in only one entry.
double Integral(const Spectrum &s, const double pot, int cvnregion)
bool IsFHC
Simple record of shifts applied to systematic parameters.
Definition: SystShifts.h:20
void OverridePOT(double newpot)
DO NOT USE UNLESS YOU ARE 110% CERTAIN THERE ISN&#39;T A BETTER WAY!
Definition: Spectrum.h:233
void AddExposure(bool IsPOT) const
Proxy for caf::StandardRecord.
Definition: SRProxy.h:2126
std::string fShortName
Definition: DataMCPair.h:47
const int WrongSi
Tangible< Cut > Selection
Definition: DataMCPair.h:52
const int FullPred
std::string ShortName() const
void CenterTitles(TH1 *histo)
Definition: Plots.cxx:1481
double Integral(double exposure, double *err=0, EExposureType expotype=kPOT) const
Return total number of events scaled to pot.
Definition: Spectrum.cxx:249
cout<< t1-> GetEntries()
Definition: plottest35.C:29
Representation of a spectrum in any variable, with associated POT.
Definition: Spectrum.h:40
TGraphAsymmErrors * PlotWithSystErrorBand(IPrediction *pred, const std::vector< const ISyst * > &systs, osc::IOscCalc *calc, double pot, int col, int errCol, float headroom, bool newaxis, EBinType bintype)
Plot prediction with +/-1sigma error band.
Definition: Plots.cxx:304
const int DataMar
ProcessPackage< L > Do
void DrawMCSyst(const int iSyst=-1) const
std::string sFHC
Definition: MakeCutFlow.C:35
void DrawLegend(LegendMap &legobj, int textCol=kBlack)
DataMCPair(Selection sel, TangibleAxis tanAxis, SpectrumLoader &loaderData, SpectrumLoader &loaderMC, std::vector< const ISyst * > systs, const Var BinWeight, const Cut &bkg=kNoCut, const Cut &wrs=kNoCut)
Tangible(const T &obj, const std::string &shortName, const std::string &blurb)
void RedrawAxes()
const int DataCol
void WriteBlurb(const DataMCPair &pair, std::string dir, std::string name, std::string extra="", std::string beginning="")
Tangible< HistAxis > TangibleAxis
Definition: DataMCPair.h:53
const Var kCCE
Definition: NumuVars.h:21
#define pot
caf::StandardRecord * sr
bool Bless
TLegend * DrawLegend() const
double POT() const
Definition: Spectrum.h:227
const Var kBinWidthWeight([](const caf::SRProxy *sr){const double Enu=kCCE(sr); if(Enu< 0.75) return 0.1/0.75;if(Enu >=0.75 &&Enu< 1) return 0.1/0.25;if(Enu >=1 &&Enu< 2) return 0.1/0.1;if(Enu >=2 &&Enu< 3) return 0.1/0.25;if(Enu >=3 &&Enu< 4) return 0.1/0.5;if(Enu >=4 &&Enu< 5) return 0.1/1;else return 1.;})
const SystShifts kNoShift
Definition: SystShifts.cxx:22
OStream cout
Definition: OStream.cxx:6
const int PredErr
std::string fBlurb
Definition: DataMCPair.h:46
Selection fSel
Definition: DataMCPair.h:182
Float_t norm
Collaborates with Spectrum and OscillatableSpectrum to fill spectra from CAF files.
TDirectory * dir
Definition: macro.C:5
enum BeamMode kViolet
void OverlayDataMCSystNorm(const int iSyst=-1) const
string shortName
THUMBNAIL BLOCK: We need to make a thumbnail for each.
TLegend * AutoPlaceLegend(double dx, double dy, double yPin)
Create a legend, maximizing distance from all histograms.
Definition: Plots.cxx:715
double T
Definition: Xdiff_gwt.C:5
Float_t e
Definition: plot.C:35
enum BeamMode kGreen
void DrawMCNormSyst(const int iSyst=-1) const
def entry(str)
Definition: HTMLTools.py:26
short int place(double jd_tt, object *cel_object, observer *location, double delta_t, short int coord_sys, short int accuracy, sky_pos *output)
simulatedPeak Scale(1/simulationNormalisationFactor)
void OverlayDataMCSyst(const int iSyst=-1) const
const Cut kNoCut
The simplest possible cut: pass everything, used as a default.
Definition: Cut.h:109
const int TotalBkg
enum BeamMode string