-
Introduce a common naming scheme for methods and variables related to primary GenParticles
Introduce a common naming scheme for methods and variables related to primary GenParticles
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
TileGeoG4CalibSD.cc 17.10 KiB
/*
Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
*/
//************************************************************
//
// Class TileGeoG4CalibSD.
// Calibration Sensitive Detector for TileCal
//
// Author: Gia Khoriauli <gia@mail.cern.ch>
// May, 2005.
//
// Major updates: December, 2005;
// July, 2013 (Sergey);
//
//************************************************************
#include "GaudiKernel/ISvcLocator.h"
#include "GaudiKernel/Bootstrap.h"
#include "CLHEP/Units/SystemOfUnits.h"
#include "TileGeoG4CalibSD.h"
#include "TileGeoG4DMLookupBuilder.h"
#include "TileEscapedEnergyProcessing.h"
#include "TileG4Interfaces/ITileCalculator.h"
#include "TileGeoG4SD/TileSDOptions.h"
#include "TileGeoG4SD/TileGeoG4Lookup.hh"
#include "TileGeoG4SD/TileGeoG4LookupBuilder.hh"
#include "TileSimEvent/TileHitVector.h"
#include "PathResolver/PathResolver.h"
#include "RDBAccessSvc/IRDBAccessSvc.h"
#include "GeoModelInterfaces/IGeoModelSvc.h"
#include "CaloIdentifier/CaloDM_ID.h"
#include "CaloIdentifier/CaloCell_ID.h"
#include "CaloSimEvent/CaloCalibrationHitContainer.h"
#include "CaloIdentifier/TileID.h"
#include "CaloG4Sim/SimulationEnergies.h"
#include "CaloG4Sim/EscapedEnergyRegistry.h"
#include "G4VPhysicalVolume.hh"
#include "G4LogicalVolume.hh"
#include "G4Step.hh"
#include "G4VTouchable.hh"
#include "G4TouchableHistory.hh"
#include "G4SDManager.hh"
#include "G4ios.hh"
#include "G4EventManager.hh"
#include "G4Event.hh"
#include "G4RunManager.hh"
#include "MCTruth/AtlasG4EventUserInfo.h"
#include "MCTruth/VTrackInformation.h"
#include <iostream>
#include <string>
//CONSTRUCTOR
TileGeoG4CalibSD::TileGeoG4CalibSD(const G4String& name, const std::vector<std::string>& outputCollectionNames, ITileCalculator* tileCalculator,
const ServiceHandle<StoreGateSvc> &detStore)
: G4VSensitiveDetector(name),
m_tileActiveCellCalibHits(outputCollectionNames[1]),
m_tileInactiveCellCalibHits(outputCollectionNames[2]),
m_tileDeadMaterialCalibHits(outputCollectionNames[3]),
m_tileHits(outputCollectionNames[0]),
m_rdbSvc(tileCalculator->GetOptions()->rDBAccessSvcName, name),
m_geoModSvc(tileCalculator->GetOptions()->geoModelSvcName, name),
m_tileTB(tileCalculator->GetOptions()->tileTB),
m_doCalibHitParticleID(tileCalculator->GetOptions()->doCalibHitParticleID),
#ifdef HITSINFO //added by Sergey
m_ntuple("TileCalibHitNtuple/TileCalibHitNtuple"),
m_ntupleCnt("TileCalibHitCntNtup/TileCalibHitCntNtup"),
#endif
m_calc(tileCalculator),
m_lookupDM(0),
m_simEn(0),
m_tile_eep(0),
m_E_tot(0.0),
m_E_em(0.0),
m_E_nonem(0.0),
m_E_invisible(0.0),
m_E_escaped(0.0),
m_stepTouchable(0),
m_stepPhysVol(0),
m_cSection(0),
m_cell(0),
m_pCell(0),
m_gCell(0),
m_result(),
m_id(),
m_calibHitType(0),
m_subCalo(0),
m_detector(0),
m_side(0),
m_module(0),
m_tower(0),
m_sample(0),
m_dm_subDet(0),
m_dm_type(0),
m_dm_sample(0),
m_dm_region(0),
m_dm_neta(0),
m_dm_nphi(0),
m_xGlobal(0.0),
m_yGlobal(0.0),
m_zGlobal(0.0),
m_phiGlobal(0.0),
m_cellNum(0),
#ifdef HITSINFO //added by Sergey
m_nEvent(1),
m_det_side(0),
#endif
m_defaultHit(false),
m_isExtended(false),
m_isNegative(false)
{
verboseLevel = std::max(verboseLevel, m_calc->GetOptions()->verboseLevel);
m_simEn = new CaloG4::SimulationEnergies();
m_tile_eep = new TileEscapedEnergyProcessing(verboseLevel);
m_tile_eep->SetEscapedFlag(false);
m_tile_eep->SetEnergy5(0.);
m_tile_eep->SetEscapedEnergy(0.);
std::unique_ptr<CaloG4::VEscapedEnergyProcessing> eep(m_tile_eep);
// @UPDATE: this is thread-safe now. EscapedEnergyRegistry is not a singleton in MT mode
CaloG4::EscapedEnergyRegistry* registry = CaloG4::EscapedEnergyRegistry::GetInstance();
registry->AddAndAdoptProcessing("Tile", std::move(eep));
#ifdef HITSINFO //added by Sergey
if (doHitsNTup) {
if(m_ntuple.retrieve().isFailure()) {
G4cout << " Can't retrieve " << m_ntuple << G4endl;
abort();
}
}
if(m_ntupleCnt.retrieve().isFailure()) {
G4cout <<" Can't retrieve " << m_ntupleCnt << G4endl;
abort();
}
#endif
// Retrieve CaloCell_ID helper from detector store
if (detStore->retrieve(m_caloCell_ID).isFailure()) {
G4cout << "FATAL: Failed to retrieve calo cell ID helper" << G4endl;
abort();
}
// Retrieve TileID helper from det store
if (detStore->retrieve(m_caloDM_ID).isFailure()) {
G4cout << "FATAL: Failed to retrieve DM ID helper" << G4endl;
abort();
}
// Grab the service handles
if (m_rdbSvc.retrieve().isFailure()) {
G4cout << "FATAL: Could not retrieve the RDB Svc" << G4endl;
abort();
}
if (m_geoModSvc.retrieve().isFailure()) {
G4cout << "FATAL: Could not retrieve the geo model svc" << G4endl;
abort();
}
//BUILD TILECAL ORDINARY AND CALIBRATION LOOK-UP TABLES
m_lookup = m_calc->GetLookupBuilder();
m_lookupDM = new TileGeoG4DMLookupBuilder(m_lookup, m_rdbSvc, m_geoModSvc, detStore, verboseLevel);
m_lookupDM->BuildLookup(m_tileTB,m_calc->GetOptions()->plateToCell);
if (verboseLevel >= 5) G4cout << "Lookup built for Tile" << G4endl;
m_plateToCell = m_lookupDM->GetPlateToCell();
G4cout << "Using plateToCell = " << (m_plateToCell ? "true" : "false") << G4endl;
// current settings for AddToCell and AddToGirder are controlled just by one flag
m_addToCell = m_plateToCell;
m_addToGirder = !m_plateToCell;
m_atlasG4EvtUserInfo = 0;
m_aStep = 0;
}
//DESTRUCTOR
TileGeoG4CalibSD::~TileGeoG4CalibSD() {
delete m_simEn;
delete m_lookupDM;
}
//-----------------------------------------------------
// Initialize - CALLED AT THE BEGGINING OF EACH EVENT
//-----------------------------------------------------
void TileGeoG4CalibSD::Initialize(G4HCofThisEvent* /*HCE*/) {
if (verboseLevel >= 5) G4cout << "Initializing SD" << G4endl;
if (!m_tileActiveCellCalibHits.isValid()) m_tileActiveCellCalibHits = std::make_unique<CaloCalibrationHitContainer>(m_tileActiveCellCalibHits.name());
if (!m_tileInactiveCellCalibHits.isValid()) m_tileInactiveCellCalibHits = std::make_unique<CaloCalibrationHitContainer>(m_tileInactiveCellCalibHits.name());
if (!m_tileDeadMaterialCalibHits.isValid()) m_tileDeadMaterialCalibHits = std::make_unique<CaloCalibrationHitContainer>(m_tileDeadMaterialCalibHits.name());
if (!m_tileHits.isValid()) m_tileHits = std::make_unique<TileHitVector>(m_tileHits.name());
//TILECAL IDENTIFIER NUMBER - ALWAYS FIXED
m_subCalo = 3;
m_atlasG4EvtUserInfo = 0;
m_E_em = 0.;
m_E_nonem = 0.;
m_E_invisible = 0.;
m_E_escaped = 0.;
m_E_tot = 0.;
m_tile_eep->SetEscapedFlag(false);
m_tile_eep->SetEnergy5(0.);
m_tile_eep->SetEscapedEnergy(0.);
}
//-----------------------------------------------------------------------------
// ProcessHits - CALLED AT EACH STEP INSIDE SENSITIVE VOLUMES
//-----------------------------------------------------------------------------
G4bool TileGeoG4CalibSD::ProcessHits(G4Step* step, G4TouchableHistory* /*ROhist*/) {
bool normalHit = !(m_tile_eep->GetEscapedFlag());
if (verboseLevel >= 10) {
auto theTouchable = static_cast<const G4TouchableHistory*>(step->GetPreStepPoint()->GetTouchable());
G4cout << ((normalHit) ? "ProcessHits: new hit in " : "ProcessHits: escaped energy in ")
<< theTouchable->GetVolume()->GetLogicalVolume()->GetName()
<< G4endl;
}
if (normalHit) {
// Classify() can call ProcessHits() again for escaped energy processing with different G4Step
m_result = m_simEn->Classify(step);
normalHit = (step->GetTotalEnergyDeposit()!=0.);
} else {
SetEscapedEnergy(m_tile_eep->GetEscapedEnergy());
m_tile_eep->SetEscapedFlag(false);
}
if (!m_atlasG4EvtUserInfo)
m_atlasG4EvtUserInfo = dynamic_cast<AtlasG4EventUserInfo*>(G4RunManager::GetRunManager()->GetCurrentEvent()->GetUserInformation());
// Update the event information to note that this step has been dealt with
if ( m_atlasG4EvtUserInfo ) {
// Update the step info
m_atlasG4EvtUserInfo->SetLastProcessedTrackID( step->GetTrack()->GetTrackID() );
m_atlasG4EvtUserInfo->SetLastProcessedStep( step->GetTrack()->GetCurrentStepNumber() );
}
//THIS METHOD WILL CHECK WHETER ARE ALL CLASSIFIED ENERGIES
//ZERO OR NOT. IF THEY ARE THEN RETURN FROM ProcessHits
if (AreClassifiedEnergiesAllZero()) {
if (verboseLevel >= 10) G4cout << "All Energies at this step = 0" << G4endl;
return false;
}
// Keep pointer to current G4Step
m_aStep = step;
//FORCE DEFAULT HIT FLAG TO BE FALSE
m_defaultHit = false;
//Reset CalibHit Type
m_calibHitType = -999;
//COUNT CLASSIFIED ENERGIES
EnergiesSimpleCounter();
//------------- H I T I D E N T I F I E R C A L C U L A T I O N -----------
//FIRST OF ALL FIND A TILECAL SECTION WHERE THE STEP IS.
//IF THE SECTION CAN'T BE FOUND (NOT EXPECTED!) OR THE STEP IS
//SOMEWHERE IN DEFAULT REGION, THEN THE STEP ENERGIES WILL GO
//IN DEFAULT HIT IN BOTH CASES.
//THIS MEANS THAT IDENTIFIER CAN'T BE DETERMINED -> RETURN DEFAULT ID
bool is_identifiable = this->FindTileCalibSection();
if (!is_identifiable) {
if (verboseLevel >= 10)
G4cout << "ProcessHits: TileCalibSection not found for volume " << m_nameVol << G4endl;
m_defaultHit = true;
} else if (m_nameVol.find("Scintillator") != G4String::npos) {//SENSITIVE MATERIAL CELL (SCINTILLATOR)
TileHitData hitData;
bool is_scin = m_calc->FindTileScinSection(m_aStep, hitData);
if (is_scin) {
//BESIDE A CALIBRATION HIT THERE ORDINARY
//HITS SHOULD BE ALSO CREATED OR UPDATED
if (normalHit) {
double deltaTime(0);
m_calc->MakePmtEdepTime(m_aStep, hitData, deltaTime); //calculation of pmtID, edep and scin_Time with aStep
m_calc->ManageScintHit(hitData, deltaTime);//create or update ordinary hit object in the collection
}
this->ScintIDCalculator(hitData);
} else {
if (verboseLevel >= 10)
G4cout << "ProcessHits: TileCell not found for volume " << m_nameVol << G4endl;
m_defaultHit = true;
}
}
//CELL PASSIVE MATERIALS
else if((m_nameVol.find("Period") != G4String::npos)
|| (m_nameVol.find("Glue") != G4String::npos)
|| (m_nameVol.find("Wrapper") != G4String::npos)) {
CellIDCalculator();
}
//FRONT AND END PLATES
else if((m_nameVol.find("Plate") != G4String::npos)
|| (m_nameVol.find("IrUp") != G4String::npos)
|| (m_nameVol.find("IrDw") != G4String::npos)
|| (m_nameVol.find("IrBox") != G4String::npos)
|| (m_nameVol.find("Iron1") != G4String::npos)
|| (m_nameVol.find("Iron2") != G4String::npos)
|| (m_nameVol.find("Iron3") != G4String::npos)
|| (m_nameVol.find("Iron4") != G4String::npos)
/* || (m_nameVol.find("SaddleModule") != G4String::npos) */) {
PlateCellIDCalculator();
} else if((m_nameVol.find("Girder") != G4String::npos)
|| (m_nameVol.find("Finger") != G4String::npos)
|| (m_nameVol.find("EPHole") != G4String::npos)
|| (m_nameVol.find("LArCables") != G4String::npos)
|| (m_nameVol.find("LArService") != G4String::npos)
|| (m_nameVol.find("ExtBarrelSaddleSupport") != G4String::npos) ) {
GirderCellIDCalculator(); //GIRDER AND FINGER MATERIALS
} else {
//HIT IS IN THE VOLUME, WHICH CAN'T BE IDENTIFIED
//FLAG IT TO BE PUT IN A DEFAULT CALIBHIT
if (verboseLevel >= 10) G4cout << "ProcessHits: Use default hit for volume " << m_nameVol << G4endl;
m_defaultHit = true;
}
if (m_defaultHit) {
if (m_tileTB) DefaultHitIDCalculatorTB(m_dm_sample,m_detector-1,0,m_module);
else DefaultHitIDCalculator();
}
if (!m_id.is_valid()) {
G4cout << "ERROR: Wrong identifier in ProcessHits() for volume " << m_nameVol << G4endl;
return true;
}
//-----------------------------------------------------
// --- M A N A G E C A L I B R A T I O N H I T ---
// (see CalibrationHitMerger.cxx for details)
//-----------------------------------------------------
double invisibleEnergy = GetInvisibleEnergy();
double visibleEnergy = GetVisibleEnergy();
if (std::abs(invisibleEnergy) < 0.001 * CLHEP::eV && visibleEnergy < 0.001 * CLHEP::eV) {
if (verboseLevel >= 10) G4cout << "Ignore hit because energy is too small " << visibleEnergy << " " << invisibleEnergy << G4endl;
return true;
}
int primary_id = 0;
if (m_doCalibHitParticleID) {
if (m_atlasG4EvtUserInfo && m_atlasG4EvtUserInfo->GetCurrentPrimaryGenParticle()) primary_id = HepMC::barcode(m_atlasG4EvtUserInfo->GetCurrentPrimaryGenParticle()); // FIXME Barcode-based
else throw std::runtime_error("CalibrationSensitiveDetector: Unable to retrieve barcode!");
}
CaloCalibrationHit* hit = new CaloCalibrationHit(m_id, m_result.energy[CaloG4::SimulationEnergies::kEm],
m_result.energy[CaloG4::SimulationEnergies::kNonEm],
m_result.energy[CaloG4::SimulationEnergies::kInvisible0],
m_result.energy[CaloG4::SimulationEnergies::kEscaped], primary_id);
// If we haven't had a hit in this cell before, add the current hit
// to the hit collection.
// If we've had a hit in this cell before, then add this to the
// previously-existing hit.
// Look for the hit in the m_calibrationHits (this is a binary search).
m_calibrationHits_ptr_t bookmark;
if (m_calibHitType == 1) { // Cell Active CalibHit - Scintillator
bookmark = m_activeCalibrationHits.lower_bound(hit);
if (bookmark == m_activeCalibrationHits.end() || ! (*bookmark)->Equals(hit)) {
// We haven't had a hit in this readout cell before. Add it to our set.
if (m_activeCalibrationHits.empty() || bookmark == m_activeCalibrationHits.begin()) {
// Insert the hit before the first entry in the map.
m_activeCalibrationHits.insert(hit);
} else {
m_activeCalibrationHits.insert(--bookmark, hit);
}
} else {
// Update the existing hit.
(*bookmark)->Add(hit);
// We don't need the hit anymore. Remember that we've adopted
// the hit, so we're responsible for deleting it if needed.
delete hit;
}
} else if (m_calibHitType == 0) { // Cell Inactive CalibHit - Iron, etc. in cell
bookmark = m_inactiveCalibrationHits.lower_bound(hit);
if (bookmark == m_inactiveCalibrationHits.end() || ! (*bookmark)->Equals(hit)) {
if (m_inactiveCalibrationHits.empty() || bookmark == m_inactiveCalibrationHits.begin()) {
m_inactiveCalibrationHits.insert(hit);
} else {
m_inactiveCalibrationHits.insert(--bookmark, hit);
}
} else {
(*bookmark)->Add(hit);
delete hit;
}
} else if (m_calibHitType != -999) { // DM CalibHit
bookmark = m_deadCalibrationHits.lower_bound(hit);
if (bookmark == m_deadCalibrationHits.end() || ! (*bookmark)->Equals(hit)) {
if (m_deadCalibrationHits.empty() || bookmark == m_deadCalibrationHits.begin()) {
m_deadCalibrationHits.insert(hit);
} else {
m_deadCalibrationHits.insert(--bookmark, hit);
}
} else {
(*bookmark)->Add(hit);
delete hit;
}
} else {
delete hit;
}
//STEP IS PROCESSED SUCCESFULY
if (verboseLevel >= 10) G4cout << "End of ProcessHits" << G4endl;
return true;
}
//-----------------------------------------------------
// EndOfEvent - CALLED AT THE END OF EACH EVENT
//-----------------------------------------------------
void TileGeoG4CalibSD::EndOfAthenaEvent() {
if (verboseLevel >= 10) G4cout << "Store Hits" << G4endl;
//CREATE CALIBHITS FROME THEIR VECTORS AND
//STORE THEM IN THE RESPECTIEVE CONTAINERS
m_calibrationHits_ptr_t it;
// Cell Active Material Container
m_tileActiveCellCalibHits->reserve(m_activeCalibrationHits.size());
for( auto &it : m_activeCalibrationHits ) {
m_tileActiveCellCalibHits->push_back(std::move(it));
}
// Cell Inactive Material Container
m_tileInactiveCellCalibHits->reserve(m_inactiveCalibrationHits.size());
for( auto &it : m_inactiveCalibrationHits ) {
m_tileInactiveCellCalibHits->push_back(std::move(it));
}
// Tile Dead Material Container
m_tileDeadMaterialCalibHits->reserve(m_deadCalibrationHits.size());
for( auto &it : m_deadCalibrationHits ) {
m_tileDeadMaterialCalibHits->push_back(std::move(it));
}
// copy ordinary hits to tileHits vector and reset all pointers
m_lookup->ResetCells(&*m_tileHits);
#ifdef HITSINFO // added by Sergey
if(m_ntupleCnt->StoreCNT(&*m_tileActiveCellCalibHits,&*m_tileInactiveCellCalibHits,&*m_tileDeadMaterialCalibHits).isFailure()) {
G4cout << "Failed to store calib hit info in ntuple" << G4endl;
}
#endif
//DEBUG CALIBHITS ENERGIES CALCULATED BY SIMPLE CALCULATOR
//AND DEBUG THE SAME ENERIES DIRECTLE FROM CALIBHITS. THEY
//MUST BE THE SAME IF EVERITHING WENT ON WELL
//
//NOTE: ATHENA DEBUGGING LEVEL SHOULD BE SET 'INFO' OR HIGHER
DebugEnergies();
m_activeCalibrationHits.clear();
m_inactiveCalibrationHits.clear();
m_deadCalibrationHits.clear();
//RESET CELL, GIRDER CELL AND
//PLATE CELL HITS COUNTER VECTORS
m_lookupDM->ResetCells();
#ifdef HITSINFO //INCREMENT OF EVENT COUNTER -- added by Sergey
if (doHitsNTup || doHitsTXT) m_nEvent++;
#endif
}