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.
- legend_pygeom_hades-0.1.0a0.dist-info/METADATA +62 -0
- legend_pygeom_hades-0.1.0a0.dist-info/RECORD +85 -0
- legend_pygeom_hades-0.1.0a0.dist-info/WHEEL +5 -0
- legend_pygeom_hades-0.1.0a0.dist-info/entry_points.txt +2 -0
- legend_pygeom_hades-0.1.0a0.dist-info/licenses/LICENSE +674 -0
- legend_pygeom_hades-0.1.0a0.dist-info/top_level.txt +1 -0
- pygeomhades/__init__.py +6 -0
- pygeomhades/_version.py +34 -0
- pygeomhades/cli.py +169 -0
- pygeomhades/configs/dummy_geom/B99000A.yaml +25 -0
- pygeomhades/configs/dummy_geom/C99000A.yaml +31 -0
- pygeomhades/configs/dummy_geom/P99000A.yaml +20 -0
- pygeomhades/configs/dummy_geom/V99000A.yaml +31 -0
- pygeomhades/configs/holder_wrap/B00000B.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00000D.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00002C.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00032B.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00035A.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00035B.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00061C.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00076C.yaml +37 -0
- pygeomhades/configs/holder_wrap/B00091B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V00048B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V02160A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V02160B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V02162B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V02166B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V03421A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V03422A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V04199A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V04545A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V04549A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V04549B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05261A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05261B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05266A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05266B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05267A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05267B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05268A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05268B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05612A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V05612B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V06643A.yaml +29 -0
- pygeomhades/configs/holder_wrap/V06649A.yaml +29 -0
- pygeomhades/configs/holder_wrap/V06659A.yaml +29 -0
- pygeomhades/configs/holder_wrap/V07298B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V07302A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V07302B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V07646A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V07647A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V07647B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V08682A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V08682B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V09372A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V09374A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V09724A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V10437B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V10447B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V11924A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V11925A.yaml +37 -0
- pygeomhades/configs/holder_wrap/V11947B.yaml +37 -0
- pygeomhades/configs/holder_wrap/V14673A.yaml +37 -0
- pygeomhades/configs/vis-scene.yaml +0 -0
- pygeomhades/core.py +275 -0
- pygeomhades/create_volumes.py +571 -0
- pygeomhades/dimensions.py +283 -0
- pygeomhades/metadata.py +28 -0
- pygeomhades/models/dummy/bottom_plate_dummy.gdml +44 -0
- pygeomhades/models/dummy/cryostat_dummy.gdml +57 -0
- pygeomhades/models/dummy/holder_bege_dummy.gdml +61 -0
- pygeomhades/models/dummy/holder_icpc_dummy.gdml +78 -0
- pygeomhades/models/dummy/lead_castle_table1_dummy.gdml +71 -0
- pygeomhades/models/dummy/lead_castle_table2_dummy.gdml +73 -0
- pygeomhades/models/dummy/source_am_collimated_dummy.gdml +97 -0
- pygeomhades/models/dummy/source_am_dummy.gdml +64 -0
- pygeomhades/models/dummy/source_ba_dummy.gdml +72 -0
- pygeomhades/models/dummy/source_co_dummy.gdml +71 -0
- pygeomhades/models/dummy/source_holder_am_dummy.gdml +73 -0
- pygeomhades/models/dummy/source_holder_dummy.gdml +61 -0
- pygeomhades/models/dummy/source_holder_th_lat_dummy.gdml +54 -0
- pygeomhades/models/dummy/source_th_dummy.gdml +134 -0
- pygeomhades/models/dummy/source_th_plates_dummy.gdml +36 -0
- pygeomhades/models/dummy/wrap_dummy.gdml +50 -0
- pygeomhades/utils.py +101 -0
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from importlib import resources
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from dbetto import AttrsDict
|
|
7
|
+
from pyg4ometry import geant4
|
|
8
|
+
|
|
9
|
+
from pygeomhades.utils import read_gdml_with_replacements
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def create_vacuum_cavity(cryostat_metadata: AttrsDict, registry: geant4.Registry) -> geant4.LogicalVolume:
|
|
13
|
+
"""Construct the vacuum cavity.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
cryostat_metadata
|
|
18
|
+
The dimensions of the various parts of the cryostat, should have
|
|
19
|
+
the following format
|
|
20
|
+
|
|
21
|
+
.. code-block:: yaml
|
|
22
|
+
|
|
23
|
+
cryostat:
|
|
24
|
+
width: 200
|
|
25
|
+
thickness: 2
|
|
26
|
+
height: 200
|
|
27
|
+
position_cavity_from_top: 10
|
|
28
|
+
position_cavity_from_bottom: 20,
|
|
29
|
+
position_from_bottom: 100
|
|
30
|
+
|
|
31
|
+
registry
|
|
32
|
+
The registry to add the geometry to.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
The logical volume for the cavity.
|
|
37
|
+
"""
|
|
38
|
+
vacuum_cavity_radius = (cryostat_metadata["width"] - 2 * cryostat_metadata["thickness"]) / 2
|
|
39
|
+
vacuum_cavity_z = (
|
|
40
|
+
cryostat_metadata["height"]
|
|
41
|
+
- cryostat_metadata["position_cavity_from_top"]
|
|
42
|
+
- cryostat_metadata["position_cavity_from_bottom"]
|
|
43
|
+
)
|
|
44
|
+
vacuum_cavity = geant4.solid.GenericPolycone(
|
|
45
|
+
"vacuum_cavity",
|
|
46
|
+
0.0,
|
|
47
|
+
2.0 * np.pi,
|
|
48
|
+
pR=([0.0, vacuum_cavity_radius, vacuum_cavity_radius, 0.0]),
|
|
49
|
+
pZ=[0.0, 0.0, vacuum_cavity_z, vacuum_cavity_z],
|
|
50
|
+
lunit="mm",
|
|
51
|
+
aunit="rad",
|
|
52
|
+
registry=registry,
|
|
53
|
+
)
|
|
54
|
+
return geant4.LogicalVolume(vacuum_cavity, "G4_Galactic", "cavity_lv", registry)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def create_wrap(wrap_metadata: AttrsDict, from_gdml: bool = False) -> geant4.LogicalVolume:
|
|
58
|
+
"""Create the mylar wrap.
|
|
59
|
+
|
|
60
|
+
.. warning::
|
|
61
|
+
|
|
62
|
+
The returned logical volume belongs to its own registry,
|
|
63
|
+
it is necessary to call :func:`reg.addVolumeRecursive` on
|
|
64
|
+
the produced PhysicalVolume to get a sane registry.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
wrap_metadata
|
|
69
|
+
The information on the dimensions of the mylar wrap,
|
|
70
|
+
should be of the format:
|
|
71
|
+
|
|
72
|
+
.. code-block:: yaml
|
|
73
|
+
|
|
74
|
+
outer:
|
|
75
|
+
height_in_mm: 100
|
|
76
|
+
radius_in_mm: 100
|
|
77
|
+
inner:
|
|
78
|
+
height_in_mm: 99
|
|
79
|
+
radius_in_mm: 99
|
|
80
|
+
|
|
81
|
+
from_gdml
|
|
82
|
+
whether to read the geometry from GDML or construct it directly.
|
|
83
|
+
"""
|
|
84
|
+
if from_gdml:
|
|
85
|
+
dummy_gdml_path = resources.files("pygeomhades") / "models" / "dummy" / "wrap_dummy.gdml"
|
|
86
|
+
|
|
87
|
+
replacements = {
|
|
88
|
+
"wrap_outer_height_in_mm": wrap_metadata.outer.height_in_mm,
|
|
89
|
+
"wrap_outer_radius_in_mm": wrap_metadata.outer.radius_in_mm,
|
|
90
|
+
"wrap_inner_radius_in_mm": wrap_metadata.inner.radius_in_mm,
|
|
91
|
+
"wrap_top_thickness_in_mm": wrap_metadata.outer.height_in_mm - wrap_metadata.inner.height_in_mm,
|
|
92
|
+
}
|
|
93
|
+
wrap_lv = read_gdml_with_replacements(dummy_gdml_path, replacements)
|
|
94
|
+
else:
|
|
95
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
96
|
+
raise NotImplementedError(msg)
|
|
97
|
+
|
|
98
|
+
return wrap_lv
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def create_holder(holder_meta: AttrsDict, det_type: str, from_gdml: bool = True) -> geant4.LogicalVolume:
|
|
102
|
+
"""Construct the holder geometry
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
holder_meta
|
|
107
|
+
The metadata describing the holder geometry, should be of the format:
|
|
108
|
+
|
|
109
|
+
.. code-block:: yaml
|
|
110
|
+
|
|
111
|
+
cylinder:
|
|
112
|
+
inner:
|
|
113
|
+
height_in_mm: 100
|
|
114
|
+
radius_in_mm: 100
|
|
115
|
+
outer:
|
|
116
|
+
height_in_mm: 104
|
|
117
|
+
radius_in_mm: 104
|
|
118
|
+
bottom_cyl:
|
|
119
|
+
inner:
|
|
120
|
+
height_in_mm: 100
|
|
121
|
+
radius_in_mm: 100
|
|
122
|
+
outer:
|
|
123
|
+
height_in_mm: 104
|
|
124
|
+
radius_in_mm: 104
|
|
125
|
+
rings:
|
|
126
|
+
position_top_ring_in_mm: 20
|
|
127
|
+
position_bottom_ring_in_mm: 30
|
|
128
|
+
radius_in_mm: 150
|
|
129
|
+
height_in_mm: 10
|
|
130
|
+
edge:
|
|
131
|
+
height_in_mm: 1000
|
|
132
|
+
|
|
133
|
+
det_type
|
|
134
|
+
Detector type.
|
|
135
|
+
from_gdml
|
|
136
|
+
Whether to construct from a GDML file
|
|
137
|
+
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
if not from_gdml:
|
|
141
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
142
|
+
raise NotImplementedError(msg)
|
|
143
|
+
|
|
144
|
+
if det_type == "icpc":
|
|
145
|
+
dummy_gdml_path = resources.files("pygeomhades") / "models" / "dummy" / "holder_icpc_dummy.gdml"
|
|
146
|
+
|
|
147
|
+
rings = holder_meta["rings"]
|
|
148
|
+
cylinder = holder_meta["cylinder"]
|
|
149
|
+
bottom_cylinder = holder_meta["bottom_cyl"]
|
|
150
|
+
|
|
151
|
+
replacements = {
|
|
152
|
+
"max_radius_in_mm": rings.radius_in_mm,
|
|
153
|
+
"outer_height_in_mm": cylinder.outer.height_in_mm,
|
|
154
|
+
"inner_height_in_mm": cylinder.inner.height_in_mm,
|
|
155
|
+
"outer_radius_in_mm": cylinder.outer.radius_in_mm,
|
|
156
|
+
"inner_radius_in_mm": cylinder.inner.radius_in_mm,
|
|
157
|
+
"outer_bottom_cyl_radius_in_mm": bottom_cylinder.outer.radius_in_mm,
|
|
158
|
+
"inner_bottom_cyl_radius_in_mm": bottom_cylinder.inner.radius_in_mm,
|
|
159
|
+
"edge_height_in_mm": holder_meta.edge.height_in_mm,
|
|
160
|
+
"pos_top_ring_in_mm": rings.position_top_ring_in_mm,
|
|
161
|
+
"pos_bottom_ring_in_mm": rings.position_bottom_ring_in_mm,
|
|
162
|
+
"end_top_ring_in_mm": rings.position_top_ring_in_mm + rings.height_in_mm,
|
|
163
|
+
"end_bottom_ring_in_mm": rings.position_bottom_ring_in_mm + rings.height_in_mm,
|
|
164
|
+
"end_bottom_cyl_outer_in_mm": cylinder.outer.height_in_mm + bottom_cylinder.outer.height_in_mm,
|
|
165
|
+
"end_bottom_cyl_inner_in_mm": cylinder.inner.height_in_mm + bottom_cylinder.inner.height_in_mm,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
elif det_type == "bege":
|
|
169
|
+
dummy_gdml_path = resources.files("pygeomhades") / "models" / "dummy" / "holder_bege_dummy.gdml"
|
|
170
|
+
|
|
171
|
+
rings = holder_meta["rings"]
|
|
172
|
+
cylinder = holder_meta["cylinder"]
|
|
173
|
+
bottom_cylinder = holder_meta["bottom_cyl"]
|
|
174
|
+
|
|
175
|
+
replacements = {
|
|
176
|
+
"max_radius_in_mm": rings.radius_in_mm,
|
|
177
|
+
"outer_height_in_mm": cylinder.outer.height_in_mm,
|
|
178
|
+
"inner_height_in_mm": cylinder.inner.height_in_mm,
|
|
179
|
+
"outer_radius_in_mm": cylinder.outer.radius_in_mm,
|
|
180
|
+
"inner_radius_in_mm": cylinder.inner.radius_in_mm,
|
|
181
|
+
"position_top_ring_in_mm": rings.position_top_ring_in_mm,
|
|
182
|
+
"end_top_ring_in_mm": rings.height_in_mm + rings.position_top_ring_in_mm,
|
|
183
|
+
}
|
|
184
|
+
else:
|
|
185
|
+
msg = "cannot construct geometry for coax or ppc"
|
|
186
|
+
raise NotImplementedError(msg)
|
|
187
|
+
|
|
188
|
+
return read_gdml_with_replacements(dummy_gdml_path, replacements)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def create_bottom_plate(plate_metadata: AttrsDict, from_gdml: bool = True) -> geant4.Registry:
|
|
192
|
+
"""Create the bottom plate.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
plate_metadata
|
|
197
|
+
Metadata describing the position of the bottom plate.
|
|
198
|
+
This should have the format:
|
|
199
|
+
|
|
200
|
+
.. code-block:: yaml
|
|
201
|
+
|
|
202
|
+
width: 100
|
|
203
|
+
depth: 200
|
|
204
|
+
height: 300
|
|
205
|
+
cavity:
|
|
206
|
+
width: 100
|
|
207
|
+
depth: 200
|
|
208
|
+
height: 200
|
|
209
|
+
from_gdml
|
|
210
|
+
Whether to construct from a GDML file
|
|
211
|
+
|
|
212
|
+
"""
|
|
213
|
+
if not from_gdml:
|
|
214
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
215
|
+
raise NotImplementedError(msg)
|
|
216
|
+
|
|
217
|
+
dummy_gdml_path = resources.files("pygeomhades") / "models" / "dummy" / "bottom_plate_dummy.gdml"
|
|
218
|
+
|
|
219
|
+
replacements = {
|
|
220
|
+
"bottom_plate_width": plate_metadata.width,
|
|
221
|
+
"bottom_plate_depth": plate_metadata.depth,
|
|
222
|
+
"bottom_plate_height": plate_metadata.height,
|
|
223
|
+
"bottom_cavity_plate_width": plate_metadata.cavity.width,
|
|
224
|
+
"bottom_cavity_plate_depth": plate_metadata.cavity.depth,
|
|
225
|
+
"bottom_cavity_plate_height": plate_metadata.cavity.height,
|
|
226
|
+
}
|
|
227
|
+
return read_gdml_with_replacements(dummy_gdml_path, replacements)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def create_lead_castle(
|
|
231
|
+
table_num: int, castle_dimensions: AttrsDict, from_gdml: bool = True, volume_name: str = "Lead_castle"
|
|
232
|
+
) -> geant4.LogicalVolume:
|
|
233
|
+
"""Create the lead castle.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
table_num
|
|
238
|
+
Which table the measurements were taken on (1 or 2).
|
|
239
|
+
castle_dimensions
|
|
240
|
+
The metadata describing the lead castle dimensions. This should
|
|
241
|
+
have the fields "base", "inner_cavity", "cavity",
|
|
242
|
+
"top", "front" and "copper_plate".
|
|
243
|
+
|
|
244
|
+
Each should have a subdictionary with this format:
|
|
245
|
+
|
|
246
|
+
.. code-block:: yaml
|
|
247
|
+
|
|
248
|
+
base:
|
|
249
|
+
height: 100
|
|
250
|
+
depth: 100
|
|
251
|
+
width: 100
|
|
252
|
+
volume_name
|
|
253
|
+
Which volume to extract, defaults to "Lead_castle".
|
|
254
|
+
|
|
255
|
+
from_gdml
|
|
256
|
+
Whether to construct from a GDML file
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
if not from_gdml:
|
|
260
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
261
|
+
raise NotImplementedError(msg)
|
|
262
|
+
|
|
263
|
+
if table_num not in [1, 2]:
|
|
264
|
+
msg = f"Table number must be 1 or 2, not {table_num}"
|
|
265
|
+
raise ValueError(msg)
|
|
266
|
+
|
|
267
|
+
dummy_gdml_path = (
|
|
268
|
+
resources.files("pygeomhades") / "models" / "dummy" / f"lead_castle_table{table_num}_dummy.gdml"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if table_num == 1:
|
|
272
|
+
replacements = {
|
|
273
|
+
"base_width_1": castle_dimensions.base.width,
|
|
274
|
+
"base_depth_1": castle_dimensions.base.depth,
|
|
275
|
+
"base_height_1": castle_dimensions.base.height,
|
|
276
|
+
"inner_cavity_width_1": castle_dimensions.inner_cavity.width,
|
|
277
|
+
"inner_cavity_depth_1": castle_dimensions.inner_cavity.depth,
|
|
278
|
+
"inner_cavity_height_1": castle_dimensions.inner_cavity.height,
|
|
279
|
+
"cavity_width_1": castle_dimensions.cavity.width,
|
|
280
|
+
"cavity_depth_1": castle_dimensions.cavity.depth,
|
|
281
|
+
"cavity_height_1": castle_dimensions.cavity.height,
|
|
282
|
+
"top_width_1": castle_dimensions.top.width,
|
|
283
|
+
"top_depth_1": castle_dimensions.top.depth,
|
|
284
|
+
"top_height_1": castle_dimensions.top.height,
|
|
285
|
+
"front_width_1": castle_dimensions.front.width,
|
|
286
|
+
"front_depth_1": castle_dimensions.front.depth,
|
|
287
|
+
"front_height_1": castle_dimensions.front.height,
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
elif table_num == 2:
|
|
291
|
+
replacements = {
|
|
292
|
+
"base_width_2": castle_dimensions.base.width,
|
|
293
|
+
"base_depth_2": castle_dimensions.base.depth,
|
|
294
|
+
"base_height_2": castle_dimensions.base.height,
|
|
295
|
+
"inner_cavity_width_2": castle_dimensions.inner_cavity.width,
|
|
296
|
+
"inner_cavity_depth_2": castle_dimensions.inner_cavity.depth,
|
|
297
|
+
"inner_cavity_height_2": castle_dimensions.inner_cavity.height,
|
|
298
|
+
"top_width_2": castle_dimensions.top.width,
|
|
299
|
+
"top_depth_2": castle_dimensions.top.depth,
|
|
300
|
+
"top_height_2": castle_dimensions.top.height,
|
|
301
|
+
"copper_plate_width": castle_dimensions.copper_plate.width,
|
|
302
|
+
"copper_plate_depth": castle_dimensions.copper_plate.depth,
|
|
303
|
+
"copper_plate_height": castle_dimensions.copper_plate.height,
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return read_gdml_with_replacements(dummy_gdml_path, replacements, vol_name=volume_name)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def create_source(
|
|
310
|
+
source_type: str, source_dims: AttrsDict, holder_dims: AttrsDict | None, from_gdml: bool = False
|
|
311
|
+
) -> geant4.LogicalVolume:
|
|
312
|
+
"""Create the geometry of the source.
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
source_type
|
|
317
|
+
The type of source (am_collimated, am, ba, co or th)
|
|
318
|
+
source_dims
|
|
319
|
+
Metadata describing the source geometry.
|
|
320
|
+
Should be of the following format:
|
|
321
|
+
|
|
322
|
+
.. code-block:: yaml
|
|
323
|
+
|
|
324
|
+
height: 0.0
|
|
325
|
+
width: 0.0
|
|
326
|
+
|
|
327
|
+
foil:
|
|
328
|
+
height: 0.0
|
|
329
|
+
width: 0.0
|
|
330
|
+
|
|
331
|
+
al_ring:
|
|
332
|
+
height: 0.0
|
|
333
|
+
width_max: 0.0
|
|
334
|
+
width_min: 0.0
|
|
335
|
+
|
|
336
|
+
capsule:
|
|
337
|
+
width: 0.0
|
|
338
|
+
depth: 0.0
|
|
339
|
+
height: 0.0
|
|
340
|
+
|
|
341
|
+
collimator:
|
|
342
|
+
width: 0.0
|
|
343
|
+
depth: 0.0
|
|
344
|
+
height: 0.0
|
|
345
|
+
beam_width: 0.0
|
|
346
|
+
beam_height: 0.0
|
|
347
|
+
window: 0.0
|
|
348
|
+
|
|
349
|
+
epoxy:
|
|
350
|
+
height: 0.0
|
|
351
|
+
width: 0.0
|
|
352
|
+
|
|
353
|
+
plates:
|
|
354
|
+
height: 0.0
|
|
355
|
+
width: 0.0
|
|
356
|
+
cavity_width: 0.0
|
|
357
|
+
|
|
358
|
+
offset_height: 0.0
|
|
359
|
+
|
|
360
|
+
holder_dims
|
|
361
|
+
Dimensions of the source holder (see :func:`get_source_holder`).
|
|
362
|
+
|
|
363
|
+
from_gdml
|
|
364
|
+
Whether to construct from a GDML file
|
|
365
|
+
"""
|
|
366
|
+
|
|
367
|
+
if not from_gdml:
|
|
368
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
369
|
+
raise NotImplementedError(msg)
|
|
370
|
+
|
|
371
|
+
dummy_gdml_path = resources.files("pygeomhades") / "models" / "dummy" / f"source_{source_type}_dummy.gdml"
|
|
372
|
+
|
|
373
|
+
if source_type == "am_collimated":
|
|
374
|
+
replacements = {
|
|
375
|
+
"source_height": source_dims.height,
|
|
376
|
+
"source_width": source_dims.width,
|
|
377
|
+
"source_capsule_height": source_dims.capsule.height,
|
|
378
|
+
"source_capsule_width": source_dims.capsule.width,
|
|
379
|
+
"window_source": source_dims.collimator.window,
|
|
380
|
+
"collimator_height": source_dims.collimator.height,
|
|
381
|
+
"collimator_depth": source_dims.collimator.depth,
|
|
382
|
+
"collimator_width": source_dims.collimator.width,
|
|
383
|
+
"collimator_beam_height": source_dims.collimator.beam_height,
|
|
384
|
+
"collimator_beam_width": source_dims.collimator.beam_width,
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
elif source_type == "am":
|
|
388
|
+
replacements = {
|
|
389
|
+
"source_height": source_dims.height,
|
|
390
|
+
"source_width": source_dims.width,
|
|
391
|
+
"source_capsule_height": source_dims.capsule.height,
|
|
392
|
+
"source_capsule_width": source_dims.capsule.width,
|
|
393
|
+
"source_capsule_depth": source_dims.capsule.depth,
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
elif source_type in ["ba", "co"]:
|
|
397
|
+
replacements = {
|
|
398
|
+
"source_height": source_dims.height,
|
|
399
|
+
"source_width": source_dims.width,
|
|
400
|
+
"source_foil_height": source_dims.foil.height,
|
|
401
|
+
"source_Alring_height": source_dims.al_ring.height,
|
|
402
|
+
"source_Alring_width_min": source_dims.al_ring.width_min,
|
|
403
|
+
"source_Alring_width_max": source_dims.al_ring.width_max,
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
elif source_type == "th":
|
|
407
|
+
replacements = {
|
|
408
|
+
"source_height": source_dims.height,
|
|
409
|
+
"source_width": source_dims.width,
|
|
410
|
+
"source_capsule_height": source_dims.capsule.height,
|
|
411
|
+
"source_capsule_width": source_dims.capsule.width,
|
|
412
|
+
"source_epoxy_height": source_dims.epoxy.height,
|
|
413
|
+
"source_epoxy_width": source_dims.epoxy.width,
|
|
414
|
+
"CuSource_holder_height": holder_dims.copper.height,
|
|
415
|
+
"CuSource_holder_width": holder_dims.copper.width,
|
|
416
|
+
"CuSource_holder_cavity_width": holder_dims.copper.cavity_width,
|
|
417
|
+
"CuSource_holder_bottom_height": holder_dims.copper.bottom_height,
|
|
418
|
+
"CuSource_holder_bottom_width": holder_dims.copper.bottom_width,
|
|
419
|
+
"source_offset_height": source_dims.offset_height,
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
else:
|
|
423
|
+
msg = f"source type of {source_type} is not defined."
|
|
424
|
+
raise RuntimeError(msg)
|
|
425
|
+
|
|
426
|
+
return read_gdml_with_replacements(dummy_gdml_path, replacements)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def create_th_plate(source_dims: AttrsDict, from_gdml: bool = False) -> geant4.LogicalVolume:
|
|
430
|
+
"""Construct the plate for the Th source
|
|
431
|
+
|
|
432
|
+
Parameters
|
|
433
|
+
----------
|
|
434
|
+
source_dims
|
|
435
|
+
See :func:`create_source` for more information.
|
|
436
|
+
from_gdml
|
|
437
|
+
Whether to construct from a GDML file
|
|
438
|
+
|
|
439
|
+
"""
|
|
440
|
+
if not from_gdml:
|
|
441
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
442
|
+
raise NotImplementedError(msg)
|
|
443
|
+
|
|
444
|
+
dummy_gdml_path = resources.files("pygeomhades") / "models" / "dummy" / "source_th_plates_dummy.gdml"
|
|
445
|
+
source = source_dims
|
|
446
|
+
|
|
447
|
+
replacements = {
|
|
448
|
+
"source_plates_height": source.plates.height,
|
|
449
|
+
"source_plates_width": source.plates.width,
|
|
450
|
+
"source_plates_cavity_width": source.plates.cavity_width,
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return read_gdml_with_replacements(dummy_gdml_path, replacements)
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def create_source_holder(
|
|
457
|
+
source_type: str, holder_dims: AttrsDict, source_z: float, meas_type: str = "lat", from_gdml: bool = True
|
|
458
|
+
) -> geant4.LogicalVolume:
|
|
459
|
+
"""Get the source holder geometry.
|
|
460
|
+
|
|
461
|
+
Parameters
|
|
462
|
+
----------
|
|
463
|
+
source_type
|
|
464
|
+
The type of source (am_collimated, am, ba, co or th)
|
|
465
|
+
holder_dims
|
|
466
|
+
The dimensions of the source holder, should be of the format:
|
|
467
|
+
|
|
468
|
+
.. code-block:: yaml
|
|
469
|
+
|
|
470
|
+
source:
|
|
471
|
+
top_plate_height: 10.0
|
|
472
|
+
top_plate_width: 10.0
|
|
473
|
+
top_height: 2.0
|
|
474
|
+
top_inner_width: 2.0
|
|
475
|
+
top_bottom_height: 2.0
|
|
476
|
+
bottom_inner_width: 2.0
|
|
477
|
+
outer_width: 100.0
|
|
478
|
+
inner_width: 10.0
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
meas_type
|
|
482
|
+
The measurement type (for th only) either lat or top.
|
|
483
|
+
source_z
|
|
484
|
+
The z position of the source from the cryostat bottom.
|
|
485
|
+
from_gdml
|
|
486
|
+
Whether to construct from a GDML file
|
|
487
|
+
"""
|
|
488
|
+
|
|
489
|
+
if not from_gdml:
|
|
490
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
491
|
+
raise NotImplementedError(msg)
|
|
492
|
+
|
|
493
|
+
source_holder = holder_dims
|
|
494
|
+
dummy_path = resources.files("pygeomhades") / "models" / "dummy"
|
|
495
|
+
|
|
496
|
+
if source_type == "th" and meas_type == "lat":
|
|
497
|
+
dummy_gdml_path = dummy_path / "source_holder_th_lat_dummy.gdml"
|
|
498
|
+
|
|
499
|
+
replacements = {
|
|
500
|
+
"cavity_source_holder_height": source_holder.source.cavity_height,
|
|
501
|
+
"source_holder_height": source_holder.source.height,
|
|
502
|
+
"source_holder_outer_width": source_holder.outer_width,
|
|
503
|
+
"source_holder_inner_width": source_holder.inner_width,
|
|
504
|
+
"cavity_source_holder_width": source_holder.holder_width,
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
elif source_type in ["am_collimated", "ba", "co", "th"]:
|
|
508
|
+
dummy_gdml_path = dummy_path / "source_holder_dummy.gdml"
|
|
509
|
+
|
|
510
|
+
replacements = {
|
|
511
|
+
"source_holder_top_plate_height": source_holder.source.top_plate_height,
|
|
512
|
+
"source_holder_top_height": source_holder.source.top_height,
|
|
513
|
+
"source_holder_topbottom_height": source_holder.source.top_bottom_height,
|
|
514
|
+
"source_holder_top_plate_width": source_holder.source.top_plate_width,
|
|
515
|
+
"source_holder_top_inner_width": source_holder.source.top_inner_width,
|
|
516
|
+
"source_holder_inner_width": source_holder.inner_width,
|
|
517
|
+
"source_holder_bottom_inner_width": source_holder.source.bottom_inner_width,
|
|
518
|
+
"source_holder_outer_width": source_holder.outer_width,
|
|
519
|
+
"position_source_fromcryostat_z": source_z,
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
elif source_type == "am":
|
|
523
|
+
dummy_gdml_path = dummy_path / "source_holder_am_dummy.gdml"
|
|
524
|
+
|
|
525
|
+
replacements = {
|
|
526
|
+
"source_holder_top_height": source_holder.source.top_height,
|
|
527
|
+
"position_source_fromcryostat_z": source_z,
|
|
528
|
+
"source_holder_top_plate_height": source_holder.source.top_plate_height,
|
|
529
|
+
"source_holder_top_plate_width": source_holder.source.top_plate_width,
|
|
530
|
+
"source_holder_top_plate_depth": source_holder.source.top_plate_depth,
|
|
531
|
+
"source_holder_topbottom_height": source_holder.source.top_bottom_height,
|
|
532
|
+
"source_holder_top_inner_width": source_holder.source.top_inner_width,
|
|
533
|
+
"source_holder_top_inner_depth": source_holder.source.top_inner_depth,
|
|
534
|
+
"source_holder_inner_width": source_holder.inner_width,
|
|
535
|
+
"source_holder_bottom_inner_width": source_holder.source.bottom_inner_width,
|
|
536
|
+
"source_holder_outer_width": source_holder.outer_width,
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
else:
|
|
540
|
+
msg = f"source type {source_type} not implemented."
|
|
541
|
+
raise RuntimeError(msg)
|
|
542
|
+
|
|
543
|
+
return read_gdml_with_replacements(dummy_gdml_path, replacements)
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def create_cryostat(cryostat_meta: AttrsDict, from_gdml: bool = True) -> geant4.LogicalVolume:
|
|
547
|
+
"""Create the cryostat logical volume.
|
|
548
|
+
|
|
549
|
+
Parameters
|
|
550
|
+
----------
|
|
551
|
+
cryostat_meta
|
|
552
|
+
Metadata describing the cryostat geometry (see :func:`create_wrap`) for details.
|
|
553
|
+
from_gdml
|
|
554
|
+
Whether to construct from a GDML file
|
|
555
|
+
|
|
556
|
+
"""
|
|
557
|
+
|
|
558
|
+
if not from_gdml:
|
|
559
|
+
msg = "cannot construct geometry without the gdml for now"
|
|
560
|
+
raise NotImplementedError(msg)
|
|
561
|
+
|
|
562
|
+
dummy_gdml_path = resources.files("pygeomhades") / "models" / "dummy" / "cryostat_dummy.gdml"
|
|
563
|
+
|
|
564
|
+
replacements = {
|
|
565
|
+
"cryostat_height": cryostat_meta.height,
|
|
566
|
+
"cryostat_width": cryostat_meta.width,
|
|
567
|
+
"cryostat_thickness": cryostat_meta.thickness,
|
|
568
|
+
"position_cryostat_cavity_fromTop": cryostat_meta.position_cavity_from_top,
|
|
569
|
+
"position_cryostat_cavity_fromBottom": cryostat_meta.position_cavity_from_bottom,
|
|
570
|
+
}
|
|
571
|
+
return read_gdml_with_replacements(dummy_gdml_path, replacements)
|