Index: trunk/src/Kinematics.cpp
===================================================================
--- trunk/src/Kinematics.cpp (revision 439)
+++ trunk/src/Kinematics.cpp (revision 440)
@@ -1,454 +1,455 @@
//==============================================================================
// Kinematics.cpp
//
// Copyright (C) 2010-2019 Tobias Toll and Thomas Ullrich
//
// This file is part of Sartre.
//
// This program 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.
// This program 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 this program. If not, see .
//
// Author: Thomas Ullrich
// Last update:
// $Date$
// $Author$
//------------------------------------------------------------------------------
//
// Note that Kinematics is only meant for ep and eA scattering.
// It is not applicable for UPC kinematics. Use UpcKinematics instead.
//
//==============================================================================
#include "Kinematics.h"
#include
#include
#include "Math/RootFinder.h"
#include "Math/BrentRootFinder.h"
#include "Math/GSLRootFinder.h"
#include "Math/RootFinderAlgorithms.h"
#include "Math/IFunction.h"
#include "Math/BrentMinimizer1D.h"
// TMP
#include "TH1D.h"
#include "TFile.h"
#define PR(x) cout << #x << " = " << (x) << endl;
using namespace std;
bool Kinematics::mError = false;
bool Kinematics::error() {return mError;}
//UPC:
double Kinematics::mXpomMin=0;
double Kinematics::mTold=0;
bool Kinematics::mXpomMinIsEvaluated=false;
//
double Kinematics::xprobe(double Q2, double W2, double vmMass)
{
mError = false;
double val = ( Q2 + vmMass*vmMass ) / (W2 - protonMass2 + Q2);
if (val > 1 || val < 0) mError = true;
return val;
}
TLorentzVector Kinematics::electronBeam(double eE, bool upc)
{
mError = false;
if (upc)
return TLorentzVector(0, 0, -sqrt(eE*eE-protonMass2), eE);
else
return TLorentzVector(0, 0, -sqrt(eE*eE-electronMass2), eE);
}
TLorentzVector Kinematics::hadronBeam(double hE)
{
mError = false;
return TLorentzVector(0, 0, sqrt(hE*hE-protonMass2), hE);
}
double Kinematics::s(const TLorentzVector& e, const TLorentzVector& p)
{
mError = false;
return (e+p)*(e+p);
}
double Kinematics::s(double eE, double hE, bool upc)
{
mError = false;
TLorentzVector e = electronBeam(eE, upc);
TLorentzVector p = hadronBeam(hE);
return (e+p)*(e+p);
}
double Kinematics::x(double Q2, double W2)
{
mError = false;
double val = Q2/(W2-protonMass2+Q2);
if (val > 1 || val < 0) mError = true;
return val;
}
double Kinematics::y(double Q2, double x, double s)
{
mError = false;
double val = Q2/(x*(s-electronMass2-protonMass2));
if (val > 1 || val < 0) mError = true;
return val;
}
double Kinematics::ymin(double s, double vmMass)
{
mError = false;
double W2min = Kinematics::W2min(vmMass);
double val = (s + W2min - sqrt((s-W2min)*(s-W2min)-4*electronMass2*W2min))/2/(s+electronMass2);
if (val > 1 || val < 0) mError = true;
return val;
}
double Kinematics::ymax(double s, double vmMass)
{
mError = false;
double W2min = Kinematics::W2min(vmMass);
double val = (s + W2min + sqrt((s-W2min)*(s-W2min)-4*electronMass2*W2min))/2/(s+electronMass2);
if (val > 1 || val < 0) mError = true;
return val;
}
double Kinematics::W2(double Q2, double x)
{
//
// Returns W2 at a given Q2 and Bjorken x
//
mError = false;
return protonMass2 + Q2*(1-x)/x;
}
double Kinematics::W2(double Q2, double xprobe, double vmMass)
{
//
// Returns W2 at a given Q2 and xprobe
// where xprobe is
// xprobe = xBJ * (1 + MV^2/Q2)
//
mError = false;
return protonMass2 + vmMass*vmMass/xprobe + Q2*(1-xprobe)/xprobe;
}
double Kinematics::W2min(double vmMass)
{
mError = false;
- return vmMass*vmMass + protonMass2;
-}
+ // return vmMass*vmMass + protonMass2;
+ return (vmMass + protonMass)*(vmMass + protonMass);
+}
double Kinematics::W2max(double s)
{
mError = false;
return s; // check !?
}
double Kinematics::Q2min(double y)
{
mError = false;
return electronMass2*y*y/(1-y);
}
double Kinematics::Q2max(double s)
{
mError = false;
return s-electronMass2-protonMass2;
}
double Kinematics::xpomeron(double t, double Q2, double W2, double vmM)
{
mError = false;
double val = (vmM*vmM + Q2 - t)/(W2 + Q2 - protonMass2); // full expression
if (val > 1 || val < 0) mError = true;
return val;
}
double Kinematics::tmax(double xpom)
{
mError = false;
return (- xpom*xpom * protonMass2 / (1-xpom)); // only if m_p (in) = m_p' (out) - to be fixed
}
double Kinematics::tmax(double t, double Q2, double W2, double vmM)
{
return tmax(xpomeron(t, Q2, W2, vmM));
}
double Kinematics::tmin(double eE)
{
mError = false;
return -2*(eE*protonMass-protonMass2); // check ?!
}
//
// UPC only
//
double Kinematics::xpomMin(double massVM, double t, TLorentzVector hBeam, TLorentzVector eBeam, double MY2minusM2){
if (mXpomMinIsEvaluated && mTold == t) return mXpomMin;
LowerXpomeronFormula formula;
mTold = t;
formula.mT = t;
formula.mVmMass2=massVM*massVM;
formula.mElectronBeam = eBeam;
formula.mHadronBeam = hBeam;
formula.mMY2minusM2 = MY2minusM2;
//
//Find starting brackets
//
double lower=1e-12;
double upper=1e-1;
//
// Find minimum and use as lower
// bracket to avoid two roots
//
ROOT::Math::BrentMinimizer1D bm;
bm.SetFunction(formula, log(lower), log(upper));
bm.Minimize(100000, 1e-8, 1e-10);
double theMin = bm.XMinimum();
//
// Run root finder
//
ROOT::Math::RootFinder rootfinder(ROOT::Math::RootFinder::kBRENT);
rootfinder.SetFunction(formula, theMin, log(upper));
rootfinder.Solve(100000000, 1e-14, 0);
//
// Now some fine adjustements
//
double bestGuess = rootfinder.Root();
int ntimes = 0;
while (formula.DoEval(bestGuess) < 0) {
bestGuess += 1e-14;
ntimes++;
if (ntimes> 10000) break;
}
double result = exp(bestGuess);
double s = (hBeam+eBeam).M2();
mXpomMin = max(result, xpomMin(s, massVM, t));
mXpomMinIsEvaluated = true;
return mXpomMin;
}
double Kinematics::xpomMin(double s, double vmM, double t) {
//
// This is the threshold value.
// In some cases a more restrictive value may be needed
//
return (electronMass2 + protonMass2 + vmM*vmM - t)/s;
}
double Kinematics::Egamma(double xpom, double t, double vmM, double hBeamEnergy, double eBeamEnergy, double MY2minusM2)
{
//
// We use that the vector meson = photon + pomeron to calculate Egamma
// (keeping the pomeron variables from above)
// We solve a quadratic equation to get the photon energy such that
// the vector meson has the correct mass.
//
double Ep=hBeamEnergy;
double Pp=-sqrt(Ep*Ep-protonMass2);
double Ee=eBeamEnergy;
double Pe=sqrt(Ee*Ee-protonMass2);
double sqrtarg= 1 - ( (2*xpom - xpom*xpom)*Pp*Pp + t - MY2minusM2) / (Ep*Ep);
double Epom=Ep*(1-sqrt(sqrtarg)); //this is close to xpom*Ep
double Ppom=xpom*Pp;
double AA = vmM*vmM - Epom*Epom - t + Ppom*Ppom + 2*Pe*(Pe+Ppom); //GeV^2
double aa = 4*(Pe+Ppom)*(Pe+Ppom) - 4*(Ee+Epom)*(Ee+Epom); //GeV^2
double bb = 4*AA*(Ee+Epom) - 8*(Pe+Ppom)*(Pe+Ppom)*Ee; //GeV^3
double cc = 4*(Pe+Ppom)*(Pe+Ppom)*Pe*Pe - AA*AA;
sqrtarg = bb*bb-4*aa*cc;
if (sqrtarg < 0) {
//This is used by validUPC as a sign of failure, needs to return something negative
return -1.;
}
return ( -bb + sqrt(sqrtarg) )/(2*aa); //GeV
}
//
// UPC only
//
bool Kinematics::validUPC(double hBeamEnergy, double eBeamEnergy, double t, double xpom, double vmMass, bool verbose)
{
//
// Here we perform all complete test of all kinematic variables
//
//
// xpom
//
double s = Kinematics::s(eBeamEnergy, hBeamEnergy, true);
double Egam = Egamma(xpom, t, vmMass, hBeamEnergy, eBeamEnergy);
double minxpom = xpomMin(s, vmMass, t);
if (xpom < minxpom) {
if (verbose) cout << "Kinematics::validUPC(): reject t=" << t << " and xpom=" << xpom
<< " because xpom < xpomMin (" << minxpom << ")" << endl;
return false;
}
if (Egam < 0) {
if (verbose) cout << "Kinematics::validUPC(): reject t=" << t << " and xpom=" << xpom
<< " because Egamma < 0 (" << Egam << ")" << endl;
return false;
}
if (xpom > 1) {
if (verbose) cout << "Kinematics::validUPC(): reject xpom="< 1" << endl;
return false;
}
//
// t
//
double t_max=tmax(xpom);
if (t > t_max) {
if (verbose) cout << "Kinematics::validUPC(): reject t=" << t << " because t > tmax (" << t_max << ")" << endl;
return false;
}
return true; //survived all tests
}
bool Kinematics::valid(double s, double t, double Q2, double W2, double vmMass,
bool useTrueXp, bool verbose)
{
//
// Here we perform all complete test of all kinematic variables
//
double x = Kinematics::x(Q2, W2);
double y = Kinematics::y(Q2, x, s);
//
// W
//
if (W2 < Kinematics::W2min(vmMass)) {
if (verbose) cout << "Kinematics::valid(): reject W=" << sqrt(W2) << " because W < Wmin" << endl;
return false;
}
if (W2 > Kinematics::W2max(s)) {
if (verbose) cout << "Kinematics::valid(): reject W=" << sqrt(W2) << " because W > Wmax" << endl;
return false;
}
//
// y range
//
double ymin = Kinematics::ymin(s, vmMass);
double ymax = Kinematics::ymax(s, vmMass);
if (y < ymin || y > ymax) {
if (verbose) cout << "Kinematics::valid(): reject y=" << y << " because y < ymin (" << ymin
<< ") || y > ymax (" << ymax << ")" << endl;
return false;
}
//
// x and y
//
if (x < 0 || x > 1) {
if (verbose) cout << "Kinematics::valid(): reject x=" << x << " because x < 0 || x > 1" << endl;
return false;
}
//
// Q2
//
if (Q2 > Kinematics::Q2max(s)) {
if (verbose) cout << "Kinematics::valid(): reject Q2=" << Q2 << " because Q2 > Q2max" << endl;
return false;
}
if (Q2 < Kinematics::Q2min(y)) {
if (verbose) cout << "Kinematics::valid(): reject Q2=" << Q2 << " because Q2 < Q2min" << endl;
return false;
}
//
// t
//
// On calculating xpomeron. xpomeron() provides the correct value
// (not neglecting t or nucleon mass). However, during initialization
// to avoid recursion we set t=0. Calling valid() with t != 0 would
// reject these values. In this case useTrueXp is set to false.
// For final checks if an event has the correct kinematics we have
// to set useTrueXp = true.
//
double xpom;
if (useTrueXp)
xpom = Kinematics::xpomeron(t, Q2, W2, vmMass);
else
xpom = Kinematics::xpomeron(0, Q2, W2, vmMass);
double tmax = Kinematics::tmax(xpom);
if (t > tmax) {
if (verbose) cout << "Kinematics::valid(): reject t=" << t << " because t > tmax (" << tmax << ")" << endl;
return false;
}
//
// xpom
//
if (xpom < 0 || xpom > 1) {
if (verbose) cout << "Kinematics::valid(): reject xpom=" << xpom << " because xpom < 0 || xpom > 1" << endl;
return false;
}
if (x > xpom) {
if (verbose) cout << "Kinematics::valid(): reject since x=" << x << " > xpom = " << xpom << endl;
return false;
}
return true; // survived all tests
}
ROOT::Math::IBaseFunctionOneDim* LowerXpomeronFormula::Clone() const
{
return new LowerXpomeronFormula();
}
double LowerXpomeronFormula::DoEval(double logxpom) const
{
double xpom = exp(logxpom);
//Start by setting up the knowns: Incoming beams, xpom, and t:
double Ee=mElectronBeam.E();
double Pe=mElectronBeam.Pz();
double Pp=mHadronBeam.Pz();
double Ep=mHadronBeam.E();
double E, pz;
//
// Use scattered proton to set up four momentum of pomeron (so far assuming no break-up):
//
double sqrtarg= 1 - ( (2*xpom - xpom*xpom)*Pp*Pp + mT - mMY2minusM2) / (Ep*Ep);
E=Ep*(1-sqrt(sqrtarg)); //this is close to xpom*Ep
pz=xpom*Pp;
//
// Next we use that the vector meson = photon + pomeron to calculate Egamma
// (keeping the pomeron variables from above)
// We solve a quadratic equation to get the photon energy such that
// the vector meson has the correct mass.
//
double AA = mVmMass2 - E*E - mT + pz*pz + 2*Pe*(Pe+pz); //GeV^2
double aa = 4*(Pe+pz)*(Pe+pz) - 4*(Ee+E)*(Ee+E); //GeV^2
double bb = 4*AA*(Ee+E) - 8*(Pe+pz)*(Pe+pz)*Ee; //GeV^3
double cc = 4*(Pe+pz)*(Pe+pz)*Pe*Pe - AA*AA;
sqrtarg = bb*bb-4*aa*cc;
return sqrtarg;
}