301 TH1::AddDirectory(kFALSE);
338 for(
size_t wireIter = 0; wireIter < wireVecHandle->size(); wireIter++)
348 std::vector<geo::WireID> wids = geom->
ChannelToWire(channel);
357 std::cout <<
"-----------------------------------------------------------------------------------------------------------" <<
std::endl;
358 std::cout <<
"Channel: " << channel <<
std::endl;
372 for(
const auto& range : signalROI.
get_ranges())
377 const std::vector<float>& signal = range.data();
389 std::vector<float> timeAve;
401 if (timeValsVec.empty())
continue;
424 std::cout <<
"-------------------- ROI #" << CountROI <<
" -------------------- " <<
std::endl;
425 if(timeValsVec.size() == 1) std::cout <<
"ROI #" << CountROI <<
" (" << timeValsVec.size() <<
" peak): ROIStartTick: " << range.offset <<
" ROIEndTick:" << range.offset+range.size() <<
std::endl;
426 else std::cout <<
"ROI #" << CountROI <<
" (" << timeValsVec.size() <<
" peaks): ROIStartTick: " << range.offset <<
" ROIEndTick:" << range.offset+range.size() <<
std::endl;
433 for(
auto const& timeValsTmp : timeValsVec )
435 std::cout <<
"Peak #" << CountPeak <<
": PeakStartTick: " << range.offset + std::get<0>(timeValsTmp) <<
" PeakMaxTick: " << range.offset + std::get<1>(timeValsTmp) <<
" PeakEndTick: " << range.offset + std::get<2>(timeValsTmp) << std::endl;
442 if (timeValsVec.empty())
continue;
457 int NumberOfPeaksBeforeFit=0;
458 unsigned int nExponentialsForFit=0;
459 double chi2PerNDF=0.;
462 unsigned int NumberOfMergedVecs = mergedVec.size();
468 for(
unsigned int j=0; j < NumberOfMergedVecs; j++)
470 int startT = std::get<0>(mergedVec.at(j));
471 int endT = std::get<1>(mergedVec.at(j));
472 int width = endT + 1 - startT;
475 int NFluctuations = std::get<3>(mergedVec.at(j));
480 if(peakVals.size() == 1) std::cout <<
"- Group #" << j <<
" (" << peakVals.size() <<
" peak): GroupStartTick: " << range.offset + startT <<
" GroupEndTick: " << range.offset + endT <<
std::endl;
481 else std::cout <<
"- Group #" << j <<
" (" << peakVals.size() <<
" peaks): GroupStartTick: " << range.offset + startT <<
" GroupEndTick: " << range.offset + endT <<
std::endl;
482 std::cout <<
"Fluctuations in this group: " << NFluctuations <<
std::endl;
483 int CountPeakInGroup=0;
484 for(
auto const& peakValsTmp : peakVals )
486 std::cout <<
"Peak #" << CountPeakInGroup <<
" in group #" << j <<
": PeakInGroupStartTick: " << range.offset + std::get<2>(peakValsTmp) <<
" PeakInGroupMaxTick: " << range.offset + std::get<0>(peakValsTmp) <<
" PeakInGroupEndTick: " << range.offset + std::get<3>(peakValsTmp) << std::endl;
496 std::cout <<
"Delete this group of peaks because width, integral or width/intergral is too small." <<
std::endl;
505 NumberOfPeaksBeforeFit = peakVals.size();
506 nExponentialsForFit = peakVals.size();
520 std::cout <<
"--- First fit ---" <<
std::endl;
521 if (nExponentialsForFit == 1) std::cout <<
"- Fitted " << nExponentialsForFit <<
" peak in group #" << j <<
":" <<
std::endl;
522 else std::cout <<
"- Fitted " << nExponentialsForFit <<
" peaks in group #" << j <<
":" <<
std::endl;
523 std::cout <<
"chi2/ndf = " << chi2PerNDF <<
std::endl;
527 std::cout <<
"tau1 [mus] = " << paramVec[0].first <<
std::endl;
528 std::cout <<
"tau2 [mus] = " << paramVec[1].first <<
std::endl;
530 for(
unsigned int i = 0; i < nExponentialsForFit; i++)
532 std::cout <<
"Peak #" << i <<
": A [ADC] = " << paramVec[2*(i+1)].first << std::endl;
533 std::cout <<
"Peak #" << i <<
": t0 [ticks] = " << range.offset + paramVec[2*(i+1)+1].first << std::endl;
538 for(
unsigned int i = 0; i < nExponentialsForFit; i++)
540 std::cout <<
"Peak #" << i <<
": A [ADC] = " << paramVec[4*i+2].first <<
std::endl;
541 std::cout <<
"Peak #" << i <<
": t0 [ticks] = " << range.offset + paramVec[4*i+3].first <<
std::endl;
542 std::cout <<
"Peak #" << i <<
": tau1 [mus] = " << paramVec[4*i].first <<
std::endl;
543 std::cout <<
"Peak #" << i <<
": tau2 [mus] = " << paramVec[4*i+1].first <<
std::endl;
549 if (!(chi2PerNDF < std::numeric_limits<double>::infinity()))
continue;
560 unsigned int nExponentialsBeforeRefit=nExponentialsForFit;
561 unsigned int nExponentialsAfterRefit=nExponentialsForFit;
562 double oldChi2PerNDF = chi2PerNDF;
567 while( (nExponentialsForFit == 1 && nExponentialsAfterRefit < 3*nExponentialsBeforeRefit && chi2PerNDF > fChi2NDFRetry) ||
568 (nExponentialsForFit > 1 && nExponentialsAfterRefit < 3*nExponentialsBeforeRefit && chi2PerNDF >
fChi2NDFRetryFactorMultiHits*fChi2NDFRetry) )
570 RefitSuccess =
false;
575 for(
auto& PeakDevCand : PeakDev)
580 peakValsTemp = peakVals;
582 AddPeak(PeakDevCand, peakValsTemp);
585 if (chi2PerNDF2 < chi2PerNDF)
587 paramVec = paramVecRefit;
588 peakVals = peakValsTemp;
589 nExponentialsForFit = peakVals.size();
590 chi2PerNDF = chi2PerNDF2;
592 nExponentialsAfterRefit++;
599 if(RefitSuccess ==
false)
601 for(
auto& PeakDevCand : PeakDev)
606 peakValsTemp=peakVals;
611 if (chi2PerNDF2 < chi2PerNDF)
613 paramVec = paramVecRefit;
614 peakVals = peakValsTemp;
615 nExponentialsForFit = peakVals.size();
616 chi2PerNDF = chi2PerNDF2;
618 nExponentialsAfterRefit++;
625 if(RefitSuccess ==
false)
634 std::cout <<
"--- Refit ---" <<
std::endl;
635 if( chi2PerNDF == oldChi2PerNDF) std::cout <<
"chi2/ndf didn't improve. Keep first fit." <<
std::endl;
638 std::cout <<
"- Added peaks to group #" << j <<
". This group now has " << nExponentialsForFit <<
" peaks:" <<
std::endl;
639 std::cout <<
"- Group #" << j <<
" (" << peakVals.size() <<
" peaks): GroupStartTick: " << range.offset + startT <<
" GroupEndTick: " << range.offset + endT <<
std::endl;
641 int CountPeakInGroup=0;
642 for(
auto const& peakValsTmp : peakVals )
644 std::cout <<
"Peak #" << CountPeakInGroup <<
" in group #" << j <<
": PeakInGroupStartTick: " << range.offset + std::get<2>(peakValsTmp) <<
" PeakInGroupMaxTick: " << range.offset + std::get<0>(peakValsTmp) <<
" PeakInGroupEndTick: " << range.offset + std::get<3>(peakValsTmp) << std::endl;
648 std::cout <<
"chi2/ndf = " << chi2PerNDF <<
std::endl;
652 std::cout <<
"tau1 [mus] = " << paramVec[0].first <<
std::endl;
653 std::cout <<
"tau2 [mus] = " << paramVec[1].first <<
std::endl;
655 for(
unsigned int i = 0; i < nExponentialsForFit; i++)
657 std::cout <<
"Peak #" << i <<
": A [ADC] = " << paramVec[2*(i+1)].first << std::endl;
658 std::cout <<
"Peak #" << i <<
": t0 [ticks] = " << range.offset + paramVec[2*(i+1)+1].first << std::endl;
663 for(
unsigned int i = 0; i < nExponentialsForFit; i++)
665 std::cout <<
"Peak #" << i <<
": A [ADC] = " << paramVec[4*i+2].first <<
std::endl;
666 std::cout <<
"Peak #" << i <<
": t0 [ticks] = " << range.offset + paramVec[4*i+3].first <<
std::endl;
667 std::cout <<
"Peak #" << i <<
": tau1 [mus] = " << paramVec[4*i].first <<
std::endl;
668 std::cout <<
"Peak #" << i <<
": tau2 [mus] = " << paramVec[4*i+1].first <<
std::endl;
680 for(
unsigned int i = 0; i < nExponentialsForFit; i++)
690 peakTau1 = paramVec[0].first;
691 peakTau2 = paramVec[1].first;
692 peakAmp = paramVec[2*(i+1)].first;
693 peakMean = paramVec[2*(i+1)+1].first;
697 peakTau1 = paramVec[4*i].first;
698 peakTau2 = paramVec[4*i+1].first;
699 peakAmp = paramVec[4*i+2].first;
700 peakMean = paramVec[4*i+3].first;
704 double peakAmpTrue = signal[std::get<0>(peakVals.at(i))];
705 double peakAmpErr = 1.;
708 TF1 Exponentials(
"Exponentials",
"( [0] * exp(0.4*(x-[1])/[2]) / ( 1 + exp(0.4*(x-[1])/[3]) ) )",startT,endT);
709 Exponentials.SetParameter(0, peakAmp);
710 Exponentials.SetParameter(1, peakMean);
711 Exponentials.SetParameter(2, peakTau1);
712 Exponentials.SetParameter(3, peakTau2);
713 double peakMeanTrue = Exponentials.GetMaximumX(startT,endT);
714 Exponentials.Delete();
717 double peakWidth =
WidthFunc(peakMean, peakAmp, peakTau1, peakTau2, startT, endT, peakMeanTrue);
726 peakMeanErr = paramVec[2*(i+1)+1].
second;
730 peakMeanErr = paramVec[4*i+3].second;
732 double peakWidthErr = 0.1*peakWidth;
736 double chargeErr = std::sqrt(TMath::Pi()) * (peakAmpErr*peakWidthErr + peakWidthErr*peakAmpErr);
739 int startTthisHit = std::get<2>(peakVals.at(i));
740 int endTthisHit = std::get<3>(peakVals.at(i));
745 double sumADC = std::accumulate(sumStartItr, sumEndItr + 1, 0.);
754 std::cout <<
"WARNING: For peak #" << i <<
" in this group:" <<
std::endl;
755 if( peakWidth <= 0 || charge <= 0. || charge != charge) std::cout <<
"Fit function returned width < 0 or charge < 0 or charge = nan." <<
std::endl;
756 if( ( nExponentialsForFit == 1 && chi2PerNDF > fChi2NDFMax ) || ( nExponentialsForFit >= 2 && chi2PerNDF >
fChi2NDFMaxFactorMultiHits*fChi2NDFMax ) )
759 std::cout <<
"WARNING: For fit of this group (" << NumberOfPeaksBeforeFit <<
" peaks before refit, " << nExponentialsForFit <<
" peaks after refit): " <<
std::endl;
760 if ( nExponentialsForFit == 1 && chi2PerNDF > fChi2NDFMax ) std::cout <<
"chi2/ndf of this fit (" << chi2PerNDF <<
") is higher than threshold (" << fChi2NDFMax <<
")." <<
std::endl;
763 std::cout <<
"---> DO NOT create hit object from fit parameters but use peak values instead." <<
std::endl;
764 std::cout <<
"---> Set fit parameter so that a sharp peak with a width of 1 tick is shown in the event display. This indicates that the fit failed." <<
std::endl;
767 peakMeanErr=peakWidth/2;
769 peakMeanTrue = std::get<0>(peakVals.at(i));
772 peakMean = peakMeanTrue;
781 startTthisHit+roiFirstBinTick,
782 endTthisHit+roiFirstBinTick,
784 peakMeanTrue+roiFirstBinTick,
800 std::cout <<
"- Created hit object for peak #" << i <<
" in this group with the following parameters (obtained from fit):" <<
std::endl;
801 std::cout <<
"HitStartTick: " << startTthisHit+roiFirstBinTick <<
std::endl;
802 std::cout <<
"HitEndTick: " << endTthisHit+roiFirstBinTick <<
std::endl;
803 std::cout <<
"HitWidthTicks: " << peakWidth <<
std::endl;
804 std::cout <<
"HitMeanTick: " << peakMeanTrue+roiFirstBinTick <<
" +- " << peakMeanErr <<
std::endl;
805 std::cout <<
"HitAmplitude [ADC]: " << peakAmpTrue <<
" +- " << peakAmpErr <<
std::endl;
806 std::cout <<
"HitIntegral [ADC*ticks]: " << charge <<
" +- " << chargeErr <<
std::endl;
807 std::cout <<
"HitADCSum [ADC*ticks]: " << sumADC <<
std::endl;
808 std::cout <<
"HitMultiplicity: " << nExponentialsForFit <<
std::endl;
809 std::cout <<
"HitIndex in group: " << numHits <<
std::endl;
810 std::cout <<
"Hitchi2/ndf: " << chi2PerNDF <<
std::endl;
811 std::cout <<
"HitNDF: " << NDF <<
std::endl;
818 std::array<float, 4> fitParams;
819 fitParams[0] = peakMean+roiFirstBinTick;
820 fitParams[1] = peakTau1;
821 fitParams[2] = peakTau2;
822 fitParams[3] = peakAmp;
846 if (nHitsInThisGroup *
fLongPulseWidth < (endT - startT + 1) ) nHitsInThisGroup++;
848 int firstTick = startT;
856 std::cout <<
"WARNING: Number of peaks in this group (" << NumberOfPeaksBeforeFit <<
") is higher than threshold (" <<
fMaxMultiHit <<
")." <<
std::endl;
857 std::cout <<
"---> DO NOT fit. Split group of peaks into hits with equal length instead." <<
std::endl;
862 std::cout <<
"WARNING: group of peak is longer (" << width <<
" ticks) than threshold (" <<
fMaxGroupLength <<
" ticks)." <<
std::endl;
863 std::cout <<
"---> DO NOT fit. Split group of peaks into hits with equal length instead." <<
std::endl;
868 std::cout <<
"WARNING: fluctuations (" << NFluctuations <<
") higher than threshold (" <<
fMaxFluctuations <<
")." <<
std::endl;
869 std::cout <<
"---> DO NOT fit. Split group of peaks into hits with equal length instead." <<
std::endl;
880 std::cout <<
"---> Group goes from tick " << roiFirstBinTick+startT <<
" to " << roiFirstBinTick+endT <<
". Split group into (" << roiFirstBinTick+endT <<
" - " << roiFirstBinTick+startT <<
")/" <<
fLongPulseWidth <<
" = " << (endT - startT) <<
"/" <<
fLongPulseWidth <<
" = " << nHitsInThisGroup <<
" peaks (" <<
fLongPulseWidth <<
" = LongPulseWidth), or maximum LongMaxHits = " <<
fLongMaxHits <<
" peaks." << std::endl;
884 for(
int hitIdx = 0; hitIdx < nHitsInThisGroup; hitIdx++)
888 double peakMeanTrue = (firstTick + lastTick) / 2.;
889 if( NumberOfPeaksBeforeFit == 1 && nHitsInThisGroup == 1) peakMeanTrue = std::get<0>(peakVals.at(0));
890 double peakMeanErr = (lastTick - firstTick) / 2.;
891 double sumADC = std::accumulate(signal.begin() + firstTick, signal.begin() + lastTick + 1, 0.);
892 double charge = sumADC;
893 double chargeErr = 0.1*sumADC;
894 double peakAmpTrue = 0;
898 if(signal[
tick] > peakAmpTrue) peakAmpTrue = signal[
tick];
901 double peakAmpErr = 1.;
902 nExponentialsForFit = nHitsInThisGroup;
906 double peakMean = peakMeanTrue-2;
907 double peakTau1 = 0.008;
908 double peakTau2 = 0.0065;
909 double peakAmp = 20.;
913 firstTick+roiFirstBinTick,
914 lastTick+roiFirstBinTick,
916 peakMeanTrue+roiFirstBinTick,
933 std::cout <<
"- Created hit object for peak #" << hitIdx <<
" in this group with the following parameters (obtained from waveform):" <<
std::endl;
934 std::cout <<
"HitStartTick: " << firstTick+roiFirstBinTick <<
std::endl;
935 std::cout <<
"HitEndTick: " << lastTick+roiFirstBinTick <<
std::endl;
936 std::cout <<
"HitWidthTicks: " << peakWidth <<
std::endl;
937 std::cout <<
"HitMeanTick: " << peakMeanTrue+roiFirstBinTick <<
" +- " << peakMeanErr <<
std::endl;
938 std::cout <<
"HitAmplitude [ADC]: " << peakAmpTrue <<
" +- " << peakAmpErr <<
std::endl;
939 std::cout <<
"HitIntegral [ADC*ticks]: " << charge <<
" +- " << chargeErr <<
std::endl;
940 std::cout <<
"HitADCSum [ADC*ticks]: " << sumADC <<
std::endl;
941 std::cout <<
"HitMultiplicity: " << nExponentialsForFit <<
std::endl;
942 std::cout <<
"HitIndex in group: " << hitIdx <<
std::endl;
943 std::cout <<
"Hitchi2/ndf: " << chi2PerNDF <<
std::endl;
944 std::cout <<
"HitNDF: " << NDF <<
std::endl;
949 std::array<float, 4> fitParams;
950 fitParams[0] = peakMean+roiFirstBinTick;
951 fitParams[1] = peakTau1;
952 fitParams[2] = peakTau2;
953 fitParams[3] = peakAmp;
957 firstTick = lastTick+1;
962 fChi2->Fill(chi2PerNDF);
void findCandidatePeaks(std::vector< float >::const_iterator startItr, std::vector< float >::const_iterator stopItr, TimeValsVec &timeValsVec, float &PeakMin, int firstTick) const
std::vector< raw::RawDigit > RawDigits
void mergeCandidatePeaks(const std::vector< float > signalVec, TimeValsVec, MergedTimeWidVec &)
std::vector< std::tuple< int, int, PeakTimeWidVec, int >> MergedTimeWidVec
ChannelID_t Channel() const
DAQ channel this raw data was read from.
std::vector< raw::RawDigit > RawDigits
void FindPeakWithMaxDeviation(const std::vector< float > fSignalVector, int fNPeaks, int fStartTime, int fEndTime, bool fSameShape, ParameterVec fparamVec, PeakTimeWidVec fpeakVals, PeakDevVec &fPeakDev)
std::vector< std::tuple< double, int, int, int >> PeakDevVec
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
CryostatID_t Cryostat
Index of cryostat.
const range_list_t & get_ranges() const
Returns the internal list of non-void ranges.
WireID_t Wire
Index of the wire within its plane.
void SplitPeak(std::tuple< double, int, int, int > fPeakDevCand, PeakTimeWidVec &fpeakValsTemp)
double fChi2NDFMaxFactorMultiHits
void addVector(FVector_ID id, std::array< float, N > const &values)
int TDCtick_t
Type representing a TDC tick.
std::vector< std::tuple< int, int, int, int >> PeakTimeWidVec
Class managing the creation of a new recob::Hit object.
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
FVector_ID initOutputs(std::string const &dataTag, size_t dataSize, std::vector< std::string > const &names=std::vector< std::string >(N,""))
constexpr ChannelID_t InvalidChannelID
ID of an invalid channel.
void AddPeak(std::tuple< double, int, int, int > fPeakDevCand, PeakTimeWidVec &fpeakValsTemp)
double fChi2NDFRetryFactorMultiHits
A class handling a collection of hits and its associations.
std::vector< std::pair< double, double >> ParameterVec
double fWidthNormalization
anab::FVectorWriter< 4 > fHitParamWriter
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
double ChargeFunc(double fPeakMean, double fPeakAmp, double fPeakTau1, double fPeakTau2, double fChargeNormFactor, double fPeakMeanTrue)
double fMinADCSumOverWidth
PlaneID_t Plane
Index of the plane within its TPC.
void saveOutputs(art::Event &evt)
Check consistency and save all the results in the event.
Detector simulation of raw signals on wires.
void FitExponentials(const std::vector< float > fSignalVector, const PeakTimeWidVec fPeakVals, int fStartTime, int fEndTime, ParameterVec &fparamVec, double &fchi2PerNDF, int &fNDF, bool fSameShape)
std::string fCalDataModuleLabel
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
std::vector< std::tuple< int, int, int >> TimeValsVec
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
void doBinAverage(const std::vector< float > &inputVec, std::vector< float > &outputVec, size_t binsToAverage) const
2D representation of charge deposited in the TDC/wire plane
unsigned int ChannelID_t
Type representing the ID of a readout channel.
TPCID_t TPC
Index of the TPC within its cryostat.
second_as<> second
Type of time stored in seconds, in double precision.
art::InputTag fNewHitsTag
double WidthFunc(double fPeakMean, double fPeakAmp, double fPeakTau1, double fPeakTau2, double fStartTime, double fEndTime, double fPeakMeanTrue)
QTextStream & endl(QTextStream &s)