BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSBeamPipeFactoryRectEllipse.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "BDSBeamPipeFactoryBase.hh"
19#include "BDSBeamPipeFactoryElliptical.hh"
20#include "BDSBeamPipeFactoryRectEllipse.hh"
21#include "BDSBeamPipe.hh"
22#include "BDSDebug.hh"
23#include "BDSException.hh"
24#include "BDSExtent.hh"
25#include "BDSUtilities.hh"
26
27#include "globals.hh"
28#include "G4Box.hh"
29#include "G4CutTubs.hh"
30#include "G4EllipticalTube.hh"
31#include "G4IntersectionSolid.hh"
32#include "G4LogicalVolume.hh"
33#include "G4SubtractionSolid.hh"
34#include "G4ThreeVector.hh"
35#include "G4VSolid.hh"
36
37#include "CLHEP/Units/SystemOfUnits.h"
38
39#include <cmath>
40#include <set>
41#include <string>
42#include <utility> // for std::pair
43
44BDSBeamPipeFactoryRectEllipse::BDSBeamPipeFactoryRectEllipse()
45{;}
46
48 G4double lengthIn,
49 G4double aper1In,
50 G4double aper2In,
51 G4double aper3In,
52 G4double aper4In,
53 G4Material* vacuumMaterialIn,
54 G4double beamPipeThicknessIn,
55 G4Material* beamPipeMaterialIn,
56 const G4String& /*pointsFileIn*/,
57 const G4String& /*pointsUnitIn*/)
58{
59 // clean up after last usage
60 CleanUp();
61
62 // CERN use rectellipse for everything because you know, why use different aperture types
63 // tolerate the case where it's a) equal rect and ellipse parameters resulting in an ellipse
64 // and b) the ellipse params are less than rect ones so also just an ellipse
65 if (((aper1In == aper3In) && (aper2In == aper4In)) ||
66 ( (aper3In < aper1In) && (aper4In < aper2In) ) )
67 {
69 BDSBeamPipe* result = ef->CreateBeamPipe(nameIn, lengthIn, aper1In, aper2In, aper3In, aper4In,
70 vacuumMaterialIn, beamPipeThicknessIn, beamPipeMaterialIn);
71 delete ef;
72 return result;
73 }
74
75 // build the solids
76 //vacuum cylindrical solid (circular cross-section)
77 G4VSolid* vacCylSolid = new G4EllipticalTube(nameIn + "_vacuum_ellipsoid", // name
78 aper3In, // horizontal semi-axis
79 aper4In, // vertical semi-axis
80 lengthIn*0.5-lengthSafety); // half length
81 //vacuum box solid (rectangular cross-section)
82 G4VSolid* vacRectSolid = new G4Box(nameIn + "_vacuum_box", // name
83 aper1In, // x half width
84 aper2In, // y half width
85 4*lengthIn); // z full width (long for unambiguous intersection)
86 allSolids.insert(vacCylSolid);
87 allSolids.insert(vacRectSolid);
88 //intersection of both of these gives the desired shape
89 vacuumSolid = new G4IntersectionSolid(nameIn + "_vacuum_solid", // name
90 vacCylSolid, // solid 1
91 vacRectSolid); // solid 2
92
93 //beampipe solid
94 //beampipe inner edge for subtraction (actually just like vacuum + lengthSafety)
95 G4VSolid* bpInnerCylSolid = new G4EllipticalTube(nameIn + "_pipe_inner_ellipsoid",// name
96 aper3In + lengthSafetyLarge, // horizontal semi-axis
97 aper4In + lengthSafetyLarge, // vertical semi-axis
98 1.5*lengthIn); // length big for unambiguous subtraction (but < outerlength)
99 //beampipe inner edge box solid (rectangular cross-section)
100 G4VSolid* bpInnerRectSolid = new G4Box(nameIn + "_pipe_inner_box", // name
101 aper1In + lengthSafetyLarge,// x half width
102 aper2In + lengthSafetyLarge,// y half width
103 1.7*lengthIn); // z long for unambiguous intersection
104 //beampipe inner intersection - 1.5*length long which is > half length for unambiguous subtraction later
105 G4VSolid* bpInnerSolid = new G4IntersectionSolid(nameIn + "_pipe_inner_solid", // name
106 bpInnerCylSolid, // solid 1
107 bpInnerRectSolid); // solid 2
108
109 //beampipe outer edge for subtraction (actually just like vacuum + lengthSafety)
110 G4double extraWidth = beamPipeThicknessIn + lengthSafetyLarge;
111 G4VSolid* bpOuterCylSolid = new G4EllipticalTube(nameIn + "_pipe_inner_ellipsoid",// name
112 aper3In + extraWidth, // horizontal semi-axis
113 aper4In + extraWidth, // hotizontal semi-axis
114 (lengthIn*0.5)-lengthSafety); // half length
115 //beampipe outer edge box solid (rectangular cross-section)
116 G4VSolid* bpOuterRectSolid = new G4Box(nameIn + "_pipe_inner_box", // name
117 aper1In + extraWidth, // x half width
118 aper2In + extraWidth, // y half width
119 lengthIn); // z full width (long for unambiguous intersection)
120 G4VSolid* bpOuterSolid = new G4IntersectionSolid(nameIn + "_pipe_inner_solid", // name
121 bpOuterCylSolid, // solid 1
122 bpOuterRectSolid); // solid 2
123
124 allSolids.insert(bpInnerCylSolid);
125 allSolids.insert(bpInnerRectSolid);
126 allSolids.insert(bpInnerSolid);
127 allSolids.insert(bpOuterCylSolid);
128 allSolids.insert(bpOuterRectSolid);
129 allSolids.insert(bpOuterSolid);
130
131 //beampipe final subtraction between outer and inner edge
132 beamPipeSolid = new G4SubtractionSolid(nameIn + "_pipe_solid", // name
133 bpOuterSolid, // this
134 bpInnerSolid); // minus this
135
136 //container cylindrical solid (circular cross-section)
137 G4VSolid* contCylSolid = new G4EllipticalTube(nameIn + "_vacuum_ellipsoid", // name
138 aper3In + extraWidth + lengthSafetyLarge, // horizontal semi-axis
139 aper4In + extraWidth + lengthSafetyLarge, // vertical semi-axis
140 lengthIn*0.5); // half length
141 //vacuum box solid (rectangular cross-section)
142 G4VSolid* contRectSolid = new G4Box(nameIn + "_vacuum_box", // name
143 aper1In + extraWidth + lengthSafetyLarge, // x half width
144 aper2In + extraWidth + lengthSafetyLarge, // y half width
145 lengthIn); // z full width (long for unambiguous intersection)
146
147 allSolids.insert(contCylSolid);
148 allSolids.insert(contRectSolid);
149
150 //intersection of both of these gives the desired shape
151 containerSolid = new G4IntersectionSolid(nameIn + "_vacuum_solid", // name
152 contCylSolid, // solid 1
153 contRectSolid); // solid 2
154
155 G4double width = aper3In + extraWidth + lengthSafetyLarge;
156 G4double height = aper2In + extraWidth + lengthSafetyLarge;
157
158 CreateContainerSubtractionSolid(nameIn, lengthIn, beamPipeThicknessIn, aper1In, aper2In, aper3In, aper4In);
159
160 return CommonFinalConstruction(nameIn, vacuumMaterialIn, beamPipeMaterialIn, lengthIn, width, height);
161}
162
164 G4double lengthIn,
165 const G4ThreeVector& inputFaceNormalIn,
166 const G4ThreeVector& outputFaceNormalIn,
167 G4double aper1In,
168 G4double aper2In,
169 G4double aper3In,
170 G4double aper4In,
171 G4Material* vacuumMaterialIn,
172 G4double beamPipeThicknessIn,
173 G4Material* beamPipeMaterialIn,
174 const G4String& /*pointsFileIn*/,
175 const G4String& /*pointsUnitIn*/)
176{
177 // clean up after last usage
178 CleanUp();
179
180 // CERN use rectellipse for everything because you know, why use different aperture types
181 // tolerate the case where it's a) equal rect and ellipse parameters resulting in an ellipse
182 // and b) the ellipse params are less than rect ones so also just an ellipse
183 if (((aper1In == aper3In) && (aper2In == aper4In)) ||
184 ( (aper3In < aper1In) && (aper4In < aper2In) ) )
185 {
187 BDSBeamPipe* result = ef->CreateBeamPipe(nameIn, lengthIn, inputFaceNormalIn, outputFaceNormalIn,
188 aper1In, aper2In, aper3In, aper4In,
189 vacuumMaterialIn, beamPipeThicknessIn, beamPipeMaterialIn);
190 delete ef;
191 return result;
192 }
193
194 inputFaceNormal = inputFaceNormalIn;
195 outputFaceNormal = outputFaceNormalIn;
196
197 G4double width = std::max(aper1In,aper3In) + beamPipeThicknessIn + lengthSafetyLarge;
198 G4double height = std::max(aper2In,aper4In) + beamPipeThicknessIn + lengthSafetyLarge;
199
200 CreateGeneralAngledSolids(nameIn, lengthIn, aper1In, aper2In, aper3In, aper4In,
201 beamPipeThicknessIn, inputFaceNormal, outputFaceNormal);
202 CreateContainerSubtractionSolid(nameIn, lengthIn, beamPipeThicknessIn, aper1In,
203 aper2In, aper3In, aper4In);
204
205 return CommonFinalConstruction(nameIn, vacuumMaterialIn, beamPipeMaterialIn,
206 lengthIn, width, height);
207}
208
210 G4Material* vacuumMaterialIn,
211 G4Material* beamPipeMaterialIn,
212 G4double lengthIn,
213 G4double containerWidthIn,
214 G4double containerHeightIn)
215{
216 BDSBeamPipeFactoryBase::CommonConstruction(nameIn, vacuumMaterialIn,
217 beamPipeMaterialIn, lengthIn);
218
219 // record extents
220 BDSExtent ext = BDSExtent(containerWidthIn, containerHeightIn, lengthIn*0.5);
221
222 // build the BDSBeamPipe instance and return it
223 return BuildBeamPipeAndRegisterVolumes(ext,containerWidthIn);
224}
225
229 G4double lengthIn,
230 G4double aper1In,
231 G4double aper2In,
232 G4double aper3In,
233 G4double aper4In,
234 G4double beamPipeThicknessIn,
235 const G4ThreeVector& inputfaceIn,
236 const G4ThreeVector& outputfaceIn)
237{
238 // long length for unambiguous boolean - ensure no gaps in beam pipe geometry
239 G4double angledVolumeLength = BDS::CalculateSafeAngledVolumeLength(inputfaceIn, outputfaceIn, lengthIn, aper1In);
240
241 // build the solids
242 // we can get the rectangular ellipse as in the straight case with the intersection of
243 // an elliptical tube (always solid) and then we can use another intersection solid
244 // with a larger (wider and taller) G4CutTubs to get the angled faces.
245 //vacuum cylindrical solid (circular cross-section)
246 G4VSolid* vacCylSolid = new G4EllipticalTube(nameIn + "_vacuum_ellipsoid",// name
247 aper3In, // horizontal semi-axis
248 aper4In, // vertical semi-axis
249 angledVolumeLength); // long length for unambiguous intersection
250 //vacuum box solid (rectangular cross-section)
251 G4VSolid* vacRectSolid = new G4Box(nameIn + "_vacuum_box", // name
252 aper1In, // x half width
253 aper2In, // y half width
254 1.1*angledVolumeLength); // long length for unambiguous intersection
255
256 //intersection of both of these gives the desired shape
257 G4VSolid* longVacuumSolid = new G4IntersectionSolid(nameIn + "_vacuum_long_solid", // name
258 vacCylSolid, // solid 1
259 vacRectSolid); // solid 2
260 //prepare angled face large cylinder for intersection get angled faces
261 //we can actually use this for the beampipe too later on - whew
262 G4double angledFaceRadius = (std::max(std::max(aper1In,aper2In),std::max(aper3In,aper4In)) + beamPipeThicknessIn) * 1.1;
263
264 // check faces of angled volume don't intersect - if it can be built, remaining angled volumes can be built
265 CheckAngledVolumeCanBeBuilt(lengthIn, inputfaceIn, outputfaceIn, angledFaceRadius, nameIn);
266
267 G4VSolid* vacuumAngledSolid = new G4CutTubs(nameIn + "_pipe_angled_faces", // name
268 0, // inner radius
269 angledFaceRadius, // outer radius
270 (lengthIn*0.5) - (lengthSafety), // accurate length
271 0, // rotation start angle
272 CLHEP::twopi, // rotation sweep angle
273 inputfaceIn, // input face normal
274 outputfaceIn); // output face normal
275
276 allSolids.insert(vacCylSolid);
277 allSolids.insert(vacRectSolid);
278 allSolids.insert(longVacuumSolid);
279 allSolids.insert(vacuumAngledSolid);
280
281 vacuumSolid = new G4IntersectionSolid(nameIn + "_vacuum_solid", // name
282 longVacuumSolid, // solid 1
283 vacuumAngledSolid); // solid 2
284
285 //beampipe cylindrical solid (circular cross-section)
286 //beampipe inner edge for subtraction (actually just like vacuum + lengthSafety)
287 if (beamPipeThicknessIn <= lengthSafetyLarge)
288 {
289 G4String message = "beam pipe thickness in element \"" + nameIn
290 + "\" is thinner than minimum " + std::to_string(lengthSafetyLarge / CLHEP::mm) + "mm.";
291 throw BDSException(__METHOD_NAME__, message);
292 }
293 G4VSolid* bpInnerCylSolid = new G4EllipticalTube(nameIn + "_pipe_inner_ellipsoid", // name
294 aper3In + lengthSafetyLarge, // horizontal semi-axis
295 aper4In + lengthSafetyLarge, // vertical semi-axis
296 angledVolumeLength); // length big for unambiguous subtraction (but < outerlength)
297 //beampipe inner edge box solid (rectangular cross-section)
298 G4VSolid* bpInnerRectSolid = new G4Box(nameIn + "_pipe_inner_box", // name
299 aper1In + lengthSafetyLarge, // x half width
300 aper2In + lengthSafetyLarge, // y half width
301 1.1*angledVolumeLength); // long length for unambiguous intersection
302 //beampipe inner intersection - 1.5*length long which is > half length for unambiguous subtraction later
303 G4VSolid* bpInnerSolid = new G4IntersectionSolid(nameIn + "_pipe_inner_solid", // name
304 bpInnerCylSolid, // solid 1
305 bpInnerRectSolid); // solid 2
306
307 //beampipe outer edge for subtraction (actually just like vacuum + lengthSafety)
308 //this length should be less than bpInnerSolid above but longer than the actual length for later intersection
309 G4double extraWidth = beamPipeThicknessIn + lengthSafetyLarge;
310 G4VSolid* bpOuterCylSolid = new G4EllipticalTube(nameIn + "_pipe_inner_ellipsoid", // name
311 aper3In + extraWidth, // horizontal semi-axis
312 aper4In + extraWidth, // vertical semi-axis
313 angledVolumeLength); // length
314 //beampipe outer edge box solid (rectangular cross-section)
315 G4VSolid* bpOuterRectSolid = new G4Box(nameIn + "_pipe_inner_box", // name
316 aper1In + extraWidth, // x half width
317 aper2In + extraWidth, // y half width
318 1.1*angledVolumeLength); // long length for unambiguous intersection
319 G4VSolid* bpOuterSolid = new G4IntersectionSolid(nameIn + "_pipe_inner_solid", // name
320 bpOuterCylSolid, // solid 1
321 bpOuterRectSolid); // solid 2
322 //correct solid shape but too long
323 G4VSolid* longBeamPipeSolid = new G4SubtractionSolid(nameIn + "_long_pipe_solid", // name
324 bpOuterSolid, // this
325 bpInnerSolid); // minus this
326
327 allSolids.insert(bpInnerCylSolid);
328 allSolids.insert(bpInnerRectSolid);
329 allSolids.insert(bpInnerSolid);
330 allSolids.insert(bpOuterCylSolid);
331 allSolids.insert(bpOuterRectSolid);
332 allSolids.insert(bpOuterSolid);
333
334 //final beampipe solid with correct shape and angled faces
335 beamPipeSolid = new G4IntersectionSolid(nameIn + "_pipe_solid", // name
336 longBeamPipeSolid, // solid1
337 vacuumAngledSolid); // solid2
338
339 //container solid
340 //container cylindrical solid (circular cross-section)
341 G4VSolid* contCylSolid = new G4EllipticalTube(nameIn + "_vacuum_ellipsoid", // name
342 aper3In + extraWidth + lengthSafetyLarge, // horizontal semi-axis
343 aper4In + extraWidth + lengthSafetyLarge, // vertical semi-axis
344 angledVolumeLength); // length
345 // length both long and different from next solid for unamibiguous intersection
346
347 //vacuum box solid (rectangular cross-section)
348 G4VSolid* contRectSolid = new G4Box(nameIn + "_vacuum_box", // name
349 aper1In + extraWidth + lengthSafetyLarge, // x half width
350 aper2In + extraWidth + lengthSafetyLarge, // y half width
351 1.1*angledVolumeLength); // z full width (long for unambiguous intersection)
352 //intersection of both of these gives the desired shape
353 G4VSolid* longContainerSolid = new G4IntersectionSolid(nameIn + "_long_container_solid", // name
354 contCylSolid, // solid 1
355 contRectSolid); // solid 2
356
357 allSolids.insert(contCylSolid);
358 allSolids.insert(contRectSolid);
359 allSolids.insert(longContainerSolid);
360
361 containerSolid = new G4IntersectionSolid(nameIn + "_container_solid", // name
362 longContainerSolid, // solid 1
363 vacuumAngledSolid); // solid 2
364}
365
366void BDSBeamPipeFactoryRectEllipse::CreateContainerSubtractionSolid(const G4String& nameIn,
367 G4double& lengthIn,
368 G4double& beamPipeThicknessIn,
369 G4double& aper1In,
370 G4double& aper2In,
371 G4double& aper3In,
372 G4double& aper4In)
373{
374 //container cylindrical solid (circular cross-section)
375 G4VSolid* contSubCylSolid = new G4EllipticalTube(nameIn + "_subtraction_ellipsoid", // name
376 aper3In + beamPipeThicknessIn + 3*lengthSafetyLarge, // horizontal semi-axis
377 aper4In + beamPipeThicknessIn + 3*lengthSafetyLarge, // vertical semi-axis
378 2*lengthIn); // long length for unambiguous subtraction
379 //vacuum box solid (rectangular cross-section)
380 G4VSolid* contSubRectSolid = new G4Box(nameIn + "_subtraction_box", // name
381 aper1In + beamPipeThicknessIn + 2*lengthSafetyLarge, // x half width
382 aper2In + beamPipeThicknessIn + 2*lengthSafetyLarge, // y half width
383 1.7*lengthIn); // z full width (long for unambiguous intersection)
384 allSolids.insert(contSubCylSolid);
385 allSolids.insert(contSubRectSolid);
386
387 //intersection of both of these gives the desired shape
388 containerSubtractionSolid = new G4IntersectionSolid(nameIn + "_subtraction_solid", // name
389 contSubCylSolid, // solid 1
390 contSubRectSolid); // solid 2
391}
G4ThreeVector outputFaceNormal
For recording the face normals in the finished pipe component.
G4ThreeVector inputFaceNormal
For recording the face normals in the finished pipe component.
void CommonConstruction(const G4String &nameIn, G4Material *vacuumMaterialIn, G4Material *beamPipeMaterialIn, G4double length)
finalise beampipe construction
BDSBeamPipe * BuildBeamPipeAndRegisterVolumes(BDSExtent extent, G4double containerRadius, G4bool containerIsCircular=false)
build beampipe and register logical volumes
static void CheckAngledVolumeCanBeBuilt(G4double length, const G4ThreeVector &inputfaceAngle, const G4ThreeVector &outputfaceAngle, G4double horizontalWidth, const G4String &name)
check if a beam pipe volume with angled faces can be constructed
G4VSolid * containerSubtractionSolid
Longer (in length) version of container solid for unambiguous subtraction.
Factory for elliptical beam pipes.
virtual BDSBeamPipe * CreateBeamPipe(const G4String &nameIn, G4double lengthIn, G4double aper1=0, G4double aper2=0, G4double aper3=0, G4double aper4=0, G4Material *vacuumMaterialIn=nullptr, G4double beamPipeThicknessIn=0, G4Material *beamPipeMaterialIn=nullptr, const G4String &pointsFileIn="", const G4String &pointsUnitIn="")
create a flat ended beampipe
BDSBeamPipe * CommonFinalConstruction(const G4String &nameIn, G4Material *vacuumMaterialIn, G4Material *beamPipeMaterialIn, G4double lengthIn, G4double widthIn, G4double heightIn)
virtual BDSBeamPipe * CreateBeamPipe(const G4String &nameIn, G4double lengthIn, G4double aper1=0, G4double aper2=0, G4double aper3=0, G4double aper4=0, G4Material *vacuumMaterialIn=nullptr, G4double beamPipeThicknessIn=0, G4Material *beamPipeMaterialIn=nullptr, const G4String &pointsFileIn="", const G4String &pointsUnitIn="")
create a flat ended beampipe
void CreateGeneralAngledSolids(const G4String &nameIn, G4double lengthIn, G4double aper1In, G4double aper2In, G4double aper3In, G4double aper4In, G4double beamPipeThicknessIn, const G4ThreeVector &inputfaceIn, const G4ThreeVector &outputfaceIn)
A holder class for a piece of beam pipe geometry.
General exception with possible name of object and message.
Holder for +- extents in 3 dimensions.
Definition BDSExtent.hh:38
G4double lengthSafety
Cache of global constants variable.
G4double lengthSafetyLarge
Cache of global constants variable.
G4double CalculateSafeAngledVolumeLength(G4double angleIn, G4double angleOut, G4double length, G4double containerWidth, G4double containerHeight=0)
Calculate safe length of an angled volume so it fills the length of its container.