10Map every ECL cellID (1..8736) to its crystal shape, volume and mass.
12Everything is taken from the plain text tables in ecl/data, no geometry is built:
14 cellID -> (thetaID, phiID) ECLGeometryPar mapping tables
15 -> crystal placement index as in ECLGeometryPar::read()
16 -> shape number (nshape) crystal_placement_<part>.dat
17 -> volume and mass of that shape crystal_shape_<part>.dat
19The Volume(cc) column of crystal_shape_<part>.dat is reproduced by the Geant4
20BelleCrystal solids used in the simulation (see crystal_volumes_masses.py), so
21these numbers are consistent with the simulated geometry.
38RING_START_CORRECTION = ([0, -5, -10, -14, -18, -22, -24, -26, -28, -30, -32, -34, -33]
39 + list(range(-32, 14))
40 + [14, 15, 16, 14, 12, 10, 8, 6, 2, -2])
43SHAPES_PER_RING = [3, 3, 4, 4, 4, 6, 6, 6, 6, 6, 6, 9, 9] + [2] * 46 + [9, 9, 6, 6, 6, 6, 6, 4, 4, 4]
46RING_PLACEMENT_OFFSET = ([0, 3, 6, 10, 14, 18, 24, 30, 36, 42, 48, 54, 63]
47 + list(range(132, 224, 2))
48 + [72, 81, 90, 96, 102, 108, 114, 120, 124, 128])
51def data_rows(filename):
52 """Yield the whitespace-separated fields of every non-empty, non-comment line."""
53 for line
in open(basf2.find_file(f
"ecl/data/{filename}")):
54 fields = line.split(
"#")[0].split()
59def part_placements(part):
60 """Return the (part, shape number) of every crystal placement of an ECL part.
62 Same selection as load_placements(): the entries with nshape >= 1000 are the
63 global transformations of the part, not crystals, and are skipped.
65 return [(part, int(fields[0]))
for fields
in data_rows(f
"crystal_placement_{part}.dat")
66 if len(fields) == 7
and int(fields[0]) < 1000]
71placements = part_placements(
"forward") + part_placements(
"backward") + part_placements(
"barrel")
72assert len(placements) == N_PLACEMENTS
75shape_volume_mass = {(part, int(fields[0])): (float(fields[-2]), float(fields[-1]))
76 for part
in (
"forward",
"barrel",
"backward")
77 for fields
in data_rows(f
"crystal_shape_{part}.dat")}
80def crystal_info(cell_id):
81 """Return (thetaID, phiID, part, shape number, volume [cc], mass [kg]) of a cellID."""
83 theta_id = max(i
for i
in range(N_THETA_RINGS)
if RING_START_CORRECTION[i] * 16 + i * 128 <= index)
84 phi_id = index - RING_START_CORRECTION[theta_id] * 16 - theta_id * 128
85 part, shape_number = placements[RING_PLACEMENT_OFFSET[theta_id] + phi_id % SHAPES_PER_RING[theta_id]]
86 volume, mass = shape_volume_mass[(part, shape_number)]
87 return theta_id, phi_id, part, shape_number, volume, mass
90if __name__ ==
"__main__":
91 print(f
"{'cellID':>6s} {'thetaID':>7s} {'phiID':>5s} {'part':8s} {'shape':>5s} "
92 f
"{'V [cc]':>8s} {'m [kg]':>6s}")
93 for cell_id
in range(1, N_CRYSTALS + 1):
94 theta_id, phi_id, part, shape_number, volume, mass = crystal_info(cell_id)
95 print(f
"{cell_id:6d} {theta_id:7d} {phi_id:5d} {part:8s} {shape_number:5d} "
96 f
"{volume:8.2f} {mass:6.3f}")