From f77740fd8b8ad59b7048c3dde2128f02388e2220 Mon Sep 17 00:00:00 2001 From: Susumu Oda <susumu.oda@cern.ch> Date: Wed, 21 Oct 2020 10:55:53 +0200 Subject: [PATCH 1/4] Rename SCT_InducedChargedModel to SCT_InducedChargeModel. --- ...edModel.cxx => SCT_InducedChargeModel.cxx} | 56 +++++++++---------- ...hargedModel.h => SCT_InducedChargeModel.h} | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) rename InnerDetector/InDetDigitization/SCT_Digitization/src/{SCT_InducedChargedModel.cxx => SCT_InducedChargeModel.cxx} (86%) rename InnerDetector/InDetDigitization/SCT_Digitization/src/{SCT_InducedChargedModel.h => SCT_InducedChargeModel.h} (99%) diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargedModel.cxx b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx similarity index 86% rename from InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargedModel.cxx rename to InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx index 3f326f0814a2..247c6c77ecc9 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargedModel.cxx +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx @@ -9,7 +9,7 @@ // 2016.4.3 for ICM (induced charge model) by Taka Kondo (KEK) //----------------------------------------------- -#include "SCT_InducedChargedModel.h" +#include "SCT_InducedChargeModel.h" // ROOT #include "TH2.h" @@ -20,16 +20,16 @@ #include <cmath> #include <iostream> -const double SCT_InducedChargedModel::s_kB = Gaudi::Units::k_Boltzmann / Gaudi::Units::joule; // [m^2*kg/s^2/K] -const double SCT_InducedChargedModel::s_e = Gaudi::Units::e_SI; // [Coulomb] -const std::vector<float> SCT_InducedChargedModel::s_VFD0 = +const double SCT_InducedChargeModel::s_kB = Gaudi::Units::k_Boltzmann / Gaudi::Units::joule; // [m^2*kg/s^2/K] +const double SCT_InducedChargeModel::s_e = Gaudi::Units::e_SI; // [Coulomb] +const std::vector<float> SCT_InducedChargeModel::s_VFD0 = { -180., -150., -120., -90., -60., -30., 0., 30., 70.}; -const std::vector<std::string> SCT_InducedChargedModel::s_VFD0str = +const std::vector<std::string> SCT_InducedChargeModel::s_VFD0str = {"M180", "M150", "M120", "M90", "M60", "M30", "0", "30", "70"}; -void SCT_InducedChargedModel::init(const float vdepl, const float vbias, const IdentifierHash hashId, ToolHandle<ISiliconConditionsTool>& siConditionsTool) { +void SCT_InducedChargeModel::init(const float vdepl, const float vbias, const IdentifierHash hashId, ToolHandle<ISiliconConditionsTool>& siConditionsTool) { - ATH_MSG_INFO("--- Induced Charged Model Paramter (Begin) --------"); + ATH_MSG_INFO("--- Induced Charge Model Paramter (Begin) --------"); //---------------setting basic parameters--------------------------- @@ -63,7 +63,7 @@ void SCT_InducedChargedModel::init(const float vdepl, const float vbias, const I ATH_MSG_INFO(" BulkDepth\t\t"<< m_bulk_depth << " cm"); ATH_MSG_INFO(" DepletionDepth\t\t"<< m_depletion_depth << " cm"); ATH_MSG_INFO(" StripPitch\t\t"<< m_strip_pitch << " cm"); - ATH_MSG_INFO("--- Induced Charged Model Paramter (End) ---------"); + ATH_MSG_INFO("--- Induced Charge Model Paramter (End) ---------"); return; } @@ -71,11 +71,11 @@ void SCT_InducedChargedModel::init(const float vdepl, const float vbias, const I //--------------------------------------------------------------------- // transport //--------------------------------------------------------------------- -void SCT_InducedChargedModel::transport(const bool isElectron, - const double x0, const double y0, - double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, - const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { +void SCT_InducedChargeModel::transport(const bool isElectron, + const double x0, const double y0, + double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, + const IdentifierHash hashId, + ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { // transport electrons and holes in the bulk // T. Kondo, 2010.9.9, 2017.7.20 // External parameters to be specified @@ -156,10 +156,10 @@ void SCT_InducedChargedModel::transport(const bool isElectron, //--------------------------------------------------------------------- // holeTransport //--------------------------------------------------------------------- -void SCT_InducedChargedModel::holeTransport(const double x0, const double y0, - double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, - const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { +void SCT_InducedChargeModel::holeTransport(const double x0, const double y0, + double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, + const IdentifierHash hashId, + ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { // Q_m2[100],Q_m1[100],Q_00[100],Q_p1[100],Q_p2[100] NTransportSteps=100 const bool isElectron = false; transport(isElectron, @@ -172,10 +172,10 @@ void SCT_InducedChargedModel::holeTransport(const double x0, const double y0, //--------------------------------------------------------------------- // electronTransport //--------------------------------------------------------------------- -void SCT_InducedChargedModel::electronTransport(const double x0, const double y0, - double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, - const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { +void SCT_InducedChargeModel::electronTransport(const double x0, const double y0, + double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, + const IdentifierHash hashId, + ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { // Q_m2[100],Q_m1[100],Q_00[100],Q_p1[100],Q_p2[100] NTransportSteps=100 const bool isElectron = true; transport(isElectron, @@ -188,10 +188,10 @@ void SCT_InducedChargedModel::electronTransport(const double x0, const double y0 //--------------------------------------------------------------- // Get parameters for electron or hole transport //--------------------------------------------------------------- -bool SCT_InducedChargedModel::getVxVyD(const bool isElectron, - const double x, const double y, double& vx, double& vy, double& D, - const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { +bool SCT_InducedChargeModel::getVxVyD(const bool isElectron, + const double x, const double y, double& vx, double& vy, double& D, + const IdentifierHash hashId, + ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { double Ex, Ey; EField(x, y, Ex, Ey); // [V/cm] if (Ey > 0.) { @@ -224,7 +224,7 @@ bool SCT_InducedChargedModel::getVxVyD(const bool isElectron, //------------------------------------------------------------------- // calculation of induced charge using Weighting (Ramo) function //------------------------------------------------------------------- -double SCT_InducedChargedModel::induced(const int istrip, const double x, const double y) const +double SCT_InducedChargeModel::induced(const int istrip, const double x, const double y) const { // x and y are the location of charge (e or hole) // induced charge on the strip "istrip" situated at the height y = d @@ -252,7 +252,7 @@ double SCT_InducedChargedModel::induced(const int istrip, const double x, const //-------------------------------------------------------------- // Electric Field Ex and Ey //-------------------------------------------------------------- -void SCT_InducedChargedModel::EField(const double x, const double y, double& Ex, double& Ey) const { +void SCT_InducedChargeModel::EField(const double x, const double y, double& Ex, double& Ey) const { // m_EFieldModel == UniformE 0; uniform E-field model // m_EFieldModel == FlatDiodeModel 1; flat diode model // m_EFieldModel == FEMsolutions 2; FEM solusions @@ -319,7 +319,7 @@ void SCT_InducedChargedModel::EField(const double x, const double y, double& Ex, ///////////////////////////////////////////////////////////////////// -void SCT_InducedChargedModel::loadICMParameters() { +void SCT_InducedChargeModel::loadICMParameters() { // Loading Ramo potential and Electric field. // In strip pitch directions : // Ramo potential : 80 divisions (81 points) with 5 um intervals from 40-440 um. diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargedModel.h b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h similarity index 99% rename from InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargedModel.h rename to InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h index d302cd03c840..1500bb8804ec 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargedModel.h +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h @@ -35,7 +35,7 @@ #include <string> #include <vector> -class SCT_InducedChargedModel { +class SCT_InducedChargeModel { public: enum EFieldModel {UniformE=0, FlatDiodeModel=1, FEMsolutions=2}; -- GitLab From 6c308da30e6b7ecf4cb639964966f29b6e112b65 Mon Sep 17 00:00:00 2001 From: Susumu Oda <susumu.oda@cern.ch> Date: Thu, 22 Oct 2020 10:15:53 +0200 Subject: [PATCH 2/4] Manual sweep of MR 37385 to master --- .../SCT_Digitization/CMakeLists.txt | 2 +- .../src/SCT_InducedChargeModel.cxx | 341 +++++++++++------- .../src/SCT_InducedChargeModel.h | 113 ++++-- 3 files changed, 293 insertions(+), 163 deletions(-) diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/CMakeLists.txt b/InnerDetector/InDetDigitization/SCT_Digitization/CMakeLists.txt index cb3be644e67b..4209b461b0fd 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/CMakeLists.txt +++ b/InnerDetector/InDetDigitization/SCT_Digitization/CMakeLists.txt @@ -14,7 +14,7 @@ atlas_add_component( SCT_Digitization src/*.cxx src/components/*.cxx INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${CLHEP_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} CommissionEvent AthenaBaseComps AthenaKernel CxxUtils PileUpToolsLib Identifier xAODEventInfo GaudiKernel SiDigitization InDetRawData InDetSimEvent HitManagement GeneratorObjects SiPropertiesToolLib InDetIdentifier InDetReadoutGeometry SCT_ReadoutGeometry InDetSimData InDetConditionsSummaryService PathResolver SCT_ConditionsToolsLib SCT_ModuleDistortionsLib ) + LINK_LIBRARIES ${ROOT_LIBRARIES} ${CLHEP_LIBRARIES} CommissionEvent AthenaBaseComps AthenaKernel CxxUtils PileUpToolsLib Identifier xAODEventInfo GaudiKernel SiDigitization InDetRawData InDetSimEvent HitManagement GeneratorObjects SiPropertiesToolLib InDetIdentifier InDetReadoutGeometry SCT_ReadoutGeometry InDetSimData InDetConditionsSummaryService PathResolver SCT_ConditionsToolsLib SCT_ModuleDistortionsLib MagFieldConditions ) atlas_add_test( SCT_DigitizationMT_test SCRIPT Digi_tf.py --inputHITSFile /cvmfs/atlas-nightlies.cern.ch/repo/data/data-art/DigitizationTests/HITS.04919495._001041.pool.root.1 --conditionsTag default:OFLCOND-RUN12-SDR-25 --digiSeedOffset1 170 --digiSeedOffset2 170 --geometryVersion ATLAS-R2-2015-03-01-00 --DataRunNumber 222525 --outputRDOFile mc15_2015_ttbar.RDO.pool.root --preInclude HITtoRDO:SimulationJobOptions/preInclude.SCTOnlyConfig.py,Digitization/ForceUseOfAlgorithms.py --postInclude Digitization/FixDataDependenciesForMT.py --skipEvents 0 --maxEvents 100 --athenaopts=--threads=10 diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx index 247c6c77ecc9..ef3fe9ece6cd 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx @@ -22,60 +22,87 @@ const double SCT_InducedChargeModel::s_kB = Gaudi::Units::k_Boltzmann / Gaudi::Units::joule; // [m^2*kg/s^2/K] const double SCT_InducedChargeModel::s_e = Gaudi::Units::e_SI; // [Coulomb] +// Sorted depletion voltage values const std::vector<float> SCT_InducedChargeModel::s_VFD0 = { -180., -150., -120., -90., -60., -30., 0., 30., 70.}; const std::vector<std::string> SCT_InducedChargeModel::s_VFD0str = {"M180", "M150", "M120", "M90", "M60", "M30", "0", "30", "70"}; -void SCT_InducedChargeModel::init(const float vdepl, const float vbias, const IdentifierHash hashId, ToolHandle<ISiliconConditionsTool>& siConditionsTool) { +SCT_InducedChargeModel::SCT_InducedChargeModel(size_t maxHash, EFieldModel model) : + m_msg("SCT_InducedChargeModel"), + m_EFieldModel(model) +{ + loadICMParameters(); + m_data.resize(maxHash); +} - ATH_MSG_INFO("--- Induced Charge Model Paramter (Begin) --------"); +SCT_InducedChargeModel::SCT_InducedChargeModelData* +SCT_InducedChargeModel::setWaferData(const float vdepl, + const float vbias, + const InDetDD::SiDetectorElement* element, + const AtlasFieldCacheCondObj* fieldCondObj, + const ToolHandle<ISiliconConditionsTool> siConditionsTool) const { + std::lock_guard<std::mutex> lock(m_mutex); + + // If cache exists, cache is used. + SCT_InducedChargeModelData* p_data = m_data[element->identifyHash()].get(); + if (p_data) return p_data; + + ATH_MSG_DEBUG("--- Induced Charged Model Paramter (Begin) --------"); + + HepGeom::Point3D<double> localpos(0., 0., 0.); // The center of wafer + HepGeom::Point3D<double> globalpos = element->globalPositionHit(localpos); + double point[3] = {globalpos.x(), globalpos.y(), globalpos.z()}; + double field[3] = {0., 0., 0.}; + MagField::AtlasFieldCache fieldCache; + fieldCondObj->getInitializedCache(fieldCache); + fieldCache.getField(point, field); + const Amg::Vector3D magneticField(field[0], field[1], field[2]); // in kTesla //---------------setting basic parameters--------------------------- + std::unique_ptr<SCT_InducedChargeModelData> data = + std::make_unique<SCT_InducedChargeModelData>(vdepl, + vbias, + element, + magneticField, + m_bulk_depth, + m_EFieldModel, + siConditionsTool); + + //--- set electric fields --- + setEField(*data); - m_VD = vdepl; // full depletion voltage [Volt] negative for type-P - m_VB = vbias; // applied bias voltage [Volt] - m_T = siConditionsTool->temperature(hashId) + Gaudi::Units::STP_Temperature; - - //------------------------ initialize subfunctions ------------ - - loadICMParameters(); - - //------------ find delepletion deph for model=0 and 1 ------------- - m_depletion_depth = m_bulk_depth; - // for type N (before type inversion) - if (m_VD >= 0.) { - if (m_VB < m_VD) m_depletion_depth = std::sqrt(m_VB/m_VD) * m_bulk_depth; - } else { - // for type P - if (m_VB <= std::abs(m_VD)) m_depletion_depth = 0.; - } - //-------------------------------------------------------- - ATH_MSG_INFO(" EFieldModel 0(uniform E), 1(Flat Diode Model), 2 (FEM solusions)\t\t"<< m_EFieldModel); - ATH_MSG_INFO(" DepletionVoltage_VD\t"<< m_VD <<" V"); - ATH_MSG_INFO(" BiasVoltage_VB \t"<< m_VB <<" V"); - ATH_MSG_INFO(" MagneticField_B \t"<< m_B <<" Tesla"); - ATH_MSG_INFO(" Temperature_T \t"<< m_T <<" K"); - ATH_MSG_INFO(" TransportTimeStep \t"<< m_transportTimeStep <<" ns"); - ATH_MSG_INFO(" TransportTimeMax\t"<< m_transportTimeMax <<" ns"); - ATH_MSG_INFO(" BulkDepth\t\t"<< m_bulk_depth << " cm"); - ATH_MSG_INFO(" DepletionDepth\t\t"<< m_depletion_depth << " cm"); - ATH_MSG_INFO(" StripPitch\t\t"<< m_strip_pitch << " cm"); - ATH_MSG_INFO("--- Induced Charge Model Paramter (End) ---------"); - - return; + ATH_MSG_DEBUG(" EFieldModel 0 (Flat Diode Model), 1 (FEM solusions) 2 (uniform E)\t"<< data->m_EFieldModel); + ATH_MSG_DEBUG(" DepletionVoltage_VD\t"<< data->m_VD <<" V"); + ATH_MSG_DEBUG(" BiasVoltage_VB \t"<< data->m_VB <<" V"); + ATH_MSG_DEBUG(" MagneticField_B \t" + << data->m_magneticField[Amg::x] << " " + << data->m_magneticField[Amg::y] << " " + << data->m_magneticField[Amg::z] <<" kTesla"); + ATH_MSG_DEBUG(" Temperature_T \t"<< data->m_T <<" K"); + ATH_MSG_DEBUG(" TransportTimeStep \t"<< m_transportTimeStep <<" ns"); + ATH_MSG_DEBUG(" TransportTimeMax\t"<< m_transportTimeMax <<" ns"); + ATH_MSG_DEBUG(" BulkDepth\t\t"<< m_bulk_depth << " cm"); + ATH_MSG_DEBUG(" DepletionDepth\t\t"<< data->m_depletion_depth << " cm"); + ATH_MSG_DEBUG(" StripPitch\t\t"<< m_strip_pitch << " cm"); + ATH_MSG_DEBUG("--- Induced Charged Model Paramter (End) ---------"); + + m_data[element->identifyHash()] = std::move(data); + + return m_data[element->identifyHash()].get(); } //--------------------------------------------------------------------- // transport //--------------------------------------------------------------------- -void SCT_InducedChargeModel::transport(const bool isElectron, +void SCT_InducedChargeModel::transport(const SCT_InducedChargeModelData& data, + const bool isElectron, const double x0, const double y0, double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const { // transport electrons and holes in the bulk // T. Kondo, 2010.9.9, 2017.7.20 // External parameters to be specified @@ -93,11 +120,11 @@ void SCT_InducedChargeModel::transport(const bool isElectron, double qstrip[NStrips]; // induced charges on strips due to an electron or a hole double vx, vy, D; for (int istrip=StartStrip; istrip<=EndStrip; istrip++) { - qstrip[istrip+Offset] = (isElectron ? -1. : +1.) * induced(istrip, x, y); // original induced charge by electron or hole + qstrip[istrip+Offset] = (isElectron ? -1. : +1.) * induced(data, istrip, x, y); // original induced charge by electron or hole } while (t_current < m_transportTimeMax) { if (!isInBulk) break; - if (!getVxVyD(isElectron, x, y, vx, vy, D, hashId, siPropertiesTool)) break; + if (!getVxVyD(data, isElectron, x, y, vx, vy, D, hashId, siPropertiesTool)) break; double delta_y = vy * m_transportTimeStep / Gaudi::Units::second; // ns -> s y += delta_y; double dt = m_transportTimeStep; // [nsec] @@ -133,7 +160,7 @@ void SCT_InducedChargeModel::transport(const bool isElectron, // get induced current by subtracting induced charges for (int istrip=StartStrip; istrip<=EndStrip; istrip++) { - double qnew = (isElectron ? -1. : +1.) * induced(istrip, x, y); + double qnew = (isElectron ? -1. : +1.) * induced(data, istrip, x, y); int jj = istrip + Offset; double dq = qnew - qstrip[jj]; qstrip[jj] = qnew; @@ -156,13 +183,15 @@ void SCT_InducedChargeModel::transport(const bool isElectron, //--------------------------------------------------------------------- // holeTransport //--------------------------------------------------------------------- -void SCT_InducedChargeModel::holeTransport(const double x0, const double y0, +void SCT_InducedChargeModel::holeTransport(const SCT_InducedChargeModelData& data, + const double x0, const double y0, double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const { // Q_m2[100],Q_m1[100],Q_00[100],Q_p1[100],Q_p2[100] NTransportSteps=100 const bool isElectron = false; - transport(isElectron, + transport(data, + isElectron, x0, y0, Q_m2, Q_m1, Q_00, Q_p1, Q_p2, hashId, @@ -172,13 +201,15 @@ void SCT_InducedChargeModel::holeTransport(const double x0, const double y0, //--------------------------------------------------------------------- // electronTransport //--------------------------------------------------------------------- -void SCT_InducedChargeModel::electronTransport(const double x0, const double y0, +void SCT_InducedChargeModel::electronTransport(const SCT_InducedChargeModelData& data, + const double x0, const double y0, double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const { // Q_m2[100],Q_m1[100],Q_00[100],Q_p1[100],Q_p2[100] NTransportSteps=100 const bool isElectron = true; - transport(isElectron, + transport(data, + isElectron, x0, y0, Q_m2, Q_m1, Q_00, Q_p1, Q_p2, hashId, @@ -188,12 +219,13 @@ void SCT_InducedChargeModel::electronTransport(const double x0, const double y0, //--------------------------------------------------------------- // Get parameters for electron or hole transport //--------------------------------------------------------------- -bool SCT_InducedChargeModel::getVxVyD(const bool isElectron, +bool SCT_InducedChargeModel::getVxVyD(const SCT_InducedChargeModelData& data, + const bool isElectron, const double x, const double y, double& vx, double& vy, double& D, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const { + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const { double Ex, Ey; - EField(x, y, Ex, Ey); // [V/cm] + getEField(data, x, y, Ex, Ey); // [V/cm] if (Ey > 0.) { if (isElectron) { // because electron has negative charge @@ -202,20 +234,27 @@ bool SCT_InducedChargeModel::getVxVyD(const bool isElectron, } const double E = std::sqrt(Ex*Ex+Ey*Ey); const double mu = (isElectron ? - siPropertiesTool->getSiProperties(hashId).calcElectronDriftMobility(m_T, E*CLHEP::volt/CLHEP::cm) : - siPropertiesTool->getSiProperties(hashId).calcHoleDriftMobility (m_T, E*CLHEP::volt/CLHEP::cm)) + siPropertiesTool->getSiProperties(hashId).calcElectronDriftMobility(data.m_T, E*CLHEP::volt/CLHEP::cm) : + siPropertiesTool->getSiProperties(hashId).calcHoleDriftMobility (data.m_T, E*CLHEP::volt/CLHEP::cm)) * (CLHEP::volt/CLHEP::cm)/(CLHEP::cm/CLHEP::s); const double v = mu * E; const double r = (isElectron ? - 1.13 + 0.0008*(m_T - Gaudi::Units::STP_Temperature) : - 0.72 - 0.0005*(m_T - Gaudi::Units::STP_Temperature)); - const double tanLA = r * mu * (isElectron ? -1. : +1.) * m_B / Gaudi::Units::tesla * Gaudi::Units::gauss; // because e has negative charge. + siPropertiesTool->getSiProperties(hashId).calcElectronHallFactor(data.m_T) : + siPropertiesTool->getSiProperties(hashId).calcHoleHallFactor(data.m_T)); + + const double tanLA = data.m_element->design().readoutSide() + * r * mu * (isElectron ? -1. : +1.) // because e has negative charge. + * data.m_element->hitDepthDirection() + * data.m_element->hitPhiDirection() + * (data.m_element->normal().cross(data.m_magneticField)).dot(data.m_element->phiAxis()) + / Gaudi::Units::tesla * Gaudi::Units::gauss * 1000.; // 1000. is to convert kTesla to Tesla. + const double secLA = std::sqrt(1.+tanLA*tanLA); const double cosLA = 1./secLA; const double sinLA = tanLA/secLA; vy = v * (Ey*cosLA - Ex*sinLA)/E; vx = v * (Ex*cosLA + Ey*sinLA)/E; - D = s_kB * m_T * mu/ s_e; + D = s_kB * data.m_T * mu/ s_e; return true; } return false; @@ -224,12 +263,16 @@ bool SCT_InducedChargeModel::getVxVyD(const bool isElectron, //------------------------------------------------------------------- // calculation of induced charge using Weighting (Ramo) function //------------------------------------------------------------------- -double SCT_InducedChargeModel::induced(const int istrip, const double x, const double y) const +double SCT_InducedChargeModel::induced(const SCT_InducedChargeModelData& data, + const int istrip, const double x, const double y) const { // x and y are the location of charge (e or hole) // induced charge on the strip "istrip" situated at the height y = d // the center of the strip (istrip=0) is x = 0.004 [cm] - double deltax = 0.0005, deltay = 0.00025; + + // Ramo potential : 80 divisions (81 points) with 5 um intervals from 40-440 um. + // In sensor depth directions 114 divisions (115 points) with 2.5 nm intervals for 285 um. + const double deltax = 0.0005, deltay = 0.00025; if (y < 0. || y > m_bulk_depth) return 0.; double xc = m_strip_pitch * (istrip + 0.5); @@ -241,10 +284,10 @@ double SCT_InducedChargeModel::induced(const int istrip, const double x, const d double fy = ( y - iy*deltay) / deltay; int ix1 = ix + 1; int iy1 = iy + 1; - double P = m_PotentialValue[ix ][iy ] *(1.-fx)*(1.-fy) - + m_PotentialValue[ix1][iy ] * fx *(1.-fy) - + m_PotentialValue[ix ][iy1] *(1.-fx)* fy - + m_PotentialValue[ix1][iy1] * fx* fy; + double P = m_PotentialValue[data.m_EFieldModel][ix ][iy ] *(1.-fx)*(1.-fy) + + m_PotentialValue[data.m_EFieldModel][ix1][iy ] * fx *(1.-fy) + + m_PotentialValue[data.m_EFieldModel][ix ][iy1] *(1.-fx)* fy + + m_PotentialValue[data.m_EFieldModel][ix1][iy1] * fx* fy; return P; } @@ -252,20 +295,23 @@ double SCT_InducedChargeModel::induced(const int istrip, const double x, const d //-------------------------------------------------------------- // Electric Field Ex and Ey //-------------------------------------------------------------- -void SCT_InducedChargeModel::EField(const double x, const double y, double& Ex, double& Ey) const { - // m_EFieldModel == UniformE 0; uniform E-field model - // m_EFieldModel == FlatDiodeModel 1; flat diode model - // m_EFieldModel == FEMsolutions 2; FEM solusions +void SCT_InducedChargeModel::getEField(const SCT_InducedChargeModelData& data, + const double x, const double y, double& Ex, double& Ey) const { + // m_EFieldModel == FlatDiodeModel 0; flat diode model + // m_EFieldModel == FEMsolutions 1; FEM solusions + // m_EFieldModel == UniformE 2; uniform E-field model // x == 0.0040 [cm] : at the center of strip // x must be within 0 and 0.008 [cm] - double deltay=0.00025, deltax=0.00025; // [cm] + // Electric field : 16 divisions (17 points) with 2.5 um intervals from 0-40 um. + // In sensor depth directions 114 divisions (115 points) with 2.5 nm intervals for 285 um. + const double deltay=0.00025, deltax=0.00025; // [cm] Ex = 0.; Ey = 0.; if (y < 0. || y > m_bulk_depth) return; //---------- case for FEM analysis solution ------------------------- - if (m_EFieldModel==FEMsolutions) { + if (data.m_EFieldModel==FEMsolutions) { int iy = static_cast<int>(y/deltay); double fy = (y-iy*deltay) / deltay; double xhalfpitch = m_strip_pitch/2.; @@ -274,7 +320,7 @@ void SCT_InducedChargeModel::EField(const double x, const double y, double& Ex, double xxx = xx; if (xx > xhalfpitch) xxx = m_strip_pitch - xx; int ix = static_cast<int>(xxx/deltax); - double fx = (xxx - ix*deltax) / deltax; + double fx = (xxx - ix*deltax) / deltax; int ix1 = ix+1; int iy1 = iy+1; @@ -282,10 +328,10 @@ void SCT_InducedChargeModel::EField(const double x, const double y, double& Ex, double Ey00 = 0., Ey10 = 0., Ey01 = 0., Ey11 = 0.; //-------- pick up appropriate data file for m_VD----------------------- - Ex00 = m_ExValue[ix][iy]; Ex10 = m_ExValue[ix1][iy]; - Ex01 = m_ExValue[ix][iy1]; Ex11 = m_ExValue[ix1][iy1]; - Ey00 = m_EyValue[ix][iy]; Ey10 = m_EyValue[ix1][iy]; - Ey01 = m_EyValue[ix][iy1]; Ey11 = m_EyValue[ix1][iy1]; + Ex00 = data.m_ExValue[ix][iy]; Ex10 = data.m_ExValue[ix1][iy]; + Ex01 = data.m_ExValue[ix][iy1]; Ex11 = data.m_ExValue[ix1][iy1]; + Ey00 = data.m_EyValue[ix][iy]; Ey10 = data.m_EyValue[ix1][iy]; + Ey01 = data.m_EyValue[ix][iy1]; Ey11 = data.m_EyValue[ix1][iy1]; //---------------- end of data bank search--- Ex = Ex00*(1.-fx)*(1.-fy) + Ex10*fx*(1.-fy) @@ -295,21 +341,21 @@ void SCT_InducedChargeModel::EField(const double x, const double y, double& Ex, + Ey01*(1.-fx)* fy + Ey11*fx* fy; } //---------- case for uniform electric field ------------------------ - else if (m_EFieldModel==UniformE) { - if (m_bulk_depth - y < m_depletion_depth && m_depletion_depth >0.) { - Ey = m_VB / m_depletion_depth; + else if (data.m_EFieldModel==UniformE) { + if (m_bulk_depth - y < data.m_depletion_depth && data.m_depletion_depth >0.) { + Ey = data.m_VB / data.m_depletion_depth; } else { Ey = 0.; } } //---------- case for flat diode model ------------------------------ - else if (m_EFieldModel==FlatDiodeModel) { - if (m_VB > std::abs(m_VD)) { - Ey = (m_VB+m_VD)/m_bulk_depth - 2.*m_VD*(m_bulk_depth-y)/(m_bulk_depth*m_bulk_depth); + else if (data.m_EFieldModel==FlatDiodeModel) { + if (data.m_VB > std::abs(data.m_VD)) { + Ey = (data.m_VB+data.m_VD)/m_bulk_depth - 2.*data.m_VD*(m_bulk_depth-y)/(m_bulk_depth*m_bulk_depth); } else { - if (m_bulk_depth - y < m_depletion_depth && m_depletion_depth >0.) { - double Emax = 2.* m_depletion_depth * std::abs(m_VD) / (m_bulk_depth*m_bulk_depth); - Ey = Emax*(1.-(m_bulk_depth-y)/m_depletion_depth); + if (m_bulk_depth - y < data.m_depletion_depth && data.m_depletion_depth >0.) { + double Emax = 2.* data.m_depletion_depth * std::abs(data.m_VD) / (m_bulk_depth*m_bulk_depth); + Ey = Emax*(1.-(m_bulk_depth-y)/data.m_depletion_depth); } else { Ey = 0.; } @@ -317,6 +363,23 @@ void SCT_InducedChargeModel::EField(const double x, const double y, double& Ex, } } +///////////////////////////////////////////////////////////////////// +size_t SCT_InducedChargeModel::getFEMIndex(SCT_InducedChargeModelData& data) const { + // Return index for s_VFD0 and EFieldModel. + // If vdepl is out of range of s_VFD0, EFieldModel of FlatDiodeModel is returned. + size_t iVFD = 0; + if (data.m_VD<s_VFD0[0] || data.m_VD>s_VFD0[s_VFD0.size()-1]) { // Out of range + data.m_EFieldModel = FlatDiodeModel; + } else { + float dVFD2 = 0.; + for (iVFD=0; iVFD<s_VFD0.size()-1; iVFD++) { + dVFD2 = s_VFD0[iVFD+1] - data.m_VD; + if (dVFD2 >= 0.) break; + } + } + return iVFD; +} + ///////////////////////////////////////////////////////////////////// void SCT_InducedChargeModel::loadICMParameters() { @@ -329,82 +392,90 @@ void SCT_InducedChargeModel::loadICMParameters() { TFile *hfile = new TFile(PathResolverFindCalibFile("SCT_Digitization/SCT_InducedChargedModel.root").c_str()); + // For Ramo Potential TH2F* h_Potential_FDM = static_cast<TH2F*>(hfile->Get("Potential_FDM")); TH2F* h_Potential_FEM = static_cast<TH2F*>(hfile->Get("Potential_FEM")); - - const float minBiasV_ICM_FEM = *std::min_element(s_VFD0.begin(), s_VFD0.end()); - const float maxBiasV_ICM_FEM = *std::max_element(s_VFD0.begin(), s_VFD0.end()); - if (m_VD<minBiasV_ICM_FEM || m_VD>maxBiasV_ICM_FEM) { - m_EFieldModel = FlatDiodeModel; // Change to FDM - ATH_MSG_INFO("Changed to Flat Diode Model since deplettion volage is out of range. (" - << minBiasV_ICM_FEM << " < m_VD < " << maxBiasV_ICM_FEM << " is allowed.)"); - } - - // For Ramo Potential - for (int ix=0; ix<NRamoPoints; ix++) { - for (int iy=0; iy<NDepthPoints; iy++) { - if (m_EFieldModel==FEMsolutions) { // FEM - m_PotentialValue[ix][iy] = h_Potential_FEM->GetBinContent(ix+1, iy+1); - } else { // FDM - m_PotentialValue[ix][iy] = h_Potential_FDM->GetBinContent(ix+1, iy+1); + // FDM case keeps only FDM potential. + // FEM case keeps both FDM and FEM potentials. + if (m_EFieldModel==FlatDiodeModel || m_EFieldModel==FEMsolutions) { + if (m_EFieldModel==FlatDiodeModel) m_PotentialValue.resize(FlatDiodeModel+1); + else m_PotentialValue.resize(FEMsolutions+1); + for (int ix=0; ix<NRamoPoints; ix++) { + for (int iy=0; iy<NDepthPoints; iy++) { + m_PotentialValue[FlatDiodeModel][ix][iy] = h_Potential_FDM->GetBinContent(ix+1, iy+1); + if (m_EFieldModel==FEMsolutions) { + m_PotentialValue[FEMsolutions][ix][iy] = h_Potential_FEM->GetBinContent(ix+1, iy+1); + } } } } - h_Potential_FDM->Delete(); h_Potential_FEM->Delete(); if (m_EFieldModel==FEMsolutions) { - - std::vector<std::string> hx_list; - std::vector<std::string> hy_list; + size_t i=0; + m_ExValue.resize(s_VFD0str.size()+1); + m_EyValue.resize(s_VFD0str.size()+1); for (const std::string& str : s_VFD0str) { - hx_list.push_back("Ex_FEM_"+str+"_0"); - hy_list.push_back("Ey_FEM_"+str+"_0"); + TH2F* h_Ex = static_cast<TH2F*>(hfile->Get(("Ex_FEM_"+str+"_0").c_str())); + TH2F* h_Ey = static_cast<TH2F*>(hfile->Get(("Ey_FEM_"+str+"_0").c_str())); + for (int ix=0; ix <NEFieldPoints; ix++){ + for (int iy=0; iy<NDepthPoints; iy++) { + m_ExValue[i][ix][iy] = h_Ex->GetBinContent(ix+1, iy+1); + m_EyValue[i][ix][iy] = h_Ey->GetBinContent(ix+1, iy+1); + } + } + h_Ex->Delete(); + h_Ey->Delete(); + i++; } - size_t iVFD = 0; - float dVFD1 = 0.; - float dVFD2 = 0.; - for (iVFD=0; iVFD<s_VFD0.size()-1; iVFD++) { // 2 of 9 will be seleted. - dVFD1 = m_VD - s_VFD0[iVFD]; - dVFD2 = s_VFD0[iVFD+1] - m_VD; - if (dVFD2 >= 0.) break; - } - - TH2F* h_Ex1 = static_cast<TH2F*>(hfile->Get((hx_list.at(iVFD)).c_str())); - TH2F* h_Ex2 = static_cast<TH2F*>(hfile->Get((hx_list.at(iVFD+1)).c_str())); - TH2F* h_Ey1 = static_cast<TH2F*>(hfile->Get((hy_list.at(iVFD)).c_str())); - TH2F* h_Ey2 = static_cast<TH2F*>(hfile->Get((hy_list.at(iVFD+1)).c_str())); TH2F* h_ExHV = static_cast<TH2F*>(hfile->Get("Ex_FEM_0_100")); TH2F* h_EyHV = static_cast<TH2F*>(hfile->Get("Ey_FEM_0_100")); - - float scalingFactor = m_VB / 100.; // Reference voltage is 100 V?? - - // For Electric field for (int ix=0; ix <NEFieldPoints; ix++){ for (int iy=0; iy<NDepthPoints; iy++) { - float Ex1 = h_Ex1->GetBinContent(ix+1, iy+1); - float Ex2 = h_Ex2->GetBinContent(ix+1, iy+1); - float ExHV = h_ExHV->GetBinContent(ix+1, iy+1); - m_ExValue[ix][iy] = (Ex1*dVFD2+Ex2*dVFD1)/(dVFD1+dVFD2); - m_ExValue[ix][iy] += ExHV*scalingFactor; - - float Ey1 = h_Ey1->GetBinContent(ix+1, iy+1); - float Ey2 = h_Ey2->GetBinContent(ix+1, iy+1); - float EyHV = h_EyHV->GetBinContent(ix+1, iy+1); - m_EyValue[ix][iy] = (Ey1*dVFD2+Ey2*dVFD1)/(dVFD1+dVFD2); - m_EyValue[ix][iy] += EyHV*scalingFactor; + m_ExValue[i][ix][iy] = h_ExHV->GetBinContent(ix+1, iy+1); + m_EyValue[i][ix][iy] = h_EyHV->GetBinContent(ix+1, iy+1); } } - - h_Ex1->Delete(); - h_Ex2->Delete(); - h_Ey1->Delete(); - h_Ey2->Delete(); h_ExHV->Delete(); h_EyHV->Delete(); } - + hfile->Close(); } + +void SCT_InducedChargeModel::setEField(SCT_InducedChargeModelData& data) const { + if (data.m_EFieldModel!=FEMsolutions) return; + + size_t iVFD = getFEMIndex(data); + if (data.m_EFieldModel==FlatDiodeModel) { + ATH_MSG_INFO("Changed to Flat Diode Model since deplettion volage is out of range. (" + << s_VFD0[0] << " < m_VD < " << s_VFD0[s_VFD0.size()-1] << " is allowed.)"); + return; + } + + const float dVFD1 = data.m_VD - s_VFD0[iVFD]; + const float dVFD2 = s_VFD0[iVFD+1] - data.m_VD; + + const float scalingFactor = data.m_VB / 100.; // Reference voltage is 100 V + + const size_t iHV = s_VFD0.size(); + + // For Electric field + for (int ix=0; ix <NEFieldPoints; ix++){ + for (int iy=0; iy<NDepthPoints; iy++) { + float Ex1 = m_ExValue[iVFD ][ix][iy]; + float Ex2 = m_ExValue[iVFD+1][ix][iy]; + float ExHV = m_ExValue[iHV ][ix][iy]; + data.m_ExValue[ix][iy] = (Ex1*dVFD2+Ex2*dVFD1)/(dVFD1+dVFD2); + data.m_ExValue[ix][iy] += ExHV*scalingFactor; + + float Ey1 = m_EyValue[iVFD ][ix][iy]; + float Ey2 = m_EyValue[iVFD+1][ix][iy]; + float EyHV = m_EyValue[iHV ][ix][iy]; + data.m_EyValue[ix][iy] = (Ey1*dVFD2+Ey2*dVFD1)/(dVFD1+dVFD2); + data.m_EyValue[ix][iy] += EyHV*scalingFactor; + } + } +} diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h index 1500bb8804ec..aebfb2669f41 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h @@ -15,15 +15,17 @@ // Athena #include "AthenaKernel/IAtRndmGenSvc.h" #include "AthenaKernel/MsgStreamMember.h" -#include "CxxUtils/checker_macros.h" #include "Identifier/IdentifierHash.h" #include "InDetConditionsSummaryService/ISiliconConditionsTool.h" +#include "InDetReadoutGeometry/SiDetectorElement.h" +#include "MagFieldConditions/AtlasFieldCacheCondObj.h" #include "PathResolver/PathResolver.h" #include "SiPropertiesTool/ISiPropertiesTool.h" // Gaudi #include "GaudiKernel/PhysicalConstants.h" #include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" // Random number #include "CLHEP/Random/RandFlat.h" @@ -32,51 +34,108 @@ #include "CLHEP/Units/SystemOfUnits.h" // C++ Standard Library +#include <array> +#include <memory> +#include <mutex> #include <string> +#include <utility> #include <vector> class SCT_InducedChargeModel { public: - enum EFieldModel {UniformE=0, FlatDiodeModel=1, FEMsolutions=2}; + enum EFieldModel {FlatDiodeModel=0, FEMsolutions=1, UniformE=2}; enum TransportStep {NTransportSteps=100}; + enum FEMNums {NRamoPoints=81, NEFieldPoints=17, NDepthPoints=115}; + enum InducedStrips {StartStrip=-2, EndStrip=+2, Offset=-StartStrip, NStrips=EndStrip+Offset+1}; - void init(const float vdepl, const float vbias, const IdentifierHash hashId, - ToolHandle<ISiliconConditionsTool>& siConditionsTool); + struct SCT_InducedChargeModelData { + float m_VD; // full depletion voltage [Volt] negative for type-P + float m_VB; // applied bias voltage [Volt] + float m_T; // temperature + float m_depletion_depth; + Amg::Vector3D m_magneticField; + EFieldModel m_EFieldModel; + const InDetDD::SiDetectorElement* m_element; + std::array<std::array<double, NDepthPoints>, NEFieldPoints> m_ExValue; + std::array<std::array<double, NDepthPoints>, NEFieldPoints> m_EyValue; + + SCT_InducedChargeModelData(const float vdepl, + const float vbias, + const InDetDD::SiDetectorElement* element, + const Amg::Vector3D& magneticField, // in kTesla + const float bulk_depth, + const EFieldModel model, + const ToolHandle<ISiliconConditionsTool> siConditionsTool) { + m_VD = vdepl; // full depletion voltage [Volt] negative for type-P + m_VB = vbias; // applied bias voltage [Volt] + m_element = element; + m_magneticField = magneticField; + + //------------ find delepletion deph for model=0 and 1 ------------- + m_depletion_depth = bulk_depth; + // for type N (before type inversion) + if (m_VD >= 0.) { + if (m_VB < m_VD) m_depletion_depth = std::sqrt(m_VB/m_VD) * bulk_depth; + } else { + // for type P + if (m_VB <= std::abs(m_VD)) m_depletion_depth = 0.; + } + + m_EFieldModel = model; + m_T = siConditionsTool->temperature(m_element->identifyHash()) + Gaudi::Units::STP_Temperature; + } + }; + + SCT_InducedChargeModel(size_t maxHash, EFieldModel model=FEMsolutions); + + SCT_InducedChargeModelData* + setWaferData(const float vdepl, + const float vbias, + const InDetDD::SiDetectorElement* element, + const AtlasFieldCacheCondObj* fieldCondObj, + const ToolHandle<ISiliconConditionsTool> siConditionsTool) const; void setRandomEngine(CLHEP::HepRandomEngine* rndmEngine) { m_rndmEngine = rndmEngine; }; - void setMagneticField(const double B) { m_B = - B*1000.; }; // m_B in [Tesla], B in kTesla - void transport(const bool isElectron, + void setEField(SCT_InducedChargeModelData& data) const; + + void transport(const SCT_InducedChargeModelData& data, + const bool isElectron, const double x0, const double y0, double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const; - void holeTransport(const double x0, const double y0, + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const; + void holeTransport(const SCT_InducedChargeModelData& data, + const double x0, const double y0, double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const; - void electronTransport(const double x0, const double y0, + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const; + void electronTransport(const SCT_InducedChargeModelData& data, + const double x0, const double y0, double* Q_m2, double* Q_m1, double* Q_00, double* Q_p1, double* Q_p2, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const; + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const; private: - enum InducedStrips {StartStrip=-2, EndStrip=+2, Offset=-StartStrip, NStrips=EndStrip+Offset+1}; void loadICMParameters(); - bool getVxVyD(const bool isElectron, + bool getVxVyD(const SCT_InducedChargeModelData& data, + const bool isElectron, const double x, const double y, double& vx, double& vy, double& D, const IdentifierHash hashId, - ToolHandle<ISiPropertiesTool>& siPropertiesTool) const; - double induced(const int istrip, const double x, const double y) const; - void EField(const double x, const double y, double& Ex, double& Ey) const; + const ToolHandle<ISiPropertiesTool> siPropertiesTool) const; + double induced(const SCT_InducedChargeModelData& data, + const int istrip, const double x, const double y) const; + void getEField(const SCT_InducedChargeModelData& data, + const double x, const double y, double& Ex, double& Ey) const; + size_t getFEMIndex(SCT_InducedChargeModelData& data) const; /// Log a message using the Athena controlled logging system MsgStream& msg(MSG::Level lvl) const { return m_msg << lvl; } /// Check whether the logging system is active at the provided verbosity level - bool msgLvl(MSG::Level lvl) { return m_msg.get().level() <= lvl; } + bool msgLvl(MSG::Level lvl) const { return m_msg.get().level() <= lvl; } //-------- parameters for e, h transport -------------------------------- static const double s_kB; // [m^2*kg/s^2/K] @@ -88,18 +147,13 @@ class SCT_InducedChargeModel { CLHEP::HepRandomEngine* m_rndmEngine; //!< Random number generation engine //------parameters given externally by jobOptions ------------------ - EFieldModel m_EFieldModel = FEMsolutions; // 0 (uniform E), 1 (flat diode model), 2 (FEM solusions) - double m_VD = -30.; // full depletion voltage [Volt] negative for type-P - double m_VB = 75.; // applied bias voltage [Volt] - double m_T; - double m_B; + EFieldModel m_EFieldModel; // 0 (flat diode model), 1 (FEM solusions), 2 (uniform E) double m_transportTimeStep = 0.50; // one step side in time [nsec] double m_transportTimeMax = m_transportTimeStep*NTransportSteps; // maximun tracing time [nsec] //------parameters mostly fixed but can be changed externally ------------ double m_bulk_depth = 0.0285; // in [cm] double m_strip_pitch = 0.0080; // in [cm] - double m_depletion_depth; double m_y_origin_min = 0.; //---------- arrays of FEM analysis ----------------------------------- @@ -110,11 +164,16 @@ class SCT_InducedChargeModel { // In sensor depth directions (for both potential and Electric field): // 114 divisions (115 points) with 2.5 nm intervals for 285 um. - enum FEMNums {NRamoPoints=81, NEFieldPoints=17, NDepthPoints=115}; + std::vector<std::array<std::array<double, NDepthPoints>, NRamoPoints>> m_PotentialValue; + std::vector<std::array<std::array<double, NDepthPoints>, NEFieldPoints>> m_ExValue; + std::vector<std::array<std::array<double, NDepthPoints>, NEFieldPoints>> m_EyValue; - double m_PotentialValue[NRamoPoints][NDepthPoints]; - double m_ExValue[NEFieldPoints][NDepthPoints]; - double m_EyValue[NEFieldPoints][NDepthPoints]; + // Cache of SCT_InducedChargeModelData for each wafer. + // Assuming wafer parameters do not change during a job. + // This should be almost always satisfied. + mutable std::vector<std::unique_ptr<SCT_InducedChargeModelData>> m_data ATLAS_THREAD_SAFE; // Guarded by m_mutex + // To protect concurrent access to m_data + mutable std::mutex m_mutex; static const std::vector<float> s_VFD0; static const std::vector<std::string> s_VFD0str; -- GitLab From 5170c5b993f05405d2c10b1191e4cdac33326bdc Mon Sep 17 00:00:00 2001 From: Susumu Oda <susumu.oda@cern.ch> Date: Thu, 22 Oct 2020 14:43:14 +0200 Subject: [PATCH 3/4] Implement an option to use SCT_InducedChargeModel as manual sweep of MR 37385 --- .../src/SCT_InducedChargeModel.cxx | 10 +- .../src/SCT_InducedChargeModel.h | 13 +-- .../src/SCT_SurfaceChargesGenerator.cxx | 102 +++++++++++++++--- .../src/SCT_SurfaceChargesGenerator.h | 13 ++- 4 files changed, 111 insertions(+), 27 deletions(-) diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx index ef3fe9ece6cd..4521adb2b339 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.cxx @@ -41,7 +41,8 @@ SCT_InducedChargeModel::setWaferData(const float vdepl, const float vbias, const InDetDD::SiDetectorElement* element, const AtlasFieldCacheCondObj* fieldCondObj, - const ToolHandle<ISiliconConditionsTool> siConditionsTool) const { + const ToolHandle<ISiliconConditionsTool> siConditionsTool, + CLHEP::HepRandomEngine* rndmEngine) const { std::lock_guard<std::mutex> lock(m_mutex); // If cache exists, cache is used. @@ -67,7 +68,8 @@ SCT_InducedChargeModel::setWaferData(const float vdepl, magneticField, m_bulk_depth, m_EFieldModel, - siConditionsTool); + siConditionsTool, + rndmEngine); //--- set electric fields --- setEField(*data); @@ -144,8 +146,8 @@ void SCT_InducedChargeModel::transport(const SCT_InducedChargeModelData& data, t_current += dt; x += vx * dt / Gaudi::Units::second; // ns -> s double diffusion = std::sqrt(2.* D * dt / Gaudi::Units::second); // ns -> s - y += diffusion * CLHEP::RandGaussZiggurat::shoot(m_rndmEngine, 0.0, 1.0); - x += diffusion * CLHEP::RandGaussZiggurat::shoot(m_rndmEngine, 0.0, 1.0); + y += diffusion * CLHEP::RandGaussZiggurat::shoot(data.m_rndmEngine, 0.0, 1.0); + x += diffusion * CLHEP::RandGaussZiggurat::shoot(data.m_rndmEngine, 0.0, 1.0); if (isElectron) { if (y < m_y_origin_min) { y = m_y_origin_min; diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h index aebfb2669f41..d25c00fa6d2c 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_InducedChargeModel.h @@ -54,9 +54,10 @@ class SCT_InducedChargeModel { float m_VB; // applied bias voltage [Volt] float m_T; // temperature float m_depletion_depth; + const InDetDD::SiDetectorElement* m_element; Amg::Vector3D m_magneticField; EFieldModel m_EFieldModel; - const InDetDD::SiDetectorElement* m_element; + CLHEP::HepRandomEngine* m_rndmEngine; std::array<std::array<double, NDepthPoints>, NEFieldPoints> m_ExValue; std::array<std::array<double, NDepthPoints>, NEFieldPoints> m_EyValue; @@ -66,7 +67,8 @@ class SCT_InducedChargeModel { const Amg::Vector3D& magneticField, // in kTesla const float bulk_depth, const EFieldModel model, - const ToolHandle<ISiliconConditionsTool> siConditionsTool) { + const ToolHandle<ISiliconConditionsTool> siConditionsTool, + CLHEP::HepRandomEngine* rndmEngine) { m_VD = vdepl; // full depletion voltage [Volt] negative for type-P m_VB = vbias; // applied bias voltage [Volt] m_element = element; @@ -84,6 +86,7 @@ class SCT_InducedChargeModel { m_EFieldModel = model; m_T = siConditionsTool->temperature(m_element->identifyHash()) + Gaudi::Units::STP_Temperature; + m_rndmEngine = rndmEngine; } }; @@ -94,8 +97,8 @@ class SCT_InducedChargeModel { const float vbias, const InDetDD::SiDetectorElement* element, const AtlasFieldCacheCondObj* fieldCondObj, - const ToolHandle<ISiliconConditionsTool> siConditionsTool) const; - void setRandomEngine(CLHEP::HepRandomEngine* rndmEngine) { m_rndmEngine = rndmEngine; }; + const ToolHandle<ISiliconConditionsTool> siConditionsTool, + CLHEP::HepRandomEngine* rndmEngine) const; void setEField(SCT_InducedChargeModelData& data) const; @@ -144,8 +147,6 @@ class SCT_InducedChargeModel { // Private message stream member mutable Athena::MsgStreamMember m_msg ATLAS_THREAD_SAFE; - CLHEP::HepRandomEngine* m_rndmEngine; //!< Random number generation engine - //------parameters given externally by jobOptions ------------------ EFieldModel m_EFieldModel; // 0 (flat diode model), 1 (FEM solusions), 2 (uniform E) double m_transportTimeStep = 0.50; // one step side in time [nsec] diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx index afbcb52c9653..5e360577cedf 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.cxx @@ -10,6 +10,7 @@ // Athena #include "GeneratorObjects/HepMcParticleLink.h" +#include "InDetIdentifier/SCT_ID.h" #include "InDetSimEvent/SiHit.h" // for SiHit, SiHit::::xDep, etc #include "HitManagement/TimedHitPtr.h" // for TimedHitPtr @@ -49,6 +50,8 @@ StatusCode SCT_SurfaceChargesGenerator::initialize() { // Get ISiliconConditionsSvc ATH_CHECK(m_siConditionsTool.retrieve()); + ATH_CHECK(m_fieldCacheCondObjInputKey.initialize(m_doInducedChargeModel)); + if (m_doTrapping) { // -- Get Radiation Damage Tool ATH_CHECK(m_radDamageTool.retrieve()); @@ -129,6 +132,13 @@ StatusCode SCT_SurfaceChargesGenerator::initialize() { } /////////////////////////////////////////////////// + // Induced Charge Module. + if (m_doInducedChargeModel) { + const SCT_ID* sct_id{nullptr}; + ATH_CHECK(detStore()->retrieve(sct_id, "SCT_ID")); + m_InducedChargeModel = std::make_unique<SCT_InducedChargeModel>(sct_id->wafer_hash_max()); + } + // Surface drift time calculation Stuff m_tHalfwayDrift = m_tSurfaceDrift * 0.5; m_distHalfInterStrip = m_distInterStrip * 0.5; @@ -304,7 +314,7 @@ void SCT_SurfaceChargesGenerator::processSiHit(const SiDetectorElement* element, const SiHit& phit, const ISiSurfaceChargesInserter& inserter, float p_eventTime, - unsigned short p_eventId, CLHEP::HepRandomEngine * rndmEngine) const { + unsigned short p_eventId, CLHEP::HepRandomEngine* rndmEngine) const { const SCT_ModuleSideDesign* design{dynamic_cast<const SCT_ModuleSideDesign*>(&(element->design()))}; if (design==nullptr) { ATH_MSG_ERROR("SCT_SurfaceChargesGenerator::process can not get " << design); @@ -353,6 +363,24 @@ void SCT_SurfaceChargesGenerator::processSiHit(const SiDetectorElement* element, float yhit{xPhi}; float zhit{xDep}; + SCT_InducedChargeModel::SCT_InducedChargeModelData* data{nullptr}; + if (m_doInducedChargeModel) { // Setting magnetic field for the ICM. + SG::ReadCondHandle<AtlasFieldCacheCondObj> readHandle{m_fieldCacheCondObjInputKey, Gaudi::Hive::currentContext()}; + const AtlasFieldCacheCondObj* fieldCondObj{*readHandle}; + float vdepl{m_vdepl}; + float vbias{m_vbias}; + if (m_useSiCondDB) { + vdepl = m_siConditionsTool->depletionVoltage(hashId); + vbias = m_siConditionsTool->biasVoltage(hashId); + } + data = m_InducedChargeModel->setWaferData(vdepl, + vbias, + element, + fieldCondObj, + m_siConditionsTool, + rndmEngine); + } + if (m_doDistortions) { if (element->isBarrel()) {// Only apply disortions to barrel modules Amg::Vector2D BOW; @@ -420,8 +448,12 @@ void SCT_SurfaceChargesGenerator::processSiHit(const SiDetectorElement* element, if (t_drift > 0.0) { const float x1{xhit + StepX * dstep}; float y1{yhit + StepY * dstep}; - y1 += tanLorentz * zReadout; // !< Taking into account the magnetic field - const float sigma{diffusionSigma(zReadout, element)}; + + float sigma{0.}; + if (not m_doInducedChargeModel) { + sigma = diffusionSigma(zReadout, element); + y1 += tanLorentz * zReadout; // !< Taking into account the magnetic field + } // These are treated in Induced Charge Model. for (int i{0}; i < m_numberOfCharges; ++i) { const float rx{CLHEP::RandGaussZiggurat::shoot(rndmEngine)}; @@ -491,21 +523,59 @@ void SCT_SurfaceChargesGenerator::processSiHit(const SiDetectorElement* element, } // m_doRamo==true } // chargeIsTrapped() } // m_doTrapping==true - + if (not m_doRamo) { - const SiLocalPosition position{element->hitLocalToLocal(xd, yd)}; - if (design->inActiveArea(position)) { - const float sdist{static_cast<float>(design->scaledDistanceToNearestDiode(position))}; // !< dist on the surface from the hit point to the nearest strip (diode) - const float t_surf{surfaceDriftTime(2.0 * sdist)}; // !< Surface drift time - const float totaltime{(m_tfix > -998.) ? m_tfix.value() : t_drift + timeOfFlight + t_surf}; // !< Total drift time - inserter(SiSurfaceCharge(position, SiCharge(q1, totaltime, hitproc, trklink))); - } else { - ATH_MSG_VERBOSE(std::fixed << std::setprecision(8) << "Local position (phi, eta, depth): (" - << position.xPhi() << ", " << position.xEta() << ", " << position.xDepth() - << ") of the element is out of active area, charge = " << q1); + if (m_doInducedChargeModel) { // Induced Charge Model + // Charges storages for 50 ns. 0.5 ns steps. + double Q_m2[SCT_InducedChargeModel::NTransportSteps]={0}; + double Q_m1[SCT_InducedChargeModel::NTransportSteps]={0}; + double Q_00[SCT_InducedChargeModel::NTransportSteps]={0}; + double Q_p1[SCT_InducedChargeModel::NTransportSteps]={0}; + double Q_p2[SCT_InducedChargeModel::NTransportSteps]={0}; + + const double mm2cm = 0.1; // For mm -> cm conversion + // Unit for y and z : mm -> cm in SCT_InducedChargeModel + m_InducedChargeModel->holeTransport(*data, + y0*mm2cm, z0*mm2cm, + Q_m2, Q_m1, Q_00, Q_p1, Q_p2, + hashId, m_siPropertiesTool); + m_InducedChargeModel->electronTransport(*data, + y0*mm2cm, z0*mm2cm, + Q_m2, Q_m1, Q_00, Q_p1, Q_p2, + hashId, m_siPropertiesTool); + + for (int it{0}; it<SCT_InducedChargeModel::NTransportSteps; it++) { + if (Q_00[it] == 0.0) continue; + double ICM_time{(it+0.5)*0.5 + timeOfFlight}; + double Q_new[SCT_InducedChargeModel::NStrips]{ + Q_m2[it], Q_m1[it], Q_00[it], Q_p1[it], Q_p2[it] + }; + for (int strip{SCT_InducedChargeModel::StartStrip}; strip<=SCT_InducedChargeModel::EndStrip; strip++) { + double ystrip{y1 + strip * stripPitch}; + SiLocalPosition position{element->hitLocalToLocal(x1, ystrip)}; + if (design->inActiveArea(position)) { + inserter(SiSurfaceCharge(position, + SiCharge(q1 * Q_new[strip+SCT_InducedChargeModel::Offset], + ICM_time, hitproc, trklink))); + } + } + } + } else { // not m_doInducedChargeModel + const SiLocalPosition position{element->hitLocalToLocal(xd, yd)}; + if (design->inActiveArea(position)) { + const float sdist{static_cast<float>(design->scaledDistanceToNearestDiode(position))}; + // !< dist on the surface from the hit point to the nearest strip (diode) + const float t_surf{surfaceDriftTime(2.0 * sdist)}; // !< Surface drift time + const float totaltime{(m_tfix > -998.) ? m_tfix.value() : t_drift + timeOfFlight + t_surf}; // !< Total drift time + inserter(SiSurfaceCharge(position, SiCharge(q1, totaltime, hitproc, trklink))); + } else { + ATH_MSG_VERBOSE(std::fixed << std::setprecision(8) << "Local position (phi, eta, depth): (" + << position.xPhi() << ", " << position.xEta() << ", " << position.xDepth() + << ") of the element is out of active area, charge = " << q1); + } } - } // end of loop on charges - } + } + } // end of loop on charges } } return; diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h index a6a89fabcdc0..ce8e9cc54b70 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h @@ -1,7 +1,7 @@ // -*- C++ -*- /* - Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ /** @@ -36,12 +36,16 @@ #include "AthenaBaseComps/AthAlgTool.h" #include "SCT_Digitization/ISCT_SurfaceChargesGenerator.h" +#include "SCT_InducedChargeModel.h" + #include "Identifier/IdentifierHash.h" #include "InDetConditionsSummaryService/ISiliconConditionsTool.h" #include "InDetCondTools/ISiLorentzAngleTool.h" +#include "MagFieldConditions/AtlasFieldCacheCondObj.h" #include "SCT_ConditionsTools/ISCT_RadDamageSummaryTool.h" #include "SCT_ModuleDistortions/ISCT_ModuleDistortionsTool.h" #include "SiPropertiesTool/ISiPropertiesTool.h" +#include "StoreGate/ReadCondHandle.h" // Gaudi #include "GaudiKernel/ITHistSvc.h" // for ITHistSvc @@ -123,6 +127,7 @@ class SCT_SurfaceChargesGenerator : public extends<AthAlgTool, ISCT_SurfaceCharg BooleanProperty m_doHistoTrap{this, "doHistoTrap", false, "Histogram the charge trapping effect"}; BooleanProperty m_doRamo{this, "doRamo", false, "Ramo Potential for charge trapping effect"}; BooleanProperty m_isOverlay{this, "isOverlay", false, "flag for overlay"}; + BooleanProperty m_doInducedChargeModel{this, "m_doInducedChargeModel", false, "Flag for Induced Charge Model"}; //ToolHandles ToolHandle<ISCT_ModuleDistortionsTool> m_distortionsTool{this, "SCTDistortionsTool", "SCT_DistortionsTool", "Tool to retrieve SCT distortions"}; @@ -133,6 +138,9 @@ class SCT_SurfaceChargesGenerator : public extends<AthAlgTool, ISCT_SurfaceCharg ServiceHandle<ITHistSvc> m_thistSvc{this, "THistSvc", "THistSvc"}; + SG::ReadCondHandleKey<AtlasFieldCacheCondObj> m_fieldCacheCondObjInputKey{ + this, "AtlasFieldCacheCondObj", "fieldCondObj", "Name of the Magnetic Field conditions object key"}; + float m_tHalfwayDrift{0.}; //!< Surface drift time float m_distInterStrip{1.0}; //!< Inter strip distance normalized to 1 float m_distHalfInterStrip{0.}; //!< Half way distance inter strip @@ -162,6 +170,9 @@ class SCT_SurfaceChargesGenerator : public extends<AthAlgTool, ISCT_SurfaceCharg TProfile* m_h_velocity_trap{nullptr}; TProfile* m_h_mobility_trap{nullptr}; TH1F* m_h_trap_pos{nullptr}; + + // For Induced Charge Module, M.Togawa + std::unique_ptr<SCT_InducedChargeModel> m_InducedChargeModel; }; #endif // SCT_SURFACECHARGESGENERATOR_H -- GitLab From 11b2d4ce5809f47029a550166f24777234e51bbe Mon Sep 17 00:00:00 2001 From: Susumu Oda <susumu.oda@cern.ch> Date: Thu, 22 Oct 2020 14:59:32 +0200 Subject: [PATCH 4/4] Change Property name to doInducedChargeModel --- .../SCT_Digitization/src/SCT_SurfaceChargesGenerator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h index ce8e9cc54b70..9510fc80b29c 100644 --- a/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h +++ b/InnerDetector/InDetDigitization/SCT_Digitization/src/SCT_SurfaceChargesGenerator.h @@ -127,7 +127,7 @@ class SCT_SurfaceChargesGenerator : public extends<AthAlgTool, ISCT_SurfaceCharg BooleanProperty m_doHistoTrap{this, "doHistoTrap", false, "Histogram the charge trapping effect"}; BooleanProperty m_doRamo{this, "doRamo", false, "Ramo Potential for charge trapping effect"}; BooleanProperty m_isOverlay{this, "isOverlay", false, "flag for overlay"}; - BooleanProperty m_doInducedChargeModel{this, "m_doInducedChargeModel", false, "Flag for Induced Charge Model"}; + BooleanProperty m_doInducedChargeModel{this, "doInducedChargeModel", false, "Flag for Induced Charge Model"}; //ToolHandles ToolHandle<ISCT_ModuleDistortionsTool> m_distortionsTool{this, "SCTDistortionsTool", "SCT_DistortionsTool", "Tool to retrieve SCT distortions"}; -- GitLab