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