LCOV - code coverage report
Current view: top level - EVGEN - AliGenDeuteron.cxx (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 181 0.6 %
Date: 2016-06-14 17:26:59 Functions: 1 18 5.6 %

          Line data    Source code
       1             : /**************************************************************************
       2             :  * Copyright(c) 2009-2010, ALICE Experiment at CERN, All rights reserved. *
       3             :  *                                                                        *
       4             :  * Author: The ALICE Off-line Project.                                    *
       5             :  * Contributors are mentioned in the code where appropriate.              *
       6             :  *                                                                        *
       7             :  * Permission to use, copy, modify and distribute this software and its   *
       8             :  * documentation strictly for non-commercial purposes is hereby granted   *
       9             :  * without fee, provided that the above copyright notice appears in all   *
      10             :  * copies and that both the copyright notice and this permission notice   *
      11             :  * appear in the supporting documentation. The authors make no claims     *
      12             :  * about the suitability of this software for any purpose. It is          *
      13             :  * provided "as is" without express or implied warranty.                  *
      14             :  **************************************************************************/
      15             : 
      16             : //////////////////////////////////////////////////////////////////////////
      17             : // Afterburner to generate (anti)deuterons simulating coalescence of
      18             : // (anti)nucleons as in A. J. Baltz et al., Phys. lett B 325(1994)7.
      19             : // If the nucleon generator does not provide a spatial description of 
      20             : // the source the afterburner can provide one.
      21             : //
      22             : // There two options for the source: a thermal picture where all nucleons
      23             : // are placed randomly and homogeneously in an spherical volume, or
      24             : // an expansion one where they are projected onto its surface.
      25             : //
      26             : // An (anti)deuteron will form if there is a pair of (anti)proton-(anti)neutron
      27             : // with momentum difference less than ~ 300MeV and relative distance less than
      28             : // ~ 2.1fm. Only 3/4 of these clusters are accepted due to the deuteron spin.
      29             : //
      30             : // When there are more than one pair fulfilling the coalescence conditions,
      31             : // the selected pair can be the one with the first partner, with
      32             : // the lowest relative momentum, the lowest relative distance or both.
      33             : //////////////////////////////////////////////////////////////////////////
      34             : 
      35             : // Author: Eulogio Serradilla <eulogio.serradilla@ciemat.es>,
      36             : //         Arturo Menchaca <menchaca@fisica.unam.mx>
      37             : //
      38             : 
      39             : #include "Riostream.h"
      40             : #include "TParticle.h"
      41             : #include "AliStack.h"
      42             : #include "AliRun.h"
      43             : #include "TMath.h"
      44             : #include "TMCProcess.h"
      45             : #include "TList.h"
      46             : #include "TVector3.h"
      47             : #include "AliMC.h"
      48             : #include "TArrayF.h"
      49             : #include "AliCollisionGeometry.h"
      50             : #include "AliGenCocktailEventHeader.h"
      51             : #include "AliGenCocktailEntry.h"
      52             : #include "AliGenCocktailAfterBurner.h"
      53             : #include "AliGenDeuteron.h"
      54             : #include "AliLog.h"
      55             : 
      56           6 : ClassImp(AliGenDeuteron)
      57             : 
      58           0 : AliGenDeuteron::AliGenDeuteron(Int_t sign, Double_t pmax, Double_t rmax, Int_t cluster)
      59           0 :  :fSign(1)
      60           0 :  ,fPmax(pmax)
      61           0 :  ,fRmax(rmax)
      62           0 :  ,fSpinProb(1)
      63           0 :  ,fClusterType(cluster)
      64           0 :  ,fModel(0)
      65           0 :  ,fTimeLength(2.5)
      66           0 :  ,fB(0)
      67           0 :  ,fR(0)
      68           0 :  ,fPsiR(0)
      69           0 :  ,fCurStack(0)
      70           0 : {
      71             : //
      72             : // constructor
      73             : //
      74           0 :         fSign = sign > 0 ? 1:-1;
      75             :         
      76           0 : }
      77             : 
      78           0 : AliGenDeuteron::~AliGenDeuteron()
      79           0 : {
      80             : //
      81             : // Default destructor
      82             : //
      83           0 : }
      84             : 
      85             : void AliGenDeuteron::Init()
      86             : {
      87             : //
      88             : // Standard AliGenerator initializer
      89             : //
      90           0 : }
      91             : 
      92             : void AliGenDeuteron::Generate()
      93             : {
      94             : //
      95             : // Look for coalescence of (anti)nucleons in the nucleon source
      96             : // provided by the generator cocktail
      97             : //
      98           0 :         AliInfo(Form("sign: %d, Pmax: %g GeV/c, Rmax: %g fm, cluster: %d",fSign, fPmax, fRmax, fClusterType));
      99           0 :         if(fModel!=kNone) AliInfo(Form("model: %d, time: %g fm/c", fModel, fTimeLength));
     100             :         
     101           0 :         AliGenCocktailAfterBurner* gener = (AliGenCocktailAfterBurner*)gAlice->GetMCApp()->Generator();
     102             :         
     103             :         // find nuclear radius, only for first generator and projectile=target
     104             :         Bool_t collisionGeometry=0;
     105           0 :         if(fModel != kNone && gener->FirstGenerator()->Generator()->ProvidesCollisionGeometry())
     106             :         {
     107           0 :                 TString name;
     108           0 :                 Int_t ap, zp, at, zt;
     109           0 :                 gener->FirstGenerator()->Generator()->GetProjectile(name,ap,zp);
     110           0 :                 gener->FirstGenerator()->Generator()->GetTarget(name,at,zt);
     111           0 :                 if(ap != at) AliWarning("projectile and target have different size");
     112           0 :                 fR = 1.29*TMath::Power(at, 1./3.);
     113             :                 collisionGeometry = 1;
     114           0 :         }
     115             :         
     116           0 :         for(Int_t ns = 0; ns < gener->GetNumberOfEvents(); ++ns)
     117             :         {
     118           0 :                 gener->SetActiveEventNumber(ns);
     119             :                 
     120           0 :                 if(fModel != kNone && collisionGeometry)
     121             :                 {
     122           0 :                         fPsiR = (gener->GetCollisionGeometry(ns))->ReactionPlaneAngle();
     123           0 :                         fB = (gener->GetCollisionGeometry(ns))->ImpactParameter();
     124             :                         
     125           0 :                         if(fB >= 2.*fR) continue; // no collision
     126             :                 }
     127             :                 
     128           0 :                 fCurStack = gener->GetStack(ns);
     129           0 :                 if(!fCurStack)
     130             :                 {
     131           0 :                         AliWarning("no event stack");
     132           0 :                         return;
     133             :                 }
     134             :                 
     135           0 :                 TList* protons = new TList();
     136           0 :                 protons->SetOwner(kFALSE);
     137           0 :                 TList* neutrons = new TList();
     138           0 :                 neutrons->SetOwner(kFALSE);
     139             :                 
     140             :                 // particles produced by the generator
     141           0 :                 for (Int_t i=0; i < fCurStack->GetNprimary(); ++i)
     142             :                 {
     143           0 :                         TParticle* iParticle = fCurStack->Particle(i);
     144             :                         
     145           0 :                         if(iParticle->GetStatusCode() != 1) continue;
     146             :                         
     147           0 :                         Int_t pdgCode = iParticle->GetPdgCode();
     148           0 :                         if(pdgCode == fSign*2212)// (anti)proton
     149             :                         {
     150           0 :                                 FixProductionVertex(iParticle);
     151           0 :                                 protons->Add(iParticle);
     152           0 :                         }
     153           0 :                         else if(pdgCode == fSign*2112) // (anti)neutron
     154             :                         {
     155           0 :                                 FixProductionVertex(iParticle);
     156           0 :                                 neutrons->Add(iParticle);
     157           0 :                         }
     158           0 :                 }
     159             :                 
     160             :                 // look for clusters
     161           0 :                 if(fClusterType==kFirstPartner)
     162             :                 {
     163           0 :                         FirstPartner(protons, neutrons);
     164           0 :                 }
     165             :                 else
     166             :                 {
     167           0 :                         WeightMatrix(protons, neutrons);
     168             :                 }
     169             :                 
     170           0 :                 protons->Clear("nodelete");
     171           0 :                 neutrons->Clear("nodelete");
     172             :                 
     173           0 :                 delete protons;
     174           0 :                 delete neutrons;
     175           0 :         }
     176             :         
     177           0 :         AliInfo("DONE");
     178           0 : }
     179             : 
     180             : Double_t AliGenDeuteron::GetCoalescenceProbability(const TParticle* nucleon1, const TParticle* nucleon2) const
     181             : {
     182             : //
     183             : // Coalescence conditions as in
     184             : // A. J. Baltz et al., Phys. lett B 325(1994)7
     185             : //
     186             : // returns < 0 if coalescence is not possible
     187             : // otherwise returns a coalescence probability
     188             : //
     189             :         const Double_t kProtonMass  = 0.938272013;
     190             :         const Double_t kNeutronMass = 0.939565378;
     191             :         
     192           0 :         TVector3 v1(nucleon1->Vx(), nucleon1->Vy(), nucleon1->Vz());
     193           0 :         TVector3 p1(nucleon1->Px(), nucleon1->Py(), nucleon1->Pz());
     194             :         
     195           0 :         TVector3 v2(nucleon2->Vx(), nucleon2->Vy(), nucleon2->Vz());
     196           0 :         TVector3 p2(nucleon2->Px(), nucleon2->Py(), nucleon2->Pz());
     197             :         
     198           0 :         Double_t deltaP = this->GetPcm(p1, kProtonMass, p2, kNeutronMass); // relative momentum in CM frame
     199           0 :         if( deltaP >= fPmax) return -1.;
     200             :         
     201           0 :         Double_t deltaR = (v2-v1).Mag();       // relative distance (cm)
     202           0 :         if(deltaR >= fRmax*1.e-13) return -1.;
     203             :         
     204           0 :         if(Rndm() > fSpinProb)    return -1.;  // spin
     205             :         
     206           0 :         if(fClusterType == kLowestMomentum) return 1. - deltaP/fPmax;
     207           0 :         if(fClusterType == kLowestDistance) return 1. - 1.e+13*deltaR/fRmax;
     208             :         
     209           0 :         return 1. - 1.e+13*(deltaP*deltaR)/(fRmax*fPmax);
     210           0 : }
     211             : 
     212             : void AliGenDeuteron::FirstPartner(const TList* protons, TList* neutrons)
     213             : {
     214             : //
     215             : // Clusters are made with the first nucleon pair that fulfill
     216             : // the coalescence conditions, starting with the protons
     217             : //
     218           0 :         TIter p_next(protons);
     219           0 :         while(TParticle* n0 = (TParticle*) p_next())
     220             :         {
     221             :                 TParticle* partner = 0;
     222           0 :                 TIter n_next(neutrons);
     223           0 :                 while(TParticle* n1 = (TParticle*) n_next() )
     224             :                 {
     225           0 :                         if(GetCoalescenceProbability(n0, n1) < 0 ) continue; // with next neutron
     226             :                         partner = n1;
     227           0 :                         break;
     228             :                 }
     229             :                 
     230           0 :                 if(partner == 0) continue; // with next proton
     231             :                 
     232           0 :                 PushDeuteron(n0, partner);
     233             :                 
     234             :                 // Remove from the list for the next iteration
     235           0 :                 neutrons->Remove(partner);
     236           0 :         }
     237           0 : }
     238             : 
     239             : void AliGenDeuteron::WeightMatrix(const TList* protons, const TList* neutrons)
     240             : {
     241             : //
     242             : // Build all possible nucleon pairs with their own probability
     243             : // and select only those with the highest coalescence probability
     244             : //
     245           0 :         Int_t nMaxPairs = protons->GetSize()*neutrons->GetSize();
     246             :         
     247           0 :         TParticle** cProton = new TParticle*[nMaxPairs];
     248           0 :         TParticle** cNeutron = new TParticle*[nMaxPairs];
     249           0 :         Double_t*  cWeight = new Double_t[nMaxPairs];
     250             :         
     251             :         // build all pairs with probability > 0
     252             :         Int_t cIdx = -1;
     253           0 :         TIter p_next(protons);
     254           0 :         while(TParticle* n1 = (TParticle*) p_next())
     255             :         {
     256           0 :                 TIter n_next(neutrons);
     257           0 :                 while(TParticle* n2 = (TParticle*) n_next() )
     258             :                 {
     259           0 :                         Double_t weight = this->GetCoalescenceProbability(n1,n2);
     260           0 :                         if(weight < 0) continue;
     261           0 :                         ++cIdx;
     262           0 :                         cProton[cIdx]  = n1;
     263           0 :                         cNeutron[cIdx] = n2;
     264           0 :                         cWeight[cIdx]  = weight;
     265           0 :                 }
     266           0 :                 n_next.Reset();
     267           0 :         }
     268           0 :         p_next.Reset();
     269             :         
     270           0 :         Int_t nPairs = cIdx + 1;
     271             :         
     272             :         // find the interacting pairs:
     273             :         // remove repeated pairs and select only
     274             :         // the pair with the highest coalescence probability
     275             :         
     276           0 :         Int_t nMaxIntPair = TMath::Min(protons->GetSize(), neutrons->GetSize());
     277             :         
     278           0 :         TParticle** iProton = new TParticle*[nMaxIntPair];
     279           0 :         TParticle** iNeutron = new TParticle*[nMaxIntPair];
     280           0 :         Double_t* iWeight = new Double_t[nMaxIntPair];
     281             :         
     282             :         Int_t iIdx = -1;
     283           0 :         while(kTRUE)
     284             :         {
     285             :                 Int_t j = -1;
     286             :                 Double_t wMax = 0;
     287           0 :                 for(Int_t i=0; i < nPairs; ++i)
     288             :                 {
     289           0 :                         if(cWeight[i] > wMax)
     290             :                         {
     291             :                                 wMax=cWeight[i];
     292             :                                 j = i;
     293           0 :                         }
     294             :                 }
     295             :                 
     296           0 :                 if(j == -1 ) break; // end
     297             :                 
     298             :                 // Save the interacting pair
     299           0 :                 ++iIdx;
     300           0 :                 iProton[iIdx]  = cProton[j];
     301           0 :                 iNeutron[iIdx] = cNeutron[j];
     302           0 :                 iWeight[iIdx]  = cWeight[j];
     303             :                 
     304             :                 // invalidate all combinations with these pairs for the next iteration
     305           0 :                 for(Int_t i=0; i < nPairs; ++i)
     306             :                 {
     307           0 :                         if(cProton[i] == iProton[iIdx]) cWeight[i] = -1.;
     308           0 :                         if(cNeutron[i] == iNeutron[iIdx]) cWeight[i] = -1.;
     309             :                 }
     310           0 :         }
     311             :         
     312           0 :         Int_t nIntPairs = iIdx + 1;
     313             :         
     314           0 :         delete[] cProton;
     315           0 :         delete[] cNeutron;
     316           0 :         delete[] cWeight;
     317             :         
     318             :         // Add the (anti)deuterons to the current event stack
     319           0 :         for(Int_t i=0; i<nIntPairs; ++i)
     320             :         {
     321           0 :                 TParticle* n1 = iProton[i];
     322           0 :                 TParticle* n2 = iNeutron[i];
     323           0 :                 PushDeuteron(n1,n2);
     324             :         }
     325             :         
     326           0 :         delete[] iProton;
     327           0 :         delete[] iNeutron;
     328           0 :         delete[] iWeight;
     329           0 : }
     330             : 
     331             : void AliGenDeuteron::PushDeuteron(TParticle* parent1, TParticle* parent2)
     332             : {
     333             : //
     334             : // Create an (anti)deuteron from parent1 and parent2,
     335             : // add to the current stack and set kDoneBit for the parents
     336             : //
     337             :         const Double_t kDeuteronMass = 1.87561282;
     338             :         const Int_t kDeuteronPdg = 1000010020;
     339             :         
     340             :         // momentum
     341           0 :         TVector3 p1(parent1->Px(), parent1->Py(), parent1->Pz());
     342           0 :         TVector3 p2(parent2->Px(), parent2->Py(), parent2->Pz());
     343           0 :         TVector3 pN = p1+p2;
     344             :         
     345             :         // production vertex same as the parent1's
     346           0 :         TVector3 vN(parent1->Vx(), parent1->Vy(), parent1->Vz());
     347             :         
     348             :         // E^2 = p^2 + m^2
     349           0 :         Double_t energy = TMath::Sqrt(pN.Mag2() + kDeuteronMass*kDeuteronMass);
     350             :         
     351           0 :         Int_t ntrk = 0;
     352             :         Double_t weight = 1;
     353             :         Int_t is = 1; // final state particle
     354             :         
     355             :         // Add a new (anti)deuteron to current event stack
     356           0 :         fCurStack->PushTrack(1, -1, fSign*kDeuteronPdg,
     357           0 :                          pN.X(), pN.Y(), pN.Z(), energy,
     358           0 :                          vN.X(), vN.Y(), vN.Z(), parent1->T(),
     359             :                          0., 0., 0., kPNCapture, ntrk, weight, is);
     360             :         
     361             :         // change the status code of the parents
     362           0 :         parent1->SetStatusCode(kCluster);
     363           0 :         parent2->SetStatusCode(kCluster);
     364             :         
     365             :         // Set kDoneBit for the parents
     366           0 :         parent1->SetBit(kDoneBit);
     367           0 :         parent2->SetBit(kDoneBit);
     368           0 : }
     369             : 
     370             : void AliGenDeuteron::FixProductionVertex(TParticle* i)
     371             : {
     372             : //
     373             : // Replace current generator nucleon spatial distribution
     374             : // with a custom distribution according to the selected model
     375             : //
     376           0 :         if(fModel == kNone || fModel > kExpansion) return;
     377             :         
     378             :         // semi-axis from collision geometry (fm)
     379           0 :         Double_t a = fTimeLength + TMath::Sqrt(fR*fR - fB*fB/4.);
     380           0 :         Double_t b = fTimeLength + fR - fB/2.;
     381             :         Double_t c = fTimeLength;
     382             :         
     383             :         Double_t xx = 0;
     384             :         Double_t yy = 0;
     385             :         Double_t zz = 0;
     386             :         
     387           0 :         if(fModel == kThermal)
     388             :         {
     389             :                 // uniformly ditributed in the volume on an ellipsoid
     390             :                 // random (r,theta,phi) unit sphere
     391           0 :                 Double_t r = TMath::Power(Rndm(),1./3.);
     392           0 :                 Double_t theta = TMath::ACos(2.*Rndm()-1.);
     393           0 :                 Double_t phi = 2.*TMath::Pi()*Rndm();
     394             :                 
     395             :                 // transform coordenates
     396           0 :                 xx = a*r*TMath::Sin(theta)*TMath::Cos(phi);
     397           0 :                 yy = b*r*TMath::Sin(theta)*TMath::Sin(phi);
     398           0 :                 zz = c*r*TMath::Cos(theta);
     399           0 :         }
     400           0 :         else if(fModel == kExpansion)
     401             :         {
     402             :                 // project into the surface of an ellipsoid
     403           0 :                 xx = a*TMath::Sin(i->Theta())*TMath::Cos(i->Phi());
     404           0 :                 yy = b*TMath::Sin(i->Theta())*TMath::Sin(i->Phi());
     405           0 :                 zz = c*TMath::Cos(i->Theta());
     406           0 :         }
     407             :         
     408             :         // rotate by the reaction plane angle
     409           0 :         Double_t x = xx*TMath::Cos(fPsiR)+yy*TMath::Sin(fPsiR);
     410           0 :         Double_t y = -xx*TMath::Sin(fPsiR)+yy*TMath::Cos(fPsiR);
     411             :         Double_t z = zz;
     412             :         
     413             :         // translate by the production vertex (cm)
     414           0 :         i->SetProductionVertex(i->Vx() + 1.e-13*x, i->Vy() + 1.e-13*y, i->Vz() + 1.e-13*z, i->T());
     415           0 : }
     416             : 
     417             : Double_t AliGenDeuteron::GetS(Double_t p1x, Double_t p1y, Double_t p1z, Double_t m1, Double_t p2x, Double_t p2y, Double_t p2z, Double_t m2) const
     418             : {
     419             : //
     420             : // square of the center of mass energy
     421             : //
     422           0 :         Double_t E1 = TMath::Sqrt( p1x*p1x + p1y*p1y + p1z*p1z + m1*m1);
     423           0 :         Double_t E2 = TMath::Sqrt( p2x*p2x + p2y*p2y + p2z*p2z + m2*m2);
     424             :         
     425           0 :         return (E1+E2)*(E1+E2) - ((p1x+p2x)*(p1x+p2x) + (p1y+p2y)*(p1y+p2y) + (p1z+p2z)*(p1z+p2z));
     426             : }
     427             : 
     428             : Double_t AliGenDeuteron::GetPcm(Double_t p1x, Double_t p1y, Double_t p1z, Double_t m1, Double_t p2x, Double_t p2y, Double_t p2z, Double_t m2) const
     429             : {
     430             : //
     431             : // momentum in the CM frame
     432             : //
     433           0 :         Double_t s = this->GetS(p1x, p1y, p1z, m1, p2x, p2y, p2z, m2);
     434             :         
     435           0 :         return TMath::Sqrt( (s-(m1-m2)*(m1-m2))*(s-(m1+m2)*(m1+m2)) )/(2.*TMath::Sqrt(s));
     436             : }
     437             : 
     438             : Double_t AliGenDeuteron::GetPcm(const TVector3& p1, Double_t m1, const TVector3& p2, Double_t m2) const
     439             : {
     440             : //
     441             : // momentum in the CM frame
     442             : //
     443           0 :         return this->GetPcm(p1.Px(),p1.Py(),p1.Pz(),m1,p2.Px(),p2.Py(),p2.Pz(),m2);
     444             : }
     445             : 

Generated by: LCOV version 1.11