#define pmcsana_cxx #include "pmcsana.h" #include #include #include #include #include "PCalTools.hpp" #include "WZ_Utils.hpp" #include #include #include using namespace std; static double PDFWeightFactor[41]; double pmcsana::computePDF(int iset, double x, double q, int flav) { double f[13]; for (int i=0;i<13;i++) f[i]=0.; evolvepdfm_(iset,x,q,f); double pdf = f[flav+6]; return pdf; } void pmcsana::Begin(TTree *tree) { TString option = GetOption(); cout<<"Start pmcsana::Begin"<simulate_merge_fsr_photons_in_cone_prob(); _merge_fsr_photons_in_cone_prob_p0 = _globalparameters->merge_fsr_photons_in_cone_prob_p0(); _merge_fsr_photons_in_cone_prob_p1 = _globalparameters->merge_fsr_photons_in_cone_prob_p1(); _merge_fsr_photons_in_cone_prob_p2 = _globalparameters->merge_fsr_photons_in_cone_prob_p2(); _merge_fsr_photons_in_cone_prob_p3 = _globalparameters->merge_fsr_photons_in_cone_prob_p3(); _simulate_merge_fsr_photons_out_cone_prob = _globalparameters->simulate_merge_fsr_photons_out_cone_prob(); _merge_fsr_photons_out_cone_prob_p0 = _globalparameters->merge_fsr_photons_out_cone_prob_p0(); _merge_fsr_photons_out_cone_prob_p1 = _globalparameters->merge_fsr_photons_out_cone_prob_p1(); _merge_fsr_photons_out_cone_prob_p2 = _globalparameters->merge_fsr_photons_out_cone_prob_p2(); _merge_fsr_photons_out_cone_prob_p3 = _globalparameters->merge_fsr_photons_out_cone_prob_p3(); _merge_fsr_photons_out_cone_prob_p4 = _globalparameters->merge_fsr_photons_out_cone_prob_p4(); // for merged photon response _simulate_merge_fsr_photons_in_cone_response = _globalparameters->simulate_merge_fsr_photons_in_cone_response(); _merge_fsr_photons_in_cone_response_p0 = _globalparameters->merge_fsr_photons_in_cone_response_p0(); _merge_fsr_photons_in_cone_response_p1 = _globalparameters->merge_fsr_photons_in_cone_response_p1(); _merge_fsr_photons_in_cone_response_p2 = _globalparameters->merge_fsr_photons_in_cone_response_p2(); _merge_fsr_photons_in_cone_response_p3 = _globalparameters->merge_fsr_photons_in_cone_response_p3(); _merge_fsr_photons_in_cone_response_p4 = _globalparameters->merge_fsr_photons_in_cone_response_p4(); _merge_fsr_photons_in_cone_response_p5 = _globalparameters->merge_fsr_photons_in_cone_response_p5(); _simulate_merge_fsr_photons_out_cone_response = _globalparameters->simulate_merge_fsr_photons_out_cone_response(); _merge_fsr_photons_out_cone_response_p0 = _globalparameters->merge_fsr_photons_out_cone_response_p0(); _merge_fsr_photons_out_cone_response_p1 = _globalparameters->merge_fsr_photons_out_cone_response_p1(); _merge_fsr_photons_out_cone_response_p2 = _globalparameters->merge_fsr_photons_out_cone_response_p2(); _merge_fsr_photons_out_cone_response_p3 = _globalparameters->merge_fsr_photons_out_cone_response_p3(); _merge_fsr_photons_out_cone_response_p4 = _globalparameters->merge_fsr_photons_out_cone_response_p4(); _merge_fsr_photons_out_cone_response_p5 = _globalparameters->merge_fsr_photons_out_cone_response_p5(); // if we want to do PDF reweight // will calculate weight for all 41 PDFs, hardcoded _doPdfReweight = _globalparameters->pdfreweight(); if(_doPdfReweight) { // pdf path string pdfpath = "/d0usr/products/lhapdfsets/NULL/v3_0/"; char _nameini[100]; string tmp = pdfpath; tmp += _globalparameters->pdfori(); strcpy(_nameini, tmp.c_str()); cout<<"Files are generated with PDF: "<<_nameini<pdfori_subset(); vector vpdfnew; vector vpdfnew_subset; for (int i=0; i<41; ++i) { vpdfnew.push_back("cteq61.LHgrid"); vpdfnew_subset.push_back(i); } initpdfsetm_(set1,*_nameini); initpdfm_(set1, pdfori_subset); // Initialize the new PDF sets : cout << "loading PDFs for reweighting" << endl; for (int i=0; i _NuLoose_EtaMax )) { cerr << "pmcsana: Wrong specification of Loose and Tight cuts!!!" << endl << " pT(Loose nu)>=" << _NuLoose_PtMin << " GeV, |eta(Loose nu)|<" << _NuLoose_EtaMax << endl << " pT(Tight nu)>=" << _NuTight_PtMin << " GeV, |eta(Tight nu)|<" << _NuTight_EtaMax << endl; throw; } } // initialize random number generator if (_randomseed==0) { _dummy = new TRandom3(_globalparameters->rand_seed()); cout << "pmcsana: Using random seed = " << _globalparameters->rand_seed() << endl; } else { _dummy = new TRandom3(_randomseed); cout << "pmcsana: Using random seed = " << _randomseed << endl; } // also set gRandom points to the instance of TRandom3 gRandom = _dummy; // initialize beam spot if(_globalparameters->VtxSmear_Option()==1) { cout<<"Initializing beamspot dependence on the run ranges and instantaneous luminosity now ..."<BeamSpotShape_file())); cout<<"Finished beamspot"<instlumi_profile(); cout<<"End pmcsana::Begin"<MINUIT_skipPreselection()) return false; //how often do we print out the number of events processed? static int update_frequency = _globalparameters->update_frequency(); static int eventsProcessed = 0; if(eventsProcessed%update_frequency==0) cout<<"Processing event number: "<< eventsProcessed << " / " << _numEvents << endl; eventsProcessed++; // // construct PMCS event information and put all information into PMCSEvent class // double evtweight; PMCSParticle wzboson_gen; vector emobjs_gen; vector muons_gen; PMCSMet met_gen; PMCSRecoil recoil_gen; PMCSVtx vtx_gen; // run number and instantaneous luminosity for this zerobias event // also keep the index so that we will use the same event for overlay int runNo = 1, ZBEvtIndex = -1, MBEvtIndex = -1; double instlumi = 0.; // // get run number and instantaneous luminosity from zerobias overlay // also keep the indices for the overlaid zerobias and minbias events // only need for ZAnalysis and WAnalysis, not relevant for ZMuAnalysis and JPsiMuAnalysis // if we read recoil file, then we do not need to get the indices to the overlaid Minbias and Zerobias events // if(_runoption == 0) { if(!_zanalysis->getRecoilSmear()->read_recoil_file()){ _zanalysis->getRecoilSmear()->setRunNoInstLumiMBZBEvtIndex(_dummy); _zanalysis->getRecoilSmear()->getRunNoInstLumiMBZBEvtIndex(runNo, instlumi, MBEvtIndex, ZBEvtIndex); } // if we do not read the mb and zb library files, will get the luminosity from a histogram if(_zanalysis->getRecoilSmear()->METSmear_Option()!=3 || _zanalysis->getRecoilSmear()->read_recoil_file()) instlumi =_instlumi_profile->GetRandom(); } else if(_runoption == 1) { if(!_wanalysis->getRecoilSmear()->read_recoil_file()){ _wanalysis->getRecoilSmear()->setRunNoInstLumiMBZBEvtIndex(_dummy); _wanalysis->getRecoilSmear()->getRunNoInstLumiMBZBEvtIndex(runNo, instlumi, MBEvtIndex, ZBEvtIndex); } // if we do not read the mb and zb library files, will get the luminosity from a histogram if(_wanalysis->getRecoilSmear()->METSmear_Option()!=3 || _wanalysis->getRecoilSmear()->read_recoil_file()) instlumi =_instlumi_profile->GetRandom(); } // read all generator level information from pmcs_ana branch constructPMCSEvent(entry, runNo, instlumi, evtweight, wzboson_gen, emobjs_gen, met_gen, recoil_gen, vtx_gen, muons_gen, _dummy); // construct pmcsEvent for future use PMCSEvent pmcsevent(runNo, MBEvtIndex, ZBEvtIndex, evtweight, instlumi, wzboson_gen, emobjs_gen, met_gen, recoil_gen, vtx_gen, muons_gen); // whether we want to do vertex cut if(_globalparameters->do_zvtx_cut() && fabs(vtx_gen.vtxz()) > _globalparameters->zvtx_cut()) { return kFALSE; // skip this event } else{ // analyze this event if(_runoption == 0) _zanalysis->analyzeEvent(pmcsevent, _dummy); if(_runoption == 1) _wanalysis->analyzeEvent(pmcsevent, _dummy); if(_runoption == 2) _zmuanalysis->analyzeEvent(pmcsevent, _dummy); if(_runoption == 3) _jpsimuanalysis->analyzeEvent(pmcsevent, _dummy); if(_runoption == 4) { // used for Z->nunu analysis, need to apply cuts on generator level neutrinos b_pmcs_ana->GetEntry(entry); int nLooseNeutrinos = 0, nTightNeutrinos = 0; for(int ipart=0; ipart_NuLoose_PtMin) nLooseNeutrinos++; if( fabs(eta)<_NuTight_EtaMax && pt>_NuTight_PtMin) nTightNeutrinos++; } } // loop over all particles to find neutrinos _znunuanalysis->analyzeEvent(pmcsevent, nLooseNeutrinos, nTightNeutrinos, _dummy); } return kTRUE; } } // SlaveTerminate void pmcsana::SlaveTerminate() {} // Terminate void pmcsana::Terminate() { if(_runoption == 0) _zanalysis -> jobSummary(_dummy, _numEvents); if(_runoption == 1) _wanalysis -> jobSummary(); if(_runoption == 2) _zmuanalysis -> jobSummary(); if(_runoption == 3) _jpsimuanalysis -> jobSummary(); if(_runoption == 4) _znunuanalysis -> jobSummary(); } // construct PMCSEvent void pmcsana::constructPMCSEvent(Int_t entry, int runNo, double instlumi, double& evtweight, PMCSParticle& wzboson, vector& emobjs, PMCSMet& met, PMCSRecoil& recoil, PMCSVtx& vtx, vector& muons, TRandom3 *dummy) { b_pmcs_ana->GetEntry(entry); b_pmcs_vtx->GetEntry(entry); // Event Weight, if we do not want to read event weight, set all of them to 1 evtweight = pmcs_ana_evwt[0]; if(!(_globalparameters->reweight())) evtweight = 1.; /* // calculate PDF weight factor if(_doPdfReweight) { double x1 = pmcs_ana_evx1[0]; double x2 = pmcs_ana_evx2[0]; int flav1 = (int)(pmcs_ana_evflav1[0]); int flav2 = (int)(pmcs_ana_evflav2[0]); // need to convert flav2 to -flav2 since flav2 is coming from antiproton // while computerPDF gets values from proton flav2 = -flav2; double q = sqrt(pmcs_ana_evqsq[0]); int iset_pdf = 1; double rpdfini1 = computePDF(iset_pdf, x1, q, flav1); double rpdfini2 = computePDF(iset_pdf, x2, q, flav2); for(int i=0; i<41; ++i) { iset_pdf = i+2; double rpdfnew1 = computePDF(iset_pdf, x1, q, flav1); double rpdfnew2 = computePDF(iset_pdf, x2, q, flav2); double rpdfweight = 1.; if(rpdfini1!=0 && rpdfnew1!=0) rpdfweight *= rpdfnew1/rpdfini1; if(rpdfini2!=0 && rpdfnew2!=0) rpdfweight *= rpdfnew2/rpdfini2; // fill the static variables PDFWeightFactor[i] = rpdfweight; } // 41 PDF sets cout<smearVertex(); double vtx_res = _globalparameters->VtxResolution(); int vtxSmearOption = _globalparameters->VtxSmear_Option(); if(smearVertex) { if(vtxSmearOption == 0) vtx.SmearVtx(vtx_res, dummy); else { // first smear primary vertex using a 40 cm gaussian function vtx.SmearVtx(40., dummy); // then calculate the event weight that is relative to this 40 cm gaussian double z = vtx.vtxz(); double beamshape = _beam->beamshape(runNo, instlumi, z); double gaus = _beam->Gaussian(40, 0., z); // now we modify event weight evtweight *= beamshape/gaus; } } // Merge electron and photons if( _globalparameters->merge_fsr_photons() ) fixEMBlock(entry, vtx, _globalparameters->merge_fsr_radius_CC(), _globalparameters->merge_fsr_radius_EC()); else fixEMBlock(entry, vtx, -1.0, -1.0); // clear emobjs vector first emobjs.clear(); double metx_raw = 0., mety_raw = 0., metz_raw = 0., met_E = 0.; // loop over all generator level particles for(int ipart=0; ipart_globalparameters->pT_Cut()) { PMCSEMObj emobj(pmcs_em_elfid[j], pmcs_em_eleg[j], pmcs_em_eletag[j], pmcs_em_elphig[j], pmcs_em_elpts[j]); emobjs.push_back(emobj); }//pt cut }//electrons // electrons and photons are already merged here since I use pmcs_em branch information // for photons, track pT is the same as photon pTset to 0 // so that later we will not calculate E/p for EMobjs that are really photons // all photons are treated as EMObjects for(int j=0;j_globalparameters->pT_Cut()) { PMCSEMObj emobj(22, pmcs_em_pheg[j], pmcs_em_phetag[j], pmcs_em_phphig[j], 0.); emobjs.push_back(emobj); // }//pt cut }//photons // mainly used for Sahal's ratio method to pass generator level neutrino information if(_runoption == 1){ TLorentzVector e(metx_raw, mety_raw,metz_raw, met_E); PMCSEMObj Nugen(12,e.E(),e.Eta(),e.Phi(),e.Pt()); emobjs.push_back(Nugen); } // have to loop over all EMObjs and calculate detector eta, phi in global and local coordinate systems for(int iem=0; iemmerge_fsr_photons_recoil()) { // for(int iph=0; iphpT_Cut()) { // recoilx_system += pmcs_em_phptg[iph] * cos(pmcs_em_phphig[iph]); // recoily_system += pmcs_em_phptg[iph] * sin(pmcs_em_phphig[iph]); // } // } // loop over all photons // } // create vector for the recoil system recoil = PMCSRecoil(recoilx_system, recoily_system); // // print out information // if(_globalparameters->debug()) { cout<<"raw event weight: "<GetEntry(entry); // get primary vertex double vtxZ = vtx.vtxz(); const Bool_t FDBG = kFALSE; Int_t nphi=0, neli=0; Int_t ph_indices[50]; Int_t el_indices[50]; for(int i=0; i<50; i++) { ph_indices[i]=-1; el_indices[i]=-1; } if(FDBG) printf("\n"); //index all photons and electrons in the pmcs_ana block //if there are many particles in this event, this will save some time for(int ip = 0; ip < pmcs_ana_npart; ip++) { if(TMath::Abs(pmcs_ana_ppid[ip])==22 && pmcs_ana_pE[ip]>0.001){ //photon TLorentzVector ph(pmcs_ana_ppx[ip],pmcs_ana_ppy[ip], pmcs_ana_ppz[ip],pmcs_ana_pE[ip]); if(FDBG) printf("Original photon: E=%.3f pT=%.3f eta=%0.3f phi=%0.3f ", ph.E(),ph.Pt(),ph.Eta(),ph.Phi()); ph_indices[nphi]=ip; nphi++; if(FDBG) cout<Uniform(0., 1.); if(prob < prob_photon) { // calculate the fraction of photon energy merged with the EM cluster double fraction = 1.; if(_simulate_merge_fsr_photons_in_cone_response) fraction = wz_utils::photon_response_in_cone(ph.Eta(), ph.Pt(), _merge_fsr_photons_in_cone_response_p0, _merge_fsr_photons_in_cone_response_p1, _merge_fsr_photons_in_cone_response_p2, _merge_fsr_photons_in_cone_response_p3, _merge_fsr_photons_in_cone_response_p4, _merge_fsr_photons_in_cone_response_p5); if(FDBG) printf(" ==> MERGED energy fraction=%.3f ", fraction); ph_indices[j]=-1; //mark as found, remove this partially merged photons, is this the best way ??? e += fraction * ph; //Merge. Is this the best way? } // only a fraction of photons can reach the calorimeter } // merged if(FDBG) printf("\n"); } //Create pmcs_em object (generated quantities only) if(FDBG){ printf(" pmcs_em entry: %.2f->%.2f Pt: %.2f->%.2f " "Eta: %.2f->%.2f Phi: %.2f->%.2f\n", e_before.E(),e.E(), e_before.Pt(),e.Pt(), e_before.Eta(),e.Eta(), e_before.Phi()>0.0?e_before.Phi():e_before.Phi()+2*TMath::Pi(), e.Phi()>0.0?e.Phi():e.Phi()+2*TMath::Pi()); } pmcs_em_eleg[ke]=e.E(); pmcs_em_elptg[ke]=e.Pt(); pmcs_em_eletag[ke]=e.Eta(); pmcs_em_elphig[ke]=e.Phi(); if(pmcs_em_elphig[ke]<0.0) pmcs_em_elphig[ke] += 2*TMath::Pi(); // need to keep track pT and particle ID // currently choose to use two unused variables pmcs_em_elpts, pmcs_em_elfid // which means these two variables can not be used for other purposes pmcs_em_elpts[ke] = trkpT; // track pT before electron/photon merging pmcs_em_elfid[ke] = pmcs_ana_ppid[ie]; //use this as pid pmcs_em_nelg++; } //Recreate the list of photons, excluding those that are collinear //to electrons. int NPhotonAfterMerging = 0; for(int j=0;j0.001){ // these photons will be included in the recoil system // and I will apply the fraction of photons that can reach the calorimeter // and the fraction of energy deposited in the calorimeter double prob_photon = 1.; if(_simulate_merge_fsr_photons_out_cone_prob) // assume CC and EC photons have the same probability prob_photon = wz_utils::photon_prob_out_cone(photon.Pt(), _merge_fsr_photons_out_cone_prob_p0, _merge_fsr_photons_out_cone_prob_p1, _merge_fsr_photons_out_cone_prob_p2, _merge_fsr_photons_out_cone_prob_p3, _merge_fsr_photons_out_cone_prob_p4); // remove the photons that are not supposed to reach the calorimeter permanently double prob = _dummy->Uniform(0., 1.); if(prob < prob_photon) { // calculate the fraction of photon energy merged with the EM cluster double fraction = 1.; if(_simulate_merge_fsr_photons_out_cone_response) fraction = wz_utils::photon_response_out_cone(photon.Eta(), photon.Pt(), _merge_fsr_photons_out_cone_response_p0, _merge_fsr_photons_out_cone_response_p1, _merge_fsr_photons_out_cone_response_p2, _merge_fsr_photons_out_cone_response_p3, _merge_fsr_photons_out_cone_response_p4, _merge_fsr_photons_out_cone_response_p5); if(FDBG) printf(" ==> MERGED energy fraction=%.3f ", fraction); ph_indices[j]=-1; //mark as found, remove this partially merged photons, is this the best way ??? photon = fraction * photon; // change photon energy that will be included in the recoil system pmcs_em_phptg[NPhotonAfterMerging] = photon.Pt(); pmcs_em_phetag[NPhotonAfterMerging] = photon.Eta(); pmcs_em_phphig[NPhotonAfterMerging] = photon.Phi(); pmcs_em_pheg[NPhotonAfterMerging] = photon.E(); pmcs_em_phfid[NPhotonAfterMerging] = 0; // this variable does not matter NPhotonAfterMerging += 1; } // only a fraction of photon can reach the calorimeter if(NPhotonAfterMerging>=120){ printf("Warning: Too many photons (%d)!\n",nphi); break; } }//get rid of merged photons and photon with pT at least 1 MeV } // loop over all photons pmcs_em_nphg = NPhotonAfterMerging; return; }