EvtTimeFNALBeam.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file EvtTimeFNALBeam.cxx
3 /// \brief configurable FNAL Beam time distribution
4 ///
5 /// \version $Id: EvtTimeFNALBeam.cxx,v 1.1 2015/06/30 18:01:24 rhatcher Exp $
6 /// \author Robert Hatcher <rhatcher \at fnal.gov>
7 /// Fermi National Accelerator Laboratory
8 ///
9 /// \update 2015-06-22 initial version
10 /// \update 2019-03-12 updated version w/ configurability for Booster
11 ///
12 /// This routine is based on a "theoretical" description of how
13 /// the Fermilab accelerator system works.
14 ///
15 /// For the Booster there are 84 RF "buckets" or 84 "bunches" of protons
16 /// in the system at a time; a "notch" (3) is taken out
17 /// leaving 81 filled buckets / bunches === "batch"
18 ///
19 /// NuMI take 2 sets of 6 batches and stacks them.
20 /// In actual practice doesn't have stacking so exact with a
21 /// 1-2 bucket offset, so inter-batch separation isn't as deep
22 /// If we ever desire a more data driven time profile we can
23 /// get wall monitor time structure histograms from Phil A.
24 ///
25 /// A note about "bucket" or "bunch" width (essentially the same thing)
26 /// per Phil A. private conversation (2010-03-25):
27 /// 0.75 ns sigma for NuMI comes from MINOS Time-of-Flight paper
28 /// though it could be currently ~ 1ns
29 /// 2.0 - 2.5 ns width for Booster is reasonable
30 /// it is expected that the Booster width >> NuMI width
31 /// due to higher electric fields / deeper buckets
32 ///
33 ////////////////////////////////////////////////////////////////////////
34 
35 #include "EvtTimeFNALBeam.h"
36 #include "EvtTimeShiftFactory.h"
38 
39 #include <iostream>
40 #include <iomanip>
41 #include <algorithm>
42 
43 //GENIE includes
44 #ifdef GENIE_PRE_R3
45  #include "GENIE/Utils/StringUtils.h"
46 #else
47  #include "GENIE/Framework/Utils/StringUtils.h"
48 #endif
50 #include "cetlib_except/exception.h"
51 
52 const double ksigma2fwhm = 2.0*std::sqrt(2.0*std::log(2.0));
53 
54 namespace evgb {
55 
57  // default to a NuMI config
58  : EvtTimeShiftI(config)
59  , fTimeBetweenBuckets(1e9/53.103e6)
60  , fBucketTimeSigma(0.750)
61  , fNBucketsPerBatch(84) // NOvA-era 81+3, MINOS-era 81+5
62  , fNFilledBucketsPerBatch(81) // 81 for both eras
63  , fDisallowedBatchMask(6,0) // don't disallow any
64  , fGlobalOffset(0)
65  {
66  std::vector<double> bi(6,1.0); // 6 equal batches
68  Config(config);
69  }
70 
72 
74  {
75  // parse config string
76  if ( config == "" ) return;
77  // GENIEHelper does a PrintConfig() when it gets this object ...
78 
79  // not the most sophisticated of parsing ... but FHICL would be overkill
80 
81  std::string configLocal = config;
82  // convert string to lowercase
83  std::transform(configLocal.begin(),configLocal.end(),configLocal.begin(),::tolower);
84 
85  // for now make use of GENIE utilities
86  std::vector<std::string> strs =
87  genie::utils::str::Split(configLocal,"\t\n ,;=(){}[]");
88  // weed out blank ones
89  strs.erase(std::remove_if(strs.begin(), strs.end(),
90  [](const std::string& x) {
91  return ( x == "") ; // put your condition here
92  }), strs.end());
93 
94  // debugging info
95  std::ostringstream msgx;
96  msgx << "Config elements:" << std::endl;
97  for (size_t j=0; j<strs.size(); ++j) {
98  msgx << " [" << std::setw(3) << j << "] -->" << strs[j] << "<--\n";
99  }
100  // this should end up as LogDebug
101  mf::LogDebug("EvtTime") << msgx.str() << std::flush;
102 
103  // blindly reduced UPPER -> lower case above to make this easier
104  size_t nstrs = strs.size();
105  for (size_t i=0; i<nstrs; ++i) {
106  if ( strs[i] == "numi" ) {
107  fTimeBetweenBuckets = 1e9/53.103e6;
108  fBucketTimeSigma = 0.750;
109  fNBucketsPerBatch = 84; // NOvA-era 81+3, MINOS-era 81+5
110  fNFilledBucketsPerBatch = 81; // 81 for both eras
111  fDisallowedBatchMask = std::vector<int>(6,0); // don't disallow any
112  fGlobalOffset = 0;
113  std::vector<double> bi(6,1.0); // 6 equal batches
115  } else
116  if ( strs[i] == "booster" ) {
117  fTimeBetweenBuckets = 1e9/53.103e6;
118  fBucketTimeSigma = 2.0;
119  fNBucketsPerBatch = 84; //
120  fNFilledBucketsPerBatch = 81; //
121  fDisallowedBatchMask = std::vector<int>(1,0); // don't disallow any
122  fGlobalOffset = 0;
123  std::vector<double> bi(1,1.0); // 1 batch
125  } else
126  if ( strs[i].find("intensity") != std::string::npos ) {
127  // a list of batch intensities ... sets # of batches
128  // eat values up until we see the end, or a word
129  std::vector<double> bi;
130  // count how many of next tokens are numbers (crude)
131  for (size_t jj=i+1; jj<nstrs; ++jj) {
132  // very crude check of being a number
133  // can be fooled by strange text
134  size_t pos = strs[jj].find_first_not_of("0123456789.-+eE");
135  if ( pos != std::string::npos ) break;
136  // looks like a numeric value
137  double val = atof(strs[jj].c_str());
138  if ( val < 0 ) {
139  mf::LogError("EvtTime")
140  << "EvtTimeFNALBeam 'intensity' value [" << (jj-i-1)
141  << "]=" << val << " '" << strs[jj] << "' "
142  << "can't be less than zero, setting to zero";
143  val = 0;
144  }
145  bi.push_back(val);
146  }
147  // ate up some strings ... move loop index
148  i += bi.size();
149  if ( bi.empty() ) {
150  mf::LogError("EvtTime")
151  << "EvtTimeFNALBeam error 'intensity' option didn't seem to have values";
152  } else {
154  }
155  } else
156  if ( strs[i] == "bdisallowed" ) {
157  mf::LogError("EvtTime")
158  << "EvtTimeFNALBeam sorry 'bdisallowed' option not yet implemented";
159  } else {
160  // all the rest take one numeric value
161  if ( i+1 >= nstrs ) {
162  mf::LogError("EvtTime")
163  << "EvtTimeFNALBeam sorry too few values for '" << strs[i] << "'";
164  continue;
165  }
166  const char* arg = strs[i+1].c_str();
167  if ( strs[i] == "sigma" ) fBucketTimeSigma = atof(arg);
168  else if ( strs[i] == "fwhm" ) fBucketTimeSigma = atof(arg)/ksigma2fwhm;
169  else if ( strs[i] == "dtbucket" ) fTimeBetweenBuckets = atof(arg);
170  else if ( strs[i] == "nperbatch" ) fNBucketsPerBatch = atoi(arg);
171  else if ( strs[i] == "nfilled" ) fNFilledBucketsPerBatch = atoi(arg);
172  else if ( strs[i] == "global" ) fGlobalOffset = atof(arg);
173  else {
174  mf::LogError("EvtTime")
175  << "unknown EvtTimeFNALBeam config key '" << strs[i] << "'";
176  continue;
177  }
178  ++i; // used up an argument
179  }
180  }
181  // consistency check
183  mf::LogError("EvtTime")
184  << "EvtTimeFNALBeam nfilled " << fNFilledBucketsPerBatch
185  << " of " << fNBucketsPerBatch << " buckets per batch,\n"
186  << "set nfilled to match buckets per batch";
188  }
189 
190  }
191 
193  {
194  // calculate in small to large
195 
196  // pick a time within a bucket
197  double offset = fRndmGen->Gaus(0.0,fBucketTimeSigma);
198 
199  // pick a bucket within a batch
200  // assume all ~ buckets constant in batch until we have another model
201  offset += fTimeBetweenBuckets *
202  (double)fRndmGen->Integer(fNFilledBucketsPerBatch);
203 
204  // pick a bucket
205  bool disallowed = true;
206  size_t ibatch = 0;
207  size_t nbatch = fCummulativeBatchPDF.size();
208  double r = 2;
209  while ( disallowed ) {
210  r = fRndmGen->Uniform();
211  for (ibatch=0; ibatch<nbatch; ++ibatch) {
212  if ( r <= fCummulativeBatchPDF[ibatch] ) break;
213  }
214  disallowed = ( fDisallowedBatchMask[ibatch] != 0 );
215  }
216  offset += fTimeBetweenBuckets*(double)fNBucketsPerBatch*(double)ibatch;
217 
218  // finally the global offset
219  return offset + fGlobalOffset;
220  }
221 
222  double EvtTimeFNALBeam::TimeOffset(std::vector<double> bi)
223  {
224  CalculateCPDF(bi);
225  return TimeOffset();
226  }
227 
228  void EvtTimeFNALBeam::PrintConfig(bool /* verbose */)
229  {
230 
231  std::ostringstream msg;
232  msg << "EvtTimeFNALBeam config: \n"
233  << " TimeBetweenBuckets: " << fTimeBetweenBuckets << " ns\n"
234  << " BucketTimeSigma: " << fBucketTimeSigma << " ns "
235  << "[FWHM " << fBucketTimeSigma*ksigma2fwhm << "]\n"
236  << " NBucketsPerBatch: " << fNBucketsPerBatch << "\n"
237  << " NFilledBucketsPerBatch: " << fNFilledBucketsPerBatch << "\n"
238  << " Relative Fractions: ";
239  double prev=0;
240  for (size_t i=0; i < fCummulativeBatchPDF.size(); ++i) {
241  double frac = fCummulativeBatchPDF[i] - prev;
242  bool skip = fDisallowedBatchMask[i];
243  msg << " ";
244  if (skip) msg << "{{";
245  msg << frac;
246  if (skip) msg << "}}";
247  prev = fCummulativeBatchPDF[i];
248  }
249  msg << "\n"
250  << " GlobalOffset: " << fGlobalOffset << " ns\n";
251 
252  mf::LogInfo("EvtTime") << msg.str();
253  }
254 
255 
256  void EvtTimeFNALBeam::SetBatchIntensities(std::vector<double> bi)
257  {
258  CalculateCPDF(bi);
259  }
260 
261  void EvtTimeFNALBeam::SetDisallowedBatchMask(std::vector<int> disallow)
262  {
263  size_t ndis = disallow.size();
264  size_t nbi = fCummulativeBatchPDF.size();
265  fDisallowedBatchMask = disallow;
266  // expand it so it's mirrors # of batch intensities
267  // but allow all that haven't been set
268  if ( nbi > ndis ) fDisallowedBatchMask.resize(nbi,0);
269  }
270 
271  void EvtTimeFNALBeam::CalculateCPDF(std::vector<double> bi)
272  {
273  fCummulativeBatchPDF.clear();
274  double sum = 0;
275  size_t nbi = bi.size();
276  for (size_t i=0; i < nbi; ++i) {
277  sum += bi[i];
278  fCummulativeBatchPDF.push_back(sum);
279  }
280  // normalize to unit probability
281  for (size_t i=0; i < nbi; ++i) fCummulativeBatchPDF[i] /= sum;
282  // make sure the mask vector keeps up (but never make it smaller)
283  // allowing all new batches
284  if ( nbi > fDisallowedBatchMask.size() )
285  fDisallowedBatchMask.resize(nbi,0);
286 
287  /*
288  for (size_t j=0; j<nbi; ++j) {
289  std::cout << " CPDF[" << j << "] " << fCummulativeBatchPDF[j]
290  << " " << ((fDisallowedBatchMask[j])?"dis":"") << "allowed"
291  << std::endl;
292  }
293  */
294 
295  }
296 
297 
298 } // namespace evgb
void msg(const char *fmt,...)
Definition: message.cpp:107
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
void SetBatchIntensities(std::vector< double > bi)
double fGlobalOffset
always displaced by this (in ns)
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
configurable FNAL Beam time distribution
EvtTimeFNALBeam(const std::string &config)
const double ksigma2fwhm
double fBucketTimeSigma
how wide is distribution in bucket
interface for event time distribution
Definition: EvtTimeShiftI.h:29
virtual void PrintConfig(bool verbose=true)
provide a means of printing the configuration
static Config * config
Definition: config.cpp:1054
void CalculateCPDF(std::vector< double > batchi)
QTextStream & flush(QTextStream &s)
virtual void Config(const std::string &config)
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
virtual double TimeOffset()
std::vector< int > fDisallowedBatchMask
disallow individual batches
vector< string > Split(string input, string delim)
Definition: StringUtils.cxx:42
double fTimeBetweenBuckets
time between buckets
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
A class for generating concrete EvtTimeShiftI derived classes based on the factory pattern...
list x
Definition: train.py:276
Physics generators for neutrinos, cosmic rays, and others.
Definition: CRYHelper.cxx:33
std::vector< double > fCummulativeBatchPDF
summed prob for batches
void SetDisallowedBatchMask(std::vector< int > disallow)
QTextStream & endl(QTextStream &s)
#define TIMESHIFTREG3(_ns, _name, _fqname)