BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSMagnetOuterFactory.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 "BDSBeamPipe.hh"
20#include "BDSColours.hh"
21#include "BDSDebug.hh"
22#include "BDSException.hh"
23#include "BDSExtent.hh"
24#include "BDSGeometryComponent.hh"
25#include "BDSGeometryExternal.hh"
26#include "BDSGeometryFactory.hh"
27#include "BDSGlobalConstants.hh"
28#include "BDSMagnetOuter.hh"
29#include "BDSMagnetOuterFactory.hh"
30#include "BDSMagnetOuterFactoryBase.hh"
31#include "BDSMagnetOuterFactoryCylindrical.hh"
32#include "BDSMagnetOuterFactoryPolesCircular.hh"
33#include "BDSMagnetOuterFactoryPolesFacet.hh"
34#include "BDSMagnetOuterFactoryPolesFacetCrop.hh"
35#include "BDSMagnetOuterFactoryPolesSquare.hh"
36#include "BDSMagnetOuterFactoryLHCLeft.hh"
37#include "BDSMagnetOuterFactoryLHCRight.hh"
38#include "BDSMagnetOuterFactoryNone.hh"
39#include "BDSMagnetOuterInfo.hh"
40#include "BDSMagnetGeometryType.hh"
41#include "BDSMaterials.hh"
42#include "BDSWarning.hh"
43
44#include "globals.hh" // geant4 globals / types
45#include "G4Box.hh"
46#include "G4CutTubs.hh"
47#include "G4LogicalVolume.hh"
48#include "G4ThreeVector.hh"
49
50#include <algorithm>
51#include <cmath>
52#include <sstream>
53#include <string>
54
56
58{
59 if (!instance)
61 return instance;
62}
63
64BDSMagnetOuterFactory::BDSMagnetOuterFactory()
65{
66 lengthSafetyLarge = BDSGlobalConstants::Instance()->LengthSafetyLarge();
75}
76
77BDSMagnetOuterFactory::~BDSMagnetOuterFactory()
78{
79 delete none;
80 delete cylindrical;
81 delete polescircular;
82 delete polessquare;
83 delete polesfacet;
84 delete polesfacetcrop;
85 delete lhcright;
86 delete lhcleft;
87 instance = nullptr;
88}
89
91{
92 switch (magnetTypeIn.underlying())
93 {
94 case BDSMagnetGeometryType::none:
95 {return none; break;}
96 case BDSMagnetGeometryType::cylindrical:
97 {return cylindrical; break;}
98 case BDSMagnetGeometryType::polescircular:
99 {return polescircular; break;}
100 case BDSMagnetGeometryType::polessquare:
101 {return polessquare; break;}
102 case BDSMagnetGeometryType::polesfacet:
103 {return polesfacet; break;}
104 case BDSMagnetGeometryType::polesfacetcrop:
105 {return polesfacetcrop; break;}
106 case BDSMagnetGeometryType::lhcleft:
107 {return lhcleft; break;}
108 case BDSMagnetGeometryType::lhcright:
109 {return lhcright; break;}
110 case BDSMagnetGeometryType::external:
111 {return nullptr; break;}
112 default:
113 {
114 throw BDSException(__METHOD_NAME__, "unknown type \"" + magnetTypeIn.ToString() + "\"");
115 break;
116 }
117 }
118}
119
121 BDSMagnetOuterInfo* outerInfo,
122 G4double outerLength,
123 G4double containerLength,
124 BDSBeamPipe* beamPipe)
125{
126 BDSMagnetOuter* outer = nullptr;
127
128 G4String name = outerInfo->name;
129 BDSMagnetGeometryType geometryType = outerInfo->geometryType;
130
131 if (geometryType == BDSMagnetGeometryType::external)
132 {
133 outer = CreateExternal(name, outerInfo, outerLength, containerLength, beamPipe);
134 G4double loadedLength = outer->GetExtent().DZ();
135 if (loadedLength > outerLength)
136 {
137 BDS::Warning(__METHOD_NAME__, "External geometry of length " + std::to_string(loadedLength/CLHEP::m)
138 + "m\nappears to be too long for magnet of length " + std::to_string(outerLength/CLHEP::m) + "m. ");
139 }
140 return outer;
141 }
142
143 // Check dimensions
144 CheckOuterBiggerThanBeamPipe(name, outerInfo, beamPipe);
145
146 BDSMagnetOuterFactoryBase* factory = GetAppropriateFactory(geometryType);
147
148 switch(magnetType.underlying())
149 {
150 case BDSMagnetType::decapole:
151 {
152 outer = factory->CreateDecapole(name, outerLength, beamPipe, containerLength, outerInfo);
153 break;
154 }
155 case BDSMagnetType::vkicker:
156 {
157 outer = factory->CreateKicker(name, outerLength, beamPipe, containerLength, outerInfo, true);
158 break;
159 }
160 case BDSMagnetType::hkicker:
161 {
162 outer = factory->CreateKicker(name, outerLength, beamPipe, containerLength, outerInfo, false);
163 break;
164 }
165 case BDSMagnetType::muonspoiler:
166 {
167 outer = factory->CreateMuonSpoiler(name, outerLength, beamPipe, containerLength, outerInfo);
168 break;
169 }
170 case BDSMagnetType::octupole:
171 {
172 outer = factory->CreateOctupole(name, outerLength, beamPipe, containerLength, outerInfo);
173 break;
174 }
175 case BDSMagnetType::quadrupole:
176 {
177 outer = factory->CreateQuadrupole(name, outerLength, beamPipe, containerLength, outerInfo);
178 break;
179 }
180 case BDSMagnetType::rfcavity:
181 {
182 outer = factory->CreateRfCavity(name, outerLength, beamPipe, containerLength, outerInfo);
183 break;
184 }
185 case BDSMagnetType::sectorbend:
186 {
187 outer = factory->CreateSectorBend(name, outerLength, beamPipe,
188 containerLength, outerInfo);
189 break;
190 }
191 case BDSMagnetType::rectangularbend:
192 {
193 outer = factory->CreateRectangularBend(name, outerLength, beamPipe,
194 containerLength, outerInfo);
195 break;
196 }
197 case BDSMagnetType::sextupole:
198 {
199 outer = factory->CreateSextupole(name, outerLength, beamPipe, containerLength, outerInfo);
200 break;
201 }
202 case BDSMagnetType::solenoid:
203 {
204 outer = factory->CreateSolenoid(name, outerLength, beamPipe, containerLength, outerInfo);
205 break;
206 }
207 case BDSMagnetType::multipole:
208 {
209 outer = factory->CreateMultipole(name, outerLength, beamPipe, containerLength, outerInfo);
210 break;
211 }
212 case BDSMagnetType::thinmultipole:
213 case BDSMagnetType::dipolefringe:
214 case BDSMagnetType::undulator:
215 case BDSMagnetType::rmatrix:
216 case BDSMagnetType::paralleltransporter:
217 {break;} // leave as nullptr - no outer geometry for dipole fringe or thin multipole
218 default:
219 G4cout << __METHOD_NAME__ << "unknown magnet type " << magnetType << " - no outer volume built" << G4endl;
220 break;
221 }
222 return outer;
223}
224
226 BDSMagnetOuterInfo* info,
227 G4double /*length*/,
228 G4double magnetContainerLength,
229 BDSBeamPipe* beampipe)
230{
231 std::map<G4String, G4Colour*> defaultMap = {
232 {"coil", BDSColours::Instance()->GetColour("coil")},
233 {"bend", BDSColours::Instance()->GetColour("sectorbend")},
234 {"yoke", BDSColours::Instance()->GetColour("quadrupole")},
235 {"quad", BDSColours::Instance()->GetColour("quadrupole")},
236 {"sext", BDSColours::Instance()->GetColour("sextupole")},
237 {"oct", BDSColours::Instance()->GetColour("octupole")},
238 {"dec", BDSColours::Instance()->GetColour("decapole")}
239 };
241 info->geometryTypeAndPath,
242 &defaultMap,
243 info->autoColour);
244
245 BDSExtent bpExtent = beampipe->GetExtent();
246 BDSExtent magInner = geom->GetInnerExtent();
247
248 if (magInner.TransverselyLessThan(bpExtent))
249 {
250 std::stringstream ss, ss2, ss3;
251 ss << info->geometryTypeAndPath;
252 ss2 << magInner;
253 ss3 << bpExtent;
254 std::string sss = ss.str();
255 sss += " will not fit around beam pipe\nin element \"" + name + "\" and could potentially overlap with it\n";
256 sss += "Determined extents to be:\n";
257 sss += "External geometry inner: " + ss2.str() + "\n";
258 sss += "Beam pipe outer : " + ss3.str() + "\n";
259 sss += "Check for overlaps with /geometry/test/run";
260 BDS::Warning(__METHOD_NAME__, sss);
261 }
262
263 BDSGeometryComponent* container = CreateContainerForExternal(name, magnetContainerLength, geom, beampipe);
264
265 BDSMagnetOuter* outer = new BDSMagnetOuter(geom, container);
266 return outer;
267}
268
270 G4double length,
271 BDSGeometryExternal* external,
272 BDSBeamPipe* beampipe)
273{
274 G4ThreeVector inputFace = beampipe->InputFaceNormal();
275 G4ThreeVector outputFace = beampipe->OutputFaceNormal();
276
277 BDSExtent outer = external->GetExtent();
278 G4VSolid* containerSolid;
279 BDSExtent containerExt;
280 if ((inputFace.z() > -1) || (outputFace.z() < 1))
281 {// use a cut tubs for angled face
282 G4double posR = std::hypot(outer.XPos(),outer.YPos());
283 G4double negR = std::hypot(outer.XNeg(),outer.YNeg());
284 G4double magnetContainerRadius = std::max(posR, negR) + 1*CLHEP::mm; // generous margin
285 containerSolid = new G4CutTubs(name + "_container_solid", // name
286 0, // inner radius
287 magnetContainerRadius, // outer radius
288 length * 0.5, // z half length
289 0, // starting angle
290 CLHEP::twopi, // sweep angle
291 inputFace,
292 outputFace);
293 containerExt = BDSExtent(magnetContainerRadius, magnetContainerRadius, 0.5*length);
294 }
295 else
296 {// flat faces so use a box
297 G4double radius = outer.MaximumAbsTransverse() + 1*CLHEP::mm; // generous margin
298 containerSolid = new G4Box(name + "_container_solid", // name
299 radius,
300 radius,
301 length*0.5);
302 containerExt = BDSExtent(radius, radius, length*0.5);
303 }
304
305 G4Material* worldMaterial = BDSMaterials::Instance()->GetMaterial(BDSGlobalConstants::Instance()->WorldMaterial());
306 G4LogicalVolume* containerLV = new G4LogicalVolume(containerSolid,
307 worldMaterial,
308 name + "_container_lv");
309
310 containerLV->SetVisAttributes(BDSGlobalConstants::Instance()->ContainerVisAttr());
311
312 BDSGeometryComponent* container = new BDSGeometryComponent(containerSolid,
313 containerLV,
314 containerExt);
315
316 return container;
317}
318
319void BDSMagnetOuterFactory::CheckOuterBiggerThanBeamPipe(const G4String& name,
320 const BDSMagnetOuterInfo* outerInfo,
321 const BDSBeamPipe* beamPipe) const
322{
323 G4double outerHorizontal = outerInfo->horizontalWidth;
324 G4double outerVertical = outerInfo->horizontalWidth * outerInfo->vhRatio;
325 BDSExtent bpExtent = beamPipe->GetExtent();
326 // 1x lsl between beam pipe and magnet container
327 // 1x lsl between magnet container and yoke
328 // 1x lsl for minimum yoke width -> takes us to minimum horizontalWidth required
329 G4double margin = 3*lengthSafetyLarge;
330 if (outerHorizontal < bpExtent.DX()+margin || outerVertical < bpExtent.DY()+margin)
331 {
332 std::string msg = "Magnet outer dimensions too small to encompass beam pipe for element " + name + "\n";
333 msg += "magnet horizontal full width -> " + std::to_string(outerHorizontal) + "mm\n";
334 msg += "magnet vertical full width -> " + std::to_string(outerVertical) + "mm\n";
335 msg += "Beam pipe width (mm): " + std::to_string(bpExtent.DX()) + ", height : ";
336 msg += std::to_string(bpExtent.DY());
337 throw BDSException(__METHOD_NAME__, msg);
338 }
339}
A holder class for a piece of beam pipe geometry.
Definition: BDSBeamPipe.hh:45
G4ThreeVector InputFaceNormal() const
Accessor.
Definition: BDSBeamPipe.hh:73
G4ThreeVector OutputFaceNormal() const
Accessor.
Definition: BDSBeamPipe.hh:74
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
G4double XPos() const
Accessor.
Definition: BDSExtent.hh:66
G4double MaximumAbsTransverse() const
Return the maximum absolute value considering only x,y.
Definition: BDSExtent.cc:171
G4double XNeg() const
Accessor.
Definition: BDSExtent.hh:65
G4double DZ() const
The difference in a dimension.
Definition: BDSExtent.hh:85
G4double YNeg() const
Accessor.
Definition: BDSExtent.hh:67
G4double DX() const
The difference in a dimension.
Definition: BDSExtent.hh:83
G4double DY() const
The difference in a dimension.
Definition: BDSExtent.hh:84
G4bool TransverselyLessThan(const BDSExtent &r) const
Comparison operator for x,y only. Ignores z (length).
Definition: BDSExtent.hh:191
G4double YPos() const
Accessor.
Definition: BDSExtent.hh:68
A generic geometry component for a bdsim model.
BDSExtent GetExtent() const
Accessor - see member for more info.
BDSExtent GetInnerExtent() const
Accessor - see member for more info.
A loaded piece of externally provided geometry.
static BDSGeometryFactory * Instance()
Singleton accessor.
BDSGeometryExternal * BuildGeometry(G4String componentName, const G4String &formatAndFilePath, std::map< G4String, G4Colour * > *colourMapping=nullptr, G4bool autoColour=true, G4double suggestedLength=0, G4double suggestedHorizontalWidth=0, std::vector< G4String > *namedVacuumVolumes=nullptr, G4bool makeSensitive=true, BDSSDType sensitivityType=BDSSDType::energydep, G4bool stripOuterVolumeAndMakeAssembly=false, G4UserLimits *userLimitsToAttachToAllLVs=nullptr, G4bool dontReloadGeometry=false)
static BDSGlobalConstants * Instance()
Access method.
Abstract base class for magnet outer volume factories.
virtual BDSMagnetOuter * CreateQuadrupole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
quadrupole outer volume
virtual BDSMagnetOuter * CreateSolenoid(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
solenoid outer volume
virtual BDSMagnetOuter * CreateKicker(G4String name, G4double length, const BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe, G4bool vertical)=0
horizontal and vertical kicker outer volume
virtual BDSMagnetOuter * CreateRectangularBend(G4String name, G4double length, const BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
rectangular bend outer volume
virtual BDSMagnetOuter * CreateDecapole(G4String name, G4double length, BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
decapole outer volume
virtual BDSMagnetOuter * CreateSectorBend(G4String name, G4double length, const BDSBeamPipe *beamPipe, G4double containerLength, const BDSMagnetOuterInfo *recipe)=0
sector bend 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
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
Factory that produces cylindrical magnet geometry.
LHC outer magnet geometry offset to the left.
LHC outer magnet geometry offset to the right.
Factory that produces null outer geometry.
Factory class for outer volume of magnets. Produces magnets with 2N-poles around the beampipe with a ...
Factory class for outer volume of magnets.
Factory class for outer volume of magnets.
Factory class for outer volume of magnets.
The main interface for using the magnet outer factories.
static BDSMagnetOuterFactory * Instance()
Singleton accessor.
BDSMagnetOuterFactoryBase * lhcleft
Factory instance.
BDSMagnetOuterFactoryBase * polesfacetcrop
Factory instance.
BDSMagnetOuterFactoryBase * lhcright
Factory instance.
static BDSMagnetOuterFactory * instance
Singleton instance.
BDSGeometryComponent * CreateContainerForExternal(const G4String &name, G4double length, BDSGeometryExternal *external, BDSBeamPipe *beampipe)
BDSMagnetOuter * CreateExternal(const G4String &name, BDSMagnetOuterInfo *info, G4double length, G4double magnetContainerLength, BDSBeamPipe *beampipe)
BDSMagnetOuterFactoryBase * cylindrical
Factory instance.
BDSMagnetOuterFactoryBase * polessquare
Factory instance.
BDSMagnetOuter * CreateMagnetOuter(BDSMagnetType magnetType, BDSMagnetOuterInfo *outerInfo, G4double outerLength, G4double chordLength, BDSBeamPipe *beampipe)
BDSMagnetOuterFactoryBase * polescircular
Factory instance.
BDSMagnetOuterFactoryBase * GetAppropriateFactory(BDSMagnetGeometryType magnetTypeIn)
Get the appropriate derived factory for the required magnet style.
BDSMagnetOuterFactoryBase * none
Factory instance.
BDSMagnetOuterFactoryBase * polesfacet
Factory instance.
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.
type underlying() const
return underlying value (can be used in switch statement)