DPhaseRealisticNoiseService_service.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Implement a service including realistic noise using 3x1x1 data
4 //
5 // A realistic nose model can be read from .root file, containing the FFT transform
6 // for each channel. In the fft array is stored average frequency
7 // on the chosen plane.
8 //
9 //
10 // NB: Hardcoded rotated geometry!
11 //
12 ////////////////////////////////////////////////////////////////////////////////
13 
16 #include <sstream>
17 #include <string>
21 #include "nurandom/RandomUtils/NuRandomService.h"
22 #include "art_root_io/TFileService.h"
23 #include "CLHEP/Random/JamesRandom.h"
24 #include "CLHEP/Random/RandFlat.h"
25 #include "CLHEP/Random/RandGauss.h"
26 #include "TProfile.h"
27 #include "TFile.h"
28 #include "TKey.h"
29 #include "TF1.h"
30 #include "TH2F.h"
31 #include "TProfile.h"
32 #include "TRandom3.h"
33 
34 using std::cout;
35 using std::ostream;
36 using std::endl;
37 using std::string;
38 using std::ostringstream;
39 using rndm::NuRandomService;
40 using CLHEP::HepJamesRandom;
41 
42 //**********************************************************************
43 
45 : fRandomSeed(0), fLogLevel(1),
46  fNoiseHistX(nullptr), fNoiseHistY(nullptr),
47  fNoiseChanHist(nullptr),
48  m_pran(nullptr) {
49  const string myname = "DPhaseRealisticNoiseService::ctor: ";
50  fNoiseModel = pset.get<string>("NoiseModel");
51  fRandomizeX = pset.get<double>("RandomizeX");
52  fRandomizeY = pset.get<double>("RandomizeY");
53  fSmooth = pset.get<double>("Smooth");
54  fSetFirst0 = pset.get<bool>("SetFirst0");
55  fSetBaseline = pset.get<bool>("SetBaseline");
56  fNoiseArrayPoints = pset.get<unsigned int>("NoiseArrayPoints");
57  fOldNoiseIndex = pset.get<bool>("OldNoiseIndex");
58  bool haveSeed = pset.get_if_present<int>("RandomSeed", fRandomSeed);
59  if ( fRandomSeed == 0 ) haveSeed = false;
60  pset.get_if_present<int>("LogLevel", fLogLevel);
61  fNoiseX.resize(fNoiseArrayPoints);
62  fNoiseY.resize(fNoiseArrayPoints);
63  int seed = fRandomSeed;
65  fNoiseHistX = tfs->make<TH1F>("xnoise", ";X Noise [ADC counts];", 1000, -0.1, 0.1);
66  fNoiseHistY = tfs->make<TH1F>("ynoise", ";Y Noise [ADC counts];", 1000, -0.1, 0.1);
67  fNoiseChanHist = tfs->make<TH1F>("NoiseChan", ";Noise channel;", fNoiseArrayPoints, 0, fNoiseArrayPoints);
68  // Assign a unique name for the random number engine ExponentialChannelNoiseServiceVIII
69  // III = for each instance of this class.
70  string rname = "DPhaseRealisticNoiseService";
71  if ( haveSeed ) {
72  if ( fLogLevel > 0 ) cout << myname << "WARNING: Using hardwired seed." << endl;
73  m_pran = new HepJamesRandom(seed);
74  } else {
75  if ( fLogLevel > 0 ) cout << myname << "Using NuRandomService." << endl;
77  m_pran = new HepJamesRandom;
78  if ( fLogLevel > 0 ) cout << myname << " Initial seed: " << m_pran->getSeed() << endl;
79  seedSvc->registerEngine(NuRandomService::CLHEPengineSeeder(m_pran), rname);
80  }
81  if ( fLogLevel > 0 ) cout << myname << " Registered seed: " << m_pran->getSeed() << endl;
82 
84 
85  //pregenerated noise model waveforms based on the realistic noise frequency pattern
86  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob();
87  for ( unsigned int isam=0; isam<fNoiseArrayPoints; ++isam ) {
88  generateNoise(detProp, fNoiseModelFrequenciesX, fNoiseX[isam], fNoiseHistX, fRandomizeX);
89  generateNoise(detProp, fNoiseModelFrequenciesY, fNoiseY[isam], fNoiseHistY, fRandomizeY);
90  }
91 
92  if ( fLogLevel > 1 ) print() << endl;
93 } //m_pran(nullptr)
94 
95 //**********************************************************************
96 
100 
101 //**********************************************************************
102 
104  const string myname = "DPhaseRealisticNoiseService::dtor: ";
105  if ( fLogLevel > 0 ) {
106  cout << myname << "Deleting random engine with seed " << m_pran->getSeed() << endl;
107  }
108  delete m_pran;
109 }
110 
111 //**********************************************************************
112 
114  detinfo::DetectorPropertiesData const& detProp,
115  Channel chan, AdcSignalVector& sigs) const{
116 
117  CLHEP::RandFlat flat(*m_pran);
118 
119  //define the baseline fluctuations
120  //done here because chan is needed to tune the phase
121  unsigned int ntick = detProp.NumberTimeSamples();
122  double dt = 1./sampling_rate(clockData);
123  unsigned int model_tick = GetModelSize();
124  std::map<Channel, double> fPhaseChannelMap;
125  Chan2Phase(fPhaseChannelMap);
126 
127  //define a short osclillating baseline function
128  double params[3] = {0.};
129  TF1 * _sin = new TF1("_sin", "[0]*TMath::Sin( [1]*x + [2] )", 0.,
130  (double)ntick*dt);
131  params[0] = 1.; //in adc
132  params[1] = (2*TMath::Pi())/(2*model_tick*dt);
133  params[2] = fPhaseChannelMap[chan];
134 
135  _sin->SetParameters(params);
136 
137  //add one of the pregenerated random noise vectors to the signal vector
138  unsigned int noisechan = 0;
139  if ( fOldNoiseIndex ) {
140  // Keep this strange way of choosing noise channel to be consistent with old results.
141  // The relative weights of the first and last channels are 0.5 and 0.6.
142  noisechan = nearbyint(flat.fire()*(1.*(fNoiseArrayPoints-1)+0.1));
143  } else {
144  noisechan = flat.fire()*fNoiseArrayPoints;
145  if ( noisechan == fNoiseArrayPoints ) --noisechan;
146  }
147  fNoiseChanHist->Fill(noisechan);
149  const geo::View_t view = geo->View(chan);
150 
151  //sigs.resize( detProp.NumberTimeSamples() );
152 
153  for ( unsigned int itck=0; itck<ntick; ++itck ) {
154  double tnoise = 0.0;
155  if ( view==geo::kY ) {
156  tnoise = fNoiseY[noisechan][itck];
157  } else if ( view==geo::kZ ) {
158  tnoise = fNoiseX[noisechan][itck];
159  } else {
160  tnoise = fNoiseX[noisechan][itck];
161  }
162 
163  if(fSetBaseline){
164  sigs[itck] += _sin->Eval((double)itck*dt);
165  }
166 
167  sigs[itck] += tnoise;
168  }
169 
170  return 0;
171 }
172 
173 //**********************************************************************
174 
175 ostream& DPhaseRealisticNoiseService::print(ostream& out, string prefix) const {
176 
177  out << prefix << "DPhaseRealisticNoiseService: " << endl;
178  out << prefix << " Noise model source file: " << fNoiseModel << endl;
179  out << prefix << " RandomizationX: " << fRandomizeX << endl;
180  out << prefix << " RandomizationY: " << fRandomizeY << endl;
181  out << prefix << " Smooth " << fSmooth << endl;
182  out << prefix << " fSetFirst0 " << fSetFirst0 << endl;
183  out << prefix << " fSetBaseline " << fSetBaseline << endl;
184  out << prefix << " RandomSeed: " << fRandomSeed << endl;
185  out << prefix << " LogLevel: " << fLogLevel << endl;
186  out << prefix << " Actual random seed: " << m_pran->getSeed();
187 
188  return out;
189 }
190 
191 //**********************************************************************
192 
194 std::vector<double> & frequencyArrayX, std::vector<double> & frequencyArrayY) const {
195 
196  //import noise model
198 
199  TFile *fin = TFile::Open(noiseModel.c_str(), "READ");
200  if(!fin->IsOpen()){
201  cout << "ERROR!: Can't open file: " << noiseModel << endl;
202  return;
203  }
204  else{
205  cout << "File: " << noiseModel << " successfully opened!" << endl;
206  }
207  //get the histogram
208  TIter next( fin->GetListOfKeys() );
209  TKey *key;
210  TProfile *inputHist = new TProfile(); //default initialisazion
211 
212  while( (key = (TKey*)next()) ){
213 
214  string name( key->GetName() );
215  std::string keyName( key->GetClassName() ); //parse char to string
216  if( keyName == "TProfile"){
217  inputHist = (TProfile*)fin->Get(key->GetName());
218  }
219  else{
220  std::cout << "ERROR! Object: " << keyName << " in file " << noiseModel
221  << "has not the right format!" << std::endl;
222  fin->Close();
223  return;
224  }
225 
226  //loop over frequencies: eliminate the last bin of the fft
227  //if geometry is 3x1x1dp, then use both models, otherwise just take 0
228 
229  frequencyArrayX.resize( inputHist->GetNbinsX() );
230  frequencyArrayY.resize( inputHist->GetNbinsX() );
231 
232  for(size_t f=0; f<(size_t)inputHist->GetNbinsX() ; f++){
233  if (name.find("_0")!=string::npos){
234 
235  //NB: use just the 3m strips view for Far Detector sim
236  frequencyArrayY.at(f) = inputHist->GetBinContent(f);
237  frequencyArrayX.at(f) = inputHist->GetBinContent(f);
238  }
239  else if(name.find("_1")!=string::npos){
240  //frequencyArrayX.at(f) = inputHist->GetBinContent(f);
241  continue;
242  }
243  else{
244  cout << "not valid view " << endl;
245  continue;
246  }
247  } //end f loop
248  } //end event loop
249 
250  //one may want to set the first bin of the model to 0
251  if(fSetFirst0){
252  frequencyArrayX[0]=0;
253  frequencyArrayY[0]=0;
254  }
255 
256  fin->Close();
257  return;
258 }
259 
260 //**********************************************************************
261 
263  return fModelsize;
264 }
265 
267  fModelsize = size;
268 }
269 
270 //**********************************************************************
271 
272 void DPhaseRealisticNoiseService::Chan2Phase(std::map<Channel, double> &PhaseChannelMap) const{
273  //create an association between channel and phase.
274 
275  CLHEP::RandFlat flat(*m_pran);
277 
278  double phase = flat.fire();
279  double dph = (TMath::Pi()*0.5)/62; //phase small increment. (May be improved)
280 
281  for(Channel chan=0; chan< geo->Nchannels() ; chan++){
282 
283  if(chan % 64 == 0){
284  phase = flat.fire();
285  }else if(chan % 32){
286  dph = -dph;
287  phase += dph;
288  }else{
289  phase += dph;
290  }
291  PhaseChannelMap[chan] = phase*2*TMath::Pi();
292  }//end for
293  return;
294 }
295 
296 //**********************************************************************
297 
299  int window_length) const{
300  //get the shift requeired for mirroring the waveform
301 
302  int size = time_vector.size();
303  double sum=0.;
304  for(int i = size - window_length; i< size; i++){ sum+=time_vector[i]; }
305  double shift = sum/window_length;
306 
307  return shift *=2;
308 }
309 
310 //**********************************************************************
311 
313  int TimeSamples) const{
314 
315  //extend by mirroring the waveform length from the model to match
316  // the one of the detector
317 
318  int ArraySize = noise.size();
319  int n_window = fSmooth; //tick window to smooth the mirroring
320  double shift =0.;
321 
322  //initialize first shift value from the mean in the time window
323  shift = GetShift(noise, n_window);
324 
325  noise.resize(2*ArraySize);
326 
327  //do first mirror
328  for(int s = ArraySize; s<2*ArraySize; s++){
329  if(s>TimeSamples){ break; }
330  noise[s] = -noise[2*ArraySize -s - 1 ] + shift;
331  }
332 
333  //if after the first pass the detector time window is not reached, do more...
334  if(TimeSamples > 2*ArraySize){
335 
336  int n = ceil(TimeSamples/ArraySize);
337  int n_pass = ceil(log(n)/log(2))+1;
338 
339  for(int pass=1; pass<n_pass; pass++){
340 
341  if(noise.size() > (size_t)TimeSamples){ break; } //no need for an extra pass
342 
343  shift = GetShift(noise, n_window);
344 
345  noise.resize( pow(2,(pass+1))*ArraySize );
346 
347  for(int s = pow(2,pass)*ArraySize; s<pow(2,(pass+1))*ArraySize; s++){
348  if(s > TimeSamples){ break; }
349  noise[s] = -noise[pow(2,(pass+1))*ArraySize -s - 1 ] + shift;
350  }
351  }//end for pass
352  }//end if
353 
354  //Correct the waveform inclination
355  double y, sx = 0, sy = 0, sxy = 0, sx2 = 0, sy2 = 0;
356 
357  for (size_t s = 0; s < (size_t)TimeSamples; ++s)
358  {
359  y = noise[s]; sx += s; sy += y; sxy += s*y; sx2 += s*s; sy2 += y*y;
360  }
361  double ssx = sx2 - ((sx * sx) / TimeSamples);
362  double c = sxy - ((sx * sy) / TimeSamples);
363  double mx = sx / TimeSamples;
364  double my = sy / TimeSamples;
365  double b = my - ((c / ssx) * mx);
366  double a = c / ssx;
367 
368  for (size_t s = 0; s < (size_t)TimeSamples; ++s) { noise[s] -= (a*s + b); }
369 
370  return;
371 }//end mirrorWaveform
372 
373 //**********************************************************************
374 
376  std::vector<double> frequencyVector,
377  AdcSignalVector& noise, TH1* aNoiseHist, double customRandom){
378 
379  const string myname = "DPRealisticNoiseService::generateNoise: ";
380  if ( fLogLevel > 1 ) {
381  cout << myname << "Generating noise." << endl;
382  }
383 
384  CLHEP::RandFlat flat(*m_pran);
385  CLHEP::RandGauss gaus(*m_pran);
386 
387  // rayleigh
388  //TF1* _rayleigh = new TF1("_rayleigh", "[0]*( x/([1]*[1]) )*TMath::Exp(-( (x*x)/(2*[1]*[1]) ))", 0, 200);
389  //_rayleigh->SetParameter(0, 7.80e+5);
390 
391  unsigned int inputFreqSize = frequencyVector.size();
392  unsigned int pointFFT = 2*(inputFreqSize-1);
393 
395  pfft->ReinitializeFFT( pointFFT ," ", pfft->FFTFitBins() );
396 
397  unsigned int model_tick = pfft->FFTSize(); //ticks of the time model
398  unsigned nbin = model_tick/2 + 1;
399  SetModelSize( model_tick );
400 
401  std::vector<TComplex> noiseFrequency(nbin, 0.);
402  double pval = 0.;
403  double phase = 0.;
404 
405  for ( unsigned int i=0; i<model_tick/2+1; ++i ) {
406 
407  pval = frequencyVector[i];
408 
409  //Randomize amplitude (Gaussian)
410  pval += customRandom*gaus.fire();
411 
412  //Randomize phase (Constant)
413  phase = flat.fire()*2.*TMath::Pi();
414  TComplex tc(pval*cos(phase),pval*sin(phase));
415  noiseFrequency[i] += tc;
416  }
417 
418  //Perform the InvFFT of the randomized noise frequency model
419  noise.clear();
420  noise.resize(model_tick, 0.0);
421  std::vector<double> tmpnoise(noise.size());
422  pfft->DoInvFFT(noiseFrequency, tmpnoise);
423  noiseFrequency.clear();
424 
425  //model is not normalized
426  for ( unsigned int itck=0; itck<noise.size(); ++itck ) {
427  noise[itck] = tmpnoise[itck];
428  }
429 
430  //here the signal is mirrored until it match the number of time samples for
431  //a given detector geometry
432  int ntick = detProp.NumberTimeSamples();
433 
434  if(noise.size()<(size_t)ntick){
435  mirrorWaveform(noise, ntick);
436  }
437 
438  for ( unsigned int itck=0; itck<noise.size(); ++itck ) {
439  aNoiseHist->Fill(noise[itck]);
440  }
441 
442  //restore fft with the same number of points as it was before
443  pfft->ReinitializeFFT( ntick ," ", pfft->FFTFitBins() );
444 
445  return;
446 }//end generateNoise
447 
448 //**********************************************************************
449 
451  fNoiseX.resize(fNoiseArrayPoints);
452  fNoiseY.resize(fNoiseArrayPoints);
453  for ( unsigned int inch=0; inch<fNoiseArrayPoints; ++inch ) {
456  }
457 }
458 
459 //**********************************************************************
460 
462 
463 //**********************************************************************
static QCString name
Definition: declinfo.cpp:673
TH1 * fNoiseHistY
distribution of noise counts for Y
AdcSignalVectorVector fNoiseX
noise on each channel for each time for X plane
std::ostream & print(std::ostream &out=std::cout, std::string prefix="") const
TH1 * fNoiseHistX
distribution of noise counts for X
bool fSetBaseline
< Sum baseline model to the data
void generateNoise(detinfo::DetectorPropertiesData const &detProp, std::vector< double > frequencyVector, AdcSignalVector &noise, TH1 *aNoiseHist, double customRandom)
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
constexpr T pow(T x)
Definition: pow.h:72
void mirrorWaveform(AdcSignalVector &noise, int TimeSamples) const
#define _sin(x)
unsigned int fNoiseArrayPoints
number of points in randomly generated noise array
Planes which measure Z direction.
Definition: geo_types.h:132
double fRandomizeY
< randomization of the average frequency spectrum (on kY)
double fRandomizeX
randomization of the average frequency spectrum (on kX or kZ)
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
int fRandomSeed
Seed for random number service. If absent or zero, use SeedSvc.
AdcSignalVectorVector fNoiseY
noise on each channel for each time for Y plane
int FFTFitBins() const
Definition: LArFFT.h:71
Planes which measure Y direction.
Definition: geo_types.h:133
art framework interface to geometry description
void Chan2Phase(std::map< Channel, double > &PhaseChannelMap) const
int fLogLevel
Log message level: 0=quiet, 1=init only, 2+=every event.
void DoInvFFT(std::vector< TComplex > &input, std::vector< T > &output)
Definition: LArFFT.h:120
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
int FFTSize() const
Definition: LArFFT.h:69
def key(type, name=None)
Definition: graph.py:13
T gaus(T x, T amplitude, T mean, T sigma)
Tests GausssianFit object with a known input.
double GetShift(AdcSignalVector time_vector, int window_length) const
HLTPathStatus const pass
std::void_t< T > n
const double a
TH1 * fNoiseChanHist
distribution of accessed noise samples
T get(std::string const &key) const
Definition: ParameterSet.h:271
std::string fNoiseModel
noise model root file
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
std::vector< double > fNoiseModelFrequenciesX
Array storing the frequencies imported from the model in kHz for plane kX (kZ)
pval
Definition: tracks.py:168
bool fOldNoiseIndex
Use old selection of noise array index.
Contains all timing reference information for the detector.
std::optional< T > get_if_present(std::string const &key) const
Definition: ParameterSet.h:224
void importNoiseModel(std::string noiseModel, std::vector< double > &frequencyArrayX, std::vector< double > &frequencyArrayY) const
std::vector< double > fNoiseModelFrequenciesY
Array storing the frequencies imported from the model in kHz for plane kY (kZ)
static bool * b
Definition: config.cpp:1043
std::vector< AdcSignal > AdcSignalVector
Definition: AdcTypes.h:22
int addNoise(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, Channel chan, AdcSignalVector &sigs) const
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
DPhaseRealisticNoiseService(fhicl::ParameterSet const &pset)
LArSoft geometry interface.
Definition: ChannelGeo.h:16
void ReinitializeFFT(int, std::string, int)
static QCString * s
Definition: config.cpp:1042
QTextStream & endl(QTextStream &s)
bool fSetFirst0
< set the first bin of the frequency array to 0
#define DEFINE_ART_SERVICE_INTERFACE_IMPL(svc, iface)