int
Proto2ShowerCalib::Init(PHCompositeNode *topNode)
{

  _ievent = 0;

  cout << "Proto2ShowerCalib::get_HistoManager - Making PHTFileServer "
      << _filename << endl;
  PHTFileServer::get().open(_filename, "RECREATE");

  fdata.open(_filename + ".dat", std::fstream::out);

  Fun4AllHistoManager *hm = get_HistoManager();
  assert(hm);

  TH2F * hCheck_Cherenkov = new TH2F("hCheck_Cherenkov", "hCheck_Cherenkov",
      1000, -2000, 2000, 5, .5, 5.5);
  hCheck_Cherenkov->GetYaxis()->SetBinLabel(1, "C1");
  hCheck_Cherenkov->GetYaxis()->SetBinLabel(2, "C2 in");
  hCheck_Cherenkov->GetYaxis()->SetBinLabel(3, "C2 out");
  hCheck_Cherenkov->GetYaxis()->SetBinLabel(4, "C2 sum");
  hm->registerHisto(hCheck_Cherenkov);

  TH1F * hNormalization = new TH1F("hNormalization", "hNormalization", 10, .5,
      10.5);
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(1, "ALL");
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(2, "C2-e");
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(3, "C2-h");
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(4, "trigger_veto_pass");
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(5, "valid_hodo_h");
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(6, "valid_hodo_v");
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(7, "good_e");
  hCheck_Cherenkov->GetXaxis()->SetBinLabel(8, "good_h");
  hm->registerHisto(hNormalization);

  hm->registerHisto(new TH1F("hCheck_Veto", "hCheck_Veto", 1000, -500, 500));
  hm->registerHisto(
      new TH1F("hCheck_Hodo_H", "hCheck_Hodo_H", 1000, -500, 500));
  hm->registerHisto(
      new TH1F("hCheck_Hodo_V", "hCheck_Hodo_V", 1000, -500, 500));

  hm->registerHisto(new TH1F("hBeam_Mom", "hBeam_Mom", 1200, -120, 120));

  hm->registerHisto(new TH2F("hEoP", "hEoP", 1000, 0, 1.5, 120, .5, 120.5));

  hm->registerHisto(new TH1F("hTemperature", "hTemperature", 500, 0, 50));

  // help index files with TChain
  TTree * T = new TTree("T", "T");
  assert(T);
  hm->registerHisto(T);

  T->Branch("info", &_eval_run);
  T->Branch("shower", &_shower);
  if(_fill_time_samples) T->Branch("time", &_time_samples);  

  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::Init_G4Hit(PHCompositeNode *topNode)
{

  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);

  hm->registerHisto(
      new TH2F(TString(get_histo_prefix()) + "_G4Hit_RZ", //
      TString(_calo_name) + " RZ projection;Z (cm);R (cm)", 1200, -300, 300,
          600, -000, 300));

  hm->registerHisto(
      new TH2F(TString(get_histo_prefix()) + "_G4Hit_XY", //
      TString(_calo_name) + " XY projection;X (cm);Y (cm)", 1200, -300, 300,
          1200, -300, 300));

  hm->registerHisto(
      new TH2F(TString(get_histo_prefix()) + "_G4Hit_LateralTruthProjection", //
          TString(_calo_name)
              + " shower lateral projection (last primary);Polar direction (cm);Azimuthal direction (cm)",
          200, -30, 30, 200, -30, 30));

  hm->registerHisto(new TH1F(TString(get_histo_prefix()) + "_G4Hit_SF", //
  TString(_calo_name) + " sampling fraction;Sampling fraction", 1000, 0, .2));

  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_G4Hit_VSF", //
          TString(_calo_name)
              + " visible sampling fraction;Visible sampling fraction", 1000, 0,
          .2));

  TH1F * h =
      new TH1F(TString(get_histo_prefix()) + "_G4Hit_HitTime", //
          TString(_calo_name)
              + " hit time (edep weighting);Hit time - T0 (ns);Geant4 energy density",
          1000, 0.5, 10000);
  QAHistManagerDef::useLogBins(h->GetXaxis());
  hm->registerHisto(h);

  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_G4Hit_FractionTruthEnergy", //
          TString(_calo_name)
              + " fraction truth energy ;G4 energy (active + absorber) / total truth energy",
          1000, 0, 1));

  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_G4Hit_FractionEMVisibleEnergy", //
          TString(_calo_name)
              + " fraction visible energy from EM; visible energy from e^{#pm} / total visible energy",
          100, 0, 1));

  return Fun4AllReturnCodes::EVENT_OK;
}
int
Proto2ShowerCalib::End(PHCompositeNode *topNode)
{
  cout << "Proto2ShowerCalib::End - write to " << _filename << endl;
  PHTFileServer::get().cd(_filename);

  Fun4AllHistoManager *hm = get_HistoManager();
  assert(hm);
  for (unsigned int i = 0; i < hm->nHistos(); i++)
    hm->getHisto(i)->Write();

//  if (_T_EMCalTrk)
//    _T_EMCalTrk->Write();

  fdata.close();

  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::process_event(PHCompositeNode *topNode)
{

  if (verbosity > 2)
    cout << "QAG4SimulationCalorimeter::process_event() entered" << endl;

  if (_caloevalstack)
    _caloevalstack->next_event(topNode);

  if (flag(kProcessG4Hit))
    {
      int ret = process_event_G4Hit(topNode);

      if (ret != Fun4AllReturnCodes::EVENT_OK)
        return ret;
    }

  if (flag(kProcessTower))
    {
      int ret = process_event_Tower(topNode);

      if (ret != Fun4AllReturnCodes::EVENT_OK)
        return ret;
    }

  if (flag(kProcessCluster))
    {
      int ret = process_event_Cluster(topNode);

      if (ret != Fun4AllReturnCodes::EVENT_OK)
        return ret;
    }

  // at the end, count success events
  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);
  TH1D* h_norm = dynamic_cast<TH1D*>(hm->getHisto(
      get_histo_prefix() + "_Normalization"));
  assert(h_norm);
  h_norm->Fill("Event", 1);

  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::Init(PHCompositeNode *topNode)
{

  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);
  TH1D * h = new TH1D(TString(get_histo_prefix()) + "_Normalization", //
  TString(_calo_name) + " Normalization;Items;Count", 10, .5, 10.5);
  int i = 1;
  h->GetXaxis()->SetBinLabel(i++, "Event");
  h->GetXaxis()->SetBinLabel(i++, "G4Hit Active");
  h->GetXaxis()->SetBinLabel(i++, "G4Hit Absor.");
  h->GetXaxis()->SetBinLabel(i++, "Tower");
  h->GetXaxis()->SetBinLabel(i++, "Tower Hit");
  h->GetXaxis()->SetBinLabel(i++, "Cluster");
  h->GetXaxis()->LabelsOption("v");
  hm->registerHisto(h);

  if (flag(kProcessG4Hit))
    {

      if (verbosity >= 1)
        cout << "QAG4SimulationCalorimeter::Init - Process sampling fraction"
            << endl;
      Init_G4Hit(topNode);
    }
  if (flag(kProcessTower))
    {
      if (verbosity >= 1)
        cout << "QAG4SimulationCalorimeter::Init - Process tower occupancies"
            << endl;
      Init_Tower(topNode);
    }
  if (flag(kProcessCluster))
    {
      if (verbosity >= 1)
        cout << "QAG4SimulationCalorimeter::Init - Process tower occupancies"
            << endl;
      Init_Cluster(topNode);
    }

  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::Init_Cluster(PHCompositeNode *topNode)
{

  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);

  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_Cluster_BestMatchERatio", //
          TString(_calo_name)
              + " best matched cluster E/E_{Truth};E_{Cluster}/E_{Truth}", 150,
          0, 1.5));

  hm->registerHisto(
      new TH2F(TString(get_histo_prefix()) + "_Cluster_LateralTruthProjection", //
          TString(_calo_name)
              + " best cluster lateral projection (last primary);Polar direction (cm);Azimuthal direction (cm)",
          200, -15, 15, 200, -15, 15));

  return Fun4AllReturnCodes::EVENT_OK;
}
int
Proto2ShowerCalib::process_event(PHCompositeNode *topNode)
{

  if (verbosity > 2)
    cout << "Proto2ShowerCalib::process_event() entered" << endl;

  // init eval objects
  _eval_run.reset();
  _shower.reset();

  Fun4AllHistoManager *hm = get_HistoManager();
  assert(hm);

  PdbParameterMap *info = findNode::getClass<PdbParameterMap>(topNode,
      "RUN_INFO");

  //if(!_is_sim) assert(info);
 
  if(info)
  {
   PHParameters run_info_copy("RunInfo");
   run_info_copy.FillFrom(info);

   _eval_run.beam_mom = run_info_copy.get_double_param("beam_MTNRG_GeV");

   TH1F * hBeam_Mom = dynamic_cast<TH1F *>(hm->getHisto("hBeam_Mom"));
   assert(hBeam_Mom);

   hBeam_Mom->Fill(_eval_run.beam_mom);
  }

  EventHeader* eventheader = findNode::getClass<EventHeader>(topNode,
      "EventHeader");
  //if(!_is_sim) assert(eventheader);

  if( eventheader )
  {
   _eval_run.run = eventheader->get_RunNumber();
   if (verbosity > 4)
    cout << __PRETTY_FUNCTION__ << _eval_run.run << endl;

   _eval_run.event = eventheader->get_EvtSequence();
  }
  // normalization
  TH1F * hNormalization = dynamic_cast<TH1F *>(hm->getHisto("hNormalization"));
  assert(hNormalization);

  hNormalization->Fill("ALL", 1);

  // other nodes
  RawTowerContainer* TOWER_CALIB_TRIGGER_VETO = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_CALIB_TRIGGER_VETO");
  //if(!_is_sim) assert(TOWER_CALIB_TRIGGER_VETO);

  RawTowerContainer* TOWER_CALIB_HODO_HORIZONTAL = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_CALIB_HODO_HORIZONTAL");
  //if(!_is_sim) assert(TOWER_CALIB_HODO_HORIZONTAL);

  RawTowerContainer* TOWER_CALIB_HODO_VERTICAL = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_CALIB_HODO_VERTICAL");
  //if(!_is_sim) assert(TOWER_CALIB_HODO_VERTICAL);

 RawTowerContainer* TOWER_RAW_CEMC;
  if(!_is_sim) 
  {
   TOWER_RAW_CEMC = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_RAW_CEMC");
  }else{
   TOWER_RAW_CEMC = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_RAW_LG_CEMC");
 }
  assert(TOWER_RAW_CEMC);

 RawTowerContainer* TOWER_CALIB_CEMC;
 if(!_is_sim)
 {
  TOWER_CALIB_CEMC = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_CEMC");
 } else {
  TOWER_CALIB_CEMC = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_LG_CEMC");
 }
  assert(TOWER_CALIB_CEMC);

  RawTowerContainer* TOWER_RAW_LG_HCALIN = 0;
  RawTowerContainer* TOWER_RAW_HG_HCALIN = 0;
  if(!_is_sim)
  {
   TOWER_RAW_LG_HCALIN = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_RAW_LG_HCALIN");
   TOWER_RAW_HG_HCALIN= findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_RAW_HG_HCALIN");
   assert(TOWER_RAW_LG_HCALIN);
   assert(TOWER_RAW_HG_HCALIN);
  }

  RawTowerContainer* TOWER_CALIB_HCALIN;
  if(!_is_sim)
  {
   TOWER_CALIB_HCALIN = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_LG_HCALIN");
  } else {
   TOWER_CALIB_HCALIN = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_LG_HCALIN");
  }
  assert(TOWER_CALIB_HCALIN);

  RawTowerContainer* TOWER_RAW_LG_HCALOUT = 0;
  RawTowerContainer* TOWER_RAW_HG_HCALOUT = 0;
  if(!_is_sim)
  {
   TOWER_RAW_LG_HCALOUT = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_RAW_LG_HCALOUT");
   TOWER_RAW_HG_HCALOUT = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_RAW_HG_HCALOUT");
   assert(TOWER_RAW_LG_HCALOUT);
   assert(TOWER_RAW_HG_HCALOUT);
  }

  RawTowerContainer* TOWER_CALIB_HCALOUT = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_LG_HCALOUT");
  assert(TOWER_CALIB_HCALOUT);

  RawTowerContainer* TOWER_TEMPERATURE_EMCAL = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_TEMPERATURE_EMCAL");
  if(!_is_sim) assert(TOWER_TEMPERATURE_EMCAL);

  RawTowerContainer* TOWER_CALIB_C1 = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_C1");
  //if(!_is_sim) assert(TOWER_CALIB_C1);
  RawTowerContainer* TOWER_CALIB_C2 = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_C2");
  //if(!_is_sim) assert(TOWER_CALIB_C2);

  if(!_is_sim && TOWER_CALIB_C2 && TOWER_CALIB_C1 && eventheader)
  {
  // Cherenkov
  RawTower * t_c2_in = NULL;
  RawTower * t_c2_out = NULL;

  if (eventheader->get_RunNumber() >= 2105)
    {
      t_c2_in = TOWER_CALIB_C2->getTower(10);
      t_c2_out = TOWER_CALIB_C2->getTower(11);
    }
  else
    {
      t_c2_in = TOWER_CALIB_C2->getTower(0);
      t_c2_out = TOWER_CALIB_C2->getTower(1);
    }
  assert(t_c2_in);
  assert(t_c2_out);

  const double c2_in = t_c2_in->get_energy();
  const double c2_out = t_c2_out->get_energy();
  const double c1 = TOWER_CALIB_C1->getTower(0)->get_energy();

  _eval_run.C2_sum = c2_in + c2_out;
  _eval_run.C1 = c1;
  bool cherekov_e = (_eval_run.C2_sum) > 100;
  hNormalization->Fill("C2-e", cherekov_e);

  bool cherekov_h = (_eval_run.C2_sum) < 20;
  hNormalization->Fill("C2-h", cherekov_h);

  TH2F * hCheck_Cherenkov = dynamic_cast<TH2F *>(hm->getHisto(
      "hCheck_Cherenkov"));
  assert(hCheck_Cherenkov);
  hCheck_Cherenkov->Fill(c1, "C1", 1);
  hCheck_Cherenkov->Fill(c2_in, "C2 in", 1);
  hCheck_Cherenkov->Fill(c2_out, "C2 out", 1);
  hCheck_Cherenkov->Fill(c2_in + c2_out, "C2 sum", 1);

  // veto
  TH1F * hCheck_Veto = dynamic_cast<TH1F *>(hm->getHisto("hCheck_Veto"));
  assert(hCheck_Veto);
  bool trigger_veto_pass = true;
    {
      auto range = TOWER_CALIB_TRIGGER_VETO->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);

          hCheck_Veto->Fill(tower->get_energy());

          if (abs(tower->get_energy()) > 15)
            trigger_veto_pass = false;
        }
    }
  hNormalization->Fill("trigger_veto_pass", trigger_veto_pass);
  _eval_run.trigger_veto_pass = trigger_veto_pass;

  // hodoscope
  TH1F * hCheck_Hodo_H = dynamic_cast<TH1F *>(hm->getHisto("hCheck_Hodo_H"));
  assert(hCheck_Hodo_H);
  int hodo_h_count = 0;
    {
      auto range = TOWER_CALIB_HODO_HORIZONTAL->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);
          hCheck_Hodo_H->Fill(tower->get_energy());

          if (abs(tower->get_energy()) > 30)
            {
              hodo_h_count++;
              _eval_run.hodo_h = tower->get_id();
            }
        }
    }

  const bool valid_hodo_h = hodo_h_count == 1;
  hNormalization->Fill("valid_hodo_h", valid_hodo_h);
  _eval_run.valid_hodo_h = valid_hodo_h;

  TH1F * hCheck_Hodo_V = dynamic_cast<TH1F *>(hm->getHisto("hCheck_Hodo_V"));
  assert(hCheck_Hodo_V);
  int hodo_v_count = 0;
   {
      auto range = TOWER_CALIB_HODO_VERTICAL->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);

          hCheck_Hodo_V->Fill(tower->get_energy());

          if (abs(tower->get_energy()) > 30)
            {
              hodo_v_count++;
              _eval_run.hodo_v = tower->get_id();
            }
        }
    }
  const bool valid_hodo_v = hodo_v_count == 1;
  _eval_run.valid_hodo_v = valid_hodo_v;
  hNormalization->Fill("valid_hodo_v", valid_hodo_v);

  const bool good_e = valid_hodo_v and valid_hodo_h and cherekov_e and trigger_veto_pass;

  const bool good_h = valid_hodo_v and valid_hodo_h and cherekov_h and trigger_veto_pass;

  hNormalization->Fill("good_e", good_e);
  hNormalization->Fill("good_h", good_h);

  _eval_run.good_temp = 1;
  _eval_run.good_e = good_e;
  _eval_run.good_h = good_h;

  }
  // tower
  double emcal_sum_energy_calib = 0;
  double emcal_sum_energy_recalib = 0;

  double hcalin_sum_energy_calib = 0;
  double hcalin_sum_energy_recalib = 0;

  double hcalout_sum_energy_calib = 0;
  double hcalout_sum_energy_recalib = 0;

  stringstream sdata;

   //EMCAL towers
    {
      auto range = TOWER_CALIB_CEMC->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {

          //RawTowerDefs::keytype key = it->first;
          RawTower* tower = it->second;
          assert(tower);

          const double energy_calib = tower->get_energy();
          emcal_sum_energy_calib += energy_calib;
           
          if(_is_sim) continue;
          const int col = tower->get_column();
          const int row = tower->get_row();

          // recalibration
          assert(
              _emcal_recalib_const.find(make_pair(col, row)) != _emcal_recalib_const.end());
          const double energy_recalib = energy_calib
              * _emcal_recalib_const[make_pair(col, row)];

          // energy sums
          emcal_sum_energy_recalib += energy_recalib;
         }
      }

  //HCALIN towers
  {
      auto range = TOWER_CALIB_HCALIN->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);

          const double energy_calib = tower->get_energy();
          hcalin_sum_energy_calib += energy_calib;

          if(_is_sim) continue;
          const int col = tower->get_column();
          const int row = tower->get_row();

          assert(
              _hcalin_recalib_const.find(make_pair(col, row)) != _hcalin_recalib_const.end());
          const double energy_recalib = energy_calib
              * _hcalin_recalib_const[make_pair(col, row)];

          hcalin_sum_energy_recalib += energy_recalib;
         }
     }
  
   //HCALOUT towers
   {
      auto range = TOWER_CALIB_HCALOUT->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);

          const double energy_calib = tower->get_energy();
          hcalout_sum_energy_calib += energy_calib;
           
          if(_is_sim) continue;
          const int col = tower->get_column();
          const int row = tower->get_row();

          assert(
              _hcalout_recalib_const.find(make_pair(col, row)) != _hcalout_recalib_const.end());
          const double energy_recalib = energy_calib
              * _hcalout_recalib_const[make_pair(col, row)];
               
              hcalout_sum_energy_recalib += energy_recalib;
         }
     }

  const double EoP = emcal_sum_energy_recalib / abs(_eval_run.beam_mom);
  _eval_run.EoP = EoP;

  // E/p
  if (_eval_run.good_e)
    {
      if (verbosity >= 3)
        cout << __PRETTY_FUNCTION__ << " sum_energy_calib = "
            << emcal_sum_energy_calib << " sum_energy_recalib = " << emcal_sum_energy_recalib
            << " _eval_run.beam_mom = " << _eval_run.beam_mom << endl;

      TH2F * hEoP = dynamic_cast<TH2F *>(hm->getHisto("hEoP"));
      assert(hEoP);

      hEoP->Fill(EoP, abs(_eval_run.beam_mom));
    }

  // calibration file
   assert(fdata.is_open());
   fdata << sdata.str();
   fdata << endl;

  _shower.emcal_e = emcal_sum_energy_calib;
  _shower.hcalin_e = hcalin_sum_energy_calib;
  _shower.hcalout_e = hcalout_sum_energy_calib;
  _shower.sum_e = emcal_sum_energy_calib + hcalin_sum_energy_calib + hcalout_sum_energy_calib ;
  _shower.hcal_asym = (hcalin_sum_energy_calib - hcalout_sum_energy_calib)/(hcalin_sum_energy_calib + hcalout_sum_energy_calib);

  _shower.emcal_e_recal = emcal_sum_energy_recalib;
  _shower.hcalin_e_recal = hcalin_sum_energy_recalib;
  _shower.hcalout_e_recal = hcalout_sum_energy_recalib;
  _shower.sum_e_recal = emcal_sum_energy_recalib + hcalin_sum_energy_recalib + hcalout_sum_energy_recalib ;

  
  if(_fill_time_samples && !_is_sim)
  {
   //HCALIN
   {
    auto range = TOWER_RAW_LG_HCALIN->getTowers();
    for (auto it = range.first; it != range.second; ++it)
    {
      RawTower_Prototype2* tower = dynamic_cast<RawTower_Prototype2 *>(it->second);
      assert(tower);

      int col = tower->get_column();
      int row = tower->get_row();
      int towerid = row + 4*col;
      for(int isample=0; isample<24; isample++)
       _time_samples.hcalin_time_samples[towerid][isample] =
                tower->get_signal_samples(isample);

     }
    }

   //HCALOUT
   {
    auto range = TOWER_RAW_LG_HCALOUT->getTowers();
    for (auto it = range.first; it != range.second; ++it)
    {
      RawTower_Prototype2* tower = dynamic_cast<RawTower_Prototype2 *>(it->second);
      assert(tower);

      int col = tower->get_column();
      int row = tower->get_row();
      int towerid = row + 4*col;
      for(int isample=0; isample<24; isample++) 
       _time_samples.hcalout_time_samples[towerid][isample] = 
		tower->get_signal_samples(isample);

     }
    }

   //EMCAL
   {
    auto range = TOWER_RAW_CEMC->getTowers();
    for (auto it = range.first; it != range.second; ++it)
    {
      RawTower_Prototype2* tower = dynamic_cast<RawTower_Prototype2 *>(it->second);
      assert(tower);

      int col = tower->get_column();
      int row = tower->get_row();
      int towerid = row + 8*col;
      for(int isample=0; isample<24; isample++)
       _time_samples.emcal_time_samples[towerid][isample] =
                tower->get_signal_samples(isample);

     }
    }
  }

  TTree * T = dynamic_cast<TTree *>(hm->getHisto("T"));
  assert(T);
  T->Fill();

  return Fun4AllReturnCodes::EVENT_OK;
}
Пример #8
0
int
Proto2ShowerCalib::process_event(PHCompositeNode *topNode)
{

  if (verbosity > 2)
    cout << "Proto2ShowerCalib::process_event() entered" << endl;

  // init eval objects
  _eval_run.reset();
  _eval_3x3_raw.reset();
  _eval_5x5_raw.reset();
  _eval_3x3_prod.reset();
  _eval_5x5_prod.reset();
  _eval_3x3_temp.reset();
  _eval_5x5_temp.reset();
  _eval_3x3_recalib.reset();
  _eval_5x5_recalib.reset();

  Fun4AllHistoManager *hm = get_HistoManager();
  assert(hm);

  if (not _is_sim)
    {
      PdbParameterMap *info = findNode::getClass<PdbParameterMap>(topNode,
          "RUN_INFO");

      assert(info);

      PHG4Parameters run_info_copy("RunInfo");
      run_info_copy.FillFrom(info);

      _eval_run.beam_mom = run_info_copy.get_double_param("beam_MTNRG_GeV");

      TH1F * hBeam_Mom = dynamic_cast<TH1F *>(hm->getHisto("hBeam_Mom"));
      assert(hBeam_Mom);

      hBeam_Mom->Fill(_eval_run.beam_mom);
    }

  EventHeader* eventheader = findNode::getClass<EventHeader>(topNode,
      "EventHeader");
  if (not _is_sim)
    {
      assert(eventheader);

      _eval_run.run = eventheader->get_RunNumber();
      if (verbosity > 4)
        cout << __PRETTY_FUNCTION__ << _eval_run.run << endl;

      _eval_run.event = eventheader->get_EvtSequence();
    }

  if (_is_sim)
    {

      PHG4TruthInfoContainer* truthInfoList = findNode::getClass<
          PHG4TruthInfoContainer>(topNode, "G4TruthInfo");

      assert(truthInfoList);

      _eval_run.run = -1;

      const PHG4Particle * p = truthInfoList->GetPrimaryParticleRange().first->second;
      assert(p);

      const PHG4VtxPoint * v = truthInfoList->GetVtx(p->get_vtx_id());
      assert(v);

      _eval_run.beam_mom = sqrt(
          p->get_px() * p->get_px() + p->get_py() * p->get_py()
              + p->get_pz() * p->get_pz());
      _eval_run.truth_y = v->get_y();
      _eval_run.truth_z = v->get_z();

    }

  // normalization
  TH1F * hNormalization = dynamic_cast<TH1F *>(hm->getHisto("hNormalization"));
  assert(hNormalization);

  hNormalization->Fill("ALL", 1);

  RawTowerContainer* TOWER_RAW_CEMC = findNode::getClass<RawTowerContainer>(
      topNode, _is_sim ? "TOWER_RAW_LG_CEMC" : "TOWER_RAW_CEMC");
  assert(TOWER_RAW_CEMC);
  RawTowerContainer* TOWER_CALIB_CEMC = findNode::getClass<RawTowerContainer>(
      topNode, _is_sim ? "TOWER_CALIB_LG_CEMC" : "TOWER_CALIB_CEMC");
  assert(TOWER_CALIB_CEMC);

  // other nodes
  RawTowerContainer* TOWER_CALIB_TRIGGER_VETO = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_CALIB_TRIGGER_VETO");
  if (not _is_sim)
    {
      assert(TOWER_CALIB_TRIGGER_VETO);
    }

  RawTowerContainer* TOWER_CALIB_HODO_HORIZONTAL = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_CALIB_HODO_HORIZONTAL");
  if (not _is_sim)
    {
      assert(TOWER_CALIB_HODO_HORIZONTAL);
    }
  RawTowerContainer* TOWER_CALIB_HODO_VERTICAL = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_CALIB_HODO_VERTICAL");
  if (not _is_sim)
    {
      assert(TOWER_CALIB_HODO_VERTICAL);
    }

  RawTowerContainer* TOWER_TEMPERATURE_EMCAL = findNode::getClass<
      RawTowerContainer>(topNode, "TOWER_TEMPERATURE_EMCAL");
  if (not _is_sim)
    {
      assert(TOWER_TEMPERATURE_EMCAL);
    }

  RawTowerContainer* TOWER_CALIB_C1 = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_C1");
  if (not _is_sim)
    {
      assert(TOWER_CALIB_C1);
    }
  RawTowerContainer* TOWER_CALIB_C2 = findNode::getClass<RawTowerContainer>(
      topNode, "TOWER_CALIB_C2");
  if (not _is_sim)
    {
      assert(TOWER_CALIB_C2);
    }

  // Cherenkov
  bool cherekov_e = false;
  if (not _is_sim)
    {
      RawTower * t_c2_in = NULL;
      RawTower * t_c2_out = NULL;

      assert(eventheader);
      if (eventheader->get_RunNumber() >= 2105)
        {
          t_c2_in = TOWER_CALIB_C2->getTower(10);
          t_c2_out = TOWER_CALIB_C2->getTower(11);
        }
      else
        {
          t_c2_in = TOWER_CALIB_C2->getTower(0);
          t_c2_out = TOWER_CALIB_C2->getTower(1);
        }
      assert(t_c2_in);
      assert(t_c2_out);

      const double c2_in = t_c2_in->get_energy();
      const double c2_out = t_c2_out->get_energy();
      const double c1 = TOWER_CALIB_C1->getTower(0)->get_energy();

      _eval_run.C2_sum = c2_in + c2_out;
      cherekov_e = (_eval_run.C2_sum) > 100;
      hNormalization->Fill("C2-e", cherekov_e);

      TH2F * hCheck_Cherenkov = dynamic_cast<TH2F *>(hm->getHisto(
          "hCheck_Cherenkov"));
      assert(hCheck_Cherenkov);
      hCheck_Cherenkov->Fill(c1, "C1", 1);
      hCheck_Cherenkov->Fill(c2_in, "C2 in", 1);
      hCheck_Cherenkov->Fill(c2_out, "C2 out", 1);
      hCheck_Cherenkov->Fill(c2_in + c2_out, "C2 sum", 1);
    }

  // veto
  TH1F * hCheck_Veto = dynamic_cast<TH1F *>(hm->getHisto("hCheck_Veto"));
  assert(hCheck_Veto);
  bool trigger_veto_pass = true;
  if (not _is_sim)
    {
      auto range = TOWER_CALIB_TRIGGER_VETO->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);

          hCheck_Veto->Fill(tower->get_energy());

          if (abs(tower->get_energy()) > 15)
            trigger_veto_pass = false;
        }
    }
  hNormalization->Fill("trigger_veto_pass", trigger_veto_pass);
  _eval_run.trigger_veto_pass = trigger_veto_pass;

  // hodoscope
  TH1F * hCheck_Hodo_H = dynamic_cast<TH1F *>(hm->getHisto("hCheck_Hodo_H"));
  assert(hCheck_Hodo_H);
  int hodo_h_count = 0;
  if (not _is_sim)
    {
      auto range = TOWER_CALIB_HODO_HORIZONTAL->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);

          hCheck_Hodo_H->Fill(tower->get_energy());

          if (abs(tower->get_energy()) > 30)
            {
              hodo_h_count++;
              _eval_run.hodo_h = tower->get_id();
            }
        }
    }
  const bool valid_hodo_h = hodo_h_count == 1;
  hNormalization->Fill("valid_hodo_h", valid_hodo_h);
  _eval_run.valid_hodo_h = valid_hodo_h;

  TH1F * hCheck_Hodo_V = dynamic_cast<TH1F *>(hm->getHisto("hCheck_Hodo_V"));
  assert(hCheck_Hodo_V);
  int hodo_v_count = 0;
  if (not _is_sim)
    {
      auto range = TOWER_CALIB_HODO_VERTICAL->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {
          RawTower* tower = it->second;
          assert(tower);

          hCheck_Hodo_V->Fill(tower->get_energy());

          if (abs(tower->get_energy()) > 30)
            {
              hodo_v_count++;
              _eval_run.hodo_v = tower->get_id();
            }
        }
    }
  const bool valid_hodo_v = hodo_v_count == 1;
  _eval_run.valid_hodo_v = valid_hodo_v;
  hNormalization->Fill("valid_hodo_v", valid_hodo_v);

  const bool good_e = (valid_hodo_v and valid_hodo_h and cherekov_e
      and trigger_veto_pass) and (not _is_sim);
  hNormalization->Fill("good_e", good_e);

  // simple clustering
  pair<int, int> max_3x3 = find_max(TOWER_CALIB_CEMC, 3);
  pair<int, int> max_5x5 = find_max(TOWER_CALIB_CEMC, 5);

  _eval_3x3_raw.max_col = max_3x3.first;
  _eval_3x3_raw.max_row = max_3x3.second;
  _eval_3x3_prod.max_col = max_3x3.first;
  _eval_3x3_prod.max_row = max_3x3.second;
  _eval_3x3_temp.max_col = max_3x3.first;
  _eval_3x3_temp.max_row = max_3x3.second;
  _eval_3x3_recalib.max_col = max_3x3.first;
  _eval_3x3_recalib.max_row = max_3x3.second;

  _eval_5x5_raw.max_col = max_5x5.first;
  _eval_5x5_raw.max_row = max_5x5.second;
  _eval_5x5_prod.max_col = max_5x5.first;
  _eval_5x5_prod.max_row = max_5x5.second;
  _eval_5x5_temp.max_col = max_5x5.first;
  _eval_5x5_temp.max_row = max_5x5.second;
  _eval_5x5_recalib.max_col = max_5x5.first;
  _eval_5x5_recalib.max_row = max_5x5.second;

  // tower
  bool good_temp = true;
  double sum_energy_calib = 0;
  double sum_energy_T = 0;
  TH1F * hTemperature = dynamic_cast<TH1F *>(hm->getHisto("hTemperature"));
  assert(hTemperature);

  stringstream sdata;

  if (good_e)
    sdata << abs(_eval_run.beam_mom) << "\t";

  // tower temperature and recalibration
    {
      auto range = TOWER_CALIB_CEMC->getTowers();
      for (auto it = range.first; it != range.second; ++it)
        {

          RawTowerDefs::keytype key = it->first;
          RawTower* tower = it->second;
          assert(tower);

          const int col = tower->get_bineta();
          const int row = tower->get_binphi();

          if (col < 0 or col >= 8)
            continue;
          if (row < 0 or row >= 8)
            continue;

          const double energy_calib = tower->get_energy();
          sum_energy_calib += energy_calib;

          RawTower* tower_raw = TOWER_RAW_CEMC->getTower(key);
          assert(tower_raw);

          double energy_T = 0;
          if (not _is_sim)
            {
              RawTower_Temperature * temp_t =
                  dynamic_cast<RawTower_Temperature *>(TOWER_TEMPERATURE_EMCAL->getTower(
                      tower->get_row(), tower->get_column())); // note swap of col/row in temperature storage
              assert(temp_t);

              const double T = temp_t->get_temperature_from_time(
                  eventheader->get_TimeStamp());
              hTemperature->Fill(T);

              if (T < 25 or T > 35)
                good_temp = false;

              energy_T = TemperatureCorrection::Apply(energy_calib, T);
            }

          // recalibration
          assert(
              _recalib_const.find(make_pair(col, row)) != _recalib_const.end());
          const double energy_recalib = energy_T
              * _recalib_const[make_pair(col, row)];

          // energy sums
          sum_energy_T += energy_T;

          // calibration file
//          sdata << tower->get_energy() << "\t";
          // calibration file - only output 5x5 towers
          if (col >= max_5x5.first - 2 and col <= max_5x5.first + 2
              and row >= max_5x5.second - 2 and row <= max_5x5.second + 2)
            {
              sdata << tower->get_energy() << "\t";
            }
          else
            {
              sdata << 0 << "\t";
            }

          // cluster 3x3
          if (col >= max_3x3.first - 1 and col <= max_3x3.first + 1)
            if (row >= max_3x3.second - 1 and row <= max_3x3.second + 1)
              {
                // in cluster

                _eval_3x3_raw.average_col += abs(tower_raw->get_energy()) * col;
                _eval_3x3_raw.average_row += abs(tower_raw->get_energy()) * row;
                _eval_3x3_raw.sum_E += abs(tower_raw->get_energy());

                _eval_3x3_prod.average_col += energy_calib * col;
                _eval_3x3_prod.average_row += energy_calib * row;
                _eval_3x3_prod.sum_E += energy_calib;

                _eval_3x3_temp.average_col += energy_T * col;
                _eval_3x3_temp.average_row += energy_T * row;
                _eval_3x3_temp.sum_E += energy_T;

                _eval_3x3_recalib.average_col += energy_recalib * col;
                _eval_3x3_recalib.average_row += energy_recalib * row;
                _eval_3x3_recalib.sum_E += energy_recalib;
              }

          // cluster 5x5
          if (col >= max_5x5.first - 2 and col <= max_5x5.first + 2)
            if (row >= max_5x5.second - 2 and row <= max_5x5.second + 2)
              {
                // in cluster

                _eval_5x5_raw.average_col += abs(tower_raw->get_energy()) * col;
                _eval_5x5_raw.average_row += abs(tower_raw->get_energy()) * row;
                _eval_5x5_raw.sum_E += abs(tower_raw->get_energy());

                _eval_5x5_prod.average_col += energy_calib * col;
                _eval_5x5_prod.average_row += energy_calib * row;
                _eval_5x5_prod.sum_E += energy_calib;

                _eval_5x5_temp.average_col += energy_T * col;
                _eval_5x5_temp.average_row += energy_T * row;
                _eval_5x5_temp.sum_E += energy_T;

                _eval_5x5_recalib.average_col += energy_recalib * col;
                _eval_5x5_recalib.average_row += energy_recalib * row;
                _eval_5x5_recalib.sum_E += energy_recalib;
              }
        }
    }

  _eval_3x3_raw.reweight_clus_pol();
  _eval_5x5_raw.reweight_clus_pol();
  _eval_3x3_prod.reweight_clus_pol();
  _eval_5x5_prod.reweight_clus_pol();
  _eval_3x3_temp.reweight_clus_pol();
  _eval_5x5_temp.reweight_clus_pol();
  _eval_3x3_recalib.reweight_clus_pol();
  _eval_5x5_recalib.reweight_clus_pol();

  const double EoP = sum_energy_T / abs(_eval_run.beam_mom);
  hNormalization->Fill("good_temp", good_temp);

  bool good_data = good_e and good_temp;
  hNormalization->Fill("good_data", good_data);

  _eval_run.good_temp = good_temp;
  _eval_run.good_e = good_e;
  _eval_run.good_data = good_data;
  _eval_run.sum_energy_T = sum_energy_T;
  _eval_run.EoP = EoP;

  // E/p
  if (good_data)
    {
      if (verbosity >= 3)
        cout << __PRETTY_FUNCTION__ << " sum_energy_calib = "
            << sum_energy_calib << " sum_energy_T = " << sum_energy_T
            << " _eval_run.beam_mom = " << _eval_run.beam_mom << endl;

      TH2F * hEoP = dynamic_cast<TH2F *>(hm->getHisto("hEoP"));
      assert(hEoP);

      hEoP->Fill(EoP, abs(_eval_run.beam_mom));
    }

  // calibration file
  if (good_data and abs(_eval_run.beam_mom) >= 4
      and abs(_eval_run.beam_mom) <= 8)
    {
      assert(fdata.is_open());

      fdata << sdata.str();

      fdata << endl;
    }

  TTree * T = dynamic_cast<TTree *>(hm->getHisto("T"));
  assert(T);
  T->Fill();

  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::process_event_Cluster(PHCompositeNode *topNode)
{

  if (verbosity > 2)
    cout << "QAG4SimulationCalorimeter::process_event_Cluster() entered"
        << endl;

  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);
  string towergeomnodename = "TOWERGEOM_" + _calo_name;
  RawTowerGeomContainer *towergeom = findNode::getClass<RawTowerGeomContainer>(
      topNode, towergeomnodename.c_str());
  if (!towergeom)
    {
      cout << PHWHERE << ": Could not find node " << towergeomnodename.c_str()
          << endl;
      return Fun4AllReturnCodes::ABORTRUN;
    }

  //get a cluster count
  TH1D* h_norm = dynamic_cast<TH1D*>(hm->getHisto(
      get_histo_prefix() + "_Normalization"));
  assert(h_norm);

  std::string nodename = "CLUSTER_" + _calo_name;
  RawClusterContainer* clusters = findNode::getClass<RawClusterContainer>(
      topNode, nodename.c_str());
  assert(clusters);
  h_norm->Fill("Cluster", clusters->size());

  // get primary
  assert(_truth_container);
  assert(not _truth_container->GetMap().empty());
  PHG4Particle * last_primary = _truth_container->GetMap().rbegin()->second;
  assert(last_primary);

  if (verbosity > 2)
    {
      cout
          << "QAG4SimulationCalorimeter::process_event_Cluster() handle this truth particle"
          << endl;
      last_primary->identify();
    }

  assert(_caloevalstack);
  CaloRawClusterEval* clustereval = _caloevalstack->get_rawcluster_eval();
  assert(clustereval);

  TH1F* h = dynamic_cast<TH1F*>(hm->getHisto(
      get_histo_prefix() + "_Cluster_BestMatchERatio"));
  assert(h);

  RawCluster* cluster = clustereval->best_cluster_from(last_primary);
  if (cluster)
    {
      // has a cluster matched and best cluster selected

      if (verbosity > 3)
        cout << "QAG4SimulationCalorimeter::process_event_Cluster::"
            << _calo_name << " - get cluster with energy "
            << cluster->get_energy() << " VS primary energy "
            << last_primary->get_e() << endl;

      h->Fill(cluster->get_energy() / (last_primary->get_e() + 1e-9)); //avoids divide zero

      // now work on the projection:
      const CLHEP::Hep3Vector hit(cluster->get_position());

      const PHG4VtxPoint* primary_vtx = //
          _truth_container->GetPrimaryVtx(last_primary->get_vtx_id());
      assert(primary_vtx);
      if (verbosity > 2)
        {
          cout
              << "QAG4SimulationCalorimeter::process_event_Cluster() handle this vertex"
              << endl;
          primary_vtx->identify();
        }

      const CLHEP::Hep3Vector  vertex(primary_vtx->get_x(), primary_vtx->get_y(),
          primary_vtx->get_z());

      // projection axis
      CLHEP::Hep3Vector axis_proj(last_primary->get_px(), last_primary->get_py(),
          last_primary->get_pz());
      if (axis_proj.mag() == 0)
        axis_proj.set(0, 0, 1);
      axis_proj = axis_proj.unit();

      // azimuthal direction axis
      CLHEP::Hep3Vector axis_azimuth = axis_proj.cross(CLHEP::Hep3Vector(0, 0, 1));
      if (axis_azimuth.mag() == 0)
        axis_azimuth.set(1, 0, 0);
      axis_azimuth = axis_azimuth.unit();

      // polar direction axis
      CLHEP::Hep3Vector axis_polar = axis_proj.cross(axis_azimuth);
      assert(axis_polar.mag() > 0);
      axis_polar = axis_polar.unit();

      TH2F * hlat = dynamic_cast<TH2F*>(hm->getHisto(
          get_histo_prefix() + "_Cluster_LateralTruthProjection"));
      assert(hlat);

      const double hit_azimuth = axis_azimuth.dot(hit - vertex);
      const double hit_polar = axis_polar.dot(hit - vertex);
      hlat->Fill(hit_polar, hit_azimuth);

    }
  else
    {
      if (verbosity > 3)
        cout << "QAG4SimulationCalorimeter::process_event_Cluster::"
            << _calo_name << " - missing cluster !";
      h->Fill(0); // no cluster matched
    }

  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::process_event_Tower(PHCompositeNode *topNode)
{
  const string detector(_calo_name);

  if (verbosity > 2)
    cout << "QAG4SimulationCalorimeter::process_event_Tower() entered" << endl;

  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);
  TH1D* h_norm = dynamic_cast<TH1D*>(hm->getHisto(
      get_histo_prefix() + "_Normalization"));
  assert(h_norm);

  string towernodename = "TOWER_CALIB_" + detector;
  // Grab the towers
  RawTowerContainer* towers = findNode::getClass<RawTowerContainer>(topNode,
      towernodename.c_str());
  if (!towers)
    {
      std::cout << PHWHERE << ": Could not find node " << towernodename.c_str()
          << std::endl;
      return Fun4AllReturnCodes::ABORTRUN;
    }
  string towergeomnodename = "TOWERGEOM_" + detector;
  RawTowerGeomContainer *towergeom = findNode::getClass<RawTowerGeomContainer>(
      topNode, towergeomnodename.c_str());
  if (!towergeom)
    {
      cout << PHWHERE << ": Could not find node " << towergeomnodename.c_str()
          << endl;
      return Fun4AllReturnCodes::ABORTRUN;
    }

  static const int max_size = 5;
  map<int, string> size_label;
  size_label[1] = "1x1";
  size_label[2] = "2x2";
  size_label[3] = "3x3";
  size_label[4] = "4x4";
  size_label[5] = "5x5";
  map<int, double> max_energy;
  map<int, TH1F*> energy_hist_list;
  map<int, TH1F*> max_energy_hist_list;

  for (int size = 1; size <= max_size; ++size)
    {
      max_energy[size] = 0;


      TH1F* h = dynamic_cast<TH1F*>(hm->getHisto(
          get_histo_prefix() + "_Tower_" + size_label[size]));
      assert(h);
      energy_hist_list[size] = h;
      h = dynamic_cast<TH1F*>(hm->getHisto(
          get_histo_prefix() + "_Tower_" + size_label[size] + "_max"));
      assert(h);
      max_energy_hist_list[size] = h;

    }

  h_norm->Fill("Tower", towergeom->size()); // total tower count
  h_norm->Fill("Tower Hit", towers->size());

  for (int binphi = 0; binphi < towergeom->get_phibins(); ++binphi)
    {
      for (int bineta = 0; bineta < towergeom->get_etabins(); ++bineta)
        {
          for (int size = 1; size <= max_size; ++size)
            {

              // for 2x2 and 4x4 use slide-2 window as implemented in DAQ
              if ((size == 2 or size == 4)
                  and ((binphi % 2 != 0) and (bineta % 2 != 0)))
                continue;

              double energy = 0;

              // sliding window made from 2x2 sums
              for (int iphi = binphi; iphi < binphi + size; ++iphi)
                {
                  for (int ieta = bineta; ieta < bineta + size; ++ieta)
                    {
                      if (ieta > towergeom->get_etabins())
                        continue;

                      // wrap around
                      int wrapphi = iphi;
                      assert(wrapphi >= 0);
                      if (wrapphi >= towergeom->get_phibins())
                        {
                          wrapphi = wrapphi - towergeom->get_phibins();
                        }

                      RawTower* tower = towers->getTower(ieta, wrapphi);

                      if (tower)
                        {
                          const double e_intput = tower->get_energy();

                          energy += e_intput;
                        }
                    }
                }

              energy_hist_list[size]->Fill(energy == 0 ? 9.1e-4 : energy); // trick to fill 0 energy tower to the first bin

              if (energy > max_energy[size])
                max_energy[size] = energy;

            } //          for (int size = 1; size <= 4; ++size)
        }
    }

  for (int size = 1; size <= max_size; ++size)
    {
      max_energy_hist_list[size]->Fill(max_energy[size]);
    }
  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::Init_Tower(PHCompositeNode *topNode)
{

  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);

  TH1F *h = new TH1F(TString(get_histo_prefix()) + "_Tower_1x1", //
  TString(_calo_name) + " 1x1 tower;1x1 TOWER Energy (GeV)", 100, 9e-4, 100);
  QAHistManagerDef::useLogBins(h->GetXaxis());
  hm->registerHisto(h);

  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_Tower_1x1_max", //
          TString(_calo_name)
              + " 1x1 tower max per event;1x1 tower max per event (GeV)", 5000,
          0, 50));

  h = new TH1F(TString(get_histo_prefix()) + "_Tower_2x2", //
  TString(_calo_name) + " 2x2 tower;2x2 TOWER Energy (GeV)", 100, 9e-4, 100);
  QAHistManagerDef::useLogBins(h->GetXaxis());
  hm->registerHisto(h);
  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_Tower_2x2_max", //
          TString(_calo_name)
              + " 2x2 tower max per event;2x2 tower max per event (GeV)", 5000,
          0, 50));

  h = new TH1F(TString(get_histo_prefix()) + "_Tower_3x3", //
  TString(_calo_name) + " 3x3 tower;3x3 TOWER Energy (GeV)", 100, 9e-4, 100);
  QAHistManagerDef::useLogBins(h->GetXaxis());
  hm->registerHisto(h);
  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_Tower_3x3_max", //
          TString(_calo_name)
              + " 3x3 tower max per event;3x3 tower max per event (GeV)", 5000,
          0, 50));

  h = new TH1F(TString(get_histo_prefix()) + "_Tower_4x4", //
  TString(_calo_name) + " 4x4 tower;4x4 TOWER Energy (GeV)", 100, 9e-4, 100);
  QAHistManagerDef::useLogBins(h->GetXaxis());
  hm->registerHisto(h);
  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_Tower_4x4_max", //
          TString(_calo_name)
              + " 4x4 tower max per event;4x4 tower max per event (GeV)", 5000,
          0, 50));

  h = new TH1F(TString(get_histo_prefix()) + "_Tower_5x5", //
  TString(_calo_name) + " 5x5 tower;5x5 TOWER Energy (GeV)", 100, 9e-4, 100);
  QAHistManagerDef::useLogBins(h->GetXaxis());
  hm->registerHisto(h);
  hm->registerHisto(
      new TH1F(TString(get_histo_prefix()) + "_Tower_5x5_max", //
          TString(_calo_name)
              + " 5x5 tower max per event;5x5 tower max per event (GeV)", 5000,
          0, 50));

  return Fun4AllReturnCodes::EVENT_OK;
}
int
QAG4SimulationCalorimeter::process_event_G4Hit(PHCompositeNode *topNode)
{

  if (verbosity > 2)
    cout << "QAG4SimulationCalorimeter::process_event_G4Hit() entered" << endl;

  TH1F* h = nullptr;

  Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
  assert(hm);

  TH1D* h_norm = dynamic_cast<TH1D*>(hm->getHisto(
      get_histo_prefix() + "_Normalization"));
  assert(h_norm);

  // get primary
  assert(_truth_container);
  PHG4TruthInfoContainer::ConstRange primary_range =
      _truth_container->GetPrimaryParticleRange();
  double total_primary_energy = 1e-9; //make it zero energy epsilon samll so it can be used for denominator
  for (PHG4TruthInfoContainer::ConstIterator particle_iter = primary_range.first;
      particle_iter != primary_range.second; ++particle_iter)
    {
      const PHG4Particle *particle = particle_iter->second;
      assert(particle);
      total_primary_energy += particle->get_e();
    }

  assert(not _truth_container->GetMap().empty());
  const PHG4Particle * last_primary =
      _truth_container->GetMap().rbegin()->second;
  assert(last_primary);

  if (verbosity > 2)
    {
      cout
          << "QAG4SimulationCalorimeter::process_event_G4Hit() handle this truth particle"
          << endl;
      last_primary->identify();
    }
  const PHG4VtxPoint* primary_vtx = //
      _truth_container->GetPrimaryVtx(last_primary->get_vtx_id());
  assert(primary_vtx);
  if (verbosity > 2)
    {
      cout
          << "QAG4SimulationCalorimeter::process_event_G4Hit() handle this vertex"
          << endl;
      primary_vtx->identify();
    }

  const double t0 = primary_vtx->get_t();
  const TVector3 vertex(primary_vtx->get_x(), primary_vtx->get_y(),
      primary_vtx->get_z());

  // projection axis
  TVector3 axis_proj(last_primary->get_px(), last_primary->get_py(),
      last_primary->get_pz());
  if (axis_proj.Mag() == 0)
    axis_proj.SetXYZ(0, 0, 1);
  axis_proj = axis_proj.Unit();

  // azimuthal direction axis
  TVector3 axis_azimuth = axis_proj.Cross(TVector3(0, 0, 1));
  if (axis_azimuth.Mag() == 0)
    axis_azimuth.SetXYZ(1, 0, 0);
  axis_azimuth = axis_azimuth.Unit();

  // polar direction axis
  TVector3 axis_polar = axis_proj.Cross(axis_azimuth);
  assert(axis_polar.Mag() > 0);
  axis_polar = axis_polar.Unit();

  double e_calo = 0.0; // active energy deposition
  double ev_calo = 0.0; // visible energy
  double ea_calo = 0.0; // absorber energy
  double ev_calo_em = 0.0; // EM visible energy

  if (_calo_hit_container)
    {
      TH2F * hrz = dynamic_cast<TH2F*>(hm->getHisto(
          get_histo_prefix() + "_G4Hit_RZ"));
      assert(hrz);
      TH2F * hxy = dynamic_cast<TH2F*>(hm->getHisto(
          get_histo_prefix() + "_G4Hit_XY"));
      assert(hxy);
      TH1F * ht = dynamic_cast<TH1F*>(hm->getHisto(
          get_histo_prefix() + "_G4Hit_HitTime"));
      assert(ht);
      TH2F * hlat = dynamic_cast<TH2F*>(hm->getHisto(
          get_histo_prefix() + "_G4Hit_LateralTruthProjection"));
      assert(hlat);

      h_norm->Fill("G4Hit Active", _calo_hit_container->size());
      PHG4HitContainer::ConstRange calo_hit_range =
          _calo_hit_container->getHits();
      for (PHG4HitContainer::ConstIterator hit_iter = calo_hit_range.first;
          hit_iter != calo_hit_range.second; hit_iter++)
        {

          PHG4Hit *this_hit = hit_iter->second;
          assert(this_hit);

          e_calo += this_hit->get_edep();
          ev_calo += this_hit->get_light_yield();

          // EM visible energy that is only associated with electron energy deposition
          PHG4Particle* particle = _truth_container->GetParticle(
              this_hit->get_trkid());
          if (!particle)
            {
              cout <<__PRETTY_FUNCTION__<<" - Error - this PHG4hit missing particle: "; this_hit -> identify();
            }
          assert(particle);
          if (abs(particle->get_pid()) == 11)
            ev_calo_em += this_hit->get_light_yield();

          const TVector3 hit(this_hit->get_avg_x(), this_hit->get_avg_y(),
              this_hit->get_avg_z());

          hrz->Fill(hit.Z(), hit.Perp(), this_hit->get_edep());
          hxy->Fill(hit.X(), hit.Y(), this_hit->get_edep());
          ht->Fill(this_hit->get_avg_t() - t0, this_hit->get_edep());

          const double hit_azimuth = axis_azimuth.Dot(hit - vertex);
          const double hit_polar = axis_polar.Dot(hit - vertex);
          hlat->Fill(hit_polar, hit_azimuth, this_hit->get_edep());
        }
    }

  if (_calo_abs_hit_container)
    {

      h_norm->Fill("G4Hit Absor.", _calo_abs_hit_container->size());

      PHG4HitContainer::ConstRange calo_abs_hit_range =
          _calo_abs_hit_container->getHits();
      for (PHG4HitContainer::ConstIterator hit_iter = calo_abs_hit_range.first;
          hit_iter != calo_abs_hit_range.second; hit_iter++)
        {

          PHG4Hit *this_hit = hit_iter->second;
          assert(this_hit);

          ea_calo += this_hit->get_edep();

        }
    }

  if (verbosity > 3)
    cout << "QAG4SimulationCalorimeter::process_event_G4Hit::" << _calo_name
        << " - SF = " << e_calo / (e_calo + ea_calo + 1e-9) << ", VSF = "
        << ev_calo / (e_calo + ea_calo + 1e-9) << endl;

  if (e_calo + ea_calo > 0)
    {
      h = dynamic_cast<TH1F*>(hm->getHisto(get_histo_prefix() + "_G4Hit_SF"));
      assert(h);
      h->Fill(e_calo / (e_calo + ea_calo));

      h = dynamic_cast<TH1F*>(hm->getHisto(get_histo_prefix() + "_G4Hit_VSF"));
      assert(h);
      h->Fill(ev_calo / (e_calo + ea_calo));
    }

  h = dynamic_cast<TH1F*>(hm->getHisto(
      get_histo_prefix() + "_G4Hit_FractionTruthEnergy"));
  assert(h);
  h->Fill((e_calo + ea_calo) / total_primary_energy);

  if (ev_calo > 0)
    {
      h = dynamic_cast<TH1F*>(hm->getHisto(
          get_histo_prefix() + "_G4Hit_FractionEMVisibleEnergy"));
      assert(h);
      h->Fill(ev_calo_em / (ev_calo));
    }

  if (verbosity > 3)
    cout << "QAG4SimulationCalorimeter::process_event_G4Hit::" << _calo_name
        << " - histogram " << h->GetName() << " Get Sum = " << h->GetSum()
        << endl;

  return Fun4AllReturnCodes::EVENT_OK;
}