// $Header: CalSmeared.cxx $

#include "CalSmeared.h"
#include "IntObj.h"

ClassImp(CalSmeared)

//______________________________________________________________________
//                                                                       
// CalSmeared
//                                                                
// CalSmeared is the Fast MC version of a cluster (really should be
// inheriting from Event Cluster class).  In addition to minimal cluster
// attributes it also keeps some information on the "perfect" cluster
// from which it is derived.

 CalSmeared::CalSmeared(SmearTraj& traj, Bool_t hadron, SmearFuzz* pFuzz,
		       TRandom *pRand)
{
  // Usual constructor.  Inputs are
  //    -- "perfect" particle position, after propagation
  //    -- hadron/lepton boolean
  //    -- smearing parameters
  //    -- random number generator instance

  McPart*    pPart = traj.GetMc();
  Int_t      partIx = traj.GetMcIx();
  Double_t*  pPos = traj.GetNewPos();
  Double_t*  pMom = traj.GetNewMom();

  Double_t a, b;
  Double_t sigma;
  Float_t examineEnergy;
  Int_t   absPid;

  sPerfect = traj.GetS();
  mcContribs = new TObjArray(1);
  mcContribs->Add(new IntObj(partIx));
  ePerfect = pPart->GetMomentum()[3];
  pid1 = pPart->GetType();
  nPart = 1;

  if (hadron) {
    a = pFuzz->energyHadA;
    b = pFuzz->energyHadB;
  }
  else {
    a = pFuzz->energyEmA;
    b = pFuzz->energyEmB;
  }

  // Save "perfect" position vector
  // Don't yet know how to get from cluster start to cluster max
  // realistically.  For now just set them equal.
  posClusterStart[0] = posPerfect[0] = *pPos;
  posClusterStart[1] = posPerfect[1] = *(pPos + 1);
  posClusterStart[2] = posPerfect[2] = *(pPos + 2);

  energySigma = sigma = 
    (TMath::Sqrt((a * a) / ePerfect + b * b)) * ePerfect;
  energy = pRand->Gaus(ePerfect, sigma);
  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 = pFuzz->transHadA;
    b = pFuzz->transHadB;
  }
  else {
    a = pFuzz->transEmA;
    b = pFuzz->transEmB;
  }
  // 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)/ePerfect + b*b);
    Double_t transDist = pRand->Gaus(0.0, transSigma);
    Double_t phi =  TMath::Pi() * pRand->Rndm(0);
    Double_t positionOffset[3]; 
    Double_t primeVec[3]; // offsets in rotated coord.
    static Double_t sqrtHalf = TMath::Sqrt(0.5);

    // errors in phi and theta added in quad. should give total trans. err
    eThetaRms = ePhiRms = transSigma * sqrtHalf; 

    // Given offset vector in rotated system with 
    // momentum vector ==> (0, 0, mag) have offset find its coordinates
    // in original frame. 
    primeVec[0] = transDist * TMath::Cos(phi);
    primeVec[1] = transDist * TMath::Sin(phi);
    primeVec[2] = 0.0;
    Rotate(primeVec, pMom, &positionOffset[0]);

    // Add on to original position vector
    for (int ix = 0; ix < 3; ix++) {
      pos[ix] = posPerfect[ix] + positionOffset[ix];
    }
  }

  // Save polar coord. version of energy position
  Double_t polar[3];
  ToPolar(&pos[0], &polar[0]);
  eTheta = polar[0];
  ePhi = polar[1];
  eR = polar[2];
}

 void CalSmeared::spewDiag(FILE* ofile) {
  // More extensive spew for debugging

  Float_t *pOrig = ((McPart *) (mcContribs->First()))->GetMomentum();
  unsigned int mcAddr = (unsigned int) mcContribs->First();
  fprintf(ofile, 
"MC addr: %i PID: %d Orig egy: %f Orig mom: ( %f, %f, %f) Smeared egy %fn",          mcAddr, pid1, ePerfect, pOrig[0], pOrig[1], pOrig[2], energy);
  fprintf(ofile, "(%f, %f, %f) => (%f, %f, %f)n", posPerfect[0],
	  posPerfect[1], posPerfect[2], pos[0], pos[1], pos[2]);
  fprintf(ofile, "Geometric path length: %f n", sPerfect);
  fprintf(ofile,"%f %f %f %f %f %f %fn", GetEnergy(), 
	  GetEnergyPhi(), GetEnergyTheta(), GetEnergyR(),
	  GetEnergyPhiRms(), GetEnergyThetaRms(), GetEnergyRRms());
}

 void CalSmeared::spew(FILE* ofile) {
  // Typical cluster output for a fastMC cluster looks like
  //        energy energyPhi energyTheta energyR phiRms thetaRms rRms
  //        0 hits
  //        1 particle(s)
  //        xxxxxxxx
  //
  // where the quantities in the first line are floating point and
  // xxxxxxxx is index (in array of all MC particles) associated with 
  // generating MC particle.
  //
  // The set of all clusters are bracketed by the lines
  //    yyy Clusters                          [before]   and
  //    end                                   [after]
  //
  //     yyy is the number of clusters to follow.

  static Int_t zero = 0;

  //  fprintf(ofile,"Clustern");
  fprintf(ofile,"%f %f %f %f %f %f %fn", GetEnergy(), 
	  GetEnergyPhi(), GetEnergyTheta(), GetEnergyR(),
	  GetEnergyPhiRms(), GetEnergyThetaRms(), GetEnergyRRms());
  fprintf(ofile,"%i hit(s)n", zero);
  fprintf(ofile,"%i particle(s)n", nPart);
  
  {
    Int_t ix;
    for (ix = 0; ix < nPart; ix++) {
      fprintf(ofile, "%i n", 
	      (unsigned int) ((IntObj *)(mcContribs->At(ix)))->Getnum());
    }
  }
}

 void CalSmeared::ToPolar(const Double_t *pRect, Double_t *pPolar) {
  // Given rectangular coords, compute polar and store in provided 3-vector.
  // (theta, phi, r).  The following conventions are used:
  // 0 <= phi < 2 pi
  // 0 < phi < pi/2 for x, y > 0.  pi/2 < phi < pi for x < 0, y > 0, etc.
  // 0 <= theta < pi; theta < pi/2 for z > 0

  Double_t r;
  Double_t theta;
  Double_t phi;
  Double_t toBeamline;

  Double_t x = *pRect;
  Double_t y = *(pRect + 1);
  Double_t z = *(pRect + 2);

  toBeamline = x*x + y*y;
  r = TMath::Sqrt(toBeamline + z*z);
  toBeamline = TMath::Sqrt(toBeamline);

  pPolar[2] = r;

  if (r <= 0.0) {
    pPolar[0] = 0.0;
    pPolar[1] = 0.0;

    return;
  }
  theta = TMath::ATan2(toBeamline, z);
  if (theta < 0) theta += TMath::Pi();

  phi = TMath::ATan2(y, x);
  if (phi < 0.0)  phi += 2 * TMath::Pi();

  pPolar[0] = theta;
  pPolar[1] = phi;

  return;
}

 void CalSmeared::Rotate(Double_t* inVec, Double_t* angleVec, 
			Double_t* result)
// Rotate something  so that z axis is "returned"
// to normalVec.  That is, if angleVec has polar coords (theta, phi, r),
//  rotate about y-axis by theta, then about z-axis by phi.

{
  // We need to rotate by theta, phi coordinates of momentum
  Double_t polar[3];
  
  ToPolar(angleVec, polar);  // Gives us theta, phi, r for normal

  Double_t temp[3];

  RotateTheta(polar[0], inVec, &temp[0]);
  RotatePhi(polar[1], &temp[0], result);
 
  return;
}

 void CalSmeared::RotateTheta(const Double_t theta, 
			     Double_t *iVec, Double_t *rVec)
// Rotate about y-axis with angle theta

{
  Double_t sinTheta = TMath::Sin(theta);
  Double_t cosTheta = TMath::Cos(theta);

  *rVec = (*iVec) * cosTheta + *(iVec + 2) * sinTheta;
  *(rVec + 1) = *(iVec + 1);
  *(rVec + 2) = *iVec * (-sinTheta) + *(iVec + 2) * cosTheta;

  return;
}

 void CalSmeared::RotatePhi(const Double_t phi, 
			   Double_t *iVec, Double_t *rVec)
// Rotate about z-axis with angle phi

{
  Double_t sinPhi = TMath::Sin(phi);
  Double_t cosPhi = TMath::Cos(phi);

  *rVec = (*iVec) * cosPhi - *(iVec + 1) * sinPhi;
  *(rVec + 1) = *iVec * (sinPhi) + *(iVec + 1) * cosPhi;
  *(rVec + 2) = *(iVec + 2);

  return;
}


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.