Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/SHiPGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,13 @@ GeoPhysVol* SHiPGeometryBuilder::build() {
world->add(new GeoTransform(timingDetectorTrf));
world->add(timingDetector);

// Build and place Calorimeter (container with ECAL front, ECAL back, HCAL)
// Full calorimeter spans Z: 96.87 to 99.77 m → centre: 98.32 m
// Build and place Calorimeter (ECAL + HCAL).
// The layer structure is driven by calo.cfg; the outer container dimensions
// and placement are fixed to match the SHiP subsystem envelope.
CalorimeterFactory calorimeterFactory(materials);
GeoPhysVol* calorimeter = calorimeterFactory.build();
GeoTrf::Transform3D calorimeterTrf =
GeoTrf::Translate3D(0.0, 0.0, 98.32 * 1000.0); // Convert m to mm
GeoTrf::Translate3D(0.0, 0.0, 98.32 * 1000.0); // 98.32 m, fixed envelope centre
world->add(new GeoNameTag("/SHiP/calorimeter"));
world->add(new GeoIdentifierTag(8));
world->add(new GeoTransform(calorimeterTrf));
Expand Down
39 changes: 39 additions & 0 deletions src/SHiPMaterials.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ void SHiPMaterials::createElements() {
// Aluminium
m_elements["Aluminium"] = new GeoElement(
"Aluminium", "Al", 13.0, 26.982 * GeoModelKernelUnits::g / GeoModelKernelUnits::mole);

// Lead
m_elements["Lead"] = new GeoElement(
"Lead", "Pb", 82.0, 207.2 * GeoModelKernelUnits::g / GeoModelKernelUnits::mole);
}

void SHiPMaterials::createMaterials() {
Expand Down Expand Up @@ -179,6 +183,41 @@ void SHiPMaterials::createMaterials() {
scintillator->add(m_elements["Hydrogen"], 0.085);
scintillator->lock();
m_materials["Scintillator"] = scintillator;

// Lead (density 11.34 g/cm³): pure Pb
GeoMaterial* lead =
new GeoMaterial("Lead", 11.34 * GeoModelKernelUnits::g / GeoModelKernelUnits::cm3);
lead->add(m_elements["Lead"], 1.0);
lead->lock();
m_materials["Lead"] = lead;

// PVT / polyvinyltoluene (density 1.032 g/cm³): C9H10
// MW = 9*12.011 + 10*1.008 = 108.099 + 10.080 = 118.179 g/mol
{
const double awC = 12.011;
const double awH = 1.008;
const double mw = 9.0 * awC + 10.0 * awH;
GeoMaterial* pvt =
new GeoMaterial("PVT", 1.032 * GeoModelKernelUnits::g / GeoModelKernelUnits::cm3);
pvt->add(m_elements["Carbon"], 9.0 * awC / mw);
pvt->add(m_elements["Hydrogen"], 10.0 * awH / mw);
pvt->lock();
m_materials["PVT"] = pvt;
}

// Polystyrene (density 1.05 g/cm³): C8H8
// MW = 8*12.011 + 8*1.008 = 96.088 + 8.064 = 104.152 g/mol
{
const double awC = 12.011;
const double awH = 1.008;
const double mw = 8.0 * awC + 8.0 * awH;
GeoMaterial* polystyrene =
new GeoMaterial("Polystyrene", 1.05 * GeoModelKernelUnits::g / GeoModelKernelUnits::cm3);
polystyrene->add(m_elements["Carbon"], 8.0 * awC / mw);
polystyrene->add(m_elements["Hydrogen"], 8.0 * awH / mw);
polystyrene->lock();
m_materials["Polystyrene"] = polystyrene;
}
}

} // namespace SHiPGeometry
39 changes: 37 additions & 2 deletions subsystems/Calorimeter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
# SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) CERN for the benefit of the SHiP Collaboration

add_library(Calorimeter src/CalorimeterFactory.cpp)
# Stage calo.cfg into the build directory so tests running from there find it.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/calo.cfg
${CMAKE_CURRENT_BINARY_DIR}/calo.cfg
COPYONLY
)
# Also stage into the top-level build dir for test_builder and OverlapCheck.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/calo.cfg
${CMAKE_BINARY_DIR}/calo.cfg
COPYONLY
)

add_library(Calorimeter
src/CalorimeterFactory.cpp
src/CalorimeterConfig.cpp
src/CaloBarLayer.cpp
src/CaloFibreHPLayer.cpp
)

target_include_directories(
Calorimeter
Expand All @@ -13,12 +31,29 @@ target_include_directories(

target_link_libraries(Calorimeter PUBLIC GeoModelCore::GeoModelKernel)

# Bake the absolute source-tree path as a compile-time fallback so the factory
# can always find calo.cfg even when CWD doesn't contain it.
target_compile_definitions(Calorimeter
PRIVATE
# Source-tree fallback (always valid during development and CI builds).
CALO_CFG_DEFAULT_PATH="${CMAKE_CURRENT_SOURCE_DIR}/calo.cfg"
# Install-time fallback: set to the installed data directory so that
# deployed builds (where the source tree is absent) can find calo.cfg.
CALO_CFG_INSTALL_PATH="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/SHiPGeometry/calo.cfg"
)

install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/calo.cfg
DESTINATION ${CMAKE_INSTALL_DATADIR}/SHiPGeometry
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if(BUILD_TESTING)
include(Catch)
add_executable(test_calorimeter test_calorimeter.cpp)
target_link_libraries(
test_calorimeter
PRIVATE Calorimeter SHiPGeometry Catch2::Catch2WithMain
)
catch_discover_tests(test_calorimeter)
catch_discover_tests(test_calorimeter
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
endif()
38 changes: 38 additions & 0 deletions subsystems/Calorimeter/calo.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
plate_xy_mm = 2160
lead_thickness_mm = 3
scint_thickness_mm = 10
pvt_thickness_mm = 10

#How many calo modules in the x and y directions?
module_nx = 2
module_ny = 3

module_pitch_x_mm = 0.0
module_pitch_y_mm = 0.0

tol_x_mm = 10
tol_y_mm = 10
tol_z_mm = 10

# Layer codes: 1=WidePVT, 3=ThinPS, 5 HPL, 7=Lead, 8 split, maybe there is a better way to input these codes?
layers = 7,1,7,2,7,3,7,4,7,1,7,2,7,3,7,4,7,1,7,2,5,6,8,7,3,7,4,7,1,7,2,5,6,7,3,7,4,7,1,7,2,7,3,7,4,7,1,7,2,5,6,7,3,7,4,7,1,7,2,7,3,7,4,7,1,7,2,7,3,7,4,7,1,7,2,7,3,7,4,7,1,7,2,7,3,7,4

#HPLs
hpl_thickness_mm = 10
fiber_diameter_mm = 1.2
fiber_core_diameter_mm = 1.0


airgap_mm = 1000


#HCAL section

gap_ecal_hcal_mm = 100;
#Layer codes are identical to above. 7 is iron though
layers2 = 7,1,7,2,7,1,7,2,7,1
iron_thickness_mm = 170

detector_offset_z_mm = 96970.0
detector_offset_x_mm = 0.0
detector_offset_y_mm = 0.0
72 changes: 36 additions & 36 deletions subsystems/Calorimeter/include/Calorimeter/CalorimeterFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,62 @@

#pragma once

#include <string>

class GeoPhysVol;

namespace SHiPGeometry {

class SHiPMaterials;
struct CalorimeterConfig;

/**
* @brief Factory for the Calorimeter (electromagnetic + hadronic calorimeter) geometry
* @brief Factory for the Calorimeter (ECAL + HCAL) geometry.
*
* Creates a fixed-size container volume matching the SHiP envelope
* (3.00 × 3.50 × 1.45 m half-sizes, centred at Z = 98 320 mm) and fills
* it with the real layer-by-layer geometry driven by calo.cfg.
*
* Creates a container with three sections:
* - ECAL front: Z 96.87-97.07 m → centre 96.97 m, half-length 0.10 m, 2.25×3.50 m
* - ECAL back: Z 98.07-98.67 m → centre 98.37 m, half-length 0.30 m, 2.75×3.50 m
* - HCAL: Z 98.77-99.77 m → centre 99.27 m, half-length 0.50 m, 3.00×3.50 m
* The config file is resolved at build() time:
* 1. "calo.cfg" relative to the current working directory (works when
* running from the build directory, where CMake stages the file).
* 2. The absolute source-tree path baked in at compile time via
* CALO_CFG_DEFAULT_PATH (always valid during development).
*/
class CalorimeterFactory {
public:
explicit CalorimeterFactory(SHiPMaterials& materials);
explicit CalorimeterFactory(SHiPMaterials& materials,
std::string configPath = "calo.cfg");
~CalorimeterFactory() = default;

/** Build and return the calorimeter container volume. */
GeoPhysVol* build();

/**
* @brief Build the Calorimeter geometry
* @return Pointer to container volume with ECAL front, ECAL back, and HCAL
* @brief Compute the total Z extent of one ECAL+gap+HCAL stack (mm).
*
* Public so tests and placement code can query the stack thickness
* independently of a full build().
*/
GeoPhysVol* build();
static double totalStackZ(const CalorimeterConfig& cfg);

/** Return the config path that will actually be opened (after resolution). */
std::string resolvedConfigPath() const;

private:
SHiPMaterials& m_materials;
std::string m_configPath;

// Component dimensions (convert m to mm)
// Note: GeoModel uses mm internally, so 1m = 1000mm

// ECAL front
static constexpr double s_ecalFrontHalfX = 2250.0; // 2.25 m
static constexpr double s_ecalFrontHalfY = 3500.0; // 3.50 m
static constexpr double s_ecalFrontHalfZ = 100.0; // 0.10 m
static constexpr double s_ecalFrontZ = 96970.0; // 96.97 m

// ECAL back
static constexpr double s_ecalBackHalfX = 2750.0; // 2.75 m
static constexpr double s_ecalBackHalfY = 3500.0; // 3.50 m
static constexpr double s_ecalBackHalfZ = 300.0; // 0.30 m
static constexpr double s_ecalBackZ = 98370.0; // 98.37 m

// HCAL
static constexpr double s_hcalHalfX = 3000.0; // 3.00 m
static constexpr double s_hcalHalfY = 3500.0; // 3.50 m
static constexpr double s_hcalHalfZ = 500.0; // 0.50 m
static constexpr double s_hcalZ = 99270.0; // 99.27 m
/** Place one NX×NY tiled stack of layers inside @p container. */
void buildStack(GeoPhysVol* container, const CalorimeterConfig& cfg,
int mx, int my, double offsetX, double offsetY) const;

// Container dimensions (spans all components)
// From CSV: ECAL front 96.87-97.07, ECAL back 98.07-98.67, HCAL 98.77-99.77
// Full span: 96.87 to 99.77 m → centre: 98.32 m, half-length: 1.45 m
static constexpr double s_containerHalfX = s_hcalHalfX; // Use largest X
static constexpr double s_containerHalfY = s_hcalHalfY; // Use largest Y
static constexpr double s_containerHalfZ = 1450.0; // 1.45 m
static constexpr double s_containerCentreZ = 98320.0; // 98.32 m
// ── Fixed container dimensions (mm) ─────────────────────────────────
// These match the SHiP subsystem envelope from subsystem_envelopes.csv
// and must not change — tests and the consistency check depend on them.
static constexpr double s_containerHalfX = 3000.0; // 3.00 m
static constexpr double s_containerHalfY = 3500.0; // 3.50 m
static constexpr double s_containerHalfZ = 1450.0; // 1.45 m
};

} // namespace SHiPGeometry
Loading
Loading