// $Id$ // // File: DVertex_factory.cc // Created: Tue Apr 6 17:01:54 EDT 2010 // Creator: davidl (on Darwin Amelia.local 9.8.0 i386) // #include #include using namespace std; #include #include #include "DVertex_factory.h" #include "TRACKING/DTrackFitter.h" using namespace jana; bool static DVertex_hypothesis_cmp(DVertex::track_info_t a, DVertex::track_info_t b) { return (a.FOM>b.FOM); } //------------------ // init //------------------ jerror_t DVertex_factory::init(void) { return NOERROR; } //------------------ // brun //------------------ jerror_t DVertex_factory::brun(jana::JEventLoop *loop, int runnumber) { // Initialize to reasonable defaults target_length = 0.0; target_z = 0.0; // Get Target parameters from XML DApplication *dapp = dynamic_cast (loop->GetJApplication()); DGeometry *geom = dapp ? dapp->GetDGeometry(runnumber):NULL; if(geom){ geom->GetTargetLength(target_length); geom->GetTargetZ(target_z); } // Get the particle ID algorithms vector pid_algorithms; loop->Get(pid_algorithms); if(pid_algorithms.size()<1){ _DBG_<<"Unable to get a DParticleID object! NO PID will be done!"<(pid_algorithms[0]); // Warn user if something happened that caused us NOT to get a pid_algorithm object pointer if(!pid_algorithm){ _DBG_<<"Unable to get a DParticleID object! NO PID will be done!"<Lock(); fcal_match= (TH2F *)gROOT->FindObject("fcal_match"); if (!fcal_match) fcal_match=new TH2F("fcal_match","#delta r vs p for FCAL/track matching",100,0,10,100,0,20); fcal_dt=(TH2F *)gROOT->FindObject("fcal_dt"); if (!fcal_dt) fcal_dt=new TH2F("fcal_dt","projected time at target for FCAL vs momentum",100,0,10,100,-10,10.); dapp->Unlock(); } return NOERROR; } //------------------ // evnt //------------------ jerror_t DVertex_factory::evnt(JEventLoop *loop, int eventnumber) { this->eventnumber=eventnumber; // clear the list of orphan showers orphan_showers.clear(); // Get list of all charged tracks vector tracks; loop->Get(tracks); // Get ToF points vectortof_points; loop->Get(tof_points); // Get BCAL and FCAL showers vectorbcal_showers; eventLoop->Get(bcal_showers, "KLOE" ); vectorfcal_showers; eventLoop->Get(fcal_showers); // group tracks according to candidate id vector >tracks_by_candidate; pid_algorithm->GroupTracks(tracks,tracks_by_candidate); // To minimize memory usage and time in allocation, we maintain a // pool of vertexInfo_t objects. Make sure the pool is large enough to hold // all of the particles we have in this event. unsigned int Nparticles_total =tracks_by_candidate.size()+bcal_showers.size() +fcal_showers.size(); for(unsigned int i=vertexInfos_pool.size(); iSetLimits(tmin, tmax, zmin, zmax, Nbinst, Nbinsz); vertexInfos_pool.push_back(vi); } // Periodically delete some vertexInfo_t objects if the pool gets too large. // This prevents memory-leakage-like behavor. if((Nparticles_total < MAX_VERTEXINFOS) && (vertexInfos_pool.size()>MAX_VERTEXINFOS)){ for(unsigned int i=MAX_VERTEXINFOS; ibcal_matches(remaining_bcal_showers); // Creat a vector to keep track of the FCAL showers that have been matched // to tracks and keep track of how many are left unsigned int remaining_fcal_showers=fcal_showers.size(); vectorfcal_matches(remaining_fcal_showers); // Find the time at the vertex by locking to the RF clock and match the // tracks with the outer detectors. If a match is found, compute a FOM for // quality of the PID from the time projected from the outer detector back // toward the vertex. for (unsigned int i=0;i<_data.size();i++){ // Match vertex time to RF bucket double corrected_rf_time=(_data[i]->x.Z()-target_z)/SPEED_OF_LIGHT; double tdiff=corrected_rf_time-_data[i]->x.T(); if (tdiff<-1.){ _data[i]->x.SetT(corrected_rf_time-2.); } else if (tdiff>1.){ _data[i]->x.SetT(corrected_rf_time+2.); } else{ _data[i]->x.SetT(corrected_rf_time); } // Here we loop over the mass hypotheses for each track for (unsigned int j=0;j<_data[i]->hypotheses.size();j++){ vector&tracks=_data[i]->hypotheses[j]; for (unsigned int k=0;kMatchToBCAL(tracks[k].track->rt, DTrackFitter::kTimeBased, bcal_showers,tproj, bcal_id) ==NOERROR){ // Store this shower in the showers vector if (bcal_matches[bcal_id]!=1){ _data[i]->showers.push_back(DVertex::shower_info_t(bcal_showers[bcal_id], tracks[k].track)); // Decrement the shower counter remaining_bcal_showers--; } bcal_matches[bcal_id]=1; matched_outer_detector=true; tracks[k].tprojected=tproj; tdiff=tproj-_data[i]->x.T(); double p=tracks[k].track->momentum().Mag(); double bcal_sigma=0.00255*pow(p,-2.52)+0.220; double bcal_chi2=tdiff*tdiff/(bcal_sigma*bcal_sigma); tracks[k].FOM=TMath::Prob(tracks[k].track->chi2_dedx+bcal_chi2,2); } else if (pid_algorithm->MatchToTOF(tracks[k].track->rt, DTrackFitter::kTimeBased, tof_points,tproj, tof_id) ==NOERROR){ matched_outer_detector=true; tracks[k].tprojected=tproj; tdiff=tproj-_data[i]->x.T(); double tof_sigma=0.08; double tof_chi2=tdiff*tdiff/(tof_sigma*tof_sigma); tracks[k].FOM=TMath::Prob(tracks[k].track->chi2_dedx+tof_chi2,2); } if (pid_algorithm->MatchToFCAL(tracks[k].track->rt, DTrackFitter::kTimeBased, fcal_showers,tproj, fcal_id,dmin) ==NOERROR){ if (matched_outer_detector==false){ // Store this shower in the showers vector if (fcal_matches[fcal_id]!=1){ _data[i]->showers.push_back(DVertex::shower_info_t(fcal_showers[fcal_id], tracks[k].track)); // Decrement the shower counter remaining_fcal_showers--; } fcal_matches[fcal_id]=1; matched_outer_detector=true; tracks[k].tprojected=tproj-2.218; // correction determine from fit to simulated data tdiff=tproj-2.218-_data[i]->x.T(); double fcal_sigma=0.6; // straight-line fit to high momentum data double fcal_chi2=tdiff*tdiff/(fcal_sigma*fcal_sigma); tracks[k].FOM=TMath::Prob(tracks[k].track->chi2_dedx+fcal_chi2,2); } if (DEBUG_HISTS){ TH2F *fcal_dt=(TH2F*)gROOT->FindObject("fcal_dt"); if (fcal_dt) fcal_dt->Fill(tracks[k].track->momentum().Mag(),tproj); } } if (DEBUG_HISTS){ TH2F *fcal_match=(TH2F *) gROOT->FindObject("fcal_match"); if (fcal_match) fcal_match->Fill(tracks[k].track->momentum().Mag(), dmin); } // If we did not succeed in matching to an outer detector, we are are // left with only the track info (dedx, chi2) for the FOM... if (matched_outer_detector==false){ tracks[k].FOM=tracks[k].track->FOM; } } // Sort hypotheses according to figure of merit sort(tracks.begin(),tracks.end(),DVertex_hypothesis_cmp); }// loop over tracks } // Vector to hold list of vertexInfo_t objects for all unmatched showers vector vertices; if (remaining_bcal_showers>0){ for (unsigned int i=0;i0){ for (unsigned int i=0;ibcal!=NULL && vi->is_matched_to_vertex==false){ double tflight=(DVector3(vi->bcal->x,vi->bcal->y,vi->bcal->z) -_data[i]->x.Vect()).Mag()/SPEED_OF_LIGHT; vi->t-=tflight; vi->Fill(vi->t,vi->sigmat,vi->z,vi->sigmaz); } if (vi->fcal!=NULL && vi->is_matched_to_vertex==false){ double tflight=(vi->fcal->getCentroid()-_data[i]->x.Vect()).Mag() /SPEED_OF_LIGHT; vi->t-=tflight; vi->Fill(vi->t,vi->sigmat,vi->z,vi->sigmaz); } } // Group photons together by time vector< vector > groups; AssignParticlesToGroups(vertices,groups); // Try to associate a group of photons with this vertex double t0=0.; double sum_invar=0, invar=0; for (unsigned int k=0;k &group = groups[k]; for (unsigned int m=0;msigmat*group[m]->sigmat); sum_invar+=invar; t0+=group[m]->t*invar; } t0*=1./sum_invar; double t_sigma_photons=1./sqrt(sum_invar); double t_sigma_tot=sqrt(t_sigma_photons*t_sigma_photons +_data[i]->t_sigma*_data[i]->t_sigma); if (fabs(t0-_data[i]->x.T())/t_sigma_tot<3.0){ for (unsigned int m=0;mshowers.push_back(DVertex::shower_info_t(group[m]->bcal,group[m]->fcal)); // Flag that we have associated the showers in this group with a // vertex group[m]->is_matched_to_vertex=true; // Decrement the bcal and fcal shower counters if (group[m]->fcal!=NULL){ fcal_matches[group[m]->fcal_index]=1; remaining_fcal_showers--; } if (group[m]->bcal!=NULL){ bcal_matches[group[m]->bcal_index]=1; remaining_bcal_showers--; } } } } // Clear the groups vector so that new groups can be formed groups.clear(); // Allow those photons that have not been matched to a vertex already // to form a new group with a different vertex for (unsigned int k=0;kis_matched_to_vertex==false) vi->is_in_group=false; } } // Deal with bcal and fcal showers that have not already been matched to // tracks or associated with a vertex. Since we have no vertex information // for these showers, assume they came from the center of the target. These // photons are put in a separate container called "orphaned_showers". if (remaining_bcal_showers>0 || remaining_fcal_showers>0){ DVector3 target_center(0.,0.,65.); vertices.clear(); if (remaining_bcal_showers>0){ for (unsigned int i=0;ibcal->x,vi->bcal->y,vi->bcal->z) -target_center).Mag()/SPEED_OF_LIGHT; vi->t-=tflight; vi->Fill(vi->t,vi->sigmat,vi->z,vi->sigmaz); vertices.push_back(vi); } } } if (remaining_fcal_showers>0){ for (unsigned int i=0;ifcal->getCentroid()-target_center).Mag() /SPEED_OF_LIGHT; vi->t-=tflight; vi->Fill(vi->t,vi->sigmat,vi->z,vi->sigmaz); vertices.push_back(vi); } } } // group the photons together vector< vector > groups; AssignParticlesToGroups(vertices,groups); for (unsigned int k=0;kshower_group; vector &group = groups[k]; for (unsigned int m=0;mbcal,group[m]->fcal)); } orphan_showers.push_back(shower_group); shower_group.clear(); } } return NOERROR; } //------------------ // erun //------------------ jerror_t DVertex_factory::erun(void) { return NOERROR; } //------------------ // fini //------------------ jerror_t DVertex_factory::fini(void) { return NOERROR; } // Form vertices from grouping charged particle tracks together according to // proximity in time and position of the closest approach to the beam line jerror_t DVertex_factory::MakeVertices(vector >&tracks_by_candidate){ // Vector to hold list of vertexInfo_t objects for all charged tracks vector vertices; // Assign and fill vertexInfo_t objects for each charged track for(unsigned int i=0; i > groups; AssignParticlesToGroups(vertices,groups); // OK, we've now grouped the particles together into groups. Create a new // DVertex for each group for (unsigned int i=0;i &group = groups[i]; DVertex *my_vertex = new DVertex; my_vertex->x.SetXYZT(0.0, 0.0, target_z,0.0); my_vertex->cov.ResizeTo(3,3); my_vertex->beamline_used = false; // Simply average POCA to beamline for all tracks DVector3 temp; double t0=0.; double sum_invar=0, invar=0; for(unsigned int j=0; jhypotheses)[0]; invar=1./(group[j]->sigmat*group[j]->sigmat); sum_invar+=invar; t0+=group[j]->t*invar; temp+=trk->position(); } t0*=1./sum_invar; temp*=1./double(group.size()); my_vertex->x.SetVect(temp); my_vertex->x.SetT(t0); my_vertex->t_sigma=0.; // <------ this needs to be fixed // Add list of tracks used to create this vertex for(unsigned int j=0; jtrack_infos; vectortracks=*(group[j]->hypotheses); for (unsigned int m=0;mhypotheses.push_back(track_infos); } _data.push_back(my_vertex); } return NOERROR; } //------------------ // FillVertexInfoBCAL //------------------ #define EPS 1.e-8 void DVertex_factory::FillVertexInfoBCAL(DVertex_factory::vertexInfo_t *vi, const DBCALShower *bcal, unsigned int index){ vi->Reset(); vi->bcal=bcal; vi->bcal_index=index; vi->fcal_index=0; vi->fcal=NULL; vi->z=0; //will be filled in later vi->sigmaz=30.0/sqrt(12); // in cm. Use length of target for z-resolution of photons vi->t=bcal->t; // will be propagated to vertex later vi->sigmat = bcal->tErr; // somtimes KLOE algorithm returns a zero RMS.. if (vi->sigmatsigmat=0.5; // guess! } //------------------ // FillVertexInfoFCAL //------------------ void DVertex_factory::FillVertexInfoFCAL(DVertex_factory::vertexInfo_t *vi, const DFCALCluster *fcal, unsigned int index){ vi->Reset(); vi->fcal=fcal; vi->fcal_index=index; vi->bcal_index=0; vi->bcal=NULL; vi->z=0; //will be filled in later vi->sigmaz=30.0/sqrt(12); // in cm. Use length of target for z-resolution of photons vi->t=fcal->getTime(); // will be propagated to vertex later vi->sigmat=0.5; } //------------------ // FillVertexInfoChargedTrack //------------------ void DVertex_factory::FillVertexInfoChargedTrack(DVertex_factory::vertexInfo_t *vi, vector*hypotheses) { vi->Reset(); vi->hypotheses = hypotheses; vi->t = (*hypotheses)[0]->t0(); vi->sigmat = (*hypotheses)[0]->t0_err(); vi->z = (*hypotheses)[0]->z(); vi->sigmaz = 0.8/sin((*hypotheses)[0]->momentum().Theta()); // in cm. For now, use 3mm wide angle track resolution scaled by sin(theta) vi->Fill(vi->t, vi->sigmat, vi->z, vi->sigmaz); } //------------------ // AllInGroups //------------------ bool DVertex_factory::AllInGroups(vector &vertices) { for(unsigned int i=0; iis_in_group)return false; } return true; } // Group "particles" (either tracks or photon candidates) together by time // and z position void DVertex_factory::AssignParticlesToGroups(vector &vertices, vector< vector > &groups ){ // Each particle has a histogram of t vs.z // values filled using approriate uncertainties (no covariance). We // can now use this list to identify resonances in the t/z plane which // indicate a vertex location. Particles within 3sigma in both t and // z of the resonance will be grouped together as belonging to the // same vertex. We loop until all particles have been assigned // to a group, even if that means assigning particles to their own // "group of one". // Loop until all particles have been assigned to a group. while(!AllInGroups(vertices)){ // Make a list of all particles that have not been assigned // to a group vector unassigned; for(unsigned int i=0; iis_in_group)unassigned.push_back(vertices[i]); } // Find the maximum t,z coordinate by adding all unassigned // particle's histos together DVector2 maxloc = DHoughFind::GetMaxBinLocation(unassigned); if(debug_level>0)_DBG_<<"Location of maximum: t="<is_in_group = true; // Add the new group to the list of groups groups.push_back(new_group); } }