// ----------------------------------------------------------------------------
// $Id: LCDFMCCalRecon.cxx,v 1.1 2001/05/10 17:55:55 toshi Exp $
// ----------------------------------------------------------------------------
//
// $Log: LCDFMCCalRecon.cxx,v $
// Revision 1.1 2001/05/10 17:55:55 toshi
// Changes C++ name convention from *.C to *.cxx to allow Windows usage.
//
//
#include <iostream.h>
#include "LCDFMCCalRecon.h"
#include "TVector3.h"
#include "LCDEDeposit.h"
#define ELEC_TYPE 11
#define GAMMA_TYPE 22
#define PIPLUS_TYPE 211
#define K0SHORT_TYPE 310
#define K0LONG_TYPE 130
#define KPLUS_TYPE 321
#define PROTON_TYPE 2212
#define NEUTRON_TYPE 2112
#define LAMBDA_TYPE 3122
#define NSMEARABLE 9
#define SMEARABLE_NOT 0
#define SMEARABLE_EM 1
#define SMEARABLE_HAD 2
#define VERY_SMALL 0.0000001
#define MCSTAT_FINALSTATE 1
//______________________________________________________________________
//
// LCDFMCCalRecon
//
// LCDFMCCalRecon is the over-all manager for Fast MC calorimetry. It must
// be instantiated for each detector (or change to smearing parameters)
// but need only be cleared between events belonging to the same
// detector
ClassImp(LCDFMCCalRecon)
//------------------------------------------------------------------------
LCDFMCCalRecon::LCDFMCCalRecon() {
// Constructor. Primary job is to assemble various parameters
// describing detector geometry and resolution.
Init();
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
LCDFMCCalRecon::LCDFMCCalRecon(Int_t iseed) {
// Constructor. Primary job is to assemble various parameters
// describing detector geometry and resolution.
Init();
m_rand.SetSeed(iseed);
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
LCDFMCCalRecon::LCDFMCCalRecon(LCDGetParameters* getparam) {
// Constructor. Primary job is to assemble various parameters
// describing detector geometry and resolution.
Init();
SetDetectorParameters(getparam);
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
LCDFMCCalRecon::LCDFMCCalRecon(LCDGetParameters* getparam, Int_t iseed) {
// Constructor. Primary job is to assemble various parameters
// describing detector geometry and resolution.
Init();
m_rand.SetSeed(iseed);
SetDetectorParameters(getparam);
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void LCDFMCCalRecon::Init() {
ClsList= 0;
// Merge sizes (default)
merge_siz_EM =0.8;
merge_siz_HAD =1.3;
merge_angle_EM =0.0200;
merge_angle_HAD=0.0600;
Int_t iseed=(Int_t)&m_rand;
m_rand.SetSeed(iseed);
m_cluster_merge = kTRUE; // Default.. do cluster merging
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void LCDFMCCalRecon::SetDetectorParameters(LCDGetParameters* Getparam) {
gp = Getparam;
nVolumes = gp->GetNVolumes();
if (nVolumes == 0) {
Int_t ok = gp->SetDetectorVolumes();
if (ok) {
nVolumes = gp->GetNVolumes();
pInnerVolume = gp->GetInnerVolume();
pVolumes = gp->GetDetectorVolumes();
} else { // make it clear we have no detector
nVolumes = 0;
pInnerVolume = 0;
pVolumes = 0;
printf(" Error in CalRecon :: Cannot define detector volumes");
}
}else{
pInnerVolume = gp->GetInnerVolume();
pVolumes = gp->GetDetectorVolumes();
}
// Set cluster merging sizes
merge_siz_EM = gp->GetEMMergeSize();
merge_siz_HAD = gp->GetHADMergeSize();
merge_angle_EM = gp->GetEMMergeAngle();
merge_angle_HAD= gp->GetHADMergeAngle();
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void
LCDFMCCalRecon::Cleanup(LCDEvent* event) {
if (event) {
event->ClusterLst()->Delete();
}
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void
LCDFMCCalRecon::Doit(LCDEvent* event) {
// Process an event. For each MC particle, check to see whether it's
// "smearable". If so, propagate, then smear energy and transverse
// position.
LCDSwimTraj traj;
if (!nVolumes) return; // no detector
ClsList = event->ClusterLst();
ClsList = event->ClusterLst();
ClsList->Delete();
//----------> create clusters
Int_t nParts = event->MCparticles()->GetEntries();
Int_t nkal =0;
LCDMcPart* pPart;
Int_t canSmear;
Bool_t hadron;
TVector3 pos0;
TVector3 mom0;
Int_t ifSwim;
LCDCluster* cluster;
TLorentzVector p4mc;
TVector3 pPos;
Double_t energy;
Double_t theta;
Double_t r;
Double_t r_cal;
Double_t z_cal;
for (Int_t i = 0 ; i< nParts ; i++) {
pPart = (LCDMcPart*)event->MCparticles()->At(i);
canSmear = Smearable(pPart);
if( canSmear ) {
hadron = (canSmear == SMEARABLE_HAD);
pos0=*(pPart->GetPositionPtr());
mom0=pPart->Get4MomentumPtr()->Vect();
Int_t charge = (Int_t)pPart->GetCharge();
traj.SetParticleParams(pos0, mom0, charge);
ifSwim = Swim(&traj, hadron);
if ( ifSwim == 1 ) {
cluster = new((*event->ClusterLst())[nkal++]) LCDCluster();
p4mc=*(pPart->Get4MomentumPtr());
Smear(p4mc.E(),&traj,hadron,cluster);
pPos=*(traj.GetNewPosPtr());
energy = p4mc.E();
theta = pPos.Theta();
r = pPos.Mag();
r_cal = r*TMath::Sin(theta);
z_cal = TMath::Abs(r_cal*TMath::Cos(theta)/TMath::Sin(theta));
if( r_cal> gp->GetEMBarrelInnerR() &&
r_cal< gp->GetHADBarrelInnerR()&&
z_cal< gp->GetEMBarrelOuterZ() ) { //EM Barrel
cluster->SetBarEnd(0); cluster->SetSystem(0);
} else if(r_cal> gp->GetHADBarrelInnerR()){ //HAD Barrel
cluster->SetBarEnd(0); cluster->SetSystem(1);
} else if(r_cal< gp->GetEMBarrelInnerR() &&
z_cal< gp->GetEMBarrelOuterZ() ){ //EM endcap
cluster->SetBarEnd(1); cluster->SetSystem(0);
} else if(r_cal< gp->GetHADBarrelInnerR()&&
z_cal> gp->GetEMBarrelOuterZ() ){ //HAD endcap
cluster->SetBarEnd(1); cluster->SetSystem(1);
}
cluster->AddParticle(i,energy);
}
}
}
// Ultimately may have another stage where distances between first-pass
// smears are examined to see if any are close enough (w.r.t. supplied
// parameters) to be combined into a single smear
if (m_cluster_merge) {
DoMerge();
}
}
Int_t LCDFMCCalRecon::Smearable(LCDMcPart* pPart) {
// Check a) that we have a final-state particle b) particle type.
// Must be electron/positron, photon, or an acceptable hadron.
// c) energy. Must be non-negligible.
static Int_t willSmear[NSMEARABLE] = {
ELEC_TYPE,
GAMMA_TYPE,
PIPLUS_TYPE,
K0SHORT_TYPE,
K0LONG_TYPE,
KPLUS_TYPE,
PROTON_TYPE,
NEUTRON_TYPE,
LAMBDA_TYPE};
Bool_t ok = kFALSE;
// Check status
Int_t mcStat = pPart->GetStatus();
if (mcStat != MCSTAT_FINALSTATE) return SMEARABLE_NOT;
Int_t partType = TMath::Abs(pPart->GetParticleID());
for (int ix = 0; ix < NSMEARABLE; ix++) {
if (partType == willSmear[ix]) {
ok = kTRUE;
break;
}
}
if (!ok) return SMEARABLE_NOT;
// Energy is very small -- forGet it
if (pPart->Get4MomentumPtr()->E() < VERY_SMALL) return SMEARABLE_NOT;
return ((partType == ELEC_TYPE) || (partType == GAMMA_TYPE)) ?
SMEARABLE_EM : SMEARABLE_HAD;
}
Int_t LCDFMCCalRecon::Swim(LCDSwimTraj* pTraj, Bool_t hadron) {
// Swim particle with initial conditions described in pTraj through
// the detector. Return true if particle showers in the detector
// (where the coil counts as part of the detector)
LCDSwimTraj::PropagateRet status;
Int_t charge = pTraj->GetCharge();
LCDDetectorVolume* pCur = (LCDDetectorVolume *) pInnerVolume;
Double_t decrS; // measured in cm
Double_t decrPath;
TVector3 pPos(0.,0.,0.);
TVector3 pMom(pTraj->GetIniMom());
LCDDetectorVolume* pNextVolume;
Int_t nVolume = 0; // debug info
// traj has been initialized with position, momentum, charge
// First swim through empty central volume
if ((pCur->field != 0.0) && (charge != 0)) { // helix
status = pTraj->HelixToCyl(pCur, &decrS);
} else { // straight line
status = pTraj->LineToCyl(pCur, &decrS);
}
if ((status == LCDSwimTraj::INTERSECT_NONE) ||
(status == LCDSwimTraj::INTERSECT_ERROR) ) return 0;
// Check that we didn't exit to the air volume next to the beampipe.
pPos = pTraj->GetNewPos();
if ((status == LCDSwimTraj::INTERSECT_ZPLUS) ||
(status == LCDSwimTraj::INTERSECT_ZMINUS)) {
if (pCur->pNextZ == 0) return 0;
pNextVolume = (LCDDetectorVolume *) pCur->pNextZ;
if (pPos.Perp() < pNextVolume->outerR) return 0;
}
pTraj->Update();
// Throw an interaction length or rad. length depending on particle type
// measured in interaction/rad len
Double_t remPath = RanExpDecay();
Double_t newR=0;
Double_t newZ=0;
Bool_t helix;
while (kTRUE) {
nVolume++;
switch(status) { // find new volume
case LCDSwimTraj::INTERSECT_ZMINUS:
case LCDSwimTraj::INTERSECT_ZPLUS:
pCur = (LCDDetectorVolume *) pCur->pNextZ;
if (!pCur) return 0;
// In the special case in which we're coming from an endcap air
// volume headed in a z-direction, there will typically be more
// than one adjacent volume. pNextZ pointer gives us innermost.
// Check this against our current radius. If necessary, follow
// pNextR pointers until we find an acceptable volume
newR=pTraj->GetNewPos().Perp();
while (newR > pCur->outerR) {
pCur = (LCDDetectorVolume *) pCur->pNextR;
if (!pCur) return 0;
}
break;
case LCDSwimTraj::INTERSECT_CYLIN:
// One extra thing to check here as well. In case we go inwards,
// there may be more than one component next to the original.
// pPrevR points
// to the one with smallest z. If this isn't right (based on
// new position), follow its pNextZ pointer.
newZ = TMath::Abs(pTraj->GetNewPos().Z());
pCur = (LCDDetectorVolume *) pCur->pPrevR;
if (!pCur) return 0;
while (newZ > pCur->outerZ) {
pCur = (LCDDetectorVolume *) pCur->pNextZ;
if (!pCur) return 0;
}
break;
case LCDSwimTraj::INTERSECT_CYLOUT:
pCur = (LCDDetectorVolume *) pCur->pNextR;
break;
default:
return 0;
}
if (!pCur) return 0; // Went outside detector
// Propagate to boundary of volume
helix = (pCur->field != 0.0) && (charge != 0);
if (helix) {
status = pTraj->HelixToCyl(pCur, &decrS);
} else { // straight line
status = pTraj->LineToCyl(pCur, &decrS);
}
if ((status == LCDSwimTraj::INTERSECT_NONE) ||
(status == LCDSwimTraj::INTERSECT_ERROR) ) return 0;
decrPath = hadron ? pCur->iLenPerCm : pCur->radLenPerCm;
decrPath *= decrS;
if (decrPath < remPath) { // keep going
remPath -= decrPath;
pTraj->Update();
} else { // We'll finish in this volume
decrS = remPath / (hadron ? pCur->iLenPerCm : pCur->radLenPerCm);
if (helix) {
status = pTraj->HelixPath(pCur->field, decrS);
} else {
status = pTraj->LinePath(decrS);
}
nVolume++;
pTraj->Update();
return 1;
}
}
}
//------------------------------------------------------------------------
void LCDFMCCalRecon::DoMerge() {
// do Cluster merge taking into account detector granuarity...
if (ClsList == 0) return;
Int_t nCluster = ClsList->GetEntries();
if (nCluster < 1) return;
//----------> Sort order of energy...
ClsList->Sort();
//----------> Cluster Mearge
Int_t ikal;
LCDCluster* pcali;
TVector3 xcali;
Int_t emhad_i;
Int_t barend_i;
Int_t jkal;
LCDCluster* pcalj;
Int_t barend_j;
Int_t emhad_j;
TVector3 xcalj;
Double_t merge_siz;
Double_t merge_angle;
Double_t diff_c;
Double_t diff_l;
for (ikal=0 ; ikal < nCluster-1 ; ikal++) {
pcali=(LCDCluster*)(ClsList->At(ikal));
emhad_i = pcali->GetSystem();
barend_i = pcali->GetBarEnd();
xcali.SetTheta(pcali->GetEnergyTheta());
xcali.SetPhi(pcali->GetEnergyTheta());
xcali.SetXYZ(pcali->GetEnergyR()*TMath::Sin(pcali->GetEnergyTheta())
*TMath::Cos(pcali->GetEnergyPhi()),
pcali->GetEnergyR()*TMath::Sin(pcali->GetEnergyTheta())
*TMath::Sin(pcali->GetEnergyPhi()),
pcali->GetEnergyR()*TMath::Cos(pcali->GetEnergyTheta()));
for (jkal=ikal+1 ; jkal < nCluster ; jkal++) {
pcalj=(LCDCluster*)ClsList->At(jkal);
barend_j = pcalj->GetBarEnd();
emhad_j = pcalj->GetSystem();
if (barend_i != barend_j || emhad_i != emhad_j) continue;
xcalj.SetXYZ(pcalj->GetEnergyR()*TMath::Sin(pcalj->GetEnergyTheta())
*TMath::Cos(pcalj->GetEnergyPhi()),
pcalj->GetEnergyR()*TMath::Sin(pcalj->GetEnergyTheta())
*TMath::Sin(pcalj->GetEnergyPhi()),
pcalj->GetEnergyR()*TMath::Cos(pcalj->GetEnergyTheta()));
merge_siz = merge_siz_EM; //EM
merge_angle = merge_angle_EM; //EM
if (emhad_i != 0) { // HAD
merge_siz = merge_siz_HAD;
merge_angle = merge_angle_HAD;
}
diff_c=xcalj.Angle(xcali);
diff_l=xcalj.Mag()*diff_c;
if ( diff_l < merge_siz || diff_c < merge_angle ){//Marge cluster
AddCluster(pcali,pcalj);
ClsList->Remove(pcalj);
//delete pcalj;
}
}
ClsList->Compress();
nCluster=ClsList->GetEntries();
}
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void LCDFMCCalRecon::AddCluster(LCDCluster* kal1, LCDCluster* kal2) {
//Energy, Theta, Phi, R
Double_t energy = kal1->GetEnergy();
Double_t eTheta = kal1->GetEnergyTheta();
Double_t ePhi = kal1->GetEnergyPhi();
Double_t eR = kal1->GetEnergyR();
Double_t ekal = kal2->GetEnergy();
Double_t tkal = kal2->GetEnergyTheta();
Double_t fkal = kal2->GetEnergyPhi();
Double_t rkal = kal2->GetEnergyR();
Double_t esum =0;
Double_t ephisum =0;
Double_t ethetasum=0;
Double_t ersum =0;
esum = energy + ekal;
Double_t phiDiff= fkal - ePhi;
if (phiDiff > TMath::Pi()) { phiDiff -= 2.*TMath::Pi();}
else if (phiDiff < -TMath::Pi()) { phiDiff += 2.*TMath::Pi();}
ephisum = ekal*phiDiff;
Double_t theDiff= tkal - eTheta;
if (theDiff > TMath::Pi()) { theDiff -= 2.*TMath::Pi();}
else if (theDiff < -TMath::Pi()) { theDiff += 2.*TMath::Pi();}
ethetasum = ekal*theDiff;
ersum = energy*eR + ekal*rkal;
energy = esum;
ePhi += ephisum/esum;
eTheta += ethetasum/esum;
eR = ersum/esum;
Double_t phiRMS = kal1->GetEnergyPhiRMS();
Double_t thetaRMS = kal1->GetEnergyThetaRMS();
Double_t rRMS = kal1->GetEnergyRRMS();;
//Temporary...T.Abe 4/20/2001
kal1->SetUpCluster(energy,
ePhi, phiRMS,
eTheta, thetaRMS,
eR, rRMS,
kal1->GetBarEnd(),kal1->GetSystem());
//McList
Int_t nMC2=kal2->GetMcListEntries();
Int_t* mcList2=kal2->GetMcList();
Float_t* emcList2=kal2->GetMcListE();
for (Int_t imc=0 ; imc < nMC2 ; imc++) {
kal1->AddParticle(mcList2[imc],emcList2[imc]);
}
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void LCDFMCCalRecon::Smear(Double_t epart, LCDSwimTraj* ptraj,
Bool_t hadron, LCDCluster* kal) {
// Inputs are
// -- "perfect" particle position, after propagation
// -- hadron/lepton boolean
// -- smearing parameters
// -- random number generator instance
Double_t a, b;
if (hadron) {
a = gp->GetCalEnergyHADA(); b = gp->GetCalEnergyHADB();
} else {
a = gp->GetCalEnergyEMA() ; b = gp->GetCalEnergyEMB() ;
}
Double_t energySigma = (TMath::Sqrt((a*a)/epart + b*b))*epart;
Double_t energy = m_rand.Gaus(epart, energySigma);
if (energy < 0.0) energy = 0.0;
// Now for position
// First step should be to calculate shower max position from what
// I've got (shower start position). This will add something in
// the direction of the momentum vector (or do I need to propagate
// along a helix for charged particles in a field??) but I don't
// know how to do this yet.
// Then smear position in plane perp. to momentum vector.
if (hadron) {
a = gp->GetCalTransHADA(); b = gp->GetCalTransHADB();
} else {
a = gp->GetCalTransEMA(); b = gp->GetCalTransEMB();
}
// Find sigma. Use MC truth -- not smeared -- energy
// sigma = sqrt((a*a)/E + (b*b))
// and use it to throw a distance in transverse plane.
// Also get random phi (in same plane). Since distance can be
// negative, just let phi range from 0 to pi.
Double_t transSigma = TMath::Sqrt((a*a)/epart + b*b);
Double_t transDist = m_rand.Gaus(0.0, transSigma);
Double_t phi = TMath::Pi()*m_rand.Rndm(0);
TVector3 xop(transDist*TMath::Cos(phi),transDist*TMath::Sin(phi),0);
TVector3 nx(1,0,0),ny(0,1,0),nz(0,0,1);
TVector3 nzp(*(ptraj->GetNewMomPtr())); nzp.SetMag(1.0);
//TVector3 nzp(*(ptraj->GetNewPosPtr())); nzp.SetMag(1.0);
TVector3 nxp(nz.Cross(nzp)) ; nxp.SetMag(1.0);
TVector3 nyp(nzp.Cross(nxp)) ; nyp.SetMag(1.0);
TVector3 xpos ((nx*nxp)*xop.X(),(ny*nxp)*xop.X(),(nz*nxp)*xop.X());
xpos += TVector3((nx*nyp)*xop.Y(),(ny*nyp)*xop.Y(),(nz*nyp)*xop.Y());
xpos += TVector3((nx*nzp)*xop.Z(),(ny*nzp)*xop.Z(),(nz*nzp)*xop.Z());
xpos += *(ptraj->GetNewPosPtr());
//
Double_t eTheta = xpos.Theta();
Double_t ePhi = xpos.Phi();
Double_t eR = xpos.Mag();
//Double_t eR = ptraj->GetNewPosPtr()->Mag();
// errors in phi and theta added in quad. should give total trans. err
Double_t eThetaRMS = transSigma/TMath::Sqrt(2.0);
Double_t ePhiRMS = eThetaRMS;
Double_t eRRMS = 0.0;
//
kal->SetUpCluster(energy,
ePhi, ePhiRMS,
eTheta, eThetaRMS,
eR, eRRMS,
0, 0);
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.