Repository: HEP-FCC/k4RecCalorimeter
Pull request #140: Create noise map for new HCal segmentations
Author: login: Archil-AD
Created: 2025-02-24T12:32:12Z | Merged: 2025-03-10T12:30:37Z


BEGINRELEASENOTES
- The CreateFCCeeCaloNoiseLevelMap tool is updated to create noise map for phi-theta and phi-row HCal segmentations

ENDRELEASENOTES



Diff:
diff --git a/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp b/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp
index 243b0bd5b..41131494a 100644
--- a/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp
+++ b/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp
@@ -5,7 +5,8 @@
 #include "k4Interface/IGeoSvc.h"
 #include "detectorSegmentations/FCCSWGridModuleThetaMerged_k4geo.h"
 #include "detectorSegmentations/FCCSWEndcapTurbine_k4geo.h"
-
+#include "detectorSegmentations/FCCSWHCalPhiTheta_k4geo.h"
+#include "detectorSegmentations/FCCSWHCalPhiRow_k4geo.h"
 
 #include "TSystem.h"
 #include "TFile.h"
@@ -19,6 +20,7 @@ CreateFCCeeCaloNoiseLevelMap::CreateFCCeeCaloNoiseLevelMap(const std::string &aN
   declareProperty("ECalBarrelNoiseTool", m_ecalBarrelNoiseTool, "Handle for the cell noise tool of Barrel ECal");
   declareProperty("ECalEndcapNoiseTool", m_ecalEndcapNoiseTool, "Handle for the cell noise tool of Endcap ECal");
   declareProperty("HCalBarrelNoiseTool", m_hcalBarrelNoiseTool, "Handle for the cell noise tool of Barrel HCal");
+  declareProperty("HCalEndcapNoiseTool", m_hcalEndcapNoiseTool, "Handle for the cell noise tool of Endcap HCal");
   declareProperty("outputFileName", m_outputFileName, "Name of the output file");
 }
 
@@ -66,6 +68,15 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
     }
   }
 
+  if (!m_hcalEndcapNoiseTool.empty())
+  {
+    if (!m_hcalEndcapNoiseTool.retrieve())
+    {
+      error() << "Unable to retrieve the HCAL Endcap noise tool!!!" << endmsg;
+      return StatusCode::FAILURE;
+    }
+  }
+
   std::unordered_map<uint64_t, std::pair<double, double>> map;
 
   for (uint iSys = 0; iSys < m_readoutNamesSegmented.size(); iSys++)
@@ -85,6 +96,8 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
     
     dd4hep::DDSegmentation::GridTheta_k4geo *segmentation = nullptr;
     dd4hep::DDSegmentation::FCCSWGridPhiTheta_k4geo *phiThetaSegmentation = nullptr;
+    dd4hep::DDSegmentation::FCCSWHCalPhiTheta_k4geo *hcalPhiThetaSegmentation = nullptr;
+    dd4hep::DDSegmentation::FCCSWHCalPhiRow_k4geo *hcalPhiRowSegmentation = nullptr;
     dd4hep::DDSegmentation::FCCSWGridModuleThetaMerged_k4geo *moduleThetaSegmentation = nullptr;
     dd4hep::DDSegmentation::FCCSWEndcapTurbine_k4geo *endcapTurbineSegmentation = nullptr;
     if (segmentationType == "FCCSWGridModuleThetaMerged_k4geo")
@@ -101,17 +114,28 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
     {
       endcapTurbineSegmentation = dynamic_cast<dd4hep::DDSegmentation::FCCSWEndcapTurbine_k4geo *>(aSegmentation);
     }
+    else if (segmentationType == "FCCSWHCalPhiTheta_k4geo")
+    {
+      segmentation = dynamic_cast<dd4hep::DDSegmentation::GridTheta_k4geo *>(aSegmentation);
+      hcalPhiThetaSegmentation = dynamic_cast<dd4hep::DDSegmentation::FCCSWHCalPhiTheta_k4geo *>(aSegmentation);
+    }
+    else if (segmentationType == "FCCSWHCalPhiRow_k4geo")
+    {
+      segmentation = dynamic_cast<dd4hep::DDSegmentation::GridTheta_k4geo *>(aSegmentation);
+      hcalPhiRowSegmentation = dynamic_cast<dd4hep::DDSegmentation::FCCSWHCalPhiRow_k4geo *>(aSegmentation);
+    }
     else
     {
       error() << "Segmentation type not handled." << endmsg;
       return StatusCode::FAILURE;
     }
-    
-    if (segmentation)
+
+    if(segmentation && segmentationType != "FCCSWHCalPhiRow_k4geo")
     {
       info() << "Segmentation: size in Theta " << segmentation->gridSizeTheta() << endmsg;
       info() << "Segmentation: offset in Theta " << segmentation->offsetTheta() << endmsg;
     }
+
     if (segmentationType == "FCCSWGridModuleThetaMerged_k4geo")
     {
       info() << "Segmentation: bins in Module " << moduleThetaSegmentation->nModules() << endmsg;
@@ -121,6 +145,11 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
       info() << "Segmentation: size in Phi " << phiThetaSegmentation->gridSizePhi() << endmsg;
       info() << "Segmentation: offset in Phi " << phiThetaSegmentation->offsetPhi() << endmsg;
     }
+    else if (segmentationType == "FCCSWHCalPhiTheta_k4geo")
+    {
+      info() << "Segmentation: size in Phi " << hcalPhiThetaSegmentation->gridSizePhi() << endmsg;
+      info() << "Segmentation: offset in Phi " << hcalPhiThetaSegmentation->offsetPhi() << endmsg;
+    }
 
     // Loop over all cells in the calorimeter and retrieve existing cellIDs
     auto decoder = m_geoSvc->getDetector()->readout(m_readoutNamesSegmented[iSys]).idSpec().decoder();
@@ -322,6 +351,207 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
         } // end loop over wheel
       } // end looper over side
     } // end if (segmentationType == "FCCSWEndcapTurbine_k4geo")
+
+    if(segmentationType == "FCCSWHCalPhiTheta_k4geo" || segmentationType == "FCCSWHCalPhiRow_k4geo")
+    {
+      for (unsigned int ilayer = 0; ilayer < m_activeVolumesNumbersSegmented[iSys]; ilayer++)
+      {
+        // HCal phi-theta segmentation
+        if (segmentationType == "FCCSWHCalPhiTheta_k4geo")
+        {
+          // Set system and layer of volume ID
+          dd4hep::DDSegmentation::CellID volumeId = 0;
+          (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+          (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+          (*decoder)["theta"].set(volumeId, 0);
+          (*decoder)["phi"].set(volumeId, 0);
+
+          // Get number of segmentation cells within the active volume
+          std::array<uint, 3> numCells;
+          std::vector<int> thetaBins(hcalPhiThetaSegmentation->thetaBins(ilayer));
+          numCells[0] = hcalPhiThetaSegmentation->phiBins();
+
+          // Barrel
+          if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+          {
+            // number of cells in the layer
+            numCells[1] = thetaBins.size();
+            // ID of first cell theta bin (smallest theta)
+            if(numCells[1] > 0) numCells[2] = thetaBins[0];
+            else
+            {
+              error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+              return StatusCode::FAILURE;
+            }
+            debug() << "Layer: " << ilayer << endmsg;
+            debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for HCal barrel : " << numCells << endmsg;
+            // Loop over segmentation cells
+            for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+            {
+              for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+              {
+                dd4hep::DDSegmentation::CellID cellId = volumeId;
+                decoder->set(cellId, "phi", iphi);
+                decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+                uint64_t id = cellId;
+                double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+                double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+                map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+              }
+            }
+          } // barrel
+
+          // For endcap, determine noise separately for positive- and negative-z part
+          if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+          {
+            // number of cells in the layer
+            numCells[1] = thetaBins.size()/2; // thetaBins contains theta IDs for both positive- and negative-z parts, hence divide size by 2
+
+            // ID of first cell theta bin (smallest theta) in the positive-z part of the endcap
+            if(numCells[1] > 0) numCells[2] = thetaBins[0];
+            else
+            {
+              error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+              return StatusCode::FAILURE;
+            }
+
+            debug() << "Layer: " << ilayer << endmsg;
+            debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for positive-z HCal endcap : " << numCells << endmsg;
+            // Loop over segmentation cells
+            for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+            {
+              for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+              {
+                dd4hep::DDSegmentation::CellID cellId = volumeId;
+                decoder->set(cellId, "phi", iphi);
+                decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+                uint64_t id = cellId;
+                double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+                double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+                map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+              }
+            }
+
+            // ID of first cell theta bin (smallest theta) in the negative-z part of the endcap
+            numCells[2] = thetaBins[thetaBins.size()/2];
+
+            debug() << "Layer: " << ilayer << endmsg;
+            debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for negative-z HCal endcap : " << numCells << endmsg;
+            // Loop over segmentation cells
+            for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+            {
+              for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+              {
+                dd4hep::DDSegmentation::CellID cellId = volumeId;
+                decoder->set(cellId, "phi", iphi);
+                decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+                uint64_t id = cellId;
+                double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+                double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+                map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+              }
+            }
+          } // Endcap
+        }
+        // HCal phi-row segmentation
+        else if (segmentationType == "FCCSWHCalPhiRow_k4geo")
+        {
+          // Set system and layer of volume ID
+          dd4hep::DDSegmentation::CellID volumeId = 0;
+          (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+          (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+          (*decoder)["row"].set(volumeId, 0);
+          (*decoder)["phi"].set(volumeId, 0);
+
+          // Get number of segmentation cells within the active volume
+          std::array<int, 3> numCells;
+          std::vector<int> cellIndexes(hcalPhiRowSegmentation->cellIndexes(ilayer));
+          numCells[0] = hcalPhiRowSegmentation->phiBins();
+
+          // Barrel
+          if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+          {
+            // number of cells in the layer
+            numCells[1] = cellIndexes.size();
+            // minimum cell index
+            if(numCells[1] > 0) numCells[2] = cellIndexes.front();
+            else
+            {
+              error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+              return StatusCode::FAILURE;
+            }
+
+            debug() << "Layer: " << ilayer << endmsg;
+            debug() << "Number of segmentation cells in phi, in row, and min cell index, for HCal barrel : " << numCells << endmsg;
+            // Loop over segmentation cells
+            for (int iphi = 0; iphi < numCells[0]; iphi++)
+            {
+              for (int irow = 0; irow < numCells[1]; irow++)
+              {
+                dd4hep::DDSegmentation::CellID cellId = volumeId;
+                decoder->set(cellId, "phi", iphi);
+                decoder->set(cellId, "row", irow + numCells[2]); // start from the minimum existing cell index in this layer
+                uint64_t id = cellId;
+                double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+                double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+                map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+              }
+            }
+          } // barrel
+
+          // For endcap, determine noise separately for positive- and negative-z part
+          if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+          {
+            // number of cells in the layer
+            numCells[1] = cellIndexes.size()/2; // cellIndexes contains cell IDs for both positive- and negative-z parts, hence divide size by 2
+
+            // minimum cell index in the positive-z part of the endcap
+            if(numCells[1] > 0) numCells[2] = cellIndexes.front();
+            else
+            {
+              error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+              return StatusCode::FAILURE;
+            }
+            debug() << "Layer: " << ilayer << endmsg;
+            debug() << "Number of segmentation cells in phi, in row, and min cell index, for positive-z HCal endcap : " << numCells << endmsg;
+            // Loop over segmentation cells
+            for (int iphi = 0; iphi < numCells[0]; iphi++)
+            {
+              for (int irow = 0; irow < numCells[1]; irow++)
+              {
+                dd4hep::DDSegmentation::CellID cellId = volumeId;
+                decoder->set(cellId, "phi", iphi);
+                decoder->set(cellId, "row", irow + numCells[2]); // start from the minimum existing cell index in this layer
+                uint64_t id = cellId;
+                double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+                double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+                map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+              }
+            }
+
+            // minimum cell index in the negative-z part of the endcap
+            numCells[2] = cellIndexes.back();
+
+            debug() << "Layer: " << ilayer << endmsg;
+            debug() << "Number of segmentation cells in phi, in row, and min cell index, for negative-z HCal endcap : " << numCells << endmsg;
+            // Loop over segmentation cells
+            for (int iphi = 0; iphi < numCells[0]; iphi++)
+            {
+              for (int irow = 0; irow < numCells[1]; irow++)
+              {
+                dd4hep::DDSegmentation::CellID cellId = volumeId;
+                decoder->set(cellId, "phi", iphi);
+                decoder->set(cellId, "row", irow + numCells[2]); // start from the minimum cell index in this layer
+                uint64_t id = cellId;
+                double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+                double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+                map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+              }
+            }
+          } // Endcap
+        } // hcal phi-row segmentation
+      } // layer loop
+    } // hcal segmentations
   }
 
   // Check if output directory exists
diff --git a/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.h b/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.h
index 3d1fbe974..0d754791f 100644
--- a/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.h
+++ b/RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.h
@@ -45,22 +45,25 @@ class CreateFCCeeCaloNoiseLevelMap : public extends1<Service, ICaloCreateMap> {
   ToolHandle<INoiseConstTool> m_ecalEndcapNoiseTool{"ReadNoiseFromFileTool", this};
   /// Handle for the cells noise tool in HCal
   ToolHandle<INoiseConstTool> m_hcalBarrelNoiseTool{"ReadNoiseFromFileTool", this};
+  /// Handle for the cells noise tool in HCal
+  ToolHandle<INoiseConstTool> m_hcalEndcapNoiseTool{"ReadNoiseFromFileTool", this};
 
   // System ID of ECAL and HCAL detectors
   Gaudi::Property<uint> m_ecalBarrelSysId{this, "ecalBarrelSysId", 4};
   Gaudi::Property<uint> m_ecalEndcapSysId{this, "ecalEndcapSysId", 5};
   Gaudi::Property<uint> m_hcalBarrelSysId{this, "hcalBarrelSysId", 8};
+  Gaudi::Property<uint> m_hcalEndcapSysId{this, "hcalEndcapSysId", 9};
 
   /// Names of the detector readout for the volumes
-  Gaudi::Property<std::vector<std::string>> m_readoutNamesSegmented{this, "readoutNames", {"ECalBarrelModuleThetaMerged", "ECalEndcapTurbine", "BarHCal_Readout_phitheta"}};
+  Gaudi::Property<std::vector<std::string>> m_readoutNamesSegmented{this, "readoutNames", {"ECalBarrelModuleThetaMerged", "ECalEndcapTurbine", "HCalBarrelReadout","HCalEndcapReadout"}};
   /// Name of the fields describing the segmented volume
-  Gaudi::Property<std::vector<std::string>> m_fieldNamesSegmented{this, "systemNames", {"system", "system", "system"}};
+  Gaudi::Property<std::vector<std::string>> m_fieldNamesSegmented{this, "systemNames", {"system", "system", "system", "system"}};
   /// Values of the fields describing the segmented volume
-  Gaudi::Property<std::vector<int>> m_fieldValuesSegmented{this, "systemValues", {4, 5, 8}};
+  Gaudi::Property<std::vector<int>> m_fieldValuesSegmented{this, "systemValues", {4, 5, 8, 9}};
   /// Names of the active volume in geometry along radial axis (e.g. layer), the others are "module" or "phi", "theta"
-  Gaudi::Property<std::vector<std::string>> m_activeFieldNamesSegmented{this, "activeFieldNames", {"layer", "layer", "layer"}};
+  Gaudi::Property<std::vector<std::string>> m_activeFieldNamesSegmented{this, "activeFieldNames", {"layer", "layer", "layer", "layer"}};
   /// Number of layers in the segmented volumes
-  Gaudi::Property<std::vector<unsigned int>> m_activeVolumesNumbersSegmented{this, "activeVolumesNumbers", {11, 98, 13}};
+  Gaudi::Property<std::vector<unsigned int>> m_activeVolumesNumbersSegmented{this, "activeVolumesNumbers", {11, 98, 13, 37}};
   // Theta ranges of layers in the segmented volumes (if needed)
   Gaudi::Property<std::vector<std::vector<double>>> m_activeVolumesTheta{this, "activeVolumesTheta"};
 


Reviews:
user: login: giovannimarchiori
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T16:20:58Z
user: login: giovannimarchiori
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T16:28:34Z
user: login: giovannimarchiori
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-09T20:49:00Z
user: login: Archil-AD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T11:37:02Z
user: login: Archil-AD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T11:37:09Z
user: login: Archil-AD
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T11:37:35Z
user: login: giovannimarchiori
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T12:30:23Z

Review comments:
diff_hunk: @@ -196,6 +232,186 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
           }
         }
       }
+      // HCal phi-theta segmentation
+      else if (segmentationType == "FCCSWHCalPhiTheta_k4geo")
+      {
+        // Set system and layer of volume ID
+        dd4hep::DDSegmentation::CellID volumeId = 0;
+        (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+        (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+        (*decoder)["theta"].set(volumeId, 0);
+        (*decoder)["phi"].set(volumeId, 0);
+
+        // Get number of segmentation cells within the active volume
+        std::array<uint, 3> numCells;
+        std::vector<int> thetaBins(hcalPhiThetaSegmentation->thetaBins(ilayer));
+        numCells[0] = hcalPhiThetaSegmentation->phiBins();
+
+        // Barrel
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size();
+          // ID of first cell theta bin (smallest theta)
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for HCal barrel : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // barrel
+
+        // For endcap, determine noise separately for positive- and negative-z part
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size()/2; // thetaBins contains theta IDs for both positive- and negative-z parts, hence divide size by 2
+
+          // ID of first cell theta bin (smallest theta) in the positive-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for positive-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+
+          // ID of first cell theta bin (smallest theta) in the negative-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[thetaBins.size()/2];
path: RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp
user: login: giovannimarchiori
body: I would add a 

`return StatusCode::FAILURE;`
in the else of the previous 

```
         if(numCells[1] > 0) numCells[2] = thetaBins[0];
          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
```
in L284-285

then the `if(numCells[1] > 0)` check here is not needed anymore

(it's usually good to couple error() with a return StatusCode::FAILURE) 


created_at: 2025-03-07T16:20:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -196,6 +232,186 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
           }
         }
       }
+      // HCal phi-theta segmentation
+      else if (segmentationType == "FCCSWHCalPhiTheta_k4geo")
+      {
+        // Set system and layer of volume ID
+        dd4hep::DDSegmentation::CellID volumeId = 0;
+        (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+        (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+        (*decoder)["theta"].set(volumeId, 0);
+        (*decoder)["phi"].set(volumeId, 0);
+
+        // Get number of segmentation cells within the active volume
+        std::array<uint, 3> numCells;
+        std::vector<int> thetaBins(hcalPhiThetaSegmentation->thetaBins(ilayer));
+        numCells[0] = hcalPhiThetaSegmentation->phiBins();
+
+        // Barrel
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size();
+          // ID of first cell theta bin (smallest theta)
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for HCal barrel : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // barrel
+
+        // For endcap, determine noise separately for positive- and negative-z part
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size()/2; // thetaBins contains theta IDs for both positive- and negative-z parts, hence divide size by 2
+
+          // ID of first cell theta bin (smallest theta) in the positive-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for positive-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+
+          // ID of first cell theta bin (smallest theta) in the negative-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[thetaBins.size()/2];
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for negative-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // Endcap
+      }
+      // HCal phi-row segmentation
+      else if (segmentationType == "FCCSWHCalPhiRow_k4geo")
+      {
+        // Set system and layer of volume ID
+        dd4hep::DDSegmentation::CellID volumeId = 0;
+        (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+        (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+        (*decoder)["row"].set(volumeId, 0);
+        (*decoder)["phi"].set(volumeId, 0);
+
+        // Get number of segmentation cells within the active volume
+        std::array<int, 3> numCells;
+        std::vector<int> cellIndexes(hcalPhiRowSegmentation->cellIndexes(ilayer));
+        numCells[0] = hcalPhiRowSegmentation->phiBins();
+
+        // Barrel
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = cellIndexes.size();
+          // minimum cell index
+          if(numCells[1] > 0) numCells[2] = cellIndexes.front();
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in row, and min cell index, for HCal barrel : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (int irow = 0; irow < numCells[1]; irow++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "row", irow + numCells[2]); // start from the minimum existing cell index in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // barrel
+
+        // For endcap, determine noise separately for positive- and negative-z part
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = cellIndexes.size()/2; // cellIndexes contains cell IDs for both positive- and negative-z parts, hence divide size by 2
+
+          // minimum cell index in the positive-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = cellIndexes.front();
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in row, and min cell index, for positive-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (int irow = 0; irow < numCells[1]; irow++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "row", irow + numCells[2]); // start from the minimum existing cell index in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+
+          // minimum cell index in the negative-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = cellIndexes.back();
path: RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp
user: login: giovannimarchiori
body: same comment (remove failure in if () before and remove if(numCells[1] > 0) here)
created_at: 2025-03-07T16:28:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,21 +42,24 @@ class CreateFCCeeCaloNoiseLevelMap : public extends1<Service, ICaloCreateMap> {
   ToolHandle<INoiseConstTool> m_ecalBarrelNoiseTool{"ReadNoiseFromFileTool", this};
   /// Handle for the cells noise tool in HCal
   ToolHandle<INoiseConstTool> m_hcalBarrelNoiseTool{"ReadNoiseFromFileTool", this};
+  /// Handle for the cells noise tool in HCal
+  ToolHandle<INoiseConstTool> m_hcalEndcapNoiseTool{"ReadNoiseFromFileTool", this};
 
   // System ID of ECAL and HCAL barrels
   Gaudi::Property<uint> m_ecalBarrelSysId{this, "ecalBarrelSysId", 4};
   Gaudi::Property<uint> m_hcalBarrelSysId{this, "hcalBarrelSysId", 8};
+  Gaudi::Property<uint> m_hcalEndcapSysId{this, "hcalEndcapSysId", 9};
 
   /// Names of the detector readout for the volumes
-  Gaudi::Property<std::vector<std::string>> m_readoutNamesSegmented{this, "readoutNames", {"ECalBarrelModuleThetaMerged", "BarHCal_Readout_phitheta"}};
+  Gaudi::Property<std::vector<std::string>> m_readoutNamesSegmented{this, "readoutNames", {"ECalBarrelModuleThetaMerged","HCalBarrelReadout","HCalEndcapReadout"}};
   /// Name of the fields describing the segmented volume
-  Gaudi::Property<std::vector<std::string>> m_fieldNamesSegmented{this, "systemNames", {"system", "system"}};
+  Gaudi::Property<std::vector<std::string>> m_fieldNamesSegmented{this, "systemNames", {"system", "system", "system"}};
   /// Values of the fields describing the segmented volume
-  Gaudi::Property<std::vector<int>> m_fieldValuesSegmented{this, "systemValues", {4, 8}};
+  Gaudi::Property<std::vector<int>> m_fieldValuesSegmented{this, "systemValues", {4, 8, 9}};
   /// Names of the active volume in geometry along radial axis (e.g. layer), the others are "module" or "phi", "theta"
   Gaudi::Property<std::vector<std::string>> m_activeFieldNamesSegmented{this, "activeFieldNames", {"layer", "layer"}};
path: RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.h
user: login: giovannimarchiori
body: shouldn't you add a further "layer" here ?
created_at: 2025-03-09T20:48:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -196,6 +232,186 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
           }
         }
       }
+      // HCal phi-theta segmentation
+      else if (segmentationType == "FCCSWHCalPhiTheta_k4geo")
+      {
+        // Set system and layer of volume ID
+        dd4hep::DDSegmentation::CellID volumeId = 0;
+        (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+        (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+        (*decoder)["theta"].set(volumeId, 0);
+        (*decoder)["phi"].set(volumeId, 0);
+
+        // Get number of segmentation cells within the active volume
+        std::array<uint, 3> numCells;
+        std::vector<int> thetaBins(hcalPhiThetaSegmentation->thetaBins(ilayer));
+        numCells[0] = hcalPhiThetaSegmentation->phiBins();
+
+        // Barrel
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size();
+          // ID of first cell theta bin (smallest theta)
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for HCal barrel : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // barrel
+
+        // For endcap, determine noise separately for positive- and negative-z part
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size()/2; // thetaBins contains theta IDs for both positive- and negative-z parts, hence divide size by 2
+
+          // ID of first cell theta bin (smallest theta) in the positive-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for positive-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+
+          // ID of first cell theta bin (smallest theta) in the negative-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[thetaBins.size()/2];
path: RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp
user: login: Archil-AD
body: thanks for the suggestion.
This is done now.
created_at: 2025-03-10T11:37:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -196,6 +232,186 @@ StatusCode CreateFCCeeCaloNoiseLevelMap::initialize()
           }
         }
       }
+      // HCal phi-theta segmentation
+      else if (segmentationType == "FCCSWHCalPhiTheta_k4geo")
+      {
+        // Set system and layer of volume ID
+        dd4hep::DDSegmentation::CellID volumeId = 0;
+        (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+        (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+        (*decoder)["theta"].set(volumeId, 0);
+        (*decoder)["phi"].set(volumeId, 0);
+
+        // Get number of segmentation cells within the active volume
+        std::array<uint, 3> numCells;
+        std::vector<int> thetaBins(hcalPhiThetaSegmentation->thetaBins(ilayer));
+        numCells[0] = hcalPhiThetaSegmentation->phiBins();
+
+        // Barrel
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size();
+          // ID of first cell theta bin (smallest theta)
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for HCal barrel : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // barrel
+
+        // For endcap, determine noise separately for positive- and negative-z part
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = thetaBins.size()/2; // thetaBins contains theta IDs for both positive- and negative-z parts, hence divide size by 2
+
+          // ID of first cell theta bin (smallest theta) in the positive-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[0];
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for positive-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+
+          // ID of first cell theta bin (smallest theta) in the negative-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = thetaBins[thetaBins.size()/2];
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in theta, and min theta ID, for negative-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (unsigned int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (unsigned int itheta = 0; itheta < numCells[1]; itheta++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "theta", itheta + numCells[2]); // start from the minimum existing theta cell in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // Endcap
+      }
+      // HCal phi-row segmentation
+      else if (segmentationType == "FCCSWHCalPhiRow_k4geo")
+      {
+        // Set system and layer of volume ID
+        dd4hep::DDSegmentation::CellID volumeId = 0;
+        (*decoder)[m_fieldNamesSegmented[iSys]].set(volumeId, m_fieldValuesSegmented[iSys]);
+        (*decoder)[m_activeFieldNamesSegmented[iSys]].set(volumeId, ilayer);
+        (*decoder)["row"].set(volumeId, 0);
+        (*decoder)["phi"].set(volumeId, 0);
+
+        // Get number of segmentation cells within the active volume
+        std::array<int, 3> numCells;
+        std::vector<int> cellIndexes(hcalPhiRowSegmentation->cellIndexes(ilayer));
+        numCells[0] = hcalPhiRowSegmentation->phiBins();
+
+        // Barrel
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalBarrelSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = cellIndexes.size();
+          // minimum cell index
+          if(numCells[1] > 0) numCells[2] = cellIndexes.front();
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in row, and min cell index, for HCal barrel : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (int irow = 0; irow < numCells[1]; irow++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "row", irow + numCells[2]); // start from the minimum existing cell index in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalBarrelNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalBarrelNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+        } // barrel
+
+        // For endcap, determine noise separately for positive- and negative-z part
+        if(m_fieldNamesSegmented[iSys] == "system" && m_fieldValuesSegmented[iSys] == m_hcalEndcapSysId)
+        {
+          // number of cells in the layer
+          numCells[1] = cellIndexes.size()/2; // cellIndexes contains cell IDs for both positive- and negative-z parts, hence divide size by 2
+
+          // minimum cell index in the positive-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = cellIndexes.front();
+          else error() << "Can not get number of cells from the segmentation object: " << segmentationType << endmsg;
+
+          debug() << "Layer: " << ilayer << endmsg;
+          debug() << "Number of segmentation cells in phi, in row, and min cell index, for positive-z HCal endcap : " << numCells << endmsg;
+          // Loop over segmentation cells
+          for (int iphi = 0; iphi < numCells[0]; iphi++)
+          {
+            for (int irow = 0; irow < numCells[1]; irow++)
+            {
+              dd4hep::DDSegmentation::CellID cellId = volumeId;
+              decoder->set(cellId, "phi", iphi);
+              decoder->set(cellId, "row", irow + numCells[2]); // start from the minimum existing cell index in this layer
+              uint64_t id = cellId;
+              double noiseRMS = m_hcalEndcapNoiseTool->getNoiseRMSPerCell(id);
+              double noiseOffset = m_hcalEndcapNoiseTool->getNoiseOffsetPerCell(id);
+              map.insert(std::pair<uint64_t, std::pair<double, double>>(id, std::make_pair(noiseRMS, noiseOffset)));
+            }
+          }
+
+          // minimum cell index in the negative-z part of the endcap
+          if(numCells[1] > 0) numCells[2] = cellIndexes.back();
path: RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.cpp
user: login: Archil-AD
body: done.
created_at: 2025-03-10T11:37:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,21 +42,24 @@ class CreateFCCeeCaloNoiseLevelMap : public extends1<Service, ICaloCreateMap> {
   ToolHandle<INoiseConstTool> m_ecalBarrelNoiseTool{"ReadNoiseFromFileTool", this};
   /// Handle for the cells noise tool in HCal
   ToolHandle<INoiseConstTool> m_hcalBarrelNoiseTool{"ReadNoiseFromFileTool", this};
+  /// Handle for the cells noise tool in HCal
+  ToolHandle<INoiseConstTool> m_hcalEndcapNoiseTool{"ReadNoiseFromFileTool", this};
 
   // System ID of ECAL and HCAL barrels
   Gaudi::Property<uint> m_ecalBarrelSysId{this, "ecalBarrelSysId", 4};
   Gaudi::Property<uint> m_hcalBarrelSysId{this, "hcalBarrelSysId", 8};
+  Gaudi::Property<uint> m_hcalEndcapSysId{this, "hcalEndcapSysId", 9};
 
   /// Names of the detector readout for the volumes
-  Gaudi::Property<std::vector<std::string>> m_readoutNamesSegmented{this, "readoutNames", {"ECalBarrelModuleThetaMerged", "BarHCal_Readout_phitheta"}};
+  Gaudi::Property<std::vector<std::string>> m_readoutNamesSegmented{this, "readoutNames", {"ECalBarrelModuleThetaMerged","HCalBarrelReadout","HCalEndcapReadout"}};
   /// Name of the fields describing the segmented volume
-  Gaudi::Property<std::vector<std::string>> m_fieldNamesSegmented{this, "systemNames", {"system", "system"}};
+  Gaudi::Property<std::vector<std::string>> m_fieldNamesSegmented{this, "systemNames", {"system", "system", "system"}};
   /// Values of the fields describing the segmented volume
-  Gaudi::Property<std::vector<int>> m_fieldValuesSegmented{this, "systemValues", {4, 8}};
+  Gaudi::Property<std::vector<int>> m_fieldValuesSegmented{this, "systemValues", {4, 8, 9}};
   /// Names of the active volume in geometry along radial axis (e.g. layer), the others are "module" or "phi", "theta"
   Gaudi::Property<std::vector<std::string>> m_activeFieldNamesSegmented{this, "activeFieldNames", {"layer", "layer"}};
path: RecFCCeeCalorimeter/src/components/CreateFCCeeCaloNoiseLevelMap.h
user: login: Archil-AD
body: right, thanks for spotting this. 
it is fixed now.
created_at: 2025-03-10T11:37:35Z
author_association: CONTRIBUTOR

PR comments:
user: login: giovannimarchiori
created_at: 2025-03-07T16:35:09Z
body: Hi @Archil-AD 
thanks, sorry for the delay! 
very clean code, only two minor comments, if you can fix them (and rebase since we merged another PR meanwhile) I would then approve and merge the PR
Thanks, Giovanni
author_association: CONTRIBUTOR
user: login: Archil-AD
created_at: 2025-03-10T11:36:24Z
body: Hi @giovannimarchiori , I have rebased and applied small fixes as you suggested.
Best regards,
Archil
author_association: CONTRIBUTOR
user: login: giovannimarchiori
created_at: 2025-03-10T12:29:21Z
body: Thank you @Archil-AD , approved!

author_association: CONTRIBUTOR