float
TrackProjectionTools::getE33Barrel( string detName, float phi, float eta ){

  string towernodename = "TOWER_CALIB_" + detName;
  // Grab the towers
  RawTowerContainer* towerList = findNode::getClass<RawTowerContainer>(_topNode, towernodename.c_str());
  if (!towerList)
    {
      std::cout << PHWHERE << ": Could not find node " << towernodename.c_str() << std::endl;
      return -1;
    }
  string towergeomnodename = "TOWERGEOM_" + detName;
  RawTowerGeomContainer *towergeo = findNode::getClass<RawTowerGeomContainer>(_topNode, towergeomnodename.c_str());
  if (! towergeo)
    {
      cout << PHWHERE << ": Could not find node " << towergeomnodename.c_str() << endl;
      return -1;
    }

  // calculate 3x3 and 5x5 tower energies
  int binphi = towergeo->get_phibin(phi);
  int bineta = towergeo->get_etabin(eta);

  float energy_3x3 = 0.0;
  float energy_5x5 = 0.0;

  for (int iphi = binphi-2; iphi <= binphi+2; ++iphi) {
    for (int ieta = bineta-2; ieta <= bineta+2; ++ieta) {

      // wrap around
      int wrapphi = iphi;
      if (wrapphi < 0) {
        wrapphi = towergeo->get_phibins() + wrapphi;
      }
      if (wrapphi >= towergeo->get_phibins()) {
        wrapphi = wrapphi - towergeo->get_phibins();
      }

      // edges
      if (ieta < 0) continue;
      if (ieta >= towergeo->get_etabins()) continue;

      RawTower* tower = towerList->getTower(ieta,wrapphi);
      if (tower) {
        energy_5x5 += tower->get_energy();
        if (abs(iphi - binphi)<=1 and abs(ieta - bineta)<=1 )
          energy_3x3 += tower->get_energy();
      }

    }
  }

  return energy_3x3;
}
Пример #2
0
int CaloTriggerSim::process_event(PHCompositeNode *topNode)
{
  if (verbosity > 0)
    std::cout << "CaloTriggerSim::process_event: entering" << std::endl;

  // pull out the tower containers and geometry objects at the start
  RawTowerContainer *towersEM3 = findNode::getClass<RawTowerContainer>(topNode, "TOWER_CALIB_CEMC");
  RawTowerContainer *towersIH3 = findNode::getClass<RawTowerContainer>(topNode, "TOWER_CALIB_HCALIN");
  RawTowerContainer *towersOH3 = findNode::getClass<RawTowerContainer>(topNode, "TOWER_CALIB_HCALOUT");
  if (verbosity > 0) {
    std::cout << "CaloTriggerSim::process_event: " << towersEM3->size() << " TOWER_CALIB_CEMC towers" << std::endl;
    std::cout << "CaloTriggerSim::process_event: " << towersIH3->size() << " TOWER_CALIB_HCALIN towers" << std::endl;
    std::cout << "CaloTriggerSim::process_event: " << towersOH3->size() << " TOWER_CALIB_HCALOUT towers" << std::endl;
  }

  RawTowerGeomContainer_Cylinderv1 *geomEM = findNode::getClass<RawTowerGeomContainer_Cylinderv1>(topNode, "TOWERGEOM_CEMC");
  RawTowerGeomContainer *geomIH = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_HCALIN");
  RawTowerGeomContainer *geomOH = findNode::getClass<RawTowerGeomContainer>(topNode, "TOWERGEOM_HCALOUT");

  // get the binning from the geometry (different for 1D vs 2D...)
  int geom_etabins = geomEM->get_etabins();
  int geom_phibins = geomEM->get_phibins();

  // if internal knowledge of geometry is unset, set it now (should
  // only happen once, on the first event)
  if (_EMCAL_1x1_NETA < 0)
  {
    _EMCAL_1x1_NETA = geom_etabins;
    _EMCAL_1x1_NPHI = geom_phibins;

    // half as many 2x2 windows along each axis as 1x1
    _EMCAL_2x2_NETA = geom_etabins / 2;
    _EMCAL_2x2_NPHI = geom_phibins / 2;

    // each 2x2 window defines a 4x4 window for which that 2x2 window
    // is the upper-left corner, so there are as many 4x4's as 2x2's
    // (except in eta, where the edge effect means there is 1 fewer)
    _EMCAL_4x4_NETA = geom_etabins / 2 - 1;
    _EMCAL_4x4_NPHI = geom_phibins / 2;

    // reset all maps
    _EMCAL_1x1_MAP.resize(_EMCAL_1x1_NETA, std::vector<float>(_EMCAL_1x1_NPHI, 0));
    _EMCAL_2x2_MAP.resize(_EMCAL_2x2_NETA, std::vector<float>(_EMCAL_2x2_NPHI, 0));
    _EMCAL_4x4_MAP.resize(_EMCAL_4x4_NETA, std::vector<float>(_EMCAL_4x4_NPHI, 0));

    if (verbosity > 0)
    {
      std::cout << "CaloTriggerSim::process_event: setting number of window in eta / phi,";
      std::cout << "1x1 are " << _EMCAL_1x1_NETA << " / " << _EMCAL_1x1_NPHI << ", ";
      std::cout << "2x2 are " << _EMCAL_2x2_NETA << " / " << _EMCAL_2x2_NPHI << ", ";
      std::cout << "4x4 are " << _EMCAL_4x4_NETA << " / " << _EMCAL_4x4_NPHI << std::endl;
    }
  }

  // reset 1x1 map
  for (int ieta = 0; ieta < _EMCAL_1x1_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _EMCAL_1x1_NPHI; iphi++)
    {
      _EMCAL_1x1_MAP[ieta][iphi] = 0;
    }
  }

  // iterate over EMCal towers, constructing 1x1's
  RawTowerContainer::ConstRange begin_end = towersEM3->getTowers();
  for (RawTowerContainer::ConstIterator rtiter = begin_end.first; rtiter != begin_end.second; ++rtiter)
  {
    RawTower *tower = rtiter->second;
    RawTowerGeom *tower_geom = geomEM->get_tower_geometry(tower->get_key());

    float this_eta = tower_geom->get_eta();
    float this_phi = tower_geom->get_phi();
    int this_etabin = geomEM->get_etabin(this_eta);
    int this_phibin = geomEM->get_phibin(this_phi);
    float this_E = tower->get_energy();

    _EMCAL_1x1_MAP[this_etabin][this_phibin] += this_E;

    if (verbosity > 1 && tower->get_energy() > 1)
    {
      std::cout << "CaloTriggerSim::process_event: EMCal 1x1 tower eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << this_etabin << " ) / " << this_phi << " ( " << this_phibin << " ) / " << this_E << std::endl;
    }
  }

  // reset 2x2 map and best
  for (int ieta = 0; ieta < _EMCAL_2x2_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _EMCAL_2x2_NPHI; iphi++)
    {
      _EMCAL_2x2_MAP[ieta][iphi] = 0;
    }
  }

  _EMCAL_2x2_BEST_E = 0;
  _EMCAL_2x2_BEST_PHI = 0;
  _EMCAL_2x2_BEST_ETA = 0;

  // now reconstruct 2x2 map from 1x1 map
  for (int ieta = 0; ieta < _EMCAL_2x2_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _EMCAL_2x2_NPHI; iphi++)
    {
      float this_sum = 0;

      this_sum += _EMCAL_1x1_MAP[2 * ieta][2 * iphi];
      this_sum += _EMCAL_1x1_MAP[2 * ieta][2 * iphi + 1];  // 2 * iphi + 1 is safe, since _EMCAL_2x2_NPHI = _EMCAL_1x1_NPHI / 2
      this_sum += _EMCAL_1x1_MAP[2 * ieta + 1][2 * iphi];  // 2 * ieta + 1 is safe, since _EMCAL_2x2_NETA = _EMCAL_1x1_NETA / 2
      this_sum += _EMCAL_1x1_MAP[2 * ieta + 1][2 * iphi + 1];

      if (_emulate_truncation) {
	this_sum = truncate_8bit( this_sum );
      }

      // populate 2x2 map
      _EMCAL_2x2_MAP[ieta][iphi] = this_sum;

      // to calculate the eta, phi position, take the average of that of the 1x1's
      float this_eta = 0.5 * (geomEM->get_etacenter(2 * ieta) + geomEM->get_etacenter(2 * ieta + 1));
      float this_phi = 0.5 * (geomEM->get_phicenter(2 * iphi) + geomEM->get_phicenter(2 * iphi + 1));
      // wrap-around phi (apparently needed for 2D geometry?)
      if (this_phi > 3.14159) this_phi -= 2 * 3.14159;
      if (this_phi < -3.14159) this_phi += 2 * 3.14159;

      if (verbosity > 1 && this_sum > 1)
      {
        std::cout << "CaloTriggerSim::process_event: EMCal 2x2 tower eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << ieta << " ) / " << this_phi << " ( " << iphi << " ) / " << this_sum << std::endl;
      }

      if (this_sum > _EMCAL_2x2_BEST_E)
      {
        _EMCAL_2x2_BEST_E = this_sum;
        _EMCAL_2x2_BEST_PHI = this_phi;
        _EMCAL_2x2_BEST_ETA = this_eta;
      }
    }
  }

  if (verbosity > 0)
  {
    std::cout << "CaloTriggerSim::process_event: best EMCal 2x2 window is at eta / phi = " << _EMCAL_2x2_BEST_ETA << " / " << _EMCAL_2x2_BEST_PHI << " and E = " << _EMCAL_2x2_BEST_E << std::endl;
  }

  // reset 4x4 map & best
  for (int ieta = 0; ieta < _EMCAL_4x4_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _EMCAL_4x4_NPHI; iphi++)
    {
      _EMCAL_4x4_MAP[ieta][iphi] = 0;
    }
  }

  _EMCAL_4x4_BEST_E = 0;
  _EMCAL_4x4_BEST_PHI = 0;
  _EMCAL_4x4_BEST_ETA = 0;

  int emcal_4x4_best_iphi = -1;
  int emcal_4x4_best_ieta = -1;

  // now reconstruct (sliding) 4x4 map from 2x2 map
  for (int ieta = 0; ieta < _EMCAL_4x4_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _EMCAL_4x4_NPHI; iphi++)
    {
      // for eta calculation (since eta distribution is potentially
      // non-uniform), average positions of all four towers
      float this_eta = 0.25 * (geomEM->get_etacenter(2 * ieta) + geomEM->get_etacenter(2 * ieta + 1) + geomEM->get_etacenter(2 * ieta + 2) + geomEM->get_etacenter(2 * ieta + 3));
      // for phi calculation (since phi distribution is uniform), take
      // first tower and add 1.5 tower widths
      float this_phi = geomEM->get_phicenter(2 * iphi) + 1.5 * (geomEM->get_phicenter(2 * iphi + 1) - geomEM->get_phicenter(2 * iphi));
      // wrap-around phi (apparently needed for 2D geometry?)
      if (this_phi > 3.14159) this_phi -= 2 * 3.14159;
      if (this_phi < -3.14159) this_phi += 2 * 3.14159;

      float this_sum = 0;

      this_sum += _EMCAL_2x2_MAP[ieta][iphi];
      this_sum += _EMCAL_2x2_MAP[ieta + 1][iphi];  // ieta + 1 is safe, since _EMCAL_4x4_NETA = _EMCAL_2x2_NETA - 1

      if (iphi != _EMCAL_4x4_NPHI - 1)
      {
        // if we are not in the last phi row, can safely access 'iphi+1'
        this_sum += _EMCAL_2x2_MAP[ieta][iphi + 1];
        this_sum += _EMCAL_2x2_MAP[ieta + 1][iphi + 1];
      }
      else
      {
        // if we are in the last phi row, wrap back around to zero
        this_sum += _EMCAL_2x2_MAP[ieta][0];
        this_sum += _EMCAL_2x2_MAP[ieta + 1][0];
      }

      _EMCAL_4x4_MAP[ieta][iphi] = this_sum;

      if (verbosity > 1 && this_sum > 1)
      {
        std::cout << "CaloTriggerSim::process_event: EMCal 4x4 tower eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << ieta << " ) / " << this_phi << " ( " << iphi << " ) / " << this_sum << std::endl;
      }

      if (this_sum > _EMCAL_4x4_BEST_E) {
	
	_EMCAL_4x4_BEST_E = this_sum;
	_EMCAL_4x4_BEST_PHI = this_phi;
	_EMCAL_4x4_BEST_ETA = this_eta;
	
	emcal_4x4_best_iphi = iphi;
	emcal_4x4_best_ieta = ieta;
  
      }
    }
  }


  _EMCAL_4x4_BEST2_E = 0;
  _EMCAL_4x4_BEST2_PHI = 0;
  _EMCAL_4x4_BEST2_ETA = 0;

  // find second-largest 4x4 which is > 1 tower away...
  for (int ieta = 0; ieta < _EMCAL_4x4_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _EMCAL_4x4_NPHI; iphi++)
    {

      int deta = ieta - emcal_4x4_best_ieta;
      int dphi = ( iphi - emcal_4x4_best_iphi ) % _EMCAL_4x4_NPHI ;

      if ( abs( deta ) < 1.5 && abs( dphi ) < 1.5 ) 
	continue;

      float this_eta = 0.25 * (geomEM->get_etacenter(2 * ieta) + geomEM->get_etacenter(2 * ieta + 1) + geomEM->get_etacenter(2 * ieta + 2) + geomEM->get_etacenter(2 * ieta + 3));
      float this_phi = geomEM->get_phicenter(2 * iphi) + 1.5 * (geomEM->get_phicenter(2 * iphi + 1) - geomEM->get_phicenter(2 * iphi));

      if (this_phi > 3.14159) this_phi -= 2 * 3.14159;
      if (this_phi < -3.14159) this_phi += 2 * 3.14159;

      float this_sum = _EMCAL_4x4_MAP[ieta][iphi];
      
      if (this_sum > _EMCAL_4x4_BEST2_E) {
	
	_EMCAL_4x4_BEST2_E = this_sum;
	_EMCAL_4x4_BEST2_PHI = this_phi;
	_EMCAL_4x4_BEST2_ETA = this_eta;

      }

    }
  }

  if (verbosity > 0)
  {
    std::cout << "CaloTriggerSim::process_event: best EMCal 4x4 window is at eta / phi = " << _EMCAL_4x4_BEST_ETA << " / " << _EMCAL_4x4_BEST_PHI << " and E = " << _EMCAL_4x4_BEST_E << std::endl;
    std::cout << "CaloTriggerSim::process_event: 2nd best EMCal 4x4 window is at eta / phi = " << _EMCAL_4x4_BEST2_ETA << " / " << _EMCAL_4x4_BEST2_PHI << " and E = " << _EMCAL_4x4_BEST2_E << std::endl;
  }

  // begin full calo sim

  // get the 0.1x0.1 binning from the OHCal geometry
  int geomOH_etabins = geomOH->get_etabins();
  int geomOH_phibins = geomOH->get_phibins();

  // if internal knowledge of geometry is unset, set it now
  if (_FULLCALO_0p1x0p1_NETA < 0)
  {
    _FULLCALO_PHI_START = geomOH->get_phibounds( 0 ).first;
    _FULLCALO_PHI_END = geomOH->get_phibounds( geomOH_phibins - 1 ).second;

    _FULLCALO_0p1x0p1_NETA = geomOH_etabins;
    _FULLCALO_0p1x0p1_NPHI = geomOH_phibins;

    // half as many 0.2x0.2 windows along each axis as 0.1x0.1
    _FULLCALO_0p2x0p2_NETA = geomOH_etabins / 2;
    _FULLCALO_0p2x0p2_NPHI = geomOH_phibins / 2;

    // each 0.2x0.2 window defines a 0.4x0.4 window for which that
    // 0.2x0.2 window is the upper-left corner, so there are as many
    // 0.4x0.4's as 0.2x0.2's (except in eta, where the edge effect
    // means there is 1 fewer)
    _FULLCALO_0p4x0p4_NETA = geomOH_etabins / 2 - 1;
    _FULLCALO_0p4x0p4_NPHI = geomOH_phibins / 2;

    // for 0.6x0.6 windows, the above logic applies, except that the
    // edge effect causes there to be 2 fewer less in eta
    _FULLCALO_0p6x0p6_NETA = geomOH_etabins / 2 - 2;
    _FULLCALO_0p6x0p6_NPHI = geomOH_phibins / 2;

    // for 0.8x0.8 windows, the above logic applies, except that the
    // edge effect causes there to be 3 fewer less in eta
    _FULLCALO_0p8x0p8_NETA = geomOH_etabins / 2 - 3;
    _FULLCALO_0p8x0p8_NPHI = geomOH_phibins / 2;

    // for 1.0x1.0 windows, the above logic applies, except that the
    // edge effect causes there to be 4 fewer less in eta
    _FULLCALO_1p0x1p0_NETA = geomOH_etabins / 2 - 4;
    _FULLCALO_1p0x1p0_NPHI = geomOH_phibins / 2;

    // reset all maps
    _FULLCALO_0p1x0p1_MAP.resize(_FULLCALO_0p1x0p1_NETA, std::vector<float>(_FULLCALO_0p1x0p1_NPHI, 0));
    _FULLCALO_0p2x0p2_MAP.resize(_FULLCALO_0p2x0p2_NETA, std::vector<float>(_FULLCALO_0p2x0p2_NPHI, 0));
    _FULLCALO_0p4x0p4_MAP.resize(_FULLCALO_0p4x0p4_NETA, std::vector<float>(_FULLCALO_0p4x0p4_NPHI, 0));
    _FULLCALO_0p6x0p6_MAP.resize(_FULLCALO_0p6x0p6_NETA, std::vector<float>(_FULLCALO_0p6x0p6_NPHI, 0));
    _FULLCALO_0p8x0p8_MAP.resize(_FULLCALO_0p8x0p8_NETA, std::vector<float>(_FULLCALO_0p8x0p8_NPHI, 0));
    _FULLCALO_1p0x1p0_MAP.resize(_FULLCALO_1p0x1p0_NETA, std::vector<float>(_FULLCALO_1p0x1p0_NPHI, 0));

    if (verbosity > 0)
    {
      std::cout << "CaloTriggerSim::process_event: determining phi range for 0.1x0.1 full calo map: " << _FULLCALO_PHI_START << " to " << _FULLCALO_PHI_END << std::endl;
      std::cout << "CaloTriggerSim::process_event: setting number of full calo window in eta / phi:" << std::endl;
      std::cout << "  0.1x0.1 are " << _FULLCALO_0p1x0p1_NETA << " / " << _FULLCALO_0p1x0p1_NPHI << ", ";
      std::cout << "0.2x0.2 are " << _FULLCALO_0p2x0p2_NETA << " / " << _FULLCALO_0p2x0p2_NPHI << ", ";
      std::cout << "0.4x0.4 are " << _FULLCALO_0p4x0p4_NETA << " / " << _FULLCALO_0p4x0p4_NPHI << ", ";
      std::cout << "0.6x0.6 are " << _FULLCALO_0p6x0p6_NETA << " / " << _FULLCALO_0p6x0p6_NPHI << ", ";
      std::cout << "0.8x0.8 are " << _FULLCALO_0p8x0p8_NETA << " / " << _FULLCALO_0p8x0p8_NPHI << ", ";
      std::cout << "1.0x1.0 are " << _FULLCALO_1p0x1p0_NETA << " / " << _FULLCALO_1p0x1p0_NPHI << std::endl;
    }
  }

  // reset 0.1x0.1 map
  for (int ieta = 0; ieta < _FULLCALO_0p1x0p1_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p1x0p1_NPHI; iphi++)
    {
      _FULLCALO_0p1x0p1_MAP[ieta][iphi] = 0;
    }
  }

  // iterate over EMCal towers, filling in the 0.1x0.1 region they contribute to
  RawTowerContainer::ConstRange begin_end_EM = towersEM3->getTowers();
  for (RawTowerContainer::ConstIterator rtiter = begin_end_EM.first; rtiter != begin_end_EM.second; ++rtiter)
  {
    RawTower *tower = rtiter->second;
    RawTowerGeom *tower_geom = geomEM->get_tower_geometry(tower->get_key());

    float this_eta = tower_geom->get_eta();
    float this_phi = tower_geom->get_phi();
    if (this_phi < _FULLCALO_PHI_START) this_phi += 2*3.14159;
    if (this_phi > _FULLCALO_PHI_END) this_phi -= 2*3.14159;
 
    // note: look up eta/phi index based on OHCal geometry, since this
    // defines the 0.1x0.1 regions
    int this_etabin = geomOH->get_etabin( this_eta );
    int this_phibin = geomOH->get_phibin( this_phi );
    float this_E = tower->get_energy();

    _FULLCALO_0p1x0p1_MAP[ this_etabin ][ this_phibin ] += this_E;

    if (verbosity > 1 && tower->get_energy() > 1)
    {
      std::cout << "CaloTriggerSim::process_event: EMCal tower at eta / phi (added to fullcalo map with etabin / phibin ) / E = " << std::setprecision(6) << this_eta << " / " << this_phi << " ( " << this_etabin << " / " << this_phibin << " ) / " << this_E << std::endl;
    }
  }

  // iterate over IHCal towers, filling in the 0.1x0.1 region they contribute to
  RawTowerContainer::ConstRange begin_end_IH = towersIH3->getTowers();
  for (RawTowerContainer::ConstIterator rtiter = begin_end_IH.first; rtiter != begin_end_IH.second; ++rtiter)
  {
    RawTower *tower = rtiter->second;
    RawTowerGeom *tower_geom = geomIH->get_tower_geometry(tower->get_key());

    float this_eta = tower_geom->get_eta();
    float this_phi = tower_geom->get_phi();
    if (this_phi < _FULLCALO_PHI_START) this_phi += 2*3.14159;
    if (this_phi > _FULLCALO_PHI_END) this_phi -= 2*3.14159;
 
    // note: look up eta/phi index based on OHCal geometry, even though I
    // think it is by construction the same as the IHCal geometry...
    int this_etabin = geomOH->get_etabin( this_eta );
    int this_phibin = geomOH->get_phibin( this_phi );
    float this_E = tower->get_energy();

    _FULLCALO_0p1x0p1_MAP[ this_etabin ][ this_phibin ] += this_E;

    if (verbosity > 1 && tower->get_energy() > 0.5)
    {
      std::cout << "CaloTriggerSim::process_event: IHCal tower at eta / phi (added to fullcalo map with etabin / phibin ) / E = " << std::setprecision(6) << this_eta << " / " << this_phi << " ( " << this_etabin << " / " << this_phibin << " ) / " << this_E << std::endl;
    }
  }

  // iterate over OHCal towers, filling in the 0.1x0.1 region they contribute to
  RawTowerContainer::ConstRange begin_end_OH = towersOH3->getTowers();
  for (RawTowerContainer::ConstIterator rtiter = begin_end_OH.first; rtiter != begin_end_OH.second; ++rtiter)
  {
    RawTower *tower = rtiter->second;
    RawTowerGeom *tower_geom = geomOH->get_tower_geometry(tower->get_key());

    float this_eta = tower_geom->get_eta();
    float this_phi = tower_geom->get_phi();
    if (this_phi < _FULLCALO_PHI_START) this_phi += 2*3.14159;
    if (this_phi > _FULLCALO_PHI_END) this_phi -= 2*3.14159;
 
    // note: use the nominal eta/phi index, since the fullcalo 0.1x0.1
    // map is defined by the OHCal geometry itself
    int this_etabin = geomOH->get_etabin( this_eta );
    int this_phibin = geomOH->get_phibin( this_phi );
    float this_E = tower->get_energy();

    _FULLCALO_0p1x0p1_MAP[ this_etabin ][ this_phibin ] += this_E;

    if (verbosity > 1 && tower->get_energy() > 0.5)
    {
      std::cout << "CaloTriggerSim::process_event: OHCal tower at eta / phi (added to fullcalo map with etabin / phibin ) / E = " << std::setprecision(6) << this_eta << " / " << this_phi << " ( " << this_etabin << " / " << this_phibin << " ) / " << this_E << std::endl;
    }
  }

  // reset 0.2x0.2 map and best
  for (int ieta = 0; ieta < _FULLCALO_0p2x0p2_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p2x0p2_NPHI; iphi++)
    {
      _FULLCALO_0p2x0p2_MAP[ ieta ][ iphi ] = 0;
    }
  }

  _FULLCALO_0p2x0p2_BEST_E = 0;
  _FULLCALO_0p2x0p2_BEST_PHI = 0;
  _FULLCALO_0p2x0p2_BEST_ETA = 0;

  // now reconstruct (non-sliding) 0.2x0.2 map from 0.1x0.1 map
  for (int ieta = 0; ieta < _FULLCALO_0p2x0p2_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p2x0p2_NPHI; iphi++)
    {
      float this_sum = 0;

      this_sum += _FULLCALO_0p1x0p1_MAP[2 * ieta][2 * iphi];
      this_sum += _FULLCALO_0p1x0p1_MAP[2 * ieta][2 * iphi + 1];  // 2 * iphi + 1 is safe, since _FULLCALO_0p2x0p2_NPHI = _FULLCALO_0p1x0p1_NPHI / 2
      this_sum += _FULLCALO_0p1x0p1_MAP[2 * ieta + 1][2 * iphi];  // 2 * ieta + 1 is safe, since _FULLCALO_0p2x0p2_NETA = _FULLCALO_0p1x0p1_NETA / 2
      this_sum += _FULLCALO_0p1x0p1_MAP[2 * ieta + 1][2 * iphi + 1];

      // populate 0.2x0.2 map
      _FULLCALO_0p2x0p2_MAP[ieta][iphi] = this_sum;

      // to calculate the eta, phi position, take the average of that
      // of the contributing 0.1x0.1's (which are defined by the OHCal geometry)
      float this_eta = 0.5 * (geomOH->get_etacenter(2 * ieta) + geomOH->get_etacenter(2 * ieta + 1));
      float this_phi = 0.5 * (geomOH->get_phicenter(2 * iphi) + geomOH->get_phicenter(2 * iphi + 1));

      if (verbosity > 1 && this_sum > 1)
      {
        std::cout << "CaloTriggerSim::process_event: FullCalo 0.2x0.2 window eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << ieta << " ) / " << this_phi << " ( " << iphi << " ) / " << this_sum << std::endl;
      }

      if (this_sum > _FULLCALO_0p2x0p2_BEST_E)
      {
        _FULLCALO_0p2x0p2_BEST_E = this_sum;
        _FULLCALO_0p2x0p2_BEST_PHI = this_phi;
        _FULLCALO_0p2x0p2_BEST_ETA = this_eta;
      }
    }
  }

  if (verbosity > 0)
  {
    std::cout << "CaloTriggerSim::process_event: best FullCalo 0.2x0.2 window is at eta / phi = " << _FULLCALO_0p2x0p2_BEST_ETA << " / " << _FULLCALO_0p2x0p2_BEST_PHI << " and E = " << _FULLCALO_0p2x0p2_BEST_E << std::endl;
  }

  // reset fullcalo 0.4x0.4 map & best
  for (int ieta = 0; ieta < _FULLCALO_0p4x0p4_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p4x0p4_NPHI; iphi++)
    {
      _FULLCALO_0p4x0p4_MAP[ ieta ][ iphi ] = 0;
    }
  }

  _FULLCALO_0p4x0p4_BEST_E = 0;
  _FULLCALO_0p4x0p4_BEST_PHI = 0;
  _FULLCALO_0p4x0p4_BEST_ETA = 0;

  // now reconstruct (sliding) 0.4x0.4 map from 0.2x0.2 map
  for (int ieta = 0; ieta < _FULLCALO_0p4x0p4_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p4x0p4_NPHI; iphi++)
    {
      // for eta calculation, use position of corner tower and add 1.5
      // tower widths
      float this_eta = geomOH->get_etacenter(2 * ieta) + 1.5 * ( geomOH->get_etacenter( 1 ) - geomOH->get_etacenter( 0 ) );
      // for phi calculation, use position of corner tower and add 1.5
      // tower widths
      float this_phi = geomOH->get_phicenter(2 * iphi) + 1.5 * (geomOH->get_phicenter( 1 ) - geomOH->get_phicenter( 0 ) );

      float this_sum = 0;

      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][iphi];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][iphi];  // 2 * ieta + 1 is safe, since _FULLCALO_0p4x0p4_NETA = _FULLCALO_0p4x0p4_NETA - 1

      // add 1 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];

      _FULLCALO_0p4x0p4_MAP[ieta][iphi] = this_sum;

      if (verbosity > 1 && this_sum > 2)
      {
        std::cout << "CaloTriggerSim::process_event: FullCalo  0.4x0.4 tower eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << ieta << " ) / " << this_phi << " ( " << iphi << " ) / " << this_sum << std::endl;
      }

      if (this_sum > _FULLCALO_0p4x0p4_BEST_E)
      {
        _FULLCALO_0p4x0p4_BEST_E = this_sum;
        _FULLCALO_0p4x0p4_BEST_PHI = this_phi;
        _FULLCALO_0p4x0p4_BEST_ETA = this_eta;
      }
    }
  }

  if (verbosity > 0)
  {
    std::cout << "CaloTriggerSim::process_event: best FullCalo 0.4x0.4 window is at eta / phi = " << _FULLCALO_0p4x0p4_BEST_ETA << " / " << _FULLCALO_0p4x0p4_BEST_PHI << " and E = " << _FULLCALO_0p4x0p4_BEST_E << std::endl;
  }

  // reset fullcalo 0.6x0.6 map & best
  for (int ieta = 0; ieta < _FULLCALO_0p6x0p6_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p6x0p6_NPHI; iphi++)
    {
      _FULLCALO_0p6x0p6_MAP[ ieta ][ iphi ] = 0;
    }
  }

  _FULLCALO_0p6x0p6_BEST_E = 0;
  _FULLCALO_0p6x0p6_BEST_PHI = 0;
  _FULLCALO_0p6x0p6_BEST_ETA = 0;

  // now reconstruct (sliding) 0.6x0.6 map from 0.2x0.2 map
  for (int ieta = 0; ieta < _FULLCALO_0p6x0p6_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p6x0p6_NPHI; iphi++)
    {
      // for eta calculation, use position of corner tower and add 2.5
      // tower widths
      float this_eta = geomOH->get_etacenter(2 * ieta) + 2.5 * ( geomOH->get_etacenter( 1 ) - geomOH->get_etacenter( 0 ) );
      // for phi calculation, use position of corner tower and add 2.5
      // tower widths
      float this_phi = geomOH->get_phicenter(2 * iphi) + 2.5 * (geomOH->get_phicenter( 1 ) - geomOH->get_phicenter( 0 ) );

      float this_sum = 0;

      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][iphi];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][iphi];  // ieta + 1 is safe, since _FULLCALO_0p6x0p6_NETA = _FULLCALO_0p2x0p2_NETA - 2
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][iphi];  // ieta + 2 is safe, since _FULLCALO_0p6x0p6_NETA = _FULLCALO_0p2x0p2_NETA - 2

      // add 1 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      // add 2 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];

      _FULLCALO_0p6x0p6_MAP[ieta][iphi] = this_sum;

      if (verbosity > 1 && this_sum > 3)
      {
        std::cout << "CaloTriggerSim::process_event: FullCalo  0.6x0.6 tower eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << ieta << " ) / " << this_phi << " ( " << iphi << " ) / " << this_sum << std::endl;
      }

      if (this_sum > _FULLCALO_0p6x0p6_BEST_E)
      {
        _FULLCALO_0p6x0p6_BEST_E = this_sum;
        _FULLCALO_0p6x0p6_BEST_PHI = this_phi;
        _FULLCALO_0p6x0p6_BEST_ETA = this_eta;
      }
    }
  }

  if (verbosity > 0)
  {
    std::cout << "CaloTriggerSim::process_event: best FullCalo 0.6x0.6 window is at eta / phi = " << _FULLCALO_0p6x0p6_BEST_ETA << " / " << _FULLCALO_0p6x0p6_BEST_PHI << " and E = " << _FULLCALO_0p6x0p6_BEST_E << std::endl;
  }

  // reset fullcalo 0.8x0.8 map & best
  for (int ieta = 0; ieta < _FULLCALO_0p8x0p8_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p8x0p8_NPHI; iphi++)
    {
      _FULLCALO_0p8x0p8_MAP[ ieta ][ iphi ] = 0;
    }
  }

  _FULLCALO_0p8x0p8_BEST_E = 0;
  _FULLCALO_0p8x0p8_BEST_PHI = 0;
  _FULLCALO_0p8x0p8_BEST_ETA = 0;

  // now reconstruct (sliding) 0.8x0.8 map from 0.2x0.2 map
  for (int ieta = 0; ieta < _FULLCALO_0p8x0p8_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_0p8x0p8_NPHI; iphi++)
    {
      // for eta calculation, use position of corner tower and add 3.5
      // tower widths
      float this_eta = geomOH->get_etacenter(2 * ieta) + 3.5 * ( geomOH->get_etacenter( 1 ) - geomOH->get_etacenter( 0 ) );
      // for phi calculation, use position of corner tower and add 3.5
      // tower widths
      float this_phi = geomOH->get_phicenter(2 * iphi) + 3.5 * (geomOH->get_phicenter( 1 ) - geomOH->get_phicenter( 0 ) );

      float this_sum = 0;

      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][iphi];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][iphi];  // ieta + 1 is safe, since _FULLCALO_0p8x0p8_NETA = _FULLCALO_0p2x0p2_NETA - 3
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][iphi];  // ieta + 2 is safe, since _FULLCALO_0p8x0p8_NETA = _FULLCALO_0p2x0p2_NETA - 3
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][iphi];  // ieta + 3 is safe, since _FULLCALO_0p8x0p8_NETA = _FULLCALO_0p2x0p2_NETA - 3

      // add 1 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      // add 2 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      // add 3 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];

      _FULLCALO_0p8x0p8_MAP[ieta][iphi] = this_sum;

      if (verbosity > 1 && this_sum > 4)
      {
        std::cout << "CaloTriggerSim::process_event: FullCalo  0.8x0.8 tower eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << ieta << " ) / " << this_phi << " ( " << iphi << " ) / " << this_sum << std::endl;
      }

      if (this_sum > _FULLCALO_0p8x0p8_BEST_E)
      {
        _FULLCALO_0p8x0p8_BEST_E = this_sum;
        _FULLCALO_0p8x0p8_BEST_PHI = this_phi;
        _FULLCALO_0p8x0p8_BEST_ETA = this_eta;
      }
    }
  }

  if (verbosity > 0)
  {
    std::cout << "CaloTriggerSim::process_event: best FullCalo 0.8x0.8 window is at eta / phi = " << _FULLCALO_0p8x0p8_BEST_ETA << " / " << _FULLCALO_0p8x0p8_BEST_PHI << " and E = " << _FULLCALO_0p8x0p8_BEST_E << std::endl;
  }

  // reset fullcalo 1.0x1.0 map & best
  for (int ieta = 0; ieta < _FULLCALO_1p0x1p0_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_1p0x1p0_NPHI; iphi++)
    {
      _FULLCALO_1p0x1p0_MAP[ ieta ][ iphi ] = 0;
    }
  }

  _FULLCALO_1p0x1p0_BEST_E = 0;
  _FULLCALO_1p0x1p0_BEST_PHI = 0;
  _FULLCALO_1p0x1p0_BEST_ETA = 0;

  // now reconstruct (sliding) 1.0x1.0 map from 0.2x0.2 map
  for (int ieta = 0; ieta < _FULLCALO_1p0x1p0_NETA; ieta++)
  {
    for (int iphi = 0; iphi < _FULLCALO_1p0x1p0_NPHI; iphi++)
    {
      // for eta calculation, use position of corner tower and add 4.5
      // tower widths
      float this_eta = geomOH->get_etacenter(2 * ieta) + 4.5 * ( geomOH->get_etacenter( 1 ) - geomOH->get_etacenter( 0 ) );
      // for phi calculation, use position of corner tower and add 4.5
      // tower widths
      float this_phi = geomOH->get_phicenter(2 * iphi) + 4.5 * (geomOH->get_phicenter( 1 ) - geomOH->get_phicenter( 0 ) );

      float this_sum = 0;

      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][iphi];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][iphi];  // ieta + 1 is safe, since _FULLCALO_1p0x1p0_NETA = _FULLCALO_0p2x0p2_NETA - 4
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][iphi];  // ieta + 2 is safe, since _FULLCALO_1p0x1p0_NETA = _FULLCALO_0p2x0p2_NETA - 4
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][iphi];  // ieta + 3 is safe, since _FULLCALO_1p0x1p0_NETA = _FULLCALO_0p2x0p2_NETA - 4
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 4][iphi];  // ieta + 4 is safe, since _FULLCALO_1p0x1p0_NETA = _FULLCALO_0p2x0p2_NETA - 4

      // add 1 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 4][ ( iphi + 1 ) % _FULLCALO_0p2x0p2_NPHI ];
      // add 2 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 4][ ( iphi + 2 ) % _FULLCALO_0p2x0p2_NPHI ];
      // add 3 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 4][ ( iphi + 3 ) % _FULLCALO_0p2x0p2_NPHI ];
      // add 4 to phi, but take modulus w.r.t. _FULLCALO_0p2x0p2_NPHI
      // in case we have wrapped back around
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta][ ( iphi + 4 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 1][ ( iphi + 4 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 2][ ( iphi + 4 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 3][ ( iphi + 4 ) % _FULLCALO_0p2x0p2_NPHI ];
      this_sum += _FULLCALO_0p2x0p2_MAP[ieta + 4][ ( iphi + 4 ) % _FULLCALO_0p2x0p2_NPHI ];

      _FULLCALO_1p0x1p0_MAP[ieta][iphi] = this_sum;

      if (verbosity > 1 && this_sum > 5)
      {
        std::cout << "CaloTriggerSim::process_event: FullCalo  1.0x1.0 tower eta ( bin ) / phi ( bin ) / E = " << std::setprecision(6) << this_eta << " ( " << ieta << " ) / " << this_phi << " ( " << iphi << " ) / " << this_sum << std::endl;
      }

      if (this_sum > _FULLCALO_1p0x1p0_BEST_E)
      {
        _FULLCALO_1p0x1p0_BEST_E = this_sum;
        _FULLCALO_1p0x1p0_BEST_PHI = this_phi;
        _FULLCALO_1p0x1p0_BEST_ETA = this_eta;
      }
    }
  }

  if (verbosity > 0)
  {
    std::cout << "CaloTriggerSim::process_event: best FullCalo 1.0x1.0 window is at eta / phi = " << _FULLCALO_1p0x1p0_BEST_ETA << " / " << _FULLCALO_1p0x1p0_BEST_PHI << " and E = " << _FULLCALO_1p0x1p0_BEST_E << std::endl;
  }



  FillNode(topNode);

  if (verbosity > 0) std::cout << "CaloTriggerSim::process_event: exiting" << std::endl;

  return Fun4AllReturnCodes::EVENT_OK;
}
int PHG4GenFitTrackProjection::process_event(PHCompositeNode *topNode) {
	if (verbosity > 1)
		cout << "PHG4GenFitTrackProjection::process_event -- entered" << endl;

	//---------------------------------
	// Get Objects off of the Node Tree
	//---------------------------------

	// Pull the reconstructed track information off the node tree...
	SvtxTrackMap* _g4tracks = findNode::getClass<SvtxTrackMap>(topNode,
			"SvtxTrackMap");
	if (!_g4tracks) {
		cerr << PHWHERE << " ERROR: Can't find SvtxTrackMap." << endl;
		return Fun4AllReturnCodes::ABORTRUN;
	}

	for (int i = 0; i < _num_cal_layers; ++i) {

		if (std::isnan(_cal_radii[i]))
			continue;

		if (verbosity > 1)
			cout << "Projecting tracks into: " << _cal_names[i] << endl;

		// pull the tower geometry
		string towergeonodename = "TOWERGEOM_" + _cal_names[i];
		RawTowerGeomContainer *towergeo = findNode::getClass<
				RawTowerGeomContainer>(topNode, towergeonodename.c_str());
		if (!towergeo) {
			cerr << PHWHERE << " ERROR: Can't find node " << towergeonodename
					<< endl;
			return Fun4AllReturnCodes::ABORTRUN;
		}

		// pull the towers
		string towernodename = "TOWER_CALIB_" + _cal_names[i];
		RawTowerContainer *towerList = findNode::getClass<RawTowerContainer>(
				topNode, towernodename.c_str());
		if (!towerList) {
			cerr << PHWHERE << " ERROR: Can't find node " << towernodename
					<< endl;
			return Fun4AllReturnCodes::ABORTRUN;
		}

		// pull the clusters
		string clusternodename = "CLUSTER_" + _cal_names[i];
		RawClusterContainer *clusterList = findNode::getClass<
				RawClusterContainer>(topNode, clusternodename.c_str());
		if (!clusterList) {
			cerr << PHWHERE << " ERROR: Can't find node " << clusternodename
					<< endl;
			return Fun4AllReturnCodes::ABORTRUN;
		}

		// loop over all tracks
		for (SvtxTrackMap::Iter iter = _g4tracks->begin();
				iter != _g4tracks->end(); ++iter) {
			SvtxTrack *track = iter->second;
#ifdef DEBUG
			cout
			<<__LINE__
			<<": track->get_charge(): "<<track->get_charge()
			<<endl;
#endif
			if(!track) {
				if(verbosity >= 2) LogWarning("!track");
				continue;
			}

			if (verbosity > 1)
				cout << "projecting track id " << track->get_id() << endl;

			if (verbosity > 1) {
				cout << " track pt = " << track->get_pt() << endl;
			}

			std::vector<double> point;
			point.assign(3, -9999.);

			auto last_state_iter = --track->end_states();

			SvtxTrackState * trackstate = last_state_iter->second;

			if(!trackstate) {
				if(verbosity >= 2) LogWarning("!trackstate");
				continue;
			}

			auto pdg = unique_ptr<TDatabasePDG> (TDatabasePDG::Instance());
			int reco_charge = track->get_charge();
			int gues_charge = pdg->GetParticle(_pid_guess)->Charge();
			if(reco_charge*gues_charge<0) _pid_guess *= -1;
#ifdef DEBUG
			cout
			<<__LINE__
			<<": guess charge: " << gues_charge
			<<": reco charge: " << reco_charge
			<<": pid: " << _pid_guess
			<<": pT: " << sqrt(trackstate->get_px()*trackstate->get_px() + trackstate->get_py()*trackstate->get_py())
			<<endl;
#endif

			auto rep = unique_ptr<genfit::AbsTrackRep> (new genfit::RKTrackRep(_pid_guess));

			unique_ptr<genfit::MeasuredStateOnPlane> msop80 = nullptr;

			{
				TVector3 pos(trackstate->get_x(), trackstate->get_y(), trackstate->get_z());
				//pos.SetXYZ(0.01,0,0);

				TVector3 mom(trackstate->get_px(), trackstate->get_py(), trackstate->get_pz());
				//mom.SetXYZ(1,0,0);

				TMatrixDSym cov(6);
				for (int i = 0; i < 6; ++i) {
					for (int j = 0; j < 6; ++j) {
						cov[i][j] = trackstate->get_error(i, j);
					}
				}

				msop80 = unique_ptr<genfit::MeasuredStateOnPlane> (new genfit::MeasuredStateOnPlane(rep.get()));

				msop80->setPosMomCov(pos, mom, cov);
			}

#ifdef DEBUG
			{
				double x = msop80->getPos().X();
				double y = msop80->getPos().Y();
				double z = msop80->getPos().Z();
//				double px = msop80->getMom().X();
//				double py = msop80->getMom().Y();
				double pz = msop80->getMom().Z();
				genfit::FieldManager *field_mgr = genfit::FieldManager::getInstance();
				double Bx=0, By=0, Bz=0;
				field_mgr->getFieldVal(x,y,z,Bx,By,Bz);
				cout
				<< __LINE__
				<< ": { " << msop80->getPos().Perp() << ", " << msop80->getPos().Phi() << ", " << msop80->getPos().Eta() << "} @ "
				//<< "{ " << Bx << ", " << By << ", " << Bz << "}"
				<< "{ " << msop80->getMom().Perp() << ", " << msop80->getMom().Phi() << ", " << pz << "} "
				<<endl;
				//msop80->Print();
			}
#endif
			try {
				rep->extrapolateToCylinder(*msop80, _cal_radii[i], TVector3(0,0,0),  TVector3(0,0,1));
				//rep->extrapolateToCylinder(*msop80, 5., TVector3(0,0,0),  TVector3(0,0,1));
			} catch (...) {
				if(verbosity >= 2) LogWarning("extrapolateToCylinder failed");
				continue;
			}

#ifdef DEBUG
			{
				cout<<__LINE__<<endl;
				//msop80->Print();
				double x = msop80->getPos().X();
				double y = msop80->getPos().Y();
				double z = msop80->getPos().Z();
//				double px = msop80->getMom().X();
//				double py = msop80->getMom().Y();
				double pz = msop80->getMom().Z();
				genfit::FieldManager *field_mgr = genfit::FieldManager::getInstance();
				double Bx=0, By=0, Bz=0;
				field_mgr->getFieldVal(x,y,z,Bx,By,Bz);
				cout
				<< __LINE__
				<< ": { " << msop80->getPos().Perp() << ", " << msop80->getPos().Phi() << ", " << msop80->getPos().Eta() << "} @ "
				//<< "{ " << Bx << ", " << By << ", " << Bz << "}"
				<< "{ " << msop80->getMom().Perp() << ", " << msop80->getMom().Phi() << ", " << pz << "} "
				<<endl;
			}
#endif

			point[0] = msop80->getPos().X();
			point[1] = msop80->getPos().Y();
			point[2] = msop80->getPos().Z();

#ifdef DEBUG
			cout
			<<__LINE__
			<<": GenFit: {"
			<< point[0] <<", "
			<< point[1] <<", "
			<< point[2] <<" }"
			<<endl;
#endif

			if (std::isnan(point[0]))
				continue;
			if (std::isnan(point[1]))
				continue;
			if (std::isnan(point[2]))
				continue;

			double x = point[0];
			double y = point[1];
			double z = point[2];

			double phi = atan2(y, x);
			double eta = asinh(z / sqrt(x * x + y * y));

			if (verbosity > 1) {
				cout << " initial track phi = " << track->get_phi();
				cout << ", eta = " << track->get_eta() << endl;
				cout << " calorimeter phi = " << phi << ", eta = " << eta
						<< endl;
			}

			// projection is outside the detector extent
			// TODO towergeo doesn't make this easy to extract, but this should be
			// fetched from the node tree instead of hardcoded
			if (fabs(eta) >= 1.0)
				continue;

			// calculate 3x3 tower energy
			int binphi = towergeo->get_phibin(phi);
			int bineta = towergeo->get_etabin(eta);

			double energy_3x3 = 0.0;
			double energy_5x5 = 0.0;
			for (int iphi = binphi - 2; iphi <= binphi + 2; ++iphi) {
				for (int ieta = bineta - 2; ieta <= bineta + 2; ++ieta) {

					// wrap around
					int wrapphi = iphi;
					if (wrapphi < 0) {
						wrapphi = towergeo->get_phibins() + wrapphi;
					}
					if (wrapphi >= towergeo->get_phibins()) {
						wrapphi = wrapphi - towergeo->get_phibins();
					}

					// edges
					if (ieta < 0)
						continue;
					if (ieta >= towergeo->get_etabins())
						continue;

					RawTower* tower = towerList->getTower(ieta, wrapphi);
					if (tower) {

						energy_5x5 += tower->get_energy();
						if (abs(iphi - binphi) <= 1 and abs(ieta - bineta) <= 1)
							energy_3x3 += tower->get_energy();

						if (verbosity > 1)
							cout << " tower " << ieta << " " << wrapphi
									<< " energy = " << tower->get_energy()
									<< endl;
					}
				}
			}

			track->set_cal_energy_3x3(_cal_types[i], energy_3x3);
			track->set_cal_energy_5x5(_cal_types[i], energy_5x5);

			// loop over all clusters and find nearest
			double min_r = DBL_MAX;
			double min_index = -9999;
			double min_dphi = NAN;
			double min_deta = NAN;
			double min_e = NAN;
#ifdef DEBUG
			double min_cluster_phi = NAN;
#endif
			for (unsigned int k = 0; k < clusterList->size(); ++k) {

				RawCluster *cluster = clusterList->getCluster(k);

				double dphi = atan2(sin(phi - cluster->get_phi()),
						cos(phi - cluster->get_phi()));
				double deta = eta - cluster->get_eta();
				double r = sqrt(pow(dphi, 2) + pow(deta, 2));

				if (r < min_r) {
					min_index = k;
					min_r = r;
					min_dphi = dphi;
					min_deta = deta;
					min_e = cluster->get_energy();
#ifdef DEBUG
					min_cluster_phi = cluster->get_phi();
#endif
				}
			}

			if (min_index != -9999) {
				track->set_cal_dphi(_cal_types[i], min_dphi);
				track->set_cal_deta(_cal_types[i], min_deta);
				track->set_cal_cluster_id(_cal_types[i], min_index);
				track->set_cal_cluster_e(_cal_types[i], min_e);

#ifdef DEBUG
			cout
			<<__LINE__
			<<": min_cluster_phi: "<<min_cluster_phi
			<<endl;
#endif

				if (verbosity > 1) {
					cout << " nearest cluster dphi = " << min_dphi << " deta = "
							<< min_deta << " e = " << min_e << endl;
				}
			}

		} // end track loop
	} // end calorimeter layer loop

	if (verbosity > 1)
		cout << "PHG4GenFitTrackProjection::process_event -- exited" << endl;

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