legend-pygeom-hades 0.1.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. legend_pygeom_hades-0.1.0a0.dist-info/METADATA +62 -0
  2. legend_pygeom_hades-0.1.0a0.dist-info/RECORD +85 -0
  3. legend_pygeom_hades-0.1.0a0.dist-info/WHEEL +5 -0
  4. legend_pygeom_hades-0.1.0a0.dist-info/entry_points.txt +2 -0
  5. legend_pygeom_hades-0.1.0a0.dist-info/licenses/LICENSE +674 -0
  6. legend_pygeom_hades-0.1.0a0.dist-info/top_level.txt +1 -0
  7. pygeomhades/__init__.py +6 -0
  8. pygeomhades/_version.py +34 -0
  9. pygeomhades/cli.py +169 -0
  10. pygeomhades/configs/dummy_geom/B99000A.yaml +25 -0
  11. pygeomhades/configs/dummy_geom/C99000A.yaml +31 -0
  12. pygeomhades/configs/dummy_geom/P99000A.yaml +20 -0
  13. pygeomhades/configs/dummy_geom/V99000A.yaml +31 -0
  14. pygeomhades/configs/holder_wrap/B00000B.yaml +37 -0
  15. pygeomhades/configs/holder_wrap/B00000D.yaml +37 -0
  16. pygeomhades/configs/holder_wrap/B00002C.yaml +37 -0
  17. pygeomhades/configs/holder_wrap/B00032B.yaml +37 -0
  18. pygeomhades/configs/holder_wrap/B00035A.yaml +37 -0
  19. pygeomhades/configs/holder_wrap/B00035B.yaml +37 -0
  20. pygeomhades/configs/holder_wrap/B00061C.yaml +37 -0
  21. pygeomhades/configs/holder_wrap/B00076C.yaml +37 -0
  22. pygeomhades/configs/holder_wrap/B00091B.yaml +37 -0
  23. pygeomhades/configs/holder_wrap/V00048B.yaml +37 -0
  24. pygeomhades/configs/holder_wrap/V02160A.yaml +37 -0
  25. pygeomhades/configs/holder_wrap/V02160B.yaml +37 -0
  26. pygeomhades/configs/holder_wrap/V02162B.yaml +37 -0
  27. pygeomhades/configs/holder_wrap/V02166B.yaml +37 -0
  28. pygeomhades/configs/holder_wrap/V03421A.yaml +37 -0
  29. pygeomhades/configs/holder_wrap/V03422A.yaml +37 -0
  30. pygeomhades/configs/holder_wrap/V04199A.yaml +37 -0
  31. pygeomhades/configs/holder_wrap/V04545A.yaml +37 -0
  32. pygeomhades/configs/holder_wrap/V04549A.yaml +37 -0
  33. pygeomhades/configs/holder_wrap/V04549B.yaml +37 -0
  34. pygeomhades/configs/holder_wrap/V05261A.yaml +37 -0
  35. pygeomhades/configs/holder_wrap/V05261B.yaml +37 -0
  36. pygeomhades/configs/holder_wrap/V05266A.yaml +37 -0
  37. pygeomhades/configs/holder_wrap/V05266B.yaml +37 -0
  38. pygeomhades/configs/holder_wrap/V05267A.yaml +37 -0
  39. pygeomhades/configs/holder_wrap/V05267B.yaml +37 -0
  40. pygeomhades/configs/holder_wrap/V05268A.yaml +37 -0
  41. pygeomhades/configs/holder_wrap/V05268B.yaml +37 -0
  42. pygeomhades/configs/holder_wrap/V05612A.yaml +37 -0
  43. pygeomhades/configs/holder_wrap/V05612B.yaml +37 -0
  44. pygeomhades/configs/holder_wrap/V06643A.yaml +29 -0
  45. pygeomhades/configs/holder_wrap/V06649A.yaml +29 -0
  46. pygeomhades/configs/holder_wrap/V06659A.yaml +29 -0
  47. pygeomhades/configs/holder_wrap/V07298B.yaml +37 -0
  48. pygeomhades/configs/holder_wrap/V07302A.yaml +37 -0
  49. pygeomhades/configs/holder_wrap/V07302B.yaml +37 -0
  50. pygeomhades/configs/holder_wrap/V07646A.yaml +37 -0
  51. pygeomhades/configs/holder_wrap/V07647A.yaml +37 -0
  52. pygeomhades/configs/holder_wrap/V07647B.yaml +37 -0
  53. pygeomhades/configs/holder_wrap/V08682A.yaml +37 -0
  54. pygeomhades/configs/holder_wrap/V08682B.yaml +37 -0
  55. pygeomhades/configs/holder_wrap/V09372A.yaml +37 -0
  56. pygeomhades/configs/holder_wrap/V09374A.yaml +37 -0
  57. pygeomhades/configs/holder_wrap/V09724A.yaml +37 -0
  58. pygeomhades/configs/holder_wrap/V10437B.yaml +37 -0
  59. pygeomhades/configs/holder_wrap/V10447B.yaml +37 -0
  60. pygeomhades/configs/holder_wrap/V11924A.yaml +37 -0
  61. pygeomhades/configs/holder_wrap/V11925A.yaml +37 -0
  62. pygeomhades/configs/holder_wrap/V11947B.yaml +37 -0
  63. pygeomhades/configs/holder_wrap/V14673A.yaml +37 -0
  64. pygeomhades/configs/vis-scene.yaml +0 -0
  65. pygeomhades/core.py +275 -0
  66. pygeomhades/create_volumes.py +571 -0
  67. pygeomhades/dimensions.py +283 -0
  68. pygeomhades/metadata.py +28 -0
  69. pygeomhades/models/dummy/bottom_plate_dummy.gdml +44 -0
  70. pygeomhades/models/dummy/cryostat_dummy.gdml +57 -0
  71. pygeomhades/models/dummy/holder_bege_dummy.gdml +61 -0
  72. pygeomhades/models/dummy/holder_icpc_dummy.gdml +78 -0
  73. pygeomhades/models/dummy/lead_castle_table1_dummy.gdml +71 -0
  74. pygeomhades/models/dummy/lead_castle_table2_dummy.gdml +73 -0
  75. pygeomhades/models/dummy/source_am_collimated_dummy.gdml +97 -0
  76. pygeomhades/models/dummy/source_am_dummy.gdml +64 -0
  77. pygeomhades/models/dummy/source_ba_dummy.gdml +72 -0
  78. pygeomhades/models/dummy/source_co_dummy.gdml +71 -0
  79. pygeomhades/models/dummy/source_holder_am_dummy.gdml +73 -0
  80. pygeomhades/models/dummy/source_holder_dummy.gdml +61 -0
  81. pygeomhades/models/dummy/source_holder_th_lat_dummy.gdml +54 -0
  82. pygeomhades/models/dummy/source_th_dummy.gdml +134 -0
  83. pygeomhades/models/dummy/source_th_plates_dummy.gdml +36 -0
  84. pygeomhades/models/dummy/wrap_dummy.gdml +50 -0
  85. pygeomhades/utils.py +101 -0
@@ -0,0 +1,37 @@
1
+ detector:
2
+ name: V11925A
3
+ position: 7.0
4
+ holder:
5
+ geometry:
6
+ bottom_cyl:
7
+ inner:
8
+ height_in_mm: 15.9
9
+ radius_in_mm: 8.0
10
+ outer:
11
+ height_in_mm: 25.4
12
+ radius_in_mm: 13.0
13
+ cylinder:
14
+ inner:
15
+ height_in_mm: 118.0
16
+ radius_in_mm: 46.5
17
+ outer:
18
+ height_in_mm: 121.1
19
+ radius_in_mm: 47.3
20
+ edge:
21
+ height_in_mm: 1.3
22
+ radius_in_mm: 49.5
23
+ rings:
24
+ height_in_mm: 8.6
25
+ position_bottom_ring_in_mm: 77.4
26
+ position_top_ring_in_mm: 40.0
27
+ radius_in_mm: 49.5
28
+ position: 5.5
29
+ wrap:
30
+ geometry:
31
+ inner:
32
+ height_in_mm: 118.5
33
+ radius_in_mm: 45.5
34
+ outer:
35
+ height_in_mm: 119.5
36
+ radius_in_mm: 46.2
37
+ position: 4.5
@@ -0,0 +1,37 @@
1
+ detector:
2
+ name: V11947B
3
+ position: 7.0
4
+ holder:
5
+ geometry:
6
+ bottom_cyl:
7
+ inner:
8
+ height_in_mm: 15.9
9
+ radius_in_mm: 8.0
10
+ outer:
11
+ height_in_mm: 25.4
12
+ radius_in_mm: 13.0
13
+ cylinder:
14
+ inner:
15
+ height_in_mm: 118.0
16
+ radius_in_mm: 47.5
17
+ outer:
18
+ height_in_mm: 121.1
19
+ radius_in_mm: 48.3
20
+ edge:
21
+ height_in_mm: 1.3
22
+ radius_in_mm: 50.5
23
+ rings:
24
+ height_in_mm: 8.6
25
+ position_bottom_ring_in_mm: 77.4
26
+ position_top_ring_in_mm: 40.0
27
+ radius_in_mm: 50.5
28
+ position: 6.0
29
+ wrap:
30
+ geometry:
31
+ inner:
32
+ height_in_mm: 114.0
33
+ radius_in_mm: 46.5
34
+ outer:
35
+ height_in_mm: 115.0
36
+ radius_in_mm: 47.2
37
+ position: 6.0
@@ -0,0 +1,37 @@
1
+ detector:
2
+ name: V14673A
3
+ position: 6.0
4
+ holder:
5
+ geometry:
6
+ bottom_cyl:
7
+ inner:
8
+ height_in_mm: 15.9
9
+ radius_in_mm: 8.0
10
+ outer:
11
+ height_in_mm: 25.4
12
+ radius_in_mm: 13.0
13
+ cylinder:
14
+ inner:
15
+ height_in_mm: 117.0
16
+ radius_in_mm: 47.2
17
+ outer:
18
+ height_in_mm: 120.1
19
+ radius_in_mm: 48.0
20
+ edge:
21
+ height_in_mm: 1.3
22
+ radius_in_mm: 50.2
23
+ rings:
24
+ height_in_mm: 8.6
25
+ position_bottom_ring_in_mm: 76.4
26
+ position_top_ring_in_mm: 14.0
27
+ radius_in_mm: 50.2
28
+ position: 5.0
29
+ wrap:
30
+ geometry:
31
+ inner:
32
+ height_in_mm: 112.0
33
+ radius_in_mm: 46.0
34
+ outer:
35
+ height_in_mm: 113.0
36
+ radius_in_mm: 46.7
37
+ position: 5.0
File without changes
pygeomhades/core.py ADDED
@@ -0,0 +1,275 @@
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ import logging
5
+ from collections.abc import Mapping
6
+ from importlib import resources
7
+ from pathlib import Path
8
+
9
+ import dbetto
10
+ import numpy as np
11
+ import pygeomtools
12
+ from dbetto import TextDB
13
+ from git import GitCommandError
14
+ from legendmeta import LegendMetadata
15
+ from pyg4ometry import geant4
16
+ from pygeomhpges import make_hpge
17
+
18
+ from pygeomhades import dimensions as dim
19
+ from pygeomhades.create_volumes import (
20
+ create_bottom_plate,
21
+ create_cryostat,
22
+ create_holder,
23
+ create_lead_castle,
24
+ create_source,
25
+ create_source_holder,
26
+ create_th_plate,
27
+ create_vacuum_cavity,
28
+ create_wrap,
29
+ )
30
+ from pygeomhades.metadata import PublicMetadataProxy
31
+ from pygeomhades.utils import merge_configs, parse_measurement
32
+
33
+ log = logging.getLogger(__name__)
34
+
35
+
36
+ DEFAULT_ASSEMBLIES = {"hpge", "lead_castle"}
37
+
38
+
39
+ def _place_pv(
40
+ lv: geant4.LogicalVolume,
41
+ name: str,
42
+ mother_lv: geant4.LogicalVolume,
43
+ reg: geant4.Registry,
44
+ *,
45
+ x_in_mm: float = 0,
46
+ y_in_mm: float = 0,
47
+ z_in_mm: float = 0,
48
+ invert_z_axes: bool = False,
49
+ ) -> geant4.PhysicalVolume:
50
+ """Wrapper to place the physical volume more concisely."""
51
+
52
+ rot = [0, np.pi, 0, "rad"] if invert_z_axes else [0, 0, 0, "rad"]
53
+
54
+ return geant4.PhysicalVolume(
55
+ rot,
56
+ [x_in_mm, y_in_mm, z_in_mm, "mm"],
57
+ lv,
58
+ name,
59
+ mother_lv,
60
+ registry=reg,
61
+ )
62
+
63
+
64
+ def construct(
65
+ hpge_name: str,
66
+ measurement: str,
67
+ config: Mapping,
68
+ assemblies: list[str] | set[str] = DEFAULT_ASSEMBLIES,
69
+ extra_meta: TextDB | Path | str | None = None,
70
+ public_geometry: bool = False,
71
+ construct_unverified: bool = False,
72
+ ) -> geant4.Registry:
73
+ """Construct the HADES geometry and return the registry containing the world volume.
74
+
75
+ Parameters
76
+ ----------
77
+ hpge_name
78
+ Name of the detector, e.g., "V07302A".
79
+ measurement
80
+ Name of the measurement, e.g., "am_HS1_top_dlt".
81
+ config
82
+ configuration dictionary defining the geometry, e.g.,
83
+
84
+ .. code-block:: yaml
85
+
86
+ source_position:
87
+ phi_in_deg: 0.0
88
+ r_in_mm: 86.0
89
+ z_in_mm: 3.0
90
+ lead_castle_idx: 1
91
+
92
+ assemblies
93
+ A list of assemblies to construct, should be a subset of:
94
+ - hpge: the detector, cryostat, holder and wrap.
95
+ - lead_castle: the shielding and bottom plate.
96
+ - source: the source and its holder.
97
+
98
+ extra_meta
99
+ Extra metadata needed to construct the geometry (or a path to it). If
100
+ `None` then this is taken as `pygeomhades/configs/holder_wrap`.
101
+ public_geometry
102
+ if true, uses the public geometry metadata instead of the LEGEND-internal
103
+ legend-metadata.
104
+ construct_unverified
105
+ If true, allows construction of unverified assemblies such as the source assembly.
106
+ Default is False.
107
+ """
108
+
109
+ if extra_meta is None:
110
+ extra_meta = TextDB(resources.files("pygeomhades") / "configs" / "holder_wrap")
111
+ elif not isinstance(extra_meta, TextDB):
112
+ extra_meta = TextDB(extra_meta)
113
+
114
+ if isinstance(config, str):
115
+ config = dbetto.utils.load_dict(config)
116
+
117
+ config = dbetto.AttrsDict(config)
118
+
119
+ lmeta = None
120
+ if not public_geometry:
121
+ with contextlib.suppress(GitCommandError):
122
+ lmeta = LegendMetadata(lazy=True)
123
+
124
+ # require user action to construct a testdata-only geometry (i.e. to avoid accidental creation of "wrong"
125
+ # geometries by LEGEND members).
126
+ if lmeta is None and not public_geometry:
127
+ msg = "cannot construct geometry from public testdata only, if not explicitly instructed"
128
+ raise RuntimeError(msg)
129
+
130
+ if lmeta is None:
131
+ log.warning("CONSTRUCTING GEOMETRY FROM PUBLIC DATA ONLY")
132
+ lmeta = PublicMetadataProxy()
133
+
134
+ diode_meta = lmeta.hardware.detectors.germanium.diodes[hpge_name]
135
+ hpge_meta = merge_configs(diode_meta, extra_meta[hpge_name])
136
+
137
+ # extract the measurement info
138
+ measurement_info = parse_measurement(measurement)
139
+
140
+ reg = geant4.Registry()
141
+
142
+ # Create the world volume
143
+ world = geant4.solid.Box("world", 20, 20, 20, reg, "m")
144
+ world_lv = geant4.LogicalVolume(world, "G4_Galactic", "world_lv", reg)
145
+ reg.setWorld(world_lv)
146
+
147
+ # place a box rotated 180 deg so the geometry is not upside down
148
+ lab = geant4.solid.Box("lab", 18, 18, 18, reg, "m")
149
+ lab_lv = geant4.LogicalVolume(lab, "G4_AIR", "lab_lv", reg)
150
+ lab_lv.pygeom_color_rgba = False
151
+
152
+ _place_pv(lab_lv, "lab_lv", world_lv, reg, invert_z_axes=True)
153
+
154
+ # extract the metadata on the cryostat
155
+ cryostat_meta = dim.get_cryostat_metadata(
156
+ hpge_meta.type, hpge_meta.production.order, hpge_meta.production.slice
157
+ )
158
+
159
+ cavity_lv = create_vacuum_cavity(cryostat_meta, reg)
160
+ cavity_lv.pygeom_color_rgba = False
161
+
162
+ _place_pv(cavity_lv, "cavity_pv", lab_lv, reg, z_in_mm=cryostat_meta.position_cavity_from_top)
163
+
164
+ if "hpge" in assemblies:
165
+ # construct the mylar wrap
166
+ wrap_lv = create_wrap(hpge_meta.hades.wrap.geometry, from_gdml=True)
167
+ wrap_lv.pygeom_color_rgba = [0.0, 0.8, 0.2, 0.3]
168
+
169
+ z_pos = hpge_meta.hades.wrap.position - cryostat_meta.position_cavity_from_top
170
+ pv = _place_pv(wrap_lv, "wrap_pv", cavity_lv, reg, z_in_mm=z_pos)
171
+ reg.addVolumeRecursive(pv)
172
+
173
+ # construct the holder
174
+ holder_lv = create_holder(hpge_meta.hades.holder.geometry, hpge_meta.type, from_gdml=True)
175
+ holder_lv.pygeom_color_rgba = [0.0, 0.8, 0.2, 0.3]
176
+
177
+ z_pos = hpge_meta.hades.holder.position - cryostat_meta.position_cavity_from_top
178
+ pv = _place_pv(holder_lv, "holder_pv", cavity_lv, reg, z_in_mm=z_pos)
179
+ reg.addVolumeRecursive(pv)
180
+
181
+ # construct the hpge
182
+ detector_lv = make_hpge(hpge_meta, name=hpge_meta.name, registry=reg)
183
+ detector_lv.pygeom_color_rgba = [0.33, 0.33, 0.33, 1.0]
184
+
185
+ # an extra offset is needed to account for the different reference point
186
+ # this is the top of the crystal in the original GDML but it's the p+ contact here
187
+
188
+ extra_offset = max(detector_lv.get_profile()[1])
189
+ z_pos = hpge_meta.hades.detector.position - cryostat_meta.position_cavity_from_top + extra_offset
190
+
191
+ # we need to flip the detector axes when placing it in the cryostat
192
+ pv = _place_pv(detector_lv, hpge_meta.name, cavity_lv, reg, z_in_mm=z_pos, invert_z_axes=True)
193
+
194
+ # register the detector info for remage
195
+ pv.set_pygeom_active_detector(
196
+ pygeomtools.RemageDetectorInfo(
197
+ "germanium",
198
+ 1, # detector id in remage.
199
+ hpge_meta,
200
+ )
201
+ )
202
+ # construct the cryostat
203
+ cryo_lv = create_cryostat(cryostat_meta, from_gdml=True)
204
+ cryo_lv.pygeom_color_rgba = [0.0, 0.2, 0.8, 0.3]
205
+
206
+ pv = _place_pv(cryo_lv, "cryo_pv", lab_lv, reg)
207
+ reg.addVolumeRecursive(pv)
208
+
209
+ if "lead_castle" in assemblies:
210
+ # construct the bottom plate
211
+ plate_meta = dim.get_bottom_plate_metadata()
212
+ plate_lv = create_bottom_plate(plate_meta, from_gdml=True)
213
+ plate_lv.pygeom_color_rgba = [0.2, 0.3, 0.5, 0.05]
214
+
215
+ z_pos = cryostat_meta.position_from_bottom + plate_meta.height / 2.0
216
+ pv = _place_pv(plate_lv, "plate_pv", lab_lv, reg, z_in_mm=z_pos)
217
+ reg.addVolumeRecursive(pv)
218
+
219
+ # construct the lead castle
220
+ table = config.get("lead_castle_idx", 1)
221
+ castle_dims = dim.get_castle_dimensions(table)
222
+ castle_lv = create_lead_castle(table, castle_dims, from_gdml=True)
223
+ castle_lv.pygeom_color_rgba = [0.2, 0.3, 0.5, 0.05]
224
+
225
+ z_pos = cryostat_meta.position_from_bottom - castle_dims.base.height / 2.0
226
+ pv = _place_pv(castle_lv, "castle_pv", lab_lv, reg, z_in_mm=z_pos)
227
+ reg.addVolumeRecursive(pv)
228
+
229
+ if table == 2:
230
+ msg = "For the lead castle the copper plate is not implemented!"
231
+ log.warning(msg)
232
+
233
+ if "source" in assemblies:
234
+ if not construct_unverified:
235
+ msg = (
236
+ "Source assembly construction is implemented, but not verified. "
237
+ "To proceed anyway, set construct_unverified to True."
238
+ )
239
+ raise NotImplementedError(msg)
240
+
241
+ # basic information on the source
242
+ source_type = measurement_info.source
243
+ position = measurement_info.position
244
+
245
+ # extract some metadata
246
+ source_dims = dim.get_source_metadata(source_type)
247
+ holder_dims = dim.get_source_holder_metadata(source_type, position)
248
+
249
+ source_lv = create_source(source_type, source_dims, holder_dims, from_gdml=True)
250
+ z_pos = hpge_meta.hades.source.z.position
251
+
252
+ pv = _place_pv(source_lv, "source_pv", lab_lv, reg, z_in_mm=z_pos)
253
+ reg.addVolumeRecursive(pv)
254
+
255
+ # construct th plate if needed
256
+ if source_type == "th":
257
+ th_plate_lv = create_th_plate(source_dims, from_gdml=True)
258
+ pv = _place_pv(th_plate_lv, "th_plate_pv", lab_lv, reg)
259
+ reg.addVolumeRecursive(pv)
260
+
261
+ s_holder_lv = create_source_holder(
262
+ source_type,
263
+ holder_dims,
264
+ source_z=hpge_meta.hades.source.z.position,
265
+ meas_type=position,
266
+ from_gdml=True,
267
+ )
268
+
269
+ # TODO: this will break so we need to change it
270
+ z_pos = -(hpge_meta.hades.source.z.position + holder_dims.source.top_plate_height / 2)
271
+
272
+ pv = _place_pv(s_holder_lv, "source_holder_pv", lab_lv, reg, z_in_mm=z_pos)
273
+ reg.addVolumeRecursive(pv)
274
+
275
+ return reg