Skip to content
Snippets Groups Projects
THcShowerCalib.h 21.2 KiB
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 ExtractData();
  void Init();
  void ReadShRawTrack(THcShTrack &trk, UInt_t ientry);
  void CalcThresholds();
  void ComposeVMs();
  void SolveAlphas();
  void FillHEcal();
  void SaveAlphas();

  TH1F* hEunc;
  TH1F* hEuncSel;
  TH1F* hEcal;
  //  TH2F* hPvsEcal;
  TH2F* hDPvsEcal;

 private:
  Int_t fRunNumber;
  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::ExtractData() {

  // Extract data for calibration from the Root file.
  // Loop over ntuples to get track parameters and calorimeter
  // hit quantities.

  char* fname = Form("Root_files/hcal_calib_%d.root",fRunNumber);
  cout << "THcShowerCalib::ExtractData: fname= " << fname << endl;

  //Reset ROOT and connect tree file
  gROOT->Reset();
  //  TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(fname);
  TFile *f = new TFile(fname);
  //  if (!f) {
  //    f = new TFile(fname);
  //  }
  TTree* tree;
  f->GetObject("T",tree);

  //Declaration of leaves types

  // 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];

  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.

  tree->SetBranchAddress("H.cal.1pr.aneg_p",H_cal_1pr_aneg_p);
  tree->SetBranchAddress("H.cal.1pr.apos_p",H_cal_1pr_apos_p);

  tree->SetBranchAddress("H.cal.2ta.aneg_p",H_cal_2ta_aneg_p);
  tree->SetBranchAddress("H.cal.2ta.apos_p",H_cal_2ta_apos_p);

  tree->SetBranchAddress("H.cal.3ta.aneg_p",H_cal_3ta_aneg_p);
  tree->SetBranchAddress("H.cal.3ta.apos_p",H_cal_3ta_apos_p);

  tree->SetBranchAddress("H.cal.4ta.aneg_p",H_cal_4ta_aneg_p);
  tree->SetBranchAddress("H.cal.4ta.apos_p",H_cal_4ta_apos_p);

  tree->SetBranchAddress("H.cal.trp",&H_cal_trp);
  tree->SetBranchAddress("H.cal.trx",&H_cal_trx);
  tree->SetBranchAddress("H.cal.trxp",&H_cal_trxp);
  tree->SetBranchAddress("H.cal.try",&H_cal_try);
  tree->SetBranchAddress("H.cal.tryp",&H_cal_tryp);

  Long64_t nentries = tree->GetEntries();
  cout << "THcShowerCalib::ExtractData: nentries= " << nentries << endl;

  // Output stream.

  char* FName = Form("raw_data/%d_raw.dat",fRunNumber);
  cout << "ExtractData: FName=" << FName << endl;
  ofstream output;
  output.open(FName,ios::out);

  // Loop over ntuples.

  Long64_t nbytes = 0;
  for (Long64_t i=0; i<nentries;i++) {
    nbytes += tree->GetEntry(i);
    Int_t nhit = 0;
    for (Int_t j=0; j<THcShTrack::fNrows; j++) {
      if (H_cal_1pr_apos_p[j]>0. || H_cal_1pr_aneg_p[j]>0.) nhit++;
      if (H_cal_2ta_apos_p[j]>0. || H_cal_2ta_aneg_p[j]>0.) nhit++;
      if (H_cal_3ta_apos_p[j]>0. || H_cal_3ta_aneg_p[j]>0.) nhit++;
      if (H_cal_4ta_apos_p[j]>0. || H_cal_4ta_aneg_p[j]>0.) nhit++;
    }
    output << nhit << " " << H_cal_trp << " " 
	   << H_cal_trx << " " << H_cal_trxp << " " 
	   << H_cal_try << " " << H_cal_tryp << endl;
    for (Int_t j=0; j<THcShTrack::fNrows; j++) {
      if (H_cal_1pr_apos_p[j]>0. || H_cal_1pr_aneg_p[j]>0.)
	output << H_cal_1pr_apos_p[j] << " " << H_cal_1pr_aneg_p[j] << " "
	       << j+1 << endl;
    }
    for (Int_t j=0; j<THcShTrack::fNrows; j++) {
      if (H_cal_2ta_apos_p[j]>0. || H_cal_2ta_aneg_p[j]>0.)
	output << H_cal_2ta_apos_p[j] << " " << H_cal_2ta_aneg_p[j] << " "
	       << j+1 + THcShTrack::fNrows << endl;
    }
    for (Int_t j=0; j<THcShTrack::fNrows; j++) {
      if (H_cal_3ta_apos_p[j]>0. || H_cal_3ta_aneg_p[j]>0.)
	output << H_cal_3ta_apos_p[j] << " " << H_cal_3ta_aneg_p[j] << " "
	       << j+1 + 2*THcShTrack::fNrows << endl;
    }
    for (Int_t j=0; j<THcShTrack::fNrows; j++) {
      if (H_cal_4ta_apos_p[j]>0. || H_cal_4ta_aneg_p[j]>0.)
	output << H_cal_4ta_apos_p[j] << " " << H_cal_4ta_aneg_p[j] << " "
	       << j+1 + 3*THcShTrack::fNrows << endl;
    }

  }   // over entries

  output.close();
  cout << "THcShowerCalib::ExtractData: nbytes= " << nbytes << endl;
}

//------------------------------------------------------------------------------

void THcShowerCalib::Init() {

  // Open the raw data file.

  //  char* FName = Form("raw_data/%d_raw.dat",fRunNumber);
  //  cout << "Init: FName=" << FName << endl;
  //  //  fDataStream.open(FName,ios::in);

  //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);
  //  hPvsEcal = new TH2F("hPvsEcal", "P versus Edep/P ",150,0.,1.5, 100,0.7,0.9);
  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.;
  }

  //  for (UInt_t ipmt=0; ipmt<THcShRawTrack::fNpmts; ipmt++) {
  //    cout << "falpha0 " << ipmt << " = " << falpha0[ipmt] << endl;
  //  }

};

//------------------------------------------------------------------------------

void THcShowerCalib::CalcThresholds() {

  // Calculate +/-3 sigma thresholds on the uncalibrated total energy
  // depositions. These thresholds are used mainly to exclude potential
  // hadronic events due to the gas Cherenkov inefficiency.

  Int_t nev = 0;
  THcShTrack trk;

  //  while (ReadShRawTrack(trk)) {
  for (UInt_t ientry=0; ientry<fNentries; ientry++) {

    ReadShRawTrack(trk, ientry);

    //    trk.Print();

    trk.SetEs(falpha0);
    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 the raw data.

  //Declaration of leaves types

  // 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);
  trk.Reset(H_cal_trp, H_cal_trx, H_cal_trxp, H_cal_try, H_cal_tryp);
  //  UInt_t nhit = 0;

  for (UInt_t j=0; j<THcShTrack::fNrows; j++) {
    for (UInt_t k=0; k<THcShTrack::fNcols; k++) {

      Double_t adc_pos, adc_neg;

      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);
	//	nhit++;
      }
  }

}

//------------------------------------------------------------------------------

void THcShowerCalib::ComposeVMs() {

  //
  // Fill in vectors and matrixes for the gain constant calculations.
  //

  // Reset the raw data stream.

  //  fDataStream.clear() ;
  //  fDataStream.seekg(0, ios::beg) ;

  fNev = 0;
  THcShTrack trk;

  // Loop over the shower track events in the raw data stream.

  //  while (ReadShRawTrack(trk)) {
  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();
      fe0 += trk.GetP();    // Accumulate track momenta.
      vector<pmt_hit> pmt_hit_list;     // Container to save PMT hits
      for (UInt_t i=0; i<trk.GetNhits(); i++) {
	THcShHit* hit = trk.GetHit(i);
	// hit->Print();
	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();
	pmt_hit_list.push_back( pmt_hit{hit->GetEpos(), nb} );
	fHitCount[nb-1]++;   //Accrue the hit counter.
	// Do the 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]++;
	};
      // 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 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.

  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 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;

  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;

  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 equal 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 swelf-correalation 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.
  //  cout << "t1 =" << t1 << endl;

  TVectorD Qiq0(THcShTrack::fNpmts);   // intermittend result
  Qiq0 = lu.Solve(q0,ok);
  cout << "Qiq0: ok=" << ok << endl;
  //  Qiq0.Print();

  Double_t t2 = q0 * Qiq0;             // another tempoary variable
  //  cout << "t2 =" << t2 << endl;

  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 versus normalized energy deposition.
  //

  // Reset.
  //  fDataStream.clear() ;
  //  fDataStream.seekg(0, ios::beg) ;

  ofstream output;
  output.open("calibrated.d",ios::out);

  Int_t nev = 0;

  THcShTrack trk;

  //  while (ReadShRawTrack(trk)) {
  for (UInt_t ientry=0; ientry<fNentries; ientry++) {
    ReadShRawTrack(trk, ientry);
    //    trk.Print();

    trk.SetEs(falphaC);          // use 'constrained' calibration constants
    //    trk.SetEs(falphaU);
    Double_t P = trk.GetP();
    Double_t Enorm = trk.Enorm();

    hEcal->Fill(Enorm);

    Double_t delta;
    fTree->SetBranchAddress("H.cal.trdelta",&delta);
    //    hPvsEcal->Fill(Enorm,P/1000.,1.);
    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.
  //

  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