00001 #include "PulseTemplate.h"
00002 #include "utils/HistogramFitFCN.h"
00003 #include "TPulseIsland.h"
00004
00005 #include "TH1.h"
00006 #include "TH1D.h"
00007 #include "TFitterMinuit.h"
00008 #include "TDirectory.h"
00009 #include "TFile.h"
00010 #include "TString.h"
00011
00012 #include <cmath>
00013 #include <iostream>
00014
00015 PulseTemplate::PulseTemplate(int nSigma, int refine, double convergence) : fTemplate(NULL), fFitter(NULL), fNPulses(0),
00016 fNSigma(nSigma), fRefine(refine), fNBins(0),
00017 fClockTick(0.), fSumX(0.), fSumX2(0.),
00018 fSum2X(0.), fConvergence(0.), fConvergenceLimit(convergence) {
00019 HistogramFitFCN* fcn = new HistogramFitFCN();
00020 fFitter = new TFitterMinuit(3);
00021 fFitter->SetMinuitFCN(fcn);
00022 }
00023
00024
00025 PulseTemplate::~PulseTemplate() {
00026 delete fTemplate;
00027 delete fFitter;
00028 }
00029
00030 void PulseTemplate::AddPulse(TPulseIsland* pulse, double shift) {
00031
00032
00033
00034
00035 TH1D* old_template;
00036 double norm;
00037 double peak;
00038 double sigma;
00039 double pol;
00040 double ped;
00041 int nsamps;
00042 std::vector<int> samples;
00043 std::vector<double> rectified_samples, reshaped_pulse;
00044
00045 if (fNPulses > 0)
00046 old_template = (TH1D*)fTemplate->Clone("old_histogram");
00047 pol = (double)pulse->GetTriggerPolarity();
00048 ped = pulse->GetPedestal(0);
00049 samples = pulse->GetSamples();
00050 ped = (double)(samples[0]+samples[1]+samples[2]+samples[3]) / 4.;
00051 nsamps = samples.size();
00052 for (int i = 0; i < nsamps; ++i)
00053 rectified_samples.push_back(pol*((double)samples[i]-ped));
00054
00055 peak = 0.;
00056 norm = pol * (double)samples[0];
00057 for (int i = 1; i < nsamps; ++i) {
00058 if ((double)samples[i] * pol > norm) {
00059 peak = (double)i;
00060 norm = (double)samples[i];
00061 }
00062 }
00063 norm *= pol;
00064
00065 sigma = 0.;
00066 for (int i = 0; i < nsamps; ++i) {
00067 std::cout << i << "\t" << sigma << "," << rectified_samples[i] << "\t";
00068 if (i % 10 == 0)
00069 std::cout << std::endl;
00070 sigma += rectified_samples[i] * std::pow(i - peak, 2.);
00071 }
00072 sigma = std::sqrt(std::abs(sigma)) / (double)nsamps;
00073
00074
00075 if (fNPulses == 0) {
00076 fClockTick = pulse->GetClockTickInNs() / (double)fRefine;
00077 fNBins = (int)(2. * (double)fNSigma * sigma) * fRefine;
00078 std::cout << "Making histogram: " << fNBins << " " << fNSigma << " " << sigma << " " << nsamps << " " << ped << std::endl;
00079 TString str = "template_";
00080 str += pulse->GetBankName();
00081 fTemplate = new TH1D(str, "Template", fNBins, -(double)fNSigma, (double)fNSigma);
00082 }
00083
00084
00085
00086
00087
00088 int pulse_index;
00089 double m = 2. * (double)fNSigma * sigma / (double)fNBins;
00090 double b = (peak + shift) - (double)fNSigma * sigma;
00091 for (int i = 0; i < fNBins; ++i) {
00092 pulse_index = (int)((double)i * m + b + 0.5);
00093 reshaped_pulse.push_back((double)samples[pulse_index] / norm);
00094 }
00095
00096
00097
00098
00099
00100
00101 if (fNPulses == 0) {
00102 unsigned int l = reshaped_pulse.size();
00103 double *reshaped_pulse_array = new double[l];
00104 for (unsigned int i = 0; i < l; ++i)
00105 reshaped_pulse_array[i] = reshaped_pulse[i];
00106 TH1::SmoothArray(reshaped_pulse.size(), reshaped_pulse_array, 1);
00107 for (unsigned int i = 0; i < l; ++i)
00108 reshaped_pulse.at(i) = reshaped_pulse_array[i];
00109 delete [] reshaped_pulse_array;
00110 }
00111
00112
00113
00114
00115
00116 double x, x_old;
00117 double e, e_old;
00118 for (int i = 0; i < fNBins; ++i) {
00119 x_old = fTemplate->GetBinContent(i+1);
00120 e_old = fTemplate->GetBinError(i+1);
00121 x = (double)fNPulses * x_old + reshaped_pulse[i];
00122 x /= (double)(fNPulses + 1);
00123 e = (double)(fNPulses - 1) * std::pow(e_old, 2.) + ((double)reshaped_pulse[i] - x_old) * ((double)reshaped_pulse[i] - x);
00124 e = std::sqrt(e / fNPulses);
00125 fTemplate->SetBinContent(i+1, x);
00126 fTemplate->SetBinError(i+1, e);
00127 }
00128
00129
00130
00131
00132 if (fNPulses > 0) {
00133 double mag_old = old_template->Integral(1, fNBins);
00134 double mag_new = fTemplate->Integral(1,fNBins);
00135 double dot_product = 0.;
00136 for (int i = 1; i <= fNBins; ++i)
00137 dot_product += old_template->GetBinContent(i) * fTemplate->GetBinContent(i);
00138 double cos_similarity = dot_product / (mag_old * mag_new);
00139 fConvergence = ((double)(fNPulses - 1) * fConvergence + (1 - cos_similarity))/(double)fNPulses;
00140 }
00141
00142
00143 fSumX = 0.;
00144 fSumX2 = 0.;
00145 int c = 0;
00146 for (int i = 1; i <= fNBins; ++i) {
00147 c = fTemplate->GetBinContent(i);
00148 fSumX += c;
00149 fSumX2 += std::pow(c, 2.);
00150 }
00151 fSum2X = std::pow(fSumX, 2.);
00152
00153
00154 ++fNPulses;
00155 }
00156
00157 double PulseTemplate::Correlation(TPulseIsland* pulse, double& ped, double& amp, double& time) {
00158
00159
00160
00161
00162
00163
00164 return 0.;
00165 }
00166
00167 double PulseTemplate::Chi2Fit(TPulseIsland* pulse, double& ped, double& amp, double& time) {
00168
00169
00170
00171
00172 std::vector<int> samples = pulse->GetSamples();
00173 int nel = samples.size();
00174 TH1D* rebinned_pulse = new TH1D("pulse2fit", "pulse2fit", nel * fRefine, -0.5, nel - 0.5);
00175 for (int i = 0; i < nel; ++i)
00176 for (int j = 1; j <= fRefine; ++j)
00177 rebinned_pulse->SetBinContent(i * fRefine + j, samples.at(i));
00178 time *= fRefine;
00179
00180
00181 fFitter->Clear();
00182 HistogramFitFCN* fcn = (HistogramFitFCN*)fFitter->GetMinuitFCN();
00183 fcn->SetH1(fTemplate);
00184 fcn->SetH2(rebinned_pulse);
00185 fFitter->SetParameter(0, "Pedestal", ped, 0.1, 0, 0);
00186 fFitter->SetParameter(1, "Amplitude", amp, 0.1, 0, 0);
00187 fFitter->SetParameter(2, "Time", time, 1., 0, 0);
00188
00189
00190
00191
00192
00193 fFitter->CreateMinimizer();
00194
00195
00196 int status = fFitter->Minimize();
00197 if (status != 0)
00198 std::cout << "ERROR: Problem with fit (" << status << ")!" << std::endl;
00199
00200
00201 ped = fFitter->GetParameter(0);
00202 amp = fFitter->GetParameter(1);
00203 time = fFitter->GetParameter(2) / (double)fRefine;
00204 fcn = (HistogramFitFCN*)fFitter->GetMinuitFCN();
00205 std::vector<double> params;
00206 params.push_back(ped);
00207 params.push_back(amp);
00208 params.push_back(time);
00209
00210 return (*fcn)(params);
00211 }
00212
00213 bool PulseTemplate::Converged() {
00214 return (fConvergence <= fConvergenceLimit && fNPulses >= 2);
00215 }
00216
00217 void PulseTemplate::Save(TFile* ofile) {
00218 TDirectory* cwd = gDirectory;
00219 if (ofile == NULL || !ofile->IsOpen()) {
00220 std::cout << "ERROR: Cannot save template to file (file NULL or not open)!" << std::endl;
00221 return;
00222 }
00223 ofile->cd();
00224 fTemplate->Write();
00225 cwd->cd();
00226 }
00227
00228 void PulseTemplate::Print() {
00229 std::cout << "Pulse Template Info:"
00230 << "\t" << "NP" << "\t" << "NS"
00231 << "\t" << "Ref" << "\t" << "NB"
00232 << "\t" << "T" << "\t" << "SX"
00233 << "\t" << "SX2" << "\t" << "S2X"
00234 << "\t" << "Conv" << "\t" << "ConLim"
00235 << std::endl;
00236 std::cout << " "
00237 << "\t" << fNPulses << "\t" << fNSigma
00238 << "\t" << fRefine << "\t" << fNBins
00239 << "\t" << fClockTick << "\t" << fSumX
00240 << "\t" << fSumX2 << "\t" << fSum2X
00241 << "\t" << fConvergence << "\t" << fConvergenceLimit
00242 << std::endl;
00243 }
00244
00245 int PulseTemplate::GetNumberOfPulses() {
00246 return fNPulses;
00247 }