ProtoDUNEChannelNoiseService_service.cc
Go to the documentation of this file.
1 // ProtoDUNEChannelNoiseService.cxx
2 
5 #include <sstream>
9 #include "nurandom/RandomUtils/NuRandomService.h"
10 #include "art_root_io/TFileService.h"
11 #include "CLHEP/Random/JamesRandom.h"
12 #include "CLHEP/Random/RandFlat.h"
13 #include "CLHEP/Random/RandGauss.h"
14 #include "TH1F.h"
15 #include "TRandom3.h"
16 #include "TF1.h"
17 #include "TMath.h"
18 
19 using std::cout;
20 using std::ostream;
21 using std::endl;
22 using std::string;
23 using std::ostringstream;
24 using rndm::NuRandomService;
25 using CLHEP::HepJamesRandom;
26 
27 //**********************************************************************
28 
31 : fRandomSeed(0), fLogLevel(1),
32  fNoiseHistZ(nullptr), fNoiseHistU(nullptr), fNoiseHistV(nullptr),
33  fNoiseChanHist(nullptr),
34  m_pran(nullptr) {
35  const string myname = "ProtoDUNEChannelNoiseService::ctor: ";
36  fLowCutoffZ = pset.get<double>("LowCutoffZ");
37  fLowCutoffU = pset.get<double>("LowCutoffU");
38  fLowCutoffV = pset.get<double>("LowCutoffV");
39  fWhiteNoiseZ = pset.get<double>("WhiteNoiseZ");
40  fWhiteNoiseU = pset.get<double>("WhiteNoiseU");
41  fWhiteNoiseV = pset.get<double>("WhiteNoiseV");
42  fNoiseArrayPoints = pset.get<unsigned int>("NoiseArrayPoints");
43  fOldNoiseIndex = pset.get<bool>("OldNoiseIndex");
44  fWirelengthZ = pset.get<double>("WireLengthZ");
45  fWirelengthU = pset.get<double>("WireLengthU");
46  fWirelengthV = pset.get<double>("WireLengthV");
47  fENOB = pset.get<double>("EffectiveNBits");
48  bool haveSeed = pset.get_if_present<int>("RandomSeed", fRandomSeed);
49  if ( fRandomSeed == 0 ) haveSeed = false;
50  pset.get_if_present<int>("LogLevel", fLogLevel);
51  fNoiseZ.resize(fNoiseArrayPoints);
52  fNoiseU.resize(fNoiseArrayPoints);
53  fNoiseV.resize(fNoiseArrayPoints);
54  int seed = fRandomSeed;
56  fNoiseHistZ = tfs->make<TH1F>("znoise", ";Z Noise [ADC counts];", 1000, -10., 10.);
57  fNoiseHistU = tfs->make<TH1F>("unoise", ";U Noise [ADC counts];", 1000, -10., 10.);
58  fNoiseHistV = tfs->make<TH1F>("vnoise", ";V Noise [ADC counts];", 1000, -10., 10.);
59  fNoiseChanHist = tfs->make<TH1F>("NoiseChan", ";Noise channel;", fNoiseArrayPoints, 0, fNoiseArrayPoints);
60  // Assign a unique name for the random number engine ProtoDUNEChannelNoiseServiceVIII
61  // III = for each instance of this class.
62  string rname = "ProtoDUNEChannelNoiseService";
63  if ( haveSeed ) {
64  if ( fLogLevel > 0 ) cout << myname << "WARNING: Using hardwired seed." << endl;
65  m_pran = new HepJamesRandom(seed);
66  } else {
67  if ( fLogLevel > 0 ) cout << myname << "Using NuRandomService." << endl;
69  m_pran = new HepJamesRandom;
70  if ( fLogLevel > 0 ) cout << myname << " Initial seed: " << m_pran->getSeed() << endl;
71  seedSvc->registerEngine(NuRandomService::CLHEPengineSeeder(m_pran), rname);
72  }
73  if ( fLogLevel > 0 ) cout << myname << " Registered seed: " << m_pran->getSeed() << endl;
74  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
75  for ( unsigned int isam=0; isam<fNoiseArrayPoints; ++isam ) {
76  generateNoise(clockData, fWirelengthZ, fENOB, fLowCutoffZ, fNoiseZ[isam], fNoiseHistZ);
77  generateNoise(clockData, fWirelengthU, fENOB, fLowCutoffU, fNoiseU[isam], fNoiseHistU);
78  generateNoise(clockData, fWirelengthV, fENOB, fLowCutoffV, fNoiseV[isam], fNoiseHistV);
79  }
80  if ( fLogLevel > 1 ) print() << endl;
81 }
82 
83 //**********************************************************************
84 
88 
89 //**********************************************************************
90 
92  const string myname = "ProtoDUNEChannelNoiseService::dtor: ";
93  if ( fLogLevel > 0 ) {
94  cout << myname << "Deleting random engine with seed " << m_pran->getSeed() << endl;
95  }
96  delete m_pran;
97 }
98 
99 //**********************************************************************
100 
103  Channel chan, AdcSignalVector& sigs) const {
104  CLHEP::RandFlat flat(*m_pran);
105  CLHEP::RandGauss gaus(*m_pran);
106  unsigned int noisechan = 0;
107  if ( fOldNoiseIndex ) {
108  // Keep this strange way of choosing noise channel to be consistent with old results.
109  // The relative weights of the first and last channels are 0.5 and 0.6.
110  noisechan = nearbyint(flat.fire()*(1.*(fNoiseArrayPoints-1)+0.1));
111  } else {
112  noisechan = flat.fire()*fNoiseArrayPoints;
113  if ( noisechan == fNoiseArrayPoints ) --noisechan;
114  }
115  fNoiseChanHist->Fill(noisechan);
117  const geo::View_t view = geo->View(chan);
118  for ( unsigned int itck=0; itck<sigs.size(); ++itck ) {
119  double tnoise = 0.0;
120  double wnoise = 0.0;
121  if ( view==geo::kU ) {
122  tnoise = fNoiseU[noisechan][itck];
123  wnoise = fWhiteNoiseU;
124  } else if ( view==geo::kV ) {
125  tnoise = fNoiseV[noisechan][itck];
126  wnoise = fWhiteNoiseV;
127  } else {
128  tnoise = fNoiseZ[noisechan][itck];
129  wnoise = fWhiteNoiseZ;
130  }
131  if ( wnoise != 0.0 ) tnoise += wnoise*gaus.fire();
132  sigs[itck] += tnoise;
133  }
134  return 0;
135 }
136 
137 //**********************************************************************
138 
139 ostream& ProtoDUNEChannelNoiseService::print(ostream& out, string prefix) const {
140  out << prefix << "ProtoDUNEChannelNoiseService: " << endl;
141  out << prefix << " LowCutoffZ: " << fLowCutoffZ << endl;
142  out << prefix << " LowCutoffU: " << fLowCutoffU << endl;
143  out << prefix << " WireLengthZ: " << fWirelengthZ << endl;
144  out << prefix << " WireLengthU: " << fWirelengthU << endl;
145  out << prefix << " WireLengthV: " << fWirelengthV << endl;
146  out << prefix << " EffectiveNBits: " << fENOB << endl;
147  out << prefix << " LowCutoffV: " << fLowCutoffV << endl;
148  out << prefix << " NoiseArrayPoints: " << fNoiseArrayPoints << endl;
149  out << prefix << " OldNoiseIndex: " << fOldNoiseIndex << endl;
150  out << prefix << " WhiteNoiseZ: " << fWhiteNoiseZ << endl;
151  out << prefix << " WhiteNoiseU: " << fWhiteNoiseU << endl;
152  out << prefix << " WhiteNoiseV: " << fWhiteNoiseV << endl;
153  out << prefix << " RandomSeed: " << fRandomSeed << endl;
154  out << prefix << " LogLevel: " << fLogLevel << endl;
155  out << prefix << " Actual random seed: " << m_pran->getSeed();
156  return out;
157 }
158 
159 //**********************************************************************
160 
163  float wirelength, float ENOB, float aLowCutoff,
164  AdcSignalVector& noise, TH1* aNoiseHist) const {
165  const string myname = "ProtoDUNEChannelNoiseService::generateNoise: ";
166  if ( fLogLevel > 1 ) {
167  cout << myname << "Generating noise." << endl;
168  if ( fLogLevel > 2 ) {
169  cout << myname << " Cutoff: " << aLowCutoff << endl;
170  cout << myname << " Seed: " << m_pran->getSeed() << endl;
171  }
172  }
173  // Fetch sampling rate.
174  float sampleRate = sampling_rate(clockData);
175  // Fetch FFT service and # ticks.
177  unsigned int ntick = pfft->FFTSize();
178  CLHEP::RandFlat flat(*m_pran);
179  // Create noise spectrum in frequency.
180  unsigned nbin = ntick/2 + 1;
181  std::vector<TComplex> noiseFrequency(nbin, 0.);
182  double pval = 0.;
183 // double lofilter = 0.;
184  double phase = 0.;
185  double rnd[3] = {0.};
186 
187  ////////////////////////////// MicroBooNE noise model/////////////////////////////////
188  // vars
189  double params[1] = {0.};
190  double fitpar[9] = {0.};
191  double wldparams[2] = {0.};
192 
193  // calculate FFT magnitude of noise from ENOB
194  double baseline_noise = std::sqrt(ntick*1.0/12)*std::pow(2, 12 - fENOB);
195  // wire length dependence function
196  TF1* _wld_f = new TF1("_wld_f", "[0] + [1]*x", 0.0, 1000);
197  // custom poisson
198  TF1* _poisson = new TF1("_poisson", "[0]**(x) * exp(-[0]) / ROOT::Math::tgamma(x+1.)", 0, 30);
199  // gain function in MHz
200  TF1* _pfn_f1 = new TF1("_pfn_f1", "([0]*1/(x*[8]/2 + 10) + ([1]*exp(-0.5*(((x*[8]/2)-[2])/[3])**2)*exp(-0.5*pow(x*[8]/(2*[4]),[5])))*[6])+[7]", 0.0, (double)ntick);
201 
202  // set data-driven parameters
203  // poisson mean
204  params[0] = 3.30762;
205  //wire length dependence parameters
206  wldparams[0] = 0.395;
207  wldparams[1] = 0.001304;
208  _wld_f->SetParameters(wldparams);
209  double wldValue = _wld_f->Eval(wirelength);
210  fitpar[0] = 9.27790e+02;
211  fitpar[1] = 1.20284e+07;
212  fitpar[2] = 4.93692e+03;
213  fitpar[3] = 1.03438e+03;
214  fitpar[4] = 2.33306e+02;
215  fitpar[5] = 1.36605e+00;
216  fitpar[6] = wldValue;
217  fitpar[7] = baseline_noise;
218  fitpar[8] = ntick;
219  _pfn_f1->SetParameters(fitpar);
220  _poisson->SetParameters(params);
221 
222  // width of frequencyBin in kHz
223  double binWidth = 1.0/(ntick*sampleRate*1.0e-6);
224  for ( unsigned int i=0; i<ntick/2+1; ++i ) {
225  //MicroBooNE noise model
226  double pfnf1val = _pfn_f1->Eval((double)i*binWidth/1000); //convert to MHz
227  // define FFT parameters
228  double randomizer = _poisson->GetRandom()/params[0];
229  pval = pfnf1val * randomizer;
230  // low frequency cutoff
231  //lofilter = 1.0/(1.0+exp(-(i-aLowCutoff/binWidth)/0.5));
232  // randomize 10%
233  flat.fireArray(2, rnd, 0, 1);
234  //pval *= lofilter*(0.9 + 0.2*rnd[0]);
235  // random phase angle
236  phase = rnd[1]*2.*TMath::Pi();
237  TComplex tc(pval*cos(phase),pval*sin(phase));
238  noiseFrequency[i] += tc;
239  }
240  // Obtain time spectrum from frequency spectrum.
241  noise.clear();
242  noise.resize(ntick,0.0);
243  std::vector<double> tmpnoise(noise.size());
244  pfft->DoInvFFT(noiseFrequency, tmpnoise);
245  noiseFrequency.clear();
246  for ( unsigned int itck=0; itck<noise.size(); ++itck ) {
247  noise[itck] = /*sqrt(ntick)**/tmpnoise[itck];
248  }
249  for ( unsigned int itck=0; itck<noise.size(); ++itck ) {
250  aNoiseHist->Fill(noise[itck]);
251  }
252 }
253 
254 //**********************************************************************
255 
257  fNoiseZ.resize(fNoiseArrayPoints);
258  fNoiseU.resize(fNoiseArrayPoints);
259  fNoiseV.resize(fNoiseArrayPoints);
260  for ( unsigned int inch=0; inch<fNoiseArrayPoints; ++inch ) {
264  }
265 }
266 
267 //**********************************************************************
268 
270 
271 //**********************************************************************
int addNoise(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, Channel chan, AdcSignalVector &sigs) const
float fWhiteNoiseU
Level (per freq bin) for white noise for U.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
Planes which measure V.
Definition: geo_types.h:130
float fWhiteNoiseZ
Level (per freq bin) for white noise for Z.
AdcSignalVectorVector fNoiseZ
noise on each channel for each time for Z (collection) plane
constexpr T pow(T x)
Definition: pow.h:72
TH1 * fNoiseHistU
distribution of noise counts for U
AdcSignalVectorVector fNoiseV
noise on each channel for each time for V plane
ProtoDUNEChannelNoiseService(fhicl::ParameterSet const &pset)
std::ostream & print(std::ostream &out=std::cout, std::string prefix="") const
void generateNoise(detinfo::DetectorClocksData const &clockData, float wirelength, float ENOB, float aLowCutoff, AdcSignalVector &noise, TH1 *aNoiseHist) const
bool fOldNoiseIndex
Use old selection of noise array index.
art framework interface to geometry description
void DoInvFFT(std::vector< TComplex > &input, std::vector< T > &output)
Definition: LArFFT.h:120
Planes which measure U.
Definition: geo_types.h:129
int FFTSize() const
Definition: LArFFT.h:69
T gaus(T x, T amplitude, T mean, T sigma)
Tests GausssianFit object with a known input.
AdcSignalVectorVector fNoiseU
noise on each channel for each time for U plane
float fLowCutoffV
low frequency filter cutoff (kHz) for V plane
T get(std::string const &key) const
Definition: ParameterSet.h:271
int fRandomSeed
Seed for random number service. If absent or zero, use SeedSvc.
TH1 * fNoiseHistV
distribution of noise counts for V
float fWhiteNoiseV
Level (per freq bin) for white noise for V.
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
pval
Definition: tracks.py:168
TH1 * fNoiseChanHist
distribution of accessed noise samples
Contains all timing reference information for the detector.
std::optional< T > get_if_present(std::string const &key) const
Definition: ParameterSet.h:224
std::vector< AdcSignal > AdcSignalVector
Definition: AdcTypes.h:22
TH1 * fNoiseHistZ
distribution of noise counts for Z
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
LArSoft geometry interface.
Definition: ChannelGeo.h:16
int fLogLevel
Log message level: 0=quiet, 1=init only, 2+=every event.
unsigned int fNoiseArrayPoints
number of points in randomly generated noise array
float fLowCutoffZ
low frequency filter cutoff (kHz) for Z (collection) plane
QTextStream & endl(QTextStream &s)
float fLowCutoffU
low frequency filter cutoff (kHz) for U plane
#define DEFINE_ART_SERVICE_INTERFACE_IMPL(svc, iface)