Belle II Software development
crystal_volumes_masses.py
1
8
9"""Compute the volume and mass of every ECL crystal shape from the Geant4 solids.
10
11The solids are built exactly as in GeoECLCreator::wrapped_crystal(): the shape
12parameters are read with load_shapes() (ecl/data/crystal_shape_*.dat, or the
13ECLCrystalsShapeAndPosition payload) and turned into BelleCrystal solids via
14shape_t::get_solid() with zero wrapping thickness, i.e. the bare CsI(Tl) crystal.
15
16The volume is BelleCrystal::GetCubicVolume(), exact (sum over the triangulated
17faces). The mass uses the density of G4_CESIUM_IODIDE (4.51 g/cm3), the material
18assigned to the crystals in the simulation.
19
20These numbers reproduce the Volume(cc) and Weight(kg) columns of
21ecl/data/crystal_shape_*.dat (Ikeda's thesis tables): exactly for the barrel
22(e.g. 987.80 and 1112.22 cc), and within ~0.1-0.3% for the endcaps (e.g. forward
23shape 1: 921.7 vs 923 cc). For the per-cellID mapping see crystal_shapes_per_cellid.py.
24"""
25
26import ROOT
27
28ROOT.gSystem.Load("libecl.so")
29ROOT.gInterpreter.Declare(r"""
30#include <ecl/geometry/shapes.h>
31#include <ecl/geometry/BelleCrystal.h>
32#include <G4SystemOfUnits.hh>
33
34/** Volume of every crystal shape: {part, shape number, volume [cm3]} */
35std::vector<std::array<double, 3>> eclShapeVolumes()
36{
37 using namespace Belle2::ECL;
38 auto shapesAndPositions = loadCrystalsShapeAndPosition();
39 std::vector<std::array<double, 3>> volumes;
40 for (ECLParts part : {ECLParts::forward, ECLParts::barrel, ECLParts::backward}) {
41 for (const shape_t* shape : load_shapes(&shapesAndPositions, part)) {
42 G4Translate3D shift;
43 const double wrapThickness = 0; // bare crystal, no wrapping
44 auto* crystal = static_cast<BelleCrystal*>(shape->get_solid("crystal", wrapThickness, shift));
45 volumes.push_back({double(part), double(shape->nshape), crystal->GetCubicVolume() / cm3});
46 }
47 }
48 return volumes;
49}
50""")
51
52
53CSI_DENSITY = 4.51
54
55part_names = {0: "forward", 1: "barrel", 2: "backward"}
56for part, shape_number, volume in ROOT.eclShapeVolumes():
57 mass = volume * CSI_DENSITY / 1000 # kg
58 print(f"{part_names[int(part)]:8s} {int(shape_number):3d} V={volume:8.2f} cm3 m={mass:6.3f} kg")