BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSMagnetOuterFactoryLHC.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2022.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "BDSAppropriateTubs.hh"
20#include "BDSBeamPipe.hh"
21#include "BDSBeamPipeInfo.hh"
22#include "BDSBeamPipeType.hh"
23#include "BDSBeamPipeFactory.hh"
24#include "BDSColours.hh"
25#include "BDSDebug.hh"
26#include "BDSException.hh"
27#include "BDSExtent.hh"
28#include "BDSGeometryComponent.hh"
29#include "BDSGlobalConstants.hh"
30#include "BDSMagnetOuter.hh"
31#include "BDSMagnetOuterFactoryCylindrical.hh"
32#include "BDSMagnetOuterFactoryLHC.hh"
33#include "BDSMagnetOuterInfo.hh"
34#include "BDSMaterials.hh"
35#include "BDSSDType.hh"
36#include "BDSUtilities.hh" // for calculateorientation
37
38#include "globals.hh" // geant4 globals / types
39//#include "G4Box.hh"
40#include "G4CutTubs.hh"
41//#include "G4IntersectionSolid.hh"
42#include "G4LogicalVolume.hh"
43#include "G4UnionSolid.hh"
44#include "G4Material.hh"
45#include "G4PVPlacement.hh"
46#include "G4SubtractionSolid.hh"
47#include "G4ThreeVector.hh"
48#include "G4Tubs.hh"
49#include "G4VisAttributes.hh"
50#include "G4VSolid.hh"
51
52#include "CLHEP/Units/SystemOfUnits.h"
53
54#include <algorithm>
55#include <cmath>
56#include <set>
57#include <utility>
58#include <vector>
59
61const G4double BDSMagnetOuterFactoryLHC::beamSeparation = 194.00*CLHEP::mm;
62
63BDSMagnetOuterFactoryLHC::BDSMagnetOuterFactoryLHC(G4bool isLeftOffsetIn):
64 isLeftOffset(isLeftOffsetIn)
65{
66 cylindrical = new BDSMagnetOuterFactoryCylindrical();
67}
68
69BDSMagnetOuterFactoryLHC::~BDSMagnetOuterFactoryLHC()
70{
71 delete cylindrical;
72}
73
75 G4double length,
76 const BDSBeamPipe* beamPipe,
77 G4double containerLength,
78 const BDSMagnetOuterInfo* recipe)
79{
80 return CreateLHCDipole(name, length, beamPipe, containerLength, recipe, YokeColour::dipole);
81}
82
84 G4double length,
85 const BDSBeamPipe* beamPipe,
86 G4double containerLength,
87 const BDSMagnetOuterInfo* recipe,
88 YokeColour colourIn)
89{
90 CleanUp();
91
92 G4double horizontalWidth = recipe->horizontalWidth;
93 G4double angleIn = recipe->angleIn;
94 G4double angleOut = recipe->angleOut;
95
96 G4bool flatFaces = (!BDS::IsFinite(angleIn)) && (!BDS::IsFinite(angleOut));
97
98 // note this geometry does not respond to horizontalWidth - it's hard coded to the
99 // design of a sector bend for the lhc. TestInputParameters requires it though
100 // to be the same check for the other methods
101
102 // test input parameters - set global options as default if not specified
103 TestInputParameters(beamPipe,horizontalWidth);
104
105 // nominal lhc beampipe parameters for reference
106 // aper1 = 4.404cm / 2
107 // aper2 = 3.428cm / 2
108 // aper3 = 4.404cm / 2
109 // containerRadius -> 24.599mm for lhc beampipe with these parameters
110
111 // geometrical constants
112 // [1] LHC design report - Chapter 7, fig 7.3
113 // [2] LHC design report - Chapter 7, fig 7.1
114 G4double beamPipeAxisSeparation = beamSeparation;
115 G4double massShift = 0.5 * beamPipeAxisSeparation; // central shift to geometry
116 //G4double collarBoxHalfHeight = 60*CLHEP::mm; // [1] by visual inspection
117 G4double collarBoxHalfWidth = 22*CLHEP::mm; // fits between outer coils
118
119 // radii
120 G4double containerInnerRadius = beamPipe->GetContainerRadius()+lengthSafetyLarge;
121 G4double innerCoilInnerRadius = containerInnerRadius + lengthSafetyLarge;
122 G4double innerCoilInnerRadiusF = 24.601*CLHEP::mm; // the fixed radius for the second pipe - F for fixed
123 G4double innerCoilOuterRadius = 42*CLHEP::mm; // [2] by visual inspection
124 G4double outerCoilInnerRadius = innerCoilOuterRadius + lengthSafetyLarge;
125 G4double outerCoilInnerRadiusF = innerCoilOuterRadius + lengthSafetyLarge; // doesn't change
126 G4double outerCoilOuterRadius = 60*CLHEP::mm; // [2] by visual inspection
127 G4double collarInnerRadius = outerCoilOuterRadius + lengthSafetyLarge;
128 G4double collarInnerRadiusF = outerCoilOuterRadius + lengthSafetyLarge;
129 G4double collarOuterRadius = 101.18*CLHEP::mm; // [1] - at 293K but don't have 1.9K measurement
130 G4double yokeOuterRadius = 570.0*0.5*CLHEP::mm; // [2] - at 293K but don't have 1.9K measurement
131 G4double magnetContainerRadius = yokeOuterRadius + lengthSafetyLarge;
132
133 // angular setup of coils
134 // these angles were calculated by visually analysing the coil layout graph in [2]
135 G4double poleInnerFullAngle = 33./180.*2; //33 degrees half angle in radians
136 G4double poleOuterFullAngle = 100./180.*2; //80 degrees half angle in radians
137 G4double coilInnerFullAngle = CLHEP::pi - poleInnerFullAngle - 1e-3; // 1e-3 is small margin to avoid overlap
138 G4double coilOuterFullAngle = CLHEP::pi - poleOuterFullAngle - 1e-3;
139
140 // whether to build various components around active beam pipe depending on how wide it is
141 // these ONLY apply to the components around the active beampipe
142 G4bool buildInnerCoil = true;
143 G4bool buildOuterCoil = true;
144 G4bool buildCollar = true; // collar around the active beam pipe
145 if (innerCoilInnerRadius > innerCoilOuterRadius)
146 {buildInnerCoil = false;}
147 if ((innerCoilInnerRadius > outerCoilInnerRadius) && (innerCoilInnerRadius < outerCoilOuterRadius))
148 {outerCoilInnerRadius = containerInnerRadius + lengthSafety;}
149 if (innerCoilInnerRadius > outerCoilOuterRadius)
150 {buildOuterCoil = false;}
151 // this still uses the boxHalfWidth but just as good as the collar annulli overlap slightly in the middle
152 // and this will protect against this
153 if ((innerCoilInnerRadius > collarInnerRadius) && (innerCoilInnerRadius < (massShift - collarBoxHalfWidth)))
154 {collarInnerRadius = containerInnerRadius + lengthSafety;}
155 if (innerCoilInnerRadius > (massShift - collarBoxHalfWidth))
156 {buildCollar = false;}
157 if (innerCoilInnerRadius > collarOuterRadius)
158 {// pipe is too big to use with this geometry!
159 throw BDSException(__METHOD_NAME__, "error in component \"" + name + "\"\n" +
160 "this beam pipe is too big to use with the LHC dipole geometry\n" +
161 "Please consider using a different magnet geometry for this particular magnet");
162 }
163
164 G4ThreeVector dipolePosition; // translation of whole assembly relative to centre of active pipe
165 if (isLeftOffset)
166 {
167 dipolePosition = G4ThreeVector(massShift,0.,0.);
168 beamPipeAxisSeparation *= -1;
169#ifdef BDSDEBUG
170 G4cout << __METHOD_NAME__ << "dipole to the left" << G4endl;
171#endif
172 }
173 else
174 {
175 dipolePosition = G4ThreeVector(-massShift,0.,0.);
176 //massShift *= -1;
177#ifdef BDSDEBUG
178 G4cout << __METHOD_NAME__ << "dipole to the right" << G4endl;
179#endif
180 }
181
182 // calculate some geometrical parameters
183 G4double angle = angleIn + angleOut; // total angle
184 G4int orientation = BDS::CalculateOrientation(-angle);
185 std::pair<G4ThreeVector,G4ThreeVector> faces = BDS::CalculateFaces(angleIn,angleOut);
186 inputFaceNormal = faces.first;
187 outputFaceNormal = faces.second;
188
189 // lengths at different points transversely - dependent on left or right geometry as well as angle +ve or -ve
190 G4double centralHalfLength = length*0.5 - orientation*0.5*beamPipeAxisSeparation*tan(fabs(angle*0.5)); // central axis of outer cylinder
191 // note container length is defined along the main beam axis - here our container is offset so the container length is also slightly different
192 G4double centralContainerLength = containerLength - orientation*beamPipeAxisSeparation*tan(fabs(angle*0.5)); // central axis of outer cylinder
193 //G4double centralContainerLength = 2*(centralHalfLength + lengthSafetyLarge) + 10*CLHEP::mm;
194 G4double secondBPHalfLength = length*0.5 - orientation*beamPipeAxisSeparation*tan(fabs(angle*0.5)); // central axis of second beampipe
195
196#ifdef BDSDEBUG
197 G4cout << __METHOD_NAME__ << "all calculated parameters: " << G4endl;
198 G4cout << "container inner radius: " << containerInnerRadius << G4endl;
199 G4cout << "inner coil inner radius: " << innerCoilInnerRadius << G4endl;
200 G4cout << "inner coil outer radius: " << innerCoilOuterRadius << G4endl;
201 G4cout << "outer coil inner radius: " << outerCoilInnerRadius << G4endl;
202 G4cout << "outer coil outer radius: " << outerCoilOuterRadius << G4endl;
203 G4cout << "collar inner radius: " << collarInnerRadius << G4endl;
204 G4cout << "collar outer radius: " << collarOuterRadius << G4endl;
205 G4cout << "yoke outer radius: " << yokeOuterRadius << G4endl;
206#endif
207
208 G4VSolid* containerSolidOuter = BDS::AppropriateTubs(name + "_container_solid_outer",
209 0, // inner radius
210 yokeOuterRadius, // outer radius
211 centralHalfLength, // half length
212 0, // rotation start angle
213 CLHEP::twopi,
214 inputFaceNormal, // input face normal
215 outputFaceNormal,
216 flatFaces);
217 allSolids.insert(containerSolidOuter);
218 G4VSolid* containerSolidInner;
219 if (beamPipe->ContainerIsCircular())
220 {
221 //circular beampipe so we can simply use its radius
222 //container is similar but slightly wider and hollow (to allow placement of beampipe)
223 //have to do subtraction as cuttubs aperture is central and the beampipe (active one) is not here
224 containerSolidInner = new G4Tubs(name + "_container_solid_inner", // name
225 0, // inner radius
226 containerInnerRadius, // outer radius
227 length, // full length for unambiguous subtraction
228 0, // rotation start angle
229 CLHEP::twopi);
230 allSolids.insert(containerSolidInner);
231 }
232 else
233 {containerSolidInner = beamPipe->GetContainerSubtractionSolid();}
234 containerSolid = new G4SubtractionSolid(name + "_outer_container_solid",// name
235 containerSolidOuter, // outer bit
236 containerSolidInner, // subtract this from it
237 nullptr, // rotation
238 -dipolePosition); // translation
239
240 // make the whole magnet container solid
241 BuildMagnetContainerSolidAngled(name, centralContainerLength, magnetContainerRadius, flatFaces);
242 // make the logical volume too manually as we don't use the BDSMagnetOuterFactoryBase method for this
243
244 // Unlike other magnets, our container is tight-fitting so we fill with empty vacuum
245 G4Material* worldMaterial = BDSMaterials::Instance()->GetMaterial(BDSGlobalConstants::Instance()->EmptyMaterial());
246 magnetContainerLV = new G4LogicalVolume(magnetContainerSolid,
247 worldMaterial,
248 name + "_container_lv");
249
250 containerLV = new G4LogicalVolume(containerSolid,
251 worldMaterial,
252 name + "_outer_container_lv");
253
254 // coil solids
255 G4VSolid* coil1Inner = nullptr;
256 G4VSolid* coil1Outer = nullptr;
257 G4VSolid* coil2Inner = nullptr;
258 G4VSolid* coil2Outer = nullptr;
259 G4VSolid* coil3Inner = nullptr;
260 G4VSolid* coil3Outer = nullptr;
261 G4VSolid* coil4Inner = nullptr;
262 G4VSolid* coil4Outer = nullptr;
263 G4LogicalVolume* coil1InnerLV = nullptr;
264 G4LogicalVolume* coil1OuterLV = nullptr;
265 G4LogicalVolume* coil2InnerLV = nullptr;
266 G4LogicalVolume* coil2OuterLV = nullptr;
267 G4LogicalVolume* coil3InnerLV = nullptr;
268 G4LogicalVolume* coil3OuterLV = nullptr;
269 G4LogicalVolume* coil4InnerLV = nullptr;
270 G4LogicalVolume* coil4OuterLV = nullptr;
271 G4PVPlacement* coil1InnerPV = nullptr;
272 G4PVPlacement* coil1OuterPV = nullptr;
273 G4PVPlacement* coil2InnerPV = nullptr;
274 G4PVPlacement* coil2OuterPV = nullptr;
275 G4PVPlacement* coil3InnerPV = nullptr;
276 G4PVPlacement* coil3OuterPV = nullptr;
277 G4PVPlacement* coil4InnerPV = nullptr;
278 G4PVPlacement* coil4OuterPV = nullptr;
279
280 G4Material* nbti = BDSMaterials::Instance()->GetMaterial("NbTi.1");
281 G4Material* stainlesssteel_316LN_2K = BDSMaterials::Instance()->GetMaterial("stainless_steel_316LN_2K");
282 G4Material* stainlesssteel_304L_2K = BDSMaterials::Instance()->GetMaterial("stainless_steel_304L_2K");
283
284 G4VisAttributes* coilVisAtt = new G4VisAttributes(*BDSColours::Instance()->GetColour("LHCcoil"));
285 coilVisAtt->SetForceLineSegmentsPerCircle((G4int)nSegmentsPerCircle);
286 allVisAttributes.insert(coilVisAtt);
287 G4VSolid* collar1PoleTopInnerSolid = nullptr;
288 G4VSolid* collar1PoleBottomInnerSolid = nullptr;
289 G4VSolid* collar1PoleTopOuterSolid = nullptr;
290 G4VSolid* collar1PoleBottomOuterSolid = nullptr;
291 G4LogicalVolume* collar1PoleTopInnerLV = nullptr;
292 G4LogicalVolume* collar1PoleBottomInnerLV = nullptr;
293 G4LogicalVolume* collar1PoleTopOuterLV = nullptr;
294 G4LogicalVolume* collar1PoleBottomOuterLV = nullptr;
295 G4PVPlacement* collar1PoleTopInnerPV = nullptr;
296 G4PVPlacement* collar1PoleBottomInnerPV = nullptr;
297 G4PVPlacement* collar1PoleTopOuterPV = nullptr;
298 G4PVPlacement* collar1PoleBottomOuterPV = nullptr;
299 G4VSolid* collar2PoleTopInnerSolid = nullptr;
300 G4VSolid* collar2PoleBottomInnerSolid = nullptr;
301 G4VSolid* collar2PoleTopOuterSolid = nullptr;
302 G4VSolid* collar2PoleBottomOuterSolid = nullptr;
303 G4LogicalVolume* collar2PoleTopInnerLV = nullptr;
304 G4LogicalVolume* collar2PoleBottomInnerLV = nullptr;
305 G4LogicalVolume* collar2PoleTopOuterLV = nullptr;
306 G4LogicalVolume* collar2PoleBottomOuterLV = nullptr;
307 G4PVPlacement* collar2PoleTopInnerPV = nullptr;
308 G4PVPlacement* collar2PoleBottomInnerPV = nullptr;
309 G4PVPlacement* collar2PoleTopOuterPV = nullptr;
310 G4PVPlacement* collar2PoleBottomOuterPV = nullptr;
311 G4LogicalVolume* collarsLV = nullptr;
312 G4PVPlacement* collarsPV = nullptr;
313 G4LogicalVolume* secondBPLV = nullptr;
314 G4PVPlacement* secondBPPV = nullptr;
315
316 // use base class yokeLV and yokePV members (reset in CleanUp())
317
318 G4VisAttributes* collarVisAtt = new G4VisAttributes(*BDSColours::Instance()->GetColour("LHCcollar"));
319 collarVisAtt->SetForceLineSegmentsPerCircle((G4int)nSegmentsPerCircle);
320 allVisAttributes.insert(collarVisAtt);
321
322 //buildInnerCoil = false;
323 if (buildInnerCoil)
324 {
325 coil1Inner = BDS::AppropriateTubs(name+"_coil1_inner_solid", // name
326 innerCoilInnerRadius + lengthSafetyLarge, // inner radius
327 innerCoilOuterRadius - lengthSafetyLarge, // outer radius
328 length*0.5 - lengthSafetyLarge, // length
329 -coilInnerFullAngle*0.5, // start angle
330 coilInnerFullAngle, // sweep angle
331 inputFaceNormal, // input face normal
332 outputFaceNormal, // output face normal
333 flatFaces);
334 coil2Inner = BDS::AppropriateTubs(name+"_coil2_inner_solid", // name
335 innerCoilInnerRadius + lengthSafetyLarge, // inner radius
336 innerCoilOuterRadius - lengthSafetyLarge, // outer radius
337 length*0.5 - lengthSafetyLarge, // length
338 CLHEP::pi-coilInnerFullAngle*0.5, // start angle
339 coilInnerFullAngle, // sweep angle
340 inputFaceNormal, // input face normal
341 outputFaceNormal, // output face normal
342 flatFaces);
343 coil1InnerLV = new G4LogicalVolume(coil1Inner,
344 nbti,
345 name+"_coil1_Inner_lv");
346 coil2InnerLV = new G4LogicalVolume(coil2Inner,
347 nbti,
348 name+"_coil2_Inner_lv");
349 coil1InnerLV->SetVisAttributes(coilVisAtt);
350 coil2InnerLV->SetVisAttributes(coilVisAtt);
351
352 coil1InnerPV = new G4PVPlacement(nullptr, // rotation
353 -dipolePosition, // position
354 coil1InnerLV, // its logical volume
355 name+"_coil1_inner_pv", // its name
356 containerLV, // its mother volume
357 false, // no boolean operation
358 0,
360 coil2InnerPV = new G4PVPlacement(nullptr, // rotation
361 -dipolePosition, // position
362 coil2InnerLV, // its logical volume
363 name+"_coil2_inner_pv", // its name
364 containerLV, // its mother volume
365 false, // no boolean operation
366 0,
368
369 allSolids.insert(coil1Inner);
370 allSolids.insert(coil2Inner);
371 allLogicalVolumes.insert(coil1InnerLV);
372 allLogicalVolumes.insert(coil2InnerLV);
373 allPhysicalVolumes.insert(coil1InnerPV);
374 allPhysicalVolumes.insert(coil2InnerPV);
375
376 collar1PoleTopInnerSolid = BDS::AppropriateTubs(name+"_collar1_pole_inner_top", // name
377 innerCoilInnerRadius + lengthSafetyLarge, // inner radius
378 innerCoilOuterRadius - lengthSafetyLarge, // outer radius
379 length*0.5 - lengthSafetyLarge, // length
380 CLHEP::pi*0.5-poleInnerFullAngle*0.5, // start angle
381 poleInnerFullAngle, // sweep angle
382 inputFaceNormal, // input face normal
383 outputFaceNormal, // output face normal
384 flatFaces);
385 collar1PoleBottomInnerSolid = BDS::AppropriateTubs(name+"_collar1_pole_inner_bottom", // name
386 innerCoilInnerRadius + lengthSafetyLarge, // inner radius
387 innerCoilOuterRadius - lengthSafetyLarge, // outer radius
388 length*0.5 - lengthSafetyLarge, // length
389 CLHEP::pi*1.5-poleInnerFullAngle*0.5, // start angle
390 poleInnerFullAngle, // sweep angle
391 inputFaceNormal, // input face normal
392 outputFaceNormal, // output face normal
393 flatFaces);
394 collar1PoleTopInnerLV = new G4LogicalVolume(collar1PoleTopInnerSolid,
395 stainlesssteel_316LN_2K,
396 name+"_collar1_pole_top_inner_lv");
397 collar1PoleBottomInnerLV = new G4LogicalVolume(collar1PoleBottomInnerSolid,
398 stainlesssteel_316LN_2K,
399 name+"_collar1_pole_bottom_inner_lv");
400
401 collar1PoleTopInnerLV->SetVisAttributes(collarVisAtt);
402 collar1PoleBottomInnerLV->SetVisAttributes(collarVisAtt);
403
404 collar1PoleTopInnerPV = new G4PVPlacement(nullptr, // rotation
405 -dipolePosition, // position
406 collar1PoleTopInnerLV, // its logical volume
407 name+"_collar1_pole_top_inner_pv",// its name
408 containerLV, // its mother volume
409 false, // no boolean operation
410 0,
412 collar1PoleBottomInnerPV = new G4PVPlacement(nullptr, // rotation
413 -dipolePosition, // position
414 collar1PoleBottomInnerLV, // its logical volume
415 name+"_collar1_pole_top_inner_pv",// its name
416 containerLV, // its mother volume
417 false, // no boolean operation
418 0,
420
421 allSolids.insert(collar1PoleTopInnerSolid);
422 allSolids.insert(collar1PoleBottomInnerSolid);
423 allLogicalVolumes.insert(collar1PoleTopInnerLV);
424 allLogicalVolumes.insert(collar1PoleBottomInnerLV);
425 allPhysicalVolumes.insert(collar1PoleTopInnerPV);
426 allPhysicalVolumes.insert(collar1PoleBottomInnerPV);
427 }
428
429 if (buildOuterCoil)
430 {
431 coil1Outer = BDS::AppropriateTubs(name+"_coil1_outer_solid", // name
432 outerCoilInnerRadius, // inner radius
433 outerCoilOuterRadius, // outer radius
434 length*0.5 - lengthSafetyLarge, // length
435 -coilOuterFullAngle*0.5, // start angle
436 coilOuterFullAngle, // sweep angle
437 inputFaceNormal, // input face normal
438 outputFaceNormal, // output face normal
439 flatFaces);
440 coil2Outer = BDS::AppropriateTubs(name+"_coil2_outer_solid", // name
441 outerCoilInnerRadius, // inner radius
442 outerCoilOuterRadius, // outer radius
443 length*0.5 - lengthSafetyLarge, // length
444 CLHEP::pi-coilOuterFullAngle*0.5, // start angle
445 coilOuterFullAngle, // sweep angle
446 inputFaceNormal, // input face normal
447 outputFaceNormal, // output face normal
448 flatFaces);
449 coil1OuterLV = new G4LogicalVolume(coil1Outer,
450 nbti,
451 name+"_coil1_Inner_lv");
452 coil2OuterLV = new G4LogicalVolume(coil2Outer,
453 nbti,
454 name+"_coil2_Inner_lv");
455 coil1OuterLV->SetVisAttributes(coilVisAtt);
456 coil2OuterLV->SetVisAttributes(coilVisAtt);
457
458 coil1OuterPV = new G4PVPlacement(nullptr, // rotation
459 -dipolePosition, // position
460 coil1OuterLV, // its logical volume
461 name+"_coil1_outer_pv", // its name
462 containerLV, // its mother volume
463 false, // no boolean operation
464 0,
466 coil2OuterPV = new G4PVPlacement(nullptr, // rotation
467 -dipolePosition, // position
468 coil2OuterLV, // its logical volume
469 name+"_coil2_outer_pv", // its name
470 containerLV, // its mother volume
471 false, // no boolean operation
472 0,
474
475 allSolids.insert(coil1Outer);
476 allSolids.insert(coil2Outer);
477 allLogicalVolumes.insert(coil1OuterLV);
478 allLogicalVolumes.insert(coil2OuterLV);
479 allPhysicalVolumes.insert(coil1OuterPV);
480 allPhysicalVolumes.insert(coil2OuterPV);
481
482 collar1PoleTopOuterSolid = BDS::AppropriateTubs(name+"_collar1_pole_outer_top", // name
483 outerCoilInnerRadius, // inner radius
484 outerCoilOuterRadius, // outer radius
485 length*0.5 - lengthSafetyLarge, // length
486 CLHEP::pi*0.5-poleOuterFullAngle*0.5,// start angle
487 poleOuterFullAngle, // sweep angle
488 inputFaceNormal, // input face normal
489 outputFaceNormal, // output face normal
490 flatFaces);
491 collar1PoleBottomOuterSolid = BDS::AppropriateTubs(name+"_collar1_pole_outer_bottom", // name
492 outerCoilInnerRadius, // inner radius
493 outerCoilOuterRadius, // outer radius
494 length*0.5 - lengthSafetyLarge, // length
495 CLHEP::pi*1.5-poleOuterFullAngle*0.5,// start angle
496 poleOuterFullAngle, // sweep angle
497 inputFaceNormal, // input face normal
498 outputFaceNormal, // output face normal
499 flatFaces);
500
501 collar1PoleTopOuterLV = new G4LogicalVolume(collar1PoleTopOuterSolid,
502 stainlesssteel_316LN_2K,
503 name+"_collar1_pole_top_outer_lv");
504 collar1PoleBottomOuterLV = new G4LogicalVolume(collar1PoleBottomOuterSolid,
505 stainlesssteel_316LN_2K,
506 name+"_collar1_pole_bottom_outer_lv");
507
508 collar1PoleTopOuterLV->SetVisAttributes(collarVisAtt);
509 collar1PoleBottomOuterLV->SetVisAttributes(collarVisAtt);
510
511 collar1PoleTopOuterPV = new G4PVPlacement(nullptr, // rotation
512 -dipolePosition, // position
513 collar1PoleTopOuterLV, // its logical volume
514 name+"_collar1_pole_top_inner_pv",// its name
515 containerLV, // its mother volume
516 false, // no boolean operation
517 0,
519 collar1PoleBottomOuterPV = new G4PVPlacement(nullptr, // rotation
520 -dipolePosition, // position
521 collar1PoleBottomOuterLV, // its logical volume
522 name+"_collar1_pole_top_inner_pv",// its name
523 containerLV, // its mother volume
524 false, // no boolean operation
525 0,
527
528 allSolids.insert(collar1PoleTopOuterSolid);
529 allSolids.insert(collar1PoleBottomOuterSolid);
530 allLogicalVolumes.insert(collar1PoleTopOuterLV);
531 allLogicalVolumes.insert(collar1PoleBottomOuterLV);
532 allPhysicalVolumes.insert(collar1PoleTopOuterPV);
533 allPhysicalVolumes.insert(collar1PoleBottomOuterPV);
534 }
535
536 // coils on inactive beam pipe - always built
537 coil3Inner = BDS::AppropriateTubs(name+"_coil3_inner_solid", // name
538 innerCoilInnerRadiusF, // inner radius
539 innerCoilOuterRadius, // outer radius
540 secondBPHalfLength - lengthSafetyLarge, // length
541 -coilInnerFullAngle*0.5, // start angle
542 coilInnerFullAngle, // sweep angle
543 inputFaceNormal, // input face normal
544 outputFaceNormal, // output face normal
545 flatFaces);
546 coil3Outer = BDS::AppropriateTubs(name+"_coil3_outer_solid", // name
547 outerCoilInnerRadiusF, // inner radius
548 outerCoilOuterRadius, // outer radius
549 secondBPHalfLength - lengthSafetyLarge, // length
550 -coilOuterFullAngle*0.5, // start angle
551 coilOuterFullAngle, // sweep angle
552 inputFaceNormal, // input face normal
553 outputFaceNormal, // output face normal
554 flatFaces);
555 coil4Inner = BDS::AppropriateTubs(name+"_coil4_inner_solid", // name
556 innerCoilInnerRadiusF, // inner radius
557 innerCoilOuterRadius, // outer radius
558 secondBPHalfLength - lengthSafetyLarge, // length
559 CLHEP::pi-coilInnerFullAngle*0.5, // start angle
560 coilInnerFullAngle, // sweep angle
561 inputFaceNormal, // input face normal
562 outputFaceNormal, // output face normal
563 flatFaces);
564 coil4Outer = BDS::AppropriateTubs(name+"_coil4_outer_solid", // name
565 outerCoilInnerRadiusF, // inner radius
566 outerCoilOuterRadius, // outer radius
567 secondBPHalfLength - lengthSafetyLarge, // length
568 CLHEP::pi-coilOuterFullAngle*0.5, // start angle
569 coilOuterFullAngle, // sweep angle
570 inputFaceNormal, // input face normal
571 outputFaceNormal, // output face normal
572 flatFaces);
573
574 coil3InnerLV = new G4LogicalVolume(coil3Inner,
575 nbti,
576 name+"_coil3_Inner_lv");
577 coil3OuterLV = new G4LogicalVolume(coil3Outer,
578 nbti,
579 name+"_coil3_Inner_lv");
580 coil4InnerLV = new G4LogicalVolume(coil4Inner,
581 nbti,
582 name+"_coil4_Inner_lv");
583 coil4OuterLV = new G4LogicalVolume(coil4Outer,
584 nbti,
585 name+"_coil4_Inner_lv");
586
587 coil3InnerLV->SetVisAttributes(coilVisAtt);
588 coil3OuterLV->SetVisAttributes(coilVisAtt);
589 coil4InnerLV->SetVisAttributes(coilVisAtt);
590 coil4OuterLV->SetVisAttributes(coilVisAtt);
591
592 allSolids.insert(coil3Inner);
593 allSolids.insert(coil3Outer);
594 allSolids.insert(coil4Inner);
595 allSolids.insert(coil4Outer);
596 allLogicalVolumes.insert(coil3InnerLV);
597 allLogicalVolumes.insert(coil3OuterLV);
598 allLogicalVolumes.insert(coil4InnerLV);
599 allLogicalVolumes.insert(coil4OuterLV);
600
601
602 // coil placement
603 coil3InnerPV = new G4PVPlacement(nullptr, // rotation
604 dipolePosition, // position
605 coil3InnerLV, // its logical volume
606 name+"_coil3_inner_pv", // its name
607 containerLV, // its mother volume
608 false, // no boolean operation
609 0,
611 coil3OuterPV = new G4PVPlacement(nullptr, // rotation
612 dipolePosition, // position
613 coil3OuterLV, // its logical volume
614 name+"_coil3_outer_pv", // its name
615 containerLV, // its mother volume
616 false, // no boolean operation
617 0,
619 coil4InnerPV = new G4PVPlacement(nullptr, // rotation
620 dipolePosition, // position
621 coil4InnerLV, // its logical volume
622 name+"_coil4_inner_pv", // its name
623 containerLV, // its mother volume
624 false, // no boolean operation
625 0,
627 coil4OuterPV = new G4PVPlacement(nullptr, // rotation
628 dipolePosition, // position
629 coil4OuterLV, // its logical volume
630 name+"_coil4_outer_pv", // its name
631 containerLV, // its mother volume
632 false, // no boolean operation
633 0,
635 allPhysicalVolumes.insert(coil3InnerPV);
636 allPhysicalVolumes.insert(coil3OuterPV);
637 allPhysicalVolumes.insert(coil4InnerPV);
638 allPhysicalVolumes.insert(coil4OuterPV);
639
640 // non-magnetic collars
641 // collar pole solids
642 collar2PoleTopInnerSolid = BDS::AppropriateTubs(name+"_collar2_pole_inner_top", // name
643 innerCoilInnerRadiusF, // inner radius
644 innerCoilOuterRadius, // outer radius
645 secondBPHalfLength - lengthSafetyLarge, // length
646 CLHEP::pi*0.5-poleInnerFullAngle*0.5, // start angle
647 poleInnerFullAngle, // sweep angle
648 inputFaceNormal, // input face normal
649 outputFaceNormal, // output face normal
650 flatFaces);
651 collar2PoleTopOuterSolid = BDS::AppropriateTubs(name+"_collar2_pole_outer_top", // name
652 outerCoilInnerRadiusF, // inner radius
653 outerCoilOuterRadius, // outer radius
654 secondBPHalfLength - lengthSafetyLarge, // length
655 CLHEP::pi*0.5-poleOuterFullAngle*0.5, // start angle
656 poleOuterFullAngle, // sweep angle
657 inputFaceNormal, // input face normal
658 outputFaceNormal, // output face normal
659 flatFaces);
660 collar2PoleBottomInnerSolid = BDS::AppropriateTubs(name+"_collar2_pole_inner_bottom", // name
661 innerCoilInnerRadiusF, // inner radius
662 innerCoilOuterRadius, // outer radius
663 secondBPHalfLength - lengthSafetyLarge, // length
664 CLHEP::pi*1.5-poleInnerFullAngle*0.5, // start angle
665 poleInnerFullAngle, // sweep angle
666 inputFaceNormal, // input face normal
667 outputFaceNormal, // output face normal
668 flatFaces);
669 collar2PoleBottomOuterSolid = BDS::AppropriateTubs(name+"_collar2_pole_outer_bottom", // name
670 outerCoilInnerRadiusF, // inner radius
671 outerCoilOuterRadius, // outer radius
672 secondBPHalfLength - lengthSafetyLarge, // length
673 CLHEP::pi*1.5-poleOuterFullAngle*0.5, // start angle
674 poleOuterFullAngle, // sweep angle
675 inputFaceNormal, // input face normal
676 outputFaceNormal, // output face normal
677 flatFaces);
678
679 // collar pole logical volumes
680 collar2PoleTopInnerLV = new G4LogicalVolume(collar2PoleTopInnerSolid,
681 stainlesssteel_316LN_2K,
682 name+"_collar2_pole_top_inner_lv");
683 collar2PoleTopOuterLV = new G4LogicalVolume(collar2PoleTopOuterSolid,
684 stainlesssteel_316LN_2K,
685 name+"_collar2_pole_top_outer_lv");
686 collar2PoleBottomInnerLV = new G4LogicalVolume(collar2PoleBottomInnerSolid,
687 stainlesssteel_316LN_2K,
688 name+"_collar2_pole_bottom_inner_lv");
689 collar2PoleBottomOuterLV = new G4LogicalVolume(collar2PoleBottomOuterSolid,
690 stainlesssteel_316LN_2K,
691 name+"_collar2_pole_bottom_outer_lv");
692
693 // collar pole visualisation
694 collar2PoleTopInnerLV->SetVisAttributes(collarVisAtt);
695 collar2PoleTopOuterLV->SetVisAttributes(collarVisAtt);
696 collar2PoleBottomInnerLV->SetVisAttributes(collarVisAtt);
697 collar2PoleBottomOuterLV->SetVisAttributes(collarVisAtt);
698
699 allSolids.insert(collar2PoleTopInnerSolid);
700 allSolids.insert(collar2PoleTopOuterSolid);
701 allSolids.insert(collar2PoleBottomInnerSolid);
702 allSolids.insert(collar2PoleBottomOuterSolid);
703 allLogicalVolumes.insert(collar2PoleTopInnerLV);
704 allLogicalVolumes.insert(collar2PoleTopOuterLV);
705 allLogicalVolumes.insert(collar2PoleBottomInnerLV);
706 allLogicalVolumes.insert(collar2PoleBottomOuterLV);
707
708 // collar pole placement
709 collar2PoleTopInnerPV = new G4PVPlacement(nullptr, // rotation
710 dipolePosition, // position
711 collar2PoleTopInnerLV, // its logical volume
712 name+"_collar2_pole_top_inner_pv",// its name
713 containerLV, // its mother volume
714 false, // no boolean operation
715 0,
717 collar2PoleTopOuterPV = new G4PVPlacement(nullptr, // rotation
718 dipolePosition, // position
719 collar2PoleTopOuterLV, // its logical volume
720 name+"_collar2_pole_top_inner_pv",// its name
721 containerLV, // its mother volume
722 false, // no boolean operation
723 0,
725 collar2PoleBottomInnerPV = new G4PVPlacement(nullptr, // rotation
726 dipolePosition, // position
727 collar2PoleBottomInnerLV, // its logical volume
728 name+"_collar2_pole_top_inner_pv",// its name
729 containerLV, // its mother volume
730 false, // no boolean operation
731 0,
733 collar2PoleBottomOuterPV = new G4PVPlacement(nullptr, // rotation
734 dipolePosition, // position
735 collar2PoleBottomOuterLV, // its logical volume
736 name+"_collar2_pole_top_inner_pv",// its name
737 containerLV, // its mother volume
738 false, // no boolean operation
739 0,
741
742 allPhysicalVolumes.insert(collar2PoleTopInnerPV);
743 allPhysicalVolumes.insert(collar2PoleTopOuterPV);
744 allPhysicalVolumes.insert(collar2PoleBottomInnerPV);
745 allPhysicalVolumes.insert(collar2PoleBottomOuterPV);
746
747 // outer annulus of collar - two as slightly different lengths
748 G4VSolid* collarAnnulus2 = BDS::AppropriateTubs(name+"_collar2_annulus_solid", // name
749 collarInnerRadiusF, // inner radius
750 collarOuterRadius, // outer radius
751 secondBPHalfLength-lengthSafety, // length
752 0, // starting angle
753 CLHEP::twopi, // angle of sweep
754 inputFaceNormal, // input face normal
755 outputFaceNormal, // output face normal
756 flatFaces);
757
758 allSolids.insert(collarAnnulus2);
759 // make final solid pointer as collar round active beam pipe optional depending on how big active beam pipe is
760 G4VSolid* collars = collarAnnulus2;
761
762 //buildCollar = false;
763 if (buildCollar)
764 {
765 // building collar around active pipe
766 G4VSolid* collarAnnulus1 = BDS::AppropriateTubs(name+"_collar1_annulus_solid", // name
767 collarInnerRadius, // inner radius
768 collarOuterRadius, // outer radius
769 length*0.5 - lengthSafetyLarge, // length
770 0, // starting angle
771 CLHEP::twopi, // angle of sweep
772 inputFaceNormal, // input face normal
773 outputFaceNormal, // output face normal
774 flatFaces);
775
776 collars = new G4UnionSolid(name + "_collars_solid", // name
777 collarAnnulus2, // solid1
778 collarAnnulus1, // solid2
779 nullptr, // rotation
780 -2*dipolePosition); // translation
781 allSolids.insert(collarAnnulus1);
782 allSolids.insert(collars);
783 }
784
785 /*
786 // This part seems to not produce any overlapping volumes and no errors but won't render
787 // in anything but the raytracer. Requires commented out collarBoxHalfHeight at top of this
788 // method to be uncommented, plus new subtraction solid for yoke will need to written
789 // ommitted for now
790
791 G4VSolid* collarBox = new G4Box(name + "_collar_box_solid", // name
792 collarBoxHalfWidth, // x half width
793 collarBoxHalfHeight, // y half width
794 2*centralHalfLength); // z half length
795 G4VSolid* collarBoxFaces = new G4CutTubs(name + "_collar_box_faces_solid", // name
796 0, // inner radius
797 50*CLHEP::cm, // outer radius
798 centralHalfLength - lengthSafety, // length
799 0, // starting angle
800 CLHEP::twopi, // sweep angle
801 inputFaceNormal, // input face normal
802 outputFaceNormal); // output face normal
803 G4VSolid* collarCentralPiece = new G4IntersectionSolid(name + "_collar_central_solid", // name
804 collarBox, // solid 1
805 collarBoxFaces); // solid 2
806
807 G4VSolid* collarTotal = new G4UnionSolid(name + "_collar2_plus_box_solid", // name
808 collars, // solid 2
809 collarCentralPiece, // solid 1
810 0, // rotation
811 -dipolePosition); // translation
812 */
813 G4VSolid* collarTotal = collars;
814
815 collarsLV = new G4LogicalVolume(collarTotal,
816 stainlesssteel_316LN_2K,
817 name+"_collars_lv");
818
819 // collar annulus visualisation attributes
820 collarsLV->SetVisAttributes(collarVisAtt);
821
822 allLogicalVolumes.insert(collarsLV); // register locally
823
824 collarsPV = new G4PVPlacement(nullptr, // rotation
825 dipolePosition, // position
826 collarsLV, // its logical volume
827 name+"_collars_pv", // its name
828 containerLV, // its mother volume
829 false, // no boolean operation
830 0, // copy number
832 allPhysicalVolumes.insert(collarsPV);
833
834 // outer iron yoke
835 G4VSolid* yokeCylinder = BDS::AppropriateTubs(name+"_yoke_cylinder_solid", // name
836 0., // inner radius
837 yokeOuterRadius - lengthSafety, // outer radius
838 centralHalfLength-lengthSafety, // length
839 0, // starting angle
840 CLHEP::twopi, // sweep angle
841 inputFaceNormal, // input face normal
842 outputFaceNormal, // output face normal
843 flatFaces);
844
845 // need to cut hole out for everything inside - note subtraction solid has to be solid
846 G4VSolid* yokeSubtractionCylinder = new G4Tubs(name + "_yoke_subtraction_cyl_solid", // name
847 0, // inner radius
848 collarOuterRadius + lengthSafety, // outer radius
849 length, // z half length - long for unambiguous subtraction
850 0, // start angle
851 CLHEP::twopi); // sweep angle
852
853 G4VSolid* yokeSubtractionSolid = new G4UnionSolid(name + "_yoke_subtraction_solid", // name
854 yokeSubtractionCylinder, // solid 1
855 yokeSubtractionCylinder, // solid 2
856 nullptr, // rotation
857 2*dipolePosition); // translation
858
859 yokeSolid = new G4SubtractionSolid(name+"_yoke_solid", // name
860 yokeCylinder, // from this
861 yokeSubtractionSolid, // subtract this
862 nullptr, // rotation
863 -dipolePosition); // translation
864 allSolids.insert(yokeSubtractionCylinder);
865 allSolids.insert(yokeSubtractionSolid);
866 allSolids.insert(yokeSolid);
867 yokeLV = new G4LogicalVolume(yokeSolid,
868 stainlesssteel_304L_2K,
869 name+"_yoke_lv");
870
871 // yoke visualisation
872 G4Colour* yokeColour;
873 switch (colourIn)
874 {
875 case YokeColour::dipole:
876 {yokeColour = BDSColours::Instance()->GetColour("LHCyoke"); break;}
877 case YokeColour::kicker:
878 {yokeColour = recipe->colour; break;}
879 default:
880 {yokeColour = BDSColours::Instance()->GetColour("LHCyoke"); break;}
881 }
882 G4VisAttributes* yokeVis = new G4VisAttributes(*yokeColour);
883 yokeVis->SetForceLineSegmentsPerCircle((G4int)nSegmentsPerCircle);
884 allVisAttributes.insert(yokeVis);
885 yokeLV->SetVisAttributes(yokeVis);
886
887 allLogicalVolumes.insert(yokeLV); // register locally
888
889 // yoke placement
890 yokePV = new G4PVPlacement(nullptr, // no rotation
891 G4ThreeVector(0,0,0), // position
892 yokeLV, // lv to be placed
893 name + "_yoke_pv", // name
894 containerLV, // mother lv to be placed in
895 false, // no boolean operation
896 0, // copy number
898 allPhysicalVolumes.insert(yokePV);
899
900 BDSBeamPipeInfo* defaultModel = BDSGlobalConstants::Instance()->DefaultBeamPipeModel();
901 G4Material* vacuumMaterial = defaultModel->vacuumMaterial;
902
903 //use beampipe factories to create another beampipe (note no magnetic field for now...)
904 BDSBeamPipe* secondBP;
905 if (flatFaces)
906 {
907 secondBP = BDSBeamPipeFactory::Instance()->CreateBeamPipe(BDSBeamPipeType::lhcdetailed,
908 name,
909 2*secondBPHalfLength-2*lengthSafety,
910 2.202*CLHEP::cm,
911 1.714*CLHEP::cm,
912 2.202*CLHEP::cm,
913 0,
914 vacuumMaterial,
915 1*CLHEP::mm,
916 stainlesssteel_316LN_2K);
917 }
918 else
919 {
920 secondBP = BDSBeamPipeFactory::Instance()->CreateBeamPipe(BDSBeamPipeType::lhcdetailed,
921 name,
922 2 * secondBPHalfLength - 2 * lengthSafety,
923 inputFaceNormal,
924 outputFaceNormal,
925 2.202 * CLHEP::cm,
926 1.714 * CLHEP::cm,
927 2.202 * CLHEP::cm,
928 0,
929 vacuumMaterial,
930 1 * CLHEP::mm,
931 stainlesssteel_316LN_2K);
932 }
933
934 secondBPLV = secondBP->GetContainerLogicalVolume();
935 secondBPPV = new G4PVPlacement(nullptr, // no rotation
936 dipolePosition, // position
937 secondBPLV, // lv to be placed
938 name + "_second_beampipe_pv", // name
939 containerLV, // mother lv to be placed in
940 false, // no boolean operation
941 0, // copy number
943 allPhysicalVolumes.insert(secondBPPV);
944
945 // visual attributes for container
946 containerLV->SetVisAttributes(containerVisAttr);
947 magnetContainerLV->SetVisAttributes(containerVisAttr);
948
949 // user limits
950 for (auto lv : allLogicalVolumes)
951 {lv->SetUserLimits(defaultUserLimits);}
952 containerLV->SetUserLimits(defaultUserLimits);
953 magnetContainerLV->SetUserLimits(defaultUserLimits);
954
955 // record extents
956 // container radius is the same for all methods as all cylindrical
957 G4double containerRadius = yokeOuterRadius;
958 // massShift defined at very beginning of this function
959 BDSExtent ext = BDSExtent(-containerRadius, containerRadius,
960 -containerRadius,containerRadius,
961 -length*0.5,length*0.5);
962
963 magnetContainer = new BDSGeometryComponent(magnetContainerSolid,
964 magnetContainerLV,
965 ext, BDSExtent(), dipolePosition);
966
967 // build the BDSMagnetOuter instance and return it
968 BDSMagnetOuter* outer = new BDSMagnetOuter(containerSolid,
969 containerLV, ext,
970 magnetContainer);
971
972 SetFaceNormals(outer);
973
974 // register objects
975 outer->RegisterDaughter(secondBP);
976 outer->RegisterLogicalVolume(allLogicalVolumes);
977 outer->RegisterSensitiveVolume(allLogicalVolumes, BDSSDType::energydep);
978 outer->RegisterPhysicalVolume(allPhysicalVolumes);
979 outer->RegisterVisAttributes(allVisAttributes);
980 // no rotation matrices used in this one
981 // allLogicalVolumes is a local variable and goes out of scope so doesn't
982 // need to be emptied or reset here
983
984 return outer;
985}
986
988 G4double length,
989 const BDSBeamPipe* beamPipe,
990 G4double containerLength,
991 const BDSMagnetOuterInfo* recipe)
992{
993 return CreateSectorBend(name, length, beamPipe, containerLength, recipe);
994}
995
997 G4double length,
998 BDSBeamPipe* beamPipe,
999 G4double containerLength,
1000 const BDSMagnetOuterInfo* recipe)
1001{
1002 G4double horizontalWidth = recipe->horizontalWidth;
1003 CleanUp();
1004
1005 // test input parameters - set global options as default if not specified
1006 TestInputParameters(beamPipe,horizontalWidth);
1007
1008 // geometrical constants
1009 // [1] LHC design report - Chapter 7, fig 7.3
1010 // [2] LHC design report - Chapter 7, fig 7.1
1011 G4double beamPipeAxisSeparation = beamSeparation;
1012 G4double massShift = 0.5 * beamPipeAxisSeparation; // central shift to geometry
1013 //G4double collarBoxHalfHeight = 60*CLHEP::mm; // [1] by visual inspection
1014 G4double collarBoxHalfWidth = 22*CLHEP::mm; // fits between outer coils
1015
1016 // radii
1017 G4double containerInnerRadius = beamPipe->GetContainerRadius()+1*CLHEP::um;
1018 G4double coilInnerRadius = containerInnerRadius + lengthSafetyLarge;
1019 G4double coilInnerRadiusF = 24.601*CLHEP::mm; // the fixed radius for the second pipe - F for fixed
1020 G4double coilOuterRadius = 60*CLHEP::mm; // [2] by visual inspection
1021 G4double collarInnerRadius = coilOuterRadius + lengthSafetyLarge;
1022 G4double collarInnerRadiusF = coilOuterRadius + lengthSafetyLarge;
1023 G4double collarOuterRadius = 101.18*CLHEP::mm; // [1] - at 293K but don't have 1.9K measurement
1024 G4double yokeOuterRadius = 570.0*0.5*CLHEP::mm; // [2] - at 293K but don't have 1.9K measurement
1025 G4double magnetContainerRadius = yokeOuterRadius + lengthSafetyLarge;
1026
1027 // angular setup of coils
1028 // these angles were calculated by visually analysing the coil layout graph in [2]
1029 G4double poleFullAngle = CLHEP::pi/6.; //30 degrees angle in radians
1030 G4double coilFullAngle = CLHEP::pi/2. - poleFullAngle - 1e-3; // 1e-3 to prevent overlaps
1031 G4double coilHalfAngle = coilFullAngle*0.5;
1032 G4double coilStartAngle = -coilHalfAngle;
1033 G4double poleStartAngle = coilHalfAngle;
1034 G4RotationMatrix* coil2rm = new G4RotationMatrix();
1035 G4RotationMatrix* coil3rm = new G4RotationMatrix();
1036 G4RotationMatrix* coil4rm = new G4RotationMatrix();
1037 coil2rm->rotateZ(CLHEP::pi/2.0);
1038 coil3rm->rotateZ(CLHEP::pi);
1039 coil4rm->rotateZ(CLHEP::pi*1.5);
1040 allRotationMatrices.insert(coil2rm);
1041 allRotationMatrices.insert(coil3rm);
1042 allRotationMatrices.insert(coil4rm);
1043
1044 // whether to build various components around active beam pipe depending on how wide it is
1045 // these ONLY apply to the components around the active beampipe
1046 G4bool buildCoil = true;
1047 G4bool buildCollar = true; // collar around the active beam pipe
1048 if (coilInnerRadius > coilOuterRadius)
1049 {buildCoil = false;}
1050 // this still uses the boxHalfWidth but just as good as the collar annulli overlap slightly in the middle
1051 // and this will protect against this
1052 if ((coilInnerRadius > collarInnerRadius) && (coilInnerRadius < (massShift - collarBoxHalfWidth)))
1053 {collarInnerRadius = containerInnerRadius + lengthSafety;}
1054 if (coilInnerRadius > (massShift - collarBoxHalfWidth))
1055 {buildCollar = false;}
1056 G4bool buildAtAll = containerInnerRadius > (beamPipeAxisSeparation - collarOuterRadius - 1*CLHEP::mm);
1057 if ((coilInnerRadius > collarOuterRadius) || buildAtAll)
1058 {// pipe is too big to use with this geometry!
1059 throw BDSException(__METHOD_NAME__, "error in component \"" + name + "\"\n" +
1060 "this beam pipe is too big to use with the LHC dipole geometry\n" +
1061 "Please consider using a different magnet geometry for this particular magnet");
1062 }
1063
1064 G4ThreeVector dipolePosition; // translation of whole assembly relative to centre of active pipe
1065 if (isLeftOffset)
1066 {
1067 dipolePosition = G4ThreeVector(massShift,0.,0.);
1068 beamPipeAxisSeparation *= -1;
1069#ifdef BDSDEBUG
1070 G4cout << __METHOD_NAME__ << "dipole to the left" << G4endl;
1071#endif
1072 }
1073 else
1074 {
1075 dipolePosition = G4ThreeVector(-massShift,0.,0.);
1076 //massShift *= -1;
1077#ifdef BDSDEBUG
1078 G4cout << __METHOD_NAME__ << "dipole to the right" << G4endl;
1079#endif
1080 }
1081
1082 if (beamPipe->ContainerIsCircular())
1083 {
1084 //circular beampipe so we can simply use its radius
1085 //container is similar but slightly wider and hollow (to allow placement of beampipe)
1086 //have to do subtraction as cuttubs aperture is central and the beampipe (active one) is not here
1087 G4VSolid* containerSolidOuter = new G4Tubs(name + "_contiainer_solid_outer", // name
1088 0, // inner radius
1089 yokeOuterRadius, // outer radius
1090 length*0.5, // half length
1091 0, // rotation start angle
1092 CLHEP::twopi); // rotation finish angle
1093
1094 G4VSolid* containerSolidInner = new G4Tubs(name + "_contiainer_solid_inner", // name
1095 0, // inner radius
1096 containerInnerRadius, // outer radius
1097 length, // full length for unambiguous subtraction
1098 0, // rotation start angle
1099 CLHEP::twopi);
1100 allSolids.insert(containerSolidOuter);
1101 allSolids.insert(containerSolidInner);
1102 containerSolid = new G4SubtractionSolid(name + "_container_solid", // name
1103 containerSolidOuter, // outer bit
1104 containerSolidInner, // subtract this from it
1105 nullptr, // rotation
1106 -dipolePosition); // translation
1107 }
1108 else
1109 {
1110 //container is similar but slightly wider
1111 G4VSolid* containerSolidOuter = new G4Tubs(name + "_contiainer_solid_outer", // name
1112 0, // inner radius
1113 yokeOuterRadius, // outer radius
1114 length*0.5, // half length
1115 0, // rotation start angle
1116 CLHEP::twopi); // rotation finish angle
1117 allSolids.insert(containerSolidOuter);
1118 containerSolid = new G4SubtractionSolid(name + "_container_solid",
1119 containerSolidOuter,
1120 beamPipe->GetContainerSubtractionSolid(),
1121 nullptr, // rotation
1122 -dipolePosition); // translation
1123 }
1124
1125 // make the whole magnet container solid
1126 BuildMagnetContainerSolidStraight(name, containerLength, magnetContainerRadius);
1127 // make the logical volume too manually as we don't use the BDSMagnetOuterFactoryBase method for this
1128
1129 // Unlike other magnets, our container is tight-fitting so we fill with empty vacuum
1130 G4Material* worldMaterial = BDSMaterials::Instance()->GetMaterial(BDSGlobalConstants::Instance()->EmptyMaterial());
1131
1132 magnetContainerLV = new G4LogicalVolume(magnetContainerSolid,
1133 worldMaterial,
1134 name + "_container_lv");
1135 containerLV = new G4LogicalVolume(containerSolid,
1136 worldMaterial,
1137 name + "_container_lv");
1138
1139 // coil solids
1140 // only need one pole & coil per beampipe which can be repeatedly placed
1141 // just inner radius can be different depending on active beam pipe hence two
1142 G4VSolid* coil1 = nullptr;
1143 G4VSolid* coil2 = nullptr;
1144 G4LogicalVolume* coil1LV = nullptr;
1145 G4LogicalVolume* coil2LV = nullptr;
1146 G4VPhysicalVolume* coil1PV = nullptr;
1147 G4VPhysicalVolume* coil2PV = nullptr;
1148 G4VPhysicalVolume* coil3PV = nullptr;
1149 G4VPhysicalVolume* coil4PV = nullptr;
1150 G4VPhysicalVolume* coil5PV = nullptr;
1151 G4VPhysicalVolume* coil6PV = nullptr;
1152 G4VPhysicalVolume* coil7PV = nullptr;
1153 G4VPhysicalVolume* coil8PV = nullptr;
1154
1155 // pole solids are the ones immediately after coilN clockwise
1156 G4VSolid* pole1 = nullptr;
1157 G4VSolid* pole2 = nullptr;
1158 G4LogicalVolume* pole1LV = nullptr;
1159 G4LogicalVolume* pole2LV = nullptr;
1160 G4VPhysicalVolume* pole1PV = nullptr;
1161 G4VPhysicalVolume* pole2PV = nullptr;
1162 G4VPhysicalVolume* pole3PV = nullptr;
1163 G4VPhysicalVolume* pole4PV = nullptr;
1164 G4VPhysicalVolume* pole5PV = nullptr;
1165 G4VPhysicalVolume* pole6PV = nullptr;
1166 G4VPhysicalVolume* pole7PV = nullptr;
1167 G4VPhysicalVolume* pole8PV = nullptr;
1168
1169 // collar solid - only need one as can union with itself but offset
1170 G4VSolid* collar = nullptr;
1171 G4VSolid* collars = nullptr; // union of two collars
1172 G4LogicalVolume* collarsLV = nullptr;
1173
1174 // materials and visual attributes
1175 G4Material* nbti = BDSMaterials::Instance()->GetMaterial("NbTi.1");
1176 G4Material* stainlesssteel_316LN_2K = BDSMaterials::Instance()->GetMaterial("stainless_steel_316LN_2K");
1177 G4Material* stainlesssteel_304L_2K = BDSMaterials::Instance()->GetMaterial("stainless_steel_304L_2K");
1178
1179 G4VisAttributes* coilVisAtt = new G4VisAttributes(*BDSColours::Instance()->GetColour("LHCcoil"));
1180 coilVisAtt->SetForceLineSegmentsPerCircle((G4int)nSegmentsPerCircle);
1181 G4VisAttributes* collarVisAtt = new G4VisAttributes(*BDSColours::Instance()->GetColour("LHCcollar"));
1182 collarVisAtt->SetForceLineSegmentsPerCircle((G4int)nSegmentsPerCircle);
1183 allVisAttributes.insert(coilVisAtt);
1184 allVisAttributes.insert(collarVisAtt);
1185
1186 if (buildCoil)
1187 {
1188 // coil solid
1189 coil1 = new G4Tubs(name+"_coil1_solid", // name
1190 coilInnerRadius, // inner radius
1191 coilOuterRadius, // outer radius
1192 length*0.5-lengthSafety, // z half length
1193 coilStartAngle, // start angle
1194 coilFullAngle); // sweep angle
1195 // coil logical volumes
1196 coil1LV = new G4LogicalVolume(coil1, // solid
1197 nbti, // material
1198 name+"_coil1_lv"); // name
1199 coil1LV->SetVisAttributes(coilVisAtt);
1200 allSolids.insert(coil1);
1201 allLogicalVolumes.insert(coil1LV);
1202
1203 // pole solid
1204 pole1 = new G4Tubs(name+"_pole1_solid", // name
1205 coilInnerRadius, // inner radius
1206 coilOuterRadius, // outer radius
1207 length*0.5 - lengthSafety, // z half length
1208 poleStartAngle, // start angle
1209 poleFullAngle); // sweep angle
1210 pole1LV = new G4LogicalVolume(pole1, // solid
1211 stainlesssteel_316LN_2K, // material
1212 name+"_pole1_lv"); // name
1213 pole1LV->SetVisAttributes(collarVisAtt);
1214 allSolids.insert(pole1);
1215 allLogicalVolumes.insert(pole1LV);
1216
1217 // coil placements
1218 coil1PV = new G4PVPlacement(nullptr, // rotation
1219 -dipolePosition, // position
1220 coil1LV, // logical volume
1221 name + "_coil1_pv", // name
1222 containerLV, // mother volume
1223 false, // boolean operation
1224 0, // copy number
1226 coil2PV = new G4PVPlacement(coil2rm, // rotation
1227 -dipolePosition, // position
1228 coil1LV, // logical volume
1229 name + "_coil2_pv", // name
1230 containerLV, // mother volume
1231 false, // boolean operation
1232 0, // copy number
1234 coil3PV = new G4PVPlacement(coil3rm, // rotation
1235 -dipolePosition, // position
1236 coil1LV, // logical volume
1237 name + "_coil3_pv", // name
1238 containerLV, // mother volume
1239 false, // boolean operation
1240 0, // copy number
1242 coil4PV = new G4PVPlacement(coil4rm, // rotation
1243 -dipolePosition, // position
1244 coil1LV, // logical volume
1245 name + "_coil4_pv", // name
1246 containerLV, // mother volume
1247 false, // boolean operation
1248 0, // copy number
1250 allPhysicalVolumes.insert(coil1PV);
1251 allPhysicalVolumes.insert(coil2PV);
1252 allPhysicalVolumes.insert(coil3PV);
1253 allPhysicalVolumes.insert(coil4PV);
1254
1255 // pole placements
1256 pole1PV = new G4PVPlacement(nullptr, // rotation
1257 -dipolePosition, // position
1258 pole1LV, // logical volume
1259 name + "_pole1_pv", // name
1260 containerLV, // mother volume
1261 false, // boolean operation
1262 0, // copy number
1264 pole2PV = new G4PVPlacement(coil2rm, // rotation
1265 -dipolePosition, // position
1266 pole1LV, // logical volume
1267 name + "_pole2_pv", // name
1268 containerLV, // mother volume
1269 false, // boolean operation
1270 0, // copy number
1272 pole3PV = new G4PVPlacement(coil3rm, // rotation
1273 -dipolePosition, // position
1274 pole1LV, // logical volume
1275 name + "_pole3_pv", // name
1276 containerLV, // mother volume
1277 false, // boolean operation
1278 0, // copy number
1280 pole4PV = new G4PVPlacement(coil4rm, // rotation
1281 -dipolePosition, // position
1282 pole1LV, // logical volume
1283 name + "_pole4_pv", // name
1284 containerLV, // mother volume
1285 false, // boolean operation
1286 0, // copy number
1288 allPhysicalVolumes.insert(pole1PV);
1289 allPhysicalVolumes.insert(pole2PV);
1290 allPhysicalVolumes.insert(pole3PV);
1291 allPhysicalVolumes.insert(pole4PV);
1292 }
1293
1294 // fixed coil
1295 coil2 = new G4Tubs(name+"_coil2_solid", // name
1296 coilInnerRadiusF, // inner radius
1297 coilOuterRadius, // outer radius
1298 length*0.5-lengthSafety, // length
1299 coilStartAngle, // start angle
1300 coilFullAngle); // sweep angle
1301 coil2LV = new G4LogicalVolume(coil2, // solid
1302 nbti, // material
1303 name+"_coil2_lv"); // name
1304 coil2LV->SetVisAttributes(coilVisAtt);
1305 allSolids.insert(coil2);
1306 allLogicalVolumes.insert(coil2LV);
1307
1308 // fixed pole
1309 pole2 = new G4Tubs(name+"_pole2_solid", // name
1310 coilInnerRadiusF, // inner radius
1311 coilOuterRadius, // outer radius
1312 length*0.5 - lengthSafety, // z half length
1313 poleStartAngle, // start angle
1314 poleFullAngle); // sweep angle
1315 pole2LV = new G4LogicalVolume(pole2, // solid
1316 stainlesssteel_316LN_2K, // material
1317 name+"_pole2_lv"); // name
1318 pole2LV->SetVisAttributes(collarVisAtt);
1319 allSolids.insert(pole2);
1320 allLogicalVolumes.insert(pole2LV);
1321
1322 // fixed coil placements
1323 coil5PV = new G4PVPlacement(nullptr, // rotation
1324 dipolePosition, // position
1325 coil2LV, // logical volume
1326 name + "_coil5_pv", // name
1327 containerLV, // mother volume
1328 false, // boolean operation
1329 0, // copy number
1331 coil6PV = new G4PVPlacement(coil2rm, // rotation
1332 dipolePosition, // position
1333 coil2LV, // logical volume
1334 name + "_coil6_pv", // name
1335 containerLV, // mother volume
1336 false, // boolean operation
1337 0, // copy number
1339 coil7PV = new G4PVPlacement(coil3rm, // rotation
1340 dipolePosition, // position
1341 coil2LV, // logical volume
1342 name + "_coil7_pv", // name
1343 containerLV, // mother volume
1344 false, // boolean operation
1345 0, // copy number
1347 coil8PV = new G4PVPlacement(coil4rm, // rotation
1348 dipolePosition, // position
1349 coil2LV, // logical volume
1350 name + "_coil8_pv", // name
1351 containerLV, // mother volume
1352 false, // boolean operation
1353 0, // copy number
1355 allPhysicalVolumes.insert(coil5PV);
1356 allPhysicalVolumes.insert(coil6PV);
1357 allPhysicalVolumes.insert(coil7PV);
1358 allPhysicalVolumes.insert(coil8PV);
1359
1360 // fixed pole placements
1361 pole5PV = new G4PVPlacement(nullptr, // rotation
1362 dipolePosition, // position
1363 pole2LV, // logical volume
1364 name + "_pole5_pv", // name
1365 containerLV, // mother volume
1366 false, // boolean operation
1367 0, // copy number
1369 pole6PV = new G4PVPlacement(coil2rm, // rotation
1370 dipolePosition, // position
1371 pole2LV, // logical volume
1372 name + "_pole6_pv", // name
1373 containerLV, // mother volume
1374 false, // boolean operation
1375 0, // copy number
1377 pole7PV = new G4PVPlacement(coil3rm, // rotation
1378 dipolePosition, // position
1379 pole2LV, // logical volume
1380 name + "_pole7_pv", // name
1381 containerLV, // mother volume
1382 false, // boolean operation
1383 0, // copy number
1385 pole8PV = new G4PVPlacement(coil4rm, // rotation
1386 dipolePosition, // position
1387 pole2LV, // logical volume
1388 name + "_pole8_pv", // name
1389 containerLV, // mother volume
1390 false, // boolean operation
1391 0, // copy number
1393
1394 allPhysicalVolumes.insert(pole5PV);
1395 allPhysicalVolumes.insert(pole6PV);
1396 allPhysicalVolumes.insert(pole7PV);
1397 allPhysicalVolumes.insert(pole8PV);
1398
1399 // non-magnetic collars
1400 // collar pole solid
1401 collar = new G4Tubs(name+"_collar_solid", // name
1402 collarInnerRadiusF, // inner radius
1403 collarOuterRadius, // outer radius
1404 length*0.5 - lengthSafety, // length
1405 0, // start angle
1406 CLHEP::twopi); // sweep angle
1407 allSolids.insert(collar);
1408 collars = collar;
1409 if (buildCollar)
1410 {
1411 if (collarInnerRadius == collarInnerRadiusF)
1412 {
1413 // can save a solid by doing the union with the existing one if they're the same
1414 collars = new G4UnionSolid(name + "_collars_solid", // name
1415 collar, // solid 1
1416 collar, // solid 2
1417 nullptr, // rotation
1418 -2*dipolePosition); // translation
1419 }
1420 else
1421 {
1422 G4VSolid* collar2 = new G4Tubs(name+"_collar2_solid", // name
1423 collarInnerRadius, // inner radius
1424 collarOuterRadius, // outer radius
1425 length*0.5-lengthSafety, // length
1426 0, // starting angle
1427 CLHEP::twopi); // angle of sweep
1428 allSolids.insert(collar2);
1429 collars = new G4UnionSolid(name + "_collars_solid", // name
1430 collar, // solid 1
1431 collar2, // solid 2
1432 nullptr, // rotation
1433 -2*dipolePosition); // translation
1434 }
1435 allSolids.insert(collars);
1436 }
1437
1438 collarsLV = new G4LogicalVolume(collars,
1439 stainlesssteel_316LN_2K,
1440 name+"_collars_lv");
1441 collarsLV->SetVisAttributes(collarVisAtt);
1442 allLogicalVolumes.insert(collarsLV);
1443
1444 G4PVPlacement* collarPV = new G4PVPlacement(nullptr, // rotation
1445 dipolePosition, // position
1446 collarsLV, // its logical volume
1447 name+"_collars_pv", // its name
1448 containerLV, // its mother volume
1449 false, // no boolean operation
1450 0, // copy number
1452 allPhysicalVolumes.insert(collarPV);
1453
1454 // prepare a solid to cut a hole in the outer yoke volume (can just use one twice)
1455 // can't use the existing collar solids as they're not solid - need them to be solid
1456 G4VSolid* collarSubtractionCylinder = new G4Tubs(name+"_collar_subtraction_solid", // name
1457 0, // inner radius
1458 collarOuterRadius + lengthSafety, // outer radius
1459 length, // double length for unambiguous subtraction
1460 0, // starting angle
1461 CLHEP::twopi); // sweep angle
1462
1463 G4VSolid* collarSubtractionCylinders = new G4UnionSolid(name + "_collar_subtraction_cylinders", // name
1464 collarSubtractionCylinder, // solid1
1465 collarSubtractionCylinder, // solid2 (here = solid1)
1466 nullptr, // rotation
1467 2*dipolePosition); // translation
1468
1469 // outer iron yoke
1470 G4VSolid* yokeCylinder = new G4Tubs(name+"_yoke_cylinder_solid", // name
1471 0., // inner radius
1472 yokeOuterRadius, // outer radius
1473 0.5*length-lengthSafety, // length
1474 0, // starting angle
1475 CLHEP::twopi * CLHEP::rad); // sweep angle
1476
1477 yokeSolid = new G4SubtractionSolid(name+"_yoke_solid", // name
1478 yokeCylinder, // from this
1479 collarSubtractionCylinders, // subtract this
1480 nullptr,
1481 -dipolePosition);
1482 allSolids.insert(collarSubtractionCylinder);
1483 allSolids.insert(collarSubtractionCylinders);
1484 allSolids.insert(yokeCylinder);
1485 yokeLV = new G4LogicalVolume(yokeSolid,
1486 stainlesssteel_304L_2K,
1487 name+"_yoke_lv");
1488
1489 // yoke visualisation
1490 G4VisAttributes* LHCred = new G4VisAttributes(*BDSColours::Instance()->GetColour("LHCyokered"));
1491 LHCred->SetForceLineSegmentsPerCircle((G4int)nSegmentsPerCircle);
1492 allVisAttributes.insert(LHCred);
1493 yokeLV->SetVisAttributes(LHCred);
1494
1495 allLogicalVolumes.insert(yokeLV); // register locally
1496
1497 // yoke placement
1498 yokePV = new G4PVPlacement(nullptr, // no rotation
1499 G4ThreeVector(0,0,0), // position
1500 yokeLV, // lv to be placed
1501 name + "_yoke_pv", // name
1502 containerLV, // mother lv to be placed in
1503 false, // no boolean operation
1504 0, // copy number
1506 allPhysicalVolumes.insert(yokePV);
1507
1508 BDSBeamPipeInfo* defaultModel = BDSGlobalConstants::Instance()->DefaultBeamPipeModel();
1509 G4Material* vacuumMaterial = defaultModel->vacuumMaterial;
1510
1511 //use beampipe factories to create another beampipe (note no magnetic field for now...)
1512 BDSBeamPipe* secondBP = BDSBeamPipeFactory::Instance()->CreateBeamPipe(BDSBeamPipeType::lhcdetailed,
1513 name,
1514 length-2*lengthSafety,
1515 2.202*CLHEP::cm, // aper1
1516 1.714*CLHEP::cm, // aper2
1517 2.202*CLHEP::cm, // aper3
1518 0, // aper4
1519 vacuumMaterial, // vacuum material
1520 1*CLHEP::mm, // beampipeThickness
1521 stainlesssteel_316LN_2K); // beampipe material
1522
1523 G4LogicalVolume* secondBPLV = secondBP->GetContainerLogicalVolume();
1524 G4PVPlacement* secondBPPV = new G4PVPlacement(nullptr, // no rotation
1525 dipolePosition, // position
1526 secondBPLV, // lv to be placed
1527 name + "_second_beampipe_pv", // name
1528 containerLV, // mother lv to be placed in
1529 false, // no boolean operation
1530 0, // copy number
1532 allPhysicalVolumes.insert(secondBPPV);
1533
1534 // visual attributes for container
1535 containerLV->SetVisAttributes(containerVisAttr);
1536 magnetContainerLV->SetVisAttributes(containerVisAttr);
1537
1538 // user limits
1539 for (auto lv : allLogicalVolumes)
1540 {lv->SetUserLimits(defaultUserLimits);}
1541 containerLV->SetUserLimits(defaultUserLimits);
1542 magnetContainerLV->SetUserLimits(defaultUserLimits);
1543
1544 // record extents
1545 // container radius is the same for all methods as all cylindrical
1546 G4double containerRadius = yokeOuterRadius;
1547 // Here the extent is considered without any offset.
1548 BDSExtent ext = BDSExtent(-containerRadius,containerRadius,
1549 -containerRadius,containerRadius,
1550 -length*0.5,length*0.5);
1551
1552 magnetContainer = new BDSGeometryComponent(magnetContainerSolid,
1553 magnetContainerLV, ext, BDSExtent(),
1554 dipolePosition);
1555
1556 // build the BDSMagnetOuter instance and return it
1557 BDSMagnetOuter* outer = new BDSMagnetOuter(containerSolid,
1558 containerLV, ext,
1559 magnetContainer);
1560
1561 SetFaceNormals(outer);
1562
1563 // register objects
1564 outer->RegisterDaughter(secondBP);
1565 outer->RegisterSolid(allSolids);
1566 outer->RegisterLogicalVolume(allLogicalVolumes);
1567 outer->RegisterPhysicalVolume(allPhysicalVolumes);
1568 outer->RegisterVisAttributes(allVisAttributes);
1569 outer->RegisterRotationMatrix(allRotationMatrices);
1570
1571 return outer;
1572}
1573
1575 G4double length,
1576 BDSBeamPipe* beamPipe,
1577 G4double containerLength,
1578 const BDSMagnetOuterInfo* recipe)
1579{
1580 return cylindrical->CreateSextupole(name,length,beamPipe,containerLength,recipe);
1581}
1582
1584 G4double length,
1585 BDSBeamPipe* beamPipe,
1586 G4double containerLength,
1587 const BDSMagnetOuterInfo* recipe)
1588{
1589 return cylindrical->CreateOctupole(name,length,beamPipe,containerLength,recipe);
1590}
1591
1593 G4double length,
1594 BDSBeamPipe* beamPipe,
1595 G4double containerLength,
1596 const BDSMagnetOuterInfo* recipe)
1597{
1598 return cylindrical->CreateDecapole(name,length,beamPipe,containerLength,recipe);
1599}
1600
1602 G4double length,
1603 BDSBeamPipe* beamPipe,
1604 G4double containerLength,
1605 const BDSMagnetOuterInfo* recipe)
1606{
1607 return cylindrical->CreateSolenoid(name,length,beamPipe,containerLength,recipe);
1608}
1609
1611 G4double length,
1612 BDSBeamPipe* beamPipe,
1613 G4double containerLength,
1614 const BDSMagnetOuterInfo* recipe)
1615{
1616 return cylindrical->CreateMultipole(name,length,beamPipe,containerLength,recipe);
1617}
1618
1620 G4double length,
1621 BDSBeamPipe* beamPipe,
1622 G4double containerLength,
1623 const BDSMagnetOuterInfo* recipe)
1624{
1625 return cylindrical->CreateRfCavity(name,length,beamPipe,containerLength,recipe);
1626}
1627
1629 G4double length,
1630 BDSBeamPipe* beamPipe,
1631 G4double containerLength,
1632 const BDSMagnetOuterInfo* recipe)
1633{
1634 return cylindrical->CreateMuonSpoiler(name,length,beamPipe,containerLength,recipe);
1635}
1636
1638 G4double length,
1639 const BDSBeamPipe* beamPipe,
1640 G4double containerLength,
1641 const BDSMagnetOuterInfo* recipe,
1642 G4bool /*vertical*/)
1643{
1644 return CreateLHCDipole(name, length, beamPipe, containerLength, recipe, YokeColour::kicker);
1645}
1646
1649 G4double& horizontalWidth)// reference to a pointer
1650{
1651 // ensure horizontalWidth is > outerCollarDiameter - hard coded as specific to the lhc design
1652 if (horizontalWidth < 202*CLHEP::mm )
1653 {horizontalWidth = 202*CLHEP::mm;}
1654}
static BDSBeamPipeFactory * Instance()
Singleton accessor.
Holder class for all information required to describe a beam pipe model.
G4Material * vacuumMaterial
Public member for direct access.
A holder class for a piece of beam pipe geometry.
Definition: BDSBeamPipe.hh:45
G4VSolid * GetContainerSubtractionSolid() const
default destructor sufficient as G4 manages solids and LVs
Definition: BDSBeamPipe.hh:63
G4double GetContainerRadius() const
If it is circular, we need the radius.
Definition: BDSBeamPipe.hh:70
G4bool ContainerIsCircular() const
Definition: BDSBeamPipe.hh:68
static BDSColours * Instance()
singleton pattern
Definition: BDSColours.cc:33
G4Colour * GetColour(const G4String &type, G4bool normaliseTo255=true)
Get colour from name.
Definition: BDSColours.cc:202
General exception with possible name of object and message.
Definition: BDSException.hh:35
Holder for +- extents in 3 dimensions.
Definition: BDSExtent.hh:39
G4bool checkOverlaps
Cache of global constants variable.
G4double nSegmentsPerCircle
Cache of global constants variable.
G4double lengthSafety
Cache of global constants variable.
G4VisAttributes * containerVisAttr
Cache of global constants variable.
G4double lengthSafetyLarge
Cache of global constants variable.
G4UserLimits * defaultUserLimits
Cache of global constants variable.
A generic geometry component for a bdsim model.
G4LogicalVolume * GetContainerLogicalVolume() const
Accessor - see member for more info.
void RegisterRotationMatrix(G4RotationMatrix *rotationMatrix)
void RegisterDaughter(BDSGeometryComponent *anotherComponent)
void RegisterLogicalVolume(G4LogicalVolume *logicalVolume)
void RegisterPhysicalVolume(G4VPhysicalVolume *physicalVolume)
void RegisterVisAttributes(G4VisAttributes *visAttribute)
void RegisterSolid(G4VSolid *solid)
void RegisterSensitiveVolume(G4LogicalVolume *sensitiveVolume, BDSSDType sensitivityType)
static BDSGlobalConstants * Instance()
Access method.
virtual BDSMagnetOuter * CreateSolenoid(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
solenoid outer volume
virtual void CleanUp()
Empty containers for next use - factories are never deleted so can't rely on scope.
void SetFaceNormals(BDSMagnetOuter *outer)
Copy face normals from members to an instance of outer.
virtual BDSMagnetOuter * CreateDecapole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
decapole outer volume
virtual BDSMagnetOuter * CreateMuonSpoiler(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
muon spoiler outer volume
virtual BDSMagnetOuter * CreateMultipole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
general multipole outer volume - could be any 2N order multipole
G4VSolid * yokeSolid
Solid for outer part that connects all poles.
virtual BDSMagnetOuter * CreateOctupole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
octupole outer volume
virtual BDSMagnetOuter * CreateRfCavity(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
RF cavity outer volume.
virtual BDSMagnetOuter * CreateSextupole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
sextupole outer volume
void BuildMagnetContainerSolidStraight(const G4String &name, G4double magnetContainerLength, G4double magnetContainerRadius)
void BuildMagnetContainerSolidAngled(const G4String &name, G4double magnetContainerLength, G4double magnetContainerRadius, G4bool flatFaces=false)
Factory that produces cylindrical magnet geometry.
virtual BDSMagnetOuter * CreateRfCavity(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
RF cavity outer volume.
virtual BDSMagnetOuter * CreateSectorBend(G4String name, G4double length, const BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
sector bend outer volume
static const G4double beamSeparation
Used in many places - make it a constant in the code and put here as most relevant.
virtual BDSMagnetOuter * CreateSolenoid(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
solenoid outer volume
virtual BDSMagnetOuter * CreateMuonSpoiler(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
muon spoiler outer volume
virtual BDSMagnetOuter * CreateDecapole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
decapole outer volume
YokeColour
Enum up front for yoke colouring.
virtual BDSMagnetOuter * CreateSextupole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
sextupole outer volume
virtual BDSMagnetOuter * CreateQuadrupole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
quadrupole outer volume
BDSMagnetOuterFactoryBase * cylindrical
Default factory to fall back to.
virtual BDSMagnetOuter * CreateOctupole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
octupole outer volume
virtual BDSMagnetOuter * CreateRectangularBend(G4String name, G4double length, const BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
rectangular bend outer volume
virtual BDSMagnetOuter * CreateMultipole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)
general multipole outer volume - could be any 2N order multipole
virtual BDSMagnetOuter * CreateKicker(G4String name, G4double length, const BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe, G4bool vertical)
horizontal and vertical kicker outer volume
BDSMagnetOuter * CreateLHCDipole(const G4String &name, G4double length, const BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe, YokeColour colourIn)
void TestInputParameters(const BDSBeamPipe *beamPipe, G4double &horizontalWidthIn)
test inputs for no null pointers or overlapping volumes due to poorly defined sizes
Holder struct of all information required to create the outer geometry of a magnet.
An object for both the returned magnet outer body but also a tight fitting container for the whole ma...
static BDSMaterials * Instance()
Singleton pattern access.
Definition: BDSMaterials.cc:38
G4Material * GetMaterial(G4String material) const
Get material by name.
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())
G4int CalculateOrientation(G4double angle)
std::pair< G4ThreeVector, G4ThreeVector > CalculateFaces(G4double angleInIn, G4double angleOutIn)
Calculate input and output normal vector.