Fork me on GitHub

Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • modules/DualReadoutCalorimeter.cc

    r9a7ea36 ra1b19ea  
    2424  // This implementation of dual calorimetry relies on several approximations:
    2525  // - If hadronic energy is found in the tower the energy resolution then the full tower enrgy is smeared according to hadronic resolution (pessimistic for (e,n) or (pi+,gamma))
    26   // - While e+ vs pi+ (or gamma vs n) separation is in principle possible for single particles (using C/S, PMT timing, lateral shower profile) it is not obvious it can be done overlapping particles.
     26  // - While e+ vs pi+ (or gamma vs n) separation is in principle possible for single particles (using C/S, PMT timing, lateral shower profile) it is not obvious it can be done overlapping particles. 
    2727  //   Now we assume that regarless of the number of particle hits per tower we can always distinguish e+ vs pi+, which is probably not true in the case (e+,n) vs (pi+,gamma) without longitudinal segmentation.
    2828
     
    6363  fItParticleInputArray(0), fItTrackInputArray(0)
    6464{
    65 
     65 
    6666  fECalResolutionFormula = new DelphesFormula;
    6767  fHCalResolutionFormula = new DelphesFormula;
     
    7575  fTowerTrackArray = new TObjArray;
    7676  fItTowerTrackArray = fTowerTrackArray->MakeIterator();
    77 
     77 
    7878}
    7979
     
    8282DualReadoutCalorimeter::~DualReadoutCalorimeter()
    8383{
    84 
     84 
    8585  if(fECalResolutionFormula) delete fECalResolutionFormula;
    8686  if(fHCalResolutionFormula) delete fHCalResolutionFormula;
     
    9494  if(fTowerTrackArray) delete fTowerTrackArray;
    9595  if(fItTowerTrackArray) delete fItTowerTrackArray;
    96 
     96 
    9797}
    9898
     
    172172  fECalEnergyMin = GetDouble("ECalEnergyMin", 0.0);
    173173  fHCalEnergyMin = GetDouble("HCalEnergyMin", 0.0);
    174   fEnergyMin = GetDouble("EnergyMin", 0.0);
    175174
    176175  fECalEnergySignificanceMin = GetDouble("ECalEnergySignificanceMin", 0.0);
    177176  fHCalEnergySignificanceMin = GetDouble("HCalEnergySignificanceMin", 0.0);
    178   fEnergySignificanceMin = GetDouble("EnergySignificanceMin", 0.0);
    179177
    180178  // switch on or off the dithering of the center of DualReadoutCalorimeter towers
     
    247245  fItParticleInputArray->Reset();
    248246  number = -1;
    249   fTowerRmax=0.;
    250 
    251   //cout<<"--------- new event ---------- "<<endl;
    252 
    253247  while((particle = static_cast<Candidate*>(fItParticleInputArray->Next())))
    254248  {
    255249    const TLorentzVector &particlePosition = particle->Position;
    256250    ++number;
    257 
    258     // compute maximum radius (needed in FinalizeTower to assess whether barrel or endcap tower)
    259     if (particlePosition.Perp() > fTowerRmax)
    260       fTowerRmax=particlePosition.Perp();
    261251
    262252    pdgCode = TMath::Abs(particle->PID);
     
    387377      fHCalTrackEnergy = 0.0;
    388378      fTrackEnergy = 0.0;
    389 
     379     
    390380      fECalTrackSigma = 0.0;
    391381      fHCalTrackSigma = 0.0;
    392382      fTrackSigma = 0.0;
    393 
     383     
    394384      fTowerTrackHits = 0;
    395385      fTowerPhotonHits = 0;
    396 
    397       fTowerTime = 0.0;
    398       fTowerTimeWeight = 0.0;
    399386
    400387      fECalTowerTrackArray->Clear();
    401388      fHCalTowerTrackArray->Clear();
    402389      fTowerTrackArray->Clear();
    403 
     390   
    404391    }
    405392
     
    425412      }
    426413
     414     
     415      /*
     416      if(fECalTrackFractions[number] > 1.0E-9 && fHCalTrackFractions[number] < 1.0E-9)
     417      {
     418        fECalTrackEnergy += ecalEnergy;
     419        ecalSigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, momentum.E());       
     420        if(ecalSigma/momentum.E() < track->TrackResolution) energyGuess = ecalEnergy;       
     421        else energyGuess = momentum.E();
     422
     423        fECalTrackSigma += (track->TrackResolution)*energyGuess*(track->TrackResolution)*energyGuess;
     424        fECalTowerTrackArray->Add(track);
     425      }
     426     
     427      else if(fECalTrackFractions[number] < 1.0E-9 && fHCalTrackFractions[number] > 1.0E-9)
     428      {
     429        fHCalTrackEnergy += hcalEnergy;
     430        hcalSigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, momentum.E());
     431        if(hcalSigma/momentum.E() < track->TrackResolution) energyGuess = hcalEnergy;
     432        else energyGuess = momentum.E();
     433
     434        fHCalTrackSigma += (track->TrackResolution)*energyGuess*(track->TrackResolution)*energyGuess;
     435        fHCalTowerTrackArray->Add(track);
     436      }
     437     
     438      // muons
     439      else if(fECalTrackFractions[number] < 1.0E-9 && fHCalTrackFractions[number] < 1.0E-9)
     440      {
     441        fEFlowTrackOutputArray->Add(track);
     442      }
     443      */
     444     
    427445      // in Dual Readout we do not care if tracks are ECAL of HCAL
    428446      if(fECalTrackFractions[number] > 1.0E-9 || fHCalTrackFractions[number] > 1.0E-9)
    429       {
     447      { 
    430448        fTrackEnergy += energy;
    431         // this sigma will be used to determine whether neutral excess is significant. We choose the resolution according to bthe higest deposited fraction (in practice had for charged hadrons and em for electrons)
     449        // this sigma will be used to determine whether neutral excess is significant. We choose the resolution according to bthe higest deposited fraction (in practice had for charged hadrons and em for electrons)     
    432450        sigma = 0.0;
    433451        if(fHCalTrackFractions[number] > 0)
     
    435453        else
    436454          sigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, momentum.E());
    437 
    438         if(sigma/momentum.E() < track->TrackResolution)
    439           energyGuess = ecalEnergy + hcalEnergy;
     455         
     456        if(sigma/momentum.E() < track->TrackResolution) 
     457          energyGuess = ecalEnergy + hcalEnergy;     
    440458        else
    441459          energyGuess = momentum.E();
    442 
     460             
    443461        fTrackSigma += (track->TrackResolution)*energyGuess*(track->TrackResolution)*energyGuess;
    444462        fTowerTrackArray->Add(track);
     463     
    445464      }
    446465      else
     
    459478    position = particle->Position;
    460479
    461 
    462480    // fill current tower
    463481    ecalEnergy = momentum.E() * fECalTowerFractions[number];
     
    467485    fHCalTowerEnergy += hcalEnergy;
    468486
    469     // assume combined timing measurements in ECAL/HCAL sections
    470     fTowerTime += (ecalEnergy + hcalEnergy) * position.T(); //sigma_t ~ 1/sqrt(E)
    471     fTowerTimeWeight += ecalEnergy + hcalEnergy;
     487    if(ecalEnergy > fTimingEnergyMin && fTower)
     488    {
     489      if (abs(particle->PID) != 11 || !fElectronsFromTrack)
     490      {
     491        fTower->ECalEnergyTimePairs.push_back(make_pair<Float_t, Float_t>(ecalEnergy, particle->Position.T()));
     492      }
     493    }
    472494
    473495    fTower->AddCandidate(particle);
    474     fTower->Position = position;
    475496  }
    476497
     
    485506
    486507  Candidate *track, *tower, *mother;
    487   Double_t energy, pt, eta, phi, r, time;
     508  Double_t energy, pt, eta, phi;
    488509  Double_t ecalEnergy, hcalEnergy;
    489510  Double_t ecalNeutralEnergy, hcalNeutralEnergy, neutralEnergy;
    490 
     511 
    491512  Double_t ecalSigma, hcalSigma, sigma;
    492513  Double_t ecalNeutralSigma, hcalNeutralSigma, neutralSigma;
    493514
    494515  Double_t weightTrack, weightCalo, bestEnergyEstimate, rescaleFactor;
    495 
     516 
    496517  TLorentzVector momentum;
    497518  TFractionMap::iterator itFractionMap;
     
    501522  if(!fTower) return;
    502523
    503   // if no hadronic energy, use ECAL resolution
     524
     525  //if (fHCalTowerEnergy < 30 && fECalTowerEnergy < 30) return;
     526  //cout<<"----------- New tower ---------"<<endl;
     527
     528
     529  // here we change behaviour w.r.t to standard calorimeter. Start with worse case scenario. If fHCalTowerEnergy > 0, assume total energy smeared by HCAL resolution.
     530  // For example, if overlapping charged pions and photons take hadronic resolution as combined measurement
     531
     532  // if no hadronic fraction at all, then use ECAL resolution
     533
     534  //cout<<"fECalTowerEnergy: "<<fECalTowerEnergy<<", fHCalTowerEnergy: "<<fHCalTowerEnergy<<", Eta: "<<fTowerEta<<endl;
     535
     536  // if no hadronic energy, use ECAL resolution
    504537  if (fHCalTowerEnergy <= fHCalEnergyMin)
    505538  {
    506539    energy = fECalTowerEnergy;
    507540    sigma  = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy);
    508   }
    509 
    510   // if hadronic fraction > 0, use HCAL resolution
     541    //cout<<"em energy"<<energy<<", sigma: "<<sigma<<endl;
     542  }
     543
     544  // if hadronic fraction > 0, use HCAL resolution
    511545  else
    512546  {
    513547    energy = fECalTowerEnergy + fHCalTowerEnergy;
    514548    sigma  = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy);
     549    //cout<<"had energy: "<<energy<<", sigma: "<<sigma<<endl;
    515550  }
    516551
    517552  energy = LogNormal(energy, sigma);
    518 
     553  //cout<<energy<<","<<ecalEnergy<<","<<hcalEnergy<<endl;
     554 
    519555  if(energy < fEnergyMin || energy < fEnergySignificanceMin*sigma) energy = 0.0;
    520556
     
    526562  hcalEnergy = LogNormal(fHCalTowerEnergy, hcalSigma);
    527563
    528   time = (fTowerTimeWeight < 1.0E-09) ? 0.0 : fTowerTime / fTowerTimeWeight;
    529 
    530564  ecalSigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, ecalEnergy);
    531565  hcalSigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, hcalEnergy);
     
    534568  if(hcalEnergy < fHCalEnergyMin || hcalEnergy < fHCalEnergySignificanceMin*hcalSigma) hcalEnergy = 0.0;
    535569
     570  //cout<<"Measured energy: "<<energy<<endl;
     571
    536572  if(fSmearTowerCenter)
    537573  {
     
    547583  pt = energy / TMath::CosH(eta);
    548584
    549   // check whether barrel or endcap tower
    550 
    551   // endcap
    552   if (TMath::Abs(fTower->Position.Pt() - fTowerRmax) > 1.e-06 && TMath::Abs(eta) > 0.){
    553     r = fTower->Position.Z()/TMath::SinH(eta);
    554   }
    555   // barrel
    556   else {
    557     r = fTower->Position.Pt();
    558   }
    559 
    560   fTower->Position.SetPtEtaPhiE(r, eta, phi, time);
    561   fTower->Momentum.SetPtEtaPhiE(pt, eta, phi, energy);
    562   fTower->L = fTower->Position.Vect().Mag();
     585  // Time calculation for tower
     586  fTower->NTimeHits = 0;
     587  sumWeightedTime = 0.0;
     588  sumWeight = 0.0;
     589
     590  for(size_t i = 0; i < fTower->ECalEnergyTimePairs.size(); ++i)
     591  {
     592    weight = TMath::Sqrt(fTower->ECalEnergyTimePairs[i].first);
     593    sumWeightedTime += weight * fTower->ECalEnergyTimePairs[i].second;
     594    sumWeight += weight;
     595    fTower->NTimeHits++;
     596  }
     597
     598  if(sumWeight > 0.0)
     599  {
     600    fTower->Position.SetPtEtaPhiE(1.0, eta, phi, sumWeightedTime/sumWeight);
     601  }
     602  else
     603  {
     604    fTower->Position.SetPtEtaPhiE(1.0, eta, phi, 999999.9);
     605  }
    563606
    564607  fTower->Momentum.SetPtEtaPhiE(pt, eta, phi, energy);
    565608  fTower->Eem = ecalEnergy;
    566609  fTower->Ehad = hcalEnergy;
    567   fTower->Etrk = fTrackEnergy;
     610
    568611  fTower->Edges[0] = fTowerEdges[0];
    569612  fTower->Edges[1] = fTowerEdges[1];
     
    581624
    582625  // fill energy flow candidates
    583 
     626 
    584627  fTrackSigma = TMath::Sqrt(fTrackSigma);
    585628  neutralEnergy = max( (energy - fTrackEnergy) , 0.0);
    586629  neutralSigma = neutralEnergy / TMath::Sqrt(fTrackSigma*fTrackSigma + sigma*sigma);
    587630
     631  //cout<<"trackEnergy: "<<fTrackEnergy<<", trackSigma: "<<fTrackSigma<<", Ntracks: "<<fTowerTrackArray->GetEntries()<<endl;
     632
     633  //cout<<"neutralEnergy: "<<neutralEnergy<<", neutralSigma: "<<neutralSigma<<endl;
     634
     635   // For now, if neutral excess is significant, simply create neutral EflowPhoton tower and clone each track into eflowtrack !!! -> Creating only photons !! EFlowNeutralHadron collection will be empy!!! TO BE FIXED
    588636  if(neutralEnergy > fEnergyMin && neutralSigma > fEnergySignificanceMin)
    589637  {
     638   
     639    //cout<<"significant neutral excess found:"<<endl;
    590640    // create new photon tower
    591641    tower = static_cast<Candidate*>(fTower->Clone());
    592     pt = neutralEnergy / TMath::CosH(eta);
     642    pt =  neutralEnergy / TMath::CosH(eta);
     643    //cout<<"Creating tower with Pt, Eta, Phi, Energy: "<<pt<<","<<eta<<","<<phi<<","<<neutralEnergy<<endl;
    593644    tower->Momentum.SetPtEtaPhiE(pt, eta, phi, neutralEnergy);
    594 
    595     // if no hadronic energy, use ECAL resolution
    596     if (fHCalTowerEnergy <= fHCalEnergyMin)
    597     {
    598       tower->Eem = neutralEnergy;
    599       tower->Ehad = 0.0;
    600       tower->PID = 22;
    601       fEFlowPhotonOutputArray->Add(tower);
    602     }
    603     // if hadronic fraction > 0, use HCAL resolution
    604     else
    605     {
    606       tower->Eem = 0;
    607       tower->Ehad = neutralEnergy;
    608       tower->PID = 130;
    609       fEFlowNeutralHadronOutputArray->Add(tower);
    610     }
     645    tower->Eem = neutralEnergy;
     646    tower->Ehad = 0.0;
     647    tower->PID = 22;
     648
     649    fEFlowPhotonOutputArray->Add(tower);
     650
    611651
    612652    //clone tracks
     
    614654    while((track = static_cast<Candidate*>(fItTowerTrackArray->Next())))
    615655    {
     656      //cout<<"looping over tracks"<<endl;
    616657      mother = track;
    617658      track = static_cast<Candidate*>(track->Clone());
     
    621662  }
    622663
    623 
     664 
    624665  // if neutral excess is not significant, rescale eflow tracks, such that the total charged equals the best measurement given by the DualReadoutCalorimeter and tracking
    625666  else if(fTrackEnergy > 0.0)
     
    629670    weightCalo  = (sigma > 0.0) ? 1 / (sigma*sigma) : 0.0;
    630671
    631     bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo);
     672    bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo); 
    632673    rescaleFactor = bestEnergyEstimate/fTrackEnergy;
    633674
     
    635676    fItTowerTrackArray->Reset();
    636677    while((track = static_cast<Candidate*>(fItTowerTrackArray->Next())))
    637     {
     678    { 
    638679      mother = track;
    639       track = static_cast<Candidate *>(track->Clone());
     680      track = static_cast<Candidate*>(track->Clone());
    640681      track->AddCandidate(mother);
    641       track->Momentum.SetPtEtaPhiM(track->Momentum.Pt()*rescaleFactor, track->Momentum.Eta(), track->Momentum.Phi(), track->Momentum.M());
     682
     683      track->Momentum *= rescaleFactor;
     684
    642685      fEFlowTrackOutputArray->Add(track);
    643686    }
    644687  }
    645 
    646 
     688 
     689
     690  /*
     691  // fill energy flow candidates
     692  fECalTrackSigma = TMath::Sqrt(fECalTrackSigma);
     693  fHCalTrackSigma = TMath::Sqrt(fHCalTrackSigma);
     694
     695  //compute neutral excesses
     696  ecalNeutralEnergy = max( (ecalEnergy - fECalTrackEnergy) , 0.0);
     697  hcalNeutralEnergy = max( (hcalEnergy - fHCalTrackEnergy) , 0.0);
     698 
     699  ecalNeutralSigma = ecalNeutralEnergy / TMath::Sqrt(fECalTrackSigma*fECalTrackSigma + ecalSigma*ecalSigma);
     700  hcalNeutralSigma = hcalNeutralEnergy / TMath::Sqrt(fHCalTrackSigma*fHCalTrackSigma + hcalSigma*hcalSigma);
     701 
     702   // if ecal neutral excess is significant, simply create neutral EflowPhoton tower and clone each track into eflowtrack
     703  if(ecalNeutralEnergy > fECalEnergyMin && ecalNeutralSigma > fECalEnergySignificanceMin)
     704  {
     705    // create new photon tower
     706    tower = static_cast<Candidate*>(fTower->Clone());
     707    pt =  ecalNeutralEnergy / TMath::CosH(eta);
     708   
     709    tower->Momentum.SetPtEtaPhiE(pt, eta, phi, ecalNeutralEnergy);
     710    tower->Eem = ecalNeutralEnergy;
     711    tower->Ehad = 0.0;
     712    tower->PID = 22;
     713   
     714    fEFlowPhotonOutputArray->Add(tower);
     715   
     716    //clone tracks
     717    fItECalTowerTrackArray->Reset();
     718    while((track = static_cast<Candidate*>(fItECalTowerTrackArray->Next())))
     719    {
     720      mother = track;
     721      track = static_cast<Candidate*>(track->Clone());
     722      track->AddCandidate(mother);
     723
     724      fEFlowTrackOutputArray->Add(track);
     725    }
     726 
     727  }
     728 
     729  // if neutral excess is not significant, rescale eflow tracks, such that the total charged equals the best measurement given by the DualReadoutCalorimeter and tracking
     730  else if(fECalTrackEnergy > 0.0)
     731  {
     732    weightTrack = (fECalTrackSigma > 0.0) ? 1 / (fECalTrackSigma*fECalTrackSigma) : 0.0;
     733    weightCalo  = (ecalSigma > 0.0) ? 1 / (ecalSigma*ecalSigma) : 0.0;
     734 
     735    bestEnergyEstimate = (weightTrack*fECalTrackEnergy + weightCalo*ecalEnergy) / (weightTrack + weightCalo);
     736    rescaleFactor = bestEnergyEstimate/fECalTrackEnergy;
     737
     738    //rescale tracks
     739    fItECalTowerTrackArray->Reset();
     740    while((track = static_cast<Candidate*>(fItECalTowerTrackArray->Next())))
     741    { 
     742      mother = track;
     743      track = static_cast<Candidate*>(track->Clone());
     744      track->AddCandidate(mother);
     745
     746      track->Momentum *= rescaleFactor;
     747
     748      fEFlowTrackOutputArray->Add(track);
     749    }
     750  }
     751
     752
     753  // if hcal neutral excess is significant, simply create neutral EflowNeutralHadron tower and clone each track into eflowtrack
     754  if(hcalNeutralEnergy > fHCalEnergyMin && hcalNeutralSigma > fHCalEnergySignificanceMin)
     755  {
     756    // create new photon tower
     757    tower = static_cast<Candidate*>(fTower->Clone());
     758    pt =  hcalNeutralEnergy / TMath::CosH(eta);
     759   
     760    tower->Momentum.SetPtEtaPhiE(pt, eta, phi, hcalNeutralEnergy);
     761    tower->Ehad = hcalNeutralEnergy;
     762    tower->Eem = 0.0;
     763   
     764    fEFlowNeutralHadronOutputArray->Add(tower);
     765   
     766    //clone tracks
     767    fItHCalTowerTrackArray->Reset();
     768    while((track = static_cast<Candidate*>(fItHCalTowerTrackArray->Next())))
     769    {
     770      mother = track;
     771      track = static_cast<Candidate*>(track->Clone());
     772      track->AddCandidate(mother);
     773
     774      fEFlowTrackOutputArray->Add(track);
     775    }
     776 
     777  }
     778 
     779  // if neutral excess is not significant, rescale eflow tracks, such that the total charged equals the best measurement given by the DualReadoutCalorimeter and tracking
     780  else if(fHCalTrackEnergy > 0.0)
     781  {
     782    weightTrack = (fHCalTrackSigma > 0.0) ? 1 / (fHCalTrackSigma*fHCalTrackSigma) : 0.0;
     783    weightCalo  = (hcalSigma > 0.0) ? 1 / (hcalSigma*hcalSigma) : 0.0;
     784 
     785    bestEnergyEstimate = (weightTrack*fHCalTrackEnergy + weightCalo*hcalEnergy) / (weightTrack + weightCalo);
     786    rescaleFactor = bestEnergyEstimate / fHCalTrackEnergy;
     787
     788    //rescale tracks
     789    fItHCalTowerTrackArray->Reset();
     790    while((track = static_cast<Candidate*>(fItHCalTowerTrackArray->Next())))
     791    { 
     792      mother = track;
     793      track = static_cast<Candidate*>(track->Clone());
     794      track->AddCandidate(mother);
     795
     796      track->Momentum *= rescaleFactor;
     797
     798      fEFlowTrackOutputArray->Add(track);
     799    }
     800  }
     801
     802  */
    647803}
    648804
Note: See TracChangeset for help on using the changeset viewer.