Changeset d612dec in git for modules/DualReadoutCalorimeter.cc
- Timestamp:
- Dec 9, 2021, 7:52:15 AM (3 years ago)
- Children:
- 29b722a
- Parents:
- a5af1df (diff), 0c0c9af (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
modules/DualReadoutCalorimeter.cc
ra5af1df rd612dec 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); 174 175 175 176 fECalEnergySignificanceMin = GetDouble("ECalEnergySignificanceMin", 0.0); 176 177 fHCalEnergySignificanceMin = GetDouble("HCalEnergySignificanceMin", 0.0); 178 fEnergySignificanceMin = GetDouble("EnergySignificanceMin", 0.0); 177 179 178 180 // switch on or off the dithering of the center of DualReadoutCalorimeter towers … … 245 247 fItParticleInputArray->Reset(); 246 248 number = -1; 249 fTowerRmax=0.; 250 251 //cout<<"--------- new event ---------- "<<endl; 252 247 253 while((particle = static_cast<Candidate*>(fItParticleInputArray->Next()))) 248 254 { 249 255 const TLorentzVector &particlePosition = particle->Position; 250 256 ++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(); 251 261 252 262 pdgCode = TMath::Abs(particle->PID); … … 377 387 fHCalTrackEnergy = 0.0; 378 388 fTrackEnergy = 0.0; 379 389 380 390 fECalTrackSigma = 0.0; 381 391 fHCalTrackSigma = 0.0; 382 392 fTrackSigma = 0.0; 383 393 384 394 fTowerTrackHits = 0; 385 395 fTowerPhotonHits = 0; 396 397 fTowerTime = 0.0; 398 fTowerTimeWeight = 0.0; 386 399 387 400 fECalTowerTrackArray->Clear(); 388 401 fHCalTowerTrackArray->Clear(); 389 402 fTowerTrackArray->Clear(); 390 403 391 404 } 392 405 … … 412 425 } 413 426 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 // muons439 else if(fECalTrackFractions[number] < 1.0E-9 && fHCalTrackFractions[number] < 1.0E-9)440 {441 fEFlowTrackOutputArray->Add(track);442 }443 */444 445 427 // in Dual Readout we do not care if tracks are ECAL of HCAL 446 428 if(fECalTrackFractions[number] > 1.0E-9 || fHCalTrackFractions[number] > 1.0E-9) 447 { 429 { 448 430 fTrackEnergy += energy; 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) 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) 450 432 sigma = 0.0; 451 433 if(fHCalTrackFractions[number] > 0) … … 453 435 else 454 436 sigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, momentum.E()); 455 456 if(sigma/momentum.E() < track->TrackResolution) 457 energyGuess = ecalEnergy + hcalEnergy; 437 438 if(sigma/momentum.E() < track->TrackResolution) 439 energyGuess = ecalEnergy + hcalEnergy; 458 440 else 459 441 energyGuess = momentum.E(); 460 442 461 443 fTrackSigma += (track->TrackResolution)*energyGuess*(track->TrackResolution)*energyGuess; 462 444 fTowerTrackArray->Add(track); 463 464 445 } 465 446 else … … 478 459 position = particle->Position; 479 460 461 480 462 // fill current tower 481 463 ecalEnergy = momentum.E() * fECalTowerFractions[number]; … … 485 467 fHCalTowerEnergy += hcalEnergy; 486 468 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 } 469 // assume combined timing measurements in ECAL/HCAL sections 470 fTowerTime += (ecalEnergy + hcalEnergy) * position.T(); //sigma_t ~ 1/sqrt(E) 471 fTowerTimeWeight += ecalEnergy + hcalEnergy; 494 472 495 473 fTower->AddCandidate(particle); 474 fTower->Position = position; 496 475 } 497 476 … … 506 485 507 486 Candidate *track, *tower, *mother; 508 Double_t energy, pt, eta, phi ;487 Double_t energy, pt, eta, phi, r, time; 509 488 Double_t ecalEnergy, hcalEnergy; 510 489 Double_t ecalNeutralEnergy, hcalNeutralEnergy, neutralEnergy; 511 490 512 491 Double_t ecalSigma, hcalSigma, sigma; 513 492 Double_t ecalNeutralSigma, hcalNeutralSigma, neutralSigma; 514 493 515 494 Double_t weightTrack, weightCalo, bestEnergyEstimate, rescaleFactor; 516 495 517 496 TLorentzVector momentum; 518 497 TFractionMap::iterator itFractionMap; … … 522 501 if(!fTower) return; 523 502 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 503 // if no hadronic energy, use ECAL resolution 537 504 if (fHCalTowerEnergy <= fHCalEnergyMin) 538 505 { 539 506 energy = fECalTowerEnergy; 540 507 sigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy); 541 //cout<<"em energy"<<energy<<", sigma: "<<sigma<<endl; 542 } 543 544 // if hadronic fraction > 0, use HCAL resolution 508 } 509 510 // if hadronic fraction > 0, use HCAL resolution 545 511 else 546 512 { 547 513 energy = fECalTowerEnergy + fHCalTowerEnergy; 548 514 sigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, energy); 549 //cout<<"had energy: "<<energy<<", sigma: "<<sigma<<endl;550 515 } 551 516 552 517 energy = LogNormal(energy, sigma); 553 //cout<<energy<<","<<ecalEnergy<<","<<hcalEnergy<<endl; 554 518 555 519 if(energy < fEnergyMin || energy < fEnergySignificanceMin*sigma) energy = 0.0; 556 520 … … 562 526 hcalEnergy = LogNormal(fHCalTowerEnergy, hcalSigma); 563 527 528 time = (fTowerTimeWeight < 1.0E-09) ? 0.0 : fTowerTime / fTowerTimeWeight; 529 564 530 ecalSigma = fECalResolutionFormula->Eval(0.0, fTowerEta, 0.0, ecalEnergy); 565 531 hcalSigma = fHCalResolutionFormula->Eval(0.0, fTowerEta, 0.0, hcalEnergy); … … 568 534 if(hcalEnergy < fHCalEnergyMin || hcalEnergy < fHCalEnergySignificanceMin*hcalSigma) hcalEnergy = 0.0; 569 535 570 //cout<<"Measured energy: "<<energy<<endl;571 572 536 if(fSmearTowerCenter) 573 537 { … … 583 547 pt = energy / TMath::CosH(eta); 584 548 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 } 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(); 606 563 607 564 fTower->Momentum.SetPtEtaPhiE(pt, eta, phi, energy); 608 565 fTower->Eem = ecalEnergy; 609 566 fTower->Ehad = hcalEnergy; 610 567 fTower->Etrk = fTrackEnergy; 611 568 fTower->Edges[0] = fTowerEdges[0]; 612 569 fTower->Edges[1] = fTowerEdges[1]; … … 624 581 625 582 // fill energy flow candidates 626 583 627 584 fTrackSigma = TMath::Sqrt(fTrackSigma); 628 585 neutralEnergy = max( (energy - fTrackEnergy) , 0.0); 629 586 neutralSigma = neutralEnergy / TMath::Sqrt(fTrackSigma*fTrackSigma + sigma*sigma); 630 587 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 FIXED636 588 if(neutralEnergy > fEnergyMin && neutralSigma > fEnergySignificanceMin) 637 589 { 638 639 //cout<<"significant neutral excess found:"<<endl;640 590 // create new photon tower 641 591 tower = static_cast<Candidate*>(fTower->Clone()); 642 pt = neutralEnergy / TMath::CosH(eta); 643 //cout<<"Creating tower with Pt, Eta, Phi, Energy: "<<pt<<","<<eta<<","<<phi<<","<<neutralEnergy<<endl; 592 pt = neutralEnergy / TMath::CosH(eta); 644 593 tower->Momentum.SetPtEtaPhiE(pt, eta, phi, neutralEnergy); 645 tower->Eem = neutralEnergy; 646 tower->Ehad = 0.0; 647 tower->PID = 22; 648 649 fEFlowPhotonOutputArray->Add(tower); 650 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 } 651 611 652 612 //clone tracks … … 654 614 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next()))) 655 615 { 656 //cout<<"looping over tracks"<<endl;657 616 mother = track; 658 617 track = static_cast<Candidate*>(track->Clone()); … … 662 621 } 663 622 664 623 665 624 // if neutral excess is not significant, rescale eflow tracks, such that the total charged equals the best measurement given by the DualReadoutCalorimeter and tracking 666 625 else if(fTrackEnergy > 0.0) … … 670 629 weightCalo = (sigma > 0.0) ? 1 / (sigma*sigma) : 0.0; 671 630 672 bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo); 631 bestEnergyEstimate = (weightTrack*fTrackEnergy + weightCalo*energy) / (weightTrack + weightCalo); 673 632 rescaleFactor = bestEnergyEstimate/fTrackEnergy; 674 633 … … 676 635 fItTowerTrackArray->Reset(); 677 636 while((track = static_cast<Candidate*>(fItTowerTrackArray->Next()))) 678 { 637 { 679 638 mother = track; 680 track = static_cast<Candidate *>(track->Clone());639 track = static_cast<Candidate *>(track->Clone()); 681 640 track->AddCandidate(mother); 682 683 track->Momentum *= rescaleFactor; 684 641 track->Momentum.SetPtEtaPhiM(track->Momentum.Pt()*rescaleFactor, track->Momentum.Eta(), track->Momentum.Phi(), track->Momentum.M()); 685 642 fEFlowTrackOutputArray->Add(track); 686 643 } 687 644 } 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 */ 645 646 803 647 } 804 648
Note:
See TracChangeset
for help on using the changeset viewer.