int PHG4SvtxMomentumRecal::process_event(PHCompositeNode *topNode)
{
  if(Verbosity() > 1) cout << "PHG4SvtxMomentumRecal::process_event -- entered" << endl;

  if (!_corr) return Fun4AllReturnCodes::EVENT_OK;
  
  //---------------------------------
  // 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;
  }
    
  // loop over all tracks
  for (SvtxTrackMap::Iter iter = _g4tracks->begin();
       iter != _g4tracks->end();
       ++iter) {
    SvtxTrack *track = iter->second;
    
    double rescale = 1.0;

    double pt = track->get_pt();
    
    double xmin = 0.0;
    double xmax = 0.0;
    _corr->GetRange(xmin,xmax);
      
    if ((pt > xmin)&&(pt < xmax)) {
      rescale = _corr->Eval(pt);
    }

    track->set_px( track->get_px() * rescale );
    track->set_py( track->get_py() * rescale );
    track->set_pz( track->get_pz() * rescale );
  } // end track loop

  if (Verbosity() > 1) cout << "PHG4SvtxMomentumRecal::process_event -- exited" << endl;

  return Fun4AllReturnCodes::EVENT_OK;
}
int PHG4SvtxTrackProjection::process_event(PHCompositeNode *topNode)
{
  if(verbosity > 1) cout << "PHG4SvtxTrackProjection::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 (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];
    RawTowerGeom *towergeo = findNode::getClass<RawTowerGeom>(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;

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

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

      // curved tracks inside mag field
      // straight projections thereafter
      std::vector<double> point;
      point.assign(3,-9999.);
      //if (_cal_radii[i] < _mag_extent) {
      // curved projections inside field

      _hough.projectToRadius(track,_magfield,_cal_radii[i],point);

      if (isnan(point[0])) continue;
      if (isnan(point[1])) continue;
      if (isnan(point[2])) continue;
      // } else {
      // 	// straight line projections after mag field exit
      // 	_hough.projectToRadius(track,_mag_extent-0.05,point);
      // 	if (isnan(point[0])) continue;
      // 	if (isnan(point[1])) continue;
      // 	if (isnan(point[2])) continue;

      // 	std::vector<double> point2;
      // 	point2.assign(3,-9999.);
      // 	_hough.projectToRadius(track,_mag_extent+0.05,point2);
      // 	if (isnan(point2[0])) continue;
      // 	if (isnan(point2[1])) continue;
      // 	if (isnan(point2[2])) continue;

      // 	// find intersection of r and z


      // find x,y of intersection
      //}
      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;
      for (int iphi = binphi-1; iphi < binphi+2; ++iphi) { 
      	for (int ieta = bineta-1; 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_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);

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

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

	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 << "PHG4SvtxTrackProjection::process_event -- exited" << 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 SvtxSimPerformanceCheckReco::process_event(PHCompositeNode *topNode) {

  ++_event;
  
  // need things off of the DST...
  PHG4TruthInfoContainer* truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode,"G4TruthInfo");
  if (!truthinfo) {
    cerr << PHWHERE << " ERROR: Can't find G4TruthInfo" << endl;
    exit(-1);
  }

  SvtxTrackMap* trackmap = findNode::getClass<SvtxTrackMap>(topNode,"SvtxTrackMap");
  if (!trackmap) {
    cerr << PHWHERE << " ERROR: Can't find SvtxTrackMap" << endl;
    exit(-1);
  }

  SvtxVertexMap* vertexmap = findNode::getClass<SvtxVertexMap>(topNode,"SvtxVertexMap");
  if (!vertexmap) {
    cerr << PHWHERE << " ERROR: Can't find SvtxVertexMap" << endl;
    exit(-1);
  }

  // create SVTX eval stack
  SvtxEvalStack svtxevalstack(topNode);

  SvtxVertexEval*   vertexeval = svtxevalstack.get_vertex_eval();
  SvtxTrackEval*     trackeval = svtxevalstack.get_track_eval();
  SvtxTruthEval*     trutheval = svtxevalstack.get_truth_eval();
  
  // loop over all truth particles
  PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange();
  for (PHG4TruthInfoContainer::ConstIterator iter = range.first; 
       iter != range.second; 
       ++iter) {
    PHG4Particle* g4particle = iter->second;
    if (trutheval->get_embed(g4particle) <= 0) continue;
    
    std::set<PHG4Hit*> g4hits = trutheval->all_truth_hits(g4particle);     
    float ng4hits = g4hits.size();  

    float truept = sqrt(pow(g4particle->get_px(),2)+pow(g4particle->get_py(),2));
    
    // examine truth particles that leave 7 detector hits
    if (ng4hits == _nlayers) {
      _truept_particles_leaving7Hits->Fill(truept);
    
      SvtxTrack* track = trackeval->best_track_from(g4particle);
    
      if (!track) {continue;}
      
      unsigned int nfromtruth = trackeval->get_nclusters_contribution(track,g4particle);
      float recopt = track->get_pt();

      unsigned int ndiff = abs((int)nfromtruth-(int)_nlayers);
      if (ndiff <= 2) {
	_truept_particles_recoWithin2Hits->Fill(truept);
      }
      if (ndiff <= 1) {
	_truept_particles_recoWithin1Hit->Fill(truept);
      }
      if (ndiff == 0) {
	_truept_particles_recoWithExactHits->Fill(truept);
      } 

      unsigned int layersfromtruth = trackeval->get_nclusters_contribution_by_layer(track,g4particle);
      unsigned int innerhits = (layersfromtruth & _inner_layer_mask);
      unsigned int ninnerhitsfromtruth = 0;
      unsigned int ninnerlayers = 0;
      for (unsigned int i = 0; i < 32; ++i) {
	ninnerhitsfromtruth += (0x1 & (innerhits >> i));
	ninnerlayers += (0x1 & (_inner_layer_mask >> i));
      }
      
      ndiff = abs((int)ninnerhitsfromtruth-(int)ninnerlayers);
      if (ndiff <= 2) {
	_truept_particles_recoWithin2InnerHits->Fill(truept);
      }
      if (ndiff <= 1) {
	_truept_particles_recoWithin1InnerHit->Fill(truept);
      }
      if (ndiff == 0) {
	_truept_particles_recoWithExactInnerHits->Fill(truept);
      } 
      
      float diff = fabs(recopt-truept)/truept;
      if (diff < 0.05) {
	_truept_particles_recoWithin5Percent->Fill(truept);
      }
      if (diff < 0.04) {
	_truept_particles_recoWithin4Percent->Fill(truept);
	_truept_quality_particles_recoWithin4Percent->Fill(truept,track->get_quality());
      }
      if (diff < 0.03) {
	_truept_particles_recoWithin3Percent->Fill(truept);
      }      
    }    
  }
int SimpleTrackingAnalysis::process_event(PHCompositeNode *topNode)
{

  // --- This is the class process_event method
  // --- This is where the bulk of the analysis is done
  // --- Here we get the various data nodes we need to do the analysis
  // --- Then we use variables (accessed through class methods) to perform calculations

  if ( verbosity > -1 )
    {
      cout << endl;
      cout << "------------------------------------------------------------------------------------" << endl;
      cout << "Now processing event number " << nevents << endl; // would be good to add verbosity switch
    }

  ++nevents; // You may as youtself, why ++nevents (pre-increment) rather
  // than nevents++ (post-increment)?  The short answer is performance.
  // For simple types it probably doesn't matter, but it can really help
  // for complex types (like the iterators below).


  // --- Truth level information
  PHG4TruthInfoContainer* truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode,"G4TruthInfo");
  if ( !truthinfo )
    {
      cerr << PHWHERE << " ERROR: Can't find G4TruthInfo" << endl;
      exit(-1);
    }

  // --- SvtxTrackMap
  SvtxTrackMap* trackmap = findNode::getClass<SvtxTrackMap>(topNode,"SvtxTrackMap");
  if ( !trackmap )
    {
      cerr << PHWHERE << " ERROR: Can't find SvtxTrackMap" << endl;
      exit(-1);
    }

  // --- SvtxVertexMap
  SvtxVertexMap* vertexmap = findNode::getClass<SvtxVertexMap>(topNode,"SvtxVertexMap");
  if ( !vertexmap )
    {
      cerr << PHWHERE << " ERROR: Can't find SvtxVertexMap" << endl;
      exit(-1);
    }



  // --- Create SVTX eval stack
  SvtxEvalStack svtxevalstack(topNode);
  // --- Get evaluator objects from the eval stack
  SvtxVertexEval*   vertexeval = svtxevalstack.get_vertex_eval();
  SvtxTrackEval*     trackeval = svtxevalstack.get_track_eval();
  SvtxTruthEval*     trutheval = svtxevalstack.get_truth_eval();



  if ( verbosity > 0 ) cout << "Now going to loop over truth partcles..." << endl; // need verbosity switch

  // --- Loop over all truth particles
  PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange();
  for ( PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter )
    {
      PHG4Particle* g4particle = iter->second; // You may ask yourself, why second?
      // In C++ the iterator is a map, which has two members
      // first is the key (analogous the index of an arry),
      // second is the value (analogous to the value stored for the array index)
      int particleID = g4particle->get_pid();

      if ( trutheval->get_embed(g4particle) <= 0 && fabs(particleID) == 11 && verbosity > 0 )
        {
          cout << "NON EMBEDDED ELECTRON!!!  WHEE!!! " << particleID << " " << iter->first << endl;
        }

      if ( trutheval->get_embed(g4particle) <= 0 ) continue; // only look at embedded particles // no good for hits files
      bool iselectron = fabs(particleID) == 11;
      bool ispion = fabs(particleID) == 211;
      if ( verbosity > 0 ) cout << "embedded particle ID is " << particleID << " ispion " << ispion << " iselectron " << iselectron << " " << iter->first << endl;

      set<PHG4Hit*> g4hits = trutheval->all_truth_hits(g4particle);
      float ng4hits = g4hits.size();

      float truept = sqrt(pow(g4particle->get_px(),2)+pow(g4particle->get_py(),2));
      float true_energy = g4particle->get_e();

      // --- Get the reconsructed SvtxTrack based on the best candidate from the truth info
      SvtxTrack* track = trackeval->best_track_from(g4particle);
      if (!track) continue;
      float recopt = track->get_pt();
      float recop = track->get_p();

      if ( verbosity > 0 )
	{
	  cout << "truept is " << truept << endl;
	  cout << "recopt is " << recopt << endl;
	  cout << "true energy is " << true_energy << endl;
	}

      // --- energy variables directly from the track object
      float emc_energy_track = track->get_cal_energy_3x3(SvtxTrack::CEMC);
      float hci_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALIN);
      float hco_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALOUT);

      if ( verbosity > 0 )
	{
	  cout << "emc_energy_track is " << emc_energy_track << endl;
	  cout << "hci_energy_track is " << hci_energy_track << endl;
	  cout << "hco_energy_track is " << hco_energy_track << endl;
	}

      // -------------------------------------------------------------------------------------
      // --- IMPORTANT NOTE: according to Jin, dphi and deta will not work correctly in HIJING

      float emc_dphi_track = track->get_cal_dphi(SvtxTrack::CEMC);
      float hci_dphi_track = track->get_cal_dphi(SvtxTrack::HCALIN);
      float hco_dphi_track = track->get_cal_dphi(SvtxTrack::HCALOUT);

      float emc_deta_track = track->get_cal_deta(SvtxTrack::CEMC);
      float hci_deta_track = track->get_cal_deta(SvtxTrack::HCALIN);
      float hco_deta_track = track->get_cal_deta(SvtxTrack::HCALOUT);

      float assoc_dphi = 0.1; // adjust as needed, consider class set method
      float assoc_deta = 0.1; // adjust as needed, consider class set method
      bool good_emc_assoc = fabs(emc_dphi_track) < assoc_dphi && fabs(emc_deta_track) < assoc_deta;
      bool good_hci_assoc = fabs(hci_dphi_track) < assoc_dphi && fabs(hci_deta_track) < assoc_deta;
      bool good_hco_assoc = fabs(hco_dphi_track) < assoc_dphi && fabs(hco_deta_track) < assoc_deta;

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


      float hct_energy_track = 0;
      if ( hci_energy_track >= 0 ) hct_energy_track += hci_energy_track;
      if ( hco_energy_track >= 0 ) hct_energy_track += hco_energy_track;

      float total_energy_dumb = 0;
      if ( emc_energy_track >= 0 ) total_energy_dumb += emc_energy_track;
      if ( hci_energy_track >= 0 ) total_energy_dumb += hci_energy_track;
      if ( hco_energy_track >= 0 ) total_energy_dumb += hco_energy_track;

      float total_energy_smart = 0;
      if ( good_emc_assoc ) total_energy_smart += emc_energy_track;
      if ( good_hci_assoc ) total_energy_smart += hci_energy_track;
      if ( good_hco_assoc ) total_energy_smart += hco_energy_track;



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

      //cout << "starting the main part of the truth analysis" << endl;

      // examine truth particles that leave all (7 or 8 depending on design) detector hits
      if ( ng4hits == nlayers )
	{
	  _truept_particles_leavingAllHits->Fill(truept);

	  unsigned int nfromtruth = trackeval->get_nclusters_contribution(track,g4particle);

	  unsigned int ndiff = abs((int)nfromtruth-(int)nlayers);
	  if ( ndiff <= 2 ) _truept_particles_recoWithin2Hits->Fill(truept);
	  if ( ndiff <= 1 ) _truept_particles_recoWithin1Hit->Fill(truept);
	  if ( ndiff == 0 ) _truept_particles_recoWithExactHits->Fill(truept);

	  float diff = fabs(recopt-truept)/truept;
	  if ( diff < 0.05 ) _truept_particles_recoWithin5Percent->Fill(truept);
	  if ( diff < 0.04 )
	    {
	      _truept_particles_recoWithin4Percent->Fill(truept);
	      _truept_quality_particles_recoWithin4Percent->Fill(truept,track->get_quality());
	    }
	  if ( diff < 0.03 ) _truept_particles_recoWithin3Percent->Fill(truept);

          double good_energy = total_energy_dumb - 3.14;


          double eoverp = good_energy/recop;
          double sigmapt = 0.011 + 0.0008*recopt;
          th2d_truept_particles_withcalocuts_leavingAllHits->Fill(truept,eoverp);
          if ( ndiff <= 2 ) th2d_truept_particles_withcalocuts_recoWithin2Hits->Fill(truept,eoverp);
          if ( ndiff <= 1 ) th2d_truept_particles_withcalocuts_recoWithin1Hit->Fill(truept,eoverp);
          if ( ndiff == 0 ) th2d_truept_particles_withcalocuts_recoWithExactHits->Fill(truept,eoverp);
          if ( diff < 0.05 ) th2d_truept_particles_withcalocuts_recoWithin5Percent->Fill(truept,eoverp);
          if ( diff < 0.04 ) th2d_truept_particles_withcalocuts_recoWithin4Percent->Fill(truept,eoverp);
          if ( diff < 0.03 ) th2d_truept_particles_withcalocuts_recoWithin3Percent->Fill(truept,eoverp);
          if ( diff < 1.0*sigmapt ) th2d_truept_particles_withcalocuts_recoWithin1Sigma->Fill(recopt,eoverp);
          if ( diff < 2.0*sigmapt ) th2d_truept_particles_withcalocuts_recoWithin2Sigma->Fill(recopt,eoverp);
          if ( diff < 3.0*sigmapt ) th2d_truept_particles_withcalocuts_recoWithin3Sigma->Fill(recopt,eoverp);


	} // end of requirement of ng4hits == nlayers

    } // end of loop over truth particles



  // loop over all reco particles
  int ntracks = 0;
  for ( SvtxTrackMap::Iter iter = trackmap->begin(); iter != trackmap->end(); ++iter )
    {

      // --- Get the StxTrack object (from the iterator)
      SvtxTrack* track = iter->second;
      float recopt = track->get_pt();
      float recop = track->get_p();

      // --- Get the truth particle from the evaluator
      PHG4Particle* g4particle = trackeval->max_truth_particle_by_nclusters(track);
      float truept = sqrt(pow(g4particle->get_px(),2)+pow(g4particle->get_py(),2));
      int particleID = g4particle->get_pid();
      if ( verbosity > 5 ) cout << "particle ID is " << particleID << endl;
      bool iselectron = fabs(particleID) == 11;
      bool ispion = fabs(particleID) == 211;

      // ---------------------
      // --- calorimeter stuff
      // ---------------------

      // --- get the energy values directly from the track
      float emc_energy_track = track->get_cal_energy_3x3(SvtxTrack::CEMC);
      float hci_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALIN);
      float hco_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALOUT);

      float total_energy = 0;
      if ( emc_energy_track > 0 ) total_energy += emc_energy_track;
      if ( hci_energy_track > 0 ) total_energy += hci_energy_track;
      if ( hco_energy_track > 0 ) total_energy += hco_energy_track;

      if ( verbosity > 2 ) cout << "total calo energy is " << total_energy << endl;

      if (trutheval->get_embed(g4particle) > 0)
	{
	  // embedded results (quality or performance measures)
	  _truept_dptoverpt->Fill(truept,(recopt-truept)/truept);
	  _truept_dca->Fill(truept,track->get_dca2d());
	  _recopt_quality->Fill(recopt,track->get_quality());
          if ( verbosity > 0 ) cout << "embedded particle ID is " << particleID << " ispion " << ispion << " iselectron " << iselectron << endl;
          // ---
	} // end if (embedded results)
      else
	{
          // electron and pion (hadron) id

	  // non-embedded results (purity measures)
	  _recopt_tracks_all->Fill(recopt);
	  _recopt_quality_tracks_all->Fill(recopt,track->get_quality());

	  unsigned int nfromtruth = trackeval->get_nclusters_contribution(track,g4particle);

	  unsigned int ndiff = abs((int)nfromtruth-(int)nlayers);
	  if ( ndiff <= 2 ) _recopt_tracks_recoWithin2Hits->Fill(recopt);
	  if ( ndiff <= 1 ) _recopt_tracks_recoWithin1Hit->Fill(recopt);
	  if ( ndiff == 0 ) _recopt_tracks_recoWithExactHits->Fill(recopt);

	  float diff = fabs(recopt-truept)/truept;
	  if ( diff < 0.05 ) _recopt_tracks_recoWithin5Percent->Fill(recopt);
	  if ( diff < 0.04 )
	    {
	      _recopt_tracks_recoWithin4Percent->Fill(recopt);
	      _recopt_quality_tracks_recoWithin4Percent->Fill(recopt,track->get_quality());
	    }
	  if ( diff < 0.03 ) _recopt_tracks_recoWithin3Percent->Fill(recopt);


	  // --------------------------------------
	  // --- same but now with calorimeter cuts
	  // --------------------------------------

          double good_energy = total_energy - 3.14;

          double eoverp = good_energy/recop;
          double sigmapt = 0.011 + 0.0008*recopt;
          th2d_recopt_tracks_withcalocuts_all->Fill(recopt,eoverp);
          if ( ndiff <= 2 ) th2d_recopt_tracks_withcalocuts_recoWithin2Hits->Fill(recopt,eoverp);
          if ( ndiff <= 1 ) th2d_recopt_tracks_withcalocuts_recoWithin1Hit->Fill(recopt,eoverp);
          if ( ndiff == 0 ) th2d_recopt_tracks_withcalocuts_recoWithExactHits->Fill(recopt,eoverp);
          if ( diff < 0.05 ) th2d_recopt_tracks_withcalocuts_recoWithin5Percent->Fill(recopt,eoverp);
          if ( diff < 0.04 ) th2d_recopt_tracks_withcalocuts_recoWithin4Percent->Fill(recopt,eoverp);
          if ( diff < 0.03 ) th2d_recopt_tracks_withcalocuts_recoWithin3Percent->Fill(recopt,eoverp);
          if ( diff < 1.0*sigmapt ) th2d_recopt_tracks_withcalocuts_recoWithin1Sigma->Fill(recopt,eoverp);
          if ( diff < 2.0*sigmapt ) th2d_recopt_tracks_withcalocuts_recoWithin2Sigma->Fill(recopt,eoverp);
          if ( diff < 3.0*sigmapt ) th2d_recopt_tracks_withcalocuts_recoWithin3Sigma->Fill(recopt,eoverp);

	  // --- done with reco tracks

	} // else (non-embedded results)

      ++ntracks;
    } // loop over reco tracks


  hmult->Fill(ntracks);

  // --- Get the leading vertex
  SvtxVertex* maxvertex = NULL;
  unsigned int maxtracks = 0;
  for ( SvtxVertexMap::Iter iter = vertexmap->begin(); iter != vertexmap->end(); ++iter )
    {
      SvtxVertex* vertex = iter->second;
      if ( vertex->size_tracks() > maxtracks )
	{
	  maxvertex = vertex;
	  maxtracks = vertex->size_tracks();
	}
    }
  if ( !maxvertex )
    {
      cerr << PHWHERE << " ERROR: cannot get reconstructed vertex (event number " << nevents << ")" << endl;
      ++nerrors;
      return Fun4AllReturnCodes::DISCARDEVENT;
    }

  // --- Get the coordinates for the vertex from the evaluator
  PHG4VtxPoint* point = vertexeval->max_truth_point_by_ntracks(maxvertex);
  if ( !point )
    {
      cerr << PHWHERE << " ERROR: cannot get truth vertex (event number " << nevents << ")" << endl;
      ++nerrors;
      return Fun4AllReturnCodes::DISCARDEVENT;
    }
  _dx_vertex->Fill(maxvertex->get_x() - point->get_x());
  _dy_vertex->Fill(maxvertex->get_y() - point->get_y());
  _dz_vertex->Fill(maxvertex->get_z() - point->get_z());

  hmult_vertex->Fill(ntracks);



  return Fun4AllReturnCodes::EVENT_OK;

}