DPhaseCoherentNoiseService_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 channel vs.
6 // frequency map for the 3x1x1 detector.
7 //
8 // Frequency are injected as sinusoidal functions, with realistic amplitudes and
9 // phases randomized to respect the correlation patterns inside the detector
10 //
11 // NB: kZ = view 1; kY = view 0
12 //
13 // mailto:andrea.scarpelli@cern.ch
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
19 #include <sstream>
20 #include <string>
21 //#include "art/canvas/Utilities/Exception.h"
25 #include "nurandom/RandomUtils/NuRandomService.h"
26 #include "art_root_io/TFileService.h"
27 #include "CLHEP/Random/JamesRandom.h"
28 #include "CLHEP/Random/RandFlat.h"
29 #include "CLHEP/Random/RandGauss.h"
30 #include "TProfile.h"
31 #include "TFile.h"
32 #include "TKey.h"
33 #include "TF1.h"
34 #include "TH2F.h"
35 #include "TProfile2D.h"
36 #include "TRandom3.h"
37 
38 using std::cout;
39 using std::ostream;
40 using std::endl;
41 using std::string;
42 using std::vector;
43 using std::map;
44 using std::ostringstream;
45 using rndm::NuRandomService;
46 using CLHEP::HepJamesRandom;
47 
48 
49 //**********************************************************************
50 
52 : fRandomSeed(0), fLogLevel(1),
53  m_pran(nullptr)
54 {
55  const string myname = "DPhaseCoherentNoiseService::ctor: ";
56  fNoiseModel = pset.get<string>("NoiseModel");
57  fAmplitudeCut = pset.get<double>("AmplitudeCut");
58  fNormalization = pset.get<int>("Normalization");
59  fRandomize = pset.get< vector< float > >("Randomize");
60  fPhaseShift = pset.get< vector< float > >("PhaseShift");
61  fChannelGroup = pset.get< vector<int> >("ChannelGroup");
62  fInchoerentNoise = pset.get< vector< float > >("InchoerentNoise");
63  fNumberOfPhases = pset.get<int>("NumberOfPhases");
64  fLogLevel = pset.get<int>("LogLevel");
65  bool haveSeed = pset.get_if_present<int>("RandomSeed", fRandomSeed);
66  if ( fRandomSeed == 0 ) haveSeed = false;
67  pset.get_if_present<int>("LogLevel", fLogLevel);
68 
69  int seed = fRandomSeed;
71 
72  // Assign a unique name for the random number engine ExponentialChannelNoiseServiceVIII
73  // III = for each instance of this class.
74  string rname = "DPhaseCoherentNoiseService";
75  if ( haveSeed )
76  {
77  if ( fLogLevel > 0 ) cout << myname << "WARNING: Using hardwired seed." << endl;
78  m_pran = new HepJamesRandom(seed);
79  }
80  else
81  {
82  if ( fLogLevel > 0 ) cout << myname << "Using NuRandomService." << endl;
84  m_pran = new HepJamesRandom;
85  if ( fLogLevel > 0 ) cout << myname << " Initial seed: " << m_pran->getSeed() << endl;
86  seedSvc->registerEngine(NuRandomService::CLHEPengineSeeder(m_pran), rname);
87  }
88  if ( fLogLevel > 0 ) cout << myname << " Registered seed: " << m_pran->getSeed() << endl;
89 
90  importNoiseModel(fNoiseModel, fChFrequencyMap, fChAmplitudeMap, fAmplitudeCut, fNormalization);
91 
92  //sanity checks for the imported maps and find max frequency array length
93  int max =0;
94 
96  for(Channel chan=0; chan< geo->Nchannels() ; chan++){
97 
98  vector<float> amplitudeArray;
99  vector<float> frequencyArray;
100 
101  getFrequencyArray( chan, frequencyArray);
102  getAmplitudeArray( chan, amplitudeArray);
103 
104  if( frequencyArray.size() != amplitudeArray.size() ){
105  if ( fLogLevel > 0 ){ cout << myname << "frequency array and amplitude array have not the same size in chan: " << chan << endl; }
106  //throw art::Exception("DPhaseCoherentNoiseService") << "frequency array and amplitude array have not the same size";
107  }
108 
109  if( max < (int)frequencyArray.size() ){ max = frequencyArray.size(); }
110  }
111 
113 
114  //pregenerated random phases arrays
115  fPhaseMap.resize(fNumberOfPhases);
116 
117  for ( int isam=0; isam<fNumberOfPhases; ++isam ) {
118  makePhaseMap(fPhaseMap[isam], fMaxFrequencySize, fPhaseShift[0], fPhaseShift[1]);
119  }
120 
121  if ( fLogLevel > 1 ) print() << endl;
122 } //m_pran(nullptr)
123 
124 //**********************************************************************
125 
128 : DPhaseCoherentNoiseService(pset) { }
129 
130 //**********************************************************************
131 
133  const string myname = "DPhaseCoherentNoiseService::dtor: ";
134  if ( fLogLevel > 0 ) {
135  cout << myname << "Deleting random engine with seed " << m_pran->getSeed() << endl;
136  }
137  delete m_pran;
138 }
139 
140 //**********************************************************************
141 
143  detinfo::DetectorPropertiesData const& detProp,
144  Channel chan, AdcSignalVector& sigs) const {
145 
146  const string myname = "DPhaseCoherentNoiseService::addNoise: ";
147  if ( fLogLevel > 0 ) {
148  cout << myname << " Processing channel: " << chan << endl;
149  }
150 
151  unsigned int ntick = detProp.NumberTimeSamples();
152 
154  const geo::View_t view = geo->View(chan);
155 
156  //get the map associated to channel and phase array associated to channel
157  int num = getNumber( chan );
158  Map phaseMap = fPhaseMap.at(num);
159  vector<float> phaseArray = phaseMap.at(chan);
160 
161  if ( fLogLevel > 0 ) {
162  cout << myname << " Map number: " << num << endl;
163  }
164 
165  //get amplitude and frequecny
166  vector<float> amplitudeArray;
167  vector<float> frequencyArray;
168 
169  getFrequencyArray( chan, frequencyArray);
170  getAmplitudeArray( chan, amplitudeArray);
171 
172  //Test if the channel was in the fft model
173  if( frequencyArray.size() == 0 && amplitudeArray.size() ==0 ){
174  vector<float> nullArray;
175  nullArray.resize( ntick );
176  sigs = nullArray;
177 
178  if ( fLogLevel > 0 ) {
179  cout << myname << " No freq and amplitude arrays for " << chan << endl;
180  }
181 
182  return 0;
183  }
184 
185 
186  //resize the signal vector
187  sigs.resize( ntick );
188 
189  //choose the correct plane for the amplitude randomization
190  float randAmp=0;
191 
192  if ( view==geo::kY )
193  {
194  randAmp = fRandomize[0];
195  }
196  else if ( view==geo::kZ ) {
197  randAmp = fRandomize[1];
198  }
199  else
200  {
201  if ( fLogLevel > 0 ) {
202  cout << myname << "Invalid plane" << endl;
203  }
204  }
205 
206  //build the noise signal
207  getNoiseArray(clockData, sigs, amplitudeArray, frequencyArray, phaseArray, randAmp);
208 
209  //add incoherent noise if set
210  if( fInchoerentNoise.size() > 0 ){
211 
212  CLHEP::RandGauss gaus(*m_pran);
213 
214  if ( view==geo::kY )
215  {
216  for ( unsigned int itck=0; itck<ntick; ++itck )
217  sigs.at(itck) += gaus.fire( fInchoerentNoise.at(0), fInchoerentNoise.at(1) );
218  }
219  else if ( view==geo::kZ )
220  {
221  for ( unsigned int itck=0; itck<ntick; ++itck )
222  sigs.at(itck) += gaus.fire( fInchoerentNoise.at(2), fInchoerentNoise.at(3) );
223  }
224  else {
225  if ( fLogLevel > 0 ) {
226  cout << myname << "Invalid plane" << endl;
227  }
228  }
229  }
230 
231  if ( fLogLevel > 1 ) {
232  cout << myname << " All done " << endl;
233  }
234 
235  return 0;
236 
237 }
238 
239 //**********************************************************************
240 
241 ostream& DPhaseCoherentNoiseService::print(ostream& out, string prefix) const {
242 
243  out << prefix << "DPhaseCoherentNoiseService: " << endl;
244  out << prefix << " Noise model source file: " << fNoiseModel << endl;
245  out << prefix << " RandomSeed: " << fRandomSeed << endl;
246  out << prefix << " LogLevel: " << fLogLevel << endl;
247  out << prefix << " Actual random seed: " << m_pran->getSeed();
248 
249  return out;
250 }
251 
252 //******************************************************************************
253 
255 
256  //return the correct random number to select the PhaseMap making sure it is
257  //correct for the given event
258 
259  int num=0;
260 
261  if( chan == 0 )
262  {
263  CLHEP::RandFlat flat(*m_pran);
264  num = flat.fire()*fNumberOfPhases;
265  fNum=num;
266  }
267  else
268  {
269  num = fNum;
270  }
271 
272  return num;
273 }
274 
275 //******************************************************************************
276 
278 
279  //test if there is the amplitude array for channel chan
280 
281  if ( fChAmplitudeMap.find(chan) != fChAmplitudeMap.end() ) {
282  array = fChAmplitudeMap.at(chan);
283  }
284 
285  return;
286 }
287 
288 //******************************************************************************
289 
291 
292  //test if there is the amplitude array for channel chan
293 
294  if ( fChFrequencyMap.find(chan) != fChFrequencyMap.end() ) {
295  array = fChFrequencyMap.at(chan);
296  }
297 
298  return;
299 }
300 
301 //******************************************************************************
302 
304  Map & chFrequencyMap, Map & chAmplitudeMap, double cut, int &normalization ) const {
305  /*
306  Import fft from the TProfile2D and store into the frequency and amplitude
307  maps if the frequencies are above the cut
308  */
309 
310  TFile *fin = TFile::Open(noiseModel.c_str(), "READ");
311  if(!fin->IsOpen()){
312  cout << "ERROR!: Can't open file: " << noiseModel << endl;
313  return;
314  }
315  else{
316  cout << "File: " << noiseModel << " successfully opened!" << endl;
317  }
318 
319  //get the histogram
320  TIter next( fin->GetListOfKeys() );
321  TKey *key;
322  TProfile2D *inputHist = new TProfile2D(); //default initialisazion
323 
324  while( (key = (TKey*)next()) ){
325 
326  string name( key->GetName() );
327  string keyName( key->GetClassName() ); //parse char to string
328  if( keyName == "TProfile2D"){
329  inputHist = (TProfile2D*)fin->Get(key->GetName());
330  }
331  else{
332  std::cout << "ERROR! Object: " << keyName << " in file " << noiseModel
333  << "has not the right format!" << std::endl;
334  fin->Close();
335  return;
336  }
337  }
338 
339  //if the model was successfully build the frequency/channel map
340  for(int xx=1; xx<inputHist->GetNbinsX()+1; xx++){
341  for(int yy=1; yy<inputHist->GetNbinsY()+1; yy++){
342 
343  double amplitude = inputHist->GetBinContent( xx, yy );
344  double ch = (int)inputHist->GetXaxis()->GetBinLowEdge(xx)+1; //channel numbered fom 1 to 1280
345  double frequency = inputHist->GetYaxis()->GetBinCenter(yy); //frequencies fom 0 to 1.25 MHz
346 
347  if(amplitude >= cut){
348  chFrequencyMap[ch].push_back( frequency );
349  chAmplitudeMap[ch].push_back( amplitude );
350  }
351  }
352  }
353 
354  //get the normalization
355  //normalization = inputHist->GetNbinsY();
356 
357  return;
358 }
359 
360 //******************************************************************************
361 
363  float minShift, float maxShift ){
364 
365  //Simpy generates an map with phases from 0 to 2*pi with the same size of size
366 
367  CLHEP::RandFlat flat(*m_pran);
368 
369  vector<float> phaseVector; //<<Phase shifts per group of channels
370  vector<float> phaseArray; //<<Phases common to all channels
371  phaseVector.resize(size);
372  phaseArray.resize(size);
373 
374  //make a new phase vector
375  for( int f=0; f<size; f++ ){
376  double phase = flat.fire()*2.*TMath::Pi();
377  phaseArray.at(f) = phase;
378 
379  }
380 
381  //loop over all channels
382  int index=0; //keep track of the groups already checked;
384  for(Channel chan=0; chan< geo->Nchannels() ; chan++){
385 
386  //assign each channel to a group
387  if( chan >= (Channel)fChannelGroup.at(index) ){
388 
389  index++; //now we can change group
390 
391  //make a new phase vector
392  for( int f=0; f<size; f++ ){
393  double phase = minShift + flat.fire()*( maxShift - minShift );
394  phaseVector.at(f) = phase + phaseArray.at(f);
395 
396  }
397  }//end if channel group
398 
399  //add the vector to the map
400  phaseMap[chan] = phaseVector;
401 
402  }//end for channels
403 
404  return;
405 }
406 
407 //******************************************************************************
408 
410  vector< float > & noiseArray,
411  vector< float > ampArray, vector< float > freqArray, vector< float > phaseArray, float randAmp ) const {
412 
413  //Sum up all the frequencies and amplitude. Make noise waveform
414  const string myname = "DPhaseCoherentNoiseService::getNoiseArray: ";
415 
416  //random number generator
417  CLHEP::RandGauss gaus(*m_pran);
418 
419  //detector properties service
420 
421  //check if frequency vector, and amplitude vector have the same size.
422  if( (ampArray.size() != freqArray.size()) || (ampArray.size() < freqArray.size()) ){
423 
424  const string myname = "DPhaseCoherentNoiseService::getNoiseArray: ";
425  if( fLogLevel > 0 ){
426  cout << myname << "ERROR: amplitude array and frequency array have not the same size." << endl;
427  }
428  return;
429  }
430 
431  //make the noiseArray: loop over time...
432  for( size_t t=0; t<noiseArray.size(); t++ ){
433 
434  //...and loop over frequencies
435  for( size_t f=0; f<freqArray.size(); f++ ){
436 
437  //randomize amplitude
438  double amp = ampArray.at(f) + gaus.fire( 0, randAmp ); //<< Randomization with the expected rms fluctuation calculated from the model
439 
440  //make signal for that frequency
441  double argument = 2*TMath::Pi()*sampling_rate(clockData)*(1.e-3)*freqArray.at(f)*t + phaseArray.at(f);
442 
443  noiseArray.at(t) += ( ((float)1/(float)fNormalization)*amp*sin( argument ) );
444  }
445  }
446 
447  //return the noise array
448  return;
449 }
450 
451 //******************************************************************************
452 
454 
455  //pregenerated random phases arrays
456  fPhaseMap.resize(fNumberOfPhases);
457  for ( int isam=0; isam<fNumberOfPhases; ++isam ) {
459  }
460 
461 }
462 
463 //**********************************************************************
464 
static QCString name
Definition: declinfo.cpp:673
std::string fNoiseModel
< noise model root file
std::vector< float > fRandomize
< randomization of the amplitude
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::string string
Definition: nybbler.cc:12
int fLogLevel
< Log message level: 0=quiet, 1=init only, 2+=every event
int fNumberOfPhases
< Number of pregenerated phase shift maps
Map fChFrequencyMap
Map storing the frequency vector for each channel.
int fNormalization
< Normalization factor ( similar to the one for the InFFT )
std::vector< int > fChannelGroup
< Channels in the same group get the same phase
struct vector vector
Planes which measure Z direction.
Definition: geo_types.h:132
void importNoiseModel(std::string noiseModel, Map &chFrequencyMap, Map &chAmplitudeMap, double cut, int &normalization) const
void makePhaseMap(Map &phaseMap, int size, float minShift, float maxShift)
Planes which measure Y direction.
Definition: geo_types.h:133
DPhaseCoherentNoiseService(fhicl::ParameterSet const &pset)
std::ostream & print(std::ostream &out=std::cout, std::string prefix="") const
art framework interface to geometry description
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
Map fChAmplitudeMap
Map holding the amplitude of the frequency for each channel.
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.
T get(std::string const &key) const
Definition: ParameterSet.h:271
void getAmplitudeArray(Channel chan, std::vector< float > &array) const
size_t size
Definition: lodepng.cpp:55
std::vector< float > fInchoerentNoise
< Mean and std of the incoherent noise
int addNoise(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, Channel chan, AdcSignalVector &sigs) const
int fNum
Hold the correct event number.
static int max(int a, int b)
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
int fRandomSeed
< Seed for random number service. If absent or zero, use SeedSvc.
void getNoiseArray(detinfo::DetectorClocksData const &clockData, std::vector< float > &noiseArray, std::vector< float > ampArray, std::vector< float > freqArray, std::vector< float > phaseArray, float randAmp) const
auto array(Array const &a)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:228
void getFrequencyArray(Channel chan, std::vector< float > &array) const
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< Map > fPhaseMap
Pregenerated phase shift maps.
std::vector< AdcSignal > AdcSignalVector
Definition: AdcTypes.h:22
double fAmplitudeCut
< only frequencies with amplitude above this cut will be considered
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
LArSoft geometry interface.
Definition: ChannelGeo.h:16
std::vector< float > fPhaseShift
< Phase shift for each group of 30 channels
std::map< int, std::vector< float > > Map
QTextStream & endl(QTextStream &s)
#define DEFINE_ART_SERVICE_INTERFACE_IMPL(svc, iface)