Changes in modules/DualReadoutCalorimeter.cc [9a7ea36:a1b19ea] in git
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
modules/DualReadoutCalorimeter.cc
r9a7ea36 ra1b19ea 24 24 // This implementation of dual calorimetry relies on several approximations: 25 25 // - 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. 27 27 // 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. 28 28 … … 63 63 fItParticleInputArray(0), fItTrackInputArray(0) 64 64 { 65 65 66 66 fECalResolutionFormula = new DelphesFormula; 67 67 fHCalResolutionFormula = new DelphesFormula; … … 75 75 fTowerTrackArray = new TObjArray; 76 76 fItTowerTrackArray = fTowerTrackArray->MakeIterator(); 77 77 78 78 } 79 79 … … 82 82 DualReadoutCalorimeter::~DualReadoutCalorimeter() 83 83 { 84 84 85 85 if(fECalResolutionFormula) delete fECalResolutionFormula; 86 86 if(fHCalResolutionFormula) delete fHCalResolutionFormula; … … 94 94 if(fTowerTrackArray) delete fTowerTrackArray; 95 95 if(fItTowerTrackArray) delete fItTowerTrackArray; 96 96 97 97 } 98 98 … … 172 172 fECalEnergyMin = GetDouble("ECalEnergyMin", 0.0); 173 173 fHCalEnergyMin = GetDouble("HCalEnergyMin", 0.0); 174 fEnergyMin = GetDouble("EnergyMin", 0.0);175 174 176 175 fECalEnergySignificanceMin = GetDouble("ECalEnergySignificanceMin", 0.0); 177 176 fHCalEnergySignificanceMin = GetDouble("HCalEnergySignificanceMin", 0.0); 178 fEnergySignificanceMin = GetDouble("EnergySignificanceMin", 0.0);179 177 180 178 // switch on or off the dithering of the center of DualReadoutCalorimeter towers … … 247 245 fItParticleInputArray->Reset(); 248 246 number = -1; 249 fTowerRmax=0.;250 251 //cout<<"--------- new event ---------- "<<endl;252 253 247 while((particle = static_cast<Candidate*>(fItParticleInputArray->Next()))) 254 248 { 255 249 const TLorentzVector &particlePosition = particle->Position; 256 250 ++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();261 251 262 252 pdgCode = TMath::Abs(particle->PID); … … 387 377 fHCalTrackEnergy = 0.0; 388 378 fTrackEnergy = 0.0; 389 379 390 380 fECalTrackSigma = 0.0; 391 381 fHCalTrackSigma = 0.0; 392 382 fTrackSigma = 0.0; 393 383 394 384 fTowerTrackHits = 0; 395 385 fTowerPhotonHits = 0; 396 397 fTowerTime = 0.0;398 fTowerTimeWeight = 0.0;399 386 400 387 fECalTowerTrackArray->Clear(); 401 388 fHCalTowerTrackArray->Clear(); 402 389 fTowerTrackArray->Clear(); 403 390 404 391 } 405 392 … … 425 412 } 426 413 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 427 445 // in Dual Readout we do not care if tracks are ECAL of HCAL 428 446 if(fECalTrackFractions[number] > 1.0E-9 || fHCalTrackFractions[number] > 1.0E-9) 429 { 447 { 430 448 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) 432 450 sigma = 0.0; 433 451 if(fHCalTrackFractions[number] > 0) … … 435 453 else 436 454 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; 440 458 else 441 459 energyGuess = momentum.E(); 442 460 443 461 fTrackSigma += (track->TrackResolution)*energyGuess*(track->TrackResolution)*energyGuess; 444 462 fTowerTrackArray->Add(track); 463 445 464 } 446 465 else … … 459 478 position = particle->Position; 460 479 461 462 480 // fill current tower 463 481 ecalEnergy = momentum.E() * fECalTowerFractions[number]; … … 467 485 fHCalTowerEnergy += hcalEnergy; 468 486 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 } 472 494 473 495 fTower->AddCandidate(particle); 474 fTower->Position = position;475 496 } 476 497 … … 485 506 486 507 Candidate *track, *tower, *mother; 487 Double_t energy, pt, eta, phi , r, time;508 Double_t energy, pt, eta, phi; 488 509 Double_t ecalEnergy, hcalEnergy; 489 510 Double_t ecalNeutralEnergy, hcalNeutralEnergy, neutralEnergy; 490 511 491 512 Double_t ecalSigma, hcalSigma, sigma; 492 513 Double_t ecalNeutralSigma, hcalNeutralSigma, neutralSigma; 493 514 494 515 Double_t weightTrack, weightCalo, bestEnergyEstimate, rescaleFactor; 495 516 496 517 TLorentzVector momentum; 497 518 TFractionMap::iterator itFractionMap; … … 501 522 if(!fTower) return; 502 523 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 504 537 if (fHCalTowerEnergy <= fHCalEnergyMin) 505 538 { 506 539 energy = fECalTowerEnergy; 507 540 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 511 545 else 512 546 { 513 547 energy = fECalTowerEnergy + fHCalTowerEnergy; 514 548 sigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy); 549 //cout<<"had energy: "<<energy<<", sigma: "<<sigma<<endl; 515 550 } 516 551 517 552 energy = LogNormal(energy, sigma); 518 553 //cout<<energy<<","<<ecalEnergy<<","<<hcalEnergy<<endl; 554 519 555 if(energy < fEnergyMin || energy < fEnergySignificanceMin*sigma) energy = 0.0; 520 556 … … 526 562 hcalEnergy = LogNormal(fHCalTowerEnergy, hcalSigma); 527 563 528 time = (fTowerTimeWeight < 1.0E-09) ? 0.0 : fTowerTime / fTowerTimeWeight;529 530 564 ecalSigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, ecalEnergy); 531 565 hcalSigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, hcalEnergy); … … 534 568 if(hcalEnergy < fHCalEnergyMin || hcalEnergy < fHCalEnergySignificanceMin*hcalSigma) hcalEnergy = 0.0; 535 569 570 //cout<<"Measured energy: "<<energy<<endl; 571 536 572 if(fSmearTowerCenter) 537 573 { … … 547 583 pt = energy / TMath::CosH(eta); 548 584 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 } 563 606 564 607 fTower->Momentum.SetPtEtaPhiE(pt, eta, phi, energy); 565 608 fTower->Eem = ecalEnergy; 566 609 fTower->Ehad = hcalEnergy; 567 fTower->Etrk = fTrackEnergy; 610 568 611 fTower->Edges[0] = fTowerEdges[0]; 569 612 fTower->Edges[1] = fTowerEdges[1]; … … 581 624 582 625 // fill energy flow candidates 583 626 584 627 fTrackSigma = TMath::Sqrt(fTrackSigma); 585 628 neutralEnergy = max( (energy - fTrackEnergy) , 0.0); 586 629 neutralSigma = neutralEnergy / TMath::Sqrt(fTrackSigma*fTrackSigma + sigma*sigma); 587 630 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 588 636 if(neutralEnergy > fEnergyMin && neutralSigma > fEnergySignificanceMin) 589 637 { 638 639 //cout<<"significant neutral excess found:"<<endl; 590 640 // create new photon tower 591 641 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; 593 644 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 611 651 612 652 //clone tracks … … 614 654 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next()))) 615 655 { 656 //cout<<"looping over tracks"<<endl; 616 657 mother = track; 617 658 track = static_cast<Candidate*>(track->Clone()); … … 621 662 } 622 663 623 664 624 665 // if neutral excess is not significant, rescale eflow tracks, such that the total charged equals the best measurement given by the DualReadoutCalorimeter and tracking 625 666 else if(fTrackEnergy > 0.0) … … 629 670 weightCalo = (sigma > 0.0) ? 1 / (sigma*sigma) : 0.0; 630 671 631 bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo); 672 bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo); 632 673 rescaleFactor = bestEnergyEstimate/fTrackEnergy; 633 674 … … 635 676 fItTowerTrackArray->Reset(); 636 677 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next()))) 637 { 678 { 638 679 mother = track; 639 track = static_cast<Candidate 680 track = static_cast<Candidate*>(track->Clone()); 640 681 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 642 685 fEFlowTrackOutputArray->Add(track); 643 686 } 644 687 } 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 */ 647 803 } 648 804
Note:
See TracChangeset
for help on using the changeset viewer.