///////////////////////////////////////////////////////////////////////////
//
// Copyright 2010
//
// This file is part of starlight.
//
// starlight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// starlight is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with starlight. If not, see .
//
///////////////////////////////////////////////////////////////////////////
//
// File and Version Information:
// $Rev:: 176 $: revision of last commit
// $Author:: jseger $: author of last commit
// $Date:: 2014-06-20 22:15:20 +0200 #$: date of last commit
//
// Description:
// Nystrand 220710
// Fixed bug which gave incorrect minv distribution in gammagammaleptonpair.
// Moved loop over W and Y from pickw to twoLeptonCrossSection in
// gammagammaleptonpair to speed up event generation.
// Changed to Woods-Saxon radius in twophotonluminosity to be consistent
// with old starligt.
//
//
///////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
#include "starlightconstants.h"
#include "gammagammaleptonpair.h"
using namespace std;
//_____________________________________________________________________________
Gammagammaleptonpair::Gammagammaleptonpair(beamBeamSystem& bbsystem)
: eventChannel(bbsystem)
{
//Initialize randomgenerator with our seed.
cout<<"Randy in leptonpair construction: "< 1.)
sigmuix = 0.;
return sigmuix;
}
//______________________________________________________________________________
void Gammagammaleptonpair::pickw(double &w)
{
// This function picks a w for the 2-photon calculation.
double x=0.,remainarea=0.,remainw=0.,a=0.,b=0.,c=0.;
int ivalw=0;
if(_wdelta != 0)
{
w=_wdelta;
ivalw=_ivalwd;
remainw=_remainwd;
}
else{
//deal with the case where sigma is an array
//_sigofw is simga integrated over y using a linear interpolation
//sigint is the integral of sgfint, normalized
//pick a random number
x = randyInstance.Rndom();//random()/(RAND_MAX+1.0);
//compare x and sgfint to find the ivalue which is just less than the random number x
for(int i=0;i<_GGlepInputnumw;i++)
{
if(x > _sigfint[i]) ivalw=i;
}
//remainder above ivalw
remainarea = x - _sigfint[ivalw];
//figure out what point corresponds to the excess area in remainarea
c = -remainarea*_signormw/(_Warray[ivalw+1]-_Warray[ivalw]);
b = _sigofw[ivalw];
a = (_sigofw[ivalw+1]-_sigofw[ivalw])/2.;
if(a==0.)
{
remainw = -c/b;
}
else{
remainw = (-b+sqrt(b*b-4.*a*c))/(2.*a);
}
_ivalwd = ivalw;
_remainwd = remainw;
//calculate the w value
w = _Warray[ivalw]+(_Warray[ivalw+1]-_Warray[ivalw])*remainw;
}
}
//______________________________________________________________________________
void Gammagammaleptonpair::picky(double &y)
{
// This function picks a y given a W
double * sigofy;
double * sgfint;
sigofy = new double[starlightLimits::MAXYBINS];
sgfint = new double[starlightLimits::MAXWBINS];
double remainw =0.,remainarea=0.,remainy=0.,a=0.,b=0.,c=0.,sgf=0.,signorm=0.,x=0.;
int ivalw=0,ivaly=0;
ivalw=_ivalwd;
remainw=_remainwd;
//average over two colums to get y array
for(int j=0;j<_GGlepInputnumy;j++)
{
sigofy[j]=_sigmax[ivalw][j]+(_sigmax[ivalw+1][j]-_sigmax[ivalw][j])*remainw;
}
//calculate the unnormalized sgfint
sgfint[0]=0.;
for(int j=0;j<_GGlepInputnumy-1;j++)
{
sgf = (sigofy[j+1]+sigofy[j])/2.;
sgfint[j+1]=sgfint[j]+sgf*(_Yarray[j+1]-_Yarray[j]);
}
//normalize the sgfint array
signorm = sgfint[_GGlepInputnumy-1];
for(int j=0;j<_GGlepInputnumy;j++)
{
sgfint[j]=sgfint[j]/signorm;
}
//pick a random number
x = randyInstance.Rndom();//random()/(RAND_MAX+1.0);
//compare x and sgfint to find the ivalue which is just less then the random number x
for(int i=0;i<_GGlepInputnumy;i++)
{
if(x > sgfint[i]) ivaly = i;
}
//remainder above ivaly
remainarea = x - sgfint[ivaly];
//figure what point corresponds to the leftover area in remainarea
c = -remainarea*signorm/(_Yarray[ivaly+1]-_Yarray[ivaly]);
b = sigofy[ivaly];
a = (sigofy[ivaly+1]-sigofy[ivaly])/2.;
if(a==0.)
{
remainy = -c/b;
}
else{
remainy = (-b + sqrt(b*b-4.*a*c))/(2.*a);
}
//calculate the y value
y = _Yarray[ivaly]+(_Yarray[ivaly+1]-_Yarray[ivaly])*remainy;
delete[] sigofy;
delete[] sgfint;
}
//______________________________________________________________________________
void Gammagammaleptonpair::pairMomentum(double w,double y,double &E,double &px,double &py,double &pz)
{
//this function calculates px,py,pz,and E given w and y
double anglepp1=0.,anglepp2=0.,pp1=0.,pp2=0.,E1=0.,E2=0.,signpx=0.,pt=0.;
//E1 and E2 are for the 2 photons in the CM frame
E1 = w*exp(y)/2.;
E2 = w*exp(-y)/2.;
//calculate px and py
//to get x and y components-- phi is random between 0 and 2*pi
anglepp1 = randyInstance.Rndom();//random()/(RAND_MAX+1.0);
anglepp2 = randyInstance.Rndom();//random()/(RAND_MAX+1.0);
pp1 = pp_1(E1);
pp2 = pp_2(E2);
px = pp1*cos(2.*starlightConstants::pi*anglepp1)+pp2*cos(2.*starlightConstants::pi*anglepp2);
py = pp1*sin(2.*starlightConstants::pi*anglepp1)+pp2*sin(2.*starlightConstants::pi*anglepp2);
//Compute vector sum Pt=Pt1+Pt2 to find pt for the produced particle
pt = sqrt(px*px+py*py);
//W is the mass of the produced particle (not necessarily on-mass-shell).Now compute its energy and pz
E = sqrt(w*w+pt*pt)*cosh(y);
pz= sqrt(w*w+pt*pt)*sinh(y);
signpx = randyInstance.Rndom();//random()/(RAND_MAX+1.0);
//pick the z direction
//Don't do this anymore since y goes from -ymax to +ymax (JN 15-02-2013)
//if(signpx > 0.5) pz = -pz;
}
//______________________________________________________________________________
double Gammagammaleptonpair::pp_1(double E)
{
// This is for beam 1
// returns on random draw from pp(E) distribution
double ereds =0.,Cm=0.,Coef=0.,x=0.,pp=0.,test=0.,u=0.;
double singleformfactorCm=0.,singleformfactorpp1=0.,singleformfactorpp2=0.;
int satisfy =0;
ereds = (E/_GGlepInputGamma_em)*(E/_GGlepInputGamma_em);
//sqrt(3)*E/gamma_em is p_t where the distribution is a maximum
Cm = sqrt(3.)*E/_GGlepInputGamma_em;
//the amplitude of the p_t spectrum at the maximum
singleformfactorCm=_bbs.beam1().formFactor(Cm*Cm+ereds);
Coef = 3.0*(singleformfactorCm*singleformfactorCm*Cm*Cm*Cm)/((2.*(starlightConstants::pi)*(ereds+Cm*Cm))*(2.*(starlightConstants::pi)*(ereds+Cm*Cm)));
//pick a test value pp, and find the amplitude there
x = randyInstance.Rndom();
pp = x*5.*starlightConstants::hbarc/_bbs.beam1().nuclearRadius();
singleformfactorpp1=_bbs.beam1().formFactor(pp*pp+ereds);
test = (singleformfactorpp1*singleformfactorpp1)*pp*pp*pp/((2.*starlightConstants::pi*(ereds+pp*pp))*(2.*starlightConstants::pi*(ereds+pp*pp)));
while(satisfy==0){
u = randyInstance.Rndom();
if(u*Coef <= test)
{
satisfy =1;
}
else{
x =randyInstance.Rndom();
pp = 5*starlightConstants::hbarc/_bbs.beam1().nuclearRadius()*x;
singleformfactorpp2=_bbs.beam1().formFactor(pp*pp+ereds);
test = (singleformfactorpp2*singleformfactorpp2)*pp*pp*pp/(2.*starlightConstants::pi*(ereds+pp*pp)*2.*starlightConstants::pi*(ereds+pp*pp));
}
}
return pp;
}
//______________________________________________________________________________
double Gammagammaleptonpair::pp_2(double E)
{
// This is for beam 2
//returns on random draw from pp(E) distribution
double ereds =0.,Cm=0.,Coef=0.,x=0.,pp=0.,test=0.,u=0.;
double singleformfactorCm=0.,singleformfactorpp1=0.,singleformfactorpp2=0.;
int satisfy =0;
ereds = (E/_GGlepInputGamma_em)*(E/_GGlepInputGamma_em);
//sqrt(3)*E/gamma_em is p_t where the distribution is a maximum
Cm = sqrt(3.)*E/_GGlepInputGamma_em;
//the amplitude of the p_t spectrum at the maximum
singleformfactorCm=_bbs.beam2().formFactor(Cm*Cm+ereds);
Coef = 3.0*(singleformfactorCm*singleformfactorCm*Cm*Cm*Cm)/((2.*(starlightConstants::pi)*(ereds+Cm*Cm))*(2.*(starlightConstants::pi)*(ereds+Cm*Cm)));
//pick a test value pp, and find the amplitude there
x = randyInstance.Rndom();
pp = x*5.*starlightConstants::hbarc/_bbs.beam2().nuclearRadius(); //Will use nucleus #1
singleformfactorpp1=_bbs.beam2().formFactor(pp*pp+ereds);
test = (singleformfactorpp1*singleformfactorpp1)*pp*pp*pp/((2.*starlightConstants::pi*(ereds+pp*pp))*(2.*starlightConstants::pi*(ereds+pp*pp)));
while(satisfy==0){
u = randyInstance.Rndom();
if(u*Coef <= test)
{
satisfy =1;
}
else{
x =randyInstance.Rndom();
pp = 5*starlightConstants::hbarc/_bbs.beam2().nuclearRadius()*x;
singleformfactorpp2=_bbs.beam2().formFactor(pp*pp+ereds);
test = (singleformfactorpp2*singleformfactorpp2)*pp*pp*pp/(2.*starlightConstants::pi*(ereds+pp*pp)*2.*starlightConstants::pi*(ereds+pp*pp));
}
}
return pp;
}
//______________________________________________________________________________
void Gammagammaleptonpair::twoBodyDecay(starlightConstants::particleTypeEnum &ipid,
double , // E (unused)
double W,
double px0, double py0, double pz0,
double& px1, double& py1, double& pz1,
double& px2, double& py2, double& pz2,
int& iFbadevent)
{
// This routine decays a particle into two particles of mass mdec,
// taking spin into account
double mdec=0.,E1=0.,E2=0.;
double pmag, anglelep[20001];
// double ytest=0.,dndtheta;
double phi,theta,xtest,Ecm;
double betax,betay,betaz;
double hirestheta,hirestest,hiresw; //added from JN->needed precision
mdec = getMass();
if(W < 2*mdec)
{
cout<<" ERROR: W="<20000bins, use double precision for anglelep and thetalep. needed when W >6Gev.
hiresw = W;
anglelep[0] = 0.;
for(int i =1;i<=20000;i++)
{
hirestheta = starlightConstants::pi * double(i) /20000.;
// Added sin(theta) phase space factor (not in thetalep) and changed E to W in thetalep call
// 11/9/2000 SRK
// Note that thetalep is form invariant, so it could be called for E, theta_lab just
// as well as W,theta_cm. Since there is a boost from cm to lab below, the former is fine.
anglelep[i] = anglelep[i-1] + thetalep(hiresw,hirestheta)*sin(hirestheta);
}
hirestheta = 0.;
xtest = randyInstance.Rndom();//random()/(RAND_MAX+1.0);
hirestest = xtest;
for(int i =1;i<=20000;i++)
{
if(xtest > (anglelep[i]/anglelep[20000]))
hirestheta = starlightConstants::pi * double(i) / 20000.;
}
theta=hirestheta;
}
if(getSpin() != 0.5)
cout<<" This model cannot yet handle this spin value for lepton pairs: "< _ptCutMin && pt1chk < _ptCutMax && pt2chk > _ptCutMin && pt2chk < _ptCutMax){
accepted = true;
_nmbAccepted++;
}
}
else if(!_ptCutEnabled && _etaCutEnabled){
if(eta1 > _etaCutMin && eta1 < _etaCutMax && eta2 > _etaCutMin && eta2 < _etaCutMax){
accepted = true;
_nmbAccepted++;
}
}
else if(_ptCutEnabled && _etaCutEnabled){
if(pt1chk > _ptCutMin && pt1chk < _ptCutMax && pt2chk > _ptCutMin && pt2chk < _ptCutMax){
if(eta1 > _etaCutMin && eta1 < _etaCutMax && eta2 > _etaCutMin && eta2 < _etaCutMax){
accepted = true;
_nmbAccepted++;
}
}
}
else if(!_ptCutEnabled && !_etaCutEnabled)
_nmbAccepted++;
}while((_ptCutEnabled || _etaCutEnabled) && !accepted);
//twoBodyDecay(ipid,pairE,comenergy,pairmomx,pairmomy,pairmomz,px1,py1,pz1,px2,py2,pz2,iFbadevent);
if (iFbadevent==0){
int q1=0,q2=0;
double xtest = randyInstance.Rndom();//random()/(RAND_MAX+1.0);
if (xtest<0.5)
{
q1=1;
q2=-1;
}
else{
q1=-1;
q2=1;
}
// The new stuff
double mlepton = getMass();
E1 = sqrt( mlepton*mlepton + px1*px1 + py1*py1 + pz1*pz1 );
E2 = sqrt( mlepton*mlepton + px2*px2 + py2*py2 + pz2*pz2 );
starlightParticle particle1(px1, py1, pz1, E1, starlightConstants::UNKNOWN, -q1*ipid, q1);
event.addParticle(particle1);
starlightParticle particle2(px2, py2, pz2, E2, starlightConstants::UNKNOWN, -q2*ipid, q2);
event.addParticle(particle2);
}
return event;
}
//______________________________________________________________________________
void Gammagammaleptonpair::calculateTable()
{
// this subroutine calculates the tables that are used
// elsewhere in the montecarlo
// the tauon decay is taken from V-A theory, 1 - 1/3 cos(theta)
// the energy of each of the two leptons in tau decay
// is calculated using formula 10.35 given
// in introduction to elementary particles by D. griffiths
// which assmes that the mass of the electron is 0.
// the highest energy attainable by the electron in such a system is
// .5 * mass of the tau
// subroutine calculateTable
double E,theta;
_tautolangle[0] = 0.;
_dgammade[0] = 0.;
for(int i =1;i<=100;i++)
{
// calculate energy of tau decay
E = double(i)/100. * .5 * starlightConstants::tauMass;
_dgammade[i] = _dgammade[i-1] + E*E * (1. - 4.*E/(3.*starlightConstants::tauMass));
// calculate angles for tau
theta = starlightConstants::pi * double(i) / 100.;
_tautolangle[i] = _tautolangle[i-1] + (1 + 0.3333333 * cos(theta));
}
}
//______________________________________________________________________________
void Gammagammaleptonpair::tauDecay(double &px1,double &py1,double &pz1,double &E1,double &px2,double &py2,double &pz2,double &E2)
{
// this routine assumes that the tauons decay to electrons and
// calculates the directons of the decays
double Ee1,Ee2,theta1,theta2,phi1,phi2, ran1, ran2 ;
double pmag1,pex1,pey1,pez1,pex2,pey2,pez2,pmag2;
double betax,betay,betaz,dir;
int Tmp_Par=0; // temp variable for the transform function .. kind of starnge - being called with 7 parameter instead of 8
// the highest energy attainable by the electron in this system is
// .5 * mass of the tau
// get two random numbers to compare with
ran1 = randyInstance.Rndom()*_dgammade[100];//(random()/(RAND_MAX+1.0)) * _dgammade[100];
ran2 = randyInstance.Rndom()*_dgammade[100];//(random()/(RAND_MAX+1.0)) * _dgammade[100];
// compute the energies that correspond to those numbers
Ee1 = 0.;
Ee2 = 0.;
for( int i =1;i<=100;i++)
{
if (ran1 > _dgammade[i])
Ee1 = double(i) /100. * .5 * getMass();
if (ran2 > _dgammade[i])
Ee2 = double(i) /100. * .5 * getMass();
}
// to find the direction of emmission, first
// we determine if the tauons have spin of +1 or -1 along the
// direction of the beam line
dir = 1.;
if ( randyInstance.Rndom() < 0.5 )//(random()/(RAND_MAX+1.0)) < 0.5)
dir = -1.;
// get two random numbers to compare with
ran1 = randyInstance.Rndom()*_tautolangle[99];//(random()/(RAND_MAX+1.0)) * _tautolangle[100];
ran2 = randyInstance.Rndom()*_tautolangle[99];//(random()/(RAND_MAX+1.0)) * _tautolangle[100];
// find the angles corrsponding to those numbers
theta1 = 0.;
theta2 = 0.;
for( int i =1;i<=100;i++)
{
if (ran1 > _tautolangle[i]) theta1 = starlightConstants::pi * double(i) /100.;
if (ran2 > _tautolangle[i]) theta2 = starlightConstants::pi * double(i) /100.;
}
// grab another two random numbers to determine phi's
phi1 = randyInstance.Rndom()*2.*starlightConstants::pi;// (random()/(RAND_MAX+1.0))* 2. * starlightConstants::pi;
phi2 = randyInstance.Rndom()*2.*starlightConstants::pi;// (random()/(RAND_MAX+1.0))* 2. * starlightConstants::pi;
// figure out the momenta of the electron in the frames of the
// tauons from which they decayed, that is electron1 is in the
// rest frame of tauon1 and e2 is in the rest fram of tau2
// again the electrons are assumed to be massless
pmag1 = Ee1;
pex1 = cos(phi1)*sin(theta1)*pmag1;
pey1 = sin(phi1)*sin(theta1)*pmag1;
pez1 = cos(theta1)*pmag1*dir;
pmag2 = Ee2;
pex2 = cos(phi2)*sin(theta2)*pmag2;
pey2 = sin(phi2)*sin(theta2)*pmag2;
pez2 = cos(theta2)*pmag2*(-1.*dir);
// now Lorentz transform into the frame of each of the particles
// do particle one first
betax = -(px1/E1);
betay = -(py1/E1);
betaz = -(pz1/E1);
//cout<<"2decay betax,pex1= "<