/***************************************************************************** * Copyright (C) 2009-2019 this file is part of the NPTool Project * * * * For the licensing terms see $NPTOOL/Licence/NPTool_Licence * * For the list of contributors see $NPTOOL/Licence/Contributors * *****************************************************************************/ /***************************************************************************** * * * Original Author : F. Flavigny contact address: flavigny@lpccaen.in2p3.fr * * * * Creation Date : April 2019 * * Last update : Nov 2019 * *---------------------------------------------------------------------------* * Decription: * * This class deal with Quasi Free Scattering Reaction in which a cluster * * or a nucleon is removed from a projectile by interaction with a target * * nucleon (proton target in general) * * * * First step (dissociation): A -> B + a * * Second step (scattering) : a + T -> 1 + 2 * * Labeling is: * * * * A --> T ==> B + (a -> T) => B + 1 + 2 * * * * where: * * + A is the beam nucleus * * + T is the target nucleon (proton) * * * * + B is the residual fragment (beam-like) * * + 1 is the scattered target nucleon (former T) * * + 2 is the knocked-out cluster/nucleon (noted a) in the intermediate * *---------------------------------------------------------------------------* * Comment: * * + Adapted from original event generator from V. Panin (R3B collab) * * * *****************************************************************************/ #include <iostream> #include <fstream> #include <string> #include <cstdlib> #include <sstream> #include <cmath> #include <vector> #include "NPQFS.h" #include "NPCore.h" #include "NPOptionManager.h" #include "NPFunction.h" // Use CLHEP System of unit and Physical Constant #include "NPGlobalSystemOfUnits.h" #include "NPPhysicalConstants.h" #ifdef NP_SYSTEM_OF_UNITS_H using namespace NPUNITS; #endif // ROOT #include"TF1.h" ClassImp(QFS) //////////////////////////////////////////////////////////////////////////////// QFS::QFS(){ //------------- Default Constructor ------------- fVerboseLevel = NPOptionManager::getInstance()->GetVerboseLevel(); fBeamEnergy = 0; fThetaCM = 0; fPhiCM = 0; fExcitationA = 0; fExcitationB = 0; fMomentumSigma = 0; fInternalMomentum = {0., 0.,0. }; fshootB=false; fshoot1=true; fshoot2=true; fIsotropic = true; fCondEcmPos = false; fCondOffshellMassPos = false; fIsAllowed = false; fUseExInGeant4=true; fTheta2VsTheta1 = 0; fPhi2VsPhi1 = 0; fPerpMomentumHist = NULL; fParMomentumHist = NULL; fDeexcitation = false; } //////////////////////////////////////////////////////////////////////////////// QFS::~QFS(){ } ///////////////////////////////////////////////////////////////////////////////////////////////////////// void QFS::ReadConfigurationFile(string Path){ ifstream ReactionFile; string GlobalPath = getenv("NPTOOL"); string StandardPath = GlobalPath + "/Inputs/EventGenerator/" + Path; ReactionFile.open(Path.c_str()); if (!ReactionFile.is_open()) { ReactionFile.open(StandardPath.c_str()); if(ReactionFile.is_open()) { Path = StandardPath; } else {cout << "QFS File " << Path << " not found" << endl;exit(1);} } NPL::InputParser parser(Path); ReadConfigurationFile(parser); } //////////////////////////////////////////////////////////////////////////////// void QFS::ReadConfigurationFile(NPL::InputParser parser){ cout << " In QFS ReadConfiguration " << endl; vector<NPL::InputBlock*> blocks = parser.GetAllBlocksWithToken("QFSReaction"); if(blocks.size()>0 && NPOptionManager::getInstance()->GetVerboseLevel()) cout << endl << "\033[1;35m//// QFS reaction found " << endl; vector<string> token1 = {"Beam","Target","Scattered","KnockedOut","Heavy"}; for(unsigned int i = 0 ; i < blocks.size() ; i++){ if(blocks[i]->HasTokenList(token1)){ int v = NPOptionManager::getInstance()->GetVerboseLevel(); NPOptionManager::getInstance()->SetVerboseLevel(0); fParticleA.ReadConfigurationFile(parser); NPOptionManager::getInstance()->SetVerboseLevel(v); fBeamEnergy= fParticleA.GetEnergy(); GetParticle(blocks[i]->GetString("Beam"),parser); fParticleT = GetParticle(blocks[i]->GetString("Target"),parser); fParticleB = GetParticle(blocks[i]->GetString("Heavy"),parser); fParticle1 = GetParticle(blocks[i]->GetString("Scattered"),parser); fParticle2 = GetParticle(blocks[i]->GetString("KnockedOut"),parser); } else{ cout << "ERROR: check your input file formatting \033[0m" << endl; exit(1); } if(blocks[i]->HasToken("ExcitationEnergyBeam")){ fExcitationA = blocks[i]->GetDouble("ExcitationEnergyBeam","MeV"); } if(blocks[i]->HasToken("ExcitationEnergyHeavy")){ fExcitationB = blocks[i]->GetDouble("ExcitationEnergyHeavy","MeV"); } if(blocks[i]->HasToken("MomentumSigma")){ fMomentumSigma = blocks[i]->GetDouble("MomentumSigma","MeV"); } if(blocks[i]->HasToken("ShootHeavy")){ fshootB = blocks[i]->GetInt("ShootHeavy"); } if(blocks[i]->HasToken("ShootLight")){ fshoot1 = blocks[i]->GetInt("ShootLight"); fshoot2 = blocks[i]->GetInt("ShootLight"); } if(blocks[i]->HasToken("ShootLight1")){ fshoot1 = blocks[i]->GetInt("ShootLight1"); } if(blocks[i]->HasToken("ShootLight2")){ fshoot2 = blocks[i]->GetInt("ShootLight2"); } if(blocks[i]->HasToken("PerpMomentumPath")){ vector<string> file_perp = blocks[i]->GetVectorString("PerpMomentumPath"); TH1F* Perptemp = Read1DProfile(file_perp[0], file_perp[1]); SetPerpMomentumHist(Perptemp); } if(blocks[i]->HasToken("ParMomentumPath")){ vector<string> file_par = blocks[i]->GetVectorString("ParMomentumPath"); TH1F* Partemp = Read1DProfile(file_par[0], file_par[1]); SetParMomentumHist(Partemp); } if(blocks[i]->HasToken("Deexcitation")){ fDeexcitation = blocks[i]->GetInt("Deexcitation"); } } cout << "\033[0m" ; } //////////////////////////////////////////////////////////////////////////////// Particle QFS::GetParticle(string name, NPL::InputParser parser){ vector<NPL::InputBlock*> blocks = parser.GetAllBlocksWithTokenAndValue("DefineParticle",name); unsigned int size = blocks.size(); if(size==0) return NPL::Particle(name); else if(size==1){ cout << " -- User defined nucleus " << name << " -- " << endl; vector<string> token = {"SubPart","BindingEnergy"}; if(blocks[0]->HasTokenList(token)){ NPL::Particle N(name,blocks[0]->GetVectorString("SubPart"),blocks[0]->GetDouble("BindingEnergy","MeV")); if(blocks[0]->HasToken("ExcitationEnergy")) N.SetExcitationEnergy(blocks[0]->GetDouble("ExcitationEnergy","MeV")); if(blocks[0]->HasToken("SpinParity")) N.SetSpinParity(blocks[0]->GetString("SpinParity").c_str()); if(blocks[0]->HasToken("Spin")) N.SetSpin(blocks[0]->GetDouble("Spin","")); if(blocks[0]->HasToken("Parity")) N.SetParity(blocks[0]->GetString("Parity").c_str()); if(blocks[0]->HasToken("LifeTime")) N.SetLifeTime(blocks[0]->GetDouble("LifeTime","s")); cout << " -- -- -- -- -- -- -- -- -- -- --" << endl; return N; } } else{ NPL::SendErrorAndExit("NPL::QFS","Too many nuclei define with the same name"); return NPL::Particle(); } return NPL::Particle(); } //////////////////////////////////////////////////////////////////////////////////////////// void QFS::CalculateVariables(){ fCondEcmPos = false; fCondOffshellMassPos = false; if(fBeamEnergy < 0) fBeamEnergy = 0 ; //cout<<"---- COMPUTE ------"<<endl; // cout<<"--CM--"<<endl; mA = fParticleA.Mass(); // Beam mass in MeV mT = fParticleT.Mass(); // Target mass in MeV fParticleB.SetExcitationEnergy(fExcitationB); mB = fParticleB.Mass(); // Heavy residual mass in MeV m1 = mT; // scattered target nucleon (same mass); m2 = fParticle2.Mass(); // knocked out cluster mass in MeV ma = m2; // intermediate cluster mass in MeV (same); double TA = fBeamEnergy; // Beam kinetic energy double PA = sqrt(TA*(TA+2*mA)); // Beam momentum (norm) double EA = sqrt(mA*mA + PA*PA); // Beam total energy fEnergyImpulsionLab_A = TLorentzVector(0.,0.,PA,EA); // Internal momentum of removed cluster/nucleon (Pa) and recoil (PB) // here fInternalMomentum contains PB (recoil fragment momentum) // readout from the input file (theoretical) PB.SetX(fInternalMomentum.X()); PB.SetY(fInternalMomentum.Y()); PB.SetZ(fInternalMomentum.Z()); Pa.SetXYZ( (-PB.X()) , (-PB.Y()) , (-PB.Z()) ); // Off-shell mass of the bound nucleon from E conservation // in virtual dissociation of A -> B + a double buffer = mA*mA + mB*mB - 2*mA*sqrt(mB*mB+Pa.Mag2()) ; if(buffer>0) {fCondOffshellMassPos = true;} else{/*cout<<"ERROR off shell mass ma_off=\t"<<buffer<<endl; Dump();*/ return;} ma_off = sqrt(buffer); //deduced total energies of "a" and "B" in restframe of A double Ea = sqrt(ma_off*ma_off + Pa.Mag2()); double EB = sqrt(mB*mB + PB.Mag2()); fEnergyImpulsionCM_a = TLorentzVector(Pa,Ea); fEnergyImpulsionCM_B = TLorentzVector(PB,EB); fEnergyImpulsionLab_a = TLorentzVector(Pa,Ea); fEnergyImpulsionLab_B = TLorentzVector(PB,EB); fEnergyImpulsionLab_a.Boost(0,0,fEnergyImpulsionLab_A.Beta()); fEnergyImpulsionLab_B.Boost(0,0,fEnergyImpulsionLab_A.Beta()); Ea_lab = fEnergyImpulsionLab_a.E(); EB_lab = fEnergyImpulsionLab_B.E(); Pa_lab = fEnergyImpulsionLab_a.Vect(); PB_lab = fEnergyImpulsionLab_B.Vect(); // Scattering part (2-body kinematics) // virtual cluster of mass "ma_off" scattering on target T // to give scattered cluster with real mass (ma=m2) // and scattered target (mT=m1) fQValue =ma_off+mT-m1-m2; s = ma_off*ma_off + mT*mT + 2*mT*Ea_lab ; fTotalEnergyImpulsionCM = TLorentzVector(0,0,0,sqrt(s)); fEcm = sqrt(s) - m1 -m2; if(fEcm>0) {fCondEcmPos = true;} if(fEcm<=0) { /*cout<<"ERROR Ecm negative =\t"<<fEcm<<endl;Dump();*/ return;} ECM_a = (s + ma_off*ma_off - mT*mT)/(2*sqrt(s)); ECM_T = (s + mT*mT - ma_off*ma_off)/(2*sqrt(s)); ECM_1 = (s + m1*m1 - m2*m2)/(2*sqrt(s)); ECM_2 = (s + m2*m2 - m1*m1)/(2*sqrt(s)); pCM_a = sqrt(ECM_a*ECM_a - ma_off*ma_off); pCM_T = sqrt(ECM_T*ECM_T - mT*mT); pCM_1 = sqrt(ECM_1*ECM_1 - m1*m1); pCM_2 = sqrt(ECM_2*ECM_2 - m2*m2); } //////////////////////////////////////////////////////////////////////////////////////////// void QFS::KineRelativistic(double& ThetaLab1, double& PhiLab1, double& KineticEnergyLab1, double& ThetaLab2, double& PhiLab2, double& KineticEnergyLab2){ fIsAllowed=false; CalculateVariables(); if(fCondOffshellMassPos && fCondEcmPos) fIsAllowed= true; else return; double thetaCM_1 = fThetaCM; double thetaCM_2 = M_PI - thetaCM_1; double phiCM_2 = fPhiCM; TVector3 z_axis(0.,0.,1.); /* // OTHER WAY of doing TVector3 pCM_2_temp(0.,0.,1.); pCM_2_temp.SetMag(pCM_2); pCM_2_temp.SetTheta(thetaCM_2); pCM_2_temp.SetPhi(phiCM_2); fEnergyImpulsionCM_2 = TLorentzVector(pCM_2_temp,ECM_2); fEnergyImpulsionCM_1 = TLorentzVector(-1*pCM_2_temp,ECM_1); */ fEnergyImpulsionCM_2 = TLorentzVector( pCM_2*sin(thetaCM_2)*cos(phiCM_2), pCM_2*sin(thetaCM_2)*sin(phiCM_2), pCM_2*cos(thetaCM_2), ECM_2); fEnergyImpulsionCM_1 = fTotalEnergyImpulsionCM - fEnergyImpulsionCM_2; //-- Boost in the direction of the moving cluster "a" --// BetaCM = Pa_lab.Mag() / (Ea_lab + mT); fEnergyImpulsionLab_1 = fEnergyImpulsionCM_1; fEnergyImpulsionLab_1.Boost(0,0,BetaCM); fEnergyImpulsionLab_2 = fEnergyImpulsionCM_2; fEnergyImpulsionLab_2.Boost(0,0,BetaCM); //-- Rotation to go from cluster frame to beam frame --// TVector3 direction = Pa_lab.Unit(); fEnergyImpulsionLab_1.RotateUz(direction); fEnergyImpulsionLab_2.RotateUz(direction); /* // Angle in the Lab frame ThetaLab1 = fEnergyImpulsionLab_1.Angle(fEnergyImpulsionLab_A.Vect()); //ThetaLab1 = fEnergyImpulsionLab_1.Angle(z_axis); if (ThetaLab1 < 0) ThetaLab1 += M_PI; ThetaLab2 = fEnergyImpulsionLab_2.Angle(fEnergyImpulsionLab_A.Vect()); //ThetaLab2 = fEnergyImpulsionLab_2.Angle(z_axis); if (fabs(ThetaLab1) < 1e-6) ThetaLab1 = 0; ThetaLab2 = fabs(ThetaLab2); if (fabs(ThetaLab2) < 1e-6) ThetaLab2 = 0; PhiLab1 = M_PI + fEnergyImpulsionLab_1.Vect().Phi(); if (fabs(PhiLab1) < 1e-6) PhiLab1 = 0; PhiLab2 = M_PI + fEnergyImpulsionLab_2.Vect().Phi(); if (fabs(PhiLab2) < 1e-6) PhiLab2 = 0; */ ThetaLab1 = fEnergyImpulsionLab_1.Angle(fEnergyImpulsionLab_A.Vect()); ThetaLab2 = fEnergyImpulsionLab_2.Angle(fEnergyImpulsionLab_A.Vect()); PhiLab1 = fEnergyImpulsionLab_1.Vect().Phi(); PhiLab2 = fEnergyImpulsionLab_2.Vect().Phi(); // Kinetic Energy in the lab frame KineticEnergyLab1 = fEnergyImpulsionLab_1.E() - m1; KineticEnergyLab2 = fEnergyImpulsionLab_2.E() - m2; // test for total energy conversion //if (fabs(fTotalEnergyImpulsionLab.E() - (fEnergyImpulsionLab_1.E()+fEnergyImpulsionLab_2.E())) > 1e-6) // cout << "Problem for energy conservation" << endl; //Dump(); } //////////////////////////////////////////////////////////////////////////////////////////// void QFS::Dump(){ cout<<endl; cout<<"------------------------------------"<<endl; cout<<"------------ DUMP QFS --------------"<<endl; cout<<"------------------------------------"<<endl; cout<<endl; cout<<"Cluster/recoil momentum (in the beam nucleus frame):"<<endl; cout<<"Pa=\t("<<Pa.Px()<<","<<Pa.Py()<<","<<Pa.Pz()<<") MeV/c"<<endl; cout<<"PB=\t("<<PB.Px()<<","<<PB.Py()<<","<<PB.Pz()<<") MeV/c"<<endl; cout<<endl; cout<<"Off-shell mass of the bound nucleon from E conservation "<<endl; cout<<" in virtual dissociation of A -> B + a"<<endl; cout<<"ma=\t"<<ma<<endl; cout<<"ma_off=\t"<<ma_off<<endl; cout<<"mB=\t"<<mB<<endl; cout<<"Deduced total energies of a and B in restframe of A"<<endl; cout<<"Ea=\t"<<fEnergyImpulsionCM_a.E()<<"\tMeV"<<endl; cout<<"EB=\t"<<fEnergyImpulsionCM_B.E()<<"\tMeV"<<endl; cout<<endl; cout<<"-- Boosted in lab frame with beam on Z axis --"<<endl; cout<<"Beta_z=\t"<<fEnergyImpulsionLab_A.Beta()<<endl; cout<<"Pa_lab=\t("<<Pa_lab.Px()<<","<<Pa_lab.Py()<<","<<Pa_lab.Pz()<<") MeV/c"<<endl; cout<<"PB_lab=\t("<<PB_lab.Px()<<","<<PB_lab.Py()<<","<<PB_lab.Pz()<<") MeV/c"<<endl; cout<<"Ea_lab=\t"<<Ea_lab<<"\tMeV"<<endl; cout<<"EB_lab=\t"<<EB_lab<<"\tMeV"<<endl; cout<<endl; cout<<"-- Scattering off virtual cluster a of virtual mass --"<<endl; cout<<"-- ma_off and energy Ea_lab on target T at rest ------"<<endl; cout<<"fQValue=\t"<<fQValue<<endl; cout<<"s=\t"<<s<<endl; cout<<"Ecm=\t"<<fEcm<<endl; cout<<"ea*=\t"<<ECM_a<<endl; cout<<"pa*=\t"<<pCM_a<<endl; cout<<"eT*=\t"<<ECM_T<<endl; cout<<"pT*=\t"<<pCM_T<<endl; cout<<"e1*=\t"<<ECM_1<<endl; cout<<"p1*=\t"<<pCM_1<<endl; cout<<"e2*=\t"<<ECM_2<<endl; cout<<"p2*=\t"<<pCM_2<<endl; cout<<"beta_cm=\t"<<BetaCM<<endl; cout<<endl; cout<<"-- Emitted Particles --"<<endl; cout<<"Theta_cm:"<<fThetaCM*180./TMath::Pi()<<endl; cout<<"Phi_cm:"<<fPhiCM*180./TMath::Pi()<<endl; cout<<"P1_CM=\t("<<fEnergyImpulsionCM_1.Px()<<","<<fEnergyImpulsionCM_1.Py()<<","<<fEnergyImpulsionCM_1.Pz()<<")"<<endl; cout<<"P2_CM=\t("<<fEnergyImpulsionCM_2.Px()<<","<<fEnergyImpulsionCM_2.Py()<<","<<fEnergyImpulsionCM_2.Pz()<<")"<<endl; cout<<"E1_lab=\t"<<fEnergyImpulsionLab_1.E()<<endl; cout<<"E2_lab=\t"<<fEnergyImpulsionLab_2.E()<<endl; cout<<"P1_lab=\t("<<fEnergyImpulsionLab_1.Px()<<","<<fEnergyImpulsionLab_1.Py()<<","<<fEnergyImpulsionLab_1.Pz()<<")"<<endl; cout<<"P2_lab=\t("<<fEnergyImpulsionLab_2.Px()<<","<<fEnergyImpulsionLab_2.Py()<<","<<fEnergyImpulsionLab_2.Pz()<<")"<<endl; cout<<"Theta1:\t"<<fEnergyImpulsionLab_1.Vect().Theta()*180./TMath::Pi()<<endl; cout<<"Theta2:\t"<<fEnergyImpulsionLab_2.Vect().Theta()*180./TMath::Pi()<<endl; cout<<"Phi1:\t"<<fEnergyImpulsionLab_1.Vect().Phi()*180./TMath::Pi()<<endl; cout<<"Phi2:\t"<<fEnergyImpulsionLab_2.Vect().Phi()*180./TMath::Pi()<<endl; } //////////////////////////////////////////////////////////////////////////////////////////// TVector3 QFS::ShootInternalMomentum(){ //Shoot a momentum (vector) for the internal cluster in the beam-at-rest frame // (1) if only a width is provided: shoot in 3 independant Gaussian // (2) if input histos are provided: use them instead of option (1) // Remark : if both width and input histos are provided only histos are considered TVector3 momentum = {0,0,0}; double PerpMomentum =0; double ParMomentum =0; double angle_tmp =0; momentum.SetX(gRandom->Gaus(0.,fMomentumSigma)); momentum.SetY(gRandom->Gaus(0.,fMomentumSigma)); momentum.SetZ(gRandom->Gaus(0.,fMomentumSigma)); if(fPerpMomentumHist){ PerpMomentum=fPerpMomentumHist->GetRandom(); angle_tmp = gRandom->Rndm()*2*M_PI; momentum.SetX(PerpMomentum * TMath::Cos(angle_tmp)); momentum.SetY(PerpMomentum * TMath::Sin(angle_tmp)); } if(fParMomentumHist){ ParMomentum=fParMomentumHist->GetRandom(); momentum.SetZ(ParMomentum); } //cout << " Shooting Random Momentum: " << endl; //cout<<"Px:"<<momentum.X() << endl; //cout<<"Py:"<<momentum.Y() << endl; //cout<<"Pz:"<<momentum.Z() << endl; SetInternalMomentum(momentum); return momentum; } //////////////////////////////////////////////////////////////////////////////////////////// TGraph* QFS::GetTheta2VsTheta1(double AngleStep_CM){ vector<double> vx; vector<double> vy; double theta1,phi1,E1,theta2,phi2,E2; SetPhiCM(0.*TMath::Pi()/180.); for (double angle=0 ; angle <= 180 ; angle+=AngleStep_CM){ SetThetaCM(angle*TMath::Pi()/180.); KineRelativistic(theta1, phi1, E1, theta2, phi2, E2); vx.push_back(theta1*180./M_PI); vy.push_back(theta2*180./M_PI); } fTheta2VsTheta1 = new TGraph(vx.size(),&vx[0],&vy[0]); return(fTheta2VsTheta1); } //////////////////////////////////////////////////////////////////////////////////////////// TGraph* QFS::GetPhi2VsPhi1(double AngleStep_CM){ vector<double> vx; vector<double> vy; double theta1,phi1,E1,theta2,phi2,E2; SetThetaCM(0.*TMath::Pi()/180.); for (double angle=-180 ; angle <= 180 ; angle+=AngleStep_CM){ SetPhiCM(angle*TMath::Pi()/180.); KineRelativistic(theta1, phi1, E1, theta2, phi2, E2); vx.push_back(phi1*180./M_PI); vy.push_back(phi2*180./M_PI); } fPhi2VsPhi1 = new TGraph(vx.size(),&vx[0],&vy[0]); return(fPhi2VsPhi1); } //////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// ///////////////// Old R3B method not using TLorentz Vector //////////////////////////////// /////////////////// (used as a reference)/////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// void QFS::TestR3B() { CalculateVariablesOld(); } void QFS::CalculateVariablesOld(){ if(fBeamEnergy < 0) fBeamEnergy = 0 ; //cout<<"---- COMPUTE ------"<<endl; // cout<<"--CM--"<<endl; mA = fParticleA.Mass(); // Beam mass in MeV mT = fParticleT.Mass(); // Target mass in MeV fParticleB.SetExcitationEnergy(fExcitationB); mB = fParticleB.Mass(); // Heavy residual mass in MeV m1 = mT; // scattered target nucleon (same mass); m2 = fParticle2.Mass(); // knocked out cluster mass in MeV ma = m2; // intermediate cluster mass in MeV (same); double TA = fBeamEnergy; // Beam kinetic energy double PA = sqrt(TA*(TA+2*mA)); // Beam momentum (norm) double EA = sqrt(mA*mA + PA*PA); // Beam total energy fEnergyImpulsionLab_A = TLorentzVector(0.,0.,PA,EA); //Internal momentum of removed cluster/nucleon //gRandom->SetSeed(0); //double mom_sigma = 0; // MeV/c //Pa.SetX(gRandom->Gaus(0.,fMomentumSigma)); //Pa.SetY(gRandom->Gaus(0.,fMomentumSigma)); //Pa.SetZ(gRandom->Gaus(0.,fMomentumSigma)); Pa.SetX(50); Pa.SetY(50); Pa.SetZ(50); //Internal momentum of heavy recoil after removal PB.SetXYZ( (-Pa.X()) , (-Pa.Y()) , (-Pa.Z()) ); // Off-shell mass of the bound nucleon from E conservation // in virtual dissociation of A -> B + a double buffer = mA*mA + mB*mB - 2*mA*sqrt(mB*mB+Pa.Mag2()) ; if(buffer<=0) { cout<<"ERROR off shell mass ma_off=\t"<<buffer<<endl; return;} ma_off = sqrt(buffer); //deduced total energies of "a" and "B" in restframe of A double Ea = sqrt(ma_off*ma_off + Pa.Mag2()); double EB = sqrt(mB*mB + PB.Mag2()); fEnergyImpulsionCM_a = TLorentzVector(Pa,Ea); fEnergyImpulsionCM_B = TLorentzVector(PB,EB); fEnergyImpulsionLab_a = TLorentzVector(Pa,Ea); fEnergyImpulsionLab_B = TLorentzVector(PB,EB); fEnergyImpulsionLab_a.Boost(0,0,fEnergyImpulsionLab_A.Beta()); fEnergyImpulsionLab_B.Boost(0,0,fEnergyImpulsionLab_A.Beta()); Ea_lab = fEnergyImpulsionLab_a.E(); EB_lab = fEnergyImpulsionLab_B.E(); Pa_lab = fEnergyImpulsionLab_a.Vect(); PB_lab = fEnergyImpulsionLab_B.Vect(); // Scattering part (2-body kinematics) // virtual cluster of mass "ma_off" scattering on target T // to give scattered cluster with real mass (ma=m2) // and scattered target (mT=m1) fQValue =ma_off+mT-m1-m2; s = ma_off*ma_off + mT*mT + 2*mT*Ea_lab ; fTotalEnergyImpulsionCM = TLorentzVector(0,0,0,sqrt(s)); fEcm = sqrt(s) - m1 -m2; if(fEcm<=0) { cout<<"ERROR Ecm negative =\t"<<fEcm<<endl;Dump(); return;} vector<double> theta1; vector<double> theta2; vector<double> phi1; vector<double> phi2; //for(int i=0; i<=180; i++){ int i = 30; KineR3B(s, ma_off, mT, ma, (double)i); if(!good) { cout<<"ERROR CM calculations!!!"<<endl; return;} cout<<endl; cout<<"------------------------------------"<<endl; cout<<"------------ DUMP R3B --------------"<<endl; cout<<"------------------------------------"<<endl; cout<<endl; cout<<"Cluster/recoil momentum (in the beam nucleus frame):"<<endl; cout<<"Pa=\t("<<Pa.Px()<<","<<Pa.Py()<<","<<Pa.Pz()<<") MeV/c"<<endl; cout<<"PB=\t("<<PB.Px()<<","<<PB.Py()<<","<<PB.Pz()<<") MeV/c"<<endl; cout<<endl; cout<<"Off-shell mass of the bound nucleon from E conservation "<<endl; cout<<" in virtual dissociation of A -> B + a"<<endl; cout<<"ma=\t"<<ma<<endl; cout<<"ma_off=\t"<<ma_off<<endl; cout<<"mB=\t"<<mB<<endl; cout<<"Deduced total energies of a and B in restframe of A"<<endl; cout<<"Ea=\t"<<fEnergyImpulsionCM_a.E()<<"\tMeV"<<endl; cout<<"EB=\t"<<fEnergyImpulsionCM_B.E()<<"\tMeV"<<endl; cout<<endl; cout<<"-- Boosted in lab frame with beam on Z axis --"<<endl; cout<<"Beta_z=\t"<<fEnergyImpulsionLab_A.Beta()<<endl; cout<<"Pa_lab=\t("<<Pa_lab.Px()<<","<<Pa_lab.Py()<<","<<Pa_lab.Pz()<<") MeV/c"<<endl; cout<<"PB_lab=\t("<<PB_lab.Px()<<","<<PB_lab.Py()<<","<<PB_lab.Pz()<<") MeV/c"<<endl; cout<<"Ea_lab=\t"<<Ea_lab<<"\tMeV"<<endl; cout<<"EB_lab=\t"<<EB_lab<<"\tMeV"<<endl; cout<<endl; cout<<"-- Scattering off virtual cluster a of virtual mass --"<<endl; cout<<"-- ma_off and energy Ea_lab on target T at rest ------"<<endl; cout<<"fQValue=\t"<<fQValue<<endl; cout<<"s=\t"<<s<<endl; cout<<"Ecm=\t"<<fEcm<<endl; cout<<endl; TVector3 P1_cm(0.,0.,1.), P2_cm(0.,0.,1.); P2_cm.SetMag(p_clust); P2_cm.SetTheta(theta_clust); //TRandom3 ra; //ra.SetSeed(0); //P2_cm.SetPhi(ra.Uniform(-1*TMath::Pi(),+1*TMath::Pi())); P2_cm.SetPhi(20.*TMath::Pi()/180.); P1_cm.SetX(-P2_cm.X()); P1_cm.SetY(-P2_cm.Y()); P1_cm.SetZ(-P2_cm.Z()); cout<<"P1_CM=\t("<<P1_cm.X()<<","<<P1_cm.Y()<<","<<P1_cm.Z()<<")"<<endl; cout<<"P2_CM=\t("<<P2_cm.X()<<","<<P2_cm.Y()<<","<<P2_cm.Z()<<")"<<endl; // Calculate relative to direction of quasi-particle (cluster) double beta_cm = -Pa_lab.Mag() / (Ea_lab + mT); double gamma_cm = 1/sqrt(1-beta_cm*beta_cm); pair<double,double> lor_a1 = Lorentz(gamma_cm,beta_cm,e_scat,P1_cm.Z()); pair<double,double> lor_a2 = Lorentz(gamma_cm,beta_cm,e_clust,P2_cm.Z()); P1_cm.SetZ(lor_a1.second); P2_cm.SetZ(lor_a2.second); //Rotating back to beam direction TVector3 P1_L = Rotations(P1_cm, Pa_lab); TVector3 P2_L = Rotations(P2_cm, Pa_lab); //TVector3 P1_L = P1_cm; //TVector3 P2_L = P2_cm; //TVector3 direction = Pa.Unit(); //P1_L.RotateUz(direction); //P1_L.RotateUz(direction); cout<<"----Calculate variables output------"<<endl; cout<<"--CM--"<<endl; cout<<"theta1*=\t"<<theta_scat*180/TMath::Pi()<<endl; cout<<"theta2*=\t"<<theta_clust*180/TMath::Pi()<<endl; cout<<"e1*=\t"<<e_scat<<endl; cout<<"p1*=\t"<<p_scat<<endl; cout<<"e2*=\t"<<e_clust<<endl; cout<<"p2*=\t"<<p_clust<<endl; cout<<"T=\t"<<T<<endl; cout<<"beta_cm=\t"<<beta_cm<<endl; cout<<"gamma_cm=\t"<<gamma_cm<<endl; cout<<"--LAB (cluster dir)--"<<endl; cout<<"P1_lab=\t("<<P1_cm.X()<<","<<P1_cm.Y()<<","<<P1_cm.Z()<<")"<<endl; cout<<"P2_lab=\t("<<P2_cm.X()<<","<<P2_cm.Y()<<","<<P2_cm.Z()<<")"<<endl; cout<<"Theta1:\t"<<P1_cm.Theta()*180./TMath::Pi()<<endl; cout<<"Theta2:\t"<<P2_cm.Theta()*180./TMath::Pi()<<endl; cout<<"--LAB--"<<endl; cout<<"Pa_lab=\t("<<Pa_lab.X()<<","<<Pa_lab.Y()<<","<<Pa_lab.Z()<<")"<<endl; cout<<"P1_L=\t("<<P1_L.X()<<","<<P1_L.Y()<<","<<P1_L.Z()<<")"<<endl; cout<<"P2_L=\t("<<P2_L.X()<<","<<P2_L.Y()<<","<<P2_L.Z()<<")"<<endl; cout<<"Theta1L:\t"<<P1_L.Theta()*180./TMath::Pi()<<endl; cout<<"Theta2L:\t"<<P2_L.Theta()*180./TMath::Pi()<<endl; cout<<"Phi1L:\t"<<P1_L.Phi()*180./TMath::Pi()<<endl; cout<<"Phi2L:\t"<<P2_L.Phi()*180./TMath::Pi()<<endl; //cout<<P1_cm.Theta()*180./TMath::Pi()<<"\t"<<P2_cm.Theta()*180./TMath::Pi()<<endl; //cout<<P1_L.Phi()*180./TMath::Pi()<<"\t"<<P2_L.Phi()*180./TMath::Pi()<<endl; theta1.push_back(P1_L.Theta()*180./TMath::Pi()); theta2.push_back(P2_L.Theta()*180./TMath::Pi()); double temp_phi1 = P1_L.Phi(); double temp_phi2 = P2_L.Phi(); phi1.push_back(180. + P1_L.Phi()*180./TMath::Pi()); phi2.push_back(180. + P2_L.Phi()*180./TMath::Pi()); //} TGraph* fTheta2VsTheta1 = new TGraph(theta1.size(),&theta1[0],&theta2[0]); TGraph* fPhi2VsPhi1 = new TGraph(phi1.size(),&phi1[0],&phi2[0]); fTheta2VsTheta1->SetName("Theta2VsTheta1"); fPhi2VsPhi1->SetName("Phi2VsPhi1"); TFile* f = new TFile("graphs.root","RECREATE"); fTheta2VsTheta1->Write(); fPhi2VsPhi1->Write(); f->Close(); } // Calculate elastic scattering kinematics in CM-system (1-target proton, 2-cluster) void QFS::KineR3B(double s,double m2off,double m1,double m2,double thetacm) { if(thetacm>180 || thetacm<0){ cout << "\nERROR! ThetaCM (in deg) should be between 0 and 180"<<endl; return; } e_clust = 0; p_clust = 0; theta_clust = 0; e_scat = 0; p_scat = 0; theta_scat = 0; T = 0; good = false; double X = s; double Y = m2off*m2off; double Z = m1*m1; double sqrt_s = sqrt(s); // Kinematics before the scattering process // (with one off-shell mass) double p2_off = sqrt(function(X,Y,Z))/2/sqrt_s; double p1_off = p2_off; // CM energies double e1_off = (s+Z-Y)/2/sqrt_s; double e2_off = (s+Y-Z)/2/sqrt_s; // Now take the real masses (after scattering) Y = m2*m2; Z = m1*m1; //And check whether the kinematical function is ok //for this specific kinematical case double ERROR_CI = function(X,Y,Z); if(ERROR_CI <= 0.){ cout << "\nERROR!!! Kinematical function is negative!"; return; } // Kinematics after the scattering process // (with all real masses) double p2 = sqrt(function(X,Y,Z))/2/sqrt_s; double p1 = p2; double e1 = (s+Z-Y)/2/sqrt_s; double e2 = (s+Y-Z)/2/sqrt_s; // Let's consider momentum transfer <t> from the // target particle 1 to the cluster 2 double t = 2*(m1*m1 - e1_off*e1 + p1_off*p1*cos(thetacm*TMath::Pi()/180.)); //CM scattering angles double theta1 = thetacm*TMath::Pi()/180.; double theta2 = TMath::Pi() - theta1; e_clust = e2; p_clust = p2; theta_clust = theta2; e_scat = e1; p_scat = p1; theta_scat = theta1; T = t; good = true; } double QFS::function(double x,double y,double z) { double lambda = x*x + y*y + z*z - 2*x*y - 2*x*z - 2*y*z; return lambda; } //---- Two consecutive rotations //first around Z on <phi>, then around new X' on <theta> (1=Pcm, 2=Pa in lab) TVector3 QFS::Rotations(TVector3 v1,TVector3 v2) { double CT = v2.Z()/v2.Mag(); // cos(theta) of v2 wrt. Z-axis double ST = sqrt(1-CT*CT); // sin(theta) double CF = v2.X()/v2.Mag()/ST; double SF = v2.Y()/v2.Mag()/ST; TVector3 v3; double _v3x = v1.X()*CT*CF - v1.Y()*SF + v1.Z()*ST*CF; double _v3y = v1.X()*CT*SF + v1.Y()*CF + v1.Z()*ST*SF; double _v3z = -v1.X()*ST + v1.Z()*CT; v3.SetXYZ(_v3x,_v3y,_v3z); cout<<"--- ROTATION---"<<endl; cout<<"CT=\t"<<CT<<endl; cout<<"ST=\t"<<ST<<endl; cout<<"CF=\t"<<CF<<endl; cout<<"SF=\t"<<SF<<endl; cout<<"v3x=\t"<<_v3x<<endl; cout<<"v3y=\t"<<_v3y<<endl; cout<<"v3z=\t"<<_v3z<<endl; return v3; } pair<double, double> QFS::Lorentz(double gamma,double beta,double e,double p) { double eL = gamma*e - gamma*beta*p; double pL = gamma*p - gamma*beta*e; return make_pair(eL, pL); }