diff --git a/CALIBRATION/hms_cal_calib/THcShHit.h b/CALIBRATION/hms_cal_calib/THcShHit.h
new file mode 100644
index 0000000000000000000000000000000000000000..20afcced1f71e1fe0c234c87a60eff0db32298c5
--- /dev/null
+++ b/CALIBRATION/hms_cal_calib/THcShHit.h
@@ -0,0 +1,72 @@
+#include <iostream>
+
+// HMS calorimeter hit class for calibration.
+
+class THcShHit {
+
+  Double_t ADCpos, ADCneg;   // pedestal subtracted ADC signals.
+  Double_t Epos, Eneg;       // Energy depositions seen from pos. & neg. sides
+  UInt_t BlkNumber;
+
+ public:
+
+  THcShHit();
+  THcShHit(Double_t adc_pos, Double_t adc_neg,
+	   UInt_t blk_number);
+  ~THcShHit();
+
+  void SetADCpos(Double_t sig) {ADCpos = sig;}
+
+  void SetADCneg(Double_t sig) {ADCneg = sig;}
+
+  void SetEpos(Double_t e) {Epos = e;}
+
+  void SetEneg(Double_t e) {Eneg = e;}
+
+  void SetBlkNumber(UInt_t n) {BlkNumber = n;}
+
+  Double_t GetADCpos() {return ADCpos;}
+
+  Double_t GetADCneg() {return ADCneg;}
+
+  Double_t GetEpos() {return Epos;}
+
+  Double_t GetEneg() {return Eneg;}
+  
+  UInt_t GetBlkNumber() {return BlkNumber;}
+
+  void Print(ostream & ostrm);
+};
+
+//------------------------------------------------------------------------------
+
+THcShHit::THcShHit() {
+  ADCpos = -99999.;
+  ADCneg = -99999.;
+  Epos = -99999.;
+  Eneg = -99999.;
+  BlkNumber = 99999;
+};
+
+THcShHit::THcShHit(Double_t adc_pos, Double_t adc_neg,
+		   UInt_t blk_number) {
+  ADCpos = adc_pos;
+  ADCneg = adc_neg;
+  Epos = 0.;
+  Eneg = 0.;
+  BlkNumber = blk_number;
+};
+
+THcShHit::~THcShHit() { };
+
+//------------------------------------------------------------------------------
+
+void THcShHit::Print(ostream & ostrm) {
+
+  // Output hit data through the stream ostrm.
+
+  ostrm << ADCpos << " " << ADCneg << " " << Epos << " " << Eneg << " "
+	<< BlkNumber << endl;
+};
+
+struct pmt_hit {Double_t signal; UInt_t channel;};
diff --git a/CALIBRATION/hms_cal_calib/THcShTrack.h b/CALIBRATION/hms_cal_calib/THcShTrack.h
new file mode 100644
index 0000000000000000000000000000000000000000..ffd11b71c393acabca51c05003dc4ad87b7c18c6
--- /dev/null
+++ b/CALIBRATION/hms_cal_calib/THcShTrack.h
@@ -0,0 +1,230 @@
+#include "THcShHit.h"
+#include "TMath.h"
+
+#include <vector>
+#include <iterator>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+
+// Track class for the HMS calorimeter calibration.
+// Comprises the spectrometer track parameters and calorimeter hits.
+//
+
+// Container (collection) of hits and its iterator.
+//
+typedef vector<THcShHit*> THcShHitList;
+typedef THcShHitList::iterator THcShHitIt;
+
+class THcShTrack {
+
+  Double_t P;   // track momentum
+  Double_t Dp;  // track momentum deviation, %
+  Double_t X;   // at the calorimater face
+  Double_t Xp;  // slope
+  Double_t Y;   // at the calorimater face
+  Double_t Yp;  // slope
+
+  THcShHitList Hits;
+
+ public:
+  THcShTrack();
+  THcShTrack(Double_t p, Double_t dp,
+	     Double_t x, Double_t xp, Double_t y, Double_t yp);
+  ~THcShTrack();
+
+  void Reset(Double_t p, Double_t dp,
+	     Double_t x, Double_t xp, Double_t y, Double_t yp);
+
+  void AddHit(Double_t adc_pos, Double_t adc_neg,
+	      Double_t e_pos, Double_t e_neg,
+	      UInt_t blk_number);
+
+  THcShHit* GetHit(UInt_t k);
+
+  UInt_t GetNhits() {return Hits.size();};
+
+  void Print(ostream & ostrm);
+
+  void SetEs(Double_t* alpha);
+
+  Double_t Enorm();
+
+  Double_t GetP() {return P*1000.;}      //MeV
+
+  Double_t GetDp() {return Dp;}
+
+  Double_t GetX() {return X;}
+  Double_t GetY() {return Y;}
+
+  Float_t Ycor(Double_t);         // coord. corection for single PMT module
+  Float_t Ycor(Double_t, Int_t);  // coord. correction for double PMT module
+
+  // Coordinate correction constants from hcana.param.
+  //
+  ////  static const Double_t fAcor = 200.;
+  ////  static const Double_t fBcor = 8000.;
+  ////  static const Double_t fCcor = 64.36;
+  ////  static const Double_t fDcor = 1.66;
+  static constexpr Double_t fAcor = 200.;
+  static constexpr Double_t fBcor = 8000.;
+  static constexpr Double_t fCcor = 64.36;
+  static constexpr Double_t fDcor = 1.66;
+
+  // Calorimeter geometry constants.
+  //
+  ////  static const Double_t fZbl = 10;   //cm, block transverse size
+  ////  static const UInt_t fNrows = 13;
+  ////  static const UInt_t fNcols =  4;
+  ////static const UInt_t fNnegs = 26;  // number of blocks with neg. side PMTs.
+  ////  static const UInt_t fNpmts = 78;   // total number of PMTs.
+  ////  static const UInt_t fNblks = fNrows*fNcols;
+  static constexpr Double_t fZbl = 10;   //cm, block transverse size
+  static constexpr UInt_t fNrows = 13;
+  static constexpr UInt_t fNcols =  4;
+  static constexpr UInt_t fNnegs = 26;  // number of blocks with neg. side PMTs.
+  static constexpr UInt_t fNpmts = 78;  // total number of PMTs.
+  static constexpr UInt_t fNblks = fNrows*fNcols;
+
+};
+
+//------------------------------------------------------------------------------
+
+THcShTrack::THcShTrack() { };
+
+THcShTrack::THcShTrack(Double_t p, Double_t dp,
+		       Double_t x, Double_t xp, Double_t y, Double_t yp) {
+  P = p;
+  Dp = dp;
+  X = x;
+  Xp = xp;
+  Y = y;
+  Yp =yp;
+};
+
+//------------------------------------------------------------------------------
+
+void THcShTrack::Reset(Double_t p, Double_t dp,
+		       Double_t x, Double_t xp, Double_t y, Double_t yp) {
+
+  // Reset track parameters, clear hit list.
+
+  P = p;
+  Dp = dp;
+  X = x;
+  Xp = xp;
+  Y = y;
+  Yp =yp;
+  Hits.clear();
+};
+
+//------------------------------------------------------------------------------
+
+void THcShTrack::AddHit(Double_t adc_pos, Double_t adc_neg,
+			Double_t e_pos, Double_t e_neg,
+			UInt_t blk_number) {
+
+  // Add a hit to the hit list.
+
+  THcShHit* hit = new THcShHit(adc_pos, adc_neg, blk_number);
+  hit->SetEpos(e_pos);
+  hit->SetEneg(e_neg);
+  Hits.push_back(hit);
+};
+
+//------------------------------------------------------------------------------
+
+THcShHit* THcShTrack::GetHit(UInt_t k) {
+  THcShHitIt it = Hits.begin();
+  for (UInt_t i=0; i<k; i++) it++;
+  return *it;
+}
+
+void THcShTrack::Print(ostream & ostrm) {
+
+  // Output the track parameters and hit list through the stream ostrm.
+
+  ostrm << P << " " << Dp << " " << X << " " << Xp << " " << Y << " " << Yp
+	<< " " << Hits.size() << endl;
+
+  for (THcShHitIt iter = Hits.begin(); iter != Hits.end(); iter++) {
+    (*iter)->Print(ostrm);
+  };
+
+};
+
+//------------------------------------------------------------------------------
+
+THcShTrack::~THcShTrack() {
+  for (THcShHitIt i = Hits.begin(); i != Hits.end(); ++i) {
+    delete *i;
+    *i = 0;
+  }
+};
+
+//------------------------------------------------------------------------------
+
+void THcShTrack::SetEs(Double_t* alpha) {
+
+  // Set hit energy depositions seen from postive and negative sides,
+  // by use of calibration (gain) constants alpha.
+  
+  for (THcShHitIt iter = Hits.begin(); iter != Hits.end(); iter++) {
+  
+    Double_t adc_pos = (*iter)->GetADCpos();
+    Double_t adc_neg = (*iter)->GetADCneg();
+    UInt_t nblk = (*iter)->GetBlkNumber();
+
+    Int_t ncol=(nblk-1)/fNrows+1;
+    Double_t xh=X+Xp*(ncol-0.5)*fZbl;
+    Double_t yh=Y+Yp*(ncol-0.5)*fZbl;
+    if (nblk <= fNnegs) {
+      (*iter)->SetEpos(adc_pos*Ycor(yh,0)*alpha[nblk-1]);
+      (*iter)->SetEneg(adc_neg*Ycor(yh,1)*alpha[fNblks+nblk-1]);
+    }
+    else {
+      (*iter)->SetEpos(adc_pos*Ycor(yh)*alpha[nblk-1]);
+      (*iter)->SetEneg(0.);
+    };
+
+  };
+
+}
+
+//------------------------------------------------------------------------------
+
+Double_t THcShTrack::Enorm() {
+
+  // Normalized to the track momentum energy depostion in the calorimeter.
+
+  Double_t sum = 0;
+
+  for (THcShHitIt iter = Hits.begin(); iter != Hits.end(); iter++) {
+    sum += (*iter)->GetEpos();
+    sum += (*iter)->GetEneg();
+  };
+
+  return sum/P/1000.;
+}
+
+//------------------------------------------------------------------------------
+
+//Coordinate correction for single PMT modules.
+//PMT attached at right (positive) side.
+
+Float_t THcShTrack::Ycor(Double_t y) {
+  return TMath::Exp(y/fAcor)/(1. + y*y/fBcor);
+}
+
+//Coordinate correction for double PMT modules.
+//
+
+Float_t THcShTrack::Ycor(Double_t y, Int_t side) {
+  if (side!=0&&side!=1) {
+    cout << "THcShower::Ycor : wrong side " << side << endl;
+    return 0.;
+  }
+  Int_t sign = 1 - 2*side;
+  return (fCcor + sign*y)/(fCcor + sign*y/fDcor);
+}
diff --git a/CALIBRATION/hms_cal_calib/THcShowerCalib.h b/CALIBRATION/hms_cal_calib/THcShowerCalib.h
new file mode 100644
index 0000000000000000000000000000000000000000..654f0c493e24a4e59b85fa1866ab3e054ca9c316
--- /dev/null
+++ b/CALIBRATION/hms_cal_calib/THcShowerCalib.h
@@ -0,0 +1,756 @@
+#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"
+
+#define D_CALO_FP 338.69    //distance from FP to the calorimeter face
+
+//Whole calorimeter
+#define XMIN -65.4
+#define XMAX  54.6
+#define YMIN -30.
+#define YMAX  30.
+
+#define DELTA_MIN -10   //HMS nominal acceptance
+#define DELTA_MAX  10
+
+#define PR_ADC_THR 0
+#define SH_ADC_THR 0
+
+#define BETA_MIN 0.5
+#define BETA_MAX 1.5
+
+using namespace std;
+
+//
+// HMS Shower Counter calibration class.
+//
+
+class THcShowerCalib {
+
+ public:
+  ////  THcShowerCalib(Int_t);
+  THcShowerCalib(string);
+  THcShowerCalib();
+  ~THcShowerCalib();
+
+  void Init();
+  bool 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;
+
+ private:
+  ////  Int_t fRunNumber;
+  string 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 = 100;   // 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) {
+THcShowerCalib::THcShowerCalib(string 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++) {
+
+    if (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);
+  char* fname = Form("ROOTfiles/hms_replay_%s.root",fRunNumber.c_str());
+  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.;
+    }
+  };
+
+  // Unit gains.
+
+  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.
+
+  Int_t nev = 0;
+  THcShTrack trk;
+
+  for (UInt_t ientry=0; ientry<fNentries; ientry++) {
+
+    if (ReadShRawTrack(trk, ientry)) {
+
+      //    trk.Print(cout);
+      //    getchar();
+
+      trk.SetEs(falpha0);             //Use initial gain constants here.
+      Double_t Enorm = trk.Enorm();
+
+      hEunc->Fill(Enorm);    
+
+      nev++;
+      //    cout << "CalcThreshods: nev=" << nev << "  Enorm=" << Enorm << endl;
+    }
+
+  };
+
+  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.);
+
+};
+
+//------------------------------------------------------------------------------
+
+bool THcShowerCalib::ReadShRawTrack(THcShTrack &trk, UInt_t ientry) {
+
+  //
+  // Set a Shower track event from ntuple ientry.
+  //
+
+  // 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          H_tr_n;
+  Double_t        H_tr_p;
+  Double_t        H_tr_x;   //X FP
+  Double_t        H_tr_xp;
+  Double_t        H_tr_y;   //Y FP
+  Double_t        H_tr_yp;
+
+  Double_t        H_tr_tg_dp;
+
+  Double_t        H_cer_npe[2];
+  Double_t        H_tr_beta;
+ 
+  // 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.tr.n", &H_tr_n);
+  fTree->SetBranchAddress("H.tr.x",&H_tr_x);
+  fTree->SetBranchAddress("H.tr.y",&H_tr_y);
+  fTree->SetBranchAddress("H.tr.th",&H_tr_xp);
+  fTree->SetBranchAddress("H.tr.ph",&H_tr_yp);
+  fTree->SetBranchAddress("H.tr.p",&H_tr_p);
+
+  fTree->SetBranchAddress("H.tr.tg_dp", &H_tr_tg_dp);
+ 
+  fTree->SetBranchAddress("H.cer.npe", H_cer_npe);
+  fTree->SetBranchAddress("H.tr.beta", &H_tr_beta);
+
+  fTree->GetEntry(ientry);
+
+  if (ientry%100000 == 0) cout << "   ReadShRawTrack: " << ientry << endl;
+
+  if (H_tr_n != 1) return 0;
+
+  bool good_trk =   H_tr_tg_dp > DELTA_MIN &&
+		    H_tr_tg_dp < DELTA_MAX &&
+		    H_tr_x + H_tr_xp*D_CALO_FP > XMIN &&
+		    H_tr_x + H_tr_xp*D_CALO_FP < XMAX &&
+                    H_tr_y + H_tr_yp*D_CALO_FP > YMIN &&
+		    H_tr_y + H_tr_yp*D_CALO_FP < YMAX ;
+  if (!good_trk) return 0;
+
+  bool good_cer = H_cer_npe[0] > 0.125 ||
+                  H_cer_npe[1] > 0.125 ;
+  if(!good_cer) return 0;
+
+  bool good_beta = H_tr_beta > BETA_MIN &&
+                   H_tr_beta < BETA_MAX ;
+  if(!good_beta) return 0;
+
+  trk.Reset(H_tr_p, H_tr_tg_dp, H_tr_x+D_CALO_FP*H_tr_xp, H_tr_xp,
+	    H_tr_y+D_CALO_FP*H_tr_yp, H_tr_yp);
+
+  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);
+      }
+
+    }
+  }
+
+  return 1;
+}
+
+//------------------------------------------------------------------------------
+
+void THcShowerCalib::ComposeVMs() {
+
+  //
+  // Fill in vectors and matrixes for the gain constant calculations.
+  //
+
+  fNev = 0;
+  THcShTrack trk;
+
+  // Loop over the shower track events in the ntuples.
+
+  for (UInt_t ientry=0; ientry<fNentries; ientry++) {
+
+    if (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
+
+    };   // success in reading
+
+  };     // over entries
+
+  // Take averages.
+
+  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.deb",ios::out);
+  for (UInt_t i=0; i<THcShTrack::fNpmts; i++)
+    q0out << fq0[i] << " " << i << endl;
+  q0out.close();
+
+  ofstream qeout;
+  qeout.open("qe.deb",ios::out);
+  for (UInt_t i=0; i<THcShTrack::fNpmts; i++)
+    qeout << fqe[i] << " " << i << endl;
+  qeout.close();
+
+  ofstream Qout;
+  Qout.open("Q.deb",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.
+  //  cout << "t1 =" << t1 << endl;
+
+  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
+  //  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 deviation versus normalized energy deposition.
+  //
+
+  ofstream output;
+  output.open("calibrated.deb",ios::out);
+
+  Int_t nev = 0;
+
+  THcShTrack trk;
+
+  for (UInt_t ientry=0; ientry<fNentries; ientry++) {
+
+    if (ReadShRawTrack(trk, ientry)) {
+      //    trk.Print(cout);
+
+      trk.SetEs(falphaC);        // use the 'constrained' calibration constants
+      Double_t P = trk.GetP();
+      Double_t delta = trk.GetDp();
+      Double_t Enorm = trk.Enorm();
+
+      hEcal->Fill(Enorm);
+
+      ////      Double_t delta;
+      ////      fTree->SetBranchAddress("H.tr.tg_dp",&delta);
+      hDPvsEcal->Fill(Enorm,delta,1.);
+
+      //      hESHvsEPR->Fill(trk.EPRnorm(), trk.ESHnorm());
+
+      output << Enorm*P/1000. << " " << P/1000. << " " << delta << " "
+      	     << trk.GetX() << " " << trk.GetY() << 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);
+  char* fname = Form("hcal.param.%s",fRunNumber.c_str());
+  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
diff --git a/CALIBRATION/hms_cal_calib/hcal_calib.cpp b/CALIBRATION/hms_cal_calib/hcal_calib.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b07474614024c1bd1ac5d737fd2705c3782f5dfd
--- /dev/null
+++ b/CALIBRATION/hms_cal_calib/hcal_calib.cpp
@@ -0,0 +1,61 @@
+#include "TCanvas.h"
+#include <TStyle.h>
+#include <TH1.h>
+#include <TF1.h>
+#include "THcShowerCalib.h"
+
+//
+// A steering Root script for the HMS calorimeter calibration.
+//
+
+void hcal_calib(string RunNumber) {
+
+  // Initialize the analysis clock
+  clock_t t = clock();
+  
+ cout << "Calibrating run " << RunNumber << endl;
+
+ THcShowerCalib theShowerCalib(RunNumber);
+
+ theShowerCalib.Init();            // Initialize constants and variables
+ theShowerCalib.CalcThresholds();  // Thresholds on the uncalibrated Edep/P
+ theShowerCalib.ComposeVMs();      // Compute vectors amd matrices for calib.
+ theShowerCalib.SolveAlphas();     // Solve for the calibration constants
+ theShowerCalib.SaveAlphas();      // Save the constants
+ // theShowerCalib.SaveRawData();  // Save raw data into file for debug purposes
+ theShowerCalib.FillHEcal();       // Fill histograms
+
+ // Plot histograms
+
+ TCanvas* Canvas =
+   new TCanvas("Canvas", "HMS Shower Counter calibration", 1000, 667);
+ Canvas->Divide(2,2);
+
+ Canvas->cd(1);
+
+ // Normalized uncalibrated energy deposition.
+
+ theShowerCalib.hEunc->DrawCopy();
+  
+ theShowerCalib.hEuncSel->SetFillColor(kGreen);
+ theShowerCalib.hEuncSel->DrawCopy("same");
+
+ // Normalized energy deposition after calibration.
+
+ Canvas->cd(3);
+ gStyle->SetOptFit();
+
+ theShowerCalib.hEcal->Fit("gaus","","",0.95,1.05);
+ theShowerCalib.hEcal->GetFunction("gaus")->SetLineColor(2);
+ theShowerCalib.hEcal->GetFunction("gaus")->SetLineWidth(1);
+ theShowerCalib.hEcal->GetFunction("gaus")->SetLineStyle(1);
+
+ // HMS delta(P) versus the calibrated energy deposition.
+
+ Canvas->cd(4);
+ theShowerCalib.hDPvsEcal->Draw();
+
+ // Calculate the analysis rate
+ t = clock() - t;
+ printf ("The analysis took %.1f seconds \n", ((float) t) / CLOCKS_PER_SEC);
+}