/*
* Delphes: a framework for fast simulation of a generic collider experiment
* Copyright (C) 2012-2014 Universite catholique de Louvain (UCL), Belgium
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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 .
*/
/** \class PhotonConversions
*
*
* Converts photons into e+ e- pairs according to mass ditribution in the detector.
*
* \author M. Selvaggi - UCL, Louvain-la-Neuve
*
*/
#include "modules/PhotonConversions.h"
#include "classes/DelphesClasses.h"
#include "classes/DelphesCylindricalFormula.h"
#include "classes/DelphesFactory.h"
#include "ExRootAnalysis/ExRootClassifier.h"
#include "ExRootAnalysis/ExRootFilter.h"
#include "ExRootAnalysis/ExRootResult.h"
#include "TDatabasePDG.h"
#include "TF1.h"
#include "TFormula.h"
#include "TLorentzVector.h"
#include "TMath.h"
#include "TObjArray.h"
#include "TRandom3.h"
#include "TString.h"
#include "TVector3.h"
#include
#include
#include
#include
using namespace std;
//------------------------------------------------------------------------------
PhotonConversions::PhotonConversions() :
fItInputArray(0), fConversionMap(0), fDecayXsec(0)
{
fDecayXsec = new TF1("decayXsec", "1.0 - 4.0/3.0 * x * (1.0 - x)", 0.0, 1.0);
fConversionMap = new DelphesCylindricalFormula;
}
//------------------------------------------------------------------------------
PhotonConversions::~PhotonConversions()
{
}
//------------------------------------------------------------------------------
void PhotonConversions::Init()
{
fRadius = GetDouble("Radius", 1.0);
fRadius2 = fRadius * fRadius;
fHalfLength = GetDouble("HalfLength", 3.0);
fEtaMax = GetDouble("EtaMax", 5.0);
fEtaMin = GetDouble("EtaMin", 2.0);
fStep = GetDouble("Step", 0.1); // in meters
fConversionMap->Compile(GetString("ConversionMap", "0.0"));
// import array with output from filter/classifier module
fInputArray = ImportArray(GetString("InputArray", "Delphes/stableParticles"));
fItInputArray = fInputArray->MakeIterator();
// create output arrays
fOutputArray = ExportArray(GetString("OutputArray", "stableParticles"));
}
//------------------------------------------------------------------------------
void PhotonConversions::Finish()
{
if(fItInputArray) delete fItInputArray;
if(fDecayXsec) delete fDecayXsec;
if(fConversionMap) delete fConversionMap;
}
//------------------------------------------------------------------------------
void PhotonConversions::Process()
{
Candidate *candidate, *ep, *em;
TLorentzVector candidatePosition, candidateMomentum;
TVector3 pos_i;
Double_t px, py, pz, pt, pt2, e, eta, phi;
Double_t x, y, z, t;
Double_t x_t, y_t, z_t, r_t;
Double_t x_i, y_i, z_i, r_i, phi_i;
Double_t dt, t1, t2, t3, t4;
Double_t tmp, discr, discr2;
Int_t nsteps, i;
Double_t rate, p_conv, x1, x2;
Bool_t converted;
fItInputArray->Reset();
while((candidate = static_cast(fItInputArray->Next())))
{
if(candidate->PID != 22)
{
fOutputArray->Add(candidate);
}
else
{
candidatePosition = candidate->Position;
candidateMomentum = candidate->Momentum;
x = candidatePosition.X() * 1.0E-3;
y = candidatePosition.Y() * 1.0E-3;
z = candidatePosition.Z() * 1.0E-3;
// check that particle position is inside the cylinder
if(TMath::Hypot(x, y) > fRadius || TMath::Abs(z) > fHalfLength) continue;
px = candidateMomentum.Px();
py = candidateMomentum.Py();
pz = candidateMomentum.Pz();
pt = candidateMomentum.Pt();
pt2 = candidateMomentum.Perp2();
eta = candidateMomentum.Eta();
phi = candidateMomentum.Phi();
e = candidateMomentum.E();
if(eta < fEtaMin || eta > fEtaMax) continue;
// solve pt2*t^2 + 2*(px*x + py*y)*t - (fRadius2 - x*x - y*y) = 0
tmp = px * y - py * x;
discr2 = pt2 * fRadius2 - tmp * tmp;
if(discr2 < 0.0)
{
// no solutions
continue;
}
tmp = px * x + py * y;
discr = TMath::Sqrt(discr2);
t1 = (-tmp + discr) / pt2;
t2 = (-tmp - discr) / pt2;
t = (t1 < 0.0) ? t2 : t1;
z_t = z + pz * t;
if(TMath::Abs(z_t) > fHalfLength)
{
t3 = (+fHalfLength - z) / pz;
t4 = (-fHalfLength - z) / pz;
t = (t3 < 0.0) ? t4 : t3;
}
// final position
x_t = x + px * t;
y_t = y + py * t;
z_t = z + pz * t;
r_t = TMath::Sqrt(x_t * x_t + y_t * y_t + z_t * z_t);
// here starts conversion code
nsteps = Int_t(r_t / fStep);
x_i = x;
y_i = y;
z_i = z;
dt = t / nsteps;
converted = false;
for(i = 0; i < nsteps; ++i)
{
x_i += px * dt;
y_i += py * dt;
z_i += pz * dt;
pos_i.SetXYZ(x_i, y_i, z_i);
// convert photon position into cylindrical coordinates, cylindrical r,phi,z !!
r_i = TMath::Sqrt(x_i * x_i + y_i * y_i);
phi_i = pos_i.Phi();
// read conversion rate/meter from card
rate = fConversionMap->Eval(r_i, phi_i, z_i);
// convert into conversion probability
p_conv = 1 - TMath::Exp(-7.0 / 9.0 * fStep * rate);
// case conversion occurs
if(gRandom->Uniform() < p_conv)
{
converted = true;
// generate x1 and x2, the fraction of the photon energy taken resp. by e+ and e-
x1 = fDecayXsec->GetRandom();
x2 = 1 - x1;
ep = static_cast(candidate->Clone());
em = static_cast(candidate->Clone());
ep->Position.SetXYZT(x_i * 1.0E3, y_i * 1.0E3, z_i * 1.0E3, candidatePosition.T() + nsteps * dt * e * 1.0E3);
em->Position.SetXYZT(x_i * 1.0E3, y_i * 1.0E3, z_i * 1.0E3, candidatePosition.T() + nsteps * dt * e * 1.0E3);
ep->Momentum.SetPtEtaPhiE(x1 * pt, eta, phi, x1 * e);
em->Momentum.SetPtEtaPhiE(x2 * pt, eta, phi, x2 * e);
ep->PID = -11;
em->PID = 11;
ep->Charge = 1.0;
em->Charge = -1.0;
ep->IsFromConversion = 1;
em->IsFromConversion = 1;
fOutputArray->Add(em);
fOutputArray->Add(ep);
break;
}
}
if(!converted) fOutputArray->Add(candidate);
}
}
}
//------------------------------------------------------------------------------