Newer
Older
#ifndef ROOT_THcShowerCalib
#define ROOT_THcShowerCalib
#include "THcShTrack.h"
#include "TH1F.h"
#include "TH2F.h"
#include "TVectorD.h"
#include "TMatrixD.h"
#include "TDecompLU.h"
#include "TMath.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#include "TROOT.h"
#include "TFile.h"
#include "TTree.h"
using namespace std;
//
// HMS Shower Counter calibration class.
//
class THcShowerCalib {
public:
THcShowerCalib(Int_t);
THcShowerCalib();
~THcShowerCalib();
void Init();
void ReadShRawTrack(THcShTrack &trk, UInt_t ientry);
void CalcThresholds();
void ComposeVMs();
void SolveAlphas();
void FillHEcal();
void SaveAlphas();
void SaveRawData();
TH1F* hEunc;
TH1F* hEuncSel;
TH1F* hEcal;
TH2F* hDPvsEcal;
Double_t fLoThr; // Low and high thresholds on the normalized uncalibrated
Double_t fHiThr; // energy deposition.
UInt_t fNev; // Number of processed events.
static const UInt_t fMinHitCount = 200; // Minimum number of hits for a PMT
// to be calibrated.
TTree* fTree;
UInt_t fNentries;
// Quantities for calculations of the calibration constants.
Double_t fe0;
Double_t fqe[THcShTrack::fNpmts];
Double_t fq0[THcShTrack::fNpmts];
Double_t fQ[THcShTrack::fNpmts][THcShTrack::fNpmts];
Double_t falphaU[THcShTrack::fNpmts]; // 'unconstrained' calib. constants
Double_t falphaC[THcShTrack::fNpmts]; // the sought calibration constants
Double_t falpha0[THcShTrack::fNpmts]; // initial gains
Double_t falpha1[THcShTrack::fNpmts]; // unit gains
UInt_t fHitCount[THcShTrack::fNpmts];
};
//------------------------------------------------------------------------------
THcShowerCalib::THcShowerCalib() {};
//------------------------------------------------------------------------------
THcShowerCalib::THcShowerCalib(Int_t RunNumber) {
fRunNumber = RunNumber;
};
//------------------------------------------------------------------------------
THcShowerCalib::~THcShowerCalib() {
};
//------------------------------------------------------------------------------
void THcShowerCalib::SaveRawData() {
// Output raw data into file for debug purposes. To be called after
// calibration constants are determined.
cout << "SaveRawData: Output raw data into hcal_calib.raw_data." << endl;
ofstream fout;
fout.open("hcal_calib.raw_data",ios::out);
THcShTrack trk;
for (UInt_t ientry=0; ientry<fNentries; ientry++) {
ReadShRawTrack(trk, ientry);
trk.SetEs(falphaC);
trk.Print(fout);
}
fout.close();
}
//------------------------------------------------------------------------------
void THcShowerCalib::Init() {
//Reset ROOT and connect tree file.
gROOT->Reset();
char* fname = Form("Root_files/hcal_calib_%d.root",fRunNumber);
cout << "THcShowerCalib::Init: Root file name = " << fname << endl;
TFile *f = new TFile(fname);
f->GetObject("T",fTree);
fNentries = fTree->GetEntries();
cout << "THcShowerCalib::Init: fNentries= " << fNentries << endl;
// Histogram declarations.
hEunc = new TH1F("hEunc", "Edep/P uncalibrated", 500, 0., 5.);
hEcal = new TH1F("hEcal", "Edep/P calibrated", 150, 0., 1.5);
hDPvsEcal = new TH2F("hDPvsEcal", "#DeltaP versus Edep/P ",
150,0.,1.5, 250,-12.5,12.5);
// Initialize qumulative quantities.
for (UInt_t i=0; i<THcShTrack::fNpmts; i++) fHitCount[i] = 0;
fe0 = 0.;
for (UInt_t i=0; i<THcShTrack::fNpmts; i++) {
fqe[i] = 0.;
fq0[i] = 0.;
falphaU[i] = 0.;
falphaC[i] = 0.;
for (UInt_t j=0; j<THcShTrack::fNpmts; j++) {
fQ[i][j] = 0.;
}
}
// Initial gains (0.5 for the 2 first columns, 1 for others).
for (UInt_t iblk=0; iblk<THcShTrack::fNblks; iblk++) {
if (iblk < THcShTrack::fNnegs) {
falpha0[iblk] = 0.5;
falpha0[THcShTrack::fNblks+iblk] = 0.5;
}
else {
falpha0[iblk] = 1.;
}
};
for (UInt_t ipmt=0; ipmt<THcShTrack::fNpmts; ipmt++) {
falpha1[ipmt] = 1.;
}
};
//------------------------------------------------------------------------------
void THcShowerCalib::CalcThresholds() {
// Calculate +/-3 RMS thresholds on the uncalibrated total energy
// depositions. These thresholds are used mainly to exclude potential
// hadronic events due to the gas Cherenkov inefficiency.
// Histogram uncalibrated energy depositions, get mean and RMS from the
// histogram, establish +/-3 * RMS thresholds.
for (UInt_t ientry=0; ientry<fNentries; ientry++) {
ReadShRawTrack(trk, ientry);
// trk.Print(cout);
// getchar();
trk.SetEs(falpha0); //Use initial gain constants here.
Double_t Enorm = trk.Enorm();
nev++;
// cout << "CalcThreshods: nev=" << nev << " Enorm=" << Enorm << endl;
hEunc->Fill(Enorm);
};
Double_t mean = hEunc->GetMean();
Double_t rms = hEunc->GetRMS();
cout << "CalcThreshods: mean=" << mean << " rms=" << rms << endl;
fLoThr = mean - 3.*rms;
fHiThr = mean + 3.*rms;
cout << "CalcThreshods: fLoThr=" << fLoThr << " fHiThr=" << fHiThr
<< " nev=" << nev << endl;
Int_t nbins = hEunc->GetNbinsX();
Int_t nlo = hEunc->FindBin(fLoThr);
Int_t nhi = hEunc->FindBin(fHiThr);
cout << "CalcThresholds: nlo=" << nlo << " nhi=" << nhi
<< " nbins=" << nbins << endl;
// Histogram selected wthin the thresholds events.
hEuncSel = (TH1F*)hEunc->Clone("hEuncSel");
for (Int_t i=0; i<nlo; i++) hEuncSel->SetBinContent(i, 0.);
for (Int_t i=nhi; i<nbins+1; i++) hEuncSel->SetBinContent(i, 0.);
};
//------------------------------------------------------------------------------
void THcShowerCalib::ReadShRawTrack(THcShTrack &trk, UInt_t ientry) {
//
// Set a Shower track event from ntuple ientry.
//
// Declaration of leaves types
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// Calorimeter ADC signals.
Double_t H_cal_1pr_aneg_p[THcShTrack::fNrows];
Double_t H_cal_1pr_apos_p[THcShTrack::fNrows];
Double_t H_cal_2ta_aneg_p[THcShTrack::fNrows];
Double_t H_cal_2ta_apos_p[THcShTrack::fNrows];
Double_t H_cal_3ta_aneg_p[THcShTrack::fNrows];
Double_t H_cal_3ta_apos_p[THcShTrack::fNrows];
Double_t H_cal_4ta_aneg_p[THcShTrack::fNrows];
Double_t H_cal_4ta_apos_p[THcShTrack::fNrows];
// Track parameters.
Double_t H_cal_trp;
Double_t H_cal_trx;
Double_t H_cal_trxp;
Double_t H_cal_try;
Double_t H_cal_tryp;
// Set branch addresses.
fTree->SetBranchAddress("H.cal.1pr.aneg_p",H_cal_1pr_aneg_p);
fTree->SetBranchAddress("H.cal.1pr.apos_p",H_cal_1pr_apos_p);
fTree->SetBranchAddress("H.cal.2ta.aneg_p",H_cal_2ta_aneg_p);
fTree->SetBranchAddress("H.cal.2ta.apos_p",H_cal_2ta_apos_p);
fTree->SetBranchAddress("H.cal.3ta.aneg_p",H_cal_3ta_aneg_p);
fTree->SetBranchAddress("H.cal.3ta.apos_p",H_cal_3ta_apos_p);
fTree->SetBranchAddress("H.cal.4ta.aneg_p",H_cal_4ta_aneg_p);
fTree->SetBranchAddress("H.cal.4ta.apos_p",H_cal_4ta_apos_p);
fTree->SetBranchAddress("H.cal.trp",&H_cal_trp);
fTree->SetBranchAddress("H.cal.trx",&H_cal_trx);
fTree->SetBranchAddress("H.cal.trxp",&H_cal_trxp);
fTree->SetBranchAddress("H.cal.try",&H_cal_try);
fTree->SetBranchAddress("H.cal.tryp",&H_cal_tryp);
fTree->GetEntry(ientry);
trk.Reset(H_cal_trp, H_cal_trx, H_cal_trxp, H_cal_try, H_cal_tryp);
for (UInt_t j=0; j<THcShTrack::fNrows; j++) {
for (UInt_t k=0; k<THcShTrack::fNcols; k++) {
switch (k) {
case 0 :
adc_pos = H_cal_1pr_apos_p[j];
adc_neg = H_cal_1pr_aneg_p[j];
break;
case 1 :
adc_pos = H_cal_2ta_apos_p[j];
adc_neg = H_cal_2ta_aneg_p[j];
break;
case 2 :
adc_pos = H_cal_3ta_apos_p[j];
adc_neg = H_cal_3ta_aneg_p[j];
break;
case 3 :
adc_pos = H_cal_4ta_apos_p[j];
adc_neg = H_cal_4ta_aneg_p[j];
break;
default:
cout << "*** ReadShRawTrack: column number k=" << k
<< " out of range! ***" << endl;
};
UInt_t nb = j+1 + k*THcShTrack::fNrows;
if (adc_pos>0. || adc_neg>0.) {
trk.AddHit(adc_pos, adc_neg, 0., 0., nb);
}
}
}
//------------------------------------------------------------------------------
void THcShowerCalib::ComposeVMs() {
//
// Fill in vectors and matrixes for the gain constant calculations.
//
// Loop over the shower track events in the ntuples.
for (UInt_t ientry=0; ientry<fNentries; ientry++) {
ReadShRawTrack(trk, ientry);
// Set energy depositions with default gains.
// Calculate normalized to the track momentum total energy deposition,
// check it against the thresholds.
trk.SetEs(falpha0);
Double_t Enorm = trk.Enorm();
if (Enorm>fLoThr && Enorm<fHiThr) {
trk.SetEs(falpha1); // Set energies with unit gains for now.
// trk.Print(cout);
fe0 += trk.GetP(); // Accumulate track momenta.
vector<pmt_hit> pmt_hit_list; // Container to save PMT hits
// Loop over hits.
for (UInt_t i=0; i<trk.GetNhits(); i++) {
THcShHit* hit = trk.GetHit(i);
// hit->Print(cout);
UInt_t nb = hit->GetBlkNumber();
// Fill the qe and q0 vectors (for positive side PMT).
fqe[nb-1] += hit->GetEpos() * trk.GetP();
fq0[nb-1] += hit->GetEpos();
// Save the PMT hit.
pmt_hit_list.push_back( pmt_hit{hit->GetEpos(), nb} );
fHitCount[nb-1]++; //Accrue the hit counter.
// Do same for the negative side PMTs.
if (nb <= THcShTrack::fNnegs) {
fqe[THcShTrack::fNblks+nb-1] += hit->GetEneg() * trk.GetP();
fq0[THcShTrack::fNblks+nb-1] += hit->GetEneg();
pmt_hit_list.push_back(pmt_hit{hit->GetEneg(),
THcShTrack::fNblks+nb} );
fHitCount[THcShTrack::fNblks+nb-1]++;
};
} //over hits
// Fill in the correlation matrix Q by retrieving the PMT hits.
for (vector<pmt_hit>::iterator i=pmt_hit_list.begin();
i < pmt_hit_list.end(); i++) {
UInt_t ic = (*i).channel;
Double_t is = (*i).signal;
for (vector<pmt_hit>::iterator j=i;
j < pmt_hit_list.end(); j++) {
UInt_t jc = (*j).channel;
Double_t js = (*j).signal;
fQ[ic-1][jc-1] += is*js;
if (jc != ic) fQ[jc-1][ic-1] += is*js;
fNev++;
}; // if within the thresholds
}; // over entries
fe0 /= fNev;
for (UInt_t i=0; i<THcShTrack::fNpmts; i++) {
fqe[i] /= fNev;
fq0[i] /= fNev;
}
for (UInt_t i=0; i<THcShTrack::fNpmts; i++)
for (UInt_t j=0; j<THcShTrack::fNpmts; j++)
fQ[i][j] /= fNev;
// Output vectors and matrixes, for debug purposes.
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
ofstream q0out;
q0out.open("q0.d",ios::out);
for (UInt_t i=0; i<THcShTrack::fNpmts; i++)
q0out << fq0[i] << " " << i << endl;
q0out.close();
ofstream qeout;
qeout.open("qe.d",ios::out);
for (UInt_t i=0; i<THcShTrack::fNpmts; i++)
qeout << fqe[i] << " " << i << endl;
qeout.close();
ofstream Qout;
Qout.open("Q.d",ios::out);
for (UInt_t i=0; i<THcShTrack::fNpmts; i++)
for (UInt_t j=0; j<THcShTrack::fNpmts; j++)
Qout << fQ[i][j] << " " << i << " " << j << endl;
Qout.close();
};
//------------------------------------------------------------------------------
void THcShowerCalib::SolveAlphas() {
// Solve for the sought calibration constants, by use of the Root
// matrix algebra package.
//
TMatrixD Q(THcShTrack::fNpmts,THcShTrack::fNpmts);
TVectorD q0(THcShTrack::fNpmts);
TVectorD qe(THcShTrack::fNpmts);
TVectorD au(THcShTrack::fNpmts);
TVectorD ac(THcShTrack::fNpmts);
Bool_t ok;
cout << "Solving Alphas..." << endl;
cout << endl;
// Print out hit numbers.
cout << "Hit counts:" << endl;
UInt_t j = 0;
cout << "Positives:";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
cout << setw(6) << fHitCount[j++] << ",";
cout << endl;
for (Int_t k=0; k<3; k++) {
cout << " ";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
cout << setw(6) << fHitCount[j++] << ",";
cout << endl;
}
cout << "Negatives:";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
cout << setw(6) << fHitCount[j++] << ",";
cout << endl;
cout << " ";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
cout << setw(6) << fHitCount[j++] << ",";
cout << endl;
// Initialize the vectors and the matrix of the Root algebra package.
for (UInt_t i=0; i<THcShTrack::fNpmts; i++) {
q0[i] = fq0[i];
qe[i] = fqe[i];
for (UInt_t k=0; k<THcShTrack::fNpmts; k++) {
Q[i][k] = fQ[i][k];
}
}
// Sanity check.
for (UInt_t i=0; i<THcShTrack::fNpmts; i++) {
// Check zero hit channels: the vector and matrix elements should be 0.
if (fHitCount[i] == 0) {
if (q0[i] != 0. || qe[i] != 0.) {
cout << "*** Inconsistency in chanel " << i << ": # of hits "
<< fHitCount[i] << ", q0=" << q0[i] << ", qe=" << qe[i];
for (UInt_t k=0; k<THcShTrack::fNpmts; k++) {
if (Q[i][k] !=0. || Q[k][i] !=0.)
cout << ", Q[" << i << "," << k << "]=" << Q[i][k]
<< ", Q[" << k << "," << i << "]=" << Q[k][i];
}
cout << " ***" << endl;
}
}
// The hit channels: the vector elements should be non zero.
if ( (fHitCount[i] != 0) && (q0[i] == 0. || qe[i] == 0.) ) {
cout << "*** Inconsistency in chanel " << i << ": # of hits "
<< fHitCount[i] << ", q0=" << q0[i] << ", qe=" << qe[i]
<< " ***" << endl;
}
} //sanity check
// Low hit number channels: exclude from calculation. Assign all the
// correspondent elements 0, except self-correlation Q(i,i)=1.
cout << endl;
cout << "Channels with hit number less than " << fMinHitCount
<< " will not be calibrated." << endl;
cout << endl;
for (UInt_t i=0; i<THcShTrack::fNpmts; i++) {
if (fHitCount[i] < fMinHitCount) {
cout << "Channel " << i << ", " << fHitCount[i]
<< " hits, will not be calibrated." << endl;
q0[i] = 0.;
qe[i] = 0.;
for (UInt_t k=0; k<THcShTrack::fNpmts; k++) {
Q[i][k] = 0.;
Q[k][i] = 0.;
}
Q[i][i] = 1.;
}
}
// Declare LU decomposition method for the correlation matrix Q.
TDecompLU lu(Q);
Double_t d1,d2;
lu.Det(d1,d2);
cout << "cond:" << lu.Condition() << endl;
cout << "det :" << d1*TMath::Power(2.,d2) << endl;
cout << "tol :" << lu.GetTol() << endl;
// Solve equation Q x au = qe for the 'unconstrained' calibration (gain)
// constants au.
au = lu.Solve(qe,ok);
cout << "au: ok=" << ok << endl;
// au.Print();
// Find the sought 'constrained' calibration constants next.
Double_t t1 = fe0 - au * q0; // temporary variable.
TVectorD Qiq0(THcShTrack::fNpmts); // an intermittent result
Qiq0 = lu.Solve(q0,ok);
cout << "Qiq0: ok=" << ok << endl;
// Qiq0.Print();
Double_t t2 = q0 * Qiq0; // another temporary variable
ac = (t1/t2) *Qiq0 + au; // the sought gain constants
// cout << "ac:" << endl;
// ac.Print();
// Assign the gain arrays.
for (UInt_t i=0; i<THcShTrack::fNpmts; i++) {
falphaU[i] = au[i];
falphaC[i] = ac[i];
}
}
//------------------------------------------------------------------------------
void THcShowerCalib::FillHEcal() {
//
// Fill histogram of the normalized energy deposition, 2-d histogram
// of momentum deviation versus normalized energy deposition.
ofstream output;
output.open("calibrated.d",ios::out);
Int_t nev = 0;
THcShTrack trk;
for (UInt_t ientry=0; ientry<fNentries; ientry++) {
ReadShRawTrack(trk, ientry);
// trk.Print(cout);
trk.SetEs(falphaC); // use the 'constrained' calibration constants
Double_t P = trk.GetP();
Double_t Enorm = trk.Enorm();
hEcal->Fill(Enorm);
Double_t delta;
fTree->SetBranchAddress("H.cal.trdelta",&delta);
hDPvsEcal->Fill(Enorm,delta,1.);
output << Enorm*P/1000. << " " << P/1000. << endl;
nev++;
};
output.close();
cout << "FillHEcal: " << nev << " events filled" << endl;
};
//------------------------------------------------------------------------------
void THcShowerCalib::SaveAlphas() {
//
// Output the gain constants in a format suitable for inclusion in the
// hcal.param file to be used in the analysis.
//
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
ofstream output;
char* fname = Form("hcal.param.%d",fRunNumber);
cout << "SaveAlphas: fname=" << fname << endl;
output.open(fname,ios::out);
output << "; Calibration constants for run " << fRunNumber
<< ", " << fNev << " events processed" << endl;
output << endl;
UInt_t j = 0;
output << "hcal_pos_gain_cor=";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
output << fixed << setw(6) << setprecision(3) << falphaC[j++] << ",";
output << endl;
for (Int_t k=0; k<3; k++) {
output << " ";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
output << fixed << setw(6) << setprecision(3) << falphaC[j++] << ",";
output << endl;
}
output << "hcal_neg_gain_cor=";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
output << fixed << setw(6) << setprecision(3) << falphaC[j++] << ",";
output << endl;
output << " ";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
output << fixed << setw(6) << setprecision(3) << falphaC[j++] << ",";
output << endl;
for (Int_t k=0; k<2; k++) {
output << " ";
for (UInt_t i=0; i<THcShTrack::fNrows; i++)
output << fixed << setw(6) << setprecision(3) << 0. << ",";
output << endl;
}
output.close();
}
#endif