From 47ec77dd67d6861fb5e7d54210f6148d5f99e9a3 Mon Sep 17 00:00:00 2001 From: Tomas Dado <tomas.dado@cern.ch> Date: Thu, 4 Feb 2021 08:08:38 +0000 Subject: [PATCH] Whitespace fixes in PixelDigitization code --- .../src/EfieldInterpolator.cxx | 1430 ++++++++------- .../src/EfieldInterpolator.h | 120 +- .../src/EnergyDepositionTool.cxx | 487 ++--- .../src/EnergyDepositionTool.h | 174 +- .../PixelDigitization/src/FEI3SimTool.cxx | 1612 +++++++++++------ .../PixelDigitization/src/FEI3SimTool.h | 39 +- .../PixelDigitization/src/FEI4SimTool.cxx | 172 +- .../PixelDigitization/src/FEI4SimTool.h | 28 +- .../PixelDigitization/src/FrontEndSimTool.h | 300 +-- .../src/PixelDigitization.cxx | 15 +- .../PixelDigitization/src/PixelDigitization.h | 25 +- .../src/PixelDigitizationTool.cxx | 196 +- .../src/PixelDigitizationTool.h | 134 +- .../PixelDigitization/src/RD53SimTool.cxx | 172 +- .../PixelDigitization/src/RD53SimTool.h | 28 +- .../PixelDigitization/src/RadDamageUtil.cxx | 528 +++--- .../PixelDigitization/src/RadDamageUtil.h | 103 +- .../PixelDigitization/src/SensorSim3DTool.cxx | 412 +++-- .../PixelDigitization/src/SensorSim3DTool.h | 181 +- .../src/SensorSimPlanarTool.cxx | 597 +++--- .../src/SensorSimPlanarTool.h | 148 +- .../PixelDigitization/src/SensorSimTool.h | 60 +- 22 files changed, 3969 insertions(+), 2992 deletions(-) diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.cxx index 0be8b63de70a..de7ed510bd67 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ // PixelDigitization includes #include "EfieldInterpolator.h" @@ -21,9 +21,9 @@ #include <TGraph2D.h> #include <algorithm> -// Constructor with parameters: -EfieldInterpolator::EfieldInterpolator(const std::string& type, const std::string& name,const IInterface* parent): - AthAlgTool(type,name,parent), +// Constructor with parameters: +EfieldInterpolator::EfieldInterpolator(const std::string& type, const std::string& name, const IInterface* parent) : + AthAlgTool(type, name, parent), m_efieldOrigin(interspline) {} EfieldInterpolator::~EfieldInterpolator() {} @@ -33,778 +33,802 @@ StatusCode EfieldInterpolator::initialize() { return StatusCode::SUCCESS; } - StatusCode EfieldInterpolator::finalize() { - ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + ATH_MSG_DEBUG("Finalizing " << name() << "..."); return StatusCode::SUCCESS; } -TVectorD CastStdVec(const std::vector<double> vin ){ - TVectorD tmp(vin.size()); - //for(uint i = 0; i<vin.size(); i++ ){ - uint index = 0; - for(auto i : vin){ - tmp[index] = i; - index++; - } - return tmp; +TVectorD CastStdVec(const std::vector<double> vin) { + TVectorD tmp(vin.size()); + //for(uint i = 0; i<vin.size(); i++ ){ + uint index = 0; + + for (auto i : vin) { + tmp[index] = i; + index++; + } + return tmp; } //Returns index at of std::vectorv where val is contained -int isContainedAt(std::vector<double> v, double val){ - for(uint i=0; i<v.size(); i++){ - //Equality for decimals - if( v.at(i)-0.00001 < val && val < v.at(i)+0.00001 ) return i; - } - return -1; +int isContainedAt(std::vector<double> v, double val) { + for (uint i = 0; i < v.size(); i++) { + //Equality for decimals + if (v.at(i) - 0.00001 < val && val < v.at(i) + 0.00001) return i; + } + return -1; } // Initialize indicating layer due to different geometry // One instance interpolates only for fixed geometry (=pixel depth) -void EfieldInterpolator::setLayer(int layer) -{ - ATH_MSG_INFO("Create interpolator for layer "<< layer); - if(layer > 0){ - //it's b layer - m_sensorDepth = 250; - }else{ - //IBL - m_sensorDepth = 200; - } - ATH_MSG_INFO("EfieldInterpolator: Default ctor"); +void EfieldInterpolator::setLayer(int layer) { + ATH_MSG_INFO("Create interpolator for layer " << layer); + if (layer > 0) { + //it's b layer + m_sensorDepth = 250; + } else { + //IBL + m_sensorDepth = 200; + } + ATH_MSG_INFO("EfieldInterpolator: Default ctor"); } -StatusCode EfieldInterpolator::loadTCADlist(const std::string TCADfileListToLoad ) -{ - m_efieldOrigin = interspline; - ATH_MSG_INFO("Load from list " << TCADfileListToLoad); - if(!initializeFromFile(TCADfileListToLoad) ){ - ATH_MSG_WARNING("ERROR: Initialize failed looking for file " << TCADfileListToLoad ); - //Check if given path links to directory: - if(!initializeFromDirectory(TCADfileListToLoad)){; - return StatusCode::FAILURE; - } - } - ATH_MSG_INFO("Finished loading TCAD list"); - return StatusCode::SUCCESS; +StatusCode EfieldInterpolator::loadTCADlist(const std::string TCADfileListToLoad) { + m_efieldOrigin = interspline; + ATH_MSG_INFO("Load from list " << TCADfileListToLoad); + if (!initializeFromFile(TCADfileListToLoad)) { + ATH_MSG_WARNING("ERROR: Initialize failed looking for file " << TCADfileListToLoad); + //Check if given path links to directory: + if (!initializeFromDirectory(TCADfileListToLoad)) { + ; + return StatusCode::FAILURE; + } + } + ATH_MSG_INFO("Finished loading TCAD list"); + return StatusCode::SUCCESS; } -bool EfieldInterpolator::initializeFromDirectory(const std::string fpath){ - //similar to function loadTCADfiles() - //instead of reading file list, list files from directory fpath and create file listing information - - //retrieve fluence and bias voltage from file name (including path, directory names fluence value) - //skip files which do not dollow naming declaration - - //Create textfile for tmp storage - std::ofstream efieldscalib; - efieldscalib.open("listOfEfields.txt"); - TPRegexp rvo("\\b-[0-9](\\w+)V\\b"); - TPRegexp rfl("\\bfl([\\w.]+)e[0-9]{1,2}"); - TString ext = ".dat"; - TString sflu, svol, fullpath; - TSystemDirectory dir( (TString) fpath, (TString) fpath); - TList *files = dir.GetListOfFiles(); - if (files) { - TSystemFile *file; - TString fname; - TIter next(files); - while ((file=(TSystemFile*)next())) { - fname = file->GetName(); - if(fname.BeginsWith("fl") && file->IsDirectory() ){ - TString deeppath = fpath; - deeppath += fname; - deeppath += "/reference/"; - TSystemDirectory deepdir(deeppath, deeppath); - TList *deepfiles = deepdir.GetListOfFiles(); - if (deepfiles) { - TSystemFile *deepfile; - TString deepfname; - TIter deepnext(deepfiles); - while ((deepfile=(TSystemFile*)deepnext())) { - deepfname = deepfile->GetName(); - if (!deepfile->IsDirectory() && deepfname.EndsWith(ext)) { - svol = deepfname(rvo); - svol.ReplaceAll("-",""); - svol.ReplaceAll("V",""); - sflu = deeppath(rfl); - sflu.ReplaceAll("fl",""); - fullpath = deeppath; - fullpath += deepfname; - if(!deepfname.Contains("pruned")){ - if(!sflu.IsFloat()){ - ATH_MSG_INFO("EfieldInterpolator load from directory - could not resolve fluence from " << fullpath); - continue; - } - if(!svol.IsFloat()){ - ATH_MSG_INFO("EfieldInterpolator load from directory - could not resolve voltage from " << fullpath); - continue; - } - }else{ - ATH_MSG_INFO("Skip pruned files: " << fullpath); - continue; - } - efieldscalib << fullpath << " " << sflu << " " << svol << std::endl; - } - } +bool EfieldInterpolator::initializeFromDirectory(const std::string fpath) { + //similar to function loadTCADfiles() + //instead of reading file list, list files from directory fpath and create file listing information + + //retrieve fluence and bias voltage from file name (including path, directory names fluence value) + //skip files which do not dollow naming declaration + + //Create textfile for tmp storage + std::ofstream efieldscalib; + efieldscalib.open("listOfEfields.txt"); + TPRegexp rvo("\\b-[0-9](\\w+)V\\b"); + TPRegexp rfl("\\bfl([\\w.]+)e[0-9]{1,2}"); + TString ext = ".dat"; + TString sflu, svol, fullpath; + TSystemDirectory dir((TString)fpath, (TString)fpath); + TList* files = dir.GetListOfFiles(); + if (files) { + TSystemFile* file; + TString fname; + TIter next(files); + while ((file = (TSystemFile*) next())) { + fname = file->GetName(); + if (fname.BeginsWith("fl") && file->IsDirectory()) { + TString deeppath = fpath; + deeppath += fname; + deeppath += "/reference/"; + TSystemDirectory deepdir(deeppath, deeppath); + TList* deepfiles = deepdir.GetListOfFiles(); + if (deepfiles) { + TSystemFile* deepfile; + TString deepfname; + TIter deepnext(deepfiles); + while ((deepfile = (TSystemFile*) deepnext())) { + deepfname = deepfile->GetName(); + if (!deepfile->IsDirectory() && deepfname.EndsWith(ext)) { + svol = deepfname(rvo); + svol.ReplaceAll("-", ""); + svol.ReplaceAll("V", ""); + sflu = deeppath(rfl); + sflu.ReplaceAll("fl", ""); + fullpath = deeppath; + fullpath += deepfname; + if (!deepfname.Contains("pruned")) { + if (!sflu.IsFloat()) { + ATH_MSG_INFO("EfieldInterpolator load from directory - could not resolve fluence from " << fullpath); + continue; } + if (!svol.IsFloat()) { + ATH_MSG_INFO("EfieldInterpolator load from directory - could not resolve voltage from " << fullpath); + continue; + } + } else { + ATH_MSG_INFO("Skip pruned files: " << fullpath); + continue; + } + efieldscalib << fullpath << " " << sflu << " " << svol << std::endl; } - } - } - efieldscalib.close(); - bool success = initializeFromFile("listOfEfields.txt"); - if(success) ATH_MSG_INFO("Initialized from directory"); - return success; -} -// Load maps into TTree for faster processing -bool EfieldInterpolator::initializeFromFile(const std::string finpath){ - TString fpath = finpath ; - m_initialized = false; - TString fTCAD = ""; - if(fpath.EndsWith(".txt")){ - //File list path, fluence and bias voltage of TCAD simulation as plain text - fTCAD = loadTCADfiles(fpath.Data()); - ATH_MSG_INFO("Loaded file " << fpath << " - all maps accumulated in " << fTCAD); - m_fInter = createInterpolationFromTCADtree(fTCAD.Data()); - ATH_MSG_INFO("created interpolation tree "); - m_initialized = true; - ATH_MSG_INFO("Loaded from .txt file"); - }else{ - if(fpath.EndsWith("toTTree.root") ){ - //File list TCAD efield maps as leaves - m_fInter = createInterpolationFromTCADtree(fpath.Data()); - m_initialized = true; - }else{ - if(fpath.EndsWith(".root")){ - //File list is already transformed to tree - m_fInter = fpath; - m_initialized = true; - } + } } - } - ATH_MSG_INFO("Interpolation has been initialized from file "<< m_fInter <<" - successful "<< m_initialized); - return m_initialized; + } + } + } + efieldscalib.close(); + bool success = initializeFromFile("listOfEfields.txt"); + if (success) ATH_MSG_INFO("Initialized from directory"); + return success; } -// Check if requested values out of range of given TCAD samples -void EfieldInterpolator::reliabilityCheck(double aimFluence, std::vector<double> fluences, double aimVoltage, std::vector<double> voltages){ - bool tooLowVolt = true; - bool tooHighVolt = true; - for(const auto iv : voltages){ - if( aimVoltage < iv ) tooHighVolt= false; - if( aimVoltage > iv ) tooLowVolt= false; - } - bool tooLowFlu = true; - bool tooHighFlu = true; - for(uint iv = 0; iv< fluences.size(); iv++){ - if( aimFluence < fluences.at(iv) ) tooHighFlu = false; - if( aimFluence > fluences.at(iv) ) tooLowFlu = false; +// Load maps into TTree for faster processing +bool EfieldInterpolator::initializeFromFile(const std::string finpath) { + TString fpath = finpath; + + m_initialized = false; + TString fTCAD = ""; + if (fpath.EndsWith(".txt")) { + //File list path, fluence and bias voltage of TCAD simulation as plain text + fTCAD = loadTCADfiles(fpath.Data()); + ATH_MSG_INFO("Loaded file " << fpath << " - all maps accumulated in " << fTCAD); + m_fInter = createInterpolationFromTCADtree(fTCAD.Data()); + ATH_MSG_INFO("created interpolation tree "); + m_initialized = true; + ATH_MSG_INFO("Loaded from .txt file"); + } else { + if (fpath.EndsWith("toTTree.root")) { + //File list TCAD efield maps as leaves + m_fInter = createInterpolationFromTCADtree(fpath.Data()); + m_initialized = true; + } else { + if (fpath.EndsWith(".root")) { + //File list is already transformed to tree + m_fInter = fpath; + m_initialized = true; + } } - if(tooLowFlu ) ATH_MSG_WARNING("WARNING: The fluence value you specified (" << aimFluence <<") is too low to be reliably interpolated!" ); - if(tooLowVolt ) ATH_MSG_WARNING("WARNING: The voltage value you specified (" << aimVoltage <<") is too low to be reliably interpolated!" ); - if(tooHighFlu ) ATH_MSG_WARNING("WARNING: The fluence value you specified (" << aimFluence <<") is too high to be reliably interpolated!" ); - if(tooHighVolt ) ATH_MSG_WARNING("WARNING: The voltage value you specified (" << aimVoltage <<") is too high to be reliably interpolated!" ); - - // Results from Closure Test - // TCAD files save 20 for 20e14 neq/cm2 - if( 12.2 < aimFluence || aimFluence < 1. ) ATH_MSG_WARNING(" WARNING: The fluence value you specified ("<< aimFluence <<") is outside the range within it could be reliably interpolated!" ); //Based on closure test June 2018 - max fluences available: ... 10 12 15 20 - if( 1010. < aimVoltage || aimVoltage < 79. ) ATH_MSG_WARNING(" WARNING: The voltage value you specified ("<< aimVoltage <<") is outside the range within it could be reliably interpolated!" ); //Based on closure test June 2018 - max volatges available: ... 600 800 1000V - return; + } + ATH_MSG_INFO("Interpolation has been initialized from file " << m_fInter << " - successful " << m_initialized); + return m_initialized; } -void EfieldInterpolator::scaleIntegralTo(TH1* hin, double aimInt, int first , int last){ - hin->Scale(aimInt/(float) hin->Integral(first,last) ); +// Check if requested values out of range of given TCAD samples +void EfieldInterpolator::reliabilityCheck(double aimFluence, std::vector<double> fluences, double aimVoltage, + std::vector<double> voltages) { + bool tooLowVolt = true; + bool tooHighVolt = true; + + for (const auto iv : voltages) { + if (aimVoltage < iv) tooHighVolt = false; + if (aimVoltage > iv) tooLowVolt = false; + } + bool tooLowFlu = true; + bool tooHighFlu = true; + for (uint iv = 0; iv < fluences.size(); iv++) { + if (aimFluence < fluences.at(iv)) tooHighFlu = false; + if (aimFluence > fluences.at(iv)) tooLowFlu = false; + } + if (tooLowFlu) ATH_MSG_WARNING( + "WARNING: The fluence value you specified (" << aimFluence << ") is too low to be reliably interpolated!"); + if (tooLowVolt) ATH_MSG_WARNING( + "WARNING: The voltage value you specified (" << aimVoltage << ") is too low to be reliably interpolated!"); + if (tooHighFlu) ATH_MSG_WARNING( + "WARNING: The fluence value you specified (" << aimFluence << ") is too high to be reliably interpolated!"); + if (tooHighVolt) ATH_MSG_WARNING("WARNING: The voltage value you specified (" << aimVoltage << ") is too high to be reliably interpolated!"); + + // Results from Closure Test + // TCAD files save 20 for 20e14 neq/cm2 + if (12.2 < aimFluence || aimFluence < 1.) ATH_MSG_WARNING(" WARNING: The fluence value you specified (" << aimFluence << ") is outside the range within it could be reliably interpolated!"); //Based on closure test June 2018 - max fluences available: ... 10 12 15 20 + if (1010. < aimVoltage || aimVoltage < 79.) ATH_MSG_WARNING(" WARNING: The voltage value you specified (" << aimVoltage << ") is outside the range within it could be reliably interpolated!"); //Based on closure test June 2018 - max voltages available: ... 600 800 1000V + return; } -double EfieldInterpolator::relativeDistance(double x1, double x2) -{ - if( x1 == 0. ) return 0.; - return( (x1-x2)/x1 ); +void EfieldInterpolator::scaleIntegralTo(TH1* hin, double aimInt, int first, int last) { + hin->Scale(aimInt / (float) hin->Integral(first, last)); } -//Use as definition for distance in Fluence/Voltage space -double EfieldInterpolator::relativeDistance(double x1, double y1, double x2, double y2) -{ - return( std::sqrt( relativeDistance(x1,x2)*relativeDistance(x1,x2) + relativeDistance(y1,y2)*relativeDistance(y1,y2))) ; +double EfieldInterpolator::relativeDistance(double x1, double x2) { + if (x1 == 0.) return 0.; + + return((x1 - x2) / x1); } -double EfieldInterpolator::extrapolateLinear(double x1, double y1, double x2, double y2, double xaim){ - // follow linear extrapolation: y=mx+b - double delx = x2-x1; - if(delx == 0) return 0.; // slope not defined - double dely = y2-y1; - double b = y1 - (dely/delx)*x1; - return (xaim*(dely/delx)+b) ; +//Use as definition for distance in Fluence/Voltage space +double EfieldInterpolator::relativeDistance(double x1, double y1, double x2, double y2) { + return(std::sqrt(relativeDistance(x1, x2) * relativeDistance(x1, x2) + relativeDistance(y1, y2) * relativeDistance(y1, y2))); } +double EfieldInterpolator::extrapolateLinear(double x1, double y1, double x2, double y2, double xaim) { + // follow linear extrapolation: y=mx+b + double delx = x2 - x1; + + if (delx == 0) return 0.; // slope not defined + + double dely = y2 - y1; + double b = y1 - (dely / delx) * x1; + return(xaim * (dely / delx) + b); +} // Return E field which is directly read from TCAD simulation // and fill edges values -TH1D* EfieldInterpolator::loadEfieldFromDat(const std::string fname, bool fillEdges ){ - TH1D* hefieldz = new TH1D( "hefieldz", "hefieldz",m_sensorDepth +1,-0.5, m_sensorDepth + 0.5); - std::ifstream in; - in.open(fname); - TString z,e; - int nlines =0; - ATH_MSG_INFO("Load E field from " << fname); - while (1) { - in >> z >> e; - if (!in.good()) break; - if (nlines < 3) printf("e=%s=%f, z=%s=%f \n",e.Data(), e.Atof(),z.Data(), z.Atof() ); - nlines++; - hefieldz->Fill(z.Atof(), e.Atof()); - } - in.close(); - if(fillEdges) EfieldInterpolator::fillEdgeValues(hefieldz); - return hefieldz; +TH1D* EfieldInterpolator::loadEfieldFromDat(const std::string fname, bool fillEdges) { + TH1D* hefieldz = new TH1D("hefieldz", "hefieldz", m_sensorDepth + 1, -0.5, m_sensorDepth + 0.5); + + std::ifstream in; + in.open(fname); + TString z, e; + int nlines = 0; + ATH_MSG_INFO("Load E field from " << fname); + while (1) { + in >> z >> e; + if (!in.good()) break; + if (nlines < 3) printf("e=%s=%f, z=%s=%f \n", e.Data(), e.Atof(), z.Data(), z.Atof()); + nlines++; + hefieldz->Fill(z.Atof(), e.Atof()); + } + in.close(); + if (fillEdges) EfieldInterpolator::fillEdgeValues(hefieldz); + return hefieldz; } // original TCAD simulations given as txt (.dat) files (zVal efieldVal) -const std::string EfieldInterpolator::loadTCADfiles(const std::string targetList) -{ - bool isIBL = true; - TString tl = targetList; - TString fName = targetList; - fName.ReplaceAll(".txt", "_toTTree.root"); - fName =fName.Remove(0,fName.Last('/')+1); //Remove prepending path and store in run directory - TFile* bufferTCADtree = new TFile(fName.Data() ,"RECREATE"); - - if(tl.Length() < 1 ){ - tl = "list_TCAD_efield_maps.txt"; - ATH_MSG_WARNING("No List to load! Set default: " << tl.Data()); - } - std::ifstream in; - TTree *tcadtree = new TTree("tcad","All TCAD E field simulations stored as individual events in tree"); - double voltage = -1.; - double fluence = -1.; - std::vector<double> efield; - std::vector<Int_t> pixeldepth; - tcadtree->Branch("voltage" ,&voltage, "voltage/D" ); - tcadtree->Branch("fluence" ,&fluence,"fluence/D"); - tcadtree->Branch("efield" ,&efield ); - tcadtree->Branch("pixeldepth" ,&pixeldepth); - //Get vetcor of {filename, fluence, bias voltage} - std::vector<std::vector<TString>> infile = list_files(tl); - TString z,e; - TString tmp = ""; - for(uint ifile = 0; ifile<infile.size(); ifile++){ - tmp = infile.at(ifile).at(0); - in.open(infile.at(ifile).at(0)); - // Number format eg 10e14 also 1.2e13 - //fluence = (infile.at(ifile).at(1).ReplaceAll("e14","")).Atof(); - fluence = (infile.at(ifile).at(1)).Atof(); - fluence = fluence * 1e-14; //choose fluence e14 as default unit - voltage = infile.at(ifile).at(2).Atof(); - Int_t nlines = 0; - efield.clear(); - pixeldepth.clear(); - while (1) { - in >> z >> e; - if (!in.good()){ - ATH_MSG_DEBUG("Break for file No. " << ifile << ": "<< infile.at(ifile).at(0) <<" . After " << nlines << " steps"); - break; - } - ATH_MSG_DEBUG("Reading input line: fluence=" << (infile.at(ifile).at(1)).Data() << fluence << " voltage=" << voltage << " e="<< e.Atof() <<"="<< e.Data() << ", z="<< (int) z.Atof() <<"="<< z.Data() <<" in file = "<< ifile ); - nlines++; - efield.push_back(e.Atof()); - pixeldepth.push_back((int) z.Atof()); - if(z.Atof() > 200 ) isIBL = false; // Pixel depth to huge to be IBL - } - bufferTCADtree->cd(); - tcadtree->Fill(); - in.close(); - } - if(!isIBL){ - ATH_MSG_INFO("Pixel depth read from file too big for IBL. Set to B layer, depth = 250um\n"); - m_sensorDepth = 250; - } - bufferTCADtree->cd(); - tcadtree->Write(); - bufferTCADtree->Close(); - return fName.Data(); +const std::string EfieldInterpolator::loadTCADfiles(const std::string targetList) { + bool isIBL = true; + TString tl = targetList; + TString fName = targetList; + + fName.ReplaceAll(".txt", "_toTTree.root"); + fName = fName.Remove(0, fName.Last('/') + 1); //Remove prepending path and store in run directory + TFile* bufferTCADtree = new TFile(fName.Data(), "RECREATE"); + + if (tl.Length() < 1) { + tl = "list_TCAD_efield_maps.txt"; + ATH_MSG_WARNING("No List to load! Set default: " << tl.Data()); + } + std::ifstream in; + TTree* tcadtree = new TTree("tcad", "All TCAD E field simulations stored as individual events in tree"); + double voltage = -1.; + double fluence = -1.; + std::vector<double> efield; + std::vector<Int_t> pixeldepth; + tcadtree->Branch("voltage", &voltage, "voltage/D"); + tcadtree->Branch("fluence", &fluence, "fluence/D"); + tcadtree->Branch("efield", &efield); + tcadtree->Branch("pixeldepth", &pixeldepth); + //Get vetcor of {filename, fluence, bias voltage} + std::vector<std::vector<TString> > infile = list_files(tl); + TString z, e; + TString tmp = ""; + for (uint ifile = 0; ifile < infile.size(); ifile++) { + tmp = infile.at(ifile).at(0); + in.open(infile.at(ifile).at(0)); + // Number format eg 10e14 also 1.2e13 + //fluence = (infile.at(ifile).at(1).ReplaceAll("e14","")).Atof(); + fluence = (infile.at(ifile).at(1)).Atof(); + fluence = fluence * 1e-14; //choose fluence e14 as default unit + voltage = infile.at(ifile).at(2).Atof(); + Int_t nlines = 0; + efield.clear(); + pixeldepth.clear(); + while (1) { + in >> z >> e; + if (!in.good()) { + ATH_MSG_DEBUG("Break for file No. " << ifile << ": " << infile.at(ifile).at(0) << " . After " << nlines << " steps"); + break; + } + ATH_MSG_DEBUG("Reading input line: fluence=" << (infile.at(ifile).at(1)).Data() << fluence << " voltage=" << voltage << " e=" << e.Atof() << "=" << e.Data() << ", z=" << (int) z.Atof() << "=" << z.Data() << " in file = " << ifile); + nlines++; + efield.push_back(e.Atof()); + pixeldepth.push_back((int) z.Atof()); + if (z.Atof() > 200) isIBL = false; // Pixel depth to huge to be IBL + } + bufferTCADtree->cd(); + tcadtree->Fill(); + in.close(); + } + if (!isIBL) { + ATH_MSG_INFO("Pixel depth read from file too big for IBL. Set to B layer, depth = 250um\n"); + m_sensorDepth = 250; + } + bufferTCADtree->cd(); + tcadtree->Write(); + bufferTCADtree->Close(); + return fName.Data(); } -std::vector<std::vector<TString>> EfieldInterpolator::list_files(TString fileList_TCADsamples) -{ - std::vector<std::vector<TString>> filelist; - TString tmpname = ""; - TString tmpfluence = ""; - TString tmpvolt = ""; - std::vector<TString> vstr; - std::ifstream in; - ATH_MSG_DEBUG("Try to open: " << fileList_TCADsamples.Data()); - in.open(fileList_TCADsamples); - int nlines = 0; - while (1) { - in >> tmpname >> tmpfluence >> tmpvolt ; - nlines++; - if (!in.good()) break; - if (tmpname.BeginsWith('#')) continue; - if (tmpname.EndsWith(".dat")){ - vstr.push_back(tmpname); - vstr.push_back(tmpfluence); - vstr.push_back(tmpvolt); - filelist.push_back(vstr); - ATH_MSG_DEBUG("Found and load:"<< tmpfluence.Atof() <<" neq/cm2 " << tmpvolt.Atof() << "V - " << tmpname.Data()); - vstr.clear(); - }else{ - ATH_MSG_WARNING("Wrong extension: "<< tmpname.Data() <<" -- check input " ); - } - } - in.close(); - return filelist; +std::vector<std::vector<TString> > EfieldInterpolator::list_files(TString fileList_TCADsamples) { + std::vector<std::vector<TString> > filelist; + TString tmpname = ""; + TString tmpfluence = ""; + TString tmpvolt = ""; + std::vector<TString> vstr; + std::ifstream in; + ATH_MSG_DEBUG("Try to open: " << fileList_TCADsamples.Data()); + in.open(fileList_TCADsamples); + int nlines = 0; + while (1) { + in >> tmpname >> tmpfluence >> tmpvolt; + nlines++; + if (!in.good()) break; + if (tmpname.BeginsWith('#')) continue; + if (tmpname.EndsWith(".dat")) { + vstr.push_back(tmpname); + vstr.push_back(tmpfluence); + vstr.push_back(tmpvolt); + filelist.push_back(vstr); + ATH_MSG_DEBUG("Found and load:" << tmpfluence.Atof() << " neq/cm2 " << tmpvolt.Atof() << "V - " << tmpname.Data()); + vstr.clear(); + } else { + ATH_MSG_WARNING("Wrong extension: " << tmpname.Data() << " -- check input "); + } + } + in.close(); + return filelist; } // Return path to file containing tree // Final tree is restructured providing e field value as function of fluence, voltage and pixeldepth -const std::string EfieldInterpolator::createInterpolationFromTCADtree(const std::string fTCAD){ - TString tmpfinter = fTCAD; - tmpfinter.ReplaceAll("toTTree","toInterpolationTTree"); - TFile* faim = new TFile(tmpfinter, "Recreate"); - TFile* ftreeTCAD = new TFile(fTCAD.c_str()); - TTreeReader myReader("tcad", ftreeTCAD); - TTreeReaderValue<double> involtage(myReader , "voltage" ); - TTreeReaderValue<double> influence(myReader , "fluence" ); - TTreeReaderValue<std::vector<double>> inefield(myReader , "efield" ); - TTreeReaderValue<std::vector<int>> inpixeldepth(myReader , "pixeldepth"); - // Get Data from TCAD tree - // Loop tree once to initialize values - // Finding which values for fluence and bias voltage exist - // do not hardcode values to maintain compatibility with new simulations available - std::vector<double> allFluences; // serves as x-axis - std::vector<double> allVoltages; // serves as y-axis - std::vector<double> allEfield; - int ne = 0; - double tmpflu, tmpvol; - while(myReader.Next()){ - tmpflu = *influence; - tmpvol = *involtage; - //Check if (double) value of fluence and bias voltage is already saved: if not save - if( std::find_if(allFluences.begin(), allFluences.end(), [&tmpflu](const double &b) { return (std::abs( tmpflu - b) < 1E-6); } ) == allFluences.end()) allFluences.push_back(tmpflu); - if( std::find_if(allVoltages.begin(), allVoltages.end(), [&tmpvol](const double &b) { return (std::abs( tmpvol - b) < 1E-6); } ) == allVoltages.end()) allVoltages.push_back(tmpvol); - ne++; - } - //put into ascending order - std::sort(allFluences.begin(), allFluences.end()); - std::sort(allVoltages.begin(), allVoltages.end()); - for(uint i=0; i<allFluences.size();i++ ) ATH_MSG_DEBUG("fluences recorded: "<< allFluences.at(i)); - for(uint i=0; i<allVoltages.size();i++ ) ATH_MSG_DEBUG("voltages recorded: "<< allVoltages.at(i)); - std::vector<double> tmpef; - myReader.Restart(); //available from ROOT 6.10. - //Exclude TCAD efield values close to sensor edge - int leftEdge = 3; //unify maps - different startting points from z=1 to z=2 and z=3. Simulation not reliable at edges, skip first and last - int rightEdge= m_sensorDepth-2; - std::vector<int> tmpz; - int nz = rightEdge - leftEdge; - // Temporary saving to avoid nesting tree loops - // ie read all z values at once -> add to each branch-param dimension for z - std::vector<double> zpixeldepth(nz, -1); - std::vector<std::vector<double>> zfluence(nz,std::vector<double>( ne, -1)); - std::vector<std::vector<double>> zvoltage(nz,std::vector<double>( ne, -1)); - std::vector<std::vector<double>> zefield(nz, std::vector<double>( ne, -1)); - std::vector<std::vector<std::vector<double>>> zefieldmap(nz,std::vector<std::vector<double>>(allFluences.size(), std::vector<double>(allVoltages.size(), -1) )); - int iev = 0; - ATH_MSG_INFO("Access TTreeReader second time\n"); - - while(myReader.Next()){ - - tmpz = *inpixeldepth; //Pixeldepth of current TCAD map - ATH_MSG_DEBUG("Number of available z values = " << tmpz.size()); - if(tmpz.at(0) > leftEdge ) ATH_MSG_WARNING("Map starting from high pixeldepth = " << tmpz.at(0) << ". Might trouble readout."); - for(int iz = leftEdge; iz < rightEdge; iz++){ - int index = 0; - //Safety check: - //files starting from z=1, z=2 or z=3 - //determine correct index to match sensor depth - ATH_MSG_DEBUG("Access tmpz \n"); - ATH_MSG_DEBUG("Adapt index shift \n"); - while( (tmpz.at(index) != iz) && (index < nz) ){ - ATH_MSG_DEBUG("Adapt possible index shift for missing edge values: pixeldepth tree = " << nz << " current index = " << index); - index++; - } - if(iz%2 ==0) ATH_MSG_DEBUG("Index "<< index <<" - iev "<< iev <<" - iz " << iz ); - tmpflu = *influence; - tmpvol = *involtage; - tmpef = *inefield; - zfluence.at(iz-leftEdge).at(iev) = tmpflu; // assign value to certain pixeldepth(z) - zvoltage.at(iz-leftEdge).at(iev) = tmpvol; - zefield .at(iz-leftEdge).at(iev) = tmpef.at(index) ; - ((zefieldmap.at(iz-leftEdge)).at(isContainedAt(allFluences, tmpflu))).at(isContainedAt(allVoltages,tmpvol)) = tmpef.at(index); - ATH_MSG_DEBUG ("Event #" << iev << "-z="<< iz << ": fluence ="<< tmpflu <<" voltage=" << tmpvol <<", E="<< tmpef.at(index)); - } - iev++; - } - ATH_MSG_DEBUG("# Start filling interpolation tree \n"); - //Filling the interpolation tree - faim->cd(); - TTree *tz_tmp = new TTree("tz","All TCAD E field simulations stored splitted by pixel depth"); - double pixeldepth = -1.; - std::vector<double> fluence; - std::vector<double> voltage; - std::vector<double> xfluence; - std::vector<double> yvoltage; - std::vector<double> efield; - std::vector<std::vector<double>> efieldfluvol; - - tz_tmp->Branch("pixeldepth" ,&pixeldepth); - tz_tmp->Branch("voltage" ,&voltage); - tz_tmp->Branch("fluence" ,&fluence); - tz_tmp->Branch("yvoltage" ,&yvoltage); - tz_tmp->Branch("xfluence" ,&xfluence); - tz_tmp->Branch("efield" ,&efield ); - tz_tmp->Branch("efieldfluvol" ,&efieldfluvol); - for(int iz = leftEdge; iz < rightEdge; iz++ ){ - pixeldepth = iz; - fluence = zfluence.at(iz-leftEdge); - voltage = zvoltage.at(iz-leftEdge); - efield = zefield .at(iz-leftEdge); - efieldfluvol = zefieldmap.at(iz-leftEdge); - xfluence = allFluences; - yvoltage = allVoltages; - ATH_MSG_DEBUG("Fill tree for z ="<< iz <<" pd=" << pixeldepth); - faim->cd(); - tz_tmp->Fill(); +const std::string EfieldInterpolator::createInterpolationFromTCADtree(const std::string fTCAD) { + TString tmpfinter = fTCAD; + + tmpfinter.ReplaceAll("toTTree", "toInterpolationTTree"); + TFile* faim = new TFile(tmpfinter, "Recreate"); + TFile* ftreeTCAD = new TFile(fTCAD.c_str()); + TTreeReader myReader("tcad", ftreeTCAD); + TTreeReaderValue<double> involtage(myReader, "voltage"); + TTreeReaderValue<double> influence(myReader, "fluence"); + TTreeReaderValue<std::vector<double> > inefield(myReader, "efield"); + TTreeReaderValue<std::vector<int> > inpixeldepth(myReader, "pixeldepth"); + // Get Data from TCAD tree + // Loop tree once to initialize values + // Finding which values for fluence and bias voltage exist + // do not hardcode values to maintain compatibility with new simulations available + std::vector<double> allFluences; // serves as x-axis + std::vector<double> allVoltages; // serves as y-axis + std::vector<double> allEfield; + int ne = 0; + double tmpflu, tmpvol; + while (myReader.Next()) { + tmpflu = *influence; + tmpvol = *involtage; + //Check if (double) value of fluence and bias voltage is already saved: if not save + if (std::find_if(allFluences.begin(), allFluences.end(), [&tmpflu](const double& b) { + return(std::abs(tmpflu - b) < 1E-6); + }) == allFluences.end()) allFluences.push_back(tmpflu); + if (std::find_if(allVoltages.begin(), allVoltages.end(), [&tmpvol](const double& b) { + return(std::abs(tmpvol - b) < 1E-6); + }) == allVoltages.end()) allVoltages.push_back(tmpvol); + ne++; + } + //put into ascending order + std::sort(allFluences.begin(), allFluences.end()); + std::sort(allVoltages.begin(), allVoltages.end()); + for (uint i = 0; i < allFluences.size(); i++) ATH_MSG_DEBUG("fluences recorded: " << allFluences.at(i)); + for (uint i = 0; i < allVoltages.size(); i++) ATH_MSG_DEBUG("voltages recorded: " << allVoltages.at(i)); + std::vector<double> tmpef; + myReader.Restart(); //available from ROOT 6.10. + //Exclude TCAD efield values close to sensor edge + int leftEdge = 3; //unify maps - different startting points from z=1 to z=2 and z=3. Simulation not reliable at edges, + // skip first and last + int rightEdge = m_sensorDepth - 2; + std::vector<int> tmpz; + int nz = rightEdge - leftEdge; + // Temporary saving to avoid nesting tree loops + // ie read all z values at once -> add to each branch-param dimension for z + std::vector<double> zpixeldepth(nz, -1); + std::vector<std::vector<double> > zfluence(nz, std::vector<double>(ne, -1)); + std::vector<std::vector<double> > zvoltage(nz, std::vector<double>(ne, -1)); + std::vector<std::vector<double> > zefield(nz, std::vector<double>(ne, -1)); + std::vector<std::vector<std::vector<double> > > zefieldmap(nz, std::vector<std::vector<double> >(allFluences.size(), std::vector<double>(allVoltages.size(), -1))); + int iev = 0; + ATH_MSG_INFO("Access TTreeReader second time\n"); + + while (myReader.Next()) { + tmpz = *inpixeldepth; //Pixeldepth of current TCAD map + ATH_MSG_DEBUG("Number of available z values = " << tmpz.size()); + if (tmpz.at(0) > leftEdge) ATH_MSG_WARNING("Map starting from high pixeldepth = " << tmpz.at(0) << ". Might trouble readout."); + for (int iz = leftEdge; iz < rightEdge; iz++) { + int index = 0; + //Safety check: + //files starting from z=1, z=2 or z=3 + //determine correct index to match sensor depth + ATH_MSG_DEBUG("Access tmpz \n"); + ATH_MSG_DEBUG("Adapt index shift \n"); + while ((tmpz.at(index) != iz) && (index < nz)) { + ATH_MSG_DEBUG("Adapt possible index shift for missing edge values: pixeldepth tree = " << nz << " current index = " << index); + index++; + } + if (iz % 2 == 0) ATH_MSG_DEBUG("Index " << index << " - iev " << iev << " - iz " << iz); + tmpflu = *influence; + tmpvol = *involtage; + tmpef = *inefield; + zfluence.at(iz - leftEdge).at(iev) = tmpflu; // assign value to certain pixeldepth(z) + zvoltage.at(iz - leftEdge).at(iev) = tmpvol; + zefield.at(iz - leftEdge).at(iev) = tmpef.at(index); + ((zefieldmap.at(iz - leftEdge)).at(isContainedAt(allFluences, tmpflu))).at(isContainedAt(allVoltages, tmpvol)) = tmpef.at(index); + ATH_MSG_DEBUG("Event #" << iev << "-z=" << iz << ": fluence =" << tmpflu << " voltage=" << tmpvol << ", E=" << tmpef.at(index)); } - - //Save new Interpolation tree + iev++; + } + ATH_MSG_DEBUG("# Start filling interpolation tree \n"); + //Filling the interpolation tree + faim->cd(); + TTree* tz_tmp = new TTree("tz", "All TCAD E field simulations stored splitted by pixel depth"); + double pixeldepth = -1.; + std::vector<double> fluence; + std::vector<double> voltage; + std::vector<double> xfluence; + std::vector<double> yvoltage; + std::vector<double> efield; + std::vector<std::vector<double> > efieldfluvol; + + tz_tmp->Branch("pixeldepth", &pixeldepth); + tz_tmp->Branch("voltage", &voltage); + tz_tmp->Branch("fluence", &fluence); + tz_tmp->Branch("yvoltage", &yvoltage); + tz_tmp->Branch("xfluence", &xfluence); + tz_tmp->Branch("efield", &efield); + tz_tmp->Branch("efieldfluvol", &efieldfluvol); + for (int iz = leftEdge; iz < rightEdge; iz++) { + pixeldepth = iz; + fluence = zfluence.at(iz - leftEdge); + voltage = zvoltage.at(iz - leftEdge); + efield = zefield.at(iz - leftEdge); + efieldfluvol = zefieldmap.at(iz - leftEdge); + xfluence = allFluences; + yvoltage = allVoltages; + ATH_MSG_DEBUG("Fill tree for z =" << iz << " pd=" << pixeldepth); faim->cd(); - tz_tmp->Write(); - faim->Close(); - m_fInter = tmpfinter.Data(); - return m_fInter; -} + tz_tmp->Fill(); + } + + //Save new Interpolation tree + faim->cd(); + tz_tmp->Write(); + faim->Close(); + m_fInter = tmpfinter.Data(); + return m_fInter; +} // Retrieve fluence values corresponding to a fixed voltage or viceversa if regular order == false -int EfieldInterpolator::fillXYvectors(std::vector<double> vLoop,int ifix, std::vector<std::vector<double>> v2vsv1, std::vector<double> &xx, std::vector<double> &yy, bool regularOrder ){ - yy.clear(); - xx.clear(); - int nfills = 0; - if(regularOrder){ - for(uint ie = 0; ie < v2vsv1.size(); ie++ ){ - double ef = v2vsv1.at(ie).at(ifix); // different fluences for volatge ifix - if(ef > 0){ - yy.push_back(ef); - xx.push_back(vLoop.at(ie)); - nfills++; - }else{ - ATH_MSG_DEBUG("E field value not available for Phi=" << vLoop.at(ie) <<" index Vol= " << ifix); - //Values not ordered in a regular fluence-bias voltage grid - } - } - }else{ - for(uint ie = 0; ie < v2vsv1.at(0).size(); ie++ ){ - double ef = v2vsv1.at(ifix).at(ie); - if(ef > 0){ - yy.push_back(ef); - xx.push_back(vLoop.at(ie)); - nfills++; - }else{ - ATH_MSG_DEBUG("E field value not available for Phi="<< vLoop.at(ifix) << " U="<< vLoop.at(ie)); - //Values not ordered in a regular fluence-bias voltage grid - } - } - } - - return nfills; +int EfieldInterpolator::fillXYvectors(std::vector<double> vLoop, int ifix, std::vector<std::vector<double> > v2vsv1, std::vector<double>& xx, std::vector<double>& yy, bool regularOrder) { + yy.clear(); + xx.clear(); + int nfills = 0; + if (regularOrder) { + for (uint ie = 0; ie < v2vsv1.size(); ie++) { + double ef = v2vsv1.at(ie).at(ifix); // different fluences for volatge ifix + if (ef > 0) { + yy.push_back(ef); + xx.push_back(vLoop.at(ie)); + nfills++; + } else { + ATH_MSG_DEBUG("E field value not available for Phi=" << vLoop.at(ie) << " index Vol= " << ifix); + //Values not ordered in a regular fluence-bias voltage grid + } + } + } else { + for (uint ie = 0; ie < v2vsv1.at(0).size(); ie++) { + double ef = v2vsv1.at(ifix).at(ie); + if (ef > 0) { + yy.push_back(ef); + xx.push_back(vLoop.at(ie)); + nfills++; + } else { + ATH_MSG_DEBUG("E field value not available for Phi=" << vLoop.at(ifix) << " U=" << vLoop.at(ie)); + //Values not ordered in a regular fluence-bias voltage grid + } + } + } + + return nfills; } //Final computation of efield according to method specified -double EfieldInterpolator::estimateEfieldLinear(double aimVoltage){ - return aimVoltage/(float) m_efieldProfile->GetNbinsX() * 10000; //10^4 for unit conversion +double EfieldInterpolator::estimateEfieldLinear(double aimVoltage) { + return aimVoltage / (float) m_efieldProfile->GetNbinsX() * 10000; //10^4 for unit conversion } //Interpolate following inverse distance weighted Interpolation -double EfieldInterpolator::estimateEfieldInvDistance(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double>> vfluvvol, double aimFlu, double aimVol, double measure) -{ - ATH_MSG_WARNING("Use interpolation method _Inverse distance weighted_ - guarantees positive E field but no reliable interpolation"); - double weight = 0.; - double meanEf = 0.; - double distance = 1.; - double efEntry = 0.; - //Loop available efield values for fluence/voltage - take weighted mean - for(uint ivol = 0; ivol < vvol.size(); ivol++ ){ - for(uint iflu = 0; iflu < vflu.size(); iflu++ ){ - efEntry = vfluvvol.at(iflu).at(ivol); - if(efEntry > 0. ){ //Otherwise (-1), TCAD not available - distance = relativeDistance(aimVol, aimFlu, vvol.at(ivol), vflu.at(iflu) ); - if( distance < 0.00001 ) return efEntry; //fluence and voltage almost correpsond to available TCAD simulation - meanEf += efEntry * TMath::Power( (1./distance), measure); - weight += TMath::Power( (1./distance),measure); - } - } +double EfieldInterpolator::estimateEfieldInvDistance(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double> > vfluvvol, double aimFlu, double aimVol, double measure) { + ATH_MSG_WARNING("Use interpolation method _Inverse distance weighted_ - guarantees positive E field but no reliable interpolation"); + double weight = 0.; + double meanEf = 0.; + double distance = 1.; + double efEntry = 0.; + //Loop available efield values for fluence/voltage - take weighted mean + for (uint ivol = 0; ivol < vvol.size(); ivol++) { + for (uint iflu = 0; iflu < vflu.size(); iflu++) { + efEntry = vfluvvol.at(iflu).at(ivol); + if (efEntry > 0.) { //Otherwise (-1), TCAD not available + distance = relativeDistance(aimVol, aimFlu, vvol.at(ivol), vflu.at(iflu)); + if (distance < 0.00001) return efEntry;//fluence and voltage almost correpsond to available TCAD simulation + + meanEf += efEntry * TMath::Power((1. / distance), measure); + weight += TMath::Power((1. / distance), measure); + } } - return (meanEf/weight); + } + return(meanEf / weight); } // Interpolate using cubic splines // E efield values given as function of fluence and bias voltage (vvol, vflu) // interpolate to value for aimFluence and aimVoltage -double EfieldInterpolator::estimateEfield(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double>> vfluvvol, double aimFlu, double aimVol, const std::string prepend, bool debug){ - ATH_MSG_DEBUG("Estimating efield"); - std::vector<double> evol; // e field values for fixed voltages inter- or extrapolated to fluence of interest - std::vector<double> vvolWoEp; // fixed voltages values for which no extrapolation is used to obatin E field in between fluences - std::vector<double> evolWoEp; - //Loop the voltages - for(uint ifix = 0; ifix < vvol.size(); ifix++ ){ - std::vector<double> vx;// = new std::vector<double> ; - std::vector<double> vy;// = new std::vector<double>; - double efflu = -1.; - int availableTCADpoints = fillXYvectors(vflu, ifix, vfluvvol, vx, vy); - ATH_MSG_DEBUG("Number of available TCAD points for voltage " << vvol.at(ifix) << ": " << availableTCADpoints ); - TString name = "FluenceEfield_"; - name += ifix; - name += "FixVol"; - name += TString::Format("%.0f",vvol.at(ifix)); - name += "-aimFlu"; - name += TString::Format("%.1f",aimFlu); - name += "-aimVol"; - name += TString::Format("%.0f",aimVol); - - TGraph* tmpgr = new TGraph(CastStdVec(vx),CastStdVec(vy)); - tmpgr->SetTitle(name.Data()); - if(isInterpolation(vx, aimFlu)){ - name+="_ip"; - }else{ - name+="_ep"; - } - if(m_useSpline ){ - efflu = tmpgr->Eval(aimFlu,0,"S"); - }else{ - efflu = tmpgr->Eval(aimFlu); //linear extrapolation - } - if(debug){ - TString aimFile = m_fInter; - aimFile.ReplaceAll(".root", "_debug.root"); - aimFile.ReplaceAll(".root", prepend ); - aimFile+= name; - aimFile+=".root"; - tmpgr->SaveAs(aimFile); - } - if(isInterpolation(vx, aimFlu)){ - // try without extrapolation: skip extrapolated values - vvolWoEp.push_back(vvol.at(ifix)); - evolWoEp.push_back(efflu); - } - - delete tmpgr; - evol.push_back(efflu); //includes extrapolated values - }//end loop voltages - - //Check for debugging distribution of available E field values in fluence and - if(debug){ - saveTGraph(vvol, vflu, vfluvvol, aimFlu, aimVol, prepend); - } - // if possible to reach voltage of interest without any extrapolation in previous step, prefer this - if(isInterpolation(vvolWoEp, aimVol) && vvolWoEp.size() > 1 ){ - vvol = vvolWoEp; - evol = evolWoEp; - }else{ - ATH_MSG_WARNING("E field created on extrapolation. Please check if reasonable!"); - } - - TString name = "VoltageEfield"; - name += "-aimFlu"; - name += TString::Format("%.1f",aimFlu); - name += "-aimVol"; - name += TString::Format("%.0f",aimVol); - double aimEf = -1; - TGraph* tmpgr = new TGraph(CastStdVec(vvol),CastStdVec(evol) ); - tmpgr->SetTitle(name.Data()); - if(isInterpolation(vvol, aimVol)){ - name+="_ip"; - }else{ - name+="_ep"; - } - if(m_useSpline){ - aimEf = tmpgr->Eval(aimVol,0,"S"); - }else{ - aimEf = tmpgr->Eval(aimVol); //linear extrapolation - } - if(debug){ - TString aimFile = m_fInter; - aimFile.ReplaceAll(".root", "_debug.root"); - aimFile.ReplaceAll(".root", prepend ); - aimFile+= name; - aimFile+=".root"; - tmpgr->SaveAs(aimFile); - } - delete tmpgr; - return aimEf; -} - -//Save all E field values as function of fluence and bias voltage for debugging -void EfieldInterpolator::saveTGraph(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double>> vfluvvol, double aimFlu, double aimVol, const std::string prepend, bool skipNegative){ - TString name = "VoltageEfield"; +double EfieldInterpolator::estimateEfield(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double> > vfluvvol, double aimFlu, double aimVol, const std::string prepend, bool debug) { + ATH_MSG_DEBUG("Estimating efield"); + std::vector<double> evol; // e field values for fixed voltages inter- or extrapolated to fluence of interest + std::vector<double> vvolWoEp; // fixed voltages values for which no extrapolation is used to obatin E field in + // between fluences + std::vector<double> evolWoEp; + //Loop the voltages + for (uint ifix = 0; ifix < vvol.size(); ifix++) { + std::vector<double> vx;// = new std::vector<double> ; + std::vector<double> vy;// = new std::vector<double>; + double efflu = -1.; + int availableTCADpoints = fillXYvectors(vflu, ifix, vfluvvol, vx, vy); + ATH_MSG_DEBUG("Number of available TCAD points for voltage " << vvol.at(ifix) << ": " << availableTCADpoints); + TString name = "FluenceEfield_"; + name += ifix; + name += "FixVol"; + name += TString::Format("%.0f", vvol.at(ifix)); name += "-aimFlu"; - name += TString::Format("%.1f",aimFlu); + name += TString::Format("%.1f", aimFlu); name += "-aimVol"; - name += TString::Format("%.0f",aimVol); - TGraph2D* tmpgr = new TGraph2D(); - tmpgr->GetYaxis()->SetTitle("voltage"); - tmpgr->GetXaxis()->SetTitle("fluence"); + name += TString::Format("%.0f", aimVol); + + TGraph* tmpgr = new TGraph(CastStdVec(vx), CastStdVec(vy)); tmpgr->SetTitle(name.Data()); - ATH_MSG_DEBUG("E field values: "<< vfluvvol.size() << " x " << vfluvvol.at(0).size() << ", flu(x)"<< vflu.size()<< ", vol(y)" << vvol.size() ); - int npoint = 0; - for(uint ix = 0; ix < vfluvvol.size(); ix++){ - for(uint iy=0; iy < vfluvvol.at(ix).size(); iy++){ - printf("Set point %i, %f,%f,%f\n",npoint, vflu.at(ix), vvol.at(iy), vfluvvol.at(ix).at(iy) ); - if(vfluvvol.at(ix).at(iy) < 0){ - if(!skipNegative) tmpgr->SetPoint(npoint, vflu.at(ix), vvol.at(iy), -1); - }else{ - tmpgr->SetPoint(npoint, vflu.at(ix), vvol.at(iy), vfluvvol.at(ix).at(iy) ); - } - npoint++; - } + if (isInterpolation(vx, aimFlu)) { + name += "_ip"; + } else { + name += "_ep"; } + if (m_useSpline) { + efflu = tmpgr->Eval(aimFlu, 0, "S"); + } else { + efflu = tmpgr->Eval(aimFlu); //linear extrapolation + } + if (debug) { + TString aimFile = m_fInter; + aimFile.ReplaceAll(".root", "_debug.root"); + aimFile.ReplaceAll(".root", prepend); + aimFile += name; + aimFile += ".root"; + tmpgr->SaveAs(aimFile); + } + if (isInterpolation(vx, aimFlu)) { + // try without extrapolation: skip extrapolated values + vvolWoEp.push_back(vvol.at(ifix)); + evolWoEp.push_back(efflu); + } + + delete tmpgr; + evol.push_back(efflu); //includes extrapolated values + }//end loop voltages + + //Check for debugging distribution of available E field values in fluence and + if (debug) { + saveTGraph(vvol, vflu, vfluvvol, aimFlu, aimVol, prepend); + } + // if possible to reach voltage of interest without any extrapolation in previous step, prefer this + if (isInterpolation(vvolWoEp, aimVol) && vvolWoEp.size() > 1) { + vvol = vvolWoEp; + evol = evolWoEp; + } else { + ATH_MSG_WARNING("E field created on extrapolation. Please check if reasonable!"); + } + + TString name = "VoltageEfield"; + name += "-aimFlu"; + name += TString::Format("%.1f", aimFlu); + name += "-aimVol"; + name += TString::Format("%.0f", aimVol); + double aimEf = -1; + TGraph* tmpgr = new TGraph(CastStdVec(vvol), CastStdVec(evol)); + tmpgr->SetTitle(name.Data()); + if (isInterpolation(vvol, aimVol)) { + name += "_ip"; + } else { + name += "_ep"; + } + if (m_useSpline) { + aimEf = tmpgr->Eval(aimVol, 0, "S"); + } else { + aimEf = tmpgr->Eval(aimVol); //linear extrapolation + } + if (debug) { TString aimFile = m_fInter; - aimFile.ReplaceAll(".root", "_debugAvailableEfieldVals.root"); - aimFile.ReplaceAll(".root", prepend ); - aimFile+= name; - aimFile+=".root"; + aimFile.ReplaceAll(".root", "_debug.root"); + aimFile.ReplaceAll(".root", prepend); + aimFile += name; + aimFile += ".root"; tmpgr->SaveAs(aimFile); + } + delete tmpgr; + return aimEf; } -TH1D* EfieldInterpolator::createEfieldProfile(double aimFluence, double aimVoltage){ - if(!m_initialized){ - ATH_MSG_WARNING("ERROR: EfieldInterpolator not properly intialized from " << m_fInter); - return NULL; - } - if(aimFluence > 1e12) aimFluence = aimFluence/1e14; //adapt units - TCAD files save 20 for 20e14 neq/cm2 - TString title = "hefieldz"; - TString info = "#Phi="; - info += TString::Format("%.2f",aimFluence); - info += "-U="; - info += TString::Format("%.0f",aimVoltage); - info += ";Pixeldepth z [#mum]"; - info += ";E [V/cm]"; - m_efieldProfile = new TH1D(title, info, m_sensorDepth,-0.5,m_sensorDepth + 0.5); - double pixeldepth; - std::vector<double> xfluence; - std::vector<double> yvoltage; - std::vector<std::vector<double>> efieldfluvol; - TFile* ftreeInterpolation = TFile::Open(m_fInter.c_str()); - TTreeReader myReader("tz", ftreeInterpolation); - TTreeReaderValue<std::vector<double>> involtage(myReader , "yvoltage" ); - TTreeReaderValue<std::vector<double>> influence(myReader , "xfluence" ); - TTreeReaderValue<std::vector<std::vector<double>>> inefield(myReader , "efieldfluvol" ); - TTreeReaderValue<double> inpixeldepth(myReader , "pixeldepth" ); - int ientry = 0; - while(myReader.Next()){ - ATH_MSG_DEBUG("TTree entry: " << ientry); - pixeldepth = *inpixeldepth; - xfluence = *influence; - yvoltage = *involtage; - efieldfluvol = *inefield; - // Check if interpolation is reliable based on given TCAD samples - if(ientry < 2){ - reliabilityCheck(aimFluence, xfluence, aimVoltage, yvoltage); - } - double aimEf =0.; - switch(m_efieldOrigin) - { - case interspline : aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol,aimFluence, aimVoltage ) ; break; - case interinvdist : aimEf = estimateEfieldInvDistance(yvoltage, xfluence, efieldfluvol,aimFluence, aimVoltage) ; break; - case linearField : m_useSpline = false; - aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol,aimFluence, aimVoltage ) ; break; - case TCAD : aimEf = estimateEfieldLinear(aimVoltage) ; - if(aimEf < 0.) ATH_MSG_ERROR("TCAD E field negative at" << pixeldepth <<" !") ; - break; - } +//Save all E field values as function of fluence and bias voltage for debugging +void EfieldInterpolator::saveTGraph(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double> > vfluvvol, double aimFlu, double aimVol, const std::string prepend, bool skipNegative) { + TString name = "VoltageEfield"; + + name += "-aimFlu"; + name += TString::Format("%.1f", aimFlu); + name += "-aimVol"; + name += TString::Format("%.0f", aimVol); + TGraph2D* tmpgr = new TGraph2D(); + tmpgr->GetYaxis()->SetTitle("voltage"); + tmpgr->GetXaxis()->SetTitle("fluence"); + tmpgr->SetTitle(name.Data()); + ATH_MSG_DEBUG("E field values: " << vfluvvol.size() << " x " << vfluvvol.at(0).size() << ", flu(x)" << vflu.size() << ", vol(y)" << vvol.size()); + int npoint = 0; + for (uint ix = 0; ix < vfluvvol.size(); ix++) { + for (uint iy = 0; iy < vfluvvol.at(ix).size(); iy++) { + printf("Set point %i, %f,%f,%f\n", npoint, vflu.at(ix), vvol.at(iy), vfluvvol.at(ix).at(iy)); + if (vfluvvol.at(ix).at(iy) < 0) { + if (!skipNegative) tmpgr->SetPoint(npoint, vflu.at(ix), vvol.at(iy), -1); + } else { + tmpgr->SetPoint(npoint, vflu.at(ix), vvol.at(iy), vfluvvol.at(ix).at(iy)); + } + npoint++; + } + } + TString aimFile = m_fInter; + aimFile.ReplaceAll(".root", "_debugAvailableEfieldVals.root"); + aimFile.ReplaceAll(".root", prepend); + aimFile += name; + aimFile += ".root"; + tmpgr->SaveAs(aimFile); +} - if(aimEf < 0.){ - if(m_useSpline){ - TString debugName = "negativeSplineZ"; - debugName+= TString::Format("%.0f",pixeldepth); - aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol,aimFluence, aimVoltage,debugName.Data(), true ); - ATH_MSG_INFO("InterpolatorMessage: linearly interpolated e=" << aimEf << ", z=" << pixeldepth <<" Phi=,"<< aimFluence <<" U=" << aimVoltage); - m_useSpline = false; - m_efieldOrigin = linearField; // not as good as interpolation - }else{ - TString debugName = "negativeLinearZ"; - debugName+= TString::Format("%.0f",pixeldepth); - aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol,aimFluence, aimVoltage,debugName.Data(), true ); - ATH_MSG_ERROR("InterpolatorMessage: spline and linear interpolation failed => InvDistWeighhted e=" << aimEf << ", z=" << pixeldepth <<" Phi=,"<< aimFluence <<" U=" << aimVoltage); - m_efieldOrigin = interinvdist; // not as good as interpolation (linear or spline) but guaranteed to be positive - } - - myReader.Restart(); - } - m_efieldProfile->SetBinContent(m_efieldProfile->FindBin(pixeldepth), aimEf ); - ientry++; - } - ftreeInterpolation->Close(); - //Check edge values - ATH_MSG_DEBUG("Fill edges"); - fillEdgeValues(m_efieldProfile); - scaleIntegralTo(m_efieldProfile,aimVoltage*10000, 2,m_sensorDepth ); //exclude first and last bin - TString newtitle = m_efieldProfile->GetTitle(); - switch(m_efieldOrigin) - { - case interspline :newtitle +=" spline" ; break; - case interinvdist :newtitle +=" inverse distance" ; break; - case linearField :newtitle +=" linear" ; break; - case TCAD :newtitle +=" TCAD" ; break; - } +TH1D* EfieldInterpolator::createEfieldProfile(double aimFluence, double aimVoltage) { + if (!m_initialized) { + ATH_MSG_WARNING("ERROR: EfieldInterpolator not properly intialized from " << m_fInter); + return NULL; + } + if (aimFluence > 1e12) aimFluence = aimFluence / 1e14; //adapt units - TCAD files save 20 for 20e14 neq/cm2 + TString title = "hefieldz"; + TString info = "#Phi="; + info += TString::Format("%.2f", aimFluence); + info += "-U="; + info += TString::Format("%.0f", aimVoltage); + info += ";Pixeldepth z [#mum]"; + info += ";E [V/cm]"; + m_efieldProfile = new TH1D(title, info, m_sensorDepth, -0.5, m_sensorDepth + 0.5); + double pixeldepth; + std::vector<double> xfluence; + std::vector<double> yvoltage; + std::vector<std::vector<double> > efieldfluvol; + TFile* ftreeInterpolation = TFile::Open(m_fInter.c_str()); + TTreeReader myReader("tz", ftreeInterpolation); + TTreeReaderValue<std::vector<double> > involtage(myReader, "yvoltage"); + TTreeReaderValue<std::vector<double> > influence(myReader, "xfluence"); + TTreeReaderValue<std::vector<std::vector<double> > > inefield(myReader, "efieldfluvol"); + TTreeReaderValue<double> inpixeldepth(myReader, "pixeldepth"); + int ientry = 0; + while (myReader.Next()) { + ATH_MSG_DEBUG("TTree entry: " << ientry); + pixeldepth = *inpixeldepth; + xfluence = *influence; + yvoltage = *involtage; + efieldfluvol = *inefield; + // Check if interpolation is reliable based on given TCAD samples + if (ientry < 2) { + reliabilityCheck(aimFluence, xfluence, aimVoltage, yvoltage); + } + double aimEf = 0.; + switch (m_efieldOrigin) { + case interspline: aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage); + break; - m_efieldProfile->SetTitle(newtitle.Data()); - ATH_MSG_DEBUG("Created Efield"); - m_efieldProfile->SetLineWidth(3) ; - m_efieldProfile->SetLineStyle(2) ; - m_efieldProfile->SetLineColor(4) ; - m_efieldProfile->SetStats(0) ; - return m_efieldProfile; + case interinvdist: aimEf = estimateEfieldInvDistance(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage); + break; + + case linearField: m_useSpline = false; + aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage); + break; + + case TCAD: aimEf = estimateEfieldLinear(aimVoltage); + if (aimEf < 0.) ATH_MSG_ERROR("TCAD E field negative at" << pixeldepth << " !"); + break; + } + + if (aimEf < 0.) { + if (m_useSpline) { + TString debugName = "negativeSplineZ"; + debugName += TString::Format("%.0f", pixeldepth); + aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage, debugName.Data(), true); + ATH_MSG_INFO("InterpolatorMessage: linearly interpolated e=" << aimEf << ", z=" << pixeldepth << " Phi=," << aimFluence << " U=" << aimVoltage); + m_useSpline = false; + m_efieldOrigin = linearField; // not as good as interpolation + } else { + TString debugName = "negativeLinearZ"; + debugName += TString::Format("%.0f", pixeldepth); + aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage, debugName.Data(), true); + ATH_MSG_ERROR("InterpolatorMessage: spline and linear interpolation failed => InvDistWeighhted e=" << aimEf << ", z=" << pixeldepth << " Phi=," << aimFluence << " U=" << aimVoltage); + m_efieldOrigin = interinvdist; // not as good as interpolation (linear or spline) but guaranteed to be positive + } + + myReader.Restart(); + } + m_efieldProfile->SetBinContent(m_efieldProfile->FindBin(pixeldepth), aimEf); + ientry++; + } + ftreeInterpolation->Close(); + //Check edge values + ATH_MSG_DEBUG("Fill edges"); + fillEdgeValues(m_efieldProfile); + scaleIntegralTo(m_efieldProfile, aimVoltage * 10000, 2, m_sensorDepth); //exclude first and last bin + TString newtitle = m_efieldProfile->GetTitle(); + switch (m_efieldOrigin) { + case interspline: newtitle += " spline"; + break; + + case interinvdist: newtitle += " inverse distance"; + break; + + case linearField: newtitle += " linear"; + break; + + case TCAD: newtitle += " TCAD"; + break; + } + + m_efieldProfile->SetTitle(newtitle.Data()); + ATH_MSG_DEBUG("Created Efield"); + m_efieldProfile->SetLineWidth(3); + m_efieldProfile->SetLineStyle(2); + m_efieldProfile->SetLineColor(4); + m_efieldProfile->SetStats(0); + return m_efieldProfile; } //First few and last few bins of TCAD maps not filled due to edge effect - fill with extrapolation -void EfieldInterpolator::fillEdgeValues(TH1D* hin){ - int nBins = hin->GetNbinsX(); - //Check first and last bins if filled - // if not extrapolate linearly from two neighbouring values - // empty (or zero) e field values cause unphysical behaviour in ATHENA/Allpix - for(int i = 5; i > 0; i--){ - //first bins - float curval = hin->GetBinContent(i); - float binii = hin->GetBinContent(i+1); - float biniii = hin->GetBinContent(i+2); - float bini = hin->GetBinContent(i); - if( (bini <0.01 && binii > 0.01 && biniii > 0.01) || ( (biniii-binii)/(float) binii *(binii-bini)/(float) binii <-0.2) ) {//either neighbour filled and bin negative, or edge detected, i.e. slope changes sign and relatively larger than middle entry - bini = extrapolateLinear(i+1, binii , i+2, biniii, i); - if (bini > 0 ){ - hin->SetBinContent(i,bini ); - }else{ - ATH_MSG_WARNING("Could not correct bin "<< i <<" for zero or edge " ); - if(curval <= 0.) hin->SetBinContent(i, 1.); //avoid negative Efield - } - }else{ - ATH_MSG_INFO("No need to fill edge bin: " << i); - } - //Last bins = right hand edge - curval = hin->GetBinContent(nBins+1-i); - binii = hin->GetBinContent(nBins+1-i-1); - biniii = hin->GetBinContent(nBins+1-i-2); - bini = hin->GetBinContent(nBins+1-i); - if( (bini <0.01 && binii > 0.01 && biniii > 0.01) ||( (biniii-binii)/(float) binii *(binii-bini)/(float) binii < -0.2) ) {//left neighbour filled and bin below negative or slope changes sign and magnitude - bini = extrapolateLinear(nBins+1-i-2, hin->GetBinContent(nBins+1-i-2) , nBins+1-i-1, hin->GetBinContent(nBins+1-i-1), nBins+1-i); - if (bini > 0.){ - hin->SetBinContent(nBins+1-i, bini); - }else{ - ATH_MSG_WARNING("Could not correct bin"<< nBins+1-i << " for zero or edge " ); - if(curval <= 0.) hin->SetBinContent(nBins+1-i, 1.); //avoid negative Efield - } - }else{ - ATH_MSG_INFO("No need to fill edge bin: " << (nBins-i) ); - } - } +void EfieldInterpolator::fillEdgeValues(TH1D* hin) { + int nBins = hin->GetNbinsX(); + + //Check first and last bins if filled + // if not extrapolate linearly from two neighbouring values + // empty (or zero) e field values cause unphysical behaviour in ATHENA/Allpix + for (int i = 5; i > 0; i--) { + //first bins + float curval = hin->GetBinContent(i); + float binii = hin->GetBinContent(i + 1); + float biniii = hin->GetBinContent(i + 2); + float bini = hin->GetBinContent(i); + if ((bini < 0.01 && binii > 0.01 && biniii > 0.01) || ((biniii - binii) / (float) binii * (binii - bini) / (float) binii < -0.2)) {//either neighbour filled and bin negative, or edge detected, i.e. slope changes sign and relatively larger than middle entry + bini = extrapolateLinear(i + 1, binii, i + 2, biniii, i); + if (bini > 0) { + hin->SetBinContent(i, bini); + } else { + ATH_MSG_WARNING("Could not correct bin " << i << " for zero or edge "); + if (curval <= 0.) hin->SetBinContent(i, 1.); //avoid negative Efield + } + } else { + ATH_MSG_INFO("No need to fill edge bin: " << i); + } + //Last bins = right hand edge + curval = hin->GetBinContent(nBins + 1 - i); + binii = hin->GetBinContent(nBins + 1 - i - 1); + biniii = hin->GetBinContent(nBins + 1 - i - 2); + bini = hin->GetBinContent(nBins + 1 - i); + if ((bini < 0.01 && binii > 0.01 && biniii > 0.01) || ((biniii - binii) / (float) binii * (binii - bini) / (float) binii < -0.2)) {//left neighbour filled and bin below negative or slope changes sign and magnitude + bini = extrapolateLinear(nBins + 1 - i - 2, hin->GetBinContent(nBins + 1 - i - 2), nBins + 1 - i - 1, hin->GetBinContent(nBins + 1 - i - 1), nBins + 1 - i); + if (bini > 0.) { + hin->SetBinContent(nBins + 1 - i, bini); + } else { + ATH_MSG_WARNING("Could not correct bin" << nBins + 1 - i << " for zero or edge "); + if (curval <= 0.) hin->SetBinContent(nBins + 1 - i, 1.); //avoid negative Efield + } + } else { + ATH_MSG_INFO("No need to fill edge bin: " << (nBins - i)); + } + } } // Main function to be called to create E field of interest -TH1D* EfieldInterpolator::getEfield(double aimFluence, double aimVoltage){ - if(m_initialized){ - m_efieldProfile = createEfieldProfile( aimFluence, aimVoltage); - }else{ - ATH_MSG_WARNING("EfieldInterpolator not initialized! Not able to produce E field."); - } - return m_efieldProfile; +TH1D* EfieldInterpolator::getEfield(double aimFluence, double aimVoltage) { + if (m_initialized) { + m_efieldProfile = createEfieldProfile(aimFluence, aimVoltage); + } else { + ATH_MSG_WARNING("EfieldInterpolator not initialized! Not able to produce E field."); + } + return m_efieldProfile; } - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.h b/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.h index 3233e94c690c..31b756dd41be 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/EfieldInterpolator.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/EfieldInterpolator.h * @author Lennart Adam <lennart.adam@cern.ch> @@ -8,79 +8,89 @@ * @brief * Instances of this class create a map (TH1D) describing the electric field profile along the pixeldepth. * E field maps based on TCAD simulations available only for limited number of values of fluence and bias voltage. - * Interpolate inbetween these simulations to save computing time. - * + * Interpolate inbetween these simulations to save computing time. + * * The TCAD simulations are performed for the FEI4 pixel sensor with a pixeldepth of 200um (IBL) or 250um (B layers) */ #ifndef PIXELDIGITIZATION_EFIELDINTERPOLATOR_H -#define PIXELDIGITIZATION_EFIELDINTERPOLATOR_H +#define PIXELDIGITIZATION_EFIELDINTERPOLATOR_H #include "AthenaBaseComps/AthAlgTool.h" #include "TH1.h" // Different options to retrieve E field // default: interspline -enum interpolationMethod{ - TCAD, //use Precomputed TCAD map +enum interpolationMethod { + TCAD, //use Precomputed TCAD map interspline, //use interpolation based on cubic splines interinvdist, //use inverse distance weighted estimate linearField //linear field according to bias voltage }; -class EfieldInterpolator: public AthAlgTool { - public: - - EfieldInterpolator(const std::string& type, const std::string& name,const IInterface* parent); - virtual ~EfieldInterpolator(); - void setLayer(int layer); - //Recommended constructor - StatusCode loadTCADlist(const std::string TCADfileListToLoad ); - //defFct +class EfieldInterpolator: public AthAlgTool { +public: + EfieldInterpolator(const std::string& type, const std::string& name, const IInterface* parent); + virtual ~EfieldInterpolator(); + void setLayer(int layer); + //Recommended constructor + StatusCode loadTCADlist(const std::string TCADfileListToLoad); + //defFct - virtual StatusCode initialize() override; - virtual StatusCode finalize() override; + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; - // Member Functions - const std::string loadTCADfiles(const std::string targetList = ""); - const std::string createInterpolationFromTCADtree(const std::string fTCAD);//TTree* tTCAD); - bool initializeFromFile(const std::string finpath); - bool initializeFromDirectory(const std::string fpath); - double estimateEfield(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double>> vfluvvol, double aimFlu, double aimVol, const std::string prepend="", bool debug =false); - double estimateEfieldInvDistance(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double>> vfluvvol, double aimFlu, double aimVol, double measure = 1.); + // Member Functions + const std::string loadTCADfiles(const std::string targetList = ""); + const std::string createInterpolationFromTCADtree(const std::string fTCAD);//TTree* tTCAD); + bool initializeFromFile(const std::string finpath); + bool initializeFromDirectory(const std::string fpath); + double estimateEfield(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double> > vfluvvol, + double aimFlu, double aimVol, const std::string prepend = "", bool debug = false); + double estimateEfieldInvDistance(std::vector<double> vvol, std::vector<double> vflu, + std::vector<std::vector<double> > vfluvvol, double aimFlu, double aimVol, + double measure = 1.); - TH1D* createEfieldProfile(double aimFluence, double aimVoltage); - TH1D* getEfield(double aimFluence, double aimVoltage); - TH1D* loadEfieldFromDat(const std::string fname, bool fillEdges = true); - void scaleIntegralTo(TH1* hin, double aimInt, int first = 1, int last = -1); - void reliabilityCheck(double aimFluence, std::vector<double> fluences, double aimVoltage, std::vector<double> voltages); + TH1D* createEfieldProfile(double aimFluence, double aimVoltage); + TH1D* getEfield(double aimFluence, double aimVoltage); + TH1D* loadEfieldFromDat(const std::string fname, bool fillEdges = true); + void scaleIntegralTo(TH1* hin, double aimInt, int first = 1, int last = -1); + void reliabilityCheck(double aimFluence, std::vector<double> fluences, double aimVoltage, + std::vector<double> voltages); +private: + // Member variables + Gaudi::Property<bool> m_initialized + { + this, "initialized", false, "Flag whether already initalized" + }; - private: - // Member variables - Gaudi::Property<bool> m_initialized - {this, "initialized", false, "Flag whether already initalized"}; + Gaudi::Property<bool> m_useSpline + { + this, "useSpline", true, "Flag whether to use cubic splines for interpolation" + }; - Gaudi::Property<bool> m_useSpline - {this, "useSpline", true, "Flag whether to use cubic splines for interpolation"}; + Gaudi::Property<int> m_sensorDepth + { + this, "sensorDepth", 200, "Depth of E fields in sensors in um" + }; - Gaudi::Property<int> m_sensorDepth - {this, "sensorDepth", 200, "Depth of E fields in sensors in um"}; - - interpolationMethod m_efieldOrigin; - TH1D* m_efieldProfile; //Final efield profile - std::string m_fInter; //path to .root file for saving interpolation TTree, i.e. ordered by pixeldepth z - std::vector<std::vector<TString>> list_files(TString fileList_TCADsamples); - double extrapolateLinear(double x1, double y1, double x2, double y2, double xaim ); - int fillXYvectors(std::vector<double> vLoop,int ifix, std::vector<std::vector<double>> v2vsv1, std::vector<double> &xx, std::vector<double> &yy, bool regularOrder = true); - void fillEdgeValues(TH1D* hin); - bool isInterpolation(const std::vector<double> &vval, double aimval) - { return ( vval.front() <= aimval && aimval <= vval.back() ); }; - bool isInterpolation(std::vector<double>* vval, double aimval) - {return ( vval->front() <= aimval && aimval <= vval->back() );}; - double relativeDistance(double x1, double x2); //difference between x1 x2 scaled to x1 - double relativeDistance(double x1, double y1, double x2, double y2); - double estimateEfieldLinear(double aimVoltage); - void saveTGraph(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double>> vfluvvol, double aimFlu, double aimVol, const std::string prepend, bool skipNegative = true); -}; + interpolationMethod m_efieldOrigin; + TH1D* m_efieldProfile; //Final efield profile + std::string m_fInter; //path to .root file for saving interpolation TTree, i.e. ordered by pixeldepth z + std::vector<std::vector<TString> > list_files(TString fileList_TCADsamples); + double extrapolateLinear(double x1, double y1, double x2, double y2, double xaim); + int fillXYvectors(std::vector<double> vLoop, int ifix, std::vector<std::vector<double> > v2vsv1, + std::vector<double>& xx, std::vector<double>& yy, bool regularOrder = true); + void fillEdgeValues(TH1D* hin); + bool isInterpolation(const std::vector<double>& vval, double aimval) + {return(vval.front() <= aimval && aimval <= vval.back());}; + bool isInterpolation(std::vector<double>* vval, double aimval) + {return(vval->front() <= aimval && aimval <= vval->back());}; + double relativeDistance(double x1, double x2); //difference between x1 x2 scaled to x1 + double relativeDistance(double x1, double y1, double x2, double y2); + double estimateEfieldLinear(double aimVoltage); + void saveTGraph(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double> > vfluvvol, + double aimFlu, double aimVol, const std::string prepend, bool skipNegative = true); +}; #endif //> !PIXELDIGITIZATION_EFIELDINTERPOLATOR_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.cxx index 4f108ea9aa25..9a111f463c8d 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "EnergyDepositionTool.h" @@ -30,19 +30,18 @@ using namespace std; // Constructor with parameters: -EnergyDepositionTool::EnergyDepositionTool(const std::string& type, const std::string& name,const IInterface* parent): - AthAlgTool(type,name,parent) {} +EnergyDepositionTool::EnergyDepositionTool(const std::string& type, const std::string& name, const IInterface* parent) : + AthAlgTool(type, name, parent) {} -EnergyDepositionTool::~EnergyDepositionTool(){} +EnergyDepositionTool::~EnergyDepositionTool() {} //======================================= // I N I T I A L I Z E //======================================= StatusCode EnergyDepositionTool::initialize() { - ATH_MSG_INFO("You are using EnergyDepositionTool for solid-state silicon detectors."); - ATH_CHECK(detStore()->retrieve(m_pixelID,"PixelID")); + ATH_CHECK(detStore()->retrieve(m_pixelID, "PixelID")); //Setup distortions tool if (!m_disableDistortions) { @@ -50,249 +49,270 @@ StatusCode EnergyDepositionTool::initialize() { ATH_CHECK(m_distortionKey.initialize()); } - if(m_doBichsel){ + if (m_doBichsel) { // Load Bichsel data m_BichselData.clear(); ATH_MSG_INFO("The number of collision for each sampling is " << m_nCols); ATH_MSG_INFO("Loading data file"); int n_ParticleType = 6; - for(int iParticleType = 1; iParticleType <= n_ParticleType; iParticleType++){ - + for (int iParticleType = 1; iParticleType <= n_ParticleType; iParticleType++) { std::ifstream inputFile; - TString inputFileName = TString::Format("PixelDigitization/Bichsel_%d%s.dat", iParticleType, m_nCols==1 ? "" : TString::Format("_%dsteps",(int)m_nCols).Data()); + TString inputFileName = TString::Format("PixelDigitization/Bichsel_%d%s.dat", iParticleType, m_nCols == 1 ? "" : TString::Format( + "_%dsteps", + (int) m_nCols).Data()); std::string FullFileName = PathResolverFindCalibFile(std::string(inputFileName.Data())); inputFile.open(FullFileName.data()); - ATH_MSG_INFO( "Loading file name : " << inputFileName.Data()); - ATH_MSG_INFO( "-- File full name: " << FullFileName.data()); - ATH_MSG_INFO( "-- Is file open ? " << inputFile.is_open()); + ATH_MSG_INFO("Loading file name : " << inputFileName.Data()); + ATH_MSG_INFO("-- File full name: " << FullFileName.data()); + ATH_MSG_INFO("-- Is file open ? " << inputFile.is_open()); - if(!inputFile.is_open()){ + if (!inputFile.is_open()) { ATH_MSG_FATAL("Fail to load file " << inputFileName.Data() << " !"); - ATH_MSG_FATAL("EnergyDepositionTool::initialize() failed"); - return StatusCode::FAILURE; + ATH_MSG_FATAL("EnergyDepositionTool::initialize() failed"); + return StatusCode::FAILURE; } // prepare data BichselData iData; - double BetaGammaLog10 = 0; inputFile >> BetaGammaLog10; - double ColELog10 = 0; inputFile >> ColELog10; - double IntXLog10 = 0; inputFile >> IntXLog10; + double BetaGammaLog10 = 0; + inputFile >> BetaGammaLog10; + double ColELog10 = 0; + inputFile >> ColELog10; + double IntXLog10 = 0; + inputFile >> IntXLog10; - ATH_MSG_INFO( "-- File eof check : " << inputFile.eof()); + ATH_MSG_INFO("-- File eof check : " << inputFile.eof()); - while(!inputFile.eof()){ + while (!inputFile.eof()) { // check if this BetaGamma has already been stored - if( (iData.Array_BetaGammaLog10.size() == 0) || (iData.Array_BetaGammaLog10.back() != BetaGammaLog10) ){ // a new BetaGamma - - if(iData.Array_BetaGammaLog10.size() != 0){ + if ((iData.Array_BetaGammaLog10.size() == 0) || (iData.Array_BetaGammaLog10.back() != BetaGammaLog10)) { // a new + // BetaGamma + if (iData.Array_BetaGammaLog10.size() != 0) { iData.Array_BetaGammaLog10_UpperBoundIntXLog10.push_back(iData.Array_BetaGammaLog10_IntXLog10.back().back()); - } + } - iData.Array_BetaGammaLog10.push_back(BetaGammaLog10); - std::vector<double> new_ColELog10; iData.Array_BetaGammaLog10_ColELog10.push_back(new_ColELog10); - std::vector<double> new_IntXLog10; iData.Array_BetaGammaLog10_IntXLog10.push_back(new_IntXLog10); - } + iData.Array_BetaGammaLog10.push_back(BetaGammaLog10); + std::vector<double> new_ColELog10; + iData.Array_BetaGammaLog10_ColELog10.push_back(new_ColELog10); + std::vector<double> new_IntXLog10; + iData.Array_BetaGammaLog10_IntXLog10.push_back(new_IntXLog10); + } - iData.Array_BetaGammaLog10_ColELog10.back().push_back(ColELog10); - iData.Array_BetaGammaLog10_IntXLog10.back().push_back(IntXLog10); + iData.Array_BetaGammaLog10_ColELog10.back().push_back(ColELog10); + iData.Array_BetaGammaLog10_IntXLog10.back().push_back(IntXLog10); - inputFile >> BetaGammaLog10; - inputFile >> ColELog10; - inputFile >> IntXLog10; + inputFile >> BetaGammaLog10; + inputFile >> ColELog10; + inputFile >> IntXLog10; } iData.Array_BetaGammaLog10_UpperBoundIntXLog10.push_back(iData.Array_BetaGammaLog10_IntXLog10.back().back()); ATH_MSG_INFO("-- Array_BetaGammaLog10 size : " << iData.Array_BetaGammaLog10.size()); ATH_MSG_INFO("-- Array_BetaGammaLog10_ColELog10 size at 0 : " << iData.Array_BetaGammaLog10_ColELog10[0].size()); ATH_MSG_INFO("-- Array_BetaGammaLog10_IntXLog10 size at 0 : " << iData.Array_BetaGammaLog10_IntXLog10[0].size()); - ATH_MSG_INFO("-- Array_BetaGammaLog10_UpperBoundIntXLog10 : " << iData.Array_BetaGammaLog10_UpperBoundIntXLog10.size()); + ATH_MSG_INFO( + "-- Array_BetaGammaLog10_UpperBoundIntXLog10 : " << iData.Array_BetaGammaLog10_UpperBoundIntXLog10.size()); m_BichselData.push_back(iData); inputFile.close(); ATH_MSG_INFO("-- Finish loading file " << inputFileName.Data()); } - ATH_MSG_INFO("Finish Loading Data File"); + ATH_MSG_INFO("Finish Loading Data File"); } - m_doDeltaRay = (m_doBichsel && m_doDeltaRay); // if we don't do Bichsel model, no re-simulation on delta-ray at all! + m_doDeltaRay = (m_doBichsel && m_doDeltaRay); // if we don't do Bichsel model, no re-simulation on delta-ray at + // all! return StatusCode::SUCCESS; } + //======================================= // F I N A L I Z E //======================================= StatusCode EnergyDepositionTool::finalize() { - ATH_MSG_DEBUG ( "EnergyDepositionTool::finalize()"); + ATH_MSG_DEBUG("EnergyDepositionTool::finalize()"); return StatusCode::SUCCESS; } - //======================================= // D E P O S I T E N E R G Y //======================================= -StatusCode EnergyDepositionTool::depositEnergy(const TimedHitPtr<SiHit> &phit, const InDetDD::SiDetectorElement &Module, std::vector<std::pair<double,double> > &trfHitRecord, std::vector<double> &initialConditions, CLHEP::HepRandomEngine *rndmEngine){ - +StatusCode EnergyDepositionTool::depositEnergy(const TimedHitPtr<SiHit>& phit, const InDetDD::SiDetectorElement& Module, + std::vector<std::pair<double, double> >& trfHitRecord, + std::vector<double>& initialConditions, + CLHEP::HepRandomEngine* rndmEngine) { ATH_MSG_DEBUG("Deposit energy in sensor volume."); //Check if simulated particle or delta ray const EBC_EVCOLL evColl = EBC_MAINEVCOLL; - const HepMcParticleLink::PositionFlag idxFlag = (phit.eventId()==0) ? HepMcParticleLink::IS_POSITION: HepMcParticleLink::IS_INDEX; - const HepMcParticleLink McLink{HepMcParticleLink(phit->trackNumber(), phit.eventId(), evColl, idxFlag)}; - const HepMC::GenParticle* genPart= McLink.cptr(); + const HepMcParticleLink::PositionFlag idxFlag = + (phit.eventId() == 0) ? HepMcParticleLink::IS_POSITION : HepMcParticleLink::IS_INDEX; + const HepMcParticleLink McLink { + HepMcParticleLink(phit->trackNumber(), phit.eventId(), evColl, idxFlag) + }; + const HepMC::GenParticle* genPart = McLink.cptr(); bool delta_hit = true; if (genPart) delta_hit = false; double sensorThickness = Module.design().thickness(); //Get path of particle through volume of G4 - double stepsize = sensorThickness/m_numberOfSteps; - const CLHEP::Hep3Vector startPosition=phit->localStartPosition(); - const CLHEP::Hep3Vector endPosition=phit->localEndPosition(); + double stepsize = sensorThickness / m_numberOfSteps; + const CLHEP::Hep3Vector startPosition = phit->localStartPosition(); + const CLHEP::Hep3Vector endPosition = phit->localEndPosition(); //Get entry and exit positions, store for SensorSim tools - double eta_0=startPosition[SiHit::xEta]; - double phi_0=startPosition[SiHit::xPhi]; - const double depth_0=startPosition[SiHit::xDep]; + double eta_0 = startPosition[SiHit::xEta]; + double phi_0 = startPosition[SiHit::xPhi]; + const double depth_0 = startPosition[SiHit::xDep]; double eta_f = endPosition[SiHit::xEta]; double phi_f = endPosition[SiHit::xPhi]; const double depth_f = endPosition[SiHit::xDep]; //Simulate effect of bowing on entry and exit points - if (!m_disableDistortions && !delta_hit) simulateBow(&Module,phi_0,eta_0,depth_0,phi_f,eta_f,depth_f); - - double dEta=eta_f-eta_0; - double dPhi=phi_f-phi_0; - const double dDepth=depth_f-depth_0; - double pathLength=sqrt(dEta*dEta+dPhi*dPhi+dDepth*dDepth); + if (!m_disableDistortions && !delta_hit) simulateBow(&Module, phi_0, eta_0, depth_0, phi_f, eta_f, depth_f); + + double dEta = eta_f - eta_0; + double dPhi = phi_f - phi_0; + const double dDepth = depth_f - depth_0; + double pathLength = sqrt(dEta * dEta + dPhi * dPhi + dDepth * dDepth); //Scale steps and charge chunks - const int nsteps=int(pathLength/stepsize)+1; - const int ncharges=this->m_numberOfCharges*this->m_numberOfSteps/nsteps+1; + const int nsteps = int(pathLength / stepsize) + 1; + const int ncharges = this->m_numberOfCharges * this->m_numberOfSteps / nsteps + 1; //Store information initialConditions.clear(); - initialConditions.push_back( eta_0 ); - initialConditions.push_back( phi_0 ); - initialConditions.push_back( depth_0 ); - initialConditions.push_back( dEta ); - initialConditions.push_back( dPhi ); - initialConditions.push_back( dDepth ); - initialConditions.push_back( ncharges ); + initialConditions.push_back(eta_0); + initialConditions.push_back(phi_0); + initialConditions.push_back(depth_0); + initialConditions.push_back(dEta); + initialConditions.push_back(dPhi); + initialConditions.push_back(dDepth); + initialConditions.push_back(ncharges); ////////////////////////////////////////////////////// // *** For Bichsel *** // ////////////////////////////////////////////////////// - double iTotalLength = pathLength*1000.; // mm -> micrometer - initialConditions.push_back( iTotalLength ); + double iTotalLength = pathLength * 1000.; // mm -> micrometer + initialConditions.push_back(iTotalLength); // -1 ParticleType means we are unable to run Bichel simulation for this case int ParticleType = -1; - if(m_doBichsel && !(Module.isDBM())){ + if (m_doBichsel && !(Module.isDBM())) { + ParticleType = delta_hit ? (m_doDeltaRay ? 4 : -1) : trfPDG(genPart->pdg_id()); - ParticleType = delta_hit ? (m_doDeltaRay ? 4 : -1) : trfPDG(genPart->pdg_id()); - - if(ParticleType != -1){ // this is a protection in case delta_hit == true (a delta ray) + if (ParticleType != -1) { // this is a protection in case delta_hit == true (a delta ray) TLorentzVector genPart_4V; - if(genPart){ // non-delta-ray - genPart_4V.SetPtEtaPhiM(genPart->momentum().perp(), genPart->momentum().eta(), genPart->momentum().phi(), genPart->momentum().m()); + if (genPart) { // non-delta-ray + genPart_4V.SetPtEtaPhiM(genPart->momentum().perp(), genPart->momentum().eta(), + genPart->momentum().phi(), genPart->momentum().m()); double iBetaGamma = genPart_4V.Beta() * genPart_4V.Gamma(); - if(iBetaGamma < m_doBichselBetaGammaCut) ParticleType = -1; - - } - else{ // delta-ray. - double k = phit->energyLoss()/CLHEP::MeV; // unit of MeV + if (iBetaGamma < m_doBichselBetaGammaCut) ParticleType = -1; + } else { // delta-ray. + double k = phit->energyLoss() / CLHEP::MeV; // unit of MeV double m = 0.511; // unit of MeV - double iBetaGamma = TMath::Sqrt(k*(2*m+k))/m; + double iBetaGamma = TMath::Sqrt(k * (2 * m + k)) / m; - if(iBetaGamma < m_doBichselBetaGammaCut) ParticleType = -1; + if (iBetaGamma < m_doBichselBetaGammaCut) ParticleType = -1; } // In-time PU - if(!m_doPU){ - if(phit.eventId() != 0) ParticleType = -1; + if (!m_doPU) { + if (phit.eventId() != 0) ParticleType = -1; } // Out-of-time PU // We don't cut on the out-of-time PU, since studies show that the fraction is too small } - } + } - if(ParticleType != -1){ // yes, good to go with Bichsel - // I don't know why genPart->momentum() goes crazy ... + if (ParticleType != -1) { // yes, good to go with Bichsel + // I don't know why genPart->momentum() goes crazy ... TLorentzVector genPart_4V; double iBetaGamma; - - if(genPart){ - genPart_4V.SetPtEtaPhiM(genPart->momentum().perp(), genPart->momentum().eta(), genPart->momentum().phi(), genPart->momentum().m()); + + if (genPart) { + genPart_4V.SetPtEtaPhiM(genPart->momentum().perp(), genPart->momentum().eta(), + genPart->momentum().phi(), genPart->momentum().m()); iBetaGamma = genPart_4V.Beta() * genPart_4V.Gamma(); - } - else{ - double k = phit->energyLoss()/CLHEP::MeV; // unit of MeV + } else { + double k = phit->energyLoss() / CLHEP::MeV; // unit of MeV double m = 0.511; // unit of MeV - iBetaGamma = TMath::Sqrt(k*(2*m+k))/m; + iBetaGamma = TMath::Sqrt(k * (2 * m + k)) / m; } int iParticleType = ParticleType; //double iTotalLength = pathLength*1000.; // mm -> micrometer // begin simulation - std::vector<std::pair<double,double> > rawHitRecord = BichselSim(iBetaGamma, iParticleType, iTotalLength, genPart ? (genPart->momentum().e()/CLHEP::MeV) : (phit->energyLoss()/CLHEP::MeV), rndmEngine); + std::vector<std::pair<double, double> > rawHitRecord = BichselSim(iBetaGamma, iParticleType, iTotalLength, + genPart ? (genPart->momentum().e() / + CLHEP::MeV) : (phit->energyLoss() / + CLHEP::MeV), + rndmEngine); // check if returned simulation result makes sense - if(rawHitRecord.size() == 0){ // deal with rawHitRecord==0 specifically -- no energy deposition - std::pair<double,double> specialHit; - specialHit.first = 0.; specialHit.second = 0.; - trfHitRecord.push_back(specialHit); - } - else if( (rawHitRecord.size() == 1) && (rawHitRecord[0].first == -1.) && (rawHitRecord[0].second == -1.) ){ // special flag returned from BichselSim meaning it FAILs - for(int j = 0; j < nsteps; j++){ // do the same thing as old digitization method - std::pair<double,double> specialHit; - specialHit.first = 1.0*iTotalLength/nsteps * (j + 0.5); specialHit.second = phit->energyLoss()*1.E+6/nsteps; + if (rawHitRecord.size() == 0) { // deal with rawHitRecord==0 specifically -- no energy deposition + std::pair<double, double> specialHit; + specialHit.first = 0.; + specialHit.second = 0.; + trfHitRecord.push_back(specialHit); + } else if ((rawHitRecord.size() == 1) && (rawHitRecord[0].first == -1.) && (rawHitRecord[0].second == -1.)) { // special flag returned from BichselSim meaning it FAILs + for (int j = 0; j < nsteps; j++) { // do the same thing as old digitization method + std::pair<double, double> specialHit; + specialHit.first = 1.0 * iTotalLength / nsteps * (j + 0.5); + specialHit.second = phit->energyLoss() * 1.E+6 / nsteps; trfHitRecord.push_back(specialHit); } - } - else{ // cluster thousands hits to ~20 groups + } else { // cluster thousands hits to ~20 groups trfHitRecord = ClusterHits(rawHitRecord, nsteps); } - } - else{ // same as old digitization method - ////////////////////////////////////////////////////// - // *** B I C H S E L O F F *** // - ////////////////////////////////////////////////////// + } else { // same as old digitization method + ////////////////////////////////////////////////////// + // *** B I C H S E L O F F *** // + ////////////////////////////////////////////////////// //double iTotalLength = pathLength*1000.; // mm -> micrometer - for(int j = 0; j < nsteps; j++){ // do the same thing as old digitization method - std::pair<double,double> specialHit; - specialHit.first = 1.0*iTotalLength/nsteps * (j + 0.5); specialHit.second = phit->energyLoss()*1.E+6/nsteps; + for (int j = 0; j < nsteps; j++) { // do the same thing as old digitization method + std::pair<double, double> specialHit; + specialHit.first = 1.0 * iTotalLength / nsteps * (j + 0.5); + specialHit.second = phit->energyLoss() * 1.E+6 / nsteps; trfHitRecord.push_back(specialHit); } } - + // *** Finsih Bichsel *** // return StatusCode::SUCCESS; - } //====================================== -// S I M U L A T E B O W +// S I M U L A T E B O W //====================================== -void EnergyDepositionTool::simulateBow(const InDetDD::SiDetectorElement * element, double& xi, double& yi, const double zi, double& xf, double& yf, const double zf) const { - +void EnergyDepositionTool::simulateBow(const InDetDD::SiDetectorElement* element, double& xi, double& yi, + const double zi, double& xf, double& yf, const double zf) const { // If tool is NONE we apply no correction. - Amg::Vector3D dir(element->hitPhiDirection()*(xf-xi), element->hitEtaDirection()*(yf-yi), element->hitDepthDirection()*(zf-zi)); + Amg::Vector3D dir(element->hitPhiDirection() * (xf - xi), + element->hitEtaDirection() * (yf - yi), element->hitDepthDirection() * (zf - zi)); Amg::Vector2D locposi = element->hitLocalToLocal(yi, xi); Amg::Vector2D locposf = element->hitLocalToLocal(yf, xf); - Amg::Vector2D newLocposi = SG::ReadCondHandle<PixelDistortionData>(m_distortionKey)->correctSimulation(m_pixelID->wafer_hash(element->identify()), locposi, dir); - Amg::Vector2D newLocposf = SG::ReadCondHandle<PixelDistortionData>(m_distortionKey)->correctSimulation(m_pixelID->wafer_hash(element->identify()), locposf, dir); + Amg::Vector2D newLocposi = SG::ReadCondHandle<PixelDistortionData>(m_distortionKey)->correctSimulation(m_pixelID->wafer_hash( + element-> + identify()), locposi, + dir); + Amg::Vector2D newLocposf = SG::ReadCondHandle<PixelDistortionData>(m_distortionKey)->correctSimulation(m_pixelID->wafer_hash( + element-> + identify()), locposf, + dir); // Extract new coordinates and convert back to hit frame. xi = newLocposi[Trk::x] * element->hitPhiDirection(); @@ -302,89 +322,96 @@ void EnergyDepositionTool::simulateBow(const InDetDD::SiDetectorElement * elemen yf = newLocposf[Trk::y] * element->hitEtaDirection(); } - //======================================= // B I C H S E L D E P O S I T I O N //======================================= // input total length should be in the unit of micrometer // InciEnergy should be in MeV -// In case there is any abnormal in runtime, (-1,-1) will be returned indicating old deposition model should be used instead +// In case there is any abnormal in runtime, (-1,-1) will be returned indicating old deposition model should be used +// instead //----------------------------------------------------------- -std::vector<std::pair<double,double> > EnergyDepositionTool::BichselSim(double BetaGamma, int ParticleType, double TotalLength, double InciEnergy, CLHEP::HepRandomEngine *rndmEngine) const{ +std::vector<std::pair<double, double> > EnergyDepositionTool::BichselSim(double BetaGamma, int ParticleType, + double TotalLength, double InciEnergy, + CLHEP::HepRandomEngine* rndmEngine) const { ATH_MSG_DEBUG("Begin EnergyDepositionTool::BichselSim"); // prepare hit record (output) - std::vector<std::pair<double,double> > rawHitRecord; + std::vector<std::pair<double, double> > rawHitRecord; double TotalEnergyLoss = 0.; double accumLength = 0.; // load relevant data - BichselData iData = m_BichselData[ParticleType-1]; + BichselData iData = m_BichselData[ParticleType - 1]; double BetaGammaLog10 = TMath::Log10(BetaGamma); - std::pair<int,int> indices_BetaGammaLog10 = GetBetaGammaIndices(BetaGammaLog10, iData); + std::pair<int, int> indices_BetaGammaLog10 = GetBetaGammaIndices(BetaGammaLog10, iData); // upper bound double IntXUpperBound = GetUpperBound(indices_BetaGammaLog10, BetaGammaLog10, iData); - if(IntXUpperBound <= 0.){ + if (IntXUpperBound <= 0.) { ATH_MSG_WARNING("Negative IntXUpperBound in EnergyDepositionTool::BichselSim! (-1,-1) will be returned"); SetFailureFlag(rawHitRecord); return rawHitRecord; } - + // mean-free path - double lambda = (1./IntXUpperBound) * 1.E4; // unit of IntX is cm-1. It needs to be converted to micrometer-1 + double lambda = (1. / IntXUpperBound) * 1.E4; // unit of IntX is cm-1. It needs to be converted to micrometer-1 // check nan lambda - if(std::isnan(lambda)){ + if (std::isnan(lambda)) { SetFailureFlag(rawHitRecord); return rawHitRecord; } // direct those hits with potential too many steps into nominal simulation int LoopLimit = m_LoopLimit; // limit assuming 1 collision per sampling - if(fabs(1.0*TotalLength/lambda) > LoopLimit){ // m_nCols is cancelled out in the formula + if (fabs(1.0 * TotalLength / lambda) > LoopLimit) { // m_nCols is cancelled out in the formula SetFailureFlag(rawHitRecord); return rawHitRecord; } // begin simulation int count = 0; - while(true){ + while (true) { // infinite loop protection - if(count >= (1.0*LoopLimit/m_nCols)){ - ATH_MSG_WARNING("Potential infinite loop in BichselSim. Exit Loop. A special flag will be returned (-1,-1). The total length is " << TotalLength << ". The lambda is " << lambda << "."); + if (count >= (1.0 * LoopLimit / m_nCols)) { + ATH_MSG_WARNING( + "Potential infinite loop in BichselSim. Exit Loop. A special flag will be returned (-1,-1). The total length is " << TotalLength << ". The lambda is " << lambda << + "."); SetFailureFlag(rawHitRecord); break; } // sample hit position -- exponential distribution double HitPosition = 0.; - for(int iHit = 0; iHit < m_nCols; iHit++){ - HitPosition += CLHEP::RandExpZiggurat::shoot(rndmEngine, lambda); + for (int iHit = 0; iHit < m_nCols; iHit++) { + HitPosition += CLHEP::RandExpZiggurat::shoot(rndmEngine, lambda); } // termination by hit position // yes, in case m_nCols > 1, we will loose the last m_nCols collisions. So m_nCols cannot be too big - if(accumLength + HitPosition >= TotalLength) - break; + if (accumLength + HitPosition >= TotalLength) break; // sample single collision double TossEnergyLoss = -1.; - while(TossEnergyLoss <= 0.){ // we have to do this because sometimes TossEnergyLoss will be negative due to too small TossIntX + while (TossEnergyLoss <= 0.) { // we have to do this because sometimes TossEnergyLoss will be negative due to too + // small TossIntX double TossIntX = CLHEP::RandFlat::shoot(rndmEngine, 0., IntXUpperBound); TossEnergyLoss = GetColE(indices_BetaGammaLog10, TMath::Log10(TossIntX), iData); } - // check if it is delta-ray -- delta-ray is already taken care of by G4 and treated as an independent hit. Unfortunately, we won't deal with delta-ray using Bichsel's model - // as long as m_nCols is not very big, the probability of having >= 2 such a big energy loss in a row is very small. In case there is a delta-ray, it would be so dominant that other energy deposition becomes negligible - if(TossEnergyLoss > (m_DeltaRayCut*1000.)){ + // check if it is delta-ray -- delta-ray is already taken care of by G4 and treated as an independent hit. + // Unfortunately, we won't deal with delta-ray using Bichsel's model + // as long as m_nCols is not very big, the probability of having >= 2 such a big energy loss in a row is very small. + // In case there is a delta-ray, it would be so dominant that other energy deposition becomes negligible + if (TossEnergyLoss > (m_DeltaRayCut * 1000.)) { TossEnergyLoss = 0.; } bool fLastStep = false; - if( ((TotalEnergyLoss + TossEnergyLoss)/1.E+6) > InciEnergy ){ - ATH_MSG_WARNING("Energy loss is larger than incident energy in EnergyDepositionTool::BichselSim! This is usually delta-ray."); - TossEnergyLoss = InciEnergy*1.E+6 - TotalEnergyLoss; + if (((TotalEnergyLoss + TossEnergyLoss) / 1.E+6) > InciEnergy) { + ATH_MSG_WARNING( + "Energy loss is larger than incident energy in EnergyDepositionTool::BichselSim! This is usually delta-ray."); + TossEnergyLoss = InciEnergy * 1.E+6 - TotalEnergyLoss; fLastStep = true; } @@ -393,16 +420,15 @@ std::vector<std::pair<double,double> > EnergyDepositionTool::BichselSim(double B TotalEnergyLoss += TossEnergyLoss; // record this hit - std::pair<double,double> oneHit; - if(m_nCols == 1) oneHit.first = accumLength; - else oneHit.first = (accumLength - 1.0*HitPosition/2); // as long as m_nCols is small enough (making sure lambda*m_nCols is withint resolution of a pixel), then taking middle point might still be reasonable + std::pair<double, double> oneHit; + if (m_nCols == 1) oneHit.first = accumLength; + else oneHit.first = (accumLength - 1.0 * HitPosition / 2);// as long as m_nCols is small enough (making sure lambda*m_nCols is within resolution of a pixel), then taking middle point might still be reasonable oneHit.second = TossEnergyLoss; rawHitRecord.push_back(oneHit); count++; - if(fLastStep) - break; + if (fLastStep) break; } ATH_MSG_DEBUG("Finish EnergyDepositionTool::BichselSim"); @@ -413,43 +439,46 @@ std::vector<std::pair<double,double> > EnergyDepositionTool::BichselSim(double B //======================================= // C L U S T E R H I T S //======================================= -std::vector<std::pair<double,double> > EnergyDepositionTool::ClusterHits(std::vector<std::pair<double,double> >& rawHitRecord, int n_pieces) const{ +std::vector<std::pair<double, double> > EnergyDepositionTool::ClusterHits(std::vector<std::pair<double, + double> >& rawHitRecord, + int n_pieces) const { ATH_MSG_DEBUG("Begin EnergyDepositionTool::ClusterHits"); - std::vector<std::pair<double,double> > trfHitRecord; + std::vector<std::pair<double, double> > trfHitRecord; - if((int)(rawHitRecord.size()) < n_pieces){ // each single collision is the most fundamental unit + if ((int) (rawHitRecord.size()) < n_pieces) { // each single collision is the most fundamental unit n_pieces = rawHitRecord.size(); } - int unitlength = int(1.0*rawHitRecord.size()/n_pieces); + int unitlength = int(1.0 * rawHitRecord.size() / n_pieces); int index_start = 0; - int index_end = unitlength-1; // [index_start, index_end] are included - while(true){ + int index_end = unitlength - 1; // [index_start, index_end] are included + while (true) { // calculate weighted center of each slice double position = 0.; double energyloss = 0.; - for(int index = index_start; index <= index_end; index++){ + for (int index = index_start; index <= index_end; index++) { position += (rawHitRecord[index].first * rawHitRecord[index].second); energyloss += rawHitRecord[index].second; } - position = (energyloss == 0. ? 0. : position/energyloss); + position = (energyloss == 0. ? 0. : position / energyloss); // store - std::pair<double,double> oneHit; - oneHit.first = position; oneHit.second = energyloss; + std::pair<double, double> oneHit; + oneHit.first = position; + oneHit.second = energyloss; trfHitRecord.push_back(oneHit); // procede to next slice index_start = index_end + 1; index_end = index_start + unitlength - 1; - if(index_start > (int)(rawHitRecord.size()-1)){ + if (index_start > (int) (rawHitRecord.size() - 1)) { break; } - if(index_end > (int)(rawHitRecord.size()-1)){ - index_end = rawHitRecord.size()-1; + if (index_end > (int) (rawHitRecord.size() - 1)) { + index_end = rawHitRecord.size() - 1; } } @@ -458,7 +487,6 @@ std::vector<std::pair<double,double> > EnergyDepositionTool::ClusterHits(std::ve return trfHitRecord; } - /////////// // Utils // /////////// @@ -466,13 +494,17 @@ std::vector<std::pair<double,double> > EnergyDepositionTool::ClusterHits(std::ve //======================================= // TRF PDG //======================================= -int EnergyDepositionTool::trfPDG(int pdgId) const{ - if(std::fabs(pdgId) == 2212) return 1; // proton - if(std::fabs(pdgId) == 211) return 2; // pion +int EnergyDepositionTool::trfPDG(int pdgId) const { + if (std::fabs(pdgId) == 2212) return 1; // proton + + if (std::fabs(pdgId) == 211) return 2; // pion + // alpha is skipped -- 3 - if(std::fabs(pdgId) == 11) return 4; // electron - if(std::fabs(pdgId) == 321) return 5; // kaon - if(std::fabs(pdgId) == 13) return 6; // muon + if (std::fabs(pdgId) == 11) return 4; // electron + + if (std::fabs(pdgId) == 321) return 5; // kaon + + if (std::fabs(pdgId) == 13) return 6; // muon return -1; // unsupported particle } @@ -481,51 +513,52 @@ int EnergyDepositionTool::trfPDG(int pdgId) const{ //======================================= // C L U S T E R H I T S //======================================= -std::pair<int,int> EnergyDepositionTool::FastSearch(std::vector<double> vec, double item) const{ - std::pair<int,int> output; +std::pair<int, int> EnergyDepositionTool::FastSearch(std::vector<double> vec, double item) const { + std::pair<int, int> output; int index_low = 0; - int index_up = vec.size()-1; + int index_up = vec.size() - 1; - if((item < vec[index_low]) || (item > vec[index_up])){ - output.first = -1; output.second = -1; + if ((item < vec[index_low]) || (item > vec[index_up])) { + output.first = -1; + output.second = -1; return output; - } - else if(item == vec[index_low]){ - output.first = index_low; output.second = index_low; + } else if (item == vec[index_low]) { + output.first = index_low; + output.second = index_low; return output; - } - else if(item == vec[index_up]){ - output.first = index_up; output.second = index_up; + } else if (item == vec[index_up]) { + output.first = index_up; + output.second = index_up; return output; } - while( (index_up - index_low) != 1 ){ - int index_middle = int(1.0*(index_up + index_low)/2.); - if(item < vec[index_middle]) - index_up = index_middle; - else if(item > vec[index_middle]) - index_low = index_middle; - else{ // accurate hit. Though this is nearly impossible ... - output.first = index_middle; output.second = index_middle; + while ((index_up - index_low) != 1) { + int index_middle = int(1.0 * (index_up + index_low) / 2.); + if (item < vec[index_middle]) index_up = index_middle; + else if (item > vec[index_middle]) index_low = index_middle; + else { // accurate hit. Though this is nearly impossible ... + output.first = index_middle; + output.second = index_middle; return output; } } - output.first = index_low; output.second = index_up; + output.first = index_low; + output.second = index_up; return output; } //======================================= -// B E T A G A M M A I N D E X +// B E T A G A M M A I N D E X //======================================= -std::pair<int,int> EnergyDepositionTool::GetBetaGammaIndices(double BetaGammaLog10, BichselData& iData) const{ - std::pair<int,int> indices_BetaGammaLog10; - if(BetaGammaLog10 > iData.Array_BetaGammaLog10.back()){ // last one is used because when beta-gamma is very large, energy deposition behavior is very similar - indices_BetaGammaLog10.first = iData.Array_BetaGammaLog10.size()-1; - indices_BetaGammaLog10.second = iData.Array_BetaGammaLog10.size()-1; - } - else{ +std::pair<int, int> EnergyDepositionTool::GetBetaGammaIndices(double BetaGammaLog10, BichselData& iData) const { + std::pair<int, int> indices_BetaGammaLog10; + if (BetaGammaLog10 > iData.Array_BetaGammaLog10.back()) { // last one is used because when beta-gamma is very large, + // energy deposition behavior is very similar + indices_BetaGammaLog10.first = iData.Array_BetaGammaLog10.size() - 1; + indices_BetaGammaLog10.second = iData.Array_BetaGammaLog10.size() - 1; + } else { indices_BetaGammaLog10 = FastSearch(iData.Array_BetaGammaLog10, BetaGammaLog10); } @@ -536,19 +569,28 @@ std::pair<int,int> EnergyDepositionTool::GetBetaGammaIndices(double BetaGammaLog // G E T C O L L I S I O N E N E R G Y //========================================== //Interpolate collision energy -double EnergyDepositionTool::GetColE(std::pair<int,int> indices_BetaGammaLog10, double IntXLog10, BichselData& iData) const{ +double EnergyDepositionTool::GetColE(std::pair<int, int> indices_BetaGammaLog10, double IntXLog10, + BichselData& iData) const { + if ((indices_BetaGammaLog10.first == -1) && (indices_BetaGammaLog10.second == -1)) return -1.; - if( (indices_BetaGammaLog10.first==-1) && (indices_BetaGammaLog10.second==-1) ) - return -1.; - // BetaGammaLog10_2 then - std::pair<int,int> indices_IntXLog10_x2 = FastSearch(iData.Array_BetaGammaLog10_IntXLog10[indices_BetaGammaLog10.second], IntXLog10); - if (indices_IntXLog10_x2.first<0) { return -1; } - if (indices_IntXLog10_x2.second<0) { return -1; } - + std::pair<int, + int> indices_IntXLog10_x2 = + FastSearch(iData.Array_BetaGammaLog10_IntXLog10[indices_BetaGammaLog10.second], IntXLog10); + if (indices_IntXLog10_x2.first < 0) { + return -1; + } + if (indices_IntXLog10_x2.second < 0) { + return -1; + } + double y21 = iData.Array_BetaGammaLog10_IntXLog10[indices_BetaGammaLog10.second][indices_IntXLog10_x2.first]; double y22 = iData.Array_BetaGammaLog10_IntXLog10[indices_BetaGammaLog10.second][indices_IntXLog10_x2.second]; - double Est_x2 = ((y22 - IntXLog10)*iData.Array_BetaGammaLog10_ColELog10[indices_BetaGammaLog10.second][indices_IntXLog10_x2.first] + (IntXLog10 - y21)*iData.Array_BetaGammaLog10_ColELog10[indices_BetaGammaLog10.second][indices_IntXLog10_x2.second])/(y22-y21); + double Est_x2 = + ((y22 - IntXLog10) * + iData.Array_BetaGammaLog10_ColELog10[indices_BetaGammaLog10.second][indices_IntXLog10_x2.first] + + (IntXLog10 - y21) * + iData.Array_BetaGammaLog10_ColELog10[indices_BetaGammaLog10.second][indices_IntXLog10_x2.second]) / (y22 - y21); double Est = Est_x2; return TMath::Power(10., Est); @@ -557,19 +599,22 @@ double EnergyDepositionTool::GetColE(std::pair<int,int> indices_BetaGammaLog10, //=========================================== // Overloaded C O L L I S I O N E N E R G Y //=========================================== -double EnergyDepositionTool::GetColE(double BetaGammaLog10, double IntXLog10, BichselData& iData) const{ - std::pair<int,int> indices_BetaGammaLog10 = GetBetaGammaIndices(BetaGammaLog10, iData); +double EnergyDepositionTool::GetColE(double BetaGammaLog10, double IntXLog10, BichselData& iData) const { + std::pair<int, int> indices_BetaGammaLog10 = GetBetaGammaIndices(BetaGammaLog10, iData); return GetColE(indices_BetaGammaLog10, IntXLog10, iData); } - //========================================== // G E T U P P E R B O U N D BETA GAMMA //========================================== -double EnergyDepositionTool::GetUpperBound(std::pair<int,int> indices_BetaGammaLog10, double BetaGammaLog10, BichselData& iData) const{ - - if (indices_BetaGammaLog10.first<0) { return -1; } - if (indices_BetaGammaLog10.second<0) { return -1; } +double EnergyDepositionTool::GetUpperBound(std::pair<int, int> indices_BetaGammaLog10, double BetaGammaLog10, + BichselData& iData) const { + if (indices_BetaGammaLog10.first < 0) { + return -1; + } + if (indices_BetaGammaLog10.second < 0) { + return -1; + } double BetaGammaLog10_1 = iData.Array_BetaGammaLog10[indices_BetaGammaLog10.first]; double BetaGammaLog10_2 = iData.Array_BetaGammaLog10[indices_BetaGammaLog10.second]; @@ -578,7 +623,8 @@ double EnergyDepositionTool::GetUpperBound(std::pair<int,int> indices_BetaGammaL double Est_2 = iData.Array_BetaGammaLog10_UpperBoundIntXLog10[indices_BetaGammaLog10.second]; // final estimation - double Est = ((BetaGammaLog10_2 - BetaGammaLog10)*Est_1 + (BetaGammaLog10 - BetaGammaLog10_1)*Est_2)/(BetaGammaLog10_2 - BetaGammaLog10_1); + double Est = ((BetaGammaLog10_2 - BetaGammaLog10) * Est_1 + (BetaGammaLog10 - BetaGammaLog10_1) * Est_2) / + (BetaGammaLog10_2 - BetaGammaLog10_1); return TMath::Power(10., Est); } @@ -586,18 +632,19 @@ double EnergyDepositionTool::GetUpperBound(std::pair<int,int> indices_BetaGammaL //========================================== // overloaded G E T U P P E R B O U N D //========================================== -double EnergyDepositionTool::GetUpperBound(double BetaGammaLog10, BichselData& iData) const{ - std::pair<int,int> indices_BetaGammaLog10 = GetBetaGammaIndices(BetaGammaLog10, iData); +double EnergyDepositionTool::GetUpperBound(double BetaGammaLog10, BichselData& iData) const { + std::pair<int, int> indices_BetaGammaLog10 = GetBetaGammaIndices(BetaGammaLog10, iData); return GetUpperBound(indices_BetaGammaLog10, BetaGammaLog10, iData); } //========================================== // S E T F A I L U R E //========================================== -void EnergyDepositionTool::SetFailureFlag(std::vector<std::pair<double,double> >& rawHitRecord) const{ +void EnergyDepositionTool::SetFailureFlag(std::vector<std::pair<double, double> >& rawHitRecord) const { rawHitRecord.clear(); std::pair<double, double> specialFlag; - specialFlag.first = -1.; specialFlag.second = -1.; + specialFlag.first = -1.; + specialFlag.second = -1.; rawHitRecord.push_back(specialFlag); return; diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.h index 05c5f05704c4..8a73afbf0f4c 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/EnergyDepositionTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/EnergyDepositionTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -27,7 +27,7 @@ #include "StoreGate/ReadCondHandleKey.h" //============================= -// C U S T O M S T R U C T +// C U S T O M S T R U C T //============================= struct BichselData { std::vector<double> Array_BetaGammaLog10; @@ -36,78 +36,106 @@ struct BichselData { std::vector<double> Array_BetaGammaLog10_UpperBoundIntXLog10; // upper bound of log10(IntX) }; -//==================== +//==================== // C L A S S D E F //==================== -class EnergyDepositionTool : public AthAlgTool { - public: - EnergyDepositionTool( const std::string& type, const std::string& name,const IInterface* parent); - - static const InterfaceID& interfaceID() ; - virtual StatusCode initialize(); - virtual StatusCode finalize(); - - virtual ~EnergyDepositionTool(); - StatusCode initTools(); - - std::vector<std::pair<double,double> > BichselSim(double BetaGamma, int ParticleType, double TotalLength, double InciEnergy, CLHEP::HepRandomEngine *rndmEngine) const; // output hit record in the format (hit position, energy loss) - - std::vector<std::pair<double,double> > ClusterHits(std::vector<std::pair<double,double> >& rawHitRecord, int n_pieces) const; // cluster hits into n steps (there could be thousands of hit) - int trfPDG(int pdgId) const; // convert pdgId to ParticleType. If it is unsupported particle, -1 is returned. - - virtual StatusCode depositEnergy(const TimedHitPtr<SiHit> &phit, const InDetDD::SiDetectorElement &Module, - std::vector<std::pair<double,double> > &trfHitRecord, std::vector<double> &initialConditions, CLHEP::HepRandomEngine *rndmEngine); - - // Variables - private: - EnergyDepositionTool(); - - const PixelID* m_pixelID{nullptr}; - - std::vector<BichselData> m_BichselData; // vector to store Bichsel Data. Each entry is for one particle type - - Gaudi::Property<int> m_numberOfSteps - {this, "numberOfSteps", 50, "Geant4:number of steps for PixelPlanar"}; - - Gaudi::Property<int> m_numberOfCharges - {this, "numberOfCharges", 10, "Geant4:number of charges for PixelPlanar"}; - - Gaudi::Property<bool> m_disableDistortions - {this, "DisableDistortions", false, "Disable simulation of module distortions"}; - - Gaudi::Property<bool> m_doBichsel - {this, "doBichsel", true, "re-do charge deposition following Bichsel model"}; - - Gaudi::Property<double> m_doBichselBetaGammaCut - {this, "doBichselBetaGammaCut", 0.1, "minimum beta-gamma for particle to be re-simulated through Bichsel Model"}; - - Gaudi::Property<bool> m_doDeltaRay - {this, "doDeltaRay", false, "whether we simulate delta-ray using Bichsel model"}; - - Gaudi::Property<double> m_DeltaRayCut - {this, "DeltaRayCut", 117.0, "Cut of delta ray [keV]"}; - - Gaudi::Property<bool> m_doPU - {this, "doPU", true, "Whether we apply Bichsel model on PU"}; - - Gaudi::Property<int> m_nCols - {this, "nCols", 1, "Number of collision for each sampling"}; - - Gaudi::Property<int> m_LoopLimit - {this, "LoopLimit", 100000, "Limit assuming 1 collision per sampling"}; - - SG::ReadCondHandleKey<PixelDistortionData> m_distortionKey - {this, "PixelDistortionData", "PixelDistortionData", "Output readout distortion data"}; - - private: - void simulateBow(const InDetDD::SiDetectorElement * element,double& xi, double& yi, const double zi, double& xf, double& yf, const double zf) const; - std::pair<int,int> FastSearch(std::vector<double> vec, double item) const; // A quick implementation of binary search in 2D table - std::pair<int,int> GetBetaGammaIndices(double BetaGammaLog10, BichselData& iData) const; // get beta-gamma index. This is so commonly used by other functions that a caching would be beneficial - double GetColE(double BetaGammaLog10, double IntXLog10, BichselData& iData) const; // return ColE NOT ColELog10 ! unit is eV - double GetColE(std::pair<int,int> indices_BetaGammaLog10, double IntXLog10, BichselData& iData) const; // return ColE NOT ColELog10 ! unit is eV - double GetUpperBound(double BetaGammaLog10, BichselData& iData) const; // return IntX upper bound - double GetUpperBound(std::pair<int,int> indices_BetaGammaLog10, double BetaGammaLog10, BichselData& iData) const; // return IntX upper bound - void SetFailureFlag(std::vector<std::pair<double,double> >& rawHitRecord) const; // return (-1,-1) which indicates failure in running BichselSim +class EnergyDepositionTool: public AthAlgTool { +public: + EnergyDepositionTool(const std::string& type, const std::string& name, const IInterface* parent); + + static const InterfaceID& interfaceID(); + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + virtual ~EnergyDepositionTool(); + StatusCode initTools(); + + std::vector<std::pair<double, double> > BichselSim(double BetaGamma, int ParticleType, double TotalLength, + double InciEnergy, CLHEP::HepRandomEngine* rndmEngine) const; // output hit record in the format (hit position, energy loss) + + std::vector<std::pair<double, double> > ClusterHits(std::vector<std::pair<double, double> >& rawHitRecord, + int n_pieces) const; // cluster hits into n steps (there could be thousands of hit) + int trfPDG(int pdgId) const; // convert pdgId to ParticleType. If it is unsupported particle, -1 is returned. + + virtual StatusCode depositEnergy(const TimedHitPtr<SiHit>& phit, const InDetDD::SiDetectorElement& Module, + std::vector<std::pair<double, double> >& trfHitRecord, + std::vector<double>& initialConditions, CLHEP::HepRandomEngine* rndmEngine); + + // Variables +private: + EnergyDepositionTool(); + + const PixelID* m_pixelID { + nullptr + }; + + std::vector<BichselData> m_BichselData; // vector to store Bichsel Data. Each entry is for one particle type + + Gaudi::Property<int> m_numberOfSteps + { + this, "numberOfSteps", 50, "Geant4:number of steps for PixelPlanar" + }; + + Gaudi::Property<int> m_numberOfCharges + { + this, "numberOfCharges", 10, "Geant4:number of charges for PixelPlanar" + }; + + Gaudi::Property<bool> m_disableDistortions + { + this, "DisableDistortions", false, "Disable simulation of module distortions" + }; + + Gaudi::Property<bool> m_doBichsel + { + this, "doBichsel", true, "re-do charge deposition following Bichsel model" + }; + + Gaudi::Property<double> m_doBichselBetaGammaCut + { + this, "doBichselBetaGammaCut", 0.1, "minimum beta-gamma for particle to be re-simulated through Bichsel Model" + }; + + Gaudi::Property<bool> m_doDeltaRay + { + this, "doDeltaRay", false, "whether we simulate delta-ray using Bichsel model" + }; + + Gaudi::Property<double> m_DeltaRayCut + { + this, "DeltaRayCut", 117.0, "Cut of delta ray [keV]" + }; + + Gaudi::Property<bool> m_doPU + { + this, "doPU", true, "Whether we apply Bichsel model on PU" + }; + + Gaudi::Property<int> m_nCols + { + this, "nCols", 1, "Number of collision for each sampling" + }; + + Gaudi::Property<int> m_LoopLimit + { + this, "LoopLimit", 100000, "Limit assuming 1 collision per sampling" + }; + + SG::ReadCondHandleKey<PixelDistortionData> m_distortionKey + { + this, "PixelDistortionData", "PixelDistortionData", "Output readout distortion data" + }; +private: + void simulateBow(const InDetDD::SiDetectorElement* element, double& xi, double& yi, const double zi, double& xf, + double& yf, const double zf) const; + std::pair<int, int> FastSearch(std::vector<double> vec, double item) const; // A quick implementation of binary search in 2D table + std::pair<int, int> GetBetaGammaIndices(double BetaGammaLog10, BichselData& iData) const; // get beta-gamma index. This is so commonly used by other functions that a caching would be beneficial + double GetColE(double BetaGammaLog10, double IntXLog10, BichselData& iData) const; // return ColE NOT ColELog10 + // ! unit is eV + double GetColE(std::pair<int, int> indices_BetaGammaLog10, double IntXLog10, BichselData& iData) const; // return ColE NOT ColELog10 ! unit is eV + double GetUpperBound(double BetaGammaLog10, BichselData& iData) const; // return IntX upper bound + double GetUpperBound(std::pair<int, int> indices_BetaGammaLog10, double BetaGammaLog10, BichselData& iData) const;// return IntX upper bound + void SetFailureFlag(std::vector<std::pair<double, double> >& rawHitRecord) const; // return (-1,-1) which indicates failure in running BichselSim }; #endif //PIXELDIGITIZATION_EnergyDepositionTool_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.cxx index 7ed6809a66f5..b946d8ce208f 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.cxx @@ -1,12 +1,11 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "FEI3SimTool.h" -FEI3SimTool::FEI3SimTool( const std::string& type, const std::string& name,const IInterface* parent): - FrontEndSimTool(type,name,parent) -{ +FEI3SimTool::FEI3SimTool(const std::string& type, const std::string& name, const IInterface* parent) : + FrontEndSimTool(type, name, parent) { } FEI3SimTool::~FEI3SimTool() { } @@ -14,38 +13,44 @@ FEI3SimTool::~FEI3SimTool() { } StatusCode FEI3SimTool::initialize() { CHECK(FrontEndSimTool::initialize()); ATH_MSG_DEBUG("FEI3SimTool::initialize()"); - return StatusCode::SUCCESS; + return StatusCode::SUCCESS; } StatusCode FEI3SimTool::finalize() { ATH_MSG_DEBUG("FEI3SimTool::finalize()"); - return StatusCode::SUCCESS; + return StatusCode::SUCCESS; } -void FEI3SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine) { +void FEI3SimTool::process(SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection, + CLHEP::HepRandomEngine* rndmEngine) { + const InDetDD::PixelModuleDesign* p_design = + static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - const InDetDD::PixelModuleDesign *p_design = static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - if (p_design->getReadoutTechnology()!=InDetDD::PixelModuleDesign::FEI3) { return; } + if (p_design->getReadoutTechnology() != InDetDD::PixelModuleDesign::FEI3) { + return; + } - const PixelID* pixelId = static_cast<const PixelID *>(chargedDiodes.element()->getIdHelper()); + const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper()); const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash Identifier moduleID = pixelId->wafer_id(chargedDiodes.element()->identify()); - int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); - int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); + int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); + int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); int moduleIndex = pixelId->eta_module(chargedDiodes.element()->identify()); - if (abs(barrel_ec)!=m_BarrelEC) { return; } + if (abs(barrel_ec) != m_BarrelEC) { + return; + } SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); SG::ReadCondHandle<PixelChargeCalibCondData> calibData(m_chargeDataKey); // Add cross-talk - CrossTalk(moduleData->getCrossTalk(barrel_ec,layerIndex),chargedDiodes); + CrossTalk(moduleData->getCrossTalk(barrel_ec, layerIndex), chargedDiodes); if (m_doNoise) { // Add thermal noise - ThermalNoise(moduleData->getThermalNoise(barrel_ec,layerIndex),chargedDiodes, rndmEngine); + ThermalNoise(moduleData->getThermalNoise(barrel_ec, layerIndex), chargedDiodes, rndmEngine); // Add random noise RandomNoise(chargedDiodes, rndmEngine); @@ -54,19 +59,21 @@ void FEI3SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle // Add random diabled pixels RandomDisable(chargedDiodes, rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs? - for (SiChargedDiodeIterator i_chargedDiode=chargedDiodes.begin(); i_chargedDiode!=chargedDiodes.end(); ++i_chargedDiode) { + for (SiChargedDiodeIterator i_chargedDiode = chargedDiodes.begin(); i_chargedDiode != chargedDiodes.end(); + ++i_chargedDiode) { // Merge ganged pixel - InDetDD::SiCellId cellID = chargedDiodes.element()->cellIdFromIdentifier(chargedDiodes.getId((*i_chargedDiode).first)); + InDetDD::SiCellId cellID = chargedDiodes.element()->cellIdFromIdentifier(chargedDiodes.getId( + (*i_chargedDiode).first)); InDetDD::SiCellId gangedCell = chargedDiodes.element()->gangedCell(cellID); - Identifier gangedID = chargedDiodes.element()->identifierFromCellId(gangedCell); + Identifier gangedID = chargedDiodes.element()->identifierFromCellId(gangedCell); if (gangedCell.isValid()) { - SiChargedDiode *gangedChargeDiode = chargedDiodes.find(gangedID); + SiChargedDiode* gangedChargeDiode = chargedDiodes.find(gangedID); int phiGanged = pixelId->phi_index(gangedID); - int phiThis = pixelId->phi_index(chargedDiodes.getId((*i_chargedDiode).first)); + int phiThis = pixelId->phi_index(chargedDiodes.getId((*i_chargedDiode).first)); if (gangedChargeDiode) { // merge charges - bool maskGanged = ((phiGanged>159) && (phiGanged<168)); - bool maskThis = ((phiThis>159) && (phiThis<168)); + bool maskGanged = ((phiGanged > 159) && (phiGanged < 168)); + bool maskThis = ((phiThis > 159) && (phiThis < 168)); // mask the one ganged pixel that does not correspond to the readout electronics. // not really sure this is needed if (maskGanged && maskThis) { @@ -74,94 +81,115 @@ void FEI3SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle } if (maskGanged) { (*i_chargedDiode).second.add(gangedChargeDiode->totalCharge()); // merged org pixel - SiHelper::maskOut(*gangedChargeDiode,true); - } - else { + SiHelper::maskOut(*gangedChargeDiode, true); + } else { gangedChargeDiode->add((*i_chargedDiode).second.totalCharge()); // merged org pixel - SiHelper::maskOut((*i_chargedDiode).second,true); + SiHelper::maskOut((*i_chargedDiode).second, true); } } } } - for (SiChargedDiodeOrderedIterator i_chargedDiode=chargedDiodes.orderedBegin(); - i_chargedDiode!=chargedDiodes.orderedEnd(); ++i_chargedDiode) - { + for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin(); + i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) { SiChargedDiode& diode = **i_chargedDiode; Identifier diodeID = chargedDiodes.getId(diode.diode()); double charge = diode.charge(); - int circ = m_pixelCabling->getFE(&diodeID,moduleID); + int circ = m_pixelCabling->getFE(&diodeID, moduleID); int type = m_pixelCabling->getPixelType(diodeID); // Apply analog threshold, timing simulation - double th0 = calibData->getAnalogThreshold((int)moduleHash, circ, type); - double ith0 = calibData->getInTimeThreshold((int)moduleHash, circ, type); + double th0 = calibData->getAnalogThreshold((int) moduleHash, circ, type); + double ith0 = calibData->getInTimeThreshold((int) moduleHash, circ, type); double thrand1 = CLHEP::RandGaussZiggurat::shoot(rndmEngine); double thrand2 = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double threshold = th0+calibData->getAnalogThresholdSigma((int)moduleHash,circ,type)*thrand1+calibData->getAnalogThresholdNoise((int)moduleHash, circ, type)*thrand2; // This noise check is unaffected by digitizationFlags.doInDetNoise in 21.0 - see PixelCellDiscriminator.cxx in that branch - double intimethreshold = (ith0/th0)*threshold; + double threshold = th0 + + calibData->getAnalogThresholdSigma((int) moduleHash, circ, + type) * thrand1 + calibData->getAnalogThresholdNoise( + (int) moduleHash, circ, type) * thrand2; // This noise check is unaffected by digitizationFlags.doInDetNoise in + // 21.0 - see PixelCellDiscriminator.cxx in that branch + double intimethreshold = (ith0 / th0) * threshold; - if (charge>threshold) { + if (charge > threshold) { int bunchSim = 0; if (diode.totalCharge().fromTrack()) { - if (moduleData->getFEI3TimingSimTune(barrel_ec,layerIndex)==2018) { bunchSim = relativeBunch2018(diode.totalCharge(),barrel_ec,layerIndex,moduleIndex, rndmEngine); } - else if (moduleData->getFEI3TimingSimTune(barrel_ec,layerIndex)==2015) { bunchSim = relativeBunch2015(diode.totalCharge(),barrel_ec,layerIndex,moduleIndex, rndmEngine); } - else if (moduleData->getFEI3TimingSimTune(barrel_ec,layerIndex)==2009) { bunchSim = relativeBunch2009(threshold,intimethreshold,diode.totalCharge(), rndmEngine); } - } - else { - if (moduleData->getFEI3TimingSimTune(barrel_ec,layerIndex)>0) { bunchSim = CLHEP::RandFlat::shootInt(rndmEngine,moduleData->getNumberOfBCID(barrel_ec,layerIndex)); } + if (moduleData->getFEI3TimingSimTune(barrel_ec, layerIndex) == 2018) { + bunchSim = relativeBunch2018(diode.totalCharge(), barrel_ec, layerIndex, moduleIndex, rndmEngine); + } else if (moduleData->getFEI3TimingSimTune(barrel_ec, layerIndex) == 2015) { + bunchSim = relativeBunch2015(diode.totalCharge(), barrel_ec, layerIndex, moduleIndex, rndmEngine); + } else if (moduleData->getFEI3TimingSimTune(barrel_ec, layerIndex) == 2009) { + bunchSim = relativeBunch2009(threshold, intimethreshold, diode.totalCharge(), rndmEngine); + } + } else { + if (moduleData->getFEI3TimingSimTune(barrel_ec, layerIndex) > 0) { + bunchSim = CLHEP::RandFlat::shootInt(rndmEngine, moduleData->getNumberOfBCID(barrel_ec, layerIndex)); + } } - if (bunchSim<0 || bunchSim>moduleData->getNumberOfBCID(barrel_ec,layerIndex)) { SiHelper::belowThreshold(diode,true,true); } - else { SiHelper::SetBunch(diode,bunchSim); } - } - else { - SiHelper::belowThreshold(diode,true,true); + if (bunchSim < 0 || bunchSim > moduleData->getNumberOfBCID(barrel_ec, layerIndex)) { + SiHelper::belowThreshold(diode, true, true); + } else { + SiHelper::SetBunch(diode, bunchSim); + } + } else { + SiHelper::belowThreshold(diode, true, true); } // charge to ToT conversion - double tot = calibData->getToT((int)moduleHash, circ, type, charge); - double totsig = calibData->getTotRes((int)moduleHash, circ, tot); - int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine,tot,totsig)); + double tot = calibData->getToT((int) moduleHash, circ, type, charge); + double totsig = calibData->getTotRes((int) moduleHash, circ, tot); + int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot, totsig)); - if (nToT<1) { nToT=1; } + if (nToT < 1) { + nToT = 1; + } - if (nToT<=moduleData->getToTThreshold(barrel_ec,layerIndex)) { SiHelper::belowThreshold(diode,true,true); } + if (nToT <= moduleData->getToTThreshold(barrel_ec, layerIndex)) { + SiHelper::belowThreshold(diode, true, true); + } - if (nToT>=moduleData->getFEI3Latency(barrel_ec,layerIndex)) { SiHelper::belowThreshold(diode,true,true); } + if (nToT >= moduleData->getFEI3Latency(barrel_ec, layerIndex)) { + SiHelper::belowThreshold(diode, true, true); + } // Filter events - if (SiHelper::isMaskOut(diode)) { continue; } - if (SiHelper::isDisabled(diode)) { continue; } + if (SiHelper::isMaskOut(diode)) { + continue; + } + if (SiHelper::isDisabled(diode)) { + continue; + } - if (!m_pixelConditionsTool->isActive(moduleHash,diodeID)) { - SiHelper::disabled(diode,true,true); + if (!m_pixelConditionsTool->isActive(moduleHash, diodeID)) { + SiHelper::disabled(diode, true, true); continue; } - int flag = diode.flag(); - int bunch = (flag>>8)&0xff; + int flag = diode.flag(); + int bunch = (flag >> 8) & 0xff; - InDetDD::SiReadoutCellId cellId=diode.getReadoutCell(); + InDetDD::SiReadoutCellId cellId = diode.getReadoutCell(); const Identifier id_readout = chargedDiodes.element()->identifierFromCellId(cellId); // Front-End simulation - if (bunch>=0 && bunch<moduleData->getNumberOfBCID(barrel_ec,layerIndex)) { - Pixel1RawData *p_rdo = new Pixel1RawData(id_readout,nToT,bunch,0,bunch); + if (bunch >= 0 && bunch < moduleData->getNumberOfBCID(barrel_ec, layerIndex)) { + Pixel1RawData* p_rdo = new Pixel1RawData(id_readout, nToT, bunch, 0, bunch); rdoCollection.push_back(p_rdo); p_rdo = nullptr; } // Duplication mechanism for FEI3 small hits : - if (moduleData->getFEI3HitDuplication(barrel_ec,layerIndex)) { + if (moduleData->getFEI3HitDuplication(barrel_ec, layerIndex)) { bool smallHitChk = false; - if (nToT<=moduleData->getFEI3SmallHitToT(barrel_ec,layerIndex)) { smallHitChk=true; } + if (nToT <= moduleData->getFEI3SmallHitToT(barrel_ec, layerIndex)) { + smallHitChk = true; + } - if (smallHitChk && bunch>0 && bunch<=moduleData->getNumberOfBCID(barrel_ec,layerIndex)) { - Pixel1RawData *p_rdo = new Pixel1RawData(id_readout,nToT,bunch-1,0,bunch-1); + if (smallHitChk && bunch > 0 && bunch <= moduleData->getNumberOfBCID(barrel_ec, layerIndex)) { + Pixel1RawData* p_rdo = new Pixel1RawData(id_readout, nToT, bunch - 1, 0, bunch - 1); rdoCollection.push_back(p_rdo); p_rdo = nullptr; } @@ -170,11 +198,11 @@ void FEI3SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle return; } -int FEI3SimTool::relativeBunch2009(const double threshold, const double intimethreshold, const SiTotalCharge &totalCharge, CLHEP::HepRandomEngine *rndmEngine) const { - - int BCID=0; +int FEI3SimTool::relativeBunch2009(const double threshold, const double intimethreshold, + const SiTotalCharge& totalCharge, CLHEP::HepRandomEngine* rndmEngine) const { + int BCID = 0; double myTimeWalkEff = 0.; - double overdrive = intimethreshold - threshold ; + double overdrive = intimethreshold - threshold; SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); @@ -184,238 +212,398 @@ int FEI3SimTool::relativeBunch2009(const double threshold, const double intimeth //double myTimeWalk = curvature/(pow((totalCharge.charge()-divergence),2.5)); //my TimeWalk computation through PARAMETRIZATION from 2009 cosmic data (by I. Ibragimov and D. Miller) - double p1 = 20./log(intimethreshold/overdrive); - double p0 = p1 * log (1. - threshold/100000.); + double p1 = 20. / log(intimethreshold / overdrive); + double p0 = p1 * log(1. - threshold / 100000.); - double myTimeWalk = -p0 -p1 * log(1. - threshold/totalCharge.charge()); + double myTimeWalk = -p0 - p1 * log(1. - threshold / totalCharge.charge()); - myTimeWalkEff = myTimeWalk+myTimeWalk*0.2*CLHEP::RandGaussZiggurat::shoot(rndmEngine); + myTimeWalkEff = myTimeWalk + myTimeWalk * 0.2 * CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double randomjitter = CLHEP::RandFlat::shoot(rndmEngine,(-moduleData->getTimeJitter(0,1)/2.0),(moduleData->getTimeJitter(0,1)/2.0)); + double randomjitter = + CLHEP::RandFlat::shoot(rndmEngine, (-moduleData->getTimeJitter(0, 1) / 2.0), + (moduleData->getTimeJitter(0, 1) / 2.0)); //double G4Time = totalCharge.time(); double G4Time = getG4Time(totalCharge); - double timing = moduleData->getTimeOffset(0,1)+myTimeWalkEff+(randomjitter)+G4Time-moduleData->getComTime(); - BCID = static_cast<int>(floor(timing/moduleData->getBunchSpace())); - //ATH_MSG_DEBUG ( CTW << " , " << myTimeWalkEff << " , " << G4Time << " , " << timing << " , " << BCID ); + double timing = moduleData->getTimeOffset(0, 1) + myTimeWalkEff + (randomjitter) + G4Time - moduleData->getComTime(); + BCID = static_cast<int>(floor(timing / moduleData->getBunchSpace())); + //ATH_MSG_DEBUG ( CTW << " , " << myTimeWalkEff << " , " << G4Time << " , " << timing << " , " << BCID ); return BCID; } // This is the new parameterization based on the 2015 collision data. -int FEI3SimTool::relativeBunch2015(const SiTotalCharge &totalCharge, int barrel_ec, int layer_disk, int moduleID, CLHEP::HepRandomEngine *rndmEngine) const { - +int FEI3SimTool::relativeBunch2015(const SiTotalCharge& totalCharge, int barrel_ec, int layer_disk, int moduleID, + CLHEP::HepRandomEngine* rndmEngine) const { /** * 2016.03.29 Soshi.Tsuno@cern.ch * * The time walk effect is directly tuned with timing scan data (collision) in 2015. - * + * * See reference in the talk, * https://indico.cern.ch/event/516099/contributions/1195889/attachments/1252177/1846815/pixelOffline_timing_04.04.2016_soshi.pdf - * + * * Ideally, it could be directly parameterized as a function of given ToT. - * However, the ToT calibration was changed over 2015-2016, where newly calibrated ToT value was not available for 2016. + * However, the ToT calibration was changed over 2015-2016, where newly calibrated ToT value was not available for + *2016. * For instance, the b-layer charge tuning was changed from ToT30@MIP (2015) to ToT18@MIP (2016). * Thus the time walk effect needs to be parameterized with more universal value, that is, charge information. * But it was non-trivial because of the migration effect between the border in ToT. - * - * Here in 2015 version, we apply the threshold of the 60% total charge to get a certain ToT value, + * + * Here in 2015 version, we apply the threshold of the 60% total charge to get a certain ToT value, * which most describes the data timing structure. - * + * * 60% working point tune-2 */ SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); double prob = 0.0; - if (barrel_ec==0 && layer_disk==1) { - if (abs(moduleID)==0) { - if (totalCharge.charge()<4100.0) { prob = 0.9349; } // corresponds to ToT=4 - else if (totalCharge.charge()<4150.0) { prob = 0.2520; } // ToT=5 - else if (totalCharge.charge()<4600.0) { prob = 0.0308; } // ToT=6 - else if (totalCharge.charge()<5250.0) { prob = 0.0160; } // ToT=7 - else if (totalCharge.charge()<5850.0) { prob = 0.0104; } // ToT=8 - else if (totalCharge.charge()<6500.0) { prob = 0.0127; } // ToT=9 - } - if (abs(moduleID)==1) { - if (totalCharge.charge()<4100.0) { prob = 0.9087; } - else if (totalCharge.charge()<4150.0) { prob = 0.2845; } - else if (totalCharge.charge()<4600.0) { prob = 0.0504; } - else if (totalCharge.charge()<5250.0) { prob = 0.0198; } - else if (totalCharge.charge()<5850.0) { prob = 0.0141; } - else if (totalCharge.charge()<6500.0) { prob = 0.0122; } - } - if (abs(moduleID)==2) { - if (totalCharge.charge()<4100.0) { prob = 0.9060; } - else if (totalCharge.charge()<4150.0) { prob = 0.2885; } - else if (totalCharge.charge()<4600.0) { prob = 0.0387; } - else if (totalCharge.charge()<5250.0) { prob = 0.0126; } - else if (totalCharge.charge()<5850.0) { prob = 0.0116; } - else if (totalCharge.charge()<6500.0) { prob = 0.0052; } - } - if (abs(moduleID)==3) { - if (totalCharge.charge()<4100.0) { prob = 0.8774; } - else if (totalCharge.charge()<4150.0) { prob = 0.3066; } - else if (totalCharge.charge()<4600.0) { prob = 0.0449; } - else if (totalCharge.charge()<5250.0) { prob = 0.0188; } - else if (totalCharge.charge()<5850.0) { prob = 0.0169; } - else if (totalCharge.charge()<6500.0) { prob = 0.0096; } - } - if (abs(moduleID)==4) { - if (totalCharge.charge()<4100.0) { prob = 0.8725; } - else if (totalCharge.charge()<4150.0) { prob = 0.2962; } - else if (totalCharge.charge()<4600.0) { prob = 0.0472; } - else if (totalCharge.charge()<5250.0) { prob = 0.0188; } - else if (totalCharge.charge()<5850.0) { prob = 0.0141; } - else if (totalCharge.charge()<6500.0) { prob = 0.0130; } - } - if (abs(moduleID)==5) { - if (totalCharge.charge()<4100.0) { prob = 0.8731; } - else if (totalCharge.charge()<4150.0) { prob = 0.3443; } - else if (totalCharge.charge()<4600.0) { prob = 0.0686; } - else if (totalCharge.charge()<5250.0) { prob = 0.0243; } - else if (totalCharge.charge()<5850.0) { prob = 0.0139; } - else if (totalCharge.charge()<6500.0) { prob = 0.0089; } - } - if (abs(moduleID)==6) { - if (totalCharge.charge()<4100.0) { prob = 0.8545; } - else if (totalCharge.charge()<4150.0) { prob = 0.2946; } - else if (totalCharge.charge()<4600.0) { prob = 0.0524; } - else if (totalCharge.charge()<5250.0) { prob = 0.0218; } - else if (totalCharge.charge()<5850.0) { prob = 0.0218; } - else if (totalCharge.charge()<6500.0) { prob = 0.0191; } + if (barrel_ec == 0 && layer_disk == 1) { + if (abs(moduleID) == 0) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9349; + } // corresponds to ToT=4 + else if (totalCharge.charge() < 4150.0) { + prob = 0.2520; + } // ToT=5 + else if (totalCharge.charge() < 4600.0) { + prob = 0.0308; + } // ToT=6 + else if (totalCharge.charge() < 5250.0) { + prob = 0.0160; + } // ToT=7 + else if (totalCharge.charge() < 5850.0) { + prob = 0.0104; + } // ToT=8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0127; + } // ToT=9 + } + if (abs(moduleID) == 1) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9087; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.2845; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.0504; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0198; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0141; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0122; + } + } + if (abs(moduleID) == 2) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9060; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.2885; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.0387; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0126; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0116; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0052; + } + } + if (abs(moduleID) == 3) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8774; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.3066; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.0449; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0188; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0169; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0096; + } + } + if (abs(moduleID) == 4) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8725; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.2962; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.0472; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0188; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0141; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0130; + } + } + if (abs(moduleID) == 5) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8731; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.3443; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.0686; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0243; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0139; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0089; + } + } + if (abs(moduleID) == 6) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8545; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.2946; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.0524; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0218; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0218; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0191; + } } } - if (barrel_ec==0 && layer_disk==2) { - if (abs(moduleID)==0) { - if (totalCharge.charge()<4100.0) { prob = 0.9479; } - else if (totalCharge.charge()<4150.0) { prob = 0.6051; } - else if (totalCharge.charge()<4600.0) { prob = 0.2031; } - else if (totalCharge.charge()<5250.0) { prob = 0.0735; } - else if (totalCharge.charge()<5850.0) { prob = 0.0462; } - else if (totalCharge.charge()<6500.0) { prob = 0.0272; } - } - if (abs(moduleID)==1) { - if (totalCharge.charge()<4100.0) { prob = 0.9736; } - else if (totalCharge.charge()<4150.0) { prob = 0.6344; } - else if (totalCharge.charge()<4600.0) { prob = 0.2439; } - else if (totalCharge.charge()<5250.0) { prob = 0.1000; } - else if (totalCharge.charge()<5850.0) { prob = 0.0435; } - else if (totalCharge.charge()<6500.0) { prob = 0.0335; } - } - if (abs(moduleID)==2) { - if (totalCharge.charge()<4100.0) { prob = 0.9461; } - else if (totalCharge.charge()<4150.0) { prob = 0.6180; } - else if (totalCharge.charge()<4600.0) { prob = 0.1755; } - else if (totalCharge.charge()<5250.0) { prob = 0.0647; } - else if (totalCharge.charge()<5850.0) { prob = 0.0476; } - else if (totalCharge.charge()<6500.0) { prob = 0.0470; } - } - if (abs(moduleID)==3) { - if (totalCharge.charge()<4100.0) { prob = 0.9542; } - else if (totalCharge.charge()<4150.0) { prob = 0.5839; } - else if (totalCharge.charge()<4600.0) { prob = 0.1899; } - else if (totalCharge.charge()<5250.0) { prob = 0.0604; } - else if (totalCharge.charge()<5850.0) { prob = 0.0576; } - else if (totalCharge.charge()<6500.0) { prob = 0.0285; } - } - if (abs(moduleID)==4) { - if (totalCharge.charge()<4100.0) { prob = 0.9233; } - else if (totalCharge.charge()<4150.0) { prob = 0.5712; } - else if (totalCharge.charge()<4600.0) { prob = 0.1633; } - else if (totalCharge.charge()<5250.0) { prob = 0.0796; } - else if (totalCharge.charge()<5850.0) { prob = 0.0612; } - else if (totalCharge.charge()<6500.0) { prob = 0.0384; } - } - if (abs(moduleID)==5) { - if (totalCharge.charge()<4100.0) { prob = 0.8994; } - else if (totalCharge.charge()<4150.0) { prob = 0.5176; } - else if (totalCharge.charge()<4600.0) { prob = 0.1626; } - else if (totalCharge.charge()<5250.0) { prob = 0.0698; } - else if (totalCharge.charge()<5850.0) { prob = 0.0416; } - else if (totalCharge.charge()<6500.0) { prob = 0.0382; } - } - if (abs(moduleID)==6) { - if (totalCharge.charge()<4100.0) { prob = 0.8919; } - else if (totalCharge.charge()<4150.0) { prob = 0.5313; } - else if (totalCharge.charge()<4600.0) { prob = 0.1585; } - else if (totalCharge.charge()<5250.0) { prob = 0.0520; } - else if (totalCharge.charge()<5850.0) { prob = 0.0318; } - else if (totalCharge.charge()<6500.0) { prob = 0.0254; } + if (barrel_ec == 0 && layer_disk == 2) { + if (abs(moduleID) == 0) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9479; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6051; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.2031; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0735; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0462; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0272; + } + } + if (abs(moduleID) == 1) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9736; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6344; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.2439; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1000; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0435; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0335; + } + } + if (abs(moduleID) == 2) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9461; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6180; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.1755; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0647; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0476; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0470; + } + } + if (abs(moduleID) == 3) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9542; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.5839; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.1899; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0604; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0576; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0285; + } + } + if (abs(moduleID) == 4) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9233; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.5712; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.1633; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0796; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0612; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0384; + } + } + if (abs(moduleID) == 5) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8994; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.5176; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.1626; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0698; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0416; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0382; + } + } + if (abs(moduleID) == 6) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8919; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.5313; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.1585; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.0520; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0318; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0254; + } } } - if (barrel_ec==0 && layer_disk==3) { - if (abs(moduleID)==0) { - if (totalCharge.charge()<4100.0) { prob = 0.9182; } - else if (totalCharge.charge()<4150.0) { prob = 0.6744; } - else if (totalCharge.charge()<4600.0) { prob = 0.3174; } - else if (totalCharge.charge()<5250.0) { prob = 0.1460; } - else if (totalCharge.charge()<5850.0) { prob = 0.1001; } - else if (totalCharge.charge()<6500.0) { prob = 0.0587; } - } - if (abs(moduleID)==1) { - if (totalCharge.charge()<4100.0) { prob = 0.9255; } - else if (totalCharge.charge()<4150.0) { prob = 0.6995; } - else if (totalCharge.charge()<4600.0) { prob = 0.3046; } - else if (totalCharge.charge()<5250.0) { prob = 0.1449; } - else if (totalCharge.charge()<5850.0) { prob = 0.0954; } - else if (totalCharge.charge()<6500.0) { prob = 0.0608; } - } - if (abs(moduleID)==2) { - if (totalCharge.charge()<4100.0) { prob = 0.9419; } - else if (totalCharge.charge()<4150.0) { prob = 0.7380; } - else if (totalCharge.charge()<4600.0) { prob = 0.3346; } - else if (totalCharge.charge()<5250.0) { prob = 0.1615; } - else if (totalCharge.charge()<5850.0) { prob = 0.0726; } - else if (totalCharge.charge()<6500.0) { prob = 0.0564; } - } - if (abs(moduleID)==3) { - if (totalCharge.charge()<4100.0) { prob = 0.9319; } - else if (totalCharge.charge()<4150.0) { prob = 0.6747; } - else if (totalCharge.charge()<4600.0) { prob = 0.2640; } - else if (totalCharge.charge()<5250.0) { prob = 0.1018; } - else if (totalCharge.charge()<5850.0) { prob = 0.0588; } - else if (totalCharge.charge()<6500.0) { prob = 0.0502; } - } - if (abs(moduleID)==4) { - if (totalCharge.charge()<4100.0) { prob = 0.9276; } - else if (totalCharge.charge()<4150.0) { prob = 0.6959; } - else if (totalCharge.charge()<4600.0) { prob = 0.2859; } - else if (totalCharge.charge()<5250.0) { prob = 0.1214; } - else if (totalCharge.charge()<5850.0) { prob = 0.0776; } - else if (totalCharge.charge()<6500.0) { prob = 0.0387; } - } - if (abs(moduleID)==5) { - if (totalCharge.charge()<4100.0) { prob = 0.8845; } - else if (totalCharge.charge()<4150.0) { prob = 0.6270; } - else if (totalCharge.charge()<4600.0) { prob = 0.2798; } - else if (totalCharge.charge()<5250.0) { prob = 0.1209; } - else if (totalCharge.charge()<5850.0) { prob = 0.0706; } - else if (totalCharge.charge()<6500.0) { prob = 0.0703; } - } - if (abs(moduleID)==6) { - if (totalCharge.charge()<4100.0) { prob = 0.8726; } - else if (totalCharge.charge()<4150.0) { prob = 0.6358; } - else if (totalCharge.charge()<4600.0) { prob = 0.2907; } - else if (totalCharge.charge()<5250.0) { prob = 0.1051; } - else if (totalCharge.charge()<5850.0) { prob = 0.0646; } - else if (totalCharge.charge()<6500.0) { prob = 0.0685; } + if (barrel_ec == 0 && layer_disk == 3) { + if (abs(moduleID) == 0) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9182; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6744; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.3174; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1460; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.1001; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0587; + } + } + if (abs(moduleID) == 1) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9255; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6995; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.3046; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1449; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0954; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0608; + } + } + if (abs(moduleID) == 2) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9419; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.7380; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.3346; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1615; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0726; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0564; + } + } + if (abs(moduleID) == 3) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9319; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6747; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.2640; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1018; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0588; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0502; + } + } + if (abs(moduleID) == 4) { + if (totalCharge.charge() < 4100.0) { + prob = 0.9276; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6959; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.2859; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1214; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0776; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0387; + } + } + if (abs(moduleID) == 5) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8845; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6270; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.2798; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1209; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0706; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0703; + } + } + if (abs(moduleID) == 6) { + if (totalCharge.charge() < 4100.0) { + prob = 0.8726; + } else if (totalCharge.charge() < 4150.0) { + prob = 0.6358; + } else if (totalCharge.charge() < 4600.0) { + prob = 0.2907; + } else if (totalCharge.charge() < 5250.0) { + prob = 0.1051; + } else if (totalCharge.charge() < 5850.0) { + prob = 0.0646; + } else if (totalCharge.charge() < 6500.0) { + prob = 0.0685; + } } } double G4Time = getG4Time(totalCharge); - double rnd = CLHEP::RandFlat::shoot(rndmEngine,0.0,1.0); + double rnd = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0); double timeWalk = 0.0; - if (rnd<prob) { timeWalk = 25.0; } + if (rnd < prob) { + timeWalk = 25.0; + } - int BCID = static_cast<int>(floor((G4Time+moduleData->getTimeOffset(barrel_ec,layer_disk)+timeWalk)/moduleData->getBunchSpace())); + int BCID = + static_cast<int>(floor((G4Time + + moduleData->getTimeOffset(barrel_ec, + layer_disk) + timeWalk) / moduleData->getBunchSpace())); return BCID; } -int FEI3SimTool::relativeBunch2018(const SiTotalCharge &totalCharge, int barrel_ec, int layer_disk, int moduleID, CLHEP::HepRandomEngine *rndmEngine) const { - +int FEI3SimTool::relativeBunch2018(const SiTotalCharge& totalCharge, int barrel_ec, int layer_disk, int moduleID, + CLHEP::HepRandomEngine* rndmEngine) const { /** * 2020.01.20 Minori.Fujimoto@cern.ch * @@ -424,269 +612,669 @@ int FEI3SimTool::relativeBunch2018(const SiTotalCharge &totalCharge, int barrel_ */ SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); - double prob = 0.0; - if (barrel_ec==0 && layer_disk==1) { - if (abs(moduleID)==0) { - if (totalCharge.charge()<6480.0) { prob = 0.035; } //ToT=4 - else if (totalCharge.charge()<6800.0) { prob = 0.010; } //ToT=5 - else if (totalCharge.charge()<7000.0) { prob = 0.010; } //ToT=6 - else if (totalCharge.charge()<9000.0) { prob = 0.005; } //ToT=7 - else if (totalCharge.charge()<10000.0) { prob = 0.001; } //ToT=8 - else if (totalCharge.charge()<11000.0) { prob = 0.001; } //ToT=9 - else if (totalCharge.charge()<12000.0) { prob = 0.001; } //ToT=10 - else if (totalCharge.charge()<13000.0) { prob = 0.001; } //ToT=11 - else if (totalCharge.charge()<14000.0) { prob = 0.001; } //ToT=12 - } - if (abs(moduleID)==1) { - if (totalCharge.charge()<6480.0) { prob = 0.035; } //ToT=4 - else if (totalCharge.charge()<6800.0) { prob = 0.010; } //ToT=5 - else if (totalCharge.charge()<7000.0) { prob = 0.010; } //ToT=6 - else if (totalCharge.charge()<9000.0) { prob = 0.005; } //ToT=7 - else if (totalCharge.charge()<10000.0) { prob = 0.001; } //ToT=8 - else if (totalCharge.charge()<11000.0) { prob = 0.001; } //ToT=9 - else if (totalCharge.charge()<12000.0) { prob = 0.001; } //ToT=10 - else if (totalCharge.charge()<13000.0) { prob = 0.001; } //ToT=11 - else if (totalCharge.charge()<14000.0) { prob = 0.001; } //ToT=12 - } - if (abs(moduleID)==2) { - if (totalCharge.charge()<6480.0) { prob = 0.075; } //ToT=4 - else if (totalCharge.charge()<6800.0) { prob = 0.010; } //ToT=5 - else if (totalCharge.charge()<7000.0) { prob = 0.010; } //ToT=6 - else if (totalCharge.charge()<9000.0) { prob = 0.005; } //ToT=7 - else if (totalCharge.charge()<10000.0) { prob = 0.001; } //ToT=8 - else if (totalCharge.charge()<11000.0) { prob = 0.001; } //ToT=9 - else if (totalCharge.charge()<12000.0) { prob = 0.001; } //ToT=10 - else if (totalCharge.charge()<13000.0) { prob = 0.001; } //ToT=11 - else if (totalCharge.charge()<14000.0) { prob = 0.001; } //ToT=12 - } - if (abs(moduleID)==3) { - if (totalCharge.charge()<6480.0) { prob = 0.075; } //ToT=4 - else if (totalCharge.charge()<6800.0) { prob = 0.010; } //ToT=5 - else if (totalCharge.charge()<7000.0) { prob = 0.010; } //ToT=6 - else if (totalCharge.charge()<9000.0) { prob = 0.005; } //ToT=7 - else if (totalCharge.charge()<10000.0) { prob = 0.001; } //ToT=8 - else if (totalCharge.charge()<11000.0) { prob = 0.001; } //ToT=9 - else if (totalCharge.charge()<12000.0) { prob = 0.001; } //ToT=10 - else if (totalCharge.charge()<13000.0) { prob = 0.001; } //ToT=11 - else if (totalCharge.charge()<14000.0) { prob = 0.001; } //ToT=12 - } - if (abs(moduleID)==4) { - if (totalCharge.charge()<6480.0) { prob = 0.060; } //ToT=4 - else if (totalCharge.charge()<6800.0) { prob = 0.010; } //ToT=5 - else if (totalCharge.charge()<7000.0) { prob = 0.010; } //ToT=6 - else if (totalCharge.charge()<9000.0) { prob = 0.005; } //ToT=7 - else if (totalCharge.charge()<10000.0) { prob = 0.001; } //ToT=8 - else if (totalCharge.charge()<11000.0) { prob = 0.001; } //ToT=9 - else if (totalCharge.charge()<12000.0) { prob = 0.001; } //ToT=10 - else if (totalCharge.charge()<13000.0) { prob = 0.001; } //ToT=11 - else if (totalCharge.charge()<14000.0) { prob = 0.001; } //ToT=12 - } - if (abs(moduleID)==5) { - if (totalCharge.charge()<6480.0) { prob = 0.060; } //ToT=4 - else if (totalCharge.charge()<6800.0) { prob = 0.010; } //ToT=5 - else if (totalCharge.charge()<7000.0) { prob = 0.010; } //ToT=6 - else if (totalCharge.charge()<9000.0) { prob = 0.005; } //ToT=7 - else if (totalCharge.charge()<10000.0) { prob = 0.001; } //ToT=8 - else if (totalCharge.charge()<11000.0) { prob = 0.001; } //ToT=9 - else if (totalCharge.charge()<12000.0) { prob = 0.001; } //ToT=10 - else if (totalCharge.charge()<13000.0) { prob = 0.001; } //ToT=11 - else if (totalCharge.charge()<14000.0) { prob = 0.001; } //ToT=12 - } - if (abs(moduleID)==6) { - if (totalCharge.charge()<6480.0) { prob = 0.050; } //ToT=4 - else if (totalCharge.charge()<6800.0) { prob = 0.008; } //ToT=5 - else if (totalCharge.charge()<7000.0) { prob = 0.010; } //ToT=6 - else if (totalCharge.charge()<9000.0) { prob = 0.005; } //ToT=7 - else if (totalCharge.charge()<10000.0) { prob = 0.001; } //ToT=8 - else if (totalCharge.charge()<11000.0) { prob = 0.001; } //ToT=9 - else if (totalCharge.charge()<12000.0) { prob = 0.001; } //ToT=10 - else if (totalCharge.charge()<13000.0) { prob = 0.001; } //ToT=11 - else if (totalCharge.charge()<14000.0) { prob = 0.001; } //ToT=12 - } - } - if (barrel_ec==0 && layer_disk==2) { - if (abs(moduleID)==0) { - if (totalCharge.charge()<5094.9) { prob = 0.1012; } //ToT = 6 - else if (totalCharge.charge()<5100.0) { prob = 0.0500; } //ToT = 7 - else if (totalCharge.charge()<5800.0) { prob = 0.0350; } //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.0250; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0200; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0150; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0100; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==1) { - if (totalCharge.charge()<5094.9) { prob = 0.0978; } //ToT = 6 - else if (totalCharge.charge()<5100.0) { prob = 0.0500; } //ToT = 7 - else if (totalCharge.charge()<5800.0) { prob = 0.0405; } //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.0250; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0200; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0150; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0100; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==2) { - if (totalCharge.charge()<5094.9) { prob = 0.1012; } //ToT = 6 - else if (totalCharge.charge()<5100.0) { prob = 0.0500; } //ToT = 7 - else if (totalCharge.charge()<5800.0) { prob = 0.0392; } //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.0250; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0200; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0150; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0100; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==3) { - if (totalCharge.charge()<5094.9) { prob = 0.1015; } //ToT = 6 - else if (totalCharge.charge()<5100.0) { prob = 0.0500; } //ToT = 7 - else if (totalCharge.charge()<5800.0) { prob = 0.0390; } //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.0250; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0200; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0150; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0100; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==4) { - if (totalCharge.charge()<5094.9) { prob = 0.0977; } - else if (totalCharge.charge()<5100.0) { prob = 0.0500; } - else if (totalCharge.charge()<5800.0) { prob = 0.0150; } //0.0284 - else if (totalCharge.charge()<6500.0) { prob = 0.0150; } //0.0307 - else if (totalCharge.charge()<7000.0) { prob = 0.0200; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0150; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0100; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==5) { - if (totalCharge.charge()<5094.9) { prob = 0.0966; } //ToT = 6 - else if (totalCharge.charge()<5100.0) { prob = 0.0500; } //ToT = 7 - else if (totalCharge.charge()<5800.0) { prob = 0.0369; } //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.0256; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0200; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0150; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0100; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==6) { - if (totalCharge.charge()<5094.9) { prob = 0.1053; } //ToT = 6 - else if (totalCharge.charge()<5100.0) { prob = 0.0500; } //ToT = 7 - else if (totalCharge.charge()<5800.0) { prob = 0.0379; } //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.0252; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0200; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0150; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0100; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - } - if (barrel_ec==0 && layer_disk==3) { - if (abs(moduleID)==0) { - if (totalCharge.charge()<5055.0) { prob = 0.1451; } //ToT = 6 - else if (totalCharge.charge()<5070.0) { prob = 0.0915; } //ToT = 7 - else if (totalCharge.charge()<5700.0) { prob = 0.0681; } //ToT = 8 - else if (totalCharge.charge()<6550.0) { prob = 0.0518; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0300; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0200; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0200; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==1) { - if (totalCharge.charge()<5055.0) { prob = 0.1418; } //ToT = 6 - else if (totalCharge.charge()<5070.0) { prob = 0.0800; } //ToT = 7 - else if (totalCharge.charge()<5700.0) { prob = 0.0600; } //ToT = 8 - else if (totalCharge.charge()<6550.0) { prob = 0.0497; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0300; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0200; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0200; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==2) { - if (totalCharge.charge()<5055.0) { prob = 0.1481; } //ToT = 6 - else if (totalCharge.charge()<5070.0) { prob = 0.0891; } //ToT = 7 - else if (totalCharge.charge()<5700.0) { prob = 0.0627; } //ToT = 8 - else if (totalCharge.charge()<6550.0) { prob = 0.0488; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0300; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0200; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0200; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==3) { - if (totalCharge.charge()<5055.0) { prob = 0.1590; } //ToT = 6 - else if (totalCharge.charge()<5070.0) { prob = 0.0930; } //ToT = 7 - else if (totalCharge.charge()<5700.0) { prob = 0.0635; } //ToT = 8 - else if (totalCharge.charge()<6550.0) { prob = 0.0485; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0300; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0200; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0200; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==4) { - if (totalCharge.charge()<5055.0) { prob = 0.1590; } //ToT = 6 - else if (totalCharge.charge()<5070.0) { prob = 0.1214; } //ToT = 7 - else if (totalCharge.charge()<5700.0) { prob = 0.0776; } //ToT = 8 - else if (totalCharge.charge()<6550.0) { prob = 0.0387; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0300; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0200; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0200; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==5) { - if (totalCharge.charge()<5055.0) { prob = 0.1518; } //ToT = 6 - else if (totalCharge.charge()<5070.0) { prob = 0.0874; } //ToT = 7 - else if (totalCharge.charge()<5700.0) { prob = 0.0603; } //ToT = 8 - else if (totalCharge.charge()<6550.0) { prob = 0.0460; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0300; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0200; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0200; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 - } - if (abs(moduleID)==6) { - if (totalCharge.charge()<5055.0) { prob = 0.1461; } //ToT = 6 - else if (totalCharge.charge()<5070.0) { prob = 0.0825; } //ToT = 7 - else if (totalCharge.charge()<5700.0) { prob = 0.0571; } //ToT = 8 - else if (totalCharge.charge()<6550.0) { prob = 0.0441; } //ToT = 9 - else if (totalCharge.charge()<7000.0) { prob = 0.0300; } //ToT = 10 - else if (totalCharge.charge()<7500.0) { prob = 0.0200; } //ToT = 11 - else if (totalCharge.charge()<8200.0) { prob = 0.0200; } //ToT = 12 - else if (totalCharge.charge()<9500.0) { prob = 0.0100; } //ToT = 13 + double prob = 0.0; + if (barrel_ec == 0 && layer_disk == 1) { + if (abs(moduleID) == 0) { + if (totalCharge.charge() < 6480.0) { + prob = 0.035; + } //ToT=4 + else if (totalCharge.charge() < 6800.0) { + prob = 0.010; + } //ToT=5 + else if (totalCharge.charge() < 7000.0) { + prob = 0.010; + } //ToT=6 + else if (totalCharge.charge() < 9000.0) { + prob = 0.005; + } //ToT=7 + else if (totalCharge.charge() < 10000.0) { + prob = 0.001; + } //ToT=8 + else if (totalCharge.charge() < 11000.0) { + prob = 0.001; + } //ToT=9 + else if (totalCharge.charge() < 12000.0) { + prob = 0.001; + } //ToT=10 + else if (totalCharge.charge() < 13000.0) { + prob = 0.001; + } //ToT=11 + else if (totalCharge.charge() < 14000.0) { + prob = 0.001; + } //ToT=12 + } + if (abs(moduleID) == 1) { + if (totalCharge.charge() < 6480.0) { + prob = 0.035; + } //ToT=4 + else if (totalCharge.charge() < 6800.0) { + prob = 0.010; + } //ToT=5 + else if (totalCharge.charge() < 7000.0) { + prob = 0.010; + } //ToT=6 + else if (totalCharge.charge() < 9000.0) { + prob = 0.005; + } //ToT=7 + else if (totalCharge.charge() < 10000.0) { + prob = 0.001; + } //ToT=8 + else if (totalCharge.charge() < 11000.0) { + prob = 0.001; + } //ToT=9 + else if (totalCharge.charge() < 12000.0) { + prob = 0.001; + } //ToT=10 + else if (totalCharge.charge() < 13000.0) { + prob = 0.001; + } //ToT=11 + else if (totalCharge.charge() < 14000.0) { + prob = 0.001; + } //ToT=12 + } + if (abs(moduleID) == 2) { + if (totalCharge.charge() < 6480.0) { + prob = 0.075; + } //ToT=4 + else if (totalCharge.charge() < 6800.0) { + prob = 0.010; + } //ToT=5 + else if (totalCharge.charge() < 7000.0) { + prob = 0.010; + } //ToT=6 + else if (totalCharge.charge() < 9000.0) { + prob = 0.005; + } //ToT=7 + else if (totalCharge.charge() < 10000.0) { + prob = 0.001; + } //ToT=8 + else if (totalCharge.charge() < 11000.0) { + prob = 0.001; + } //ToT=9 + else if (totalCharge.charge() < 12000.0) { + prob = 0.001; + } //ToT=10 + else if (totalCharge.charge() < 13000.0) { + prob = 0.001; + } //ToT=11 + else if (totalCharge.charge() < 14000.0) { + prob = 0.001; + } //ToT=12 + } + if (abs(moduleID) == 3) { + if (totalCharge.charge() < 6480.0) { + prob = 0.075; + } //ToT=4 + else if (totalCharge.charge() < 6800.0) { + prob = 0.010; + } //ToT=5 + else if (totalCharge.charge() < 7000.0) { + prob = 0.010; + } //ToT=6 + else if (totalCharge.charge() < 9000.0) { + prob = 0.005; + } //ToT=7 + else if (totalCharge.charge() < 10000.0) { + prob = 0.001; + } //ToT=8 + else if (totalCharge.charge() < 11000.0) { + prob = 0.001; + } //ToT=9 + else if (totalCharge.charge() < 12000.0) { + prob = 0.001; + } //ToT=10 + else if (totalCharge.charge() < 13000.0) { + prob = 0.001; + } //ToT=11 + else if (totalCharge.charge() < 14000.0) { + prob = 0.001; + } //ToT=12 + } + if (abs(moduleID) == 4) { + if (totalCharge.charge() < 6480.0) { + prob = 0.060; + } //ToT=4 + else if (totalCharge.charge() < 6800.0) { + prob = 0.010; + } //ToT=5 + else if (totalCharge.charge() < 7000.0) { + prob = 0.010; + } //ToT=6 + else if (totalCharge.charge() < 9000.0) { + prob = 0.005; + } //ToT=7 + else if (totalCharge.charge() < 10000.0) { + prob = 0.001; + } //ToT=8 + else if (totalCharge.charge() < 11000.0) { + prob = 0.001; + } //ToT=9 + else if (totalCharge.charge() < 12000.0) { + prob = 0.001; + } //ToT=10 + else if (totalCharge.charge() < 13000.0) { + prob = 0.001; + } //ToT=11 + else if (totalCharge.charge() < 14000.0) { + prob = 0.001; + } //ToT=12 + } + if (abs(moduleID) == 5) { + if (totalCharge.charge() < 6480.0) { + prob = 0.060; + } //ToT=4 + else if (totalCharge.charge() < 6800.0) { + prob = 0.010; + } //ToT=5 + else if (totalCharge.charge() < 7000.0) { + prob = 0.010; + } //ToT=6 + else if (totalCharge.charge() < 9000.0) { + prob = 0.005; + } //ToT=7 + else if (totalCharge.charge() < 10000.0) { + prob = 0.001; + } //ToT=8 + else if (totalCharge.charge() < 11000.0) { + prob = 0.001; + } //ToT=9 + else if (totalCharge.charge() < 12000.0) { + prob = 0.001; + } //ToT=10 + else if (totalCharge.charge() < 13000.0) { + prob = 0.001; + } //ToT=11 + else if (totalCharge.charge() < 14000.0) { + prob = 0.001; + } //ToT=12 + } + if (abs(moduleID) == 6) { + if (totalCharge.charge() < 6480.0) { + prob = 0.050; + } //ToT=4 + else if (totalCharge.charge() < 6800.0) { + prob = 0.008; + } //ToT=5 + else if (totalCharge.charge() < 7000.0) { + prob = 0.010; + } //ToT=6 + else if (totalCharge.charge() < 9000.0) { + prob = 0.005; + } //ToT=7 + else if (totalCharge.charge() < 10000.0) { + prob = 0.001; + } //ToT=8 + else if (totalCharge.charge() < 11000.0) { + prob = 0.001; + } //ToT=9 + else if (totalCharge.charge() < 12000.0) { + prob = 0.001; + } //ToT=10 + else if (totalCharge.charge() < 13000.0) { + prob = 0.001; + } //ToT=11 + else if (totalCharge.charge() < 14000.0) { + prob = 0.001; + } //ToT=12 } } - if (abs(barrel_ec)==2 && layer_disk==0) { - if (totalCharge.charge()<5550.0) { prob = 0.124;} //ToT = 6 - else if (totalCharge.charge()<6000.0) { prob = 0.067;} //ToT = 7 - else if (totalCharge.charge()<6400.0) { prob = 0.0005;} //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.002;} //ToT = 9 - else if (totalCharge.charge()<6800.0) { prob = 0.040;} //ToT = 10 - else if (totalCharge.charge()<7300.0) { prob = 0.031;} //ToT = 11 - else if (totalCharge.charge()<7400.0) { prob = 0.040;} //ToT = 12 - else if (totalCharge.charge()<7500.0) { prob = 0.001; } //ToT = 13 + if (barrel_ec == 0 && layer_disk == 2) { + if (abs(moduleID) == 0) { + if (totalCharge.charge() < 5094.9) { + prob = 0.1012; + } //ToT = 6 + else if (totalCharge.charge() < 5100.0) { + prob = 0.0500; + } //ToT = 7 + else if (totalCharge.charge() < 5800.0) { + prob = 0.0350; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0250; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0200; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0150; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0100; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 1) { + if (totalCharge.charge() < 5094.9) { + prob = 0.0978; + } //ToT = 6 + else if (totalCharge.charge() < 5100.0) { + prob = 0.0500; + } //ToT = 7 + else if (totalCharge.charge() < 5800.0) { + prob = 0.0405; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0250; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0200; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0150; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0100; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 2) { + if (totalCharge.charge() < 5094.9) { + prob = 0.1012; + } //ToT = 6 + else if (totalCharge.charge() < 5100.0) { + prob = 0.0500; + } //ToT = 7 + else if (totalCharge.charge() < 5800.0) { + prob = 0.0392; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0250; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0200; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0150; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0100; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 3) { + if (totalCharge.charge() < 5094.9) { + prob = 0.1015; + } //ToT = 6 + else if (totalCharge.charge() < 5100.0) { + prob = 0.0500; + } //ToT = 7 + else if (totalCharge.charge() < 5800.0) { + prob = 0.0390; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0250; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0200; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0150; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0100; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 4) { + if (totalCharge.charge() < 5094.9) { + prob = 0.0977; + } else if (totalCharge.charge() < 5100.0) { + prob = 0.0500; + } else if (totalCharge.charge() < 5800.0) { + prob = 0.0150; + } //0.0284 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0150; + } //0.0307 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0200; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0150; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0100; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 5) { + if (totalCharge.charge() < 5094.9) { + prob = 0.0966; + } //ToT = 6 + else if (totalCharge.charge() < 5100.0) { + prob = 0.0500; + } //ToT = 7 + else if (totalCharge.charge() < 5800.0) { + prob = 0.0369; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0256; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0200; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0150; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0100; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 6) { + if (totalCharge.charge() < 5094.9) { + prob = 0.1053; + } //ToT = 6 + else if (totalCharge.charge() < 5100.0) { + prob = 0.0500; + } //ToT = 7 + else if (totalCharge.charge() < 5800.0) { + prob = 0.0379; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.0252; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0200; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0150; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0100; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } } - if (abs(barrel_ec)==2 && layer_disk==1) { - if (totalCharge.charge()<5550.0) { prob = 0.124;} //ToT = 6 - else if (totalCharge.charge()<6000.0) { prob = 0.067;} //ToT = 7 - else if (totalCharge.charge()<6400.0) { prob = 0.0005;} //ToT = 8 - else if (totalCharge.charge()<6500.0) { prob = 0.002;} //ToT = 9 - else if (totalCharge.charge()<6800.0) { prob = 0.040;} //ToT = 10 - else if (totalCharge.charge()<7300.0) { prob = 0.031;} //ToT = 11 - else if (totalCharge.charge()<7400.0) { prob = 0.040;} //ToT = 12 - else if (totalCharge.charge()<7500.0) { prob = 0.001; } //ToT = 13 + if (barrel_ec == 0 && layer_disk == 3) { + if (abs(moduleID) == 0) { + if (totalCharge.charge() < 5055.0) { + prob = 0.1451; + } //ToT = 6 + else if (totalCharge.charge() < 5070.0) { + prob = 0.0915; + } //ToT = 7 + else if (totalCharge.charge() < 5700.0) { + prob = 0.0681; + } //ToT = 8 + else if (totalCharge.charge() < 6550.0) { + prob = 0.0518; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0300; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0200; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0200; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 1) { + if (totalCharge.charge() < 5055.0) { + prob = 0.1418; + } //ToT = 6 + else if (totalCharge.charge() < 5070.0) { + prob = 0.0800; + } //ToT = 7 + else if (totalCharge.charge() < 5700.0) { + prob = 0.0600; + } //ToT = 8 + else if (totalCharge.charge() < 6550.0) { + prob = 0.0497; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0300; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0200; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0200; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 2) { + if (totalCharge.charge() < 5055.0) { + prob = 0.1481; + } //ToT = 6 + else if (totalCharge.charge() < 5070.0) { + prob = 0.0891; + } //ToT = 7 + else if (totalCharge.charge() < 5700.0) { + prob = 0.0627; + } //ToT = 8 + else if (totalCharge.charge() < 6550.0) { + prob = 0.0488; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0300; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0200; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0200; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 3) { + if (totalCharge.charge() < 5055.0) { + prob = 0.1590; + } //ToT = 6 + else if (totalCharge.charge() < 5070.0) { + prob = 0.0930; + } //ToT = 7 + else if (totalCharge.charge() < 5700.0) { + prob = 0.0635; + } //ToT = 8 + else if (totalCharge.charge() < 6550.0) { + prob = 0.0485; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0300; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0200; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0200; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 4) { + if (totalCharge.charge() < 5055.0) { + prob = 0.1590; + } //ToT = 6 + else if (totalCharge.charge() < 5070.0) { + prob = 0.1214; + } //ToT = 7 + else if (totalCharge.charge() < 5700.0) { + prob = 0.0776; + } //ToT = 8 + else if (totalCharge.charge() < 6550.0) { + prob = 0.0387; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0300; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0200; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0200; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 5) { + if (totalCharge.charge() < 5055.0) { + prob = 0.1518; + } //ToT = 6 + else if (totalCharge.charge() < 5070.0) { + prob = 0.0874; + } //ToT = 7 + else if (totalCharge.charge() < 5700.0) { + prob = 0.0603; + } //ToT = 8 + else if (totalCharge.charge() < 6550.0) { + prob = 0.0460; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0300; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0200; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0200; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + if (abs(moduleID) == 6) { + if (totalCharge.charge() < 5055.0) { + prob = 0.1461; + } //ToT = 6 + else if (totalCharge.charge() < 5070.0) { + prob = 0.0825; + } //ToT = 7 + else if (totalCharge.charge() < 5700.0) { + prob = 0.0571; + } //ToT = 8 + else if (totalCharge.charge() < 6550.0) { + prob = 0.0441; + } //ToT = 9 + else if (totalCharge.charge() < 7000.0) { + prob = 0.0300; + } //ToT = 10 + else if (totalCharge.charge() < 7500.0) { + prob = 0.0200; + } //ToT = 11 + else if (totalCharge.charge() < 8200.0) { + prob = 0.0200; + } //ToT = 12 + else if (totalCharge.charge() < 9500.0) { + prob = 0.0100; + } //ToT = 13 + } + } + if (abs(barrel_ec) == 2 && layer_disk == 0) { + if (totalCharge.charge() < 5550.0) { + prob = 0.124; + } //ToT = 6 + else if (totalCharge.charge() < 6000.0) { + prob = 0.067; + } //ToT = 7 + else if (totalCharge.charge() < 6400.0) { + prob = 0.0005; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.002; + } //ToT = 9 + else if (totalCharge.charge() < 6800.0) { + prob = 0.040; + } //ToT = 10 + else if (totalCharge.charge() < 7300.0) { + prob = 0.031; + } //ToT = 11 + else if (totalCharge.charge() < 7400.0) { + prob = 0.040; + } //ToT = 12 + else if (totalCharge.charge() < 7500.0) { + prob = 0.001; + } //ToT = 13 + } + if (abs(barrel_ec) == 2 && layer_disk == 1) { + if (totalCharge.charge() < 5550.0) { + prob = 0.124; + } //ToT = 6 + else if (totalCharge.charge() < 6000.0) { + prob = 0.067; + } //ToT = 7 + else if (totalCharge.charge() < 6400.0) { + prob = 0.0005; + } //ToT = 8 + else if (totalCharge.charge() < 6500.0) { + prob = 0.002; + } //ToT = 9 + else if (totalCharge.charge() < 6800.0) { + prob = 0.040; + } //ToT = 10 + else if (totalCharge.charge() < 7300.0) { + prob = 0.031; + } //ToT = 11 + else if (totalCharge.charge() < 7400.0) { + prob = 0.040; + } //ToT = 12 + else if (totalCharge.charge() < 7500.0) { + prob = 0.001; + } //ToT = 13 } - if (abs(barrel_ec)==2 && layer_disk==2) { - if (totalCharge.charge()<5400.0) { prob = 0.180;} //ToT=6 - else if (totalCharge.charge()<5700.0) { prob = 0.067;} //ToT=7 - else if (totalCharge.charge()<5701.0) { prob = 0.0005;} //ToT=8 - else if (totalCharge.charge()<5702.0) { prob = 0.0005;} //ToT=9 - else if (totalCharge.charge()<5800.0) { prob = 0.036;} //ToT=10 - else if (totalCharge.charge()<6000.0) { prob = 0.031;} //ToT=11 - else if (totalCharge.charge()<6500.0) { prob = 0.034;} //ToT=12 - else if (totalCharge.charge()<7000.0) { prob = 0.001; } //ToT = 13 + if (abs(barrel_ec) == 2 && layer_disk == 2) { + if (totalCharge.charge() < 5400.0) { + prob = 0.180; + } //ToT=6 + else if (totalCharge.charge() < 5700.0) { + prob = 0.067; + } //ToT=7 + else if (totalCharge.charge() < 5701.0) { + prob = 0.0005; + } //ToT=8 + else if (totalCharge.charge() < 5702.0) { + prob = 0.0005; + } //ToT=9 + else if (totalCharge.charge() < 5800.0) { + prob = 0.036; + } //ToT=10 + else if (totalCharge.charge() < 6000.0) { + prob = 0.031; + } //ToT=11 + else if (totalCharge.charge() < 6500.0) { + prob = 0.034; + } //ToT=12 + else if (totalCharge.charge() < 7000.0) { + prob = 0.001; + } //ToT = 13 } double G4Time = getG4Time(totalCharge); - double rnd = CLHEP::RandFlat::shoot(rndmEngine,0.0,1.0); + double rnd = CLHEP::RandFlat::shoot(rndmEngine, 0.0, 1.0); double timeWalk = 0.0; - if (rnd<prob) { timeWalk = 25.0; } + if (rnd < prob) { + timeWalk = 25.0; + } - int BCID = static_cast<int>(floor((G4Time+moduleData->getTimeOffset(barrel_ec,layer_disk)+timeWalk)/moduleData->getBunchSpace())); + int BCID = + static_cast<int>(floor((G4Time + + moduleData->getTimeOffset(barrel_ec, + layer_disk) + timeWalk) / moduleData->getBunchSpace())); return BCID; } - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.h index 4297c7f48af7..5ba28bb29117 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI3SimTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/FEI3SimTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -14,23 +14,24 @@ #include "AthenaBaseComps/AthAlgTool.h" #include "FrontEndSimTool.h" -class FEI3SimTool:public FrontEndSimTool { - - public: - FEI3SimTool( const std::string& type, const std::string& name,const IInterface* parent); - - virtual StatusCode initialize(); - virtual StatusCode finalize(); - virtual ~FEI3SimTool(); - virtual void process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine); - - private: - FEI3SimTool(); - - int relativeBunch2009(const double threshold, const double intimethreshold, const SiTotalCharge &totalCharge, CLHEP::HepRandomEngine *rndmEngine) const; - int relativeBunch2015(const SiTotalCharge &totalCharge, int barrel_ec, int layer_disk, int moduleID, CLHEP::HepRandomEngine *rndmEngine) const; - int relativeBunch2018(const SiTotalCharge &totalCharge, int barrel_ec, int layer_disk, int moduleID, CLHEP::HepRandomEngine *rndmEngine) const; - +class FEI3SimTool: public FrontEndSimTool { +public: + FEI3SimTool(const std::string& type, const std::string& name, const IInterface* parent); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual ~FEI3SimTool(); + virtual void process(SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection, + CLHEP::HepRandomEngine* rndmEngine); +private: + FEI3SimTool(); + + int relativeBunch2009(const double threshold, const double intimethreshold, const SiTotalCharge& totalCharge, + CLHEP::HepRandomEngine* rndmEngine) const; + int relativeBunch2015(const SiTotalCharge& totalCharge, int barrel_ec, int layer_disk, int moduleID, + CLHEP::HepRandomEngine* rndmEngine) const; + int relativeBunch2018(const SiTotalCharge& totalCharge, int barrel_ec, int layer_disk, int moduleID, + CLHEP::HepRandomEngine* rndmEngine) const; }; #endif // PIXELDIGITIZATION_FEI3SimTool_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.cxx index baab2f0611e3..37234a5c5225 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.cxx @@ -1,12 +1,11 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "FEI4SimTool.h" -FEI4SimTool::FEI4SimTool( const std::string& type, const std::string& name,const IInterface* parent): - FrontEndSimTool(type,name,parent) -{ +FEI4SimTool::FEI4SimTool(const std::string& type, const std::string& name, const IInterface* parent) : + FrontEndSimTool(type, name, parent) { } FEI4SimTool::~FEI4SimTool() { } @@ -15,56 +14,63 @@ StatusCode FEI4SimTool::initialize() { CHECK(FrontEndSimTool::initialize()); ATH_MSG_DEBUG("FEI4SimTool::initialize()"); - return StatusCode::SUCCESS; + return StatusCode::SUCCESS; } StatusCode FEI4SimTool::finalize() { ATH_MSG_DEBUG("FEI4SimTool::finalize()"); - return StatusCode::SUCCESS; + return StatusCode::SUCCESS; } -void FEI4SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine) { +void FEI4SimTool::process(SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection, + CLHEP::HepRandomEngine* rndmEngine) { + const InDetDD::PixelModuleDesign* p_design = + static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - const InDetDD::PixelModuleDesign *p_design = static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - if (p_design->getReadoutTechnology()!=InDetDD::PixelModuleDesign::FEI4) { return; } + if (p_design->getReadoutTechnology() != InDetDD::PixelModuleDesign::FEI4) { + return; + } - const PixelID* pixelId = static_cast<const PixelID *>(chargedDiodes.element()->getIdHelper()); + const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper()); const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash Identifier moduleID = pixelId->wafer_id(chargedDiodes.element()->identify()); - int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); - int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); + int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); + int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); - if (abs(barrel_ec)!=m_BarrelEC) { return; } + if (abs(barrel_ec) != m_BarrelEC) { + return; + } SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); SG::ReadCondHandle<PixelChargeCalibCondData> calibData(m_chargeDataKey); int maxFEI4SmallHit = 2; - int overflowToT = moduleData->getFEI4OverflowToT(barrel_ec,layerIndex); + int overflowToT = moduleData->getFEI4OverflowToT(barrel_ec, layerIndex); std::vector<Pixel1RawData*> p_rdo_small_fei4; int nSmallHitsFEI4 = 0; std::vector<int> row, col; const int maxRow = p_design->rowsPerCircuit(); const int maxCol = p_design->columnsPerCircuit(); - std::vector<std::vector<int>> FEI4Map(maxRow+16,std::vector<int>(maxCol+16)); + std::vector<std::vector<int> > FEI4Map(maxRow + 16, std::vector<int>(maxCol + 16)); // Add cross-talk - CrossTalk(moduleData->getCrossTalk(barrel_ec,layerIndex),chargedDiodes); + CrossTalk(moduleData->getCrossTalk(barrel_ec, layerIndex), chargedDiodes); if (m_doNoise) { // Add thermal noise - ThermalNoise(moduleData->getThermalNoise(barrel_ec,layerIndex),chargedDiodes,rndmEngine); + ThermalNoise(moduleData->getThermalNoise(barrel_ec, layerIndex), chargedDiodes, rndmEngine); // Add random noise - RandomNoise(chargedDiodes,rndmEngine); + RandomNoise(chargedDiodes, rndmEngine); } // Add random diabled pixels - RandomDisable(chargedDiodes,rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs? + RandomDisable(chargedDiodes, rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs? - for (SiChargedDiodeOrderedIterator i_chargedDiode=chargedDiodes.orderedBegin(); i_chargedDiode!=chargedDiodes.orderedEnd(); ++i_chargedDiode) { + for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin(); + i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) { SiChargedDiode& diode = **i_chargedDiode; Identifier diodeID = chargedDiodes.getId(diode.diode()); @@ -72,78 +78,102 @@ void FEI4SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle // charge scaling function applied. (Reference: ATL-COM-INDET-2018-052) if (moduleData->getUseFEI4SpecialScalingFunction()) { - double corrQ = 1.11*(1.0-(-7.09*1000.0)/(23.72*1000.0+charge)+(-0.22*1000.0)/(-0.42*1000.0+charge)); - if (corrQ<1.0) { corrQ = 1.0; } - charge *= 1.0/corrQ; + double corrQ = 1.11 * + (1.0 - (-7.09 * 1000.0) / (23.72 * 1000.0 + charge) + (-0.22 * 1000.0) / + (-0.42 * 1000.0 + charge)); + if (corrQ < 1.0) { + corrQ = 1.0; + } + charge *= 1.0 / corrQ; } charge *= moduleData->getFEI4ChargScaling(); - int circ = m_pixelCabling->getFE(&diodeID,moduleID); + int circ = m_pixelCabling->getFE(&diodeID, moduleID); int type = m_pixelCabling->getPixelType(diodeID); // Apply analog threshold, timing simulation - double th0 = calibData->getAnalogThreshold((int)moduleHash, circ, type); + double th0 = calibData->getAnalogThreshold((int) moduleHash, circ, type); double thrand1 = CLHEP::RandGaussZiggurat::shoot(rndmEngine); double thrand2 = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double threshold = th0+calibData->getAnalogThresholdSigma((int)moduleHash,circ,type)*thrand1+calibData->getAnalogThresholdNoise((int)moduleHash, circ, type)*thrand2; // This noise check is unaffected by digitizationFlags.doInDetNoise in 21.0 - see PixelCellDiscriminator.cxx in that branch + double threshold = th0 + + calibData->getAnalogThresholdSigma((int) moduleHash, circ, + type) * thrand1 + calibData->getAnalogThresholdNoise( + (int) moduleHash, circ, type) * thrand2; // This noise check is unaffected by digitizationFlags.doInDetNoise in + // 21.0 - see PixelCellDiscriminator.cxx in that branch - if (charge>threshold) { + if (charge > threshold) { int bunchSim; if (diode.totalCharge().fromTrack()) { - bunchSim = static_cast<int>(floor((getG4Time(diode.totalCharge())+moduleData->getTimeOffset(barrel_ec,layerIndex))/moduleData->getBunchSpace())); - } - else { - bunchSim = CLHEP::RandFlat::shootInt(rndmEngine,moduleData->getNumberOfBCID(barrel_ec,layerIndex)); + bunchSim = + static_cast<int>(floor((getG4Time(diode.totalCharge()) + + moduleData->getTimeOffset(barrel_ec, layerIndex)) / moduleData->getBunchSpace())); + } else { + bunchSim = CLHEP::RandFlat::shootInt(rndmEngine, moduleData->getNumberOfBCID(barrel_ec, layerIndex)); } - if (bunchSim<0 || bunchSim>moduleData->getNumberOfBCID(barrel_ec,layerIndex)) { SiHelper::belowThreshold(diode,true,true); } - else { SiHelper::SetBunch(diode,bunchSim); } - } - else { - SiHelper::belowThreshold(diode,true,true); + if (bunchSim < 0 || bunchSim > moduleData->getNumberOfBCID(barrel_ec, layerIndex)) { + SiHelper::belowThreshold(diode, true, true); + } else { + SiHelper::SetBunch(diode, bunchSim); + } + } else { + SiHelper::belowThreshold(diode, true, true); } // charge to ToT conversion - double tot = calibData->getToT((int)moduleHash, circ, type, charge); - double totsig = calibData->getTotRes((int)moduleHash, circ, tot); - int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine,tot,totsig)); + double tot = calibData->getToT((int) moduleHash, circ, type, charge); + double totsig = calibData->getTotRes((int) moduleHash, circ, tot); + int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot, totsig)); - if (nToT<1) { nToT=1; } + if (nToT < 1) { + nToT = 1; + } // FEI4 HitDiscConfig - if (nToT==2 && maxFEI4SmallHit==2) { nToT=1; } - if (nToT>=overflowToT) { nToT=overflowToT; } + if (nToT == 2 && maxFEI4SmallHit == 2) { + nToT = 1; + } + if (nToT >= overflowToT) { + nToT = overflowToT; + } - if (nToT<=moduleData->getToTThreshold(barrel_ec,layerIndex)) { SiHelper::belowThreshold(diode,true,true); } + if (nToT <= moduleData->getToTThreshold(barrel_ec, layerIndex)) { + SiHelper::belowThreshold(diode, true, true); + } // Filter events - if (SiHelper::isMaskOut(diode)) { continue; } - if (SiHelper::isDisabled(diode)) { continue; } + if (SiHelper::isMaskOut(diode)) { + continue; + } + if (SiHelper::isDisabled(diode)) { + continue; + } - if (!m_pixelConditionsTool->isActive(moduleHash,diodeID)) { - SiHelper::disabled(diode,true,true); + if (!m_pixelConditionsTool->isActive(moduleHash, diodeID)) { + SiHelper::disabled(diode, true, true); continue; } - int flag = diode.flag(); - int bunch = (flag>>8)&0xff; + int flag = diode.flag(); + int bunch = (flag >> 8) & 0xff; - InDetDD::SiReadoutCellId cellId=diode.getReadoutCell(); + InDetDD::SiReadoutCellId cellId = diode.getReadoutCell(); const Identifier id_readout = chargedDiodes.element()->identifierFromCellId(cellId); int iirow = cellId.phiIndex(); int iicol = cellId.etaIndex(); - if (iicol>=maxCol) { iicol=iicol-maxCol; } // FEI4 copy mechanism works per FE. + if (iicol >= maxCol) { + iicol = iicol - maxCol; + } // FEI4 copy mechanism works per FE. // Front-End simulation - if (bunch>=0 && bunch<moduleData->getNumberOfBCID(barrel_ec,layerIndex)) { - Pixel1RawData *p_rdo = new Pixel1RawData(id_readout,nToT,bunch,0,bunch); - if (nToT>maxFEI4SmallHit) { + if (bunch >= 0 && bunch < moduleData->getNumberOfBCID(barrel_ec, layerIndex)) { + Pixel1RawData* p_rdo = new Pixel1RawData(id_readout, nToT, bunch, 0, bunch); + if (nToT > maxFEI4SmallHit) { rdoCollection.push_back(p_rdo); FEI4Map[iirow][iicol] = 2; //Flag for "big hits" - } - else { + } else { p_rdo_small_fei4.push_back(p_rdo); row.push_back(iirow); col.push_back(iicol); @@ -155,17 +185,19 @@ void FEI4SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle } // Copy mechanism for IBL small hits: - if (nSmallHitsFEI4>0) { + if (nSmallHitsFEI4 > 0) { bool recorded = false; //First case: Record small hits which are in the same Pixel Digital Region than a big hit: - for (int ismall=0; ismall<nSmallHitsFEI4; ismall++) { - int rowPDR = row[ismall]/2; - int colPDR = col[ismall]/2; - for (int rowBigHit=2*rowPDR; rowBigHit!=2*rowPDR+2 && rowBigHit<maxRow; ++rowBigHit) { - for (int colBigHit=2*colPDR; colBigHit!=2*colPDR+2 && colBigHit<maxCol; ++colBigHit) { - ATH_MSG_DEBUG("rowBig = " << rowBigHit << " colBig = " << colBigHit << " Map Content = " << FEI4Map[rowBigHit][colBigHit]); - if (FEI4Map[rowBigHit][colBigHit]==2 && !recorded) { + for (int ismall = 0; ismall < nSmallHitsFEI4; ismall++) { + int rowPDR = row[ismall] / 2; + int colPDR = col[ismall] / 2; + for (int rowBigHit = 2 * rowPDR; rowBigHit != 2 * rowPDR + 2 && rowBigHit < maxRow; ++rowBigHit) { + for (int colBigHit = 2 * colPDR; colBigHit != 2 * colPDR + 2 && colBigHit < maxCol; ++colBigHit) { + ATH_MSG_DEBUG( + "rowBig = " << rowBigHit << " colBig = " << colBigHit << " Map Content = " << + FEI4Map[rowBigHit][colBigHit]); + if (FEI4Map[rowBigHit][colBigHit] == 2 && !recorded) { rdoCollection.push_back(p_rdo_small_fei4[ismall]); recorded = true; } @@ -173,14 +205,14 @@ void FEI4SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle } // Second case: Record small hits which are phi-neighbours with a big hit: - if (!recorded && row[ismall]<maxRow-1) { - if (FEI4Map[row[ismall]+1][col[ismall]]==2) { + if (!recorded && row[ismall] < maxRow - 1) { + if (FEI4Map[row[ismall] + 1][col[ismall]] == 2) { rdoCollection.push_back(p_rdo_small_fei4[ismall]); recorded = true; } } - if (!recorded && row[ismall]!=0) { - if (FEI4Map[row[ismall]-1][col[ismall]]==2) { + if (!recorded && row[ismall] != 0) { + if (FEI4Map[row[ismall] - 1][col[ismall]] == 2) { rdoCollection.push_back(p_rdo_small_fei4[ismall]); recorded = true; } @@ -189,5 +221,3 @@ void FEI4SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle } return; } - - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.h index 9d99552c933d..2441f1d64eba 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/FEI4SimTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/FEI4SimTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -14,19 +14,17 @@ #include "AthenaBaseComps/AthAlgTool.h" #include "FrontEndSimTool.h" -class FEI4SimTool:public FrontEndSimTool { - - public: - FEI4SimTool( const std::string& type, const std::string& name,const IInterface* parent); - - virtual StatusCode initialize(); - virtual StatusCode finalize(); - virtual ~FEI4SimTool(); - virtual void process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine); - - private: - FEI4SimTool(); - +class FEI4SimTool: public FrontEndSimTool { +public: + FEI4SimTool(const std::string& type, const std::string& name, const IInterface* parent); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual ~FEI4SimTool(); + virtual void process(SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection, + CLHEP::HepRandomEngine* rndmEngine); +private: + FEI4SimTool(); }; #endif // PIXELDIGITIZATION_FEI4SimTool_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/FrontEndSimTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/FrontEndSimTool.h index 4bcf7ad3976b..f8de8f008ecc 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/FrontEndSimTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/FrontEndSimTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #ifndef PIXELDIGITIZATION_FrontEndSimTool_H #define PIXELDIGITIZATION_FrontEndSimTool_H @@ -33,171 +33,205 @@ static const InterfaceID IID_IFrontEndSimTool("FrontEndSimTool", 1, 0); -class FrontEndSimTool:public AthAlgTool,virtual public IAlgTool { - - public: - FrontEndSimTool( const std::string& type, const std::string& name,const IInterface* parent): - AthAlgTool(type,name,parent) - { +class FrontEndSimTool: public AthAlgTool, virtual public IAlgTool { +public: + FrontEndSimTool(const std::string& type, const std::string& name, const IInterface* parent) : + AthAlgTool(type, name, parent) { declareInterface<FrontEndSimTool>(this); } - static const InterfaceID& interfaceID() { return IID_IFrontEndSimTool; } + static const InterfaceID& interfaceID() {return IID_IFrontEndSimTool;} - virtual StatusCode initialize() { - ATH_CHECK(m_pixelConditionsTool.retrieve()); - ATH_CHECK(m_pixelCabling.retrieve()); - ATH_CHECK(m_moduleDataKey.initialize()); - ATH_CHECK(m_chargeDataKey.initialize()); - return StatusCode::SUCCESS; - } + virtual StatusCode initialize() { + ATH_CHECK(m_pixelConditionsTool.retrieve()); + ATH_CHECK(m_pixelCabling.retrieve()); + ATH_CHECK(m_moduleDataKey.initialize()); + ATH_CHECK(m_chargeDataKey.initialize()); + return StatusCode::SUCCESS; + } - virtual StatusCode finalize() { return StatusCode::FAILURE; } - virtual ~FrontEndSimTool() {} - virtual void process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine) = 0; - - void CrossTalk(double crossTalk, SiChargedDiodeCollection &chargedDiodes) const { - const InDetDD::PixelModuleDesign *p_design = static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - SiChargedDiodeMap oldChargedDiodes=chargedDiodes.chargedDiodes(); - for (SiChargedDiodeIterator i_chargedDiode=oldChargedDiodes.begin(); i_chargedDiode!=oldChargedDiodes.end(); ++i_chargedDiode) { - InDetDD::SiCellId diode=(*i_chargedDiode).second.diode(); - std::vector<InDetDD::SiCellId> neighbours; - p_design->neighboursOfCell(diode,neighbours); - for (std::vector<InDetDD::SiCellId>::const_iterator p_neighbour=neighbours.begin(); p_neighbour!=neighbours.end(); ++p_neighbour) { - const double intersection=p_design->intersectionLength(diode,*p_neighbour); - // add cross talk only if the intersection is non-zero - // if the original pixel is at (col,row) then the intersection length is - // (col+-1, row+-1) : 0 -> diagonal - // (col , row+-1) : 0.4 mm (or 0.6 if long pixel) pixel width = 400um or 600um - // (col+-1, row ) : 0.05 mm , pixel height = 50um - // intersection length is just the length of the contact surface between the two pixels - if (intersection>0) { - // create a new charge: - // Q(new) = Q*L*X - // Q = charge of source pixel - // L = intersection length [mm] - // X = crosstalk factor [mm-1] - const SiChargedDiode &siCharge = (*i_chargedDiode).second; - SiCharge charge(siCharge.charge()*intersection*crossTalk, siCharge.totalCharge().time(), SiCharge::diodeX_Talk, siCharge.totalCharge().particleLink()); - chargedDiodes.add(*p_neighbour,charge); - } + virtual StatusCode finalize() {return StatusCode::FAILURE;} + virtual ~FrontEndSimTool() {} + virtual void process(SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection, + CLHEP::HepRandomEngine* rndmEngine) = 0; + + void CrossTalk(double crossTalk, SiChargedDiodeCollection& chargedDiodes) const { + const InDetDD::PixelModuleDesign* p_design = + static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); + SiChargedDiodeMap oldChargedDiodes = chargedDiodes.chargedDiodes(); + + for (SiChargedDiodeIterator i_chargedDiode = oldChargedDiodes.begin(); i_chargedDiode != oldChargedDiodes.end(); + ++i_chargedDiode) { + InDetDD::SiCellId diode = (*i_chargedDiode).second.diode(); + std::vector<InDetDD::SiCellId> neighbours; + p_design->neighboursOfCell(diode, neighbours); + for (std::vector<InDetDD::SiCellId>::const_iterator p_neighbour = neighbours.begin(); + p_neighbour != neighbours.end(); ++p_neighbour) { + const double intersection = p_design->intersectionLength(diode, *p_neighbour); + // add cross talk only if the intersection is non-zero + // if the original pixel is at (col,row) then the intersection length is + // (col+-1, row+-1) : 0 -> diagonal + // (col , row+-1) : 0.4 mm (or 0.6 if long pixel) pixel width = 400um or 600um + // (col+-1, row ) : 0.05 mm , pixel height = 50um + // intersection length is just the length of the contact surface between the two pixels + if (intersection > 0) { + // create a new charge: + // Q(new) = Q*L*X + // Q = charge of source pixel + // L = intersection length [mm] + // X = crosstalk factor [mm-1] + const SiChargedDiode& siCharge = (*i_chargedDiode).second; + SiCharge charge(siCharge.charge() * intersection* crossTalk, + siCharge.totalCharge().time(), SiCharge::diodeX_Talk, siCharge.totalCharge().particleLink()); + chargedDiodes.add(*p_neighbour, charge); } } - return; } + return; + } - void ThermalNoise(double thermalNoise, SiChargedDiodeCollection &chargedDiodes, CLHEP::HepRandomEngine *rndmEngine) const { - for (SiChargedDiodeOrderedIterator i_chargedDiode=chargedDiodes.orderedBegin(); - i_chargedDiode!=chargedDiodes.orderedEnd(); ++i_chargedDiode) - { - SiCharge charge(thermalNoise*CLHEP::RandGaussZiggurat::shoot(rndmEngine),0,SiCharge::noise); - (*i_chargedDiode)->add(charge); - } - return; + void ThermalNoise(double thermalNoise, SiChargedDiodeCollection& chargedDiodes, + CLHEP::HepRandomEngine* rndmEngine) const { + for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin(); + i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) { + SiCharge charge(thermalNoise * CLHEP::RandGaussZiggurat::shoot(rndmEngine), 0, SiCharge::noise); + (*i_chargedDiode)->add(charge); } + return; + } - void RandomNoise(SiChargedDiodeCollection &chargedDiodes, CLHEP::HepRandomEngine *rndmEngine) const { - SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); - SG::ReadCondHandle<PixelChargeCalibCondData> calibData(m_chargeDataKey); - const InDetDD::PixelModuleDesign *p_design = static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - - const PixelID* pixelId = static_cast<const PixelID *>(chargedDiodes.element()->getIdHelper()); - const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash - int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); - int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); - int nNoise = CLHEP::RandPoisson::shoot(rndmEngine, p_design->numberOfCircuits()*p_design->columnsPerCircuit()*p_design->rowsPerCircuit()*moduleData->getNoiseOccupancy(barrel_ec,layerIndex)*static_cast<double>(moduleData->getNumberOfBCID(barrel_ec,layerIndex))); - - for (int i=0; i<nNoise; i++) { - int circuit = CLHEP::RandFlat::shootInt(rndmEngine,p_design->numberOfCircuits()); - int column = CLHEP::RandFlat::shootInt(rndmEngine,p_design->columnsPerCircuit()); - int row = CLHEP::RandFlat::shootInt(rndmEngine,p_design->rowsPerCircuit()); - if (row>159 && p_design->getReadoutTechnology()==InDetDD::PixelModuleDesign::FEI3) { row += 8; } // jump over ganged pixels - rowsPerCircuit == 320 above - - InDetDD::SiReadoutCellId roCell(row, p_design->columnsPerCircuit()*circuit+column); - Identifier noisyID=chargedDiodes.element()->identifierFromCellId(roCell); - - if (roCell.isValid()) { - InDetDD::SiCellId diodeNoise = roCell; - - double x = CLHEP::RandFlat::shoot(rndmEngine,0.,1.); - int bin=0; - std::vector<float> noiseShape = moduleData->getNoiseShape(barrel_ec,layerIndex); - for (size_t j=1; j<noiseShape.size(); j++) { - if (x>noiseShape[j-1] && x<=noiseShape[j]) { bin=j-1; continue; } + void RandomNoise(SiChargedDiodeCollection& chargedDiodes, CLHEP::HepRandomEngine* rndmEngine) const { + SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); + SG::ReadCondHandle<PixelChargeCalibCondData> calibData(m_chargeDataKey); + const InDetDD::PixelModuleDesign* p_design = + static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); + + const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper()); + const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash + int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); + int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); + int nNoise = CLHEP::RandPoisson::shoot(rndmEngine, + p_design->numberOfCircuits() * p_design->columnsPerCircuit() * p_design->rowsPerCircuit() * + moduleData->getNoiseOccupancy(barrel_ec, + layerIndex) * + static_cast<double>(moduleData->getNumberOfBCID(barrel_ec, layerIndex))); + + for (int i = 0; i < nNoise; i++) { + int circuit = CLHEP::RandFlat::shootInt(rndmEngine, p_design->numberOfCircuits()); + int column = CLHEP::RandFlat::shootInt(rndmEngine, p_design->columnsPerCircuit()); + int row = CLHEP::RandFlat::shootInt(rndmEngine, p_design->rowsPerCircuit()); + if (row > 159 && p_design->getReadoutTechnology() == InDetDD::PixelModuleDesign::FEI3) { + row += 8; + } // jump over ganged pixels - rowsPerCircuit == 320 above + + InDetDD::SiReadoutCellId roCell(row, p_design->columnsPerCircuit() * circuit + column); + Identifier noisyID = chargedDiodes.element()->identifierFromCellId(roCell); + + if (roCell.isValid()) { + InDetDD::SiCellId diodeNoise = roCell; + + double x = CLHEP::RandFlat::shoot(rndmEngine, 0., 1.); + int bin = 0; + std::vector<float> noiseShape = moduleData->getNoiseShape(barrel_ec, layerIndex); + for (size_t j = 1; j < noiseShape.size(); j++) { + if (x > noiseShape[j - 1] && x <= noiseShape[j]) { + bin = j - 1; + continue; } - double noiseToTm = bin+1.5; - double noiseToT = CLHEP::RandGaussZiggurat::shoot(rndmEngine,noiseToTm,1.); + } + double noiseToTm = bin + 1.5; + double noiseToT = CLHEP::RandGaussZiggurat::shoot(rndmEngine, noiseToTm, 1.); - int type = m_pixelCabling->getPixelType(noisyID); - double chargeShape = calibData->getCharge((int)moduleHash, circuit, type, noiseToT); + int type = m_pixelCabling->getPixelType(noisyID); + double chargeShape = calibData->getCharge((int) moduleHash, circuit, type, noiseToT); - chargedDiodes.add(diodeNoise,SiCharge(chargeShape,0,SiCharge::noise)); - } + chargedDiodes.add(diodeNoise, SiCharge(chargeShape, 0, SiCharge::noise)); } - return; } + return; + } - void RandomDisable(SiChargedDiodeCollection &chargedDiodes, CLHEP::HepRandomEngine *rndmEngine) const { - SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); - const PixelID* pixelId = static_cast<const PixelID *>(chargedDiodes.element()->getIdHelper()); - int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); - int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); - for (SiChargedDiodeOrderedIterator i_chargedDiode=chargedDiodes.orderedBegin(); i_chargedDiode!=chargedDiodes.orderedEnd(); ++i_chargedDiode) { - if (CLHEP::RandFlat::shoot(rndmEngine)<moduleData->getDisableProbability(barrel_ec,layerIndex)) { - SiHelper::disabled(**i_chargedDiode,true,false); - } + void RandomDisable(SiChargedDiodeCollection& chargedDiodes, CLHEP::HepRandomEngine* rndmEngine) const { + SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); + const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper()); + int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); + int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); + for (SiChargedDiodeOrderedIterator i_chargedDiode = chargedDiodes.orderedBegin(); + i_chargedDiode != chargedDiodes.orderedEnd(); ++i_chargedDiode) { + if (CLHEP::RandFlat::shoot(rndmEngine) < moduleData->getDisableProbability(barrel_ec, layerIndex)) { + SiHelper::disabled(**i_chargedDiode, true, false); } - return; } + return; + } - private: - FrontEndSimTool(); - - protected: - ToolHandle<IInDetConditionsTool> m_pixelConditionsTool - {this, "PixelConditionsSummaryTool", "PixelConditionsSummaryTool", "Tool to retrieve Pixel Conditions summary"}; +private: + FrontEndSimTool(); +protected: + ToolHandle<IInDetConditionsTool> m_pixelConditionsTool + { + this, "PixelConditionsSummaryTool", "PixelConditionsSummaryTool", "Tool to retrieve Pixel Conditions summary" + }; - ServiceHandle<IPixelCablingSvc> m_pixelCabling - {this, "PixelCablingSvc", "PixelCablingSvc", "Pixel cabling service"}; + ServiceHandle<IPixelCablingSvc> m_pixelCabling + { + this, "PixelCablingSvc", "PixelCablingSvc", "Pixel cabling service" + }; - SG::ReadCondHandleKey<PixelModuleData> m_moduleDataKey - {this, "PixelModuleData", "PixelModuleData", "Pixel module data"}; + SG::ReadCondHandleKey<PixelModuleData> m_moduleDataKey + { + this, "PixelModuleData", "PixelModuleData", "Pixel module data" + }; - SG::ReadCondHandleKey<PixelChargeCalibCondData> m_chargeDataKey - {this, "PixelChargeCalibCondData", "PixelChargeCalibCondData", "Pixel charge calibration data"}; + SG::ReadCondHandleKey<PixelChargeCalibCondData> m_chargeDataKey + { + this, "PixelChargeCalibCondData", "PixelChargeCalibCondData", "Pixel charge calibration data" + }; - Gaudi::Property<int> m_BarrelEC - {this, "BarrelEC", 0, "Index of barrel or endcap"}; + Gaudi::Property<int> m_BarrelEC + { + this, "BarrelEC", 0, "Index of barrel or endcap" + }; - Gaudi::Property<bool> m_doNoise - {this, "DoNoise", true, "Flag ofnoise simulation"}; + Gaudi::Property<bool> m_doNoise + { + this, "DoNoise", true, "Flag ofnoise simulation" + }; - double getG4Time(const SiTotalCharge &totalCharge) const { - // If there is one single charge, return its time: - if (totalCharge.chargeComposition().empty()) { return totalCharge.time(); } + double getG4Time(const SiTotalCharge& totalCharge) const { + // If there is one single charge, return its time: + if (totalCharge.chargeComposition().empty()) { + return totalCharge.time(); + } - std::list<SiCharge>::const_iterator p_charge=totalCharge.chargeComposition().begin(); - int findfirst = 0; - SiCharge first = *p_charge; + std::list<SiCharge>::const_iterator p_charge = totalCharge.chargeComposition().begin(); + int findfirst = 0; + SiCharge first = *p_charge; - // Look for first charge which is not noise - for (; p_charge!=totalCharge.chargeComposition().end(); p_charge++) { - if (p_charge->processType()!=SiCharge::noise) { findfirst=1; break; } + // Look for first charge which is not noise + for (; p_charge != totalCharge.chargeComposition().end(); p_charge++) { + if (p_charge->processType() != SiCharge::noise) { + findfirst = 1; + break; } + } - // if all charges were noise, return the time of the highest charge - if (findfirst==0) { return totalCharge.time(); } + // if all charges were noise, return the time of the highest charge + if (findfirst == 0) { + return totalCharge.time(); + } - // look for the earlist charge among the remaining non-noise charges: - first = *p_charge; - p_charge++; + // look for the earlist charge among the remaining non-noise charges: + first = *p_charge; + p_charge++; - for ( ; p_charge!=totalCharge.chargeComposition().end() ; p_charge++) { - if (p_charge->time()<first.time() && p_charge->processType()!=SiCharge::noise) { first=*p_charge; } + for (; p_charge != totalCharge.chargeComposition().end(); p_charge++) { + if (p_charge->time() < first.time() && p_charge->processType() != SiCharge::noise) { + first = *p_charge; } - return first.time(); } - + return first.time(); + } }; #endif // PIXELDIGITIZATION_FrontEndSimTool_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.cxx index 23c2201eb789..c71cd69867e3 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.cxx @@ -1,26 +1,25 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "PixelDigitization.h" // Constructor with parameters: -PixelDigitization::PixelDigitization(const std::string &name, - ISvcLocator *pSvcLocator) : - AthAlgorithm(name,pSvcLocator) -{ +PixelDigitization::PixelDigitization(const std::string& name, + ISvcLocator* pSvcLocator) : + AthAlgorithm(name, pSvcLocator) { } // Initialize method: StatusCode PixelDigitization::initialize() { ATH_MSG_DEBUG("initialize()"); ATH_CHECK(m_pixelDigitizationTool.retrieve()); - ATH_MSG_DEBUG ( "Successfully retreived IPixelDigitizaitonTool." ); + ATH_MSG_DEBUG("Successfully retreived IPixelDigitizaitonTool."); return StatusCode::SUCCESS; } // Execute method: StatusCode PixelDigitization::execute() { - ATH_MSG_DEBUG ( "execute()" ); + ATH_MSG_DEBUG("execute()"); return m_pixelDigitizationTool->processAllSubEvents(Gaudi::Hive::currentContext()); } diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.h b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.h index 63bbb60a1ec2..a9f46ebecd63 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitization.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/PixelDigitization.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -15,16 +15,17 @@ #include "GaudiKernel/ToolHandle.h" #include "PileUpTools/IPileUpTool.h" -class PixelDigitization : public AthAlgorithm { - public: - PixelDigitization(const std::string &name,ISvcLocator *pSvcLocator); - virtual ~PixelDigitization() = default; - virtual StatusCode initialize() override final; - virtual StatusCode execute() override final; - virtual bool isClonable() const override final { return true; } - - private: - ToolHandle<IPileUpTool> m_pixelDigitizationTool{this, "DigitizationTool", "PixelDigitizationTool", "PixelDigitizationTool name"}; +class PixelDigitization: public AthAlgorithm { +public: + PixelDigitization(const std::string& name, ISvcLocator* pSvcLocator); + virtual ~PixelDigitization() = default; + virtual StatusCode initialize() override final; + virtual StatusCode execute() override final; + virtual bool isClonable() const override final {return true;} +private: + ToolHandle<IPileUpTool> m_pixelDigitizationTool { + this, "DigitizationTool", "PixelDigitizationTool", "PixelDigitizationTool name" + }; }; #endif // PIXELDIGITIZATION_PIXELDIGITIZATION_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.cxx index 35e1214bf5c7..8d24f1dc37f8 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "PixelDigitizationTool.h" #include "SiDigitization/SiChargedDiodeCollection.h" @@ -10,10 +10,10 @@ #include <limits> #include <cstdint> -PixelDigitizationTool::PixelDigitizationTool(const std::string &type, - const std::string &name, - const IInterface * pIID) : - PileUpToolBase(type,name,pIID) { +PixelDigitizationTool::PixelDigitizationTool(const std::string& type, + const std::string& name, + const IInterface* pIID) : + PileUpToolBase(type, name, pIID) { } //======================================= @@ -27,7 +27,7 @@ StatusCode PixelDigitizationTool::initialize() { } ATH_CHECK(m_rndmSvc.retrieve()); - ATH_CHECK(detStore()->retrieve(m_detID,"PixelID")); + ATH_CHECK(detStore()->retrieve(m_detID, "PixelID")); ATH_MSG_DEBUG("Pixel ID helper retrieved"); ATH_CHECK(m_chargeTool.retrieve()); @@ -39,7 +39,7 @@ StatusCode PixelDigitizationTool::initialize() { ATH_MSG_FATAL("Property InputObjectName not set !"); return StatusCode::FAILURE; } - if(m_onlyUseContainerName) m_inputObjectName = m_hitsContainerKey.key(); + if (m_onlyUseContainerName) m_inputObjectName = m_hitsContainerKey.key(); ATH_MSG_DEBUG("Input objects in container : '" << m_inputObjectName << "'"); ATH_CHECK(m_hitsContainerKey.initialize(!m_onlyUseContainerName)); @@ -61,7 +61,6 @@ StatusCode PixelDigitizationTool::finalize() { // P R O C E S S S U B E V E N T S //======================================= StatusCode PixelDigitizationTool::processAllSubEvents(const EventContext& ctx) { - // Prepare event ATH_MSG_DEBUG("Prepare event"); ATH_CHECK(prepareEvent(ctx, 0)); @@ -72,7 +71,9 @@ StatusCode PixelDigitizationTool::processAllSubEvents(const EventContext& ctx) { if (!m_onlyUseContainerName) { SG::ReadHandle<SiHitCollection> hitCollection(m_hitsContainerKey, ctx); if (!hitCollection.isValid()) { - ATH_MSG_ERROR("Could not get Pixel SiHitCollection container " << hitCollection.name() << " from store " << hitCollection.store()); + ATH_MSG_ERROR( + "Could not get Pixel SiHitCollection container " << hitCollection.name() << " from store " << + hitCollection.store()); return StatusCode::FAILURE; } @@ -80,21 +81,27 @@ StatusCode PixelDigitizationTool::processAllSubEvents(const EventContext& ctx) { m_timedHits->reserve(1); m_timedHits->insert(0, hitCollection.cptr()); ATH_MSG_DEBUG("SiHitCollection found with " << hitCollection->size() << " hits"); - } - else { + } else { TimedHitCollList hitCollList; unsigned int numberOfSiHits(0); - ATH_CHECK(m_mergeSvc->retrieveSubEvtsData(m_inputObjectName,hitCollList,numberOfSiHits)); + ATH_CHECK(m_mergeSvc->retrieveSubEvtsData(m_inputObjectName, hitCollList, numberOfSiHits)); m_timedHits->reserve(numberOfSiHits); // Now merge all collections into one - for (TimedHitCollList::iterator iColl=hitCollList.begin(); iColl!=hitCollList.end(); iColl++) { + for (TimedHitCollList::iterator iColl = hitCollList.begin(); iColl != hitCollList.end(); iColl++) { // Decide if this event will be processed depending on HardScatterSplittingMode - if (m_HardScatterSplittingMode==2 && !m_HardScatterSplittingSkipper) { m_HardScatterSplittingSkipper=true; continue; } - if (m_HardScatterSplittingMode==1 && m_HardScatterSplittingSkipper) { continue; } - if (m_HardScatterSplittingMode==1 && !m_HardScatterSplittingSkipper) { m_HardScatterSplittingSkipper=true; } + if (m_HardScatterSplittingMode == 2 && !m_HardScatterSplittingSkipper) { + m_HardScatterSplittingSkipper = true; + continue; + } + if (m_HardScatterSplittingMode == 1 && m_HardScatterSplittingSkipper) { + continue; + } + if (m_HardScatterSplittingMode == 1 && !m_HardScatterSplittingSkipper) { + m_HardScatterSplittingSkipper = true; + } const SiHitCollection* p_collection(iColl->second); m_timedHits->insert(iColl->first, p_collection); - ATH_MSG_DEBUG("SiTrackerHitCollection found with"<<p_collection->size()<<" hits"); // loop on the hit collections + ATH_MSG_DEBUG("SiTrackerHitCollection found with" << p_collection->size() << " hits"); // loop on the hit collections } } // Digitize hits @@ -112,66 +119,77 @@ StatusCode PixelDigitizationTool::digitizeEvent(const EventContext& ctx) { SG::ReadCondHandle<InDetDD::SiDetectorElementCollection> pixelDetEleHandle(m_pixelDetEleCollKey, ctx); const InDetDD::SiDetectorElementCollection* elements(*pixelDetEleHandle); - if (not pixelDetEleHandle.isValid() or elements==nullptr) { + if (not pixelDetEleHandle.isValid() or elements == nullptr) { ATH_MSG_FATAL(m_pixelDetEleCollKey.fullKey() << " is not available."); return StatusCode::FAILURE; } - std::unique_ptr<SiChargedDiodeCollection> chargedDiodes = std::make_unique<SiChargedDiodeCollection>(); - std::vector<std::pair<double,double> > trfHitRecord; trfHitRecord.clear(); - std::vector<double> initialConditions; initialConditions.clear(); + std::unique_ptr<SiChargedDiodeCollection> chargedDiodes = std::make_unique<SiChargedDiodeCollection>(); + std::vector<std::pair<double, double> > trfHitRecord; + trfHitRecord.clear(); + std::vector<double> initialConditions; + initialConditions.clear(); std::vector<bool> processedElements; - processedElements.resize(m_detID->wafer_hash_max(),false); + processedElements.resize(m_detID->wafer_hash_max(), false); // Set the RNG to use for this event. ATHRNG::RNGWrapper* rngWrapper = m_rndmSvc->getEngine(this); - rngWrapper->setSeed( name(), ctx ); - CLHEP::HepRandomEngine *rndmEngine = rngWrapper->getEngine(ctx); + rngWrapper->setSeed(name(), ctx); + CLHEP::HepRandomEngine* rndmEngine = rngWrapper->getEngine(ctx); TimedHitCollection<SiHit>::const_iterator firstHit, lastHit; - + //////////////////////////////////////////////// // **** Loop over the Detectors with hits **** //////////////////////////////////////////////// - while (m_timedHits->nextDetectorElement(firstHit,lastHit)) { - + while (m_timedHits->nextDetectorElement(firstHit, lastHit)) { // Create the identifier for the collection ATH_MSG_DEBUG("create ID for the hit collection"); - Identifier id = m_detID->wafer_id((*firstHit)->getBarrelEndcap(),(*firstHit)->getLayerDisk(),(*firstHit)->getPhiModule(),(*firstHit)->getEtaModule()); + Identifier id = m_detID->wafer_id((*firstHit)->getBarrelEndcap(), + (*firstHit)->getLayerDisk(), + (*firstHit)->getPhiModule(), (*firstHit)->getEtaModule()); IdentifierHash wafer_hash = m_detID->wafer_hash(id); // Get the det element from the manager const InDetDD::SiDetectorElement* sielement = elements->getDetectorElement(wafer_hash); - if (sielement==0) { - ATH_MSG_DEBUG(" Barrel=" << (*firstHit)->getBarrelEndcap() << " Layer=" << (*firstHit)->getLayerDisk() << " Eta=" << (*firstHit)->getEtaModule() << " Phi=" << (*firstHit)->getPhiModule()); + if (sielement == 0) { + ATH_MSG_DEBUG( + " Barrel=" << (*firstHit)->getBarrelEndcap() << " Layer=" << (*firstHit)->getLayerDisk() << " Eta=" << + (*firstHit)->getEtaModule() << " Phi=" << (*firstHit)->getPhiModule()); ATH_MSG_ERROR("detector manager could not find element with id = " << id); break; } // Create the charged diodes collection chargedDiodes->setDetectorElement(sielement); - const InDetDD::PixelModuleDesign *p_design= static_cast<const InDetDD::PixelModuleDesign*>(&(sielement->design())); + const InDetDD::PixelModuleDesign* p_design = static_cast<const InDetDD::PixelModuleDesign*>(&(sielement->design())); /////////////////////////////////////////////////////////// // **** Loop over the hits and created charged diodes **** /////////////////////////////////////////////////////////// - for (TimedHitCollection<SiHit>::const_iterator phit=firstHit; phit!=lastHit; phit++) { + for (TimedHitCollection<SiHit>::const_iterator phit = firstHit; phit != lastHit; phit++) { //skip hits which are more than 10us away - if (fabs((*phit)->meanTime())<10000.0*CLHEP::ns) { - ATH_MSG_DEBUG("HASH = " << m_detID->wafer_hash(m_detID->wafer_id((*phit)->getBarrelEndcap(),(*phit)->getLayerDisk(),(*phit)->getPhiModule(),(*phit)->getEtaModule()))); + if (fabs((*phit)->meanTime()) < 10000.0 * CLHEP::ns) { + ATH_MSG_DEBUG("HASH = " << + m_detID->wafer_hash(m_detID->wafer_id((*phit)->getBarrelEndcap(), (*phit)->getLayerDisk(), + (*phit)->getPhiModule(), (*phit)->getEtaModule()))); // Apply charge collection tools ATH_MSG_DEBUG("Running sensor simulation."); //Deposit energy in sensor - ATH_CHECK(m_energyDepositionTool->depositEnergy( *phit, *sielement, trfHitRecord, initialConditions, rndmEngine)); + ATH_CHECK(m_energyDepositionTool->depositEnergy(*phit, *sielement, trfHitRecord, initialConditions, + rndmEngine)); //Create signal in sensor, loop over collection of loaded sensorTools - for (unsigned int itool=0; itool<m_chargeTool.size(); itool++) { + for (unsigned int itool = 0; itool < m_chargeTool.size(); itool++) { ATH_MSG_DEBUG("Executing tool " << m_chargeTool[itool]->name()); - if (m_chargeTool[itool]->induceCharge( *phit, *chargedDiodes, *sielement, *p_design, trfHitRecord, initialConditions, rndmEngine)==StatusCode::FAILURE) { break; } + if (m_chargeTool[itool]->induceCharge(*phit, *chargedDiodes, *sielement, *p_design, trfHitRecord, + initialConditions, rndmEngine) == StatusCode::FAILURE) { + break; + } } initialConditions.clear(); trfHitRecord.clear(); @@ -180,23 +198,26 @@ StatusCode PixelDigitizationTool::digitizeEvent(const EventContext& ctx) { } ATH_MSG_DEBUG("Hit collection ID=" << m_detID->show_to_string(chargedDiodes->identify())); - ATH_MSG_DEBUG("in digitize elements with hits: ec - layer - eta - phi " << m_detID->barrel_ec(chargedDiodes->identify()) << " - " << m_detID->layer_disk(chargedDiodes->identify()) << " - " << m_detID->eta_module(chargedDiodes->identify()) << " - " << m_detID->phi_module(chargedDiodes->identify())); + ATH_MSG_DEBUG("in digitize elements with hits: ec - layer - eta - phi " << + m_detID->barrel_ec(chargedDiodes->identify()) << " - " << m_detID->layer_disk( + chargedDiodes->identify()) << " - " << m_detID->eta_module( + chargedDiodes->identify()) << " - " << m_detID->phi_module(chargedDiodes->identify())); IdentifierHash idHash = chargedDiodes->identifyHash(); - assert(idHash<processedElements.size()); + assert(idHash < processedElements.size()); processedElements[idHash] = true; /////////////////////////////////////////////////////////// // *** Create and store RDO and SDO **** /////////////////////////////////////////////////////////// - PixelRDO_Collection *RDOColl = new PixelRDO_Collection(chargedDiodes->identifyHash()); + PixelRDO_Collection* RDOColl = new PixelRDO_Collection(chargedDiodes->identifyHash()); RDOColl->setIdentifier(chargedDiodes->identify()); - for (unsigned int itool=0; itool<m_fesimTool.size(); itool++) { + for (unsigned int itool = 0; itool < m_fesimTool.size(); itool++) { ATH_MSG_DEBUG("Executing tool " << m_fesimTool[itool]->name()); - m_fesimTool[itool]->process(*chargedDiodes,*RDOColl, rndmEngine); + m_fesimTool[itool]->process(*chargedDiodes, *RDOColl, rndmEngine); } - ATH_CHECK(m_rdoContainer->addCollection(RDOColl,RDOColl->identifyHash())); + ATH_CHECK(m_rdoContainer->addCollection(RDOColl, RDOColl->identifyHash())); ATH_MSG_DEBUG("Pixel RDOs '" << RDOColl->identifyHash() << "' added to container"); addSDO(chargedDiodes.get()); @@ -209,28 +230,33 @@ StatusCode PixelDigitizationTool::digitizeEvent(const EventContext& ctx) { /////////////////////////////////////////////////////////// // *** Loop over the Detectors without hits **** /////////////////////////////////////////////////////////// - if (!m_onlyHitElements) { + if (!m_onlyHitElements) { ATH_MSG_DEBUG("processing elements without hits"); - for (unsigned int i=0; i<processedElements.size(); i++) { + for (unsigned int i = 0; i < processedElements.size(); i++) { if (!processedElements[i]) { IdentifierHash idHash = i; - if (!idHash.is_valid()) { ATH_MSG_ERROR("PixelDetector element id hash is invalid = " << i); } + if (!idHash.is_valid()) { + ATH_MSG_ERROR("PixelDetector element id hash is invalid = " << i); + } - const InDetDD::SiDetectorElement *element = elements->getDetectorElement(idHash); + const InDetDD::SiDetectorElement* element = elements->getDetectorElement(idHash); if (element) { - ATH_MSG_DEBUG ("In digitize of untouched elements: layer - phi - eta " << m_detID->layer_disk(element->identify()) << " - " << m_detID->phi_module(element->identify()) << " - " << m_detID->eta_module(element->identify()) << " - " << "size: " << processedElements.size()); + ATH_MSG_DEBUG("In digitize of untouched elements: layer - phi - eta " << + m_detID->layer_disk(element->identify()) << " - " << m_detID->phi_module( + element->identify()) << " - " << m_detID->eta_module( + element->identify()) << " - " << "size: " << processedElements.size()); chargedDiodes->setDetectorElement(element); ATH_MSG_DEBUG("Digitize non hit element"); // Create and store RDO and SDO - PixelRDO_Collection *RDOColl = new PixelRDO_Collection(chargedDiodes->identifyHash()); + PixelRDO_Collection* RDOColl = new PixelRDO_Collection(chargedDiodes->identifyHash()); RDOColl->setIdentifier(chargedDiodes->identify()); - for (unsigned int itool=0; itool<m_fesimTool.size(); itool++) { + for (unsigned int itool = 0; itool < m_fesimTool.size(); itool++) { ATH_MSG_DEBUG("Executing tool " << m_fesimTool[itool]->name()); - m_fesimTool[itool]->process(*chargedDiodes,*RDOColl, rndmEngine); + m_fesimTool[itool]->process(*chargedDiodes, *RDOColl, rndmEngine); } - ATH_CHECK(m_rdoContainer->addCollection(RDOColl,RDOColl->identifyHash())); + ATH_CHECK(m_rdoContainer->addCollection(RDOColl, RDOColl->identifyHash())); ATH_MSG_DEBUG("Pixel RDOs '" << RDOColl->identifyHash() << "' added to container"); addSDO(chargedDiodes.get()); @@ -250,7 +276,6 @@ StatusCode PixelDigitizationTool::digitizeEvent(const EventContext& ctx) { // Convert a SiTotalCharge to a InDetSimData, and store it. (this needs working...) //----------------------------------------------------------------------------------------------- void PixelDigitizationTool::addSDO(SiChargedDiodeCollection* collection) { - typedef SiTotalCharge::list_t list_t; std::vector<InDetSimData::Deposit> deposits; @@ -258,39 +283,46 @@ void PixelDigitizationTool::addSDO(SiChargedDiodeCollection* collection) { // loop over the charged diodes SiChargedDiodeIterator EndOfDiodeCollection = collection->end(); - for(SiChargedDiodeIterator i_chargedDiode=collection->begin(); i_chargedDiode!=EndOfDiodeCollection; ++i_chargedDiode) { + for (SiChargedDiodeIterator i_chargedDiode = collection->begin(); i_chargedDiode != EndOfDiodeCollection; + ++i_chargedDiode) { deposits.clear(); const list_t& charges = (*i_chargedDiode).second.totalCharge().chargeComposition(); bool real_particle_hit = false; // loop over the list - list_t::const_iterator EndOfChargeList = charges.end(); - for ( list_t::const_iterator i_ListOfCharges = charges.begin(); i_ListOfCharges!=EndOfChargeList; ++i_ListOfCharges) { - + list_t::const_iterator EndOfChargeList = charges.end(); + for (list_t::const_iterator i_ListOfCharges = charges.begin(); i_ListOfCharges != EndOfChargeList; + ++i_ListOfCharges) { const HepMcParticleLink& trkLink = i_ListOfCharges->particleLink(); int barcode = trkLink.barcode(); - if ((barcode == 0) || (barcode == m_vetoThisBarcode)){ + if ((barcode == 0) || (barcode == m_vetoThisBarcode)) { continue; } - if(!real_particle_hit) { real_particle_hit = trkLink.isValid(); } + if (!real_particle_hit) { + real_particle_hit = trkLink.isValid(); + } // check if this track number has been already used. std::vector<InDetSimData::Deposit>::reverse_iterator theDeposit = deposits.rend(); //dummy value std::vector<InDetSimData::Deposit>::reverse_iterator depositsR_end = deposits.rend(); std::vector<InDetSimData::Deposit>::reverse_iterator i_Deposit = deposits.rbegin(); - for ( ; i_Deposit != depositsR_end; ++i_Deposit) { - if( (*i_Deposit).first == trkLink ) {theDeposit = i_Deposit; break;} + for (; i_Deposit != depositsR_end; ++i_Deposit) { + if ((*i_Deposit).first == trkLink) { + theDeposit = i_Deposit; + break; + } } // if the charge has already hit the Diode add it to the deposit - if(theDeposit != depositsR_end ) (*theDeposit).second += i_ListOfCharges->charge(); + if (theDeposit != depositsR_end) (*theDeposit).second += i_ListOfCharges->charge(); else { // create a new deposit InDetSimData::Deposit deposit(trkLink, i_ListOfCharges->charge()); deposits.push_back(deposit); } } // add the simdata object to the map: - if(real_particle_hit || m_createNoiseSDO) { - m_simDataColl->insert(std::make_pair(collection->getId((*i_chargedDiode).first),InDetSimData(deposits,(*i_chargedDiode).second.flag()))); + if (real_particle_hit || m_createNoiseSDO) { + m_simDataColl->insert(std::make_pair(collection->getId((*i_chargedDiode).first), + InDetSimData(deposits, (*i_chargedDiode).second.flag()))); } } } @@ -311,8 +343,8 @@ StatusCode PixelDigitizationTool::prepareEvent(const EventContext& ctx, unsigned ATH_MSG_DEBUG("InDetSimDataCollection " << m_simDataColl.name() << " registered in StoreGate"); // Create hit collection - if(m_timedHits) delete m_timedHits; - m_timedHits = new TimedHitCollection<SiHit>(); + if (m_timedHits) delete m_timedHits; + m_timedHits = new TimedHitCollection<SiHit>(); m_HardScatterSplittingSkipper = false; return StatusCode::SUCCESS; @@ -327,7 +359,7 @@ StatusCode PixelDigitizationTool::mergeEvent(const EventContext& ctx) { // Digitize hits ATH_CHECK(digitizeEvent(ctx)); - for (std::vector<SiHitCollection*>::iterator it = m_hitCollPtrs.begin();it!=m_hitCollPtrs.end();it++) { + for (std::vector<SiHitCollection*>::iterator it = m_hitCollPtrs.begin(); it != m_hitCollPtrs.end(); it++) { (*it)->Clear(); delete(*it); } @@ -339,19 +371,26 @@ StatusCode PixelDigitizationTool::mergeEvent(const EventContext& ctx) { //======================================= // P R O C E S S B U N C H X I N G //======================================= -StatusCode PixelDigitizationTool::processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) { - +StatusCode PixelDigitizationTool::processBunchXing(int bunchXing, SubEventIterator bSubEvents, + SubEventIterator eSubEvents) { ATH_MSG_VERBOSE("PixelDigitizationTool::processBunchXing() " << bunchXing); //decide if this event will be processed depending on HardScatterSplittingMode & bunchXing - if (m_HardScatterSplittingMode==2 && !m_HardScatterSplittingSkipper) { m_HardScatterSplittingSkipper=true; return StatusCode::SUCCESS; } - if (m_HardScatterSplittingMode==1 && m_HardScatterSplittingSkipper) { return StatusCode::SUCCESS; } - if (m_HardScatterSplittingMode==1 && !m_HardScatterSplittingSkipper) { m_HardScatterSplittingSkipper=true; } + if (m_HardScatterSplittingMode == 2 && !m_HardScatterSplittingSkipper) { + m_HardScatterSplittingSkipper = true; + return StatusCode::SUCCESS; + } + if (m_HardScatterSplittingMode == 1 && m_HardScatterSplittingSkipper) { + return StatusCode::SUCCESS; + } + if (m_HardScatterSplittingMode == 1 && !m_HardScatterSplittingSkipper) { + m_HardScatterSplittingSkipper = true; + } typedef PileUpMergeSvc::TimedList<SiHitCollection>::type TimedHitCollList; TimedHitCollList hitCollList; if (!(m_mergeSvc->retrieveSubSetEvtData(m_inputObjectName, hitCollList, bunchXing, - bSubEvents, eSubEvents).isSuccess()) && + bSubEvents, eSubEvents).isSuccess()) && hitCollList.size() == 0) { ATH_MSG_ERROR("Could not fill TimedHitCollList"); return StatusCode::FAILURE; @@ -362,14 +401,15 @@ StatusCode PixelDigitizationTool::processBunchXing(int bunchXing, SubEventIterat TimedHitCollList::iterator iColl(hitCollList.begin()); TimedHitCollList::iterator endColl(hitCollList.end()); - for( ; iColl != endColl; iColl++){ - SiHitCollection *hitCollPtr = new SiHitCollection(*iColl->second); + for (; iColl != endColl; iColl++) { + SiHitCollection* hitCollPtr = new SiHitCollection(*iColl->second); PileUpTimeEventIndex timeIndex(iColl->first); ATH_MSG_DEBUG("SiHitCollection found with " << hitCollPtr->size() << " hits"); - ATH_MSG_VERBOSE("time index info. time: " << timeIndex.time() << " index: " << timeIndex.index() << " type: " << timeIndex.type()); + ATH_MSG_VERBOSE( + "time index info. time: " << timeIndex.time() << " index: " << timeIndex.index() << " type: " << + timeIndex.type()); m_timedHits->insert(timeIndex, hitCollPtr); m_hitCollPtrs.push_back(hitCollPtr); } return StatusCode::SUCCESS; } - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.h index c1da6db1a38b..b5559b3b0d68 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/PixelDigitizationTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/PixelDigitizationTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -34,59 +34,83 @@ #include "InDetReadoutGeometry/SiDetectorElementCollection.h" -class PixelDigitizationTool : public PileUpToolBase { - - public: - PixelDigitizationTool(const std::string &type, const std::string &name, const IInterface *pIID); - - virtual StatusCode initialize() override; - virtual StatusCode processAllSubEvents(const EventContext& ctx) override; - virtual StatusCode finalize() override; - - virtual StatusCode prepareEvent(const EventContext& ctx, unsigned int) override; - StatusCode digitizeEvent(const EventContext& ctx); - virtual StatusCode mergeEvent(const EventContext& ctx) override; - virtual StatusCode processBunchXing(int bunchXing, SubEventIterator bSubEvents, SubEventIterator eSubEvents) override final; - - protected: - void addSDO(SiChargedDiodeCollection *collection); - - private: - - PixelDigitizationTool(); - PixelDigitizationTool(const PixelDigitizationTool&); - PixelDigitizationTool &operator=(const PixelDigitizationTool&); - - std::vector<SiHitCollection*> m_hitCollPtrs; - - Gaudi::Property<bool> m_onlyUseContainerName{this, "OnlyUseContainerName", true, "Don't use the ReadHandleKey directly. Just extract the container name from it."}; - SG::ReadHandleKey<SiHitCollection> m_hitsContainerKey{this, "InputObjectName", "", "Input HITS collection name"}; - SG::ReadCondHandleKey<InDetDD::SiDetectorElementCollection> m_pixelDetEleCollKey{this, "PixelDetEleCollKey", "PixelDetectorElementCollection", "Key of SiDetectorElementCollection for Pixel"}; - std::string m_inputObjectName{""}; - SG::WriteHandleKey<PixelRDO_Container> m_rdoContainerKey{this, "RDOCollName", "PixelRDOs", "RDO collection name"}; - SG::WriteHandle<PixelRDO_Container> m_rdoContainer{}; - SG::WriteHandleKey<InDetSimDataCollection> m_simDataCollKey{this, "SDOCollName", "PixelSDO_Map", "SDO collection name"}; - SG::WriteHandle<InDetSimDataCollection> m_simDataColl{}; - Gaudi::Property<int> m_HardScatterSplittingMode{this, "HardScatterSplittingMode", 0, "Control pileup & signal splitting"}; - bool m_HardScatterSplittingSkipper{false}; - Gaudi::Property<bool> m_onlyHitElements{this, "OnlyHitElements", false, "Process only elements with hits"}; - - const PixelID *m_detID{}; - - - TimedHitCollection<SiHit> *m_timedHits{}; - - ToolHandleArray<SensorSimTool> m_chargeTool{this, "ChargeTools", {}, "List of charge tools"}; - ToolHandleArray<FrontEndSimTool> m_fesimTool{this, "FrontEndSimTools", {}, "List of Front-End simulation tools"}; - ToolHandle<EnergyDepositionTool> m_energyDepositionTool{this, "EnergyDepositionTool", "EnergyDepositionTool", "Energy deposition tool"}; - - protected: - - ServiceHandle<IAthRNGSvc> m_rndmSvc{this, "RndmSvc", "AthRNGSvc", ""}; //!< Random number service - ServiceHandle <PileUpMergeSvc> m_mergeSvc{this, "PileUpMergeSvc", "PileUpMergeSvc", ""}; - - Gaudi::Property<bool> m_createNoiseSDO{this, "CreateNoiseSDO", false, "Set create noise SDO flag"}; - +class PixelDigitizationTool: public PileUpToolBase { +public: + PixelDigitizationTool(const std::string& type, const std::string& name, const IInterface* pIID); + + virtual StatusCode initialize() override; + virtual StatusCode processAllSubEvents(const EventContext& ctx) override; + virtual StatusCode finalize() override; + + virtual StatusCode prepareEvent(const EventContext& ctx, unsigned int) override; + StatusCode digitizeEvent(const EventContext& ctx); + virtual StatusCode mergeEvent(const EventContext& ctx) override; + virtual StatusCode processBunchXing(int bunchXing, SubEventIterator bSubEvents, + SubEventIterator eSubEvents) override final; +protected: + void addSDO(SiChargedDiodeCollection* collection); +private: + PixelDigitizationTool(); + PixelDigitizationTool(const PixelDigitizationTool&); + PixelDigitizationTool& operator = (const PixelDigitizationTool&); + + std::vector<SiHitCollection*> m_hitCollPtrs; + + Gaudi::Property<bool> m_onlyUseContainerName { + this, "OnlyUseContainerName", true, "Don't use the ReadHandleKey directly. Just extract the container name from it." + }; + SG::ReadHandleKey<SiHitCollection> m_hitsContainerKey { + this, "InputObjectName", "", "Input HITS collection name" + }; + SG::ReadCondHandleKey<InDetDD::SiDetectorElementCollection> m_pixelDetEleCollKey { + this, "PixelDetEleCollKey", "PixelDetectorElementCollection", "Key of SiDetectorElementCollection for Pixel" + }; + std::string m_inputObjectName { + "" + }; + SG::WriteHandleKey<PixelRDO_Container> m_rdoContainerKey { + this, "RDOCollName", "PixelRDOs", "RDO collection name" + }; + SG::WriteHandle<PixelRDO_Container> m_rdoContainer {}; + SG::WriteHandleKey<InDetSimDataCollection> m_simDataCollKey { + this, "SDOCollName", "PixelSDO_Map", "SDO collection name" + }; + SG::WriteHandle<InDetSimDataCollection> m_simDataColl {}; + Gaudi::Property<int> m_HardScatterSplittingMode { + this, "HardScatterSplittingMode", 0, "Control pileup & signal splitting" + }; + bool m_HardScatterSplittingSkipper { + false + }; + Gaudi::Property<bool> m_onlyHitElements { + this, "OnlyHitElements", false, "Process only elements with hits" + }; + + const PixelID* m_detID {}; + + + TimedHitCollection<SiHit>* m_timedHits {}; + + ToolHandleArray<SensorSimTool> m_chargeTool { + this, "ChargeTools", {}, "List of charge tools" + }; + ToolHandleArray<FrontEndSimTool> m_fesimTool { + this, "FrontEndSimTools", {}, "List of Front-End simulation tools" + }; + ToolHandle<EnergyDepositionTool> m_energyDepositionTool { + this, "EnergyDepositionTool", "EnergyDepositionTool", "Energy deposition tool" + }; +protected: + ServiceHandle<IAthRNGSvc> m_rndmSvc { + this, "RndmSvc", "AthRNGSvc", "" + }; //!< Random number service + ServiceHandle <PileUpMergeSvc> m_mergeSvc { + this, "PileUpMergeSvc", "PileUpMergeSvc", "" + }; + + Gaudi::Property<bool> m_createNoiseSDO { + this, "CreateNoiseSDO", false, "Set create noise SDO flag" + }; }; #endif // PIXELDIGITIZATION_PIXELDIGITIZATIONTOOL_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.cxx index 5fa2e54cc1b3..33eb0634effd 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "RD53SimTool.h" @@ -11,9 +11,8 @@ #include "CLHEP/Random/RandFlat.h" -RD53SimTool::RD53SimTool( const std::string& type, const std::string& name,const IInterface* parent): - FrontEndSimTool(type,name,parent) -{ +RD53SimTool::RD53SimTool(const std::string& type, const std::string& name, const IInterface* parent) : + FrontEndSimTool(type, name, parent) { } RD53SimTool::~RD53SimTool() { } @@ -22,155 +21,182 @@ StatusCode RD53SimTool::initialize() { CHECK(FrontEndSimTool::initialize()); ATH_MSG_DEBUG("RD53SimTool::initialize()"); - return StatusCode::SUCCESS; + return StatusCode::SUCCESS; } StatusCode RD53SimTool::finalize() { ATH_MSG_DEBUG("RD53SimTool::finalize()"); - return StatusCode::SUCCESS; + return StatusCode::SUCCESS; } -void RD53SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine) { +void RD53SimTool::process(SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection, + CLHEP::HepRandomEngine* rndmEngine) { + const InDetDD::PixelModuleDesign* p_design = + static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - const InDetDD::PixelModuleDesign *p_design = static_cast<const InDetDD::PixelModuleDesign*>(&(chargedDiodes.element())->design()); - if (p_design->getReadoutTechnology()!=InDetDD::PixelModuleDesign::RD53) { return; } + if (p_design->getReadoutTechnology() != InDetDD::PixelModuleDesign::RD53) { + return; + } - const PixelID* pixelId = static_cast<const PixelID *>(chargedDiodes.element()->getIdHelper()); + const PixelID* pixelId = static_cast<const PixelID*>(chargedDiodes.element()->getIdHelper()); const IdentifierHash moduleHash = pixelId->wafer_hash(chargedDiodes.identify()); // wafer hash Identifier moduleID = pixelId->wafer_id(chargedDiodes.element()->identify()); - int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); - int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); + int barrel_ec = pixelId->barrel_ec(chargedDiodes.element()->identify()); + int layerIndex = pixelId->layer_disk(chargedDiodes.element()->identify()); - if (abs(barrel_ec)!=m_BarrelEC) { return; } + if (abs(barrel_ec) != m_BarrelEC) { + return; + } SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); SG::ReadCondHandle<PixelChargeCalibCondData> calibData(m_chargeDataKey); //int maxRD53SmallHit = 0; unused - int overflowToT = moduleData->getFEI4OverflowToT(barrel_ec,layerIndex); + int overflowToT = moduleData->getFEI4OverflowToT(barrel_ec, layerIndex); std::vector<Pixel1RawData*> p_rdo_small_fei4; //int nSmallHitsRD53 = 0; unused std::vector<int> row, col; const int maxRow = p_design->rowsPerCircuit(); const int maxCol = p_design->columnsPerCircuit(); - std::vector<std::vector<int>> RD53Map(maxRow+16,std::vector<int>(maxCol+16)); + std::vector<std::vector<int> > RD53Map(maxRow + 16, std::vector<int>(maxCol + 16)); // Add cross-talk - CrossTalk(moduleData->getCrossTalk(barrel_ec,layerIndex),chargedDiodes); + CrossTalk(moduleData->getCrossTalk(barrel_ec, layerIndex), chargedDiodes); if (m_doNoise) { // Add thermal noise - ThermalNoise(moduleData->getThermalNoise(barrel_ec,layerIndex),chargedDiodes,rndmEngine); + ThermalNoise(moduleData->getThermalNoise(barrel_ec, layerIndex), chargedDiodes, rndmEngine); // Add random noise - RandomNoise(chargedDiodes,rndmEngine); + RandomNoise(chargedDiodes, rndmEngine); } // Add random diabled pixels - RandomDisable(chargedDiodes,rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs? - - for (SiChargedDiodeIterator i_chargedDiode=chargedDiodes.begin(); i_chargedDiode!=chargedDiodes.end(); ++i_chargedDiode) { + RandomDisable(chargedDiodes, rndmEngine); // FIXME How should we handle disabling pixels in Overlay jobs? + for (SiChargedDiodeIterator i_chargedDiode = chargedDiodes.begin(); i_chargedDiode != chargedDiodes.end(); + ++i_chargedDiode) { Identifier diodeID = chargedDiodes.getId((*i_chargedDiode).first); double charge = (*i_chargedDiode).second.charge(); - int circ = m_pixelCabling->getFE(&diodeID,moduleID); + int circ = m_pixelCabling->getFE(&diodeID, moduleID); int type = m_pixelCabling->getPixelType(diodeID); // Apply analogu threshold, timing simulation - double th0 = calibData->getAnalogThreshold((int)moduleHash, circ, type); + double th0 = calibData->getAnalogThreshold((int) moduleHash, circ, type); - double threshold = th0+calibData->getAnalogThresholdSigma((int)moduleHash,circ,type)*CLHEP::RandGaussZiggurat::shoot(rndmEngine)+calibData->getAnalogThresholdNoise((int)moduleHash, circ, type)*CLHEP::RandGaussZiggurat::shoot(rndmEngine); // This noise check is unaffected by digitizationFlags.doInDetNoise in 21.0 - see PixelCellDiscriminator.cxx in that branch - - if (charge>threshold) { + double threshold = th0 + + calibData->getAnalogThresholdSigma((int) moduleHash, circ, + type) * CLHEP::RandGaussZiggurat::shoot(rndmEngine) + + calibData->getAnalogThresholdNoise((int) moduleHash, circ, + type) + * + CLHEP::RandGaussZiggurat::shoot(rndmEngine); // This noise check is unaffected by digitizationFlags.doInDetNoise in 21.0 - see PixelCellDiscriminator.cxx in that branch + if (charge > threshold) { int bunchSim = 0; if ((*i_chargedDiode).second.totalCharge().fromTrack()) { - bunchSim = static_cast<int>(floor((getG4Time((*i_chargedDiode).second.totalCharge())+moduleData->getTimeOffset(barrel_ec,layerIndex))/moduleData->getBunchSpace())); - } - else { - bunchSim = CLHEP::RandFlat::shootInt(rndmEngine,moduleData->getNumberOfBCID(barrel_ec,layerIndex)); + bunchSim = + static_cast<int>(floor((getG4Time((*i_chargedDiode).second.totalCharge()) + + moduleData->getTimeOffset(barrel_ec, layerIndex)) / moduleData->getBunchSpace())); + } else { + bunchSim = CLHEP::RandFlat::shootInt(rndmEngine, moduleData->getNumberOfBCID(barrel_ec, layerIndex)); } - if (bunchSim<0 || bunchSim>moduleData->getNumberOfBCID(barrel_ec,layerIndex)) { SiHelper::belowThreshold((*i_chargedDiode).second,true,true); } - else { SiHelper::SetBunch((*i_chargedDiode).second,bunchSim); } - } - else { - SiHelper::belowThreshold((*i_chargedDiode).second,true,true); + if (bunchSim < 0 || bunchSim > moduleData->getNumberOfBCID(barrel_ec, layerIndex)) { + SiHelper::belowThreshold((*i_chargedDiode).second, true, true); + } else { + SiHelper::SetBunch((*i_chargedDiode).second, bunchSim); + } + } else { + SiHelper::belowThreshold((*i_chargedDiode).second, true, true); } // charge to ToT conversion - double tot = calibData->getToT((int)moduleHash, circ, type, charge); - double totsig = calibData->getTotRes((int)moduleHash, circ, tot); - int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine,tot,totsig)); + double tot = calibData->getToT((int) moduleHash, circ, type, charge); + double totsig = calibData->getTotRes((int) moduleHash, circ, tot); + int nToT = static_cast<int>(CLHEP::RandGaussZiggurat::shoot(rndmEngine, tot, totsig)); - if (nToT<1) { nToT=1; } + if (nToT < 1) { + nToT = 1; + } // RD53 HitDiscConfig - if (nToT>=overflowToT) { nToT=overflowToT; } + if (nToT >= overflowToT) { + nToT = overflowToT; + } - if (nToT<=moduleData->getToTThreshold(barrel_ec,layerIndex)) { SiHelper::belowThreshold((*i_chargedDiode).second,true,true); } + if (nToT <= moduleData->getToTThreshold(barrel_ec, layerIndex)) { + SiHelper::belowThreshold((*i_chargedDiode).second, true, true); + } // Filter events - if (SiHelper::isMaskOut((*i_chargedDiode).second)) { continue; } - if (SiHelper::isDisabled((*i_chargedDiode).second)) { continue; } + if (SiHelper::isMaskOut((*i_chargedDiode).second)) { + continue; + } + if (SiHelper::isDisabled((*i_chargedDiode).second)) { + continue; + } - if (!m_pixelConditionsTool->isActive(moduleHash,diodeID)) { - SiHelper::disabled((*i_chargedDiode).second,true,true); + if (!m_pixelConditionsTool->isActive(moduleHash, diodeID)) { + SiHelper::disabled((*i_chargedDiode).second, true, true); continue; } - int flag = (*i_chargedDiode).second.flag(); - int bunch = (flag>>8)&0xff; + int flag = (*i_chargedDiode).second.flag(); + int bunch = (flag >> 8) & 0xff; - InDetDD::SiReadoutCellId cellId=(*i_chargedDiode).second.getReadoutCell(); + InDetDD::SiReadoutCellId cellId = (*i_chargedDiode).second.getReadoutCell(); const Identifier id_readout = chargedDiodes.element()->identifierFromCellId(cellId); int iirow = cellId.phiIndex(); int iicol = cellId.etaIndex(); - if (iicol>=maxCol) { iicol=iicol-maxCol; } // RD53 copy mechanism works per FE. + if (iicol >= maxCol) { + iicol = iicol - maxCol; + } // RD53 copy mechanism works per FE. // Front-End simulation - if (bunch>=0 && bunch<moduleData->getNumberOfBCID(barrel_ec,layerIndex)) { - Pixel1RawData *p_rdo = new Pixel1RawData(id_readout,nToT,bunch,0,bunch); + if (bunch >= 0 && bunch < moduleData->getNumberOfBCID(barrel_ec, layerIndex)) { + Pixel1RawData* p_rdo = new Pixel1RawData(id_readout, nToT, bunch, 0, bunch); //see commented code below for clarification why this is always executed rdoCollection.push_back(p_rdo); RD53Map[iirow][iicol] = 2; //Flag for "big hits" // // /** - if (nToT>maxRD53SmallHit) { //this must be true, since maxRD53SmallHit is zero, and + if (nToT>maxRD53SmallHit) { //this must be true, since maxRD53SmallHit is zero, and // nToT is at least 1 - rdoCollection.push_back(p_rdo); - RD53Map[iirow][iicol] = 2; //Flag for "big hits" - } - //So the following code is never reached; I leave it here assuming the developer will - //revisit it. + rdoCollection.push_back(p_rdo); + RD53Map[iirow][iicol] = 2; //Flag for "big hits" + } + //So the following code is never reached; I leave it here assuming the developer will + //revisit it. else { - p_rdo_small_fei4.push_back(p_rdo); - row.push_back(iirow); - col.push_back(iicol); - RD53Map[iirow][iicol] = 1; //Flag for low hits - nSmallHitsRD53++; - } **/ + p_rdo_small_fei4.push_back(p_rdo); + row.push_back(iirow); + col.push_back(iicol); + RD53Map[iirow][iicol] = 1; //Flag for low hits + nSmallHitsRD53++; + } **/ p_rdo = nullptr; } } // again, the following code is never reached but left here for the developer to comment // Copy mechanism for IBL small hits: /** - if (nSmallHitsRD53>0) { - bool recorded = false; + if (nSmallHitsRD53>0) { + bool recorded = false; - //First case: Record small hits which are in the same Pixel Digital Region than a big hit: - for (int ismall=0; ismall<nSmallHitsRD53; ismall++) { + //First case: Record small hits which are in the same Pixel Digital Region than a big hit: + for (int ismall=0; ismall<nSmallHitsRD53; ismall++) { int rowPDR = row[ismall]/2; int colPDR = col[ismall]/2; for (int rowBigHit=2*rowPDR; rowBigHit!=2*rowPDR+2 && rowBigHit<maxRow; ++rowBigHit) { for (int colBigHit=2*colPDR; colBigHit!=2*colPDR+2 && colBigHit<maxCol; ++colBigHit) { - ATH_MSG_DEBUG("rowBig = " << rowBigHit << " colBig = " << colBigHit << " Map Content = " << RD53Map[rowBigHit][colBigHit]); + ATH_MSG_DEBUG("rowBig = " << rowBigHit << " colBig = " << colBigHit << " Map Content = " << + RD53Map[rowBigHit][colBigHit]); if (RD53Map[rowBigHit][colBigHit]==2 && !recorded) { rdoCollection.push_back(p_rdo_small_fei4[ismall]); recorded = true; @@ -191,10 +217,8 @@ void RD53SimTool::process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Colle recorded = true; } } - } - } - **/ + } + } + **/ return; } - - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.h index c338b05d721b..0f382223a27d 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/RD53SimTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/RD53SimTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -14,19 +14,17 @@ #include "AthenaBaseComps/AthAlgTool.h" #include "FrontEndSimTool.h" -class RD53SimTool:public FrontEndSimTool { - - public: - RD53SimTool( const std::string& type, const std::string& name,const IInterface* parent); - - virtual StatusCode initialize(); - virtual StatusCode finalize(); - virtual ~RD53SimTool(); - virtual void process(SiChargedDiodeCollection &chargedDiodes,PixelRDO_Collection &rdoCollection, CLHEP::HepRandomEngine *rndmEngine); - - private: - RD53SimTool(); - +class RD53SimTool: public FrontEndSimTool { +public: + RD53SimTool(const std::string& type, const std::string& name, const IInterface* parent); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual ~RD53SimTool(); + virtual void process(SiChargedDiodeCollection& chargedDiodes, PixelRDO_Collection& rdoCollection, + CLHEP::HepRandomEngine* rndmEngine); +private: + RD53SimTool(); }; #endif // PIXELDIGITIZATION_RD53SimTool_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.cxx index 440a2e9f552d..6a1a6c766cfa 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "RadDamageUtil.h" @@ -33,10 +33,10 @@ using namespace std; // Constructor with parameters: -RadDamageUtil::RadDamageUtil(const std::string& type, const std::string& name,const IInterface* parent): - AthAlgTool(type,name,parent) {} +RadDamageUtil::RadDamageUtil(const std::string& type, const std::string& name, const IInterface* parent) : + AthAlgTool(type, name, parent) {} -RadDamageUtil::~RadDamageUtil(){} +RadDamageUtil::~RadDamageUtil() {} //======================================= // I N I T I A L I Z E @@ -47,87 +47,90 @@ StatusCode RadDamageUtil::initialize() { ATH_MSG_DEBUG("You are using RadDamageUtil for solid-state silicon detectors."); return StatusCode::SUCCESS; } - + //======================================= // G E N E R A T E R A M O M A P //======================================= -// The third of the 3 maps should be the most accurate. +// The third of the 3 maps should be the most accurate. // See doc/RadDamageDefaults.pdf in the Allpix repo for details. // See ATL-COM-INDET-2018-011 for details. //======================================= -const StatusCode RadDamageUtil::generateRamoMap( TH3F* ramoPotentialMap, InDetDD::PixelModuleDesign* module){ - +const StatusCode RadDamageUtil::generateRamoMap(TH3F* ramoPotentialMap, InDetDD::PixelModuleDesign* module) { //TODO: this needs to come from DB double pitchX = 0.05; double pitchY = 0.25; //TODO: from PixelModuleDesign double sensorThickness = module->thickness() * 1000.0;//default 200; - - //Ramo potential evaluated up to 2x pitch away - //from the center of the primary pixel. + + //Ramo potential evaluated up to 2x pitch away + //from the center of the primary pixel. double xmin = 0.; - double xmax = 2*pitchX*1000; + double xmax = 2 * pitchX * 1000; double ymin = 0.; - double ymax = 2*pitchY*1000; + double ymax = 2 * pitchY * 1000; //One bin per 10 microns. - ramoPotentialMap = new TH3F("hramomap1","hramomap1",((xmax-xmin)/10.), xmin, xmax, ((ymax-ymin)/10.), ymin, ymax, int(sensorThickness*1000)/10, 0., sensorThickness*1000.); - + ramoPotentialMap = new TH3F("hramomap1", "hramomap1", ((xmax - xmin) / 10.), xmin, xmax, ((ymax - ymin) / 10.), ymin, + ymax, int(sensorThickness * 1000) / 10, 0., sensorThickness * 1000.); + //****************** //*** Loop in z *** //****************** - for (int k=1; k <= ramoPotentialMap->GetNbinsZ(); k++){ - + for (int k = 1; k <= ramoPotentialMap->GetNbinsZ(); k++) { //use the lower bin edge. - double z = ramoPotentialMap->GetZaxis()->GetBinCenter(k) - ramoPotentialMap->GetZaxis()->GetBinWidth(k)/2.; + double z = ramoPotentialMap->GetZaxis()->GetBinCenter(k) - ramoPotentialMap->GetZaxis()->GetBinWidth(k) / 2.; //****************** //*** Loop in x,y *** //****************** - for (int i=1; i <= ramoPotentialMap->GetNbinsX(); i++){ //Loop over x - for (int j=1; j <= ramoPotentialMap->GetNbinsY(); j++){ //loop over y - - double x = ramoPotentialMap->GetXaxis()->GetBinCenter(i) - ramoPotentialMap->GetXaxis()->GetBinWidth(i)/2.; - double y = ramoPotentialMap->GetYaxis()->GetBinCenter(j) - ramoPotentialMap->GetYaxis()->GetBinWidth(j)/2.; + for (int i = 1; i <= ramoPotentialMap->GetNbinsX(); i++) { //Loop over x + for (int j = 1; j <= ramoPotentialMap->GetNbinsY(); j++) { //loop over y + double x = ramoPotentialMap->GetXaxis()->GetBinCenter(i) - ramoPotentialMap->GetXaxis()->GetBinWidth(i) / 2.; + double y = ramoPotentialMap->GetYaxis()->GetBinCenter(j) - ramoPotentialMap->GetYaxis()->GetBinWidth(j) / 2.; //******************************* //*** Option A: 1D approx. in z //******************************* - if (m_defaultRamo==-1) { - if (x>(pitchX*1000.0*0.5) || y>(pitchY*1000.0*0.5)) { - ramoPotentialMap->SetBinContent(i,j,k,0.01); //outside of the primary pixel. + if (m_defaultRamo == -1) { + if (x > (pitchX * 1000.0 * 0.5) || y > (pitchY * 1000.0 * 0.5)) { + ramoPotentialMap->SetBinContent(i, j, k, 0.01); //outside of the primary pixel. //TODO what is the last bin value? Is 0.01 the min? - } - else { + } else { //TODO make sure all of these eta/phi values make sense for non-barrel modules too //The formula below parameterises the 1D Ramo potential. See ATL-COM-INDET-2018-011 for details. - double par_a = 3*sensorThickness/pitchY; - double norm = exp(-par_a)+exp(-1.0); - double val = exp(-par_a*z/(1000.0*sensorThickness))+exp(-z/(1000*sensorThickness)); + double par_a = 3 * sensorThickness / pitchY; + double norm = exp(-par_a) + exp(-1.0); + double val = exp(-par_a * z / (1000.0 * sensorThickness)) + exp(-z / (1000 * sensorThickness)); val -= norm; - val /= (2.0-norm); - ramoPotentialMap->SetBinContent(i,j,k,val); + val /= (2.0 - norm); + ramoPotentialMap->SetBinContent(i, j, k, val); } - } + } //******************************* //*** Option B: 2D approx. in xy //******************************* - else if (m_defaultRamo==0) { + else if (m_defaultRamo == 0) { double par_a = 10.0; - double norm = exp( -par_a ) + exp(-1.); - double val = exp( -par_a*z/(1000*sensorThickness) ) + exp( -z/(1000*sensorThickness) ); + double norm = exp(-par_a) + exp(-1.); + double val = exp(-par_a * z / (1000 * sensorThickness)) + exp(-z / (1000 * sensorThickness)); val -= norm; - val /= ( 2.-norm ); + val /= (2. - norm); //From equation 16 in the RadDamageDefaults support note, using solution for weighting potential in 2D - double productSolution = weighting2D(x,z,pitchX,sensorThickness) * weighting2D(y,z,pitchY,sensorThickness) * val / (weighting2D(0,z,pitchX,sensorThickness) * weighting2D(0,z,pitchY,sensorThickness)); - ramoPotentialMap->SetBinContent(i,j,k, productSolution); - } + double productSolution = weighting2D(x, z, pitchX, sensorThickness) * weighting2D(y, z, pitchY, + sensorThickness) * val / + (weighting2D(0, z, pitchX, + sensorThickness) * weighting2D(0, z, pitchY, sensorThickness)); + ramoPotentialMap->SetBinContent(i, j, k, productSolution); + } //************************************************ //*** Option C: Poisson's eqn. w/ simple geometry //************************************************ - else if (m_defaultRamo>0) { - double fullSolution = weighting3D( x/sensorThickness,y/sensorThickness,z/sensorThickness,m_defaultRamo,m_defaultRamo,4,pitchX/sensorThickness,pitchY/sensorThickness); //N = 4 is arbitrary; just need something bigger than ~1 - ramoPotentialMap->SetBinContent(i,j,k,fullSolution); + else if (m_defaultRamo > 0) { + double fullSolution = weighting3D(x / sensorThickness, y / sensorThickness, z / sensorThickness, + m_defaultRamo, m_defaultRamo, 4, pitchX / sensorThickness, + pitchY / sensorThickness); //N = 4 is arbitrary; just need something bigger + // than ~1 + ramoPotentialMap->SetBinContent(i, j, k, fullSolution); }//Ramo option > 0. }//loop over y. }//loop over x. @@ -136,12 +139,12 @@ const StatusCode RadDamageUtil::generateRamoMap( TH3F* ramoPotentialMap, InDetDD } //TODO: What about debugging the ramo potential? I vaguely remember running into issues with this. //======================================= -// A L P H A +// A L P H A //======================================= -//Constituent of full poisson solution. +//Constituent of full poisson solution. //Last terms in eqn. 18, 19 in support note -double RadDamageUtil::alpha(int n, int Nrep, double a){ - return ( (2*TMath::Pi()*n) / (Nrep*a)); +double RadDamageUtil::alpha(int n, int Nrep, double a) { + return((2 * TMath::Pi() * n) / (Nrep * a)); } //======================================= @@ -149,125 +152,127 @@ double RadDamageUtil::alpha(int n, int Nrep, double a){ //======================================= //Approx, solution to Poisson's eqn. with simplified geometry //See section 1.3 in support note for details -double RadDamageUtil::weighting3D(double x, double y, double z, int n, int m, int Nrep, double a, double b){ - - //TODO: talk to ben about this comment: - //be warned that there is numerical instability if n and m are too large! Suggest n ~ m ~ 10. +double RadDamageUtil::weighting3D(double x, double y, double z, int n, int m, int Nrep, double a, double b) { + //TODO: talk to ben about this comment: + //be warned that there is numerical instability if n and m are too large! Suggest n ~ m ~ 10. double potential = 0.; double pi = TMath::Pi(); - for (int i=-n; i<=n; i++){ - for (int j=-m; j<=m; j++){ + for (int i = -n; i <= n; i++) { + for (int j = -m; j <= m; j++) { double X = 0.; double Y = 0.; double Z = 0.; double factor_x = 0.; double factor_y = 0.; - if (i==0 && j==0){ - factor_x = 1./Nrep; + if (i == 0 && j == 0) { + factor_x = 1. / Nrep; factor_y = factor_x; - Z = 1-z; + Z = 1 - z; } else { //Equation 18 & 19 in support note - factor_x = std::sin( i*pi/Nrep )/ (pi*i); - factor_y = std::sin( j*pi/Nrep )/ (pi*j); + factor_x = std::sin(i * pi / Nrep) / (pi * i); + factor_y = std::sin(j * pi / Nrep) / (pi * j); //Equation 17 in support note - double norm = std::sqrt( std::pow( alpha(i,Nrep,a),2) + std::pow( alpha(j,Nrep,b),2) ); - Z = sinh(norm*(1-z))/sinh(norm); + double norm = std::sqrt(std::pow(alpha(i, Nrep, a), 2) + std::pow(alpha(j, Nrep, b), 2)); + Z = sinh(norm * (1 - z)) / sinh(norm); } //Equation 18 & 19 in support note - X = factor_x*std::cos( alpha(i,Nrep,a)*x ); - Y = factor_y*std::cos( alpha(j,Nrep,b)*y ); + X = factor_x * std::cos(alpha(i, Nrep, a) * x); + Y = factor_y * std::cos(alpha(j, Nrep, b) * y); //Equation 20 in support note - potential+= Z * X * Y; + potential += Z * X * Y; } } return potential; -} +} //======================================= //W E I G H T I N G 2 D //======================================= //Solution to Poisson's equation for a 2D inf. strip //i.e. weighting potential with 2D solution -double RadDamageUtil::weighting2D(double x, double z, double Lx, double sensorThickness){ - - if (z==0) z=0.00001;//a pathology in the definition. - double pi = 4.*TMath::ATan(1.); +double RadDamageUtil::weighting2D(double x, double z, double Lx, double sensorThickness) { + if (z == 0) z = 0.00001; //a pathology in the definition. + double pi = 4. * TMath::ATan(1.); //scale to binsize (inputs assumed to be in mm) sensorThickness *= 1000.; Lx *= 1000; - + //val is set according to equation 3 in the radDamageDefaults support note - double val = (TMath::Sin(pi*z/sensorThickness)*TMath::SinH(0.5*pi*Lx/sensorThickness)/(TMath::CosH(pi*x/sensorThickness)-TMath::Cos(pi*z/sensorThickness)*TMath::CosH(0.5*pi*Lx/sensorThickness))); - if (val > 0) return TMath::ATan(val)/pi; - else return TMath::ATan(val)/pi+1; + double val = + (TMath::Sin(pi * z / sensorThickness) * TMath::SinH(0.5 * pi * Lx / sensorThickness) / + (TMath::CosH(pi * x / sensorThickness) - TMath::Cos(pi * z / sensorThickness) * + TMath::CosH(0.5 * pi * Lx / sensorThickness))); + if (val > 0) return TMath::ATan(val) / pi; + else return TMath::ATan(val) / pi + 1; } //========================================= // G E N E R A T E E - F I E L D M A P //========================================= -const StatusCode RadDamageUtil::generateEfieldMap( TH1F*& eFieldMap, InDetDD::PixelModuleDesign* module ){ - - //TODO: from DB - double biasVoltage = 600.; - double sensorThickness = module->thickness(); //default should be 0.2? - double fluence = 8.;//*e14 neq/cm^2 - eFieldMap = new TH1F("hefieldz","hefieldz",200,0,sensorThickness*1e3); - - std::string TCAD_list = PathResolver::find_file("ibl_TCAD_EfieldProfiles.txt", "DATAPATH"); //IBL layer - if(sensorThickness > 0.2){ - //is blayer - TCAD_list = PathResolver::find_file("blayer_TCAD_EfieldProfiles.txt", "DATAPATH"); //B layer - if(sensorThickness > 0.25){ - ATH_MSG_WARNING("Sensor thickness ("<< sensorThickness << "mm) does not match geometry provided in samples"); - return StatusCode::FAILURE; - } +const StatusCode RadDamageUtil::generateEfieldMap(TH1F*& eFieldMap, InDetDD::PixelModuleDesign* module) { + //TODO: from DB + double biasVoltage = 600.; + double sensorThickness = module->thickness(); //default should be 0.2? + double fluence = 8.;//*e14 neq/cm^2 + + eFieldMap = new TH1F("hefieldz", "hefieldz", 200, 0, sensorThickness * 1e3); + + std::string TCAD_list = PathResolver::find_file("ibl_TCAD_EfieldProfiles.txt", "DATAPATH"); //IBL layer + if (sensorThickness > 0.2) { + //is blayer + TCAD_list = PathResolver::find_file("blayer_TCAD_EfieldProfiles.txt", "DATAPATH"); //B layer + if (sensorThickness > 0.25) { + ATH_MSG_WARNING("Sensor thickness (" << sensorThickness << "mm) does not match geometry provided in samples"); + return StatusCode::FAILURE; } + } - CHECK( m_EfieldInterpolator->loadTCADlist(TCAD_list) ); - eFieldMap = (TH1F*) m_EfieldInterpolator->getEfield(fluence , biasVoltage); + CHECK(m_EfieldInterpolator->loadTCADlist(TCAD_list)); + eFieldMap = (TH1F*) m_EfieldInterpolator->getEfield(fluence, biasVoltage); return StatusCode::SUCCESS; } -StatusCode RadDamageUtil::generateEfieldMap( TH1F* &eFieldMap, InDetDD::PixelModuleDesign* /*module*/, double fluence, double biasVoltage, int layer, std::string TCAD_list, bool interpolate ){ +StatusCode RadDamageUtil::generateEfieldMap(TH1F*& eFieldMap, InDetDD::PixelModuleDesign* /*module*/, double fluence, + double biasVoltage, int layer, std::string TCAD_list, bool interpolate) { + TString id; + //TODO adapt saving location for documentation of E field interpolation + TString predirname = ""; - TString id; - //TODO adapt saving location for documentation of E field interpolation - TString predirname =""; - if(interpolate){ - id = "Interpolation"; - }else{ - id = "TCAD"; - } - if(interpolate){ - CHECK( m_EfieldInterpolator->loadTCADlist(TCAD_list) ); - eFieldMap = (TH1F*) m_EfieldInterpolator->getEfield(fluence , biasVoltage); - }else{ - //retrieve E field directly from file (needs to be .dat file with table) - CHECK( m_EfieldInterpolator->loadTCADlist(TCAD_list) ); - ATH_MSG_INFO("Load Efield map from " << TCAD_list ); - } - if(!eFieldMap){ - ATH_MSG_ERROR("E field has not been created!"); - return StatusCode::FAILURE; - } - //For debugging save map - //TCAD_list.ReplaceAll(".txt","_map.root"); - TString dirname = "layer"; - dirname+=layer; - dirname+="_fl"; - dirname+=TString::Format("%.1f",fluence/(float)(1e14)); - dirname+="e14_U"; - dirname+=TString::Format("%.0f",biasVoltage); - dirname+=id; - dirname.ReplaceAll(".","-"); - dirname = predirname + dirname; - dirname+=(".root"); - eFieldMap->SaveAs(dirname.Data()); - return StatusCode::SUCCESS; + if (interpolate) { + id = "Interpolation"; + } else { + id = "TCAD"; + } + if (interpolate) { + CHECK(m_EfieldInterpolator->loadTCADlist(TCAD_list)); + eFieldMap = (TH1F*) m_EfieldInterpolator->getEfield(fluence, biasVoltage); + } else { + //retrieve E field directly from file (needs to be .dat file with table) + CHECK(m_EfieldInterpolator->loadTCADlist(TCAD_list)); + ATH_MSG_INFO("Load Efield map from " << TCAD_list); + } + if (!eFieldMap) { + ATH_MSG_ERROR("E field has not been created!"); + return StatusCode::FAILURE; + } + //For debugging save map + //TCAD_list.ReplaceAll(".txt","_map.root"); + TString dirname = "layer"; + dirname += layer; + dirname += "_fl"; + dirname += TString::Format("%.1f", fluence / (float) (1e14)); + dirname += "e14_U"; + dirname += TString::Format("%.0f", biasVoltage); + dirname += id; + dirname.ReplaceAll(".", "-"); + dirname = predirname + dirname; + dirname += (".root"); + eFieldMap->SaveAs(dirname.Data()); + return StatusCode::SUCCESS; } //================================================== @@ -276,173 +281,175 @@ StatusCode RadDamageUtil::generateEfieldMap( TH1F* &eFieldMap, InDetDD::PixelMod //Currently, if one is missing, all 3 have to be regenerated. //It IS possible to split them up but riht now that means lots of repeated code. //Might be worth coming back in the future if it needs to be optimised or -//if -const StatusCode RadDamageUtil::generateDistanceTimeMap( TH2F* &distanceMap_e, TH2F* &distanceMap_h, TH1F* &timeMap_e, TH1F* &timeMap_h, TH2F* &lorentzMap_e, TH2F* &lorentzMap_h, TH1F* &eFieldMap, InDetDD::PixelModuleDesign* module ){ - // Implementation for precomputed maps - //https://gitlab.cern.ch/radiationDamageDigitization/radDamage_athena_rel22/blob/rel22_radDamageDev_master/scripts/SaveMapsForAthena.C - //TODO: From DB call each time - double temperature = 300; - double bField = 2;//Tesla - //From PixelModuleDesign: TODO - //FIXME workaround, if PixelModuleDesign not available: retrieve sensor thickness from E field - //double sensorThickness = module->thickness() * 1000.0;//default is 200; - double sensorThickness = 0.2; //mm - //Check if x axis (sensor depth) of E field larger than IBL sensors - if(eFieldMap->GetXaxis()->GetXmax() > 210 ){ //Efield in um - sensorThickness = 0.250; - } - if(module){ - sensorThickness = module->thickness() * 1000.0;//default is 200; +//if +const StatusCode RadDamageUtil::generateDistanceTimeMap(TH2F*& distanceMap_e, TH2F*& distanceMap_h, TH1F*& timeMap_e, + TH1F*& timeMap_h, TH2F*& lorentzMap_e, TH2F*& lorentzMap_h, + TH1F*& eFieldMap, InDetDD::PixelModuleDesign* module) { + // Implementation for precomputed maps + //https://gitlab.cern.ch/radiationDamageDigitization/radDamage_athena_rel22/blob/rel22_radDamageDev_master/scripts/SaveMapsForAthena.C + //TODO: From DB call each time + double temperature = 300; + double bField = 2;//Tesla + //From PixelModuleDesign: TODO + //FIXME workaround, if PixelModuleDesign not available: retrieve sensor thickness from E field + //double sensorThickness = module->thickness() * 1000.0;//default is 200; + double sensorThickness = 0.2; //mm + + //Check if x axis (sensor depth) of E field larger than IBL sensors + if (eFieldMap->GetXaxis()->GetXmax() > 210) { //Efield in um + sensorThickness = 0.250; + } + if (module) { + sensorThickness = module->thickness() * 1000.0;//default is 200; + } + + //Y-axis is time charge carrier travelled for, + //X-axis is initial position of charge carrier, + //Z-axis is final position of charge carrier + distanceMap_e = new TH2F("edistance", "Electron Distance Map", 100, 0, sensorThickness, 1000, 0, 1000); //mm by ns + distanceMap_h = new TH2F("hdistance", "Holes Distance Map", 100, 0, sensorThickness, 1000, 0, 1000); + //Initalize distance maps + for (int i = 1; i <= distanceMap_e->GetNbinsX(); i++) { + for (int j = 1; j <= distanceMap_e->GetNbinsY(); j++) { + distanceMap_h->SetBinContent(i, j, sensorThickness); //if you travel long enough, you will reach the electrode. + distanceMap_e->SetBinContent(i, j, 0.); //if you travel long enough, you will reach the electrode. } - - //Y-axis is time charge carrier travelled for, - //X-axis is initial position of charge carrier, - //Z-axis is final position of charge carrier - distanceMap_e = new TH2F("edistance","Electron Distance Map",100,0,sensorThickness,1000,0,1000); //mm by ns - distanceMap_h = new TH2F("hdistance","Holes Distance Map",100,0,sensorThickness,1000,0,1000); - //Initalize distance maps - for (int i=1; i<= distanceMap_e->GetNbinsX(); i++){ - for (int j=1; j<= distanceMap_e->GetNbinsY(); j++){ - distanceMap_h->SetBinContent(i,j,sensorThickness); //if you travel long enough, you will reach the electrode. - distanceMap_e->SetBinContent(i,j,0.); //if you travel long enough, you will reach the electrode. + } + + //From a given place in the sensor bulk, show time-to-electrode + timeMap_e = new TH1F("etimes", "Electron Time Map", 100, 0, sensorThickness); //mm + timeMap_h = new TH1F("htimes", "Hole Time Map", 100, 0, sensorThickness); //mm + + //X axis is initial position of charge carrier (in z) + //Y axis is distance travelled in z by charge carrier + //Z axis is tan( lorentz_angle ) + lorentzMap_e = new TH2F("lorentz_map_e", "Lorentz Map e", 100, 0, sensorThickness, 100, 0, sensorThickness); //mm by mm + lorentzMap_h = new TH2F("lorentz_map_h", "Lorentz Map h", 100, 0, sensorThickness, 100, 0, sensorThickness); //mm by mm + ATH_MSG_DEBUG("Did not find time and/or distance maps. Will compute them from the E-field map.."); + + for (int i = 1; i <= distanceMap_e->GetNbinsX(); i++) { //Loop over initial position of charge carrier (in z) + double time_e = 0.; //ns + double time_h = 0.; //ns + double distanceTravelled_e = 0; //mm + double distanceTravelled_h = 0; //mm + double drift_e = 0.; //mm + double drift_h = 0.; //mm + + for (int j = i; j >= 1; j--) { //Lower triangle + double dz = distanceMap_e->GetXaxis()->GetBinWidth(j); //mm + double z_j = distanceMap_e->GetXaxis()->GetBinCenter(j); //mm + //printf("\n \n distance map bin center i/j: %f/%f width %f (mm) \n sensor thickness: %f \n E field value: %f in + // bin %f \n ", z_i, z_j, dz, sensorThickness, Ez, z_i*1000); + // + double Ez = eFieldMap->GetBinContent(eFieldMap->GetXaxis()->FindBin(z_j * 1000)) / 1e7; // in MV/mm; + std::pair<double, double> mu = getMobility(Ez, temperature); //mm^2/MV*ns + if (Ez > 0) { + //Electrons + //double tanLorentzAngle = mu.first*bField*(1.0E-3); //rad, unit conversion; pixelPitch_eta-Field is in T = + // V*s/m^2 + double tanLorentzAngle = getTanLorentzAngle(Ez, temperature, bField, false); + time_e += dz / (mu.first * Ez); //mm * 1/(mm/ns) = ns + + //Fill: time charge carrier travelled for, given staring position (i) and final position (z_j) + distanceMap_e->SetBinContent(i, distanceMap_e->GetYaxis()->FindBin(time_e), z_j); + + drift_e += dz * tanLorentzAngle; //Increment the total drift parallel to plane of sensor + distanceTravelled_e += dz; //mm (travelled in z) + lorentzMap_e->SetBinContent(i, j, drift_e / distanceTravelled_e); } + timeMap_e->SetBinContent(i, time_e); } - - //From a given place in the sensor bulk, show time-to-electrode - timeMap_e = new TH1F("etimes","Electron Time Map",100,0,sensorThickness); //mm - timeMap_h = new TH1F("htimes","Hole Time Map",100,0,sensorThickness); //mm - - //X axis is initial position of charge carrier (in z) - //Y axis is distance travelled in z by charge carrier - //Z axis is tan( lorentz_angle ) - lorentzMap_e = new TH2F("lorentz_map_e","Lorentz Map e",100,0,sensorThickness,100,0,sensorThickness); //mm by mm - lorentzMap_h = new TH2F("lorentz_map_h","Lorentz Map h",100,0,sensorThickness,100,0,sensorThickness); //mm by mm - ATH_MSG_DEBUG ("Did not find time and/or distance maps. Will compute them from the E-field map.."); - - for (int i=1; i<= distanceMap_e->GetNbinsX(); i++){ //Loop over initial position of charge carrier (in z) - double time_e = 0.; //ns - double time_h = 0.; //ns - double distanceTravelled_e=0; //mm - double distanceTravelled_h=0; //mm - double drift_e = 0.; //mm - double drift_h = 0.; //mm - - for (int j=i; j >= 1; j--){ //Lower triangle - double dz = distanceMap_e->GetXaxis()->GetBinWidth(j); //mm - double z_j = distanceMap_e->GetXaxis()->GetBinCenter(j); //mm - //printf("\n \n distance map bin center i/j: %f/%f width %f (mm) \n sensor thickness: %f \n E field value: %f in bin %f \n ", z_i, z_j, dz, sensorThickness, Ez, z_i*1000); - // - double Ez = eFieldMap->GetBinContent(eFieldMap->GetXaxis()->FindBin(z_j*1000))/1e7; // in MV/mm; - std::pair<double, double> mu = getMobility(Ez, temperature); //mm^2/MV*ns - if (Ez > 0){ - - //Electrons - //double tanLorentzAngle = mu.first*bField*(1.0E-3); //rad, unit conversion; pixelPitch_eta-Field is in T = V*s/m^2 - double tanLorentzAngle = getTanLorentzAngle(Ez, temperature, bField, false); - time_e += dz/(mu.first*Ez); //mm * 1/(mm/ns) = ns - - //Fill: time charge carrier travelled for, given staring position (i) and final position (z_j) - distanceMap_e->SetBinContent(i,distanceMap_e->GetYaxis()->FindBin(time_e),z_j); - - drift_e += dz*tanLorentzAngle; //Increment the total drift parallel to plane of sensor - distanceTravelled_e += dz; //mm (travelled in z) - lorentzMap_e->SetBinContent(i,j,drift_e/distanceTravelled_e); - } - timeMap_e->SetBinContent(i,time_e); - } - //Mainly copied from l416 ff changed naming k=>j - //https://gitlab.cern.ch/radiationDamageDigitization/radDamage_athena_rel22/blob/rel22_radDamageDev_master/scripts/SaveMapsForAthena.C - for (int j=i; j <= distanceMap_e->GetNbinsX(); j++){ //holes go the opposite direction as electrons. - - double dz = distanceMap_e->GetXaxis()->GetBinWidth(j); //similar to _h - //double Ez = eFieldMap->GetBinContent(eFieldMap->GetXaxis()->FindBin(z_i*1000))/1e7; // in MV/mm; - double z_j= distanceMap_e->GetXaxis()->GetBinCenter(j); //mm //similar to _h - double Ez = eFieldMap->GetBinContent(eFieldMap->GetXaxis()->FindBin(z_j*1000))/1e7; // in MV/mm; - std::pair<double, double> mu = getMobility(Ez, temperature); //mm^2/MV*ns - if (Ez > 0){ - //Holes - //std::pair<double, double> mu = getMobility(Ez, temperature); //mm^2/MV*ns - //double tanLorentzAngle = mu.second*bField*(1.0E-3); //rad - double tanLorentzAngle = getTanLorentzAngle(Ez, temperature,bField, true); - time_h+=dz/(mu.second*Ez); //mm * 1/(mm/ns) = ns - distanceMap_h->SetBinContent(i,distanceMap_h->GetYaxis()->FindBin(time_h),z_j); - - drift_h+=dz*tanLorentzAngle; - distanceTravelled_h += dz; //mm - lorentzMap_h->SetBinContent(i,j,drift_h/distanceTravelled_h); - } - timeMap_h->SetBinContent(i,time_h); - } - - + //Mainly copied from l416 ff changed naming k=>j + //https://gitlab.cern.ch/radiationDamageDigitization/radDamage_athena_rel22/blob/rel22_radDamageDev_master/scripts/SaveMapsForAthena.C + for (int j = i; j <= distanceMap_e->GetNbinsX(); j++) { //holes go the opposite direction as electrons. + double dz = distanceMap_e->GetXaxis()->GetBinWidth(j); //similar to _h + //double Ez = eFieldMap->GetBinContent(eFieldMap->GetXaxis()->FindBin(z_i*1000))/1e7; // in MV/mm; + double z_j = distanceMap_e->GetXaxis()->GetBinCenter(j); //mm //similar to _h + double Ez = eFieldMap->GetBinContent(eFieldMap->GetXaxis()->FindBin(z_j * 1000)) / 1e7; // in MV/mm; + std::pair<double, double> mu = getMobility(Ez, temperature); //mm^2/MV*ns + if (Ez > 0) { + //Holes + //std::pair<double, double> mu = getMobility(Ez, temperature); //mm^2/MV*ns + //double tanLorentzAngle = mu.second*bField*(1.0E-3); //rad + double tanLorentzAngle = getTanLorentzAngle(Ez, temperature, bField, true); + time_h += dz / (mu.second * Ez); //mm * 1/(mm/ns) = ns + distanceMap_h->SetBinContent(i, distanceMap_h->GetYaxis()->FindBin(time_h), z_j); + + drift_h += dz * tanLorentzAngle; + distanceTravelled_h += dz; //mm + lorentzMap_h->SetBinContent(i, j, drift_h / distanceTravelled_h); + } + timeMap_h->SetBinContent(i, time_h); } + } return StatusCode::SUCCESS; //Finally, we make maps of the average collected charge, in order to make charge chunking corrections later. //TODO: talk to Ben about the above comment. Where is code? - } + //======================================= // G E T M O B I L I T Y //======================================= -const std::pair<double,double> RadDamageUtil::getMobility(double electricField, double temperature) const{ +const std::pair<double, double> RadDamageUtil::getMobility(double electricField, double temperature) const { //Returns the electron/hole mobility *in the z direction* //Note, this already includes the Hall scattering factor! - //These parameterizations come from C. Jacoboni et al., Solid-State Electronics 20 89. (1977) 77. (see also https://cds.cern.ch/record/684187/files/indet-2001-004.pdf). + //These parameterizations come from C. Jacoboni et al., Solid-State Electronics 20 89. (1977) 77. (see also + // https://cds.cern.ch/record/684187/files/indet-2001-004.pdf). //electrons - double vsat_e = 15.3*pow(temperature,-0.87);// mm/ns - double ecrit_e = 1.01E-7*pow(temperature,1.55);// MV/mm - double beta_e = 2.57E-2*pow(temperature,0.66);//dimensionless - double r_e = 1.13+0.0008*(temperature-273.);//Hall scaling factor + double vsat_e = 15.3 * pow(temperature, -0.87);// mm/ns + double ecrit_e = 1.01E-7 * pow(temperature, 1.55);// MV/mm + double beta_e = 2.57E-2 * pow(temperature, 0.66);//dimensionless + double r_e = 1.13 + 0.0008 * (temperature - 273.);//Hall scaling factor //holes - double vsat_h = 1.62*pow(temperature,-0.52);// mm/ns - double ecrit_h = 1.24E-7*pow(temperature,1.68);// MV/mm - double beta_h = 0.46*pow(temperature,0.17); - double r_h = 0.72 - 0.0005*(temperature-273.); + double vsat_h = 1.62 * pow(temperature, -0.52);// mm/ns + double ecrit_h = 1.24E-7 * pow(temperature, 1.68);// MV/mm + double beta_h = 0.46 * pow(temperature, 0.17); + double r_h = 0.72 - 0.0005 * (temperature - 273.); - double num_e = vsat_e/ecrit_e; - double den_e = pow(1+pow((electricField/ecrit_e),beta_e),(1/beta_e)); - double mobility_e = r_e*num_e/den_e; + double num_e = vsat_e / ecrit_e; + double den_e = pow(1 + pow((electricField / ecrit_e), beta_e), (1 / beta_e)); + double mobility_e = r_e * num_e / den_e; - double num_h = vsat_h/ecrit_h; - double den_h = pow(1+pow((electricField/ecrit_h),beta_h),(1/beta_h)); - double mobility_h = r_h*num_h/den_h; + double num_h = vsat_h / ecrit_h; + double den_h = pow(1 + pow((electricField / ecrit_h), beta_h), (1 / beta_h)); + double mobility_h = r_h * num_h / den_h; - return std::make_pair( mobility_e, mobility_h ); + return std::make_pair(mobility_e, mobility_h); } //======================================= // G E T L O R E N T Z A N G L E //======================================= -//Taken from https://gitlab.cern.ch/radiationDamageDigitization/radDamage_athena_rel22/blob/rel22_radDamageDev_master/scripts/SaveMapsForAthena.C -double RadDamageUtil::getTanLorentzAngle(double electricField, double temperature, double bField, bool isHole){ - double hallEffect = 1.;//already in mobility//= 1.13 + 0.0008*(temperature - 273.0); //Hall Scattering Factor - taken from https://cds.cern.ch/record/684187/files/indet-2001-004.pdf - if (isHole) hallEffect = 0.72 - 0.0005*(temperature - 273.0); - std::pair<double,double> mobility = getMobility(electricField, temperature); - double mobility_object = mobility.first; - if(isHole) mobility_object = mobility.second; - double tanLorentz = hallEffect*mobility_object*bField*(1.0E-3); //unit conversion - return tanLorentz; +//Taken from +// https://gitlab.cern.ch/radiationDamageDigitization/radDamage_athena_rel22/blob/rel22_radDamageDev_master/scripts/SaveMapsForAthena.C +double RadDamageUtil::getTanLorentzAngle(double electricField, double temperature, double bField, bool isHole) { + double hallEffect = 1.;//already in mobility//= 1.13 + 0.0008*(temperature - 273.0); //Hall Scattering Factor - taken + // from https://cds.cern.ch/record/684187/files/indet-2001-004.pdf + + if (isHole) hallEffect = 0.72 - 0.0005 * (temperature - 273.0); + std::pair<double, double> mobility = getMobility(electricField, temperature); + double mobility_object = mobility.first; + if (isHole) mobility_object = mobility.second; + double tanLorentz = hallEffect * mobility_object * bField * (1.0E-3); //unit conversion + return tanLorentz; } - //======================================= // G E T T R A P P I N G T I M E //======================================= -const std::pair<double,double> RadDamageUtil::getTrappingTimes( double fluence) const{ - +const std::pair<double, double> RadDamageUtil::getTrappingTimes(double fluence) const { double trappingTimeElectrons(0.), trappingTimeHoles(0.); - if(fluence!=0.0){ - trappingTimeElectrons = 1.0/(m_betaElectrons*fluence); //Make memberVar - trappingTimeHoles = 1.0/(m_betaHoles*fluence); //ns - } - else{//fluence = 0 so do not trap! + if (fluence != 0.0) { + trappingTimeElectrons = 1.0 / (m_betaElectrons * fluence); //Make memberVar + trappingTimeHoles = 1.0 / (m_betaHoles * fluence); //ns + } else {//fluence = 0 so do not trap! trappingTimeElectrons = 1000; //~infinity trappingTimeHoles = 1000; } - return std::make_pair( trappingTimeElectrons, trappingTimeHoles); + return std::make_pair(trappingTimeElectrons, trappingTimeHoles); } bool RadDamageUtil::saveDebugMaps() { @@ -453,7 +460,6 @@ bool RadDamageUtil::saveDebugMaps() { // F I N A L I Z E //======================================= StatusCode RadDamageUtil::finalize() { - ATH_MSG_DEBUG ( "RadDamageUtil::finalize()"); + ATH_MSG_DEBUG("RadDamageUtil::finalize()"); return StatusCode::SUCCESS; } - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.h b/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.h index fba016124e83..1f010df7e5ea 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/RadDamageUtil.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/RadDamageUtil.h * @author Ben Nachman <Ben.Nachman@cern.ch> @@ -26,52 +26,63 @@ #include "EfieldInterpolator.h" -//==================== +//==================== // C L A S S D E F //==================== -class RadDamageUtil : public AthAlgTool { - - public: - RadDamageUtil( const std::string& type, const std::string& name,const IInterface* parent); - - virtual StatusCode initialize() override; - virtual StatusCode finalize() override; - - virtual ~RadDamageUtil(); - StatusCode initTools(); - const StatusCode generateRamoMap(TH3F* ramPotentialMap, InDetDD::PixelModuleDesign* module); - const StatusCode generateEfieldMap(TH1F*& eFieldMap, InDetDD::PixelModuleDesign* module); - StatusCode generateEfieldMap(TH1F* &eFieldMap, InDetDD::PixelModuleDesign* module, double fluence, double biasVoltage, int layer, std::string TCAD_list, bool interpolate); - const StatusCode generateDistanceTimeMap( TH2F* &distanceMap_e, TH2F* &distanceMap_h, TH1F* &timeMap_e, TH1F* &timeMap_h, TH2F* &lorentzMap_e, TH2F* &lorentzMap_h, TH1F* &eFieldMap, InDetDD::PixelModuleDesign* module); - - const std::pair<double,double> getTrappingTimes( double fluence ) const; - const std::pair<double,double> getMobility( double electricField, double temperature) const; - double getTanLorentzAngle(double electricField, double temperature, double bField, bool isHole); - - bool saveDebugMaps(); - - private: - RadDamageUtil(); - - Gaudi::Property<int> m_defaultRamo - {this, "defaultRamo", 1, "Mapping strategy of Ramo potential"}; - - Gaudi::Property<double> m_betaElectrons - {this, "betaElectrons", 4.5e-16, "Used in trapping time calculation"}; - - Gaudi::Property<double> m_betaHoles - {this, "betaHoles", 6.0e-16, "Used in trapping time calculation"}; - - Gaudi::Property<bool> m_saveDebugMaps - {this, "saveDebugMaps", false, "Flag to save map"}; - - double alpha(int n, int Nrep, double a); //Poisson solution factor - double weighting3D(double x, double y, double z, int n, int m, int Nrep, double a, double b); - double weighting2D(double x, double z, double Lx, double sensorThickness); - - ToolHandle<EfieldInterpolator> m_EfieldInterpolator - {this, "EfieldInterpolator", "EfieldInterpolator", "Create an Efield for fluence and bias volatge of interest based on TCAD samples"}; - +class RadDamageUtil: public AthAlgTool { +public: + RadDamageUtil(const std::string& type, const std::string& name, const IInterface* parent); + + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + + virtual ~RadDamageUtil(); + StatusCode initTools(); + const StatusCode generateRamoMap(TH3F* ramPotentialMap, InDetDD::PixelModuleDesign* module); + const StatusCode generateEfieldMap(TH1F*& eFieldMap, InDetDD::PixelModuleDesign* module); + StatusCode generateEfieldMap(TH1F*& eFieldMap, InDetDD::PixelModuleDesign* module, double fluence, double biasVoltage, + int layer, std::string TCAD_list, bool interpolate); + const StatusCode generateDistanceTimeMap(TH2F*& distanceMap_e, TH2F*& distanceMap_h, TH1F*& timeMap_e, + TH1F*& timeMap_h, TH2F*& lorentzMap_e, TH2F*& lorentzMap_h, TH1F*& eFieldMap, + InDetDD::PixelModuleDesign* module); + + const std::pair<double, double> getTrappingTimes(double fluence) const; + const std::pair<double, double> getMobility(double electricField, double temperature) const; + double getTanLorentzAngle(double electricField, double temperature, double bField, bool isHole); + + bool saveDebugMaps(); +private: + RadDamageUtil(); + + Gaudi::Property<int> m_defaultRamo + { + this, "defaultRamo", 1, "Mapping strategy of Ramo potential" + }; + + Gaudi::Property<double> m_betaElectrons + { + this, "betaElectrons", 4.5e-16, "Used in trapping time calculation" + }; + + Gaudi::Property<double> m_betaHoles + { + this, "betaHoles", 6.0e-16, "Used in trapping time calculation" + }; + + Gaudi::Property<bool> m_saveDebugMaps + { + this, "saveDebugMaps", false, "Flag to save map" + }; + + double alpha(int n, int Nrep, double a); //Poisson solution factor + double weighting3D(double x, double y, double z, int n, int m, int Nrep, double a, double b); + double weighting2D(double x, double z, double Lx, double sensorThickness); + + ToolHandle<EfieldInterpolator> m_EfieldInterpolator + { + this, "EfieldInterpolator", "EfieldInterpolator", + "Create an Efield for fluence and bias volatge of interest based on TCAD samples" + }; }; #endif //PIXELDIGITIZATION_RADDAMAGEUTIL_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.cxx index 0ac99797f98f..29a1fb0afb6e 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "SensorSim3DTool.h" #include "InDetReadoutGeometry/SiDetectorElement.h" @@ -28,9 +28,8 @@ using namespace InDetDD; //=============================================== // C O N S T R U C T O R //=============================================== -SensorSim3DTool::SensorSim3DTool(const std::string& type, const std::string& name,const IInterface* parent): - SensorSimTool(type,name,parent) -{ +SensorSim3DTool::SensorSim3DTool(const std::string& type, const std::string& name, const IInterface* parent) : + SensorSimTool(type, name, parent) { } SensorSim3DTool::~SensorSim3DTool() { } @@ -49,62 +48,58 @@ StatusCode SensorSim3DTool::initialize() { std::vector<std::string> mapsPath_list; - if (!m_doRadDamage) { m_fluence=0; } + if (!m_doRadDamage) { + m_fluence = 0; + } - if (static_cast<int>(m_fluence)==1) { - mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_0_20V.root")); + if (static_cast<int>(m_fluence) == 1) { + mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_0_20V.root")); m_fluence_layers.push_back(1e-10); - } - else if (static_cast<int>(m_fluence)==2) { + } else if (static_cast<int>(m_fluence) == 2) { mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_1e14_20V.root")); m_fluence_layers.push_back(1e14); - } - else if (static_cast<int>(m_fluence)==3) { + } else if (static_cast<int>(m_fluence) == 3) { mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_2e14_30V.root")); m_fluence_layers.push_back(2e14); - } - else if (static_cast<int>(m_fluence)==4) { - mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_5e14_40V.root")); + } else if (static_cast<int>(m_fluence) == 4) { + mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_5e14_40V.root")); m_fluence_layers.push_back(5e14); - } - else if (static_cast<int>(m_fluence)==5) { + } else if (static_cast<int>(m_fluence) == 5) { mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_1e15_50V.root")); - m_fluence_layers.push_back(1e15); - } - else if (static_cast<int>(m_fluence)==6) { + m_fluence_layers.push_back(1e15); + } else if (static_cast<int>(m_fluence) == 6) { mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_5e15_160V.root")); m_fluence_layers.push_back(5e15); - } - else if (static_cast<int>(m_fluence)==7) { - mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_6e15_190V_new.root")); + } else if (static_cast<int>(m_fluence) == 7) { + mapsPath_list.push_back(PathResolverFindCalibFile( + "PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_6e15_190V_new.root")); m_fluence_layers.push_back(6e15); - } - else if (static_cast<int>(m_fluence)==8) { - mapsPath_list.push_back(PathResolverFindCalibFile("PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_1e16_260V_new.root")); + } else if (static_cast<int>(m_fluence) == 8) { + mapsPath_list.push_back(PathResolverFindCalibFile( + "PixelDigitization/TCAD_IBL_3Dsensors_efields/phi_1e16_260V_new.root")); m_fluence_layers.push_back(1e16); } // ***************************** // *** Setup Maps **** // ***************************** - //TODO This is only temporary until remotely stored maps and locally generated maps can be implemented - - for (unsigned int i=0; i<mapsPath_list.size(); i++) { + //TODO This is only temporary until remotely stored maps and locally generated maps can be implemented + for (unsigned int i = 0; i < mapsPath_list.size(); i++) { ATH_MSG_INFO("Using maps located in: " << mapsPath_list.at(i)); //std::unique_ptr<TFile> mapsFile=std::make_unique<TFile>( (mapsPath_list.at(i)).c_str() ); //this is the ramo potential. - TFile * mapsFile = new TFile((mapsPath_list.at(i)).c_str()); //this is the ramo potential. + TFile* mapsFile = new TFile((mapsPath_list.at(i)).c_str()); //this is the ramo potential. std::pair < int, int > Layer; // index for layer/end cap position - Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at Layer.first=1 + Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at iayer.first=1 Layer.second = i; //Layer: 0 = IBL Planar, 1=B-Layer, 2=Layer-1, 3=Layer-2 //For 3D sensor, only possible index should be 0-0 //May want to be changed in the future, since there's no point having an index with only one possible value //Setup ramo weighting field map - TH3F *ramoPotentialMap_hold; + TH3F* ramoPotentialMap_hold; ramoPotentialMap_hold = 0; - ramoPotentialMap_hold = (TH3F * ) mapsFile->Get("ramo"); + ramoPotentialMap_hold = (TH3F* ) mapsFile->Get("ramo"); if (ramoPotentialMap_hold == 0) { ATH_MSG_INFO("Did not find a Ramo potential map. Will use an approximate form."); return StatusCode::FAILURE; //Obviously, remove this when gen. code is set up @@ -116,21 +111,21 @@ StatusCode SensorSim3DTool::initialize() { ATH_MSG_INFO("Using fluence " << m_fluence_layers.at(i)); //Now setup the E-field. - TH2F *eFieldMap_hold; + TH2F* eFieldMap_hold; eFieldMap_hold = 0; - eFieldMap_hold = (TH2F * ) mapsFile->Get("efield"); + eFieldMap_hold = (TH2F* ) mapsFile->Get("efield"); if (eFieldMap_hold == 0) { ATH_MSG_INFO("Unable to load sensor e-field map, so generating one using approximations."); return StatusCode::FAILURE; //Obviously, remove this when gen. code is set up } m_eFieldMap[Layer] = eFieldMap_hold; - TH3F * xPositionMap_e_hold; - TH3F * xPositionMap_h_hold; - TH3F * yPositionMap_e_hold; - TH3F * yPositionMap_h_hold; - TH2F * timeMap_e_hold; - TH2F * timeMap_h_hold; + TH3F* xPositionMap_e_hold; + TH3F* xPositionMap_h_hold; + TH3F* yPositionMap_e_hold; + TH3F* yPositionMap_h_hold; + TH2F* timeMap_e_hold; + TH2F* timeMap_h_hold; xPositionMap_e_hold = 0; xPositionMap_h_hold = 0; @@ -138,15 +133,15 @@ StatusCode SensorSim3DTool::initialize() { yPositionMap_h_hold = 0; timeMap_e_hold = 0; timeMap_h_hold = 0; - xPositionMap_e_hold = (TH3F * ) mapsFile->Get("xPosition_e"); - xPositionMap_h_hold = (TH3F * ) mapsFile->Get("xPosition_h"); - yPositionMap_e_hold = (TH3F * ) mapsFile->Get("yPosition_e"); - yPositionMap_h_hold = (TH3F * ) mapsFile->Get("yPosition_h"); - timeMap_e_hold = (TH2F * ) mapsFile->Get("etimes"); - timeMap_h_hold = (TH2F * ) mapsFile->Get("htimes"); + xPositionMap_e_hold = (TH3F* ) mapsFile->Get("xPosition_e"); + xPositionMap_h_hold = (TH3F* ) mapsFile->Get("xPosition_h"); + yPositionMap_e_hold = (TH3F* ) mapsFile->Get("yPosition_e"); + yPositionMap_h_hold = (TH3F* ) mapsFile->Get("yPosition_h"); + timeMap_e_hold = (TH2F* ) mapsFile->Get("etimes"); + timeMap_h_hold = (TH2F* ) mapsFile->Get("htimes"); //Now, determine the time to reach the electrode and the trapping position. - if (xPositionMap_e_hold == 0 || xPositionMap_h_hold == 0 || yPositionMap_e_hold == 0 || yPositionMap_h_hold == 0 || timeMap_e_hold == 0 || timeMap_h_hold == 0) { - + if (xPositionMap_e_hold == 0 || xPositionMap_h_hold == 0 || yPositionMap_e_hold == 0 || yPositionMap_h_hold == 0 || + timeMap_e_hold == 0 || timeMap_h_hold == 0) { ATH_MSG_INFO("Unable to load at least one of teh distance/time maps, so generating all using approximations."); return StatusCode::FAILURE; //Obviously, remove this when gen. code is set up } @@ -158,11 +153,11 @@ StatusCode SensorSim3DTool::initialize() { m_timeMap_h[Layer] = timeMap_h_hold; // Get average charge data (for charge chunk effect correction) - m_avgChargeMap_e=0; - m_avgChargeMap_h=0; - m_avgChargeMap_e=(TH2F*)mapsFile->Get("avgCharge_e"); - m_avgChargeMap_h=(TH2F*)mapsFile->Get("avgCharge_h"); - if (m_avgChargeMap_e==0 || m_avgChargeMap_h==0) { + m_avgChargeMap_e = 0; + m_avgChargeMap_h = 0; + m_avgChargeMap_e = (TH2F*) mapsFile->Get("avgCharge_e"); + m_avgChargeMap_h = (TH2F*) mapsFile->Get("avgCharge_h"); + if (m_avgChargeMap_e == 0 || m_avgChargeMap_h == 0) { ATH_MSG_INFO("Unsuccessful picking up histogram: m_avgChargeMap"); } } @@ -181,17 +176,25 @@ StatusCode SensorSim3DTool::finalize() { //=============================================== // I N D U C E C H A R G E //=============================================== -StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiChargedDiodeCollection &chargedDiodes, const InDetDD::SiDetectorElement &Module, const InDetDD::PixelModuleDesign &p_design, std::vector< std::pair<double,double> > &trfHitRecord, std::vector<double> &initialConditions, CLHEP::HepRandomEngine *rndmEngine) { - - - if (!Module.isBarrel()) { return StatusCode::SUCCESS; } - if (p_design.getReadoutTechnology()!=InDetDD::PixelModuleDesign::FEI4) { return StatusCode::SUCCESS; } - if (p_design.numberOfCircuits()>1) { return StatusCode::SUCCESS; } +StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit>& phit, SiChargedDiodeCollection& chargedDiodes, + const InDetDD::SiDetectorElement& Module, + const InDetDD::PixelModuleDesign& p_design, std::vector< std::pair<double, + double> >& trfHitRecord, std::vector<double>& initialConditions, + CLHEP::HepRandomEngine* rndmEngine) { + if (!Module.isBarrel()) { + return StatusCode::SUCCESS; + } + if (p_design.getReadoutTechnology() != InDetDD::PixelModuleDesign::FEI4) { + return StatusCode::SUCCESS; + } + if (p_design.numberOfCircuits() > 1) { + return StatusCode::SUCCESS; + } - ATH_MSG_DEBUG("Applying SensorSim3D charge processor"); - if( initialConditions.size() != 8 ){ - ATH_MSG_INFO("ERROR! Starting coordinates were not filled correctly in EnergyDepositionSvc."); - return StatusCode::FAILURE; + ATH_MSG_DEBUG("Applying SensorSim3D charge processor"); + if (initialConditions.size() != 8) { + ATH_MSG_INFO("ERROR! Starting coordinates were not filled correctly in EnergyDepositionSvc."); + return StatusCode::FAILURE; } //Calculate trapping times based on fluence (already includes check for fluence=0) @@ -203,7 +206,7 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg double eta_0 = initialConditions[0]; double phi_0 = initialConditions[1]; - double depth_0 = initialConditions[2]; + double depth_0 = initialConditions[2]; double dEta = initialConditions[3]; double dPhi = initialConditions[4]; double dDepth = initialConditions[5]; @@ -213,25 +216,26 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg ATH_MSG_VERBOSE("Applying 3D sensor simulation."); double sensorThickness = Module.design().thickness(); - const InDet::SiliconProperties & siProperties = m_siPropertiesTool->getSiProperties(Module.identifyHash()); + const InDet::SiliconProperties& siProperties = m_siPropertiesTool->getSiProperties(Module.identifyHash()); double eleholePairEnergy = siProperties.electronHolePairsPerEnergy(); // Charge Collection Probability Map bin size const double x_bin_size = 0.001; const double y_bin_size = 0.001; - + std::string readout; - + // determine which readout is used // FEI4 : 50 X 250 microns - double pixel_size_x = Module.width()/p_design.rows(); - double pixel_size_y = Module.length()/p_design.columns(); + double pixel_size_x = Module.width() / p_design.rows(); + double pixel_size_y = Module.length() / p_design.columns(); double module_size_x = Module.width(); double module_size_y = Module.length(); const EBC_EVCOLL evColl = EBC_MAINEVCOLL; - const HepMcParticleLink::PositionFlag idxFlag = (phit.eventId()==0) ? HepMcParticleLink::IS_POSITION: HepMcParticleLink::IS_INDEX; - if (m_doRadDamage && m_fluence>0) { + const HepMcParticleLink::PositionFlag idxFlag = + (phit.eventId() == 0) ? HepMcParticleLink::IS_POSITION : HepMcParticleLink::IS_INDEX; + if (m_doRadDamage && m_fluence > 0) { //**************************************// //*** Now diffuse charges to surface *** // //**************************************// @@ -261,7 +265,9 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg bool coord = Module.isModuleFrame(); - ATH_MSG_DEBUG("ismoduleframe " << coord << " -- startPosition (x,y,z) = " << chargepos.x() << ", " << chargepos.y() << ", " << chargepos.z()); + ATH_MSG_DEBUG( + "ismoduleframe " << coord << " -- startPosition (x,y,z) = " << chargepos.x() << ", " << chargepos.y() << ", " << + chargepos.z()); // -- change origin of coordinates to the left bottom of module double x_new = chargepos.x() + module_size_x / 2.; @@ -269,7 +275,7 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg // -- change from module frame to pixel frame - int nPixX = int(x_new / pixel_size_x); + int nPixX = int(x_new / pixel_size_x); int nPixY = int(y_new / pixel_size_y); ATH_MSG_DEBUG(" -- nPixX = " << nPixX << " nPixY = " << nPixY); // In case the charge moves into a neighboring pixel @@ -277,7 +283,7 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg int extraNPixY = nPixY; //position relative to the bottom left corner of the pixel - double x_pix = x_new - pixel_size_x * (nPixX); + double x_pix = x_new - pixel_size_x * (nPixX); double y_pix = y_new - pixel_size_y * (nPixY); // -- change origin of coordinates to the center of the pixel double x_pix_center = x_pix - pixel_size_x / 2; @@ -287,7 +293,7 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg //only process hits which are not on the electrodes (E-field zero) //all the maps have 250 as the x value, so need to invert x and y whenever reading maps - double efield = getElectricField(y_pix, x_pix); + double efield = getElectricField(y_pix, x_pix); if (efield == 0) { ATH_MSG_DEBUG("Skipping since efield = 0 for x_pix = " << x_pix << " y_pix = " << y_pix); continue; @@ -295,17 +301,15 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg //Loop over charge-carrier pairs for (int j = 0; j < ncharges; j++) { - if (m_doRadDamage && m_fluence > 0) { - double eHit = energy_per_step; //Need to determine how many elementary charges this charge chunk represents. - double chunk_size = energy_per_step*eleholePairEnergy; //number of electrons/holes + double chunk_size = energy_per_step * eleholePairEnergy; //number of electrons/holes ATH_MSG_DEBUG("Chunk size: " << energy_per_step << "*" << eleholePairEnergy << " = " << chunk_size); //set minimum limit to prevent dividing into smaller subcharges than one fundamental charge if (chunk_size < 1) chunk_size = 1; - double kappa = 1./sqrt(chunk_size); + double kappa = 1. / sqrt(chunk_size); // Loop over everything twice: once for electrons and once for holes for (int eholes = 0; eholes < 2; eholes++) { @@ -323,26 +327,27 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg double phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); //Apply diffusion. rdif is teh max. diffusion - double Dt = getMobility(efield, isHole) * (0.024) * std::min(driftTime, timeToElectrode) * m_temperature / 273.; + double Dt = + getMobility(efield, isHole) * (0.024) * std::min(driftTime, timeToElectrode) * m_temperature / 273.; double rdif = sqrt(Dt) / 1000; //in mm double xposDiff = x_pix + rdif * phiRand; double etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); double yposDiff = y_pix + rdif * etaRand; - // Account for drifting into another pixel - while (xposDiff > pixel_size_x){ + // Account for drifting into another pixel + while (xposDiff > pixel_size_x) { extraNPixX = extraNPixX + 1; // increments or decrements pixel count in x xposDiff = xposDiff - pixel_size_x; // moves xpos coordinate 1 pixel over in x } - while (xposDiff < 0){ + while (xposDiff < 0) { extraNPixX = extraNPixX - 1; xposDiff = xposDiff + pixel_size_x; } - while (yposDiff > pixel_size_y){ + while (yposDiff > pixel_size_y) { extraNPixY = extraNPixY + 1; // increments or decrements pixel count in y yposDiff = yposDiff - pixel_size_y; // moves xpos coordinate 1 pixel over in y } - while (yposDiff < 0){ + while (yposDiff < 0) { extraNPixY = extraNPixY - 1; yposDiff = yposDiff + pixel_size_y; } @@ -350,13 +355,18 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg ATH_MSG_DEBUG(" -- diffused position w.r.t. pixel edge = " << xposDiff << " " << yposDiff); - double average_charge = m_avgChargeMap_e->GetBinContent(m_avgChargeMap_e->GetYaxis()->FindBin(y_pix*1000),m_avgChargeMap_e->GetXaxis()->FindBin(x_pix*1000)); - if (isHole) average_charge = m_avgChargeMap_h->GetBinContent(m_avgChargeMap_h->GetYaxis()->FindBin(y_pix*1000),m_avgChargeMap_h->GetXaxis()->FindBin(x_pix*1000)); + double average_charge = m_avgChargeMap_e->GetBinContent(m_avgChargeMap_e->GetYaxis()->FindBin( + y_pix * 1000), + m_avgChargeMap_e->GetXaxis()->FindBin(x_pix * + 1000)); + if (isHole) average_charge = + m_avgChargeMap_h->GetBinContent(m_avgChargeMap_h->GetYaxis()->FindBin( + y_pix * 1000), m_avgChargeMap_h->GetXaxis()->FindBin(x_pix * 1000)); ATH_MSG_DEBUG(" -- driftTime, timeToElectrode = " << driftTime << " " << timeToElectrode); - double xposFinal = getTrappingPositionY(yposDiff, xposDiff, std::min(driftTime,timeToElectrode), isHole); - double yposFinal = getTrappingPositionX(yposDiff, xposDiff, std::min(driftTime,timeToElectrode), isHole); + double xposFinal = getTrappingPositionY(yposDiff, xposDiff, std::min(driftTime, timeToElectrode), isHole); + double yposFinal = getTrappingPositionX(yposDiff, xposDiff, std::min(driftTime, timeToElectrode), isHole); ATH_MSG_DEBUG(" -- trapped position w.r.t. pixel edge = " << xposFinal << " " << yposFinal); @@ -368,104 +378,116 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg for (int j = -1; j <= 1; j++) { double yNeighbor = j * pixel_size_y; - ATH_MSG_DEBUG(" -- Ramo init position w.r.t. Ramo map edge = " << x_pix+pixel_size_x*3-xNeighbor << " " << y_pix+pixel_size_y*1/2-yNeighbor); - ATH_MSG_DEBUG(" -- Ramo final position w.r.t. Ramo map edge = " << xposFinal+pixel_size_x*3-xNeighbor << " " << yposFinal+pixel_size_y*1/2-yNeighbor); + ATH_MSG_DEBUG( + " -- Ramo init position w.r.t. Ramo map edge = " << x_pix + pixel_size_x * 3 - xNeighbor << " " << y_pix + pixel_size_y * 1 / 2 - + yNeighbor); + ATH_MSG_DEBUG( + " -- Ramo final position w.r.t. Ramo map edge = " << xposFinal + pixel_size_x * 3 - xNeighbor << " " << yposFinal + pixel_size_y * 1 / 2 - + yNeighbor); //Ramo map over 500umx350um pixel area //Ramo init different if charge diffused into neighboring pixel -> change primary pixel!! - double ramoInit = getRamoPotential(y_pix+pixel_size_y*1/2-yNeighbor,x_pix+pixel_size_x*3-xNeighbor); - double ramoFinal = getRamoPotential(yposFinal+pixel_size_y*1/2-yNeighbor,xposFinal+pixel_size_x*3-xNeighbor); + double ramoInit = getRamoPotential(y_pix + pixel_size_y * 1 / 2 - yNeighbor, + x_pix + pixel_size_x * 3 - xNeighbor); + double ramoFinal = getRamoPotential(yposFinal + pixel_size_y * 1 / 2 - yNeighbor, + xposFinal + pixel_size_x * 3 - xNeighbor); // Record deposit - double eHitRamo = (1-2*isHole)*eHit*(ramoFinal - ramoInit); + double eHitRamo = (1 - 2 * isHole) * eHit * (ramoFinal - ramoInit); - ATH_MSG_DEBUG("At neighbor pixel " << i << " " << j << " Hit of " << eHitRamo << " including Ramo factor: " << ramoFinal - ramoInit); + ATH_MSG_DEBUG( + "At neighbor pixel " << i << " " << j << " Hit of " << eHitRamo << " including Ramo factor: " << ramoFinal - + ramoInit); if (m_doChunkCorrection) { ATH_MSG_DEBUG("Energy before chunk correction: " << eHitRamo); - eHitRamo = eHit*average_charge + kappa*(eHitRamo - eHit*average_charge); + eHitRamo = eHit * average_charge + kappa * (eHitRamo - eHit * average_charge); ATH_MSG_DEBUG("Energy after chunk correction: " << eHitRamo); } double induced_charge = eHitRamo * eleholePairEnergy; // -- pixel coordinates --> module coordinates - double x_mod = x_pix + xNeighbor + pixel_size_x * extraNPixX - module_size_x / 2.; + double x_mod = x_pix + xNeighbor + pixel_size_x * extraNPixX - module_size_x / 2.; double y_mod = y_pix + yNeighbor + pixel_size_y * extraNPixY - module_size_y / 2.; SiLocalPosition chargePos = Module.hitLocalToLocal(y_mod, x_mod); - SiSurfaceCharge scharge(chargePos, SiCharge(induced_charge, hitTime(phit), SiCharge::track, HepMcParticleLink(phit->trackNumber(), phit.eventId(), evColl, idxFlag))); + SiSurfaceCharge scharge(chargePos, SiCharge(induced_charge, hitTime( + phit), SiCharge::track, HepMcParticleLink( + phit->trackNumber(), phit.eventId(), evColl, idxFlag))); SiCellId diode = Module.cellIdOfPosition(scharge.position()); SiCharge charge = scharge.charge(); if (diode.isValid()) { chargedDiodes.add(diode, charge); ATH_MSG_DEBUG("induced charge: " << induced_charge << " x_mod: " << x_mod << " y_mod: " << y_mod); - - } - + } } } } } } - } - } - else { + } + } else { //**************************************// //*** Now diffuse charges to surface *** // //**************************************// - for(unsigned int istep = 0; istep < trfHitRecord.size(); istep++) { - std::pair<double,double> iHitRecord = trfHitRecord[istep]; + for (unsigned int istep = 0; istep < trfHitRecord.size(); istep++) { + std::pair<double, double> iHitRecord = trfHitRecord[istep]; double eta_i = eta_0; double phi_i = phi_0; double depth_i = depth_0; if (iTotalLength) { - eta_i += 1.0*iHitRecord.first/iTotalLength*dEta; - phi_i += 1.0*iHitRecord.first/iTotalLength*dPhi; - depth_i += 1.0*iHitRecord.first/iTotalLength*dDepth; + eta_i += 1.0 * iHitRecord.first / iTotalLength * dEta; + phi_i += 1.0 * iHitRecord.first / iTotalLength * dPhi; + depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth; } - double es_current = 1.0*iHitRecord.second/1.E+6; + double es_current = 1.0 * iHitRecord.second / 1.E+6; double dist_electrode = 0.5 * sensorThickness - Module.design().readoutSide() * depth_i; - if (dist_electrode<0) dist_electrode=0; + if (dist_electrode < 0) dist_electrode = 0; CLHEP::Hep3Vector chargepos; - chargepos.setX(phi_i); chargepos.setY(eta_i); chargepos.setZ(dist_electrode); + chargepos.setX(phi_i); + chargepos.setY(eta_i); + chargepos.setZ(dist_electrode); bool coord = Module.isModuleFrame(); - ATH_MSG_DEBUG("ismoduleframe "<<coord << " -- startPosition (x,y,z) = " << chargepos.x() << ", " << chargepos.y() << ", " << chargepos.z()); + ATH_MSG_DEBUG( + "ismoduleframe " << coord << " -- startPosition (x,y,z) = " << chargepos.x() << ", " << chargepos.y() << ", " << + chargepos.z()); // -- change origin of coordinates to the left bottom of module - double x_new = chargepos.x() + module_size_x/2.; - double y_new = chargepos.y() + module_size_y/2.; + double x_new = chargepos.x() + module_size_x / 2.; + double y_new = chargepos.y() + module_size_y / 2.; // -- change from module frame to pixel frame - int nPixX = int(x_new/pixel_size_x); - int nPixY = int(y_new/pixel_size_y); - ATH_MSG_DEBUG(" -- nPixX = "<<nPixX<<" nPixY = "<<nPixY); - double x_pix = x_new - pixel_size_x*(nPixX); - double y_pix = y_new - pixel_size_y*(nPixY); + int nPixX = int(x_new / pixel_size_x); + int nPixY = int(y_new / pixel_size_y); + ATH_MSG_DEBUG(" -- nPixX = " << nPixX << " nPixY = " << nPixY); + double x_pix = x_new - pixel_size_x * (nPixX); + double y_pix = y_new - pixel_size_y * (nPixY); // -- change origin of coordinates to the center of the pixel - double x_pix_center = x_pix - pixel_size_x/2; - double y_pix_center = y_pix - pixel_size_y/2; - ATH_MSG_DEBUG(" -- current hit position w.r.t. pixel center = "<<x_pix_center<<" "<<y_pix_center); + double x_pix_center = x_pix - pixel_size_x / 2; + double y_pix_center = y_pix - pixel_size_y / 2; + ATH_MSG_DEBUG(" -- current hit position w.r.t. pixel center = " << x_pix_center << " " << y_pix_center); - double x_neighbor; double y_neighbor; CLHEP::Hep3Vector pos_neighbor; + double x_neighbor; + double y_neighbor; + CLHEP::Hep3Vector pos_neighbor; // -- Calculate signal in current pixel and in the neighboring ones // -- loop in the x-coordinate - for (int i=-1; i<=1; i++){ - x_neighbor = x_pix_center - i*pixel_size_x; + for (int i = -1; i <= 1; i++) { + x_neighbor = x_pix_center - i * pixel_size_x; // -- loop in the y-coordinate - for (int j=-1; j<=1; j++){ - y_neighbor = y_pix_center - j*pixel_size_y; + for (int j = -1; j <= 1; j++) { + y_neighbor = y_pix_center - j * pixel_size_y; // -- check if the neighbor falls inside the charge collection prob map window - if ( (fabs(x_neighbor)<pixel_size_x) && (fabs(y_neighbor)<pixel_size_y) ){ - + if ((fabs(x_neighbor) < pixel_size_x) && (fabs(y_neighbor) < pixel_size_y)) { // -- change origin of coordinates to the bottom left of the charge // collection prob map "window", i.e. shift of 1-pixel twd bottom left double x_neighbor_map = x_neighbor + pixel_size_x; @@ -476,23 +498,24 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg // -- retrieve the charge collection probability from Svc // -- swap x and y bins to match Map coord convention - double ccprob_neighbor = getProbMapEntry("FEI4",y_bin_cc_map,x_bin_cc_map); - if ( ccprob_neighbor == -1. ) return StatusCode::FAILURE; + double ccprob_neighbor = getProbMapEntry("FEI4", y_bin_cc_map, x_bin_cc_map); + if (ccprob_neighbor == -1.) return StatusCode::FAILURE; - double ed=es_current*eleholePairEnergy*ccprob_neighbor; + double ed = es_current * eleholePairEnergy * ccprob_neighbor; // -- pixel coordinates --> module coordinates //double x_mod = x_neighbor - half_pixel_size_x + pixel_size_x*nPixX -module_size_x/2.; //double y_mod = y_neighbor - half_pixel_size_y + pixel_size_y*nPixY -module_size_y/2.; - double x_mod = x_neighbor + pixel_size_x/2 + pixel_size_x*nPixX -module_size_x/2.; - double y_mod = y_neighbor + pixel_size_y/2 + pixel_size_y*nPixY -module_size_y/2.; - SiLocalPosition chargePos = Module.hitLocalToLocal(y_mod,x_mod); + double x_mod = x_neighbor + pixel_size_x / 2 + pixel_size_x * nPixX - module_size_x / 2.; + double y_mod = y_neighbor + pixel_size_y / 2 + pixel_size_y * nPixY - module_size_y / 2.; + SiLocalPosition chargePos = Module.hitLocalToLocal(y_mod, x_mod); - SiSurfaceCharge scharge(chargePos,SiCharge(ed,hitTime(phit),SiCharge::track,HepMcParticleLink(phit->trackNumber(),phit.eventId(),evColl,idxFlag))); + SiSurfaceCharge scharge(chargePos, SiCharge(ed, hitTime(phit), SiCharge::track, HepMcParticleLink( + phit->trackNumber(), phit.eventId(), evColl, idxFlag))); SiCellId diode = Module.cellIdOfPosition(scharge.position()); SiCharge charge = scharge.charge(); if (diode.isValid()) { - chargedDiodes.add(diode,charge); + chargedDiodes.add(diode, charge); } } } @@ -507,34 +530,32 @@ StatusCode SensorSim3DTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiCharg StatusCode SensorSim3DTool::readProbMap(std::string fileE) { std::string line; const std::string fileName = fileE; - std::string inputFile=PathResolverFindCalibFile(fileName); - if (inputFile=="") { - ATH_MSG_ERROR ( "Could not open input file!!!!!" ); + std::string inputFile = PathResolverFindCalibFile(fileName); + if (inputFile == "") { + ATH_MSG_ERROR("Could not open input file!!!!!"); return StatusCode::FAILURE; } - ATH_MSG_DEBUG("opening file "<<inputFile); + ATH_MSG_DEBUG("opening file " << inputFile); std::ifstream myfile(inputFile.c_str()); if (myfile.is_open()) { - ATH_MSG_DEBUG (" opened file!"); + ATH_MSG_DEBUG(" opened file!"); while (myfile.good()) { - while (std::getline(myfile,line)) { + while (std::getline(myfile, line)) { std::istringstream sline(line); - int xpos,ypos; + int xpos, ypos; double prob; - sline>>xpos>>ypos>>prob; - if (fileName.find("FEI4")!=std::string::npos) { - m_probMapFEI4.insert( std::make_pair( std::make_pair( xpos , ypos ) , prob ) ); - ATH_MSG_DEBUG ("FEI4 inside xpos "<<xpos<<" ypos "<<ypos<<" prob "<<prob); - } - else if (fileName.find("FEI3")!=std::string::npos) { - m_probMapFEI3.insert( std::make_pair( std::make_pair( xpos , ypos ) , prob ) ); - ATH_MSG_DEBUG ("FEI3 inside xpos "<<xpos<<" ypos "<<ypos<<" prob "<<prob); - } - else { - ATH_MSG_ERROR ("Please check name of Charge Coll Prob Maps! (should contain FEI3 or FEI4) "); + sline >> xpos >> ypos >> prob; + if (fileName.find("FEI4") != std::string::npos) { + m_probMapFEI4.insert(std::make_pair(std::make_pair(xpos, ypos), prob)); + ATH_MSG_DEBUG("FEI4 inside xpos " << xpos << " ypos " << ypos << " prob " << prob); + } else if (fileName.find("FEI3") != std::string::npos) { + m_probMapFEI3.insert(std::make_pair(std::make_pair(xpos, ypos), prob)); + ATH_MSG_DEBUG("FEI3 inside xpos " << xpos << " ypos " << ypos << " prob " << prob); + } else { + ATH_MSG_ERROR("Please check name of Charge Coll Prob Maps! (should contain FEI3 or FEI4) "); return StatusCode::FAILURE; } - } + } } myfile.close(); } @@ -543,17 +564,21 @@ StatusCode SensorSim3DTool::readProbMap(std::string fileE) { // -- Print out the Charge Collection Probability map (full map) StatusCode SensorSim3DTool::printProbMap(std::string readout) { - if (readout=="FEI4") { - for (std::multimap<std::pair<int,int>, double >::iterator it = m_probMapFEI4.begin(); it != m_probMapFEI4.end(); ++it ) { - ATH_MSG_DEBUG("read full probMap FEI4 --- bin x "<<it->first.first<<" bin y "<<it->first.second<<" prob "<<it->second); + if (readout == "FEI4") { + for (std::multimap<std::pair<int, int>, double >::iterator it = m_probMapFEI4.begin(); it != m_probMapFEI4.end(); + ++it) { + ATH_MSG_DEBUG( + "read full probMap FEI4 --- bin x " << it->first.first << " bin y " << it->first.second << " prob " << + it->second); } - } - else if(readout=="FEI3") { - for (std::multimap<std::pair<int,int>, double >::iterator it = m_probMapFEI3.begin(); it != m_probMapFEI3.end(); ++it ) { - ATH_MSG_DEBUG("read full probMap FEI3 --- bin x "<<it->first.first<<" bin y "<<it->first.second<<" prob "<<it->second); + } else if (readout == "FEI3") { + for (std::multimap<std::pair<int, int>, double >::iterator it = m_probMapFEI3.begin(); it != m_probMapFEI3.end(); + ++it) { + ATH_MSG_DEBUG( + "read full probMap FEI3 --- bin x " << it->first.first << " bin y " << it->first.second << " prob " << + it->second); } - } - else { + } else { ATH_MSG_ERROR("Error in printout Charge Coll Prob Maps! (readout should contain FEI3 or FEI4 strings) "); return StatusCode::FAILURE; } @@ -562,17 +587,15 @@ StatusCode SensorSim3DTool::printProbMap(std::string readout) { // -- Returns the Charge Collection Probability at a given point (bin_x,bin_y) double SensorSim3DTool::getProbMapEntry(std::string readout, int binx, int biny) { - std::pair<int,int> doublekey(binx,biny); + std::pair<int, int> doublekey(binx, biny); double echarge; - if (readout=="FEI4") { - std::multimap<std::pair<int,int>,double>::const_iterator iter = m_probMapFEI4.find(doublekey); + if (readout == "FEI4") { + std::multimap<std::pair<int, int>, double>::const_iterator iter = m_probMapFEI4.find(doublekey); echarge = iter->second; - } - else if(readout=="FEI3") { - std::multimap<std::pair<int,int>,double>::const_iterator iter = m_probMapFEI3.find(doublekey); + } else if (readout == "FEI3") { + std::multimap<std::pair<int, int>, double>::const_iterator iter = m_probMapFEI3.find(doublekey); echarge = iter->second; - } - else { + } else { ATH_MSG_ERROR("No Map Entry available for the requested readout"); echarge = -1.; } @@ -581,24 +604,28 @@ double SensorSim3DTool::getProbMapEntry(std::string readout, int binx, int biny) double SensorSim3DTool::getElectricField(double x, double y) { std::pair < int, int > Layer; // index for layer/end cap position - Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at Layer.first=1 + Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at + // Layer.first=1 Layer.second = 0; //Layer: 0 = IBL Planar, 1=B-Layer, 2=Layer-1, 3=Layer-2 - int n_binx = m_eFieldMap[Layer]->GetXaxis()->FindBin(x * 1000); //position coordinates in um to return electric field in V/cm + int n_binx = m_eFieldMap[Layer]->GetXaxis()->FindBin(x * 1000); //position coordinates in um to return electric field + // in V/cm int n_biny = m_eFieldMap[Layer]->GetYaxis()->FindBin(y * 1000); double electricField = m_eFieldMap[Layer]->GetBinContent(n_binx, n_biny); return electricField * 1.0E-7; //return efield in MV/mm (for mobility calculation) } double SensorSim3DTool::getMobility(double electricField, bool isHoleBit) { - //Not exactly the same as the getMobility function in RadDamageUtil, since we don't have a Hall effect for 3D sensors (B and E are parallel) + //Not exactly the same as the getMobility function in RadDamageUtil, since we don't have a Hall effect for 3D sensors + // (B and E are parallel) //Maybe good to do something about this in the future double vsat = 0; double ecrit = 0; double beta = 0; - //These parameterizations come from C. Jacoboni et al., Solid-State Electronics 20 (1977) 77-89. (see also https://cds.cern.ch/record/684187/files/indet-2001-004.pdf). + //These parameterizations come from C. Jacoboni et al., Solid-State Electronics 20 (1977) 77-89. (see also + // https://cds.cern.ch/record/684187/files/indet-2001-004.pdf). if (!isHoleBit) { vsat = 15.3 * pow(m_temperature, -0.87); // mm/ns @@ -616,7 +643,7 @@ double SensorSim3DTool::getMobility(double electricField, bool isHoleBit) { } double SensorSim3DTool::getDriftTime(bool isHoleBit) { - double u = CLHEP::RandFlat::shoot(0., 1.); // + double u = CLHEP::RandFlat::shoot(0., 1.); // double driftTime = 0; if (!isHoleBit) driftTime = (-1.) * m_trappingTimeElectrons * TMath::Log(u); // ns @@ -625,9 +652,9 @@ double SensorSim3DTool::getDriftTime(bool isHoleBit) { } double SensorSim3DTool::getTimeToElectrode(double x, double y, bool isHoleBit) { - std::pair < int, int > Layer; // index for layer/end cap position - Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at Layer.first=1 + Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at + // Layer.first=1 Layer.second = 0; //Layer: 0 = IBL Planar, 1=B-Layer, 2=Layer-1, 3=Layer-2 // Uses (x,y) position in um to return time to electrode in ns @@ -647,7 +674,8 @@ double SensorSim3DTool::getTimeToElectrode(double x, double y, bool isHoleBit) { double SensorSim3DTool::getTrappingPositionX(double initX, double initY, double driftTime, bool isHoleBit) { std::pair < int, int > Layer; // index for layer/end cap position - Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at Layer.first=1 + Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at + // Layer.first=1 Layer.second = 0; //Layer: 0 = IBL Planar, 1=B-Layer, 2=Layer-1, 3=Layer-2 double finalX = initX; @@ -656,13 +684,11 @@ double SensorSim3DTool::getTrappingPositionX(double initX, double initY, double int n_biny = m_xPositionMap_e[Layer]->GetYaxis()->FindBin(initY * 1000); int n_bint = m_xPositionMap_e[Layer]->GetZaxis()->FindBin(driftTime); finalX = m_xPositionMap_e[Layer]->GetBinContent(n_binx, n_biny, n_bint); - } else { int n_binx = m_xPositionMap_h[Layer]->GetXaxis()->FindBin(initX * 1000); int n_biny = m_xPositionMap_h[Layer]->GetYaxis()->FindBin(initY * 1000); int n_bint = m_xPositionMap_h[Layer]->GetZaxis()->FindBin(driftTime); finalX = m_xPositionMap_h[Layer]->GetBinContent(n_binx, n_biny, n_bint); - } return finalX * 1e-3; //[mm] @@ -670,7 +696,8 @@ double SensorSim3DTool::getTrappingPositionX(double initX, double initY, double double SensorSim3DTool::getTrappingPositionY(double initX, double initY, double driftTime, bool isHoleBit) { std::pair < int, int > Layer; // index for layer/end cap position - Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at Layer.first=1 + Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at + // Layer.first=1 Layer.second = 0; //Layer: 0 = IBL Planar, 1=B-Layer, 2=Layer-1, 3=Layer-2 double finalY = initY; @@ -689,16 +716,15 @@ double SensorSim3DTool::getTrappingPositionY(double initX, double initY, double return finalY * 1e-3; //[mm] } -double SensorSim3DTool::getRamoPotential(double x, double y){ +double SensorSim3DTool::getRamoPotential(double x, double y) { std::pair < int, int > Layer; // index for layer/end cap position - Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at Layer.first=1 + Layer.first = 0; //Barrel (0) or End Cap (1) - Now only for Barrel. If we want to add End Caps, put them at + // Layer.first=1 Layer.second = 0; //Layer: 0 = IBL Planar, 1=B-Layer, 2=Layer-1, 3=Layer-2 - int n_binx = m_ramoPotentialMap[Layer]->GetXaxis()->FindBin(x*1000); - int n_biny = m_ramoPotentialMap[Layer]->GetYaxis()->FindBin(y*1000); - double ramoPotential = m_ramoPotentialMap[Layer]->GetBinContent(n_binx,n_biny); + int n_binx = m_ramoPotentialMap[Layer]->GetXaxis()->FindBin(x * 1000); + int n_biny = m_ramoPotentialMap[Layer]->GetYaxis()->FindBin(y * 1000); + double ramoPotential = m_ramoPotentialMap[Layer]->GetBinContent(n_binx, n_biny); return ramoPotential; } - - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.h index 70b71af31061..1d4466900a0a 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSim3DTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/SensorSim3DTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -17,84 +17,105 @@ #include "GaudiKernel/ToolHandle.h" #include "RadDamageUtil.h" -class SensorSim3DTool : public SensorSimTool { - - public: - SensorSim3DTool( const std::string& type, const std::string& name,const IInterface* parent); - virtual StatusCode initialize() override; - virtual StatusCode finalize() override; - virtual ~SensorSim3DTool(); - - virtual StatusCode induceCharge(const TimedHitPtr<SiHit> &phit, SiChargedDiodeCollection& chargedDiodes, - const InDetDD::SiDetectorElement &Module, const InDetDD::PixelModuleDesign &p_design, - std::vector< std::pair<double,double> > &trfHitRecord, std::vector<double> &initialConditions, CLHEP::HepRandomEngine *rndmEngine) override; - - - // 3D sensor simulation using probability density map (used in RUN-2 (no radiation damage) - StatusCode readProbMap(std::string); - StatusCode printProbMap(std::string); - double getProbMapEntry(std::string, int, int); - - double getElectricField(double x, double y); - double getMobility(double electricField, bool isHoleBit); - double getDriftTime(bool isHoleBit); - double getTimeToElectrode(double x, double y, bool isHoleBit); - double getTrappingPositionX(double initX, double initY, double driftTime, bool isHoleBit); - double getTrappingPositionY(double initX, double initY, double driftTime, bool isHoleBit); - double getRamoPotential(double x, double y); - - private: - SensorSim3DTool(); - - // 3D sensor simulation using probability density map (used in RUN-2 (no radiation damage) - std::multimap<std::pair<int,int>,double> m_probMapFEI4; - std::multimap<std::pair<int,int>,double> m_probMapFEI3; - - // Map for radiation damage simulation - std::map<std::pair<int, int>, TH3F*> m_ramoPotentialMap; - std::map<std::pair<int, int>, TH2F*> m_eFieldMap; - std::map<std::pair<int, int>, TH3F*> m_xPositionMap_e; - std::map<std::pair<int, int>, TH3F*> m_xPositionMap_h; - std::map<std::pair<int, int>, TH3F*> m_yPositionMap_e; - std::map<std::pair<int, int>, TH3F*> m_yPositionMap_h; - std::map<std::pair<int, int>, TH2F*> m_timeMap_e; - std::map<std::pair<int, int>, TH2F*> m_timeMap_h; - TH2F* m_avgChargeMap_e; - TH2F* m_avgChargeMap_h; - - std::vector<double> m_fluence_layers; - std::map<std::pair<int, int>, double> m_fluence_layersMaps; - - Gaudi::Property<std::string> m_cc_prob_file_fei3 - {this, "CCProbMapFileFEI3", "PixelDigitization/3DFEI3-3E-problist-1um_v1.txt", "Input probability file for 3D FEI3 sensor."}; - - Gaudi::Property<std::string> m_cc_prob_file_fei4 - {this, "CCProbMapFileFEI4", "PixelDigitization/3DFEI4-2E-problist-1um_v0.txt", "Input probability file for 3D FEI4 sensor."}; - - Gaudi::Property<int> m_numberOfSteps - {this, "numberOfSteps", 50, "Number of steps for Pixel3D module"}; - - Gaudi::Property<bool> m_doRadDamage - {this, "doRadDamage", false, "doRadDmaage bool: should be flag"}; - - Gaudi::Property<bool> m_doChunkCorrection - {this, "doChunkCorrection", false, "doChunkCorrection bool: should be flag"}; - - Gaudi::Property<double> m_fluence - {this, "fluence", 0, "this is the fluence benchmark, 0-6. 0 is unirradiated, 1 is start of Run 2, 5 is end of 2018 and 6 is projected end of 2018"}; - - Gaudi::Property<double> m_trappingTimeElectrons - {this, "trappingTimeElectrons", 0.0, "Characteristic time till electron is trapped [ns]"}; - - Gaudi::Property<double> m_trappingTimeHoles - {this, "trappingTimeHoles", 0.0, "Characteristic time till hole is trapped [ns]"}; - - Gaudi::Property<double> m_temperature - {this, "Temperature", 300.0, "Default temperature [K]"}; - - ToolHandle<RadDamageUtil> m_radDamageUtil - {this, "RadDamageUtil", "RadDamageUtil", "Rad Damage utility"}; - +class SensorSim3DTool: public SensorSimTool { +public: + SensorSim3DTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual ~SensorSim3DTool(); + + virtual StatusCode induceCharge(const TimedHitPtr<SiHit>& phit, SiChargedDiodeCollection& chargedDiodes, + const InDetDD::SiDetectorElement& Module, const InDetDD::PixelModuleDesign& p_design, + std::vector< std::pair<double, double> >& trfHitRecord, + std::vector<double>& initialConditions, CLHEP::HepRandomEngine* rndmEngine) override; + + + // 3D sensor simulation using probability density map (used in RUN-2 (no radiation damage) + StatusCode readProbMap(std::string); + StatusCode printProbMap(std::string); + double getProbMapEntry(std::string, int, int); + + double getElectricField(double x, double y); + double getMobility(double electricField, bool isHoleBit); + double getDriftTime(bool isHoleBit); + double getTimeToElectrode(double x, double y, bool isHoleBit); + double getTrappingPositionX(double initX, double initY, double driftTime, bool isHoleBit); + double getTrappingPositionY(double initX, double initY, double driftTime, bool isHoleBit); + double getRamoPotential(double x, double y); +private: + SensorSim3DTool(); + + // 3D sensor simulation using probability density map (used in RUN-2 (no radiation damage) + std::multimap<std::pair<int, int>, double> m_probMapFEI4; + std::multimap<std::pair<int, int>, double> m_probMapFEI3; + + // Map for radiation damage simulation + std::map<std::pair<int, int>, TH3F*> m_ramoPotentialMap; + std::map<std::pair<int, int>, TH2F*> m_eFieldMap; + std::map<std::pair<int, int>, TH3F*> m_xPositionMap_e; + std::map<std::pair<int, int>, TH3F*> m_xPositionMap_h; + std::map<std::pair<int, int>, TH3F*> m_yPositionMap_e; + std::map<std::pair<int, int>, TH3F*> m_yPositionMap_h; + std::map<std::pair<int, int>, TH2F*> m_timeMap_e; + std::map<std::pair<int, int>, TH2F*> m_timeMap_h; + TH2F* m_avgChargeMap_e; + TH2F* m_avgChargeMap_h; + + std::vector<double> m_fluence_layers; + std::map<std::pair<int, int>, double> m_fluence_layersMaps; + + Gaudi::Property<std::string> m_cc_prob_file_fei3 + { + this, "CCProbMapFileFEI3", "PixelDigitization/3DFEI3-3E-problist-1um_v1.txt", + "Input probability file for 3D FEI3 sensor." + }; + + Gaudi::Property<std::string> m_cc_prob_file_fei4 + { + this, "CCProbMapFileFEI4", "PixelDigitization/3DFEI4-2E-problist-1um_v0.txt", + "Input probability file for 3D FEI4 sensor." + }; + + Gaudi::Property<int> m_numberOfSteps + { + this, "numberOfSteps", 50, "Number of steps for Pixel3D module" + }; + + Gaudi::Property<bool> m_doRadDamage + { + this, "doRadDamage", false, "doRadDmaage bool: should be flag" + }; + + Gaudi::Property<bool> m_doChunkCorrection + { + this, "doChunkCorrection", false, "doChunkCorrection bool: should be flag" + }; + + Gaudi::Property<double> m_fluence + { + this, "fluence", 0, + "this is the fluence benchmark, 0-6. 0 is unirradiated, 1 is start of Run 2, 5 is end of 2018 and 6 is projected end of 2018" + }; + + Gaudi::Property<double> m_trappingTimeElectrons + { + this, "trappingTimeElectrons", 0.0, "Characteristic time till electron is trapped [ns]" + }; + + Gaudi::Property<double> m_trappingTimeHoles + { + this, "trappingTimeHoles", 0.0, "Characteristic time till hole is trapped [ns]" + }; + + Gaudi::Property<double> m_temperature + { + this, "Temperature", 300.0, "Default temperature [K]" + }; + + ToolHandle<RadDamageUtil> m_radDamageUtil + { + this, "RadDamageUtil", "RadDamageUtil", "Rad Damage utility" + }; }; #endif // PIXELDIGITIZATION_SensorSim3DTool_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.cxx b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.cxx index 6ce14d94912f..a5edb25dd320 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.cxx +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.cxx @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ #include "SensorSimPlanarTool.h" #include "InDetReadoutGeometry/SiDetectorElement.h" @@ -27,9 +27,8 @@ using namespace InDetDD; //=============================================== // C O N S T R U C T O R //=============================================== -SensorSimPlanarTool::SensorSimPlanarTool(const std::string& type, const std::string& name,const IInterface* parent): - SensorSimTool(type,name,parent) -{ +SensorSimPlanarTool::SensorSimPlanarTool(const std::string& type, const std::string& name, const IInterface* parent) : + SensorSimTool(type, name, parent) { } SensorSimPlanarTool::~SensorSimPlanarTool() { } @@ -38,11 +37,11 @@ SensorSimPlanarTool::~SensorSimPlanarTool() { } // I N I T I A L I Z E //=============================================== StatusCode SensorSimPlanarTool::initialize() { - ATH_MSG_DEBUG ( "SensorSimPlanarTool::initialize()"); - ATH_CHECK(SensorSimTool::initialize()); + ATH_MSG_DEBUG("SensorSimPlanarTool::initialize()"); + ATH_CHECK(SensorSimTool::initialize()); ATH_CHECK(m_radDamageUtil.retrieve()); - ATH_MSG_DEBUG ( "RadDamageUtil tool retrieved successfully"); + ATH_MSG_DEBUG("RadDamageUtil tool retrieved successfully"); ATH_CHECK(m_lorentzAngleTool.retrieve()); @@ -50,43 +49,47 @@ StatusCode SensorSimPlanarTool::initialize() { std::vector<std::string> mapsPath_list; std::vector<std::string> TCADpath_list; - // Use all TCAD E field files in this directory for creating E field via interpolation (pruned filed excluded) - std::string iblFiles = PathResolverFindCalibDirectory("PixelDigitization/TCAD_IBL_efields/fei4-200um/"); - std::string sensorFiles = PathResolverFindCalibDirectory("PixelDigitization/TCAD_Blayer_efields/fei4-250um/"); + // Use all TCAD E field files in this directory for creating E field via interpolation (pruned filed excluded) + std::string iblFiles = PathResolverFindCalibDirectory("PixelDigitization/TCAD_IBL_efields/fei4-200um/"); + std::string sensorFiles = PathResolverFindCalibDirectory("PixelDigitization/TCAD_Blayer_efields/fei4-250um/"); // For each layer one configuration - TCADpath_list = {iblFiles, sensorFiles, sensorFiles, sensorFiles}; //IBL - 200um sensor depth, B layer - 20um, layer 1, layer 2 + TCADpath_list = { + iblFiles, sensorFiles, sensorFiles, sensorFiles + }; //IBL - 200um sensor depth, B layer - 20um, layer 1, layer 2 if (m_doInterpolateEfield) { - if (m_fluenceMap.size()==0 || m_fluenceLayer.size()==0 || m_voltageLayer.size()==0 || m_fluenceMap.size()!=m_fluenceLayer.size() || m_fluenceMap.size()!=m_voltageLayer.size()) { + if (m_fluenceMap.size() == 0 || m_fluenceLayer.size() == 0 || m_voltageLayer.size() == 0 || + m_fluenceMap.size() != m_fluenceLayer.size() || m_fluenceMap.size() != m_voltageLayer.size()) { ATH_MSG_INFO("Use interpolation, but the input map/fluence/valtage are not set."); return StatusCode::FAILURE; } ATH_MSG_INFO("No benchmark value set for fluence. Use interpolation."); mapsPath_list.clear(); - for (size_t i=0; i<m_fluenceMap.size(); i++) { + for (size_t i = 0; i < m_fluenceMap.size(); i++) { mapsPath_list.push_back(PathResolverFindCalibFile(m_fluenceMap[i])); } // ***************************** // *** Setup Maps **** // ***************************** - //TODO This is only temporary until remotely stored maps and locally generated maps can be implemented - //E field already implemented: needs fluence and bias voltage given as Property m_fluence, m_fluenceB, ..., m_fluence1, ... - for (unsigned int i=0; i<mapsPath_list.size(); i++) { - - ATH_MSG_INFO("Using maps located in: "<<mapsPath_list.at(i) << " for layer No." << i); + //TODO This is only temporary until remotely stored maps and locally generated maps can be implemented + //E field already implemented: needs fluence and bias voltage given as Property m_fluence, m_fluenceB, ..., + // m_fluence1, ... + for (unsigned int i = 0; i < mapsPath_list.size(); i++) { + ATH_MSG_INFO("Using maps located in: " << mapsPath_list.at(i) << " for layer No." << i); ATH_MSG_INFO("Create E field via interpolation based on files from: " << TCADpath_list.at(i)); - //std::unique_ptr<TFile> mapsFile=std::make_unique<TFile>( (mapsPath_list.at(i)).c_str() ); //this is the ramo potential. - TFile* mapsFile=new TFile( (mapsPath_list.at(i)).c_str() ); //this is the ramo potential. + //std::unique_ptr<TFile> mapsFile=std::make_unique<TFile>( (mapsPath_list.at(i)).c_str() ); //this is the ramo + // potential. + TFile* mapsFile = new TFile((mapsPath_list.at(i)).c_str()); //this is the ramo potential. //Setup ramo weighting field map TH3F* ramoPotentialMap_hold; - ramoPotentialMap_hold=0; - ramoPotentialMap_hold=(TH3F*)mapsFile->Get("hramomap1"); - if (ramoPotentialMap_hold==0) ramoPotentialMap_hold=(TH3F*)mapsFile->Get("ramo3d"); - if (ramoPotentialMap_hold==0){ + ramoPotentialMap_hold = 0; + ramoPotentialMap_hold = (TH3F*) mapsFile->Get("hramomap1"); + if (ramoPotentialMap_hold == 0) ramoPotentialMap_hold = (TH3F*) mapsFile->Get("ramo3d"); + if (ramoPotentialMap_hold == 0) { ATH_MSG_INFO("Did not find a Ramo potential map. Will use an approximate form."); ATH_MSG_WARNING("Not implemented yet - exit"); return StatusCode::FAILURE; //Obviously, remove this when gen. code is set up @@ -94,37 +97,41 @@ StatusCode SensorSimPlanarTool::initialize() { m_ramoPotentialMap.push_back(ramoPotentialMap_hold); //Now setup the E-field. TH1F* eFieldMap_hold; - eFieldMap_hold= new TH1F() ; + eFieldMap_hold = new TH1F(); //ATH_MSG_INFO("Generating E field maps using interpolation."); - CHECK(m_radDamageUtil->generateEfieldMap( eFieldMap_hold, NULL, m_fluenceLayer[i], m_voltageLayer[i], i, TCADpath_list.at(i), true)); + CHECK(m_radDamageUtil->generateEfieldMap(eFieldMap_hold, NULL, m_fluenceLayer[i], m_voltageLayer[i], i, + TCADpath_list.at(i), true)); - TH2F* lorentzMap_e_hold = new TH2F(); - TH2F* lorentzMap_h_hold = new TH2F(); + TH2F* lorentzMap_e_hold = new TH2F(); + TH2F* lorentzMap_h_hold = new TH2F(); TH2F* distanceMap_h_hold = new TH2F(); TH2F* distanceMap_e_hold = new TH2F(); - TH1F* timeMap_e_hold = new TH1F(); - TH1F* timeMap_h_hold = new TH1F(); + TH1F* timeMap_e_hold = new TH1F(); + TH1F* timeMap_h_hold = new TH1F(); - ATH_CHECK(m_radDamageUtil->generateDistanceTimeMap( distanceMap_e_hold, distanceMap_h_hold, timeMap_e_hold, timeMap_h_hold, lorentzMap_e_hold, lorentzMap_h_hold, eFieldMap_hold, NULL )); + ATH_CHECK(m_radDamageUtil->generateDistanceTimeMap(distanceMap_e_hold, distanceMap_h_hold, timeMap_e_hold, + timeMap_h_hold, lorentzMap_e_hold, lorentzMap_h_hold, + eFieldMap_hold, NULL)); // For debugging and documentation: uncomment to save different maps which are based on the interpolated E field - if(m_radDamageUtil->saveDebugMaps()){ + if (m_radDamageUtil->saveDebugMaps()) { TString prename = "map_layer_"; prename += i; prename += "distance_e.root"; distanceMap_e_hold->SaveAs(prename); prename.ReplaceAll("_e", "_h"); distanceMap_h_hold->SaveAs(prename); - prename.ReplaceAll("distance","time"); + prename.ReplaceAll("distance", "time"); timeMap_h_hold->SaveAs(prename); - prename.ReplaceAll( "_h","_e"); + prename.ReplaceAll("_h", "_e"); timeMap_e_hold->SaveAs(prename); prename.ReplaceAll("time", "lorentz"); lorentzMap_e_hold->SaveAs(prename); - prename.ReplaceAll( "_e","_h"); + prename.ReplaceAll("_e", "_h"); lorentzMap_h_hold->SaveAs(prename); } //Safetycheck - if (distanceMap_e_hold == 0 || distanceMap_h_hold == 0 || timeMap_e_hold == 0 || timeMap_h_hold == 0 || lorentzMap_e_hold == 0 || lorentzMap_h_hold == 0){ + if (distanceMap_e_hold == 0 || distanceMap_h_hold == 0 || timeMap_e_hold == 0 || timeMap_h_hold == 0 || + lorentzMap_e_hold == 0 || lorentzMap_h_hold == 0) { ATH_MSG_INFO("Unable to load at least one of the distance/time/Lorentz angle maps."); return StatusCode::FAILURE;//Obviously, remove this when gen. code is set up } @@ -150,33 +157,38 @@ StatusCode SensorSimPlanarTool::finalize() { //=============================================== // I N D U C E C H A R G E //=============================================== -StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiChargedDiodeCollection &chargedDiodes, - const InDetDD::SiDetectorElement &Module, const InDetDD::PixelModuleDesign &p_design, - std::vector< std::pair<double,double> > &trfHitRecord, std::vector<double> &initialConditions, CLHEP::HepRandomEngine *rndmEngine) { - +StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit>& phit, SiChargedDiodeCollection& chargedDiodes, + const InDetDD::SiDetectorElement& Module, + const InDetDD::PixelModuleDesign& p_design, + std::vector< std::pair<double, double> >& trfHitRecord, + std::vector<double>& initialConditions, + CLHEP::HepRandomEngine* rndmEngine) { // So far, this is only discriminating variable from 3D sensor. - if (p_design.numberOfCircuits()<2){ - if(!Module.isDBM()) { //DBM modules also processed here - return StatusCode::SUCCESS; - } + if (p_design.numberOfCircuits() < 2) { + if (!Module.isDBM()) { //DBM modules also processed here + return StatusCode::SUCCESS; + } } - const PixelID* p_pixelId = static_cast<const PixelID *>(Module.getIdHelper()); - int layer=p_pixelId->layer_disk(Module.identify() ); + const PixelID* p_pixelId = static_cast<const PixelID*>(Module.getIdHelper()); + int layer = p_pixelId->layer_disk(Module.identify()); // retrieve conditions data SG::ReadCondHandle<PixelModuleData> moduleData(m_moduleDataKey); - std::pair<double,double> trappingTimes; + std::pair<double, double> trappingTimes; if (m_doRadDamage && Module.isBarrel()) { - if (m_doInterpolateEfield) { trappingTimes = m_radDamageUtil->getTrappingTimes(m_fluenceLayer[layer]); } - else { trappingTimes = m_radDamageUtil->getTrappingTimes(moduleData->getFluenceLayer(layer)); } + if (m_doInterpolateEfield) { + trappingTimes = m_radDamageUtil->getTrappingTimes(m_fluenceLayer[layer]); + } else { + trappingTimes = m_radDamageUtil->getTrappingTimes(moduleData->getFluenceLayer(layer)); + } } //Load values from energyDeposition double eta_0 = initialConditions[0]; double phi_0 = initialConditions[1]; - double depth_0 = initialConditions[2]; + double depth_0 = initialConditions[2]; double dEta = initialConditions[3]; double dPhi = initialConditions[4]; double dDepth = initialConditions[5]; @@ -186,7 +198,7 @@ StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiC //Set up physical detector properties, switch on detector material ATH_MSG_DEBUG("Applying planar sensor simulation"); double sensorThickness = Module.design().thickness(); - const InDet::SiliconProperties & siProperties = m_siPropertiesTool->getSiProperties(Module.identifyHash()); + const InDet::SiliconProperties& siProperties = m_siPropertiesTool->getSiProperties(Module.identifyHash()); int etaCells = p_design.columns(); int phiCells = p_design.rows(); @@ -194,50 +206,50 @@ StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiC double eleholePairEnergy = 0; double smearRand = 0; - if (Module.isDBM()){ + if (Module.isDBM()) { eleholePairEnergy = 1. / (13. * CLHEP::eV); // was 3.62 eV. m_diffusionConstant = .00265; smearRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - } - else{ + } else { eleholePairEnergy = siProperties.electronHolePairsPerEnergy(); m_diffusionConstant = .007; } - double collectionDist = 0.2*CLHEP::mm; - double smearScale = 1. + 0.35*smearRand; + double collectionDist = 0.2 * CLHEP::mm; + double smearScale = 1. + 0.35 * smearRand; double tanLorentz = m_lorentzAngleTool->getTanLorentzAngle(Module.identifyHash()); - double coLorentz=std::sqrt(1.0+pow(tanLorentz,2)); + double coLorentz = std::sqrt(1.0 + pow(tanLorentz, 2)); const EBC_EVCOLL evColl = EBC_MAINEVCOLL; - const HepMcParticleLink::PositionFlag idxFlag = (phit.eventId()==0) ? HepMcParticleLink::IS_POSITION: HepMcParticleLink::IS_INDEX; + const HepMcParticleLink::PositionFlag idxFlag = + (phit.eventId() == 0) ? HepMcParticleLink::IS_POSITION : HepMcParticleLink::IS_INDEX; //**************************************// //*** Now diffuse charges to surface *** // //**************************************// for (unsigned int i = 0; i < trfHitRecord.size(); i++) { - std::pair<double,double> iHitRecord = trfHitRecord[i]; + std::pair<double, double> iHitRecord = trfHitRecord[i]; double eta_i = eta_0; double phi_i = phi_0; double depth_i = depth_0; if (iTotalLength) { - eta_i += 1.0*iHitRecord.first/iTotalLength*dEta; - phi_i += 1.0*iHitRecord.first/iTotalLength*dPhi; - depth_i += 1.0*iHitRecord.first/iTotalLength*dDepth; + eta_i += 1.0 * iHitRecord.first / iTotalLength * dEta; + phi_i += 1.0 * iHitRecord.first / iTotalLength * dPhi; + depth_i += 1.0 * iHitRecord.first / iTotalLength * dDepth; } //Find the position of the centre of the pixel in which the charge carriers are created, wrt centre of module - SiLocalPosition pos_i = Module.hitLocalToLocal(eta_i,phi_i); - SiCellId pixel_i = Module.cellIdOfPosition( pos_i ); + SiLocalPosition pos_i = Module.hitLocalToLocal(eta_i, phi_i); + SiCellId pixel_i = Module.cellIdOfPosition(pos_i); SiLocalPosition centreOfPixel_i; - int nnLoop_pixelEtaMax = 0; - int nnLoop_pixelEtaMin = 0; - int nnLoop_pixelPhiMax = 0; - int nnLoop_pixelPhiMin = 0; - + int nnLoop_pixelEtaMax = 0; + int nnLoop_pixelEtaMin = 0; + int nnLoop_pixelPhiMax = 0; + int nnLoop_pixelPhiMin = 0; + int numBins_driftTime_e = 0; int numBins_driftTime_h = 0; int numBins_weightingPotential_x = 0; @@ -248,58 +260,75 @@ StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiC centreOfPixel_i = p_design.positionFromColumnRow(pixel_i.etaIndex(), pixel_i.phiIndex()); //Make limits for NN loop - nnLoop_pixelEtaMax = std::min( 1,pixel_i.etaIndex() ); - nnLoop_pixelEtaMin = std::max( -1, pixel_i.etaIndex() + 1 - etaCells ); + nnLoop_pixelEtaMax = std::min(1, pixel_i.etaIndex()); + nnLoop_pixelEtaMin = std::max(-1, pixel_i.etaIndex() + 1 - etaCells); - nnLoop_pixelPhiMax = std::min( 1,pixel_i.phiIndex() ); - nnLoop_pixelPhiMin = std::max( -1, pixel_i.phiIndex() + 1 - phiCells ); + nnLoop_pixelPhiMax = std::min(1, pixel_i.phiIndex()); + nnLoop_pixelPhiMin = std::max(-1, pixel_i.phiIndex() + 1 - phiCells); //Setup values to check for overflow when using maps if (m_doInterpolateEfield) { - numBins_driftTime_e = m_distanceMap_e[layer]->GetNbinsY(); //Returns nBins = totalBins - underflow - overflow - numBins_driftTime_h = m_distanceMap_h[layer]->GetNbinsY(); + numBins_driftTime_e = m_distanceMap_e[layer]->GetNbinsY(); //Returns nBins = totalBins - underflow - overflow + numBins_driftTime_h = m_distanceMap_h[layer]->GetNbinsY(); numBins_weightingPotential_x = m_ramoPotentialMap[layer]->GetNbinsX(); numBins_weightingPotential_y = m_ramoPotentialMap[layer]->GetNbinsY(); - numBins_weightingPotential_z = m_ramoPotentialMap[layer]->GetNbinsZ(); - } - else { // use fluence value from conditions data + numBins_weightingPotential_z = m_ramoPotentialMap[layer]->GetNbinsZ(); + } else { // use fluence value from conditions data numBins_driftTime_e = moduleData->getDistanceMap_e(layer)->GetNbinsY(); - numBins_driftTime_h = moduleData->getDistanceMap_h(layer)->GetNbinsY(); + numBins_driftTime_h = moduleData->getDistanceMap_h(layer)->GetNbinsY(); numBins_weightingPotential_x = moduleData->getRamoPotentialMap(layer)->GetNbinsX(); numBins_weightingPotential_y = moduleData->getRamoPotentialMap(layer)->GetNbinsY(); - numBins_weightingPotential_z = moduleData->getRamoPotentialMap(layer)->GetNbinsZ(); + numBins_weightingPotential_z = moduleData->getRamoPotentialMap(layer)->GetNbinsZ(); } } // Distance between charge and readout side. p_design->readoutSide() is // +1 if readout side is in +ve depth axis direction and visa-versa. double dist_electrode = 0.5 * sensorThickness - Module.design().readoutSide() * depth_i; - if (dist_electrode<0) { dist_electrode=0; } - + if (dist_electrode < 0) { + dist_electrode = 0; + } + // nonTrapping probability double nontrappingProbability = 1.0; - if (Module.isDBM()){ - nontrappingProbability = exp(-dist_electrode/collectionDist); + if (Module.isDBM()) { + nontrappingProbability = exp(-dist_electrode / collectionDist); } if (m_doInterpolateEfield) { - m_ramo_x_binMap = 1000. * (m_ramoPotentialMap[layer]->GetNbinsX() / (m_ramoPotentialMap[layer]->GetXaxis()->GetXmax() - m_ramoPotentialMap[layer]->GetXaxis()->GetXmin())); - m_ramo_y_binMap = 1000. * (m_ramoPotentialMap[layer]->GetNbinsY() / (m_ramoPotentialMap[layer]->GetYaxis()->GetXmax() - m_ramoPotentialMap[layer]->GetYaxis()->GetXmin())); - m_ramo_z_binMap = 1000. * (m_ramoPotentialMap[layer]->GetNbinsZ() / (m_ramoPotentialMap[layer]->GetZaxis()->GetXmax() - m_ramoPotentialMap[layer]->GetZaxis()->GetXmin())); - } - else{ - m_ramo_x_binMap =1000. * (moduleData->getRamoPotentialMap(layer)->GetNbinsX() / (moduleData->getRamoPotentialMap(layer)->GetXaxis()->GetXmax() - moduleData->getRamoPotentialMap(layer)->GetXaxis()->GetXmin())); - m_ramo_y_binMap =1000. * (moduleData->getRamoPotentialMap(layer)->GetNbinsY() / (moduleData->getRamoPotentialMap(layer)->GetYaxis()->GetXmax() - moduleData->getRamoPotentialMap(layer)->GetYaxis()->GetXmin())); - m_ramo_z_binMap =1000. * (moduleData->getRamoPotentialMap(layer)->GetNbinsZ() / (moduleData->getRamoPotentialMap(layer)->GetZaxis()->GetXmax() - moduleData->getRamoPotentialMap(layer)->GetZaxis()->GetXmin())); + m_ramo_x_binMap = 1000. * + (m_ramoPotentialMap[layer]->GetNbinsX() / + (m_ramoPotentialMap[layer]->GetXaxis()->GetXmax() - + m_ramoPotentialMap[layer]->GetXaxis()->GetXmin())); + m_ramo_y_binMap = 1000. * + (m_ramoPotentialMap[layer]->GetNbinsY() / + (m_ramoPotentialMap[layer]->GetYaxis()->GetXmax() - + m_ramoPotentialMap[layer]->GetYaxis()->GetXmin())); + m_ramo_z_binMap = 1000. * + (m_ramoPotentialMap[layer]->GetNbinsZ() / + (m_ramoPotentialMap[layer]->GetZaxis()->GetXmax() - + m_ramoPotentialMap[layer]->GetZaxis()->GetXmin())); + } else { + m_ramo_x_binMap = 1000. * + (moduleData->getRamoPotentialMap(layer)->GetNbinsX() / + (moduleData->getRamoPotentialMap(layer)->GetXaxis()->GetXmax() - + moduleData->getRamoPotentialMap(layer)->GetXaxis()->GetXmin())); + m_ramo_y_binMap = 1000. * + (moduleData->getRamoPotentialMap(layer)->GetNbinsY() / + (moduleData->getRamoPotentialMap(layer)->GetYaxis()->GetXmax() - + moduleData->getRamoPotentialMap(layer)->GetYaxis()->GetXmin())); + m_ramo_z_binMap = 1000. * + (moduleData->getRamoPotentialMap(layer)->GetNbinsZ() / + (moduleData->getRamoPotentialMap(layer)->GetZaxis()->GetXmax() - + moduleData->getRamoPotentialMap(layer)->GetZaxis()->GetXmin())); } - for (int j=0; j<ncharges; j++) { - + for (int j = 0; j < ncharges; j++) { if (m_doRadDamage && !(Module.isDBM()) && Module.isBarrel()) { - double u = CLHEP::RandFlat::shoot(0.,1.); - double drifttime_e = (-1.)*(trappingTimes.first)*TMath::Log(u); //ns - u = CLHEP::RandFlat::shoot(0.,1.); - double drifttime_h = (-1.)*(trappingTimes.second)*TMath::Log(u); //ns + double u = CLHEP::RandFlat::shoot(0., 1.); + double drifttime_e = (-1.) * (trappingTimes.first) * TMath::Log(u); //ns + u = CLHEP::RandFlat::shoot(0., 1.); + double drifttime_h = (-1.) * (trappingTimes.second) * TMath::Log(u); //ns //Now, need the z-position at the trap. double depth_f_e = 0.0; @@ -308,115 +337,125 @@ StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiC double tanLorentz_h = 0.0; //TODO: the holes map does not currently extend for a drift time long enough that, any hole will reach //the corresponding electrode. This needs to be rectified by either (a) extrapolating the current map or - //(b) making a new map with a y-axis (drift time) that extends to at least 18 ns so all charge carriers reach electrode. - //However, if choose (b), will need to reduce granularity of map. + //(b) making a new map with a y-axis (drift time) that extends to at least 18 ns so all charge carriers reach + // electrode. + //However, if choose (b), will need to reduce granularity of map. if (m_doInterpolateEfield) { int nbin_z_e_xbin = m_distanceMap_e[layer]->GetXaxis()->FindBin(dist_electrode); int nbin_z_e_ybin = m_distanceMap_e[layer]->GetYaxis()->FindBin(drifttime_e); - if (nbin_z_e_ybin>numBins_driftTime_e) { nbin_z_e_ybin = numBins_driftTime_e; } - depth_f_e = m_distanceMap_e[layer]->GetBinContent(nbin_z_e_xbin,nbin_z_e_ybin); + if (nbin_z_e_ybin > numBins_driftTime_e) { + nbin_z_e_ybin = numBins_driftTime_e; + } + depth_f_e = m_distanceMap_e[layer]->GetBinContent(nbin_z_e_xbin, nbin_z_e_ybin); int nbin_z_h_xbin = m_distanceMap_h[layer]->GetXaxis()->FindBin(dist_electrode); int nbin_z_h_ybin = m_distanceMap_h[layer]->GetYaxis()->FindBin(drifttime_h); - if (nbin_z_h_ybin>numBins_driftTime_h) { nbin_z_h_ybin = numBins_driftTime_h; } - depth_f_h = m_distanceMap_h[layer]->GetBinContent( nbin_z_h_xbin,nbin_z_h_ybin ); - int nbin_Lorentz_e = m_lorentzMap_e[layer]->FindBin(dist_electrode,depth_f_e); - tanLorentz_e = m_lorentzMap_e[layer]->GetBinContent(nbin_Lorentz_e); - int nbin_Lorentz_h = m_lorentzMap_h[layer]->FindBin(dist_electrode,depth_f_h); - tanLorentz_h = m_lorentzMap_h[layer]->GetBinContent(nbin_Lorentz_h); - } - else { // use fluence value from conditions data + if (nbin_z_h_ybin > numBins_driftTime_h) { + nbin_z_h_ybin = numBins_driftTime_h; + } + depth_f_h = m_distanceMap_h[layer]->GetBinContent(nbin_z_h_xbin, nbin_z_h_ybin); + int nbin_Lorentz_e = m_lorentzMap_e[layer]->FindBin(dist_electrode, depth_f_e); + tanLorentz_e = m_lorentzMap_e[layer]->GetBinContent(nbin_Lorentz_e); + int nbin_Lorentz_h = m_lorentzMap_h[layer]->FindBin(dist_electrode, depth_f_h); + tanLorentz_h = m_lorentzMap_h[layer]->GetBinContent(nbin_Lorentz_h); + } else { // use fluence value from conditions data int nbin_z_e_xbin = moduleData->getDistanceMap_e(layer)->GetXaxis()->FindBin(dist_electrode); int nbin_z_e_ybin = moduleData->getDistanceMap_e(layer)->GetYaxis()->FindBin(drifttime_e); - if (nbin_z_e_ybin>numBins_driftTime_e) { nbin_z_e_ybin = numBins_driftTime_e; } - depth_f_e = moduleData->getDistanceMap_e(layer)->GetBinContent(nbin_z_e_xbin,nbin_z_e_ybin); + if (nbin_z_e_ybin > numBins_driftTime_e) { + nbin_z_e_ybin = numBins_driftTime_e; + } + depth_f_e = moduleData->getDistanceMap_e(layer)->GetBinContent(nbin_z_e_xbin, nbin_z_e_ybin); int nbin_z_h_xbin = moduleData->getDistanceMap_h(layer)->GetXaxis()->FindBin(dist_electrode); int nbin_z_h_ybin = moduleData->getDistanceMap_h(layer)->GetYaxis()->FindBin(drifttime_h); - if (nbin_z_h_ybin>numBins_driftTime_h) { nbin_z_h_ybin = numBins_driftTime_h; } - depth_f_h = moduleData->getDistanceMap_h(layer)->GetBinContent( nbin_z_h_xbin,nbin_z_h_ybin ); - int nbin_Lorentz_e = moduleData->getLorentzMap_e(layer)->FindBin(dist_electrode,depth_f_e); - tanLorentz_e = moduleData->getLorentzMap_e(layer)->GetBinContent(nbin_Lorentz_e); - int nbin_Lorentz_h = moduleData->getLorentzMap_h(layer)->FindBin(dist_electrode,depth_f_h); - tanLorentz_h = moduleData->getLorentzMap_h(layer)->GetBinContent(nbin_Lorentz_h); + if (nbin_z_h_ybin > numBins_driftTime_h) { + nbin_z_h_ybin = numBins_driftTime_h; + } + depth_f_h = moduleData->getDistanceMap_h(layer)->GetBinContent(nbin_z_h_xbin, nbin_z_h_ybin); + int nbin_Lorentz_e = moduleData->getLorentzMap_e(layer)->FindBin(dist_electrode, depth_f_e); + tanLorentz_e = moduleData->getLorentzMap_e(layer)->GetBinContent(nbin_Lorentz_e); + int nbin_Lorentz_h = moduleData->getLorentzMap_h(layer)->FindBin(dist_electrode, depth_f_h); + tanLorentz_h = moduleData->getLorentzMap_h(layer)->GetBinContent(nbin_Lorentz_h); } - double dz_e = fabs(dist_electrode - depth_f_e); - double dz_h = fabs(depth_f_h - dist_electrode); - double coLorentz_e = std::sqrt(1.0+std::pow(tanLorentz_e,2)); + double dz_e = fabs(dist_electrode - depth_f_e); + double dz_h = fabs(depth_f_h - dist_electrode); + double coLorentz_e = std::sqrt(1.0 + std::pow(tanLorentz_e, 2)); //Apply drift due to Lorentz force and diffusion double phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); //Apply diffusion. rdif is teh max. diffusion - double rdif_e=this->m_diffusionConstant*sqrt( fabs(dist_electrode - depth_f_e)*coLorentz_e/0.3); - double phi_f_e=phi_i + dz_e*tanLorentz_e + rdif_e*phiRand; + double rdif_e = this->m_diffusionConstant * sqrt(fabs(dist_electrode - depth_f_e) * coLorentz_e / 0.3); + double phi_f_e = phi_i + dz_e * tanLorentz_e + rdif_e * phiRand; double etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double eta_f_e=eta_i + rdif_e*etaRand; + double eta_f_e = eta_i + rdif_e * etaRand; phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double coLorentz_h = std::sqrt(1.0+std::pow(tanLorentz_h,2)); - double rdif_h=this->m_diffusionConstant*sqrt( fabs(dist_electrode - depth_f_h)*coLorentz_h/0.3); - double phi_f_h=phi_i + dz_h*tanLorentz_h + rdif_h*phiRand; + double coLorentz_h = std::sqrt(1.0 + std::pow(tanLorentz_h, 2)); + double rdif_h = this->m_diffusionConstant * sqrt(fabs(dist_electrode - depth_f_h) * coLorentz_h / 0.3); + double phi_f_h = phi_i + dz_h * tanLorentz_h + rdif_h * phiRand; etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double eta_f_h=eta_i + rdif_h*etaRand; + double eta_f_h = eta_i + rdif_h * etaRand; // amount of energy to be converted into charges at current step - double energy_per_step = 1.0*iHitRecord.second/1.E+6/ncharges; + double energy_per_step = 1.0 * iHitRecord.second / 1.E+6 / ncharges; // Slim Edge for IBL planar sensors: - if ( p_design.getReadoutTechnology()==InDetDD::PixelModuleDesign::FEI4) { - ATH_CHECK(applyIBLSlimEdges(energy_per_step,eta_f_e)); - ATH_CHECK(applyIBLSlimEdges(energy_per_step,eta_f_h)); + if (p_design.getReadoutTechnology() == InDetDD::PixelModuleDesign::FEI4) { + ATH_CHECK(applyIBLSlimEdges(energy_per_step, eta_f_e)); + ATH_CHECK(applyIBLSlimEdges(energy_per_step, eta_f_h)); } - int nbin_ramo_f_e_z; - int nbin_ramo_f_h_z; - // distinction necessary because of min(z) = -0.5 + int nbin_ramo_f_e_z; + int nbin_ramo_f_h_z; + // distinction necessary because of min(z) = -0.5 float minz = 1; - if (layer != 0) minz = 1.5; - nbin_ramo_f_e_z = int( minz + depth_f_e * m_ramo_z_binMap ); - nbin_ramo_f_h_z = int( minz + depth_f_h * m_ramo_z_binMap ); - - // Check for overflow in ramo hists in z-direction - if (nbin_ramo_f_h_z > numBins_weightingPotential_z){ nbin_ramo_f_h_z = numBins_weightingPotential_z + 1; } - if (nbin_ramo_f_e_z > numBins_weightingPotential_z){ nbin_ramo_f_e_z = numBins_weightingPotential_z + 1; } + if (layer != 0) minz = 1.5; + nbin_ramo_f_e_z = int( minz + depth_f_e * m_ramo_z_binMap ); + nbin_ramo_f_h_z = int( minz + depth_f_h * m_ramo_z_binMap ); + + // Check for overflow in ramo hists in z-direction + if (nbin_ramo_f_h_z > numBins_weightingPotential_z) { + nbin_ramo_f_h_z = numBins_weightingPotential_z + 1; + } + if (nbin_ramo_f_e_z > numBins_weightingPotential_z) { + nbin_ramo_f_e_z = numBins_weightingPotential_z + 1; + } //Loop over nearest neighbours in x and y //We assume that the lateral diffusion is minimal - for (int p=nnLoop_pixelEtaMin; p<=nnLoop_pixelEtaMax; p++){ - + for (int p = nnLoop_pixelEtaMin; p <= nnLoop_pixelEtaMax; p++) { // scale factors accounting for different pixel sizes - double scale_f=1.; - double columnWidth=p_design.widthFromColumnRange(pixel_i.etaIndex()-p,pixel_i.etaIndex()-p); - if (std::abs(columnWidth-0.6)<1e-9){ - scale_f = 4./6.; - } - else if (std::abs(columnWidth-0.45)<1e-9){ - scale_f = 25./45.; - } - else if (std::abs(columnWidth-0.5)<1e-9){ - scale_f = 25./50.; - } - - for (int q=nnLoop_pixelPhiMin; q<=nnLoop_pixelPhiMax; q++){ - - //Since both e-h charge carriers start in the same place, they have the same initial ramo value + double scale_f = 1.; + double columnWidth = p_design.widthFromColumnRange(pixel_i.etaIndex() - p, pixel_i.etaIndex() - p); + if (std::abs(columnWidth - 0.6) < 1e-9) { + scale_f = 4. / 6.; + } else if (std::abs(columnWidth - 0.45) < 1e-9) { + scale_f = 25. / 45.; + } else if (std::abs(columnWidth - 0.5) < 1e-9) { + scale_f = 25. / 50.; + } + + for (int q = nnLoop_pixelPhiMin; q <= nnLoop_pixelPhiMax; q++) { + //Since both e-h charge carriers start in the same place, they have the same initial ramo value //Centre of nearest neighbour (nn) pixel - SiLocalPosition centreOfPixel_nn = p_design.positionFromColumnRow( pixel_i.etaIndex() - p, pixel_i.phiIndex() - q ); + SiLocalPosition centreOfPixel_nn = p_design.positionFromColumnRow(pixel_i.etaIndex() - p, + pixel_i.phiIndex() - q); - //What is the displacement of the nn pixel from the primary pixel. + //What is the displacement of the nn pixel from the primary pixel. //This is to index the correct entry in the Ramo weighting potential map double dPhi_nn_centre = centreOfPixel_nn.xPhi() - centreOfPixel_i.xPhi(); //in mm double dEta_nn_centre = centreOfPixel_nn.xEta() - centreOfPixel_i.xEta(); //in mm - //This all has to be done relative to the (0,0) position since the - //Ramo weighting potential is only mapped out for 1/8th of a pixel. Much of this logic is reflecting the charge + //This all has to be done relative to the (0,0) position since the + //Ramo weighting potential is only mapped out for 1/8th of a pixel. Much of this logic is reflecting the + // charge //carrier across the boundaries. //Find the displacment of the charge carriers from the centre of the pixel in +ve quadrant - - double pixelEta_f_e = eta_f_e - centreOfPixel_i.xEta() ; - double pixelPhi_f_e = phi_f_e - centreOfPixel_i.xPhi() ; - double pixelEta_f_h = eta_f_h - centreOfPixel_i.xEta() ; - double pixelPhi_f_h = phi_f_h - centreOfPixel_i.xPhi() ; + double pixelEta_f_e = eta_f_e - centreOfPixel_i.xEta(); + double pixelPhi_f_e = phi_f_e - centreOfPixel_i.xPhi(); + + double pixelEta_f_h = eta_f_h - centreOfPixel_i.xEta(); + double pixelPhi_f_h = phi_f_h - centreOfPixel_i.xPhi(); //Final position of charge carriers wrt nn centre double dEta_f_e = pixelEta_f_e - dEta_nn_centre; @@ -430,105 +469,115 @@ StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiC double ramo_f_e = 0.0; double ramo_f_h = 0.0; - int nbin_ramo_f_e_x = int( 1 + std::abs( dPhi_f_e ) * m_ramo_x_binMap ); - int nbin_ramo_f_e_y = int( 1 + std::abs( dEta_f_e ) * m_ramo_y_binMap ); - - // Check for overflow in ramo hists in x- and y-direction - if (nbin_ramo_f_e_x > numBins_weightingPotential_x){ - nbin_ramo_f_e_x = numBins_weightingPotential_x + 1; - } - if (nbin_ramo_f_e_y > numBins_weightingPotential_y){ - nbin_ramo_f_e_y = numBins_weightingPotential_y + 1; - } - - if(nbin_ramo_f_e_x<=numBins_weightingPotential_x && nbin_ramo_f_e_y<=numBins_weightingPotential_y && nbin_ramo_f_e_z<=numBins_weightingPotential_z) { - if (m_doInterpolateEfield) { - ramo_f_e = m_ramoPotentialMap[layer]->GetBinContent(nbin_ramo_f_e_x,nbin_ramo_f_e_y,nbin_ramo_f_e_z); + int nbin_ramo_f_e_x = int( 1 + std::abs(dPhi_f_e) * m_ramo_x_binMap ); + int nbin_ramo_f_e_y = int( 1 + std::abs(dEta_f_e) * m_ramo_y_binMap ); + + // Check for overflow in ramo hists in x- and y-direction + if (nbin_ramo_f_e_x > numBins_weightingPotential_x) { + nbin_ramo_f_e_x = numBins_weightingPotential_x + 1; + } + if (nbin_ramo_f_e_y > numBins_weightingPotential_y) { + nbin_ramo_f_e_y = numBins_weightingPotential_y + 1; + } + + if (nbin_ramo_f_e_x <= numBins_weightingPotential_x && nbin_ramo_f_e_y <= numBins_weightingPotential_y && + nbin_ramo_f_e_z <= numBins_weightingPotential_z) { + if (m_doInterpolateEfield) { + ramo_f_e = m_ramoPotentialMap[layer]->GetBinContent(nbin_ramo_f_e_x, nbin_ramo_f_e_y, nbin_ramo_f_e_z); + } else { + ramo_f_e = moduleData->getRamoPotentialMap(layer)->GetBinContent(nbin_ramo_f_e_x, nbin_ramo_f_e_y, + nbin_ramo_f_e_z); } - else{ - ramo_f_e = moduleData->getRamoPotentialMap(layer)->GetBinContent(nbin_ramo_f_e_x,nbin_ramo_f_e_y,nbin_ramo_f_e_z); - } - } - - int nbin_ramo_f_h_x = int( 1 + std::abs( dPhi_f_h ) * m_ramo_x_binMap ); - int nbin_ramo_f_h_y = int( 1 + std::abs( dEta_f_h ) * m_ramo_y_binMap ); - - // Check for overflow in ramo hists in x- and y-direction - if (nbin_ramo_f_h_x > numBins_weightingPotential_x){ - nbin_ramo_f_h_x = numBins_weightingPotential_x + 1; - } - if (nbin_ramo_f_h_y > numBins_weightingPotential_y){ - nbin_ramo_f_h_y = numBins_weightingPotential_y + 1; - } - - if (nbin_ramo_f_h_x<=numBins_weightingPotential_x && nbin_ramo_f_h_y<=numBins_weightingPotential_y && nbin_ramo_f_h_z<=numBins_weightingPotential_z) { - if (m_doInterpolateEfield) { - ramo_f_h = m_ramoPotentialMap[layer]->GetBinContent(nbin_ramo_f_h_x,nbin_ramo_f_h_y,nbin_ramo_f_h_z); - } - else{ - ramo_f_h = moduleData->getRamoPotentialMap(layer)->GetBinContent(nbin_ramo_f_h_x,nbin_ramo_f_h_y,nbin_ramo_f_h_z); - } - } - //Account for the imperfect binning that would cause charge to be double-counted - - if (m_doInterpolateEfield) { - if (m_ramoPotentialMap[layer]->GetZaxis()->FindBin(depth_f_h*1000)==m_ramoPotentialMap[layer]->GetNbinsZ()+1) { ramo_f_h = 0.0; } //this means the hole has reached the back end - - if (m_ramoPotentialMap[layer]->GetZaxis()->FindBin(depth_f_e*1000)==1) { - if (fabs(dEta_f_e)>=Module.etaPitch()/2.0 || fabs(dPhi_f_e)>=Module.phiPitch()/2.0) { ramo_f_e = 0.0; } - else if (fabs(dEta_f_e)<Module.etaPitch()/2.0 && fabs(dPhi_f_e)<Module.phiPitch()/2.0) { ramo_f_e = 1.0; } - } - } - else{ - if(moduleData->getRamoPotentialMap(layer)->GetZaxis()->FindBin(depth_f_h*1000) - ==moduleData->getRamoPotentialMap(layer)->GetNbinsZ()+1) { - ramo_f_h=0; - } //this means the hole has reached the back end - - if (moduleData->getRamoPotentialMap(layer)->GetZaxis()->FindBin(depth_f_e*1000)==1) { - if (fabs(dEta_f_e)>=Module.etaPitch()/2.0 || fabs(dPhi_f_e)>=Module.phiPitch()/2.0) { ramo_f_e = 0.0; } - else if (fabs(dEta_f_e)<Module.etaPitch()/2.0 && fabs(dPhi_f_e)<Module.phiPitch()/2.0) { ramo_f_e = 1.0; } + } + + int nbin_ramo_f_h_x = int( 1 + std::abs(dPhi_f_h) * m_ramo_x_binMap ); + int nbin_ramo_f_h_y = int( 1 + std::abs(dEta_f_h) * m_ramo_y_binMap ); + + // Check for overflow in ramo hists in x- and y-direction + if (nbin_ramo_f_h_x > numBins_weightingPotential_x) { + nbin_ramo_f_h_x = numBins_weightingPotential_x + 1; + } + if (nbin_ramo_f_h_y > numBins_weightingPotential_y) { + nbin_ramo_f_h_y = numBins_weightingPotential_y + 1; + } + + if (nbin_ramo_f_h_x <= numBins_weightingPotential_x && nbin_ramo_f_h_y <= numBins_weightingPotential_y && + nbin_ramo_f_h_z <= numBins_weightingPotential_z) { + if (m_doInterpolateEfield) { + ramo_f_h = m_ramoPotentialMap[layer]->GetBinContent(nbin_ramo_f_h_x, nbin_ramo_f_h_y, nbin_ramo_f_h_z); + } else { + ramo_f_h = moduleData->getRamoPotentialMap(layer)->GetBinContent(nbin_ramo_f_h_x, nbin_ramo_f_h_y, + nbin_ramo_f_h_z); } - } + } + //Account for the imperfect binning that would cause charge to be double-counted + + if (m_doInterpolateEfield) { + if (m_ramoPotentialMap[layer]->GetZaxis()->FindBin(depth_f_h * 1000) == + m_ramoPotentialMap[layer]->GetNbinsZ() + 1) { + ramo_f_h = 0.0; + } //this means the hole has reached the back end + + if (m_ramoPotentialMap[layer]->GetZaxis()->FindBin(depth_f_e * 1000) == 1) { + if (fabs(dEta_f_e) >= Module.etaPitch() / 2.0 || fabs(dPhi_f_e) >= Module.phiPitch() / 2.0) { + ramo_f_e = 0.0; + } else if (fabs(dEta_f_e) < Module.etaPitch() / 2.0 && fabs(dPhi_f_e) < Module.phiPitch() / 2.0) { + ramo_f_e = 1.0; + } + } + } else { + if (moduleData->getRamoPotentialMap(layer)->GetZaxis()->FindBin(depth_f_h * 1000) + == moduleData->getRamoPotentialMap(layer)->GetNbinsZ() + 1) { + ramo_f_h = 0; + } //this means the hole has reached the back end + + if (moduleData->getRamoPotentialMap(layer)->GetZaxis()->FindBin(depth_f_e * 1000) == 1) { + if (fabs(dEta_f_e) >= Module.etaPitch() / 2.0 || fabs(dPhi_f_e) >= Module.phiPitch() / 2.0) { + ramo_f_e = 0.0; + } else if (fabs(dEta_f_e) < Module.etaPitch() / 2.0 && fabs(dPhi_f_e) < Module.phiPitch() / 2.0) { + ramo_f_e = 1.0; + } + } + } - //Given final position of charge carrier, find induced charge. The difference in Ramo weighting potential gives the fraction of charge induced. + //Given final position of charge carrier, find induced charge. The difference in Ramo weighting potential + // gives the fraction of charge induced. //The energy_per_step is transformed into charge with the eleholePair per Energy - double induced_charge = (ramo_f_e - ramo_f_h) * energy_per_step * eleholePairEnergy; - + double induced_charge = (ramo_f_e - ramo_f_h) * energy_per_step * eleholePairEnergy; + //Collect charge in centre of each pixel, since location within pixel doesn't matter for record - SiLocalPosition chargePos = Module.hitLocalToLocal( centreOfPixel_nn.xEta(), centreOfPixel_nn.xPhi() ); + SiLocalPosition chargePos = Module.hitLocalToLocal(centreOfPixel_nn.xEta(), centreOfPixel_nn.xPhi()); //The following lines are adapted from SiDigitization's Inserter class - SiSurfaceCharge scharge( - chargePos, - SiCharge( induced_charge, hitTime(phit), SiCharge::track, - HepMcParticleLink(phit->trackNumber(), phit.eventId(), evColl,idxFlag) - ) - ); + SiSurfaceCharge scharge( + chargePos, + SiCharge(induced_charge, hitTime(phit), SiCharge::track, + HepMcParticleLink(phit->trackNumber(), phit.eventId(), evColl, idxFlag) + ) + ); SiCellId diode = Module.cellIdOfPosition(scharge.position()); SiCharge charge = scharge.charge(); if (diode.isValid()) { - chargedDiodes.add(diode,charge); + chargedDiodes.add(diode, charge); } //IF } //For q } //for p - } - else { //If no radDamage, run original + } else { //If no radDamage, run original // diffusion sigma - double rdif=this->m_diffusionConstant*sqrt(dist_electrode*coLorentz/0.3); + double rdif = this->m_diffusionConstant * sqrt(dist_electrode * coLorentz / 0.3); // position at the surface double phiRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double phi_drifted=phi_i+dist_electrode*tanLorentz+rdif*phiRand; + double phi_drifted = phi_i + dist_electrode * tanLorentz + rdif * phiRand; double etaRand = CLHEP::RandGaussZiggurat::shoot(rndmEngine); - double eta_drifted=eta_i+rdif*etaRand; + double eta_drifted = eta_i + rdif * etaRand; // amount of energy to be converted into charges at current step - double energy_per_step = 1.0*iHitRecord.second/1.E+6/ncharges; + double energy_per_step = 1.0 * iHitRecord.second / 1.E+6 / ncharges; // Slim Edge for IBL planar sensors: - if (!(Module.isDBM()) && p_design.getReadoutTechnology()==InDetDD::PixelModuleDesign::FEI4) { - ATH_CHECK(applyIBLSlimEdges(energy_per_step,eta_drifted)); + if (!(Module.isDBM()) && p_design.getReadoutTechnology() == InDetDD::PixelModuleDesign::FEI4) { + ATH_CHECK(applyIBLSlimEdges(energy_per_step, eta_drifted)); } // Get the charge position in Reconstruction local coordinates. @@ -536,54 +585,50 @@ StatusCode SensorSimPlanarTool::induceCharge(const TimedHitPtr<SiHit> &phit, SiC // The parametrization of the sensor efficiency (if needed) double ed = 0; - if (Module.isDBM()){ - ed=energy_per_step*eleholePairEnergy*nontrappingProbability*smearScale; - } - else { - ed=energy_per_step*eleholePairEnergy; + if (Module.isDBM()) { + ed = energy_per_step * eleholePairEnergy * nontrappingProbability * smearScale; + } else { + ed = energy_per_step * eleholePairEnergy; } //The following lines are adapted from SiDigitization's Inserter class - SiSurfaceCharge scharge(chargePos,SiCharge(ed,hitTime(phit),SiCharge::track,HepMcParticleLink(phit->trackNumber(),phit.eventId(),evColl,idxFlag))); + SiSurfaceCharge scharge(chargePos, SiCharge(ed, hitTime(phit), SiCharge::track, HepMcParticleLink( + phit->trackNumber(), phit.eventId(), evColl, idxFlag))); SiCellId diode = Module.cellIdOfPosition(scharge.position()); SiCharge charge = scharge.charge(); if (diode.isValid()) { - chargedDiodes.add(diode,charge); + chargedDiodes.add(diode, charge); } - - } //else: no radDamage, run original + } //else: no radDamage, run original }//end cycle for charge }//trfHitRecord.size() return StatusCode::SUCCESS; } -StatusCode SensorSimPlanarTool::applyIBLSlimEdges(double &energy_per_step, double &eta_drifted) { - - if (fabs(eta_drifted)>20.440) { energy_per_step=0.0; } - if (fabs(eta_drifted)<20.440 && fabs(eta_drifted)>20.200) { - if (eta_drifted>0) { - energy_per_step = energy_per_step*(68.13-eta_drifted*3.333); - eta_drifted = eta_drifted-0.250; +StatusCode SensorSimPlanarTool::applyIBLSlimEdges(double& energy_per_step, double& eta_drifted) { + if (fabs(eta_drifted) > 20.440) { + energy_per_step = 0.0; + } + if (fabs(eta_drifted) < 20.440 && fabs(eta_drifted) > 20.200) { + if (eta_drifted > 0) { + energy_per_step = energy_per_step * (68.13 - eta_drifted * 3.333); + eta_drifted = eta_drifted - 0.250; + } else { + energy_per_step = energy_per_step * (68.13 + eta_drifted * 3.333); + eta_drifted = eta_drifted + 0.250; } - else { - energy_per_step = energy_per_step*(68.13+eta_drifted*3.333); - eta_drifted = eta_drifted+0.250; - } } - if (fabs(eta_drifted)<20.200 && fabs(eta_drifted)>20.100) { - if (eta_drifted>0) { - energy_per_step = energy_per_step*(41.2-eta_drifted*2.0); - eta_drifted = eta_drifted-0.250; + if (fabs(eta_drifted) < 20.200 && fabs(eta_drifted) > 20.100) { + if (eta_drifted > 0) { + energy_per_step = energy_per_step * (41.2 - eta_drifted * 2.0); + eta_drifted = eta_drifted - 0.250; + } else { + energy_per_step = energy_per_step * (41.2 + eta_drifted * 2.0); + eta_drifted = eta_drifted + 0.250; } - else { - energy_per_step = energy_per_step*(41.2+eta_drifted*2.0); - eta_drifted = eta_drifted+0.250; - } } return StatusCode::SUCCESS; } - - diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.h index 26d0d6fbe731..08aee096fd11 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimPlanarTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/SensorSimPlanarTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -16,67 +16,89 @@ #include "InDetCondTools/ISiLorentzAngleTool.h" #include "RadDamageUtil.h" -class SensorSimPlanarTool : public SensorSimTool { - - public: - SensorSimPlanarTool( const std::string& type, const std::string& name,const IInterface* parent); - virtual StatusCode initialize() override; - virtual StatusCode finalize() override; - virtual ~SensorSimPlanarTool(); - - virtual StatusCode induceCharge(const TimedHitPtr<SiHit> &phit, SiChargedDiodeCollection& chargedDiodes, - const InDetDD::SiDetectorElement &Module, const InDetDD::PixelModuleDesign &p_design, - std::vector< std::pair<double,double> > &trfHitRecord, std::vector<double> &initialConditions, CLHEP::HepRandomEngine *rndmEngine) override; - - //Apply slim edge inefficiencies for IBL sensors - StatusCode applyIBLSlimEdges( double &energyPerStep, double &eta_drifted); - - private: - SensorSimPlanarTool(); - - // Map for radiation damage simulation - std::vector<TH3F*> m_ramoPotentialMap; - std::vector<TH2F*> m_distanceMap_e; - std::vector<TH2F*> m_distanceMap_h; - std::vector<TH2F*> m_lorentzMap_e; - std::vector<TH2F*> m_lorentzMap_h; - - // maps to directly get factor to calculate bin instead of calling FindBin - double m_ramo_x_binMap; - double m_ramo_y_binMap; - double m_ramo_z_binMap; - - Gaudi::Property<int> m_numberOfSteps - {this, "numberOfSteps", 50, "Geant4:number of steps for PixelPlanar"}; - - Gaudi::Property<double> m_diffusionConstant - {this, "diffusionConstant", 0.0, "Geant4:Diffusion Constant for PixelPlanar"}; - - Gaudi::Property<bool> m_doRadDamage - {this, "doRadDamage", false, "doRadDmaage bool: should be flag"}; - - Gaudi::Property<bool> m_doInterpolateEfield - {this, "doInterpolateEfield", false, "doInterpolateEfield bool: should be flag"}; - - Gaudi::Property<std::vector<std::string>> m_fluenceMap - {this, "FluenceMap", {"PixelDigitization/maps_IBL_PL_400V_fl5_5e14.root", - "PixelDigitization/maps_PIX_400V_fl5_19e14.root", - "PixelDigitization/maps_PIX_250V_fl2_28e14.root", - "PixelDigitization/maps_PIX_250V_fl1_53e14.root"}, - "Fluence map for radiation damage when interpolation method is activated"}; - - Gaudi::Property<std::vector<double>> m_fluenceLayer - {this, "FluenceLayer", {5.50e14, 5.19e14, 2.28e14, 1.53e14}, "Fluence for radiation damage when interpolation method is activated"}; - - Gaudi::Property<std::vector<float>> m_voltageLayer - {this, "BiasVoltageLayer", {400.0,400.0,250.0,250.0}, "Bias voltage for radiation damage when interpolation method is activated"}; - - ToolHandle<RadDamageUtil> m_radDamageUtil - {this, "RadDamageUtil", "RadDamageUtil", "Rad Damage utility"}; - - ToolHandle<ISiLorentzAngleTool> m_lorentzAngleTool - {this, "LorentzAngleTool", "PixelLorentzAngleTool", "Tool to retreive Lorentz angle"}; - +class SensorSimPlanarTool: public SensorSimTool { +public: + SensorSimPlanarTool(const std::string& type, const std::string& name, const IInterface* parent); + virtual StatusCode initialize() override; + virtual StatusCode finalize() override; + virtual ~SensorSimPlanarTool(); + + virtual StatusCode induceCharge(const TimedHitPtr<SiHit>& phit, SiChargedDiodeCollection& chargedDiodes, + const InDetDD::SiDetectorElement& Module, const InDetDD::PixelModuleDesign& p_design, + std::vector< std::pair<double, double> >& trfHitRecord, + std::vector<double>& initialConditions, CLHEP::HepRandomEngine* rndmEngine) override; + + //Apply slim edge inefficiencies for IBL sensors + StatusCode applyIBLSlimEdges(double& energyPerStep, double& eta_drifted); +private: + SensorSimPlanarTool(); + + // Map for radiation damage simulation + std::vector<TH3F*> m_ramoPotentialMap; + std::vector<TH2F*> m_distanceMap_e; + std::vector<TH2F*> m_distanceMap_h; + std::vector<TH2F*> m_lorentzMap_e; + std::vector<TH2F*> m_lorentzMap_h; + + // maps to directly get factor to calculate bin instead of calling FindBin + double m_ramo_x_binMap; + double m_ramo_y_binMap; + double m_ramo_z_binMap; + + Gaudi::Property<int> m_numberOfSteps + { + this, "numberOfSteps", 50, "Geant4:number of steps for PixelPlanar" + }; + + Gaudi::Property<double> m_diffusionConstant + { + this, "diffusionConstant", 0.0, "Geant4:Diffusion Constant for PixelPlanar" + }; + + Gaudi::Property<bool> m_doRadDamage + { + this, "doRadDamage", false, "doRadDmaage bool: should be flag" + }; + + Gaudi::Property<bool> m_doInterpolateEfield + { + this, "doInterpolateEfield", false, "doInterpolateEfield bool: should be flag" + }; + + Gaudi::Property<std::vector<std::string> > m_fluenceMap + { + this, "FluenceMap", { + "PixelDigitization/maps_IBL_PL_400V_fl5_5e14.root", + "PixelDigitization/maps_PIX_400V_fl5_19e14.root", + "PixelDigitization/maps_PIX_250V_fl2_28e14.root", + "PixelDigitization/maps_PIX_250V_fl1_53e14.root" + }, + "Fluence map for radiation damage when interpolation method is activated" + }; + + Gaudi::Property<std::vector<double> > m_fluenceLayer + { + this, "FluenceLayer", { + 5.50e14, 5.19e14, 2.28e14, 1.53e14 + }, "Fluence for radiation damage when interpolation method is activated" + }; + + Gaudi::Property<std::vector<float> > m_voltageLayer + { + this, "BiasVoltageLayer", { + 400.0, 400.0, 250.0, 250.0 + }, "Bias voltage for radiation damage when interpolation method is activated" + }; + + ToolHandle<RadDamageUtil> m_radDamageUtil + { + this, "RadDamageUtil", "RadDamageUtil", "Rad Damage utility" + }; + + ToolHandle<ISiLorentzAngleTool> m_lorentzAngleTool + { + this, "LorentzAngleTool", "PixelLorentzAngleTool", "Tool to retreive Lorentz angle" + }; }; #endif // PIXELDIGITIZATION_SensorSimPlanarTool_H diff --git a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimTool.h b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimTool.h index 849cb7cacb36..0108376baf57 100644 --- a/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimTool.h +++ b/InnerDetector/InDetDigitization/PixelDigitization/src/SensorSimTool.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -*/ + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + */ /** * @file PixelDigitization/SensorSimTool.h * @author Soshi Tsuno <Soshi.Tsuno@cern.ch> @@ -27,40 +27,40 @@ static const InterfaceID IID_ISensorSimTool("SensorSimTool", 1, 0); -class SensorSimTool:public AthAlgTool,virtual public IAlgTool { - - public: - SensorSimTool( const std::string& type, const std::string& name,const IInterface* parent) : - AthAlgTool(type,name,parent) - { +class SensorSimTool: public AthAlgTool, virtual public IAlgTool { +public: + SensorSimTool(const std::string& type, const std::string& name, const IInterface* parent) : + AthAlgTool(type, name, parent) { declareInterface<SensorSimTool>(this); } - static const InterfaceID& interfaceID() { return IID_ISensorSimTool; } - - virtual StatusCode initialize() { - ATH_CHECK(AthAlgTool::initialize()); - ATH_CHECK(m_siPropertiesTool.retrieve()); - ATH_CHECK(m_moduleDataKey.initialize()); - return StatusCode::SUCCESS; - } - - virtual StatusCode finalize() {return StatusCode::FAILURE;} - virtual ~SensorSimTool() {} - virtual StatusCode induceCharge(const TimedHitPtr<SiHit> &phit, SiChargedDiodeCollection& chargedDiodes, - const InDetDD::SiDetectorElement &Module, const InDetDD::PixelModuleDesign &p_design, - std::vector< std::pair<double,double> > &trfHitRecord, std::vector<double> &initialConditions, CLHEP::HepRandomEngine *rndmEngine) = 0; + static const InterfaceID& interfaceID() {return IID_ISensorSimTool;} - private: - SensorSimTool(); - - protected: - ToolHandle<ISiPropertiesTool> m_siPropertiesTool - {this, "SiPropertiesTool", "SiPropertiesTool", "Tool to retrieve SiProperties"}; + virtual StatusCode initialize() { + ATH_CHECK(AthAlgTool::initialize()); + ATH_CHECK(m_siPropertiesTool.retrieve()); + ATH_CHECK(m_moduleDataKey.initialize()); + return StatusCode::SUCCESS; + } - SG::ReadCondHandleKey<PixelModuleData> m_moduleDataKey - {this, "PixelModuleData", "PixelModuleData", "Pixel module data"}; + virtual StatusCode finalize() {return StatusCode::FAILURE;} + virtual ~SensorSimTool() {} + virtual StatusCode induceCharge(const TimedHitPtr<SiHit>& phit, SiChargedDiodeCollection& chargedDiodes, + const InDetDD::SiDetectorElement& Module, const InDetDD::PixelModuleDesign& p_design, + std::vector< std::pair<double, double> >& trfHitRecord, + std::vector<double>& initialConditions, CLHEP::HepRandomEngine* rndmEngine) = 0; +private: + SensorSimTool(); +protected: + ToolHandle<ISiPropertiesTool> m_siPropertiesTool + { + this, "SiPropertiesTool", "SiPropertiesTool", "Tool to retrieve SiProperties" + }; + SG::ReadCondHandleKey<PixelModuleData> m_moduleDataKey + { + this, "PixelModuleData", "PixelModuleData", "Pixel module data" + }; }; #endif // PIXELDIGITIZATION_SensorSimTool_H -- GitLab