All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SBNNoise_tool.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file SBNNoise.cc
3 /// \author F. Varanini
4 ////////////////////////////////////////////////////////////////////////
5 
6 #include <cmath>
7 #include "IGenNoise.h"
8 #include "art/Framework/Core/EDProducer.h"
9 #include "art/Utilities/ToolMacros.h"
10 #include "art/Utilities/make_tool.h"
11 #include "messagefacility/MessageLogger/MessageLogger.h"
12 #include "cetlib_except/exception.h"
15 #include "art_root_io/TFileService.h"
16 
17 // art extensions
18 #include "nurandom/RandomUtils/NuRandomService.h"
19 
20 #include "icarus_signal_processing/WaveformTools.h"
21 
22 // CLHEP libraries
23 #include "CLHEP/Random/RandFlat.h"
24 #include "CLHEP/Random/RandGeneral.h"
25 #include "CLHEP/Random/RandGaussQ.h"
26 
27 #include "TH1F.h"
28 #include "TProfile.h"
29 #include "TFile.h"
30 
31 #include <complex.h>
32 #include <Eigen/Core>
33 #include <unsupported/Eigen/FFT>
34 
35 #include <fstream>
36 
37 namespace icarus_tool
38 {
39 
41 {
42 public:
43  explicit SBNNoise(const fhicl::ParameterSet& pset);
44 
45  ~SBNNoise();
46 
47  void configure(const fhicl::ParameterSet& pset) override;
48 
49  void nextEvent() override;
50 
51  void generateNoise(CLHEP::HepRandomEngine& noise_engine,
52  CLHEP::HepRandomEngine& cornoise_engine,
53  icarusutil::TimeVec& noise,
55  double noise_factor,
56  const geo::PlaneID&,
57  unsigned int board) override;
58 
59 private:
60  void GenerateCorrelatedNoise(CLHEP::HepRandomEngine&, icarusutil::TimeVec&, double, unsigned int);
61  void GenerateUncorrelatedNoise(CLHEP::HepRandomEngine&, icarusutil::TimeVec&, double);
62  void GenNoise(std::function<void (double[])>&, const icarusutil::TimeVec&, icarusutil::TimeVec&, float);
63  void ComputeRMSs();
64  void makeHistograms();
65 
66  // Member variables from the fhicl file
67  size_t fPlane;
69  float fNoiseRand;
75  std::string fHistogramName;
80  std::string fTotalRMSHistoName;
81 
82  using WaveformTools = icarus_signal_processing::WaveformTools<icarusutil::SigProcPrecision>;
83 
85 
86  // We'll recover the bin contents and store in a vector
87  // with the likely false hope this will be faster...
88  icarusutil::TimeVec fCoherentNoiseVec; //< Input full noise frequency distribution
89  icarusutil::TimeVec fIncoherentNoiseVec; //< Input full noise frequency distribution
90 
91  std::vector<double> fCorrAmpDistVec; //< Keep track of motherboard contributions
92 
93  double fIncoherentNoiseRMS; //< RMS of full noise waveform
94  double fCoherentNoiseRMS; //< RMS of full noise waveform
95 
96  // Container for doing the work
98 
99  // Keep track of seed initialization for uncorrelated noise
100  bool fNeedFirstSeed=true;
101 
102  // Histograms
103  TProfile* fInputNoiseHist;
104  TProfile* fMedianNoiseHist;
105  TProfile* fPeakNoiseHist;
106  TProfile* fCorAmpDistHist;
110 
111 float totalRMS;
112 
113 
114  // Keep instance of the eigen FFT
115  Eigen::FFT<double> fEigenFFT;
116 
117 };
118 
119 //----------------------------------------------------------------------
120 // Constructor.
121 SBNNoise::SBNNoise(const fhicl::ParameterSet& pset)
122 {
123  // Recover the configuration of the tool from the input fhicl file and set up
124  configure(pset);
125 ComputeRMSs();
126 
127  // Output some histograms to catalogue what's been done
128  makeHistograms();
129 }
130 
132 {
133 }
134 
135 void SBNNoise::configure(const fhicl::ParameterSet& pset)
136 {
137  // Recover the histogram used for noise generation
138  fPlane = pset.get< size_t >("Plane");
139  fMedianNumBins = pset.get< int >("MedianNumBins");
140  fNoiseRand = pset.get< float >("NoiseRand");
141  fCorrelatedSeed = pset.get< long >("CorrelatedSeed",1000);
142  fUncorrelatedSeed = pset.get< long >("UncorrelatedSeed",5000);
143  fIncoherentNoiseFrac = pset.get< float >("IncoherentNoiseFraction",0.5);
144  fStoreHistograms = pset.get< bool >("StoreHistograms");
145  fInputNoiseHistFileName = pset.get< std::string >("NoiseHistFileName");
146  fCorrelatedHistogramName = pset.get< std::string >("CorrelatedHistogramName");
147  fUncorrelatedHistogramName = pset.get< std::string >("UncorrelatedHistogramName");
148  fCorrelatedRMSHistoName = pset.get< std::string >("CorrelatedRMSHistoName");
149  fUncorrelatedRMSHistoName = pset.get< std::string >("UncorrelatedRMSHistoName");
150  fTotalRMSHistoName = pset.get< std::string >("TotalRMSHistoName");
151  // Initialize the work vector
152  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
153  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clockData);
154  fNoiseFrequencyVec.resize(detProp.NumberTimeSamples(),std::complex<float>(0.,0.));
155 
156  // Set up to input the histogram with the overall noise spectrum
157  std::string fullFileName;
158  std::string corrAmpFileName;
159 
160  cet::search_path searchPath("FW_SEARCH_PATH");
161  searchPath.find_file(fInputNoiseHistFileName, fullFileName);
162 
163  TFile inputFile(fullFileName.c_str(), "READ");
164 
165  if (!inputFile.IsOpen())
166  throw cet::exception("NoiseFromHist::configure") << "Unable to open input file: " << fInputNoiseHistFileName << std::endl;
167 
168  TH1D* corrHistPtr = (TH1D*)inputFile.Get(fCorrelatedHistogramName.c_str());
169  if (!corrHistPtr)
170  throw cet::exception("NoiseFromHist::configure") << "Unable to recover desired histogram: " << fCorrelatedHistogramName << std::endl;
171 
172  TH1D* uncorrHistPtr = (TH1D*)inputFile.Get(fUncorrelatedHistogramName.c_str());
173  if (!uncorrHistPtr)
174  throw cet::exception("NoiseFromHist::configure") << "Unable to recover desired histogram: " << fUncorrelatedHistogramName << std::endl;
175 
176  corrRMSHistPtr = (TH1D*)inputFile.Get(fCorrelatedRMSHistoName.c_str());
177  if (!corrRMSHistPtr)
178  throw cet::exception("NoiseFromHist::configure") << "Unable to recover desired histogram: " << fCorrelatedRMSHistoName << std::endl;
179 
180  uncorrRMSHistPtr = (TH1D*)inputFile.Get(fUncorrelatedRMSHistoName.c_str());
181  if (!uncorrRMSHistPtr)
182  throw cet::exception("NoiseFromHist::configure") << "Unable to recover desired histogram: " << fUncorrelatedRMSHistoName << std::endl;
183 
184  totalRMSHistPtr = (TH1D*)inputFile.Get(fTotalRMSHistoName.c_str());
185  if (!totalRMSHistPtr)
186  throw cet::exception("NoiseFromHist::configure") << "Unable to recover desired histogram: " << fTotalRMSHistoName << std::endl;
187 
188  // Close the input file
189  inputFile.Close();
190 std::cout << " corr nbins " << corrHistPtr->GetNbinsX() << std::endl;
191 std::cout << " uncorr nbins " << uncorrHistPtr->GetNbinsX() << std::endl;
192  fCoherentNoiseVec.resize(corrHistPtr->GetNbinsX(), 0.);
193 
194  // Recover the bin contents into local vectors
195  for(size_t histIdx = 0; histIdx < size_t(corrHistPtr->GetNbinsX()); histIdx++)
196  fCoherentNoiseVec[histIdx] = corrHistPtr->GetBinContent(histIdx+1);
197 fIncoherentNoiseVec.resize(uncorrHistPtr->GetNbinsX(), 0.);
198 
199  // Recover the bin contents into local vectors
200  for(size_t histIdx = 0; histIdx < size_t(uncorrHistPtr->GetNbinsX()); histIdx++)
201  fIncoherentNoiseVec[histIdx] = uncorrHistPtr->GetBinContent(histIdx+1);
202  // Should we store hists?
203 
204 std::cout << " after filling vectors " << std::endl;
205  if (fStoreHistograms)
206  {
207  // Define histograms
208  art::ServiceHandle<art::TFileService> tfs;
209 
210  art::TFileDirectory* histDirectory = tfs.get();
211 
212  // Make a directory for these histograms
213  art::TFileDirectory dir = histDirectory->mkdir(Form("CorNoisePlane%1zu",fPlane));
214 
215  float sampleRate = sampling_rate(clockData);
216  float readOutSize = detProp.ReadOutWindowSize();
217  float maxFreq = 1.e6 / (2. * sampleRate);
218  float minFreq = 1.e6 / (2. * sampleRate * readOutSize);
219  int numSamples = readOutSize / 2;
220 
221  fInputNoiseHist = dir.make<TProfile>("InNoise", ";freq(kHz)", numSamples, minFreq, maxFreq);
222  fMedianNoiseHist = dir.make<TProfile>("MedNoise", ";freq(kHz)", numSamples, minFreq, maxFreq);;
223  fPeakNoiseHist = dir.make<TProfile>("PeakNoise", ";freq(kHz)", numSamples, minFreq, maxFreq);;
224 
225  fCorAmpDistHist = dir.make<TProfile>("CorAmp", ";Motherboard", fCorrAmpDistVec.size(),0.,fCorrAmpDistVec.size());
226  }
227 
228  return;
229 }
230 
232 {
233  // We update the correlated seed because we want to see different noise event-by-event
234  fCorrelatedSeed = (333 * fCorrelatedSeed) % 900000000;
235 
236  return;
237 }
238 
239 void SBNNoise::generateNoise(CLHEP::HepRandomEngine& engine_unc,
240  CLHEP::HepRandomEngine& engine_corr,
241  icarusutil::TimeVec& noise,
243  double noise_factor,
244  const geo::PlaneID& planeID,
245  unsigned int board)
246 {
247 noise_factor=totalRMS;
248 //std::cout << " generating noise " << std::endl;
249  // Define a couple of vectors to hold intermediate work
250  icarusutil::TimeVec noise_unc(noise.size(),0.);
251  icarusutil::TimeVec noise_corr(noise.size(),0.);
252 
253  // Make sure the work vector is size right with the output
254  if (fNoiseFrequencyVec.size() != noise.size()) fNoiseFrequencyVec.resize(noise.size(),std::complex<float>(0.,0.));
255  //std::cout << " generating uncorrelated noise " << std::endl;
256  // If applying incoherent noise call the generator
257  if (fIncoherentNoiseFrac > 0.) GenerateUncorrelatedNoise(engine_unc,noise_unc,noise_factor);
258 
259 // int board=channel/64;
260 //std::cout << " generating correlated noise " << std::endl;
261  // If applying coherent noise call the generator
262  if (fIncoherentNoiseFrac < 1.) GenerateCorrelatedNoise(engine_corr, noise_corr, noise_factor, board);
263  // std::cout << " summing noise " << std::endl;
264  // Take the noise as the simple sum of the two contributions
265  std::transform(noise_unc.begin(),noise_unc.end(),noise_corr.begin(),noise.begin(),std::plus<float>());
266 
267  return;
268 }
269 
270 void SBNNoise::GenerateUncorrelatedNoise(CLHEP::HepRandomEngine& engine, icarusutil::TimeVec &noise, double noise_factor)
271 {
272  // Here we aim to produce a waveform consisting of incoherent noise
273  // Note that this is expected to be the dominate noise contribution
274  // Check for seed initialization
275  if (fNeedFirstSeed)
276  {
277  engine.setSeed(fUncorrelatedSeed,0);
278  fNeedFirstSeed = false;
279  }
280 
281  // Get the generator
282  CLHEP::RandFlat noiseGen(engine,0,1);
283 
284  std::function<void (double[])> randGenFunc = [&noiseGen](double randArray[]){noiseGen.fireArray(2,randArray);};
285 
286  float scaleFactor = fIncoherentNoiseFrac * noise_factor / fIncoherentNoiseRMS;
287 
288  GenNoise(randGenFunc, fIncoherentNoiseVec, noise, scaleFactor);
289 
290  return;
291 }
292 
293 void SBNNoise::GenerateCorrelatedNoise(CLHEP::HepRandomEngine& engine, icarusutil::TimeVec &noise, double noise_factor, unsigned int board)
294 {
295 
296  // Set the engine seed to the board being considered
297  engine.setSeed(fCorrelatedSeed+board,0);
298 
299  CLHEP::RandFlat noiseGen(engine,0,1);
300 
301  std::function<void (double[])> randGenFunc = [&noiseGen](double randArray[]){noiseGen.fireArray(2,randArray);};
302 
303  float fraction = std::sqrt(1. - fIncoherentNoiseFrac * fIncoherentNoiseFrac);
304  float scaleFactor = fraction * noise_factor / fCoherentNoiseRMS;
305 
306  GenNoise(randGenFunc, fCoherentNoiseVec, noise, scaleFactor);
307 
308 
309  return;
310 }
311 
312 void SBNNoise::GenNoise(std::function<void (double[])>& gen,const icarusutil::TimeVec& freqDist, icarusutil::TimeVec& noise, float scaleFactor)
313 {
314  double rnd_corr[2] = {0.,0.};
315 
316  // Build out the frequency vector
317  for(size_t i=0; i< noise.size()/2; ++i)
318  {
319  // exponential noise spectrum
320  gen(rnd_corr);
321 
322  float pval = freqDist[i] * ((1-fNoiseRand) + 2 * fNoiseRand*rnd_corr[0]) * scaleFactor;
323  float phase = rnd_corr[1] * 2. * M_PI;
324 
325  std::complex<float> tc(pval*cos(phase),pval*sin(phase));
326 
327  fNoiseFrequencyVec[i] = tc;
328  }
329 
330  // inverse FFT MCSignal
331  fEigenFFT.inv(noise, fNoiseFrequencyVec);
332 
333  return;
334 }
335 
337 {
338 
339  return;
340 }
341 
343 {
344  // Let's get the rms we expect from the incoherent noise contribution to the waveform
345  // A couple of ways to do this, let's basically invert the frequency spectrum to
346  // produce a waveform and then get the rms from that
347  std::function<void (double[])> randGenFunc = [](double randArray[]){randArray[0]=0.5; randArray[1]=0.5;};
348 
349  icarusutil::TimeVec waveNoise(fIncoherentNoiseVec.size());
350  float scaleFactor = 1.;
351 
352  GenNoise(randGenFunc, fIncoherentNoiseVec, waveNoise, scaleFactor);
353 
354  // Now get the details...
355  double nSig(3.);
356  double mean,rmsTrunc;
357  int nTrunc;
358  int range;
359 
360  // Use the waveform tool to recover the full rms
361  fWaveformTool.getTruncatedMeanRMS(waveNoise, nSig, mean, fIncoherentNoiseRMS, rmsTrunc, nTrunc, range);
362 
363  // Do the same for the coherent term
364  GenNoise(randGenFunc, fCoherentNoiseVec, waveNoise, scaleFactor);
365 
366  fWaveformTool.getTruncatedMeanRMS(waveNoise, nSig, mean, fCoherentNoiseRMS, rmsTrunc, nTrunc, range);
367 
368  if (fStoreHistograms)
369  {
370  for(size_t idx = 0; idx < fCorrAmpDistVec.size(); idx++)
371  fCorAmpDistHist->Fill(idx, fCorrAmpDistVec[idx], 1.);
372  }
373 
374  totalRMS=totalRMSHistPtr->GetMean();
375 double rmsUnc=uncorrRMSHistPtr->GetMean();
376 //double rmsCorr=corrRMSHistPtr->GetMean();
378  return;
379 }
380 
381 DEFINE_ART_CLASS_TOOL(SBNNoise)
382 }
std::string fCorrelatedRMSHistoName
WaveformTools fWaveformTool
icarusutil::TimeVec fIncoherentNoiseVec
Utilities related to art service access.
static constexpr Sample_t transform(Sample_t sample)
void GenerateCorrelatedNoise(CLHEP::HepRandomEngine &, icarusutil::TimeVec &, double, unsigned int)
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
void GenNoise(std::function< void(double[])> &, const icarusutil::TimeVec &, icarusutil::TimeVec &, float)
std::vector< ComplexVal > FrequencyVec
void configure(const fhicl::ParameterSet &pset) override
void nextEvent() override
std::string fUncorrelatedRMSHistoName
std::vector< SigProcPrecision > TimeVec
std::vector< double > fCorrAmpDistVec
icarus_signal_processing::WaveformTools< icarusutil::SigProcPrecision > WaveformTools
std::string fUncorrelatedHistogramName
SBNNoise(const fhicl::ParameterSet &pset)
std::string fCorrelatedHistogramName
icarusutil::TimeVec fCoherentNoiseVec
tuple dir
Definition: dropbox.py:28
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
void generateNoise(CLHEP::HepRandomEngine &noise_engine, CLHEP::HepRandomEngine &cornoise_engine, icarusutil::TimeVec &noise, detinfo::DetectorPropertiesData const &, double noise_factor, const geo::PlaneID &, unsigned int board) override
std::string fTotalRMSHistoName
This is the interface class for a tool to handle a GenNoise for the overall response.
std::string fInputNoiseHistFileName
art::ServiceHandle< art::TFileService > tfs
void GenerateUncorrelatedNoise(CLHEP::HepRandomEngine &, icarusutil::TimeVec &, double)
std::string fHistogramName
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
icarusutil::FrequencyVec fNoiseFrequencyVec
BEGIN_PROLOG could also be cout
auto const detProp
Eigen::FFT< double > fEigenFFT