7 #include "fhiclcpp/ParameterSet.h"
8 #include "messagefacility/MessageLogger/MessageLogger.h"
9 #include "art_root_io/TFileService.h"
13 #include "art/Utilities/ToolMacros.h"
14 #include "art/Utilities/make_tool.h"
32 class OpDeconvolutionAlgWiener;
43 std::vector<raw::OpDetWaveform>
RunDeconvolution(std::vector<raw::OpDetWaveform>
const& wfHandle)
override;
90 art::ServiceHandle<art::TFileService>
tfs;
99 fDebug = p.get<
bool >(
"Debug");
107 if(fHypoSignalCustom){
116 fFilter = p.get< std::string >(
"Filter");
121 fFilterParams = p.get< std::vector<double> >(
"FilterParams");
127 auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
129 if (fElectronics==
"Daphne")
fSamplingFreq=fDaphne_Freq/1000.;
130 auto const* lar_prop = lar::providerFrom<detinfo::LArPropertiesService>();
135 cet::search_path sp(
"FW_SEARCH_PATH");
136 sp.find_file(fOpDetDataFile, fname);
137 TFile*
file = TFile::Open(fname.c_str(),
"READ");
138 std::vector<double>* SinglePEVec_p;
139 file->GetObject(
"SinglePEVec", SinglePEVec_p);
140 if (fElectronics==
"Daphne") file->GetObject(
"SinglePEVec_40ftCable_Daphne", SinglePEVec_p);
143 mf::LogInfo(
"OpDeconvolutionAlg")<<
"Loaded SER from "<<fOpDetDataFile<<
"... size="<<
fSinglePEWave.size()<<std::endl;
148 fFilterTF1 =
new TF1(
"FilterTemplate", fFilter.c_str());
149 for(
size_t k=0;
k<fFilterParams.size();
k++)
151 mf::LogInfo(
"OpDeconvolutionAlg")<<
"Creating parametrized filter... TF1:"<<fFilter<<std::endl;
156 if(fFilter==
"Wiener")
158 else if(fFilter==
"Wiener1PE")
160 mf::LogInfo(
"OpDeconvolutionAlg")<<
"Built light signal hypothesis... L="<<fFilter<<
" size"<<
fSignalHypothesis.size()<<std::endl;
167 std::vector<raw::OpDetWaveform> wfDeco;
168 wfDeco.reserve(wfVector.size());
170 for(
auto const& wf : wfVector)
173 size_t wfsize=wf.Waveform().size();
174 if(wfsize>MaxBinsFFT){
175 mf::LogWarning(
"OpDeconvolutionAlg")<<
"Skipping waveform...waveform size is"<<wfsize<<
"...maximum allowed FFT size is="<<MaxBinsFFT<<std::endl;
178 mf::LogInfo(
"OpDeconvolutionAlg")<<
"Deconvolving waveform:"<<NDecoWf<<
"...size="<<wfsize<<std::endl;
179 size_t wfsizefft=WfSizeFFT(wfsize);
181 std::vector<double> wave;
182 wave.reserve(wfsizefft);
183 wave.assign(wf.Waveform().begin(), wf.Waveform().end());
186 double minADC=*min_element(wave.begin(), wave.end());
189 if(fApplyExpoAvSmooth)
190 ApplyExpoAvSmoothing(wave);
192 ApplyUnAvSmoothing(wave);
195 double baseline_mean=0., baseline_stddev=1.;
196 EstimateBaselineStdDev(wave, baseline_mean, baseline_stddev);
197 double wfPeakPE=fHypoSignalScale*(baseline_mean-minADC)/fPMTChargeToADC;
198 SubtractBaseline(wave, baseline_mean);
201 wave.resize(wfsizefft, 0);
202 std::vector<TComplex> fDeconvolutionKernel=DeconvolutionKernel(wfsize, baseline_stddev, wfPeakPE);
205 fft_service->ReinitializeFFT(wfsizefft,
"", 20);
206 fft_service->Convolute(wave, fDeconvolutionKernel);
210 EstimateBaselineStdDev(wave, baseline_mean, baseline_stddev);
211 SubtractBaseline(wave, baseline_mean);
212 double fDecoWfScaleFactor=1./fDecoWaveformPrecision;
213 std::transform(wave.begin(), wave.end(), wave.begin(), [fDecoWfScaleFactor](
double &dec){
return fDecoWfScaleFactor*dec; } );
218 auto minADC_ix=min_element(wave.begin(), wave.end());
219 std::cout<<
"Stamp="<<wf.TimeStamp()<<
" OpCh"<<wf.ChannelNumber()<<
" MinADC="<<minADC<<
" (";
220 std::cout<<minADC_ix-wave.begin()<<
") Size="<<wf.Waveform().size()<<
" ScFactor="<<wfPeakPE<<
"\n\n";
223 TH1F * h_deco =
tfs->make< TH1F >(name.c_str(),
";Bin;#PE", MaxBinsFFT, 0, MaxBinsFFT);
224 for(
size_t k=0;
k<wave.size();
k++){
226 h_deco->Fill(
k, wave[
k]);
230 TH1F * h_raw =
tfs->make< TH1F >(name.c_str(),
";Bin;ADC", MaxBinsFFT, 0, MaxBinsFFT);
231 for(
size_t k=0;
k<wf.Waveform().size();
k++){
233 h_raw->Fill(
k, wf.Waveform()[
k]);
238 raw::OpDetWaveform decowf( wf.TimeStamp(), wf.ChannelNumber(), std::vector<short unsigned int> (wave.begin(), wave.end()) );
239 wfDeco.push_back(decowf);
248 std::transform (std::next(wf.begin(), 1), wf.end(), wf.begin(), std::next(wf.begin(), 1),
249 [&](
double _x,
double _y) {
return fExpoAvSmoothPar*_x+ (1. - fExpoAvSmoothPar)*_y; } );
254 std::vector<double> wf_aux(wf.begin(), wf.end());
255 for(
size_t bin=fUnAvNeighbours;
bin<wf.size()-fUnAvNeighbours;
bin++){
257 for(
size_t nbin=
bin-fUnAvNeighbours; nbin<=
bin+fUnAvNeighbours; nbin++)
260 wf[
bin]=sum*fNormUnAvSmooth;
266 if (n && !(n & (n - 1)))
278 if(fHypoSignalCustom && fHypoSignalWeights.size()!=fHypoSignalTimeConsts.size()){
279 mf::LogWarning(
"OpDeconvolutionAlg")<<
"HypoSignalWeights and HypoSignalTimeConsts must have the same size"<<
280 "...Switching to 2-exponential (default values in LArProperties)"<<std::endl;
282 if(!fHypoSignalCustom || fHypoSignalWeights.size()!=fHypoSignalTimeConsts.size()){
287 mf::LogInfo(
"OpDeconvolutionAlg")<<
"Creating hypothesis signal for Wiener filter..."<<std::endl;
288 mf::LogInfo(
"OpDeconvolutionAlg")<<
"Using a "<<fHypoSignalTimeConsts.size()<<
"-exponential"<<std::endl;
289 mf::LogInfo(
"OpDeconvolutionAlg")<<
"Time constants [ns]:";
290 for(
auto &tau:fHypoSignalTimeConsts) mf::LogInfo(
"OpDeconvolutionAlg")<<tau<<
" ";
291 mf::LogInfo(
"OpDeconvolutionAlg")<<
"\nWeights:";
292 for(
auto &
w:fHypoSignalWeights) mf::LogInfo(
"OpDeconvolutionAlg")<<
w<<
" ";
293 mf::LogInfo(
"OpDeconvolutionAlg")<<
"\n";
295 std::vector<double> v(n, 0);
296 size_t maxbin=fSamplingFreq*fHypoSignalTimeWindow;
300 for(
size_t k=0;
k<maxbin;
k++){
301 double t = (double)(
k) / fSamplingFreq;
303 for(
size_t ix=0; ix<fHypoSignalTimeConsts.size(); ix++){
304 value+=fHypoSignalWeights[ix]*
std::exp(-1.*t/fHypoSignalTimeConsts[ix]);
319 double minADC=*min_element(wf.begin(), wf.end());
320 double maxADC=*max_element(wf.begin(), wf.end());
321 unsigned nbins=25*ceil(maxADC-minADC);
322 TH1F h_std = TH1F(
"",
";;", nbins, 0, (maxADC-minADC)/2);
323 TH1F h_mean = TH1F(
"",
";;", nbins, minADC, maxADC);
325 for(
size_t ix=0; ix<wf.size()-fBaselineSample; ix++){
326 double sum2=0, sum=0;
327 for(
size_t jx=ix; jx<ix+fBaselineSample; jx++){
328 sum = sum + wf.at(jx);
330 sum/=fBaselineSample;
331 for(
size_t jx=ix; jx<ix+fBaselineSample; jx++){
332 sum2 = sum2 + pow( wf.at(jx)-sum, 2 );
334 h_std.Fill( std::sqrt(sum2/fBaselineSample) );
339 _stddev=h_std.GetXaxis()->GetBinCenter(h_std.GetMaximumBin());
340 _mean=h_mean.GetXaxis()->GetBinCenter(h_mean.GetMaximumBin());
343 std::cout<<
" -- Estimating baseline...StdDev: "<<_stddev<<
" Bias="<<_mean<<std::endl;
344 std::cout<<
" .. "<<minADC<<
" "<<maxADC<<
" "<<maxADC-minADC<<
" "<<ceil(log10(maxADC-minADC))<<
" "<<nbins<<
"\n";
347 TH1F * hs_std =
tfs->make< TH1F > (name.c_str(),
"Baseline StdDev;ADC;# entries",
348 h_std.GetNbinsX(), h_std.GetXaxis()->GetXmin(), h_std.GetXaxis()->GetXmax());
349 for(
int k=1;
k<=h_std.GetNbinsX();
k++)
350 hs_std->SetBinContent(
k, h_std.GetBinContent(
k));
353 TH1F * hs_mean =
tfs->make< TH1F >(name.c_str(),
"Baseline Mean;ADC;# entries",
354 h_mean.GetNbinsX(), h_mean.GetXaxis()->GetXmin(), h_mean.GetXaxis()->GetXmax());
355 for(
int k=1;
k<=h_mean.GetNbinsX();
k++)
356 hs_mean->SetBinContent(
k, h_mean.GetBinContent(
k));
365 size_t size=WfSizeFFT(wfsize);
366 TComplex kerinit(0,0,
false);
367 std::vector<TComplex> kernel(size, kerinit);
368 fft_service->ReinitializeFFT (size,
"", 20);
371 std::vector<double> ser( fSinglePEWave.begin(), std::next(fSinglePEWave.begin(),
size) );
372 std::vector<TComplex> serfft;
374 fft_service->DoFFT(ser, serfft);
377 double freq_step=fSamplingFreq/
size;
378 for(
size_t k=0;
k<size/2;
k++){
379 kernel[
k]= fFilterTF1->Eval(
k*freq_step) / serfft[
k] ;
390 std::vector<double> hypo( fSignalHypothesis.begin(), std::next(fSignalHypothesis.begin(),
size) );
391 std::vector<TComplex> hypofft;
392 hypofft.resize(size);
393 fft_service->DoFFT(hypo, hypofft);
396 double noise_power=wfsize*baseline_stddev*baseline_stddev;
397 if(fScaleHypoSignal){
398 noise_power/=pow(snr_scaling, 2);
401 for(
size_t k=0;
k<size/2;
k++){
402 double den = pow(TComplex::Abs(serfft[
k]), 2) + noise_power / pow(TComplex::Abs(hypofft[k]), 2) ;
403 kernel[
k]= TComplex::Conjugate( serfft[k] ) / den;
411 TH1F * hs_wiener =
tfs->make< TH1F >
412 (name.c_str(),
"Wiener Filter;Frequency Bin;Magnitude",size/2, 0, size/2);
413 for(
size_t k=0;
k<size/2;
k++)
414 hs_wiener->SetBinContent(
k, TComplex::Abs( kernel[
k]*serfft[
k] ) );
double fHypoSignalTimeWindow
virtual double ScintFastTimeConst() const =0
Utilities related to art service access.
virtual double ScintSlowTimeConst() const =0
std::vector< double > ScintArrivalTimesShape(size_t n, detinfo::LArProperties const &lar_prop)
std::string fOpDetDataFile
void SubtractBaseline(std::vector< double > &wf, double baseline)
std::vector< double > fSignalHypothesis
~OpDeconvolutionAlgWiener()
std::vector< double > fHypoSignalTimeConsts
std::size_t size(FixedBins< T, C > const &) noexcept
std::vector< double > fSinglePEWave
short unsigned int fBaselineSample
std::vector< double > fHypoSignalWeights
std::vector< TComplex > DeconvolutionKernel(size_t size, double baseline_stddev, double snr_scaling)
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
std::vector< double > fNoiseHypothesis
void EstimateBaselineStdDev(std::vector< double > &wf, double &_mean, double &_stddev)
void ApplyExpoAvSmoothing(std::vector< double > &wf)
virtual double ScintYieldRatio() const =0
art::ServiceHandle< util::LArFFT > fft_service
OpDeconvolutionAlgWiener(fhicl::ParameterSet const &p)
std::vector< raw::OpDetWaveform > RunDeconvolution(std::vector< raw::OpDetWaveform > const &wfHandle) override
short unsigned int fUnAvNeighbours
art::ServiceHandle< art::TFileService > tfs
double fDecoWaveformPrecision
std::vector< double > fFilterParams
size_t WfSizeFFT(size_t n)
std::string to_string(WindowPattern const &pattern)
art::ServiceHandle< art::TFileService > tfs
BEGIN_PROLOG could also be cout
void ApplyUnAvSmoothing(std::vector< double > &wf)