// $Header: CalRecon.cxx $

#include "CalRecon.h"
#include "CalSmeared.h"

#define  false  0
#define  true   1

#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 PIZERO_TYPE 111     // not included among the smearables

#define SMEARABLE_NOT  0
#define SMEARABLE_EM   1
#define SMEARABLE_HAD  2

//______________________________________________________________________
//                                                                       
// CalRecon
//                                                                
// CalRecon 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(CalRecon)   

 CalRecon::CalRecon(const TString& name)  { 
  // Constructor.   Primary job is to assemble various parameters
  // describing detector geometry and resolution.

  Int_t ok;
  ok = GetDetector(name);
  if (ok) {
    //  InitSmearPar();
    smears = new TObjArray(10);
  }
  else { // make it clear we have no detector
    nVolumes = 0;
    pInnerVolume = 0;
    pVolumes = 0;
  }
}
      
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 void CalRecon::cleanup() {
  // Get rid of allocated memory, obsolete pointers.

  // Get rid of reference to old MCparticles
  MCparticles = 0;

  // Get rid of old smears if any
  smears->Delete(0);
  
};

 void CalRecon::doit(Event* event) {
  // Process an event.  For each MC particle, check to see whether it's
  // "smearable".  If so, propagate, then smear energy and transverse
  // position.  

  SmearTraj  traj;
  Bool_t     ok;

  MCparticles = event->MCparticles();
  nPart = MCparticles->GetLast() + 1;

  if (!nVolumes) return;  // no detector
  
  for (Int_t ix = 0; ix < nPart; ix++) { // Process particle with index ix.
    
    McPart*       pPart = (McPart*) (*MCparticles)[ix];
    CalSmeared*   pSmeared;
    Int_t         canSmear;

    if (canSmear = Smearable(pPart)) {
      Bool_t hadron = (canSmear == SMEARABLE_HAD);
      SmearVolume *pCur;
      traj.SetParticle(pPart, ix);
      if (pCur = Swim(&traj, hadron)) {
	pSmeared = new CalSmeared(traj, hadron, pCur->pFuzz, pRand); 
    
        smears->Add(pSmeared);
      }
    }

    // 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
  }
};


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 void CalRecon::spew(FILE* ofile) const
{
  // Output standard cluster quantities to ascii file.

  if (!nVolumes) return;  // no detector

  Int_t  nSmear = smears->GetLast() + 1; 
  fprintf(ofile, "Clusters n %i n", nSmear);
  //  fprintf(ofile, "%d MC particles produced %d smeared clustersn", 
  //	  nPart, nSmear);
  for (Int_t iSmear = 0; iSmear < nSmear; iSmear++) {
    CalSmeared* pSmear = (CalSmeared *) (*smears)[iSmear];
    pSmear->spew(ofile);
  }
  fprintf(ofile, "endn");
}

#define VERY_SMALL 0.0000001
#define MCSTAT_FINALSTATE  1
 Int_t CalRecon::Smearable(McPart* 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,
    //    PIZERO_TYPE,
    K0SHORT_TYPE,
    K0LONG_TYPE,
    KPLUS_TYPE,
    PROTON_TYPE,
    NEUTRON_TYPE,
    LAMBDA_TYPE};

  Bool_t ok = false;

  // Check status
  Int_t mcStat = pPart->GetStatus();
  if (mcStat != MCSTAT_FINALSTATE) return SMEARABLE_NOT;

  Int_t partType = pPart->GetType();
  if (partType < 0) {
    partType = - partType;
  }

  for (int ix = 0; ix < NSMEARABLE; ix++) {
    if (partType == willSmear[ix]) {
      ok = true;
      break;
    }
  }
  if (!ok) return SMEARABLE_NOT;

  // Energy is very small -- forget it
  Float_t* iniMom = pPart->GetMomentum();
  if (*(iniMom + 3)  < VERY_SMALL) return SMEARABLE_NOT;

  return  ((partType == ELEC_TYPE) || (partType == GAMMA_TYPE)) ?
    SMEARABLE_EM  : SMEARABLE_HAD;
}

 Int_t CalRecon::GetDetector(const TString& name) {
  // Somehow get access to needed detector parameters.  For now, use the
  // name to identify a set of parameters.  Could also use it to identify
  // a file, or to just ask (from some parameter server class) for information
  // about the "ambient" detector, if any.
  //
  // Result of this call is to initialize the following fields in CalRecon:
  //       nBarrel   pBarrels
  //       nEndcap   pEndcaps
  // so that at the end have a list of pointers to barrels, arranged in
  // order of increasing R, and a list of endcap in order of increasing z
  
  pRand = new TRandom();

  if (name.CompareTo("Small") == 0)   GetSmall();
  else if (name.CompareTo("Large") == 0) GetLarge();
  else {
    printf("Unsupported detectorn");
    return 0;
  }

  return 1;
}

 SmearVolume*  CalRecon::Swim(SmearTraj* 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)

  SmearTraj::PropagateRet status;
  Int_t                   charge = pTraj->GetCharge();
  SmearVolume*            pCur = (SmearVolume *) pInnerVolume;
  Double_t                decrS;              // measured in cm
  Double_t      totalPath, remPath; // measured in interaction/rad len
  Double_t      decrPath;
  Double_t*     pPos;
  Double_t*     pMom;
  SmearVolume*  pNextVolume;

  int           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 == SmearTraj::INTERSECT_NONE) ||
      (status == SmearTraj::INTERSECT_ERROR)   ) return 0;

  // Check that we didn't exit to the air volume next to the beampipe.
  pPos = pTraj->GetNewPos();
  if ((status == SmearTraj::INTERSECT_ZPLUS) || 
      (status == SmearTraj::INTERSECT_ZMINUS)) {
    Double_t x = *pPos;
    Double_t y = *(pPos + 1);

    if (pCur->pNextZ == 0) return 0;
    pNextVolume = (SmearVolume *) pCur->pNextZ;
    if (TMath::Sqrt(x*x + y*y) < pNextVolume->outerR) return 0;
  }

  pTraj->Update();

  // We can update mcPart, but first we have to change doubles to floats
  pMom = pTraj->GetNewMom();
  {
    Float_t pos[3];
    Float_t mom[3];

    for (int i = 0; i < 3; i++) {
      pos[i] = *(pPos + i);
      mom[i] = *(pMom + i);
    }
    pTraj->GetMc()->SetParticleAtCal(&mom[0], &pos[0]);
  }

  // Throw an interaction length or rad. length depending on particle type
  totalPath = remPath = RanExpDecay(pRand);

  while (true) {
    Bool_t helix;
    nVolume++;
    switch(status) {   // find new volume
    case SmearTraj::INTERSECT_ZMINUS:
    case SmearTraj::INTERSECT_ZPLUS:
      pCur = (SmearVolume *) 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
      {
	Double_t *newPos = pTraj->GetNewPos();
	Double_t x = *newPos;
	Double_t y = *(newPos + 1);
	Double_t newR = TMath::Sqrt(x*x + y*y);

	while (newR > pCur->outerR) {
	  pCur = (SmearVolume *) pCur->pNextR;
	  if (!pCur) return 0;
	}
      }
      break;
    case SmearTraj::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.
      
      {
	Double_t *newPos = pTraj->GetNewPos();
	Double_t newZ = TMath::Abs(*(newPos + 2));
	pCur = (SmearVolume *) pCur->pPrevR;
	if (!pCur) return 0;

	while (newZ > pCur->outerZ) {
	  pCur = (SmearVolume *) pCur->pNextZ;
	  if (!pCur) return 0;
	}
      }
      break;
    case SmearTraj::INTERSECT_CYLOUT:
      pCur = (SmearVolume *) 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 == SmearTraj::INTERSECT_NONE) ||
	(status == SmearTraj::INTERSECT_ERROR)  ) return 0;

    decrPath = decrS * (hadron ? pCur->iLenPerCm : pCur->radLenPerCm);

    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 pCur;
    }
  }
}



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.