7 #include <FairLogger.h> 
    8 #include <FairParticle.h> 
    9 #include <FairPrimaryGenerator.h> 
   10 #include <FairRunSim.h> 
   12 #include <TDatabasePDG.h> 
   14 #include <TParticle.h> 
   15 #include <TParticlePDG.h> 
   25 constexpr 
auto cRED = 
"\033[1;31m";
 
   28 constexpr 
auto cGREEN = 
"\033[1;32m";
 
   29 constexpr 
auto cBLUE = 
"\033[1;34m";
 
   31 Int_t AtTPC2Body::fgNIon = 0;
 
   41                        Int_t mult, std::vector<Double_t> *px, std::vector<Double_t> *py, std::vector<Double_t> *pz,
 
   42                        std::vector<Double_t> *mass, std::vector<Double_t> *Ex, Double_t ResEner, Double_t MinCMSAng,
 
   44    : fMult(mult), fPx(0.), fPy(0.), fPz(0.), fVx(0.), fVy(0.), fVz(0.), fIon(0), fPType(0.), fQ(0),
 
   45      fThetaCmsMin(MinCMSAng), fThetaCmsMax(MaxCMSAng), fBeamEnergy_buff(ResEner), fNoSolution(kFALSE),
 
   46      fIsFixedTargetPos(kFALSE), fIsFixedMomentum(kFALSE)
 
   52    auto *kProton = 
new TParticle(); 
 
   53    kProton->SetPdgCode(2212);
 
   54    auto *kNeutron = 
new TParticle(); 
 
   55    kNeutron->SetPdgCode(2112);
 
   57    for (Int_t i = 0; i < fMult; i++) {
 
   59       fPx.push_back(Double_t(a->at(i)) * px->at(i));
 
   60       fPy.push_back(Double_t(a->at(i)) * py->at(i));
 
   61       fPz.push_back(Double_t(a->at(i)) * pz->at(i));
 
   62       Masses.push_back(mass->at(i) * 1000.0);
 
   63       fExEnergy.push_back(Ex->at(i));
 
   64       fWm.push_back(mass->at(i) * 1000.0 * 0.93149401 + Ex->at(i));
 
   66       FairParticle *ParticleBuff;
 
   67       sprintf(buffer, 
"Product_Ion%d", i);
 
   71          IonBuff = 
new FairIon(buffer, z->at(i), a->at(i), q->at(i), 0.0, mass->at(i)); 
 
   72          ParticleBuff = 
new FairParticle(
"dummyPart", 1, 1, 1.0, 0, 0.0, 0.0);          
 
   73          fPType.emplace_back(
"Ion");
 
   74          std::cout << 
" Adding : " << buffer << std::endl;
 
   76       } 
else if (a->at(i) == 1 && z->at(i) == 1) {
 
   78          IonBuff = 
new FairIon(
"dummyIon", 50, 50, 0, 0.0, 100); 
 
   79          ParticleBuff = 
new FairParticle(2212, kProton);         
 
   80          fPType.emplace_back(
"Proton");
 
   82       } 
else if (a->at(i) == 1 && z->at(i) == 0) {
 
   84          IonBuff = 
new FairIon(
"dummyIon", 50, 50, 0, 0.0, 100); 
 
   85          ParticleBuff = 
new FairParticle(2112, kNeutron);        
 
   86          fPType.emplace_back(
"Neutron");
 
   89       std::cout << 
" Z " << z->at(i) << 
" A " << a->at(i) << std::endl;
 
   91       fIon.push_back(IonBuff);
 
   92       fParticle.push_back(ParticleBuff);
 
   95    FairRunSim *run = FairRunSim::Instance();
 
   97       std::cout << 
"-E- FairIonGenerator: No FairRun instantised!" << std::endl;
 
   98       Fatal(
"FairIonGenerator", 
"No FairRun instantised!");
 
  101    for (Int_t i = 0; i < fMult; i++) {
 
  103       if (fPType.at(i) == 
"Ion") {
 
  105          std::cout << 
" In position " << i << 
" adding an : " << fPType.at(i) << std::endl;
 
  106          run->AddNewIon(fIon.at(i)); 
 
  107          std::cout << 
" fIon name :" << fIon.at(i)->GetName() << std::endl;
 
  108          std::cout << 
" fParticle name :" << fParticle.at(i)->GetName() << std::endl;
 
  110       } 
else if (fPType.at(i) == 
"Proton") {
 
  112          std::cout << 
" In position " << i << 
" adding an : " << fPType.at(i) << std::endl;
 
  114          std::cout << 
" fIon name :" << fIon.at(i)->GetName() << std::endl;
 
  115          std::cout << 
" fParticle name :" << fParticle.at(i)->GetName() << std::endl;
 
  116          std::cout << fParticle.at(i)->GetName() << std::endl;
 
  118       } 
else if (fPType.at(i) == 
"Neutron") {
 
  120          std::cout << 
" In position " << i << 
" adding an : " << fPType.at(i) << std::endl;
 
  122          std::cout << 
" fIon name :" << fIon.at(i)->GetName() << std::endl;
 
  123          std::cout << 
" fParticle name :" << fParticle.at(i)->GetName() << std::endl;
 
  124          std::cout << fParticle.at(i)->GetName() << std::endl;
 
  131    std::cout << 
" -I- AtTPC2Body : Fixed target position at " << vx << 
"   " << vy << 
"   " << vz << std::endl;
 
  132    fIsFixedTargetPos = kTRUE;
 
  140    std::cout << 
" -I- AtTPC2Body : Fixed beam momentum " << px << 
"  " << py << 
"   " << pz << std::endl;
 
  141    fIsFixedMomentum = kTRUE;
 
  151    std::vector<Double_t> Ang; 
 
  152    std::vector<Double_t> Ene; 
 
  163    Double_t costhetamin = TMath::Cos(fThetaCmsMin * TMath::DegToRad());
 
  164    Double_t costhetamax = TMath::Cos(fThetaCmsMax * TMath::DegToRad());
 
  167    Double_t thetacmsInput =
 
  168       TMath::ACos((costhetamax - costhetamin) * gRandom->Uniform() + costhetamin) * TMath::RadToDeg();
 
  170    std::cout << 
cBLUE << 
" -I- AtTPC2Body : Random CMS Theta angle in degrees : " << thetacmsInput << 
cNORMAL 
  172    const Double_t rad2deg = 0.0174532925;
 
  174    if (fIsFixedTargetPos) {
 
  175       fBeamEnergy = fBeamEnergy_buff;
 
  177       std::cout << 
cBLUE << 
" -I- AtTPC2Body Beam energy (Fixed Target mode) : " << fBeamEnergy << 
cNORMAL << std::endl;
 
  182       std::cout << 
cBLUE << 
" -I- AtTPC2Body Residual energy (Active Target mode) : " 
  186    if (fBeamEnergy > 0 &&
 
  188         fIsFixedTargetPos)) { 
 
  190       if (fIsFixedTargetPos) {
 
  191          fPxBeam = fPxBeam_buff;
 
  192          fPyBeam = fPyBeam_buff;
 
  193          fPzBeam = fPzBeam_buff;
 
  202       Double_t eb = fBeamEnergy + fWm.at(0);
 
  203       Double_t pb2 = fBeamEnergy * fBeamEnergy + 2.0 * fBeamEnergy * fWm.at(0);
 
  204       Double_t pb = TMath::Sqrt(pb2);
 
  205       Double_t beta = pb / (eb + fWm.at(1));
 
  206       Double_t gamma = 1.0 / sqrt(1.0 - beta * beta);
 
  208       Double_t thetacms = thetacmsInput * rad2deg; 
 
  210       Double_t thetacmr = TMath::Pi() - thetacms;
 
  211       Double_t e = fBeamEnergy + fWm.at(0) + fWm.at(1);
 
  212       Double_t e_cm2 = e * e - pb2;
 
  213       Double_t e_cm = TMath::Sqrt(e_cm2);
 
  214       Double_t t_cm = e_cm - fWm.at(2) - fWm.at(3);
 
  217          std::cout << 
"-I- AtTPC2Body : No solution!" << std::endl;
 
  225          Double_t t_cm2 = t_cm * t_cm;
 
  226          Double_t t3_cm = (t_cm2 + 2. * fWm.at(3) * t_cm) / (t_cm + fWm.at(2) + fWm.at(3)) / 2.0;
 
  227          Double_t t4_cm = (t_cm2 + 2. * fWm.at(2) * t_cm) / (t_cm + fWm.at(2) + fWm.at(3)) / 2.0;
 
  228          Double_t p3_cm2 = t3_cm * t3_cm + 2.0 * t3_cm * fWm.at(2);
 
  229          Double_t p3_cm = TMath::Sqrt(p3_cm2);
 
  230          Double_t tg_thetalabs =
 
  231             p3_cm * TMath::Sin(thetacms) /
 
  232             (gamma * (p3_cm * TMath::Cos(thetacms) + beta * TMath::Sqrt(p3_cm * p3_cm + fWm.at(2) * fWm.at(2))));
 
  234          if (tg_thetalabs >= 1.0e6) {
 
  235             Ang.push_back(TMath::Pi() / 2.0);
 
  237             Ang.push_back(TMath::ATan(tg_thetalabs));
 
  241             Ang.at(0) = TMath::Pi() + Ang.at(0);
 
  243          Double_t p4_cm2 = t4_cm * t4_cm + 2. * t4_cm * fWm.at(3);
 
  244          Double_t p4_cm = TMath::Sqrt(p4_cm2);
 
  245          Double_t tg_thetalabr =
 
  246             p4_cm * TMath::Sin(thetacmr) /
 
  247             (gamma * (p4_cm * TMath::Cos(thetacmr) + beta * TMath::Sqrt(p4_cm * p4_cm + fWm.at(3) * fWm.at(3))));
 
  250          if (tg_thetalabr > 1.0e6) {
 
  251             Ang.push_back(TMath::Pi() / 2.0);
 
  253             Ang.push_back(TMath::ATan(tg_thetalabr));
 
  257             Ang.at(1) = TMath::Pi() + Ang.at(1);
 
  261          Double_t p3_cmx = p3_cm * sin(thetacms);
 
  262          Double_t p3_cmz = p3_cm * cos(thetacms);
 
  263          Double_t p3_labx = p3_cmx;
 
  264          Double_t p3_labz = gamma * (p3_cmz + beta * (t3_cm + fWm.at(2)));
 
  265          Double_t p3_lab = TMath::Sqrt(p3_labx * p3_labx + p3_labz * p3_labz);
 
  266          Ene.push_back(TMath::Sqrt(p3_lab * p3_lab + fWm.at(2) * fWm.at(2)) - fWm.at(2));
 
  268          Double_t p4_cmx = p4_cm * sin(thetacmr);
 
  269          Double_t p4_cmz = p4_cm * cos(thetacmr);
 
  270          Double_t p4_labx = p4_cmx;
 
  271          Double_t p4_labz = gamma * (p4_cmz + beta * (t4_cm + fWm.at(3)));
 
  272          Double_t p4_lab = TMath::Sqrt(p4_labx * p4_labx + p4_labz * p4_labz);
 
  273          Ene.push_back(TMath::Sqrt(p4_lab * p4_lab + fWm.at(3) * fWm.at(3)) - fWm.at(3));
 
  276             std::cout << 
" -I- ===== AtTPC2Body - Kinematics ====== " << std::endl;
 
  277             std::cout << 
" -I- ===== No Valid Solution on Beam Event for these kinematics (probably due to threshold " 
  280             std::cout << 
" -I- ===== Setting Values to 0  ====== " << std::endl;
 
  288             std::cout << 
cBLUE << 
" -I- ===== AtTPC2Body - Kinematics ====== " << std::endl;
 
  289             std::cout << 
" Decay of scattered particle enabled : " << kIsDecay << 
"\n";
 
  290             std::cout << 
" Scattered energy:" << Ene.at(0) << 
" MeV" << std::endl;
 
  291             std::cout << 
" Scattered  angle:" << Ang.at(0) * 180 / TMath::Pi() << 
" deg" << std::endl;
 
  292             std::cout << 
" Recoil energy:" << Ene.at(1) << 
" MeV" << std::endl;
 
  293             std::cout << 
" Recoiled angle:" << Ang.at(1) * 180.0 / TMath::Pi() << 
" deg" << 
cNORMAL << std::endl;
 
  311          fPx.at(2) = p3_labx / 1000.0; 
 
  313          fPz.at(2) = p3_labz / 1000.0;
 
  315          fPx.at(3) = p4_labx / 1000.0;
 
  317          fPz.at(3) = p4_labz / 1000.0;
 
  319          Double_t phiBeam1 = 0., phiBeam2 = 0.;
 
  321          phiBeam1 = 2 * TMath::Pi() * gRandom->Uniform(); 
 
  322          phiBeam2 = phiBeam1 + TMath::Pi();
 
  337          TVector3 BeamPos(fPxBeam * 1000, fPyBeam * 1000, fPzBeam * 1000); 
 
  339          LOG(DEBUG) << 
" Beam Theta (Mom) : " << BeamPos.Theta() * 180.0 / TMath::Pi();
 
  340          LOG(DEBUG) << 
" Beam Phi (Mom) : " << BeamPos.Phi() * 180.0 / TMath::Pi();
 
  342          Double_t thetaLab1, phiLab1, thetaLab2, phiLab2;
 
  343          auto EulerTransformer = std::make_unique<AtEulerTransformation>();
 
  344          EulerTransformer->SetBeamDirectionAtVertexTheta(BeamPos.Theta());
 
  345          EulerTransformer->SetBeamDirectionAtVertexPhi(BeamPos.Phi());
 
  347          EulerTransformer->SetThetaInBeamSystem(Ang.at(0));
 
  348          EulerTransformer->SetPhiInBeamSystem(phiBeam1);
 
  349          EulerTransformer->DoTheEulerTransformationBeam2Lab(); 
 
  352          thetaLab1 = EulerTransformer->GetThetaInLabSystem();
 
  353          phiLab1 = EulerTransformer->GetPhiInLabSystem();
 
  354          LOG(DEBUG) << 
" Scattered  angle Phi :" << phiBeam1 * 180.0 / TMath::Pi() << 
" deg";
 
  355          LOG(DEBUG) << 
" Scattered  angle Theta (Euler) :" << thetaLab1 * 180.0 / TMath::Pi() << 
" deg";
 
  356          LOG(DEBUG) << 
" Scattered  angle Phi (Euler) :" << phiLab1 * 180.0 / TMath::Pi() << 
" deg";
 
  362          TVector3 direction1 = TVector3(sin(thetaLab1) * cos(phiLab1), sin(thetaLab1) * sin(phiLab1), cos(thetaLab1));
 
  364          EulerTransformer->SetThetaInBeamSystem(Ang.at(1));
 
  365          EulerTransformer->SetPhiInBeamSystem(phiBeam2);
 
  366          EulerTransformer->DoTheEulerTransformationBeam2Lab(); 
 
  369          thetaLab2 = EulerTransformer->GetThetaInLabSystem();
 
  370          phiLab2 = EulerTransformer->GetPhiInLabSystem();
 
  372          TVector3 direction2 = TVector3(sin(thetaLab2) * cos(phiLab2), sin(thetaLab2) * sin(phiLab2), cos(thetaLab2));
 
  374          LOG(DEBUG) << 
" Recoiled  angle Phi :" << phiBeam2 * 180.0 / TMath::Pi() << 
" deg";
 
  375          LOG(DEBUG) << 
" Recoiled  angle Theta (Euler) :" << thetaLab2 * 180.0 / TMath::Pi() << 
" deg";
 
  376          LOG(DEBUG) << 
" Recoiled  angle Phi (Euler) :" << phiLab2 * 180.0 / TMath::Pi() << 
" deg";
 
  378          LOG(DEBUG) << 
"  Phi Diference :" << (phiBeam1 * 180.0 / TMath::Pi()) - (phiBeam2 * 180.0 / TMath::Pi())
 
  380          LOG(DEBUG) << 
"  Phi Diference (Euler) :" << (phiLab1 * 180.0 / TMath::Pi()) - (phiLab2 * 180.0 / TMath::Pi())
 
  383          LOG(DEBUG) << 
" Direction 1 Theta : " << direction1.Theta() * 180.0 / TMath::Pi();
 
  384          LOG(DEBUG) << 
" Direction 1 Phi : " << direction1.Phi() * 180.0 / TMath::Pi();
 
  385          LOG(DEBUG) << 
" Direction 2 Theta : " << direction2.Theta() * 180.0 / TMath::Pi();
 
  386          LOG(DEBUG) << 
" Direction 2 Phi : " << direction2.Phi() * 180.0 / TMath::Pi();
 
  388          fPx.at(2) = p3_lab * direction1.X() / 1000.0; 
 
  389          fPy.at(2) = p3_lab * direction1.Y() / 1000.0;
 
  390          fPz.at(2) = p3_lab * direction1.Z() / 1000.0;
 
  392          fPx.at(3) = p4_lab * direction2.X() / 1000.0;
 
  393          fPy.at(3) = p4_lab * direction2.Y() / 1000.0;
 
  394          fPz.at(3) = p4_lab * direction2.Z() / 1000.0;
 
  444       for (Int_t i = 0; i < fMult; i++) {
 
  446          TParticlePDG *thisPart = 
nullptr;
 
  448          if (fPType.at(i) == 
"Ion")
 
  449             thisPart = TDatabasePDG::Instance()->GetParticle(fIon.at(i)->GetName());
 
  450          else if (fPType.at(i) == 
"Proton")
 
  451             thisPart = TDatabasePDG::Instance()->GetParticle(fParticle.at(i)->GetName());
 
  452          else if (fPType.at(i) == 
"Neutron")
 
  453             thisPart = TDatabasePDG::Instance()->GetParticle(fParticle.at(i)->GetName());
 
  457             if (fPType.at(i) == 
"Ion")
 
  458                std::cout << 
"-W- FairIonGenerator: Ion " << fIon.at(i)->GetName() << 
" not found in database!" 
  460             else if (fPType.at(i) == 
"Proton")
 
  461                std::cout << 
"-W- FairIonGenerator: Particle " << fParticle.at(i)->GetName() << 
" not found in database!" 
  463             else if (fPType.at(i) == 
"Neutron")
 
  464                std::cout << 
"-W- FairIonGenerator: Particle " << fParticle.at(i)->GetName() << 
" not found in database!" 
  470          int pdgType = thisPart->PdgCode();
 
  473          if (fIsFixedTargetPos) {
 
  486          TVector3 ScatP(fPx.at(2), fPy.at(2), fPz.at(2));
 
  490          Int_t trackIdCut = 0;
 
  498              pdgType != 1000500500 && fPType.at(i) == 
"Ion") {
 
  500             std::cout << 
cBLUE << 
"-I- FairIonGenerator: Generating ions of type " << fIon.at(i)->GetName()
 
  501                       << 
" (PDG code " << pdgType << 
")" << std::endl;
 
  502             std::cout << 
"    Momentum (" << fPx.at(i) << 
", " << fPy.at(i) << 
", " << fPz.at(i)
 
  503                       << 
") Gev from vertex (" << fVx << 
", " << fVy << 
", " << fVz << 
") cm" << std::endl;
 
  504             primGen->AddTrack(pdgType, fPx.at(i), fPy.at(i), fPz.at(i), fVx, fVy, fVz);
 
  507                     pdgType == 2212 && fPType.at(i) == 
"Proton") {
 
  509             std::cout << 
"-I- FairIonGenerator: Generating ions of type " << fParticle.at(i)->GetName() << 
" (PDG code " 
  510                       << pdgType << 
")" << std::endl;
 
  511             std::cout << 
"    Momentum (" << fPx.at(i) << 
", " << fPy.at(i) << 
", " << fPz.at(i)
 
  512                       << 
") Gev from vertex (" << fVx << 
", " << fVy << 
", " << fVz << 
") cm" << std::endl;
 
  513             primGen->AddTrack(pdgType, fPx.at(i), fPy.at(i), fPz.at(i), fVx, fVy, fVz);
 
  516                     pdgType == 2112 && fPType.at(i) == 
"Neutron") {
 
  518             std::cout << 
"-I- FairIonGenerator: Generating ions of type " << fParticle.at(i)->GetName() << 
" (PDG code " 
  519                       << pdgType << 
")" << std::endl;
 
  520             std::cout << 
"    Momentum (" << fPx.at(i) << 
", " << fPy.at(i) << 
", " << fPz.at(i)
 
  521                       << 
") Gev from vertex (" << fVx << 
", " << fVy << 
", " << fVz << 
") cm" << 
cNORMAL << std::endl;
 
  522             primGen->AddTrack(pdgType, fPx.at(i), fPy.at(i), fPz.at(i), fVx, fVy, fVz);
 
  528    if (kIsDecay == kFALSE)