BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSMagnet.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 "BDSBeamPipe.hh"
19#include "BDSBeamPipeFactory.hh"
20#include "BDSBeamPipeInfo.hh"
21#include "BDSBeamPipeType.hh"
22#include "BDSFieldBuilder.hh"
23#include "BDSFieldInfo.hh"
24#include "BDSIntegratorType.hh"
25#include "BDSMagnetGeometryType.hh"
26#include "BDSMagnetOuter.hh"
27#include "BDSMagnetOuterInfo.hh"
28#include "BDSMagnetOuterFactory.hh"
29#include "BDSMagnetOuterFactoryLHC.hh"
30#include "BDSMagnetStrength.hh"
31#include "BDSMagnetType.hh"
32#include "BDSMagnet.hh"
33#include "BDSUtilities.hh"
34
35#include "G4Box.hh"
36#include "G4LogicalVolume.hh"
37#include "G4Material.hh"
38#include "G4PVPlacement.hh"
39#include "G4String.hh"
40#include "G4ThreeVector.hh"
41#include "G4Transform3D.hh"
42#include "G4Types.hh"
43#include "G4VPhysicalVolume.hh"
44
45#include "CLHEP/Units/SystemOfUnits.h"
46
47class G4Userlimits;
48
50 const G4String& nameIn,
51 G4double lengthIn,
52 BDSBeamPipeInfo* beamPipeInfoIn,
53 BDSMagnetOuterInfo* magnetOuterInfoIn,
54 BDSFieldInfo* vacuumFieldInfoIn,
55 G4double angleIn,
56 BDSFieldInfo* outerFieldInfoIn,
57 G4bool isThinIn):
58 BDSAcceleratorComponent(nameIn, lengthIn, angleIn, typeIn.ToString(), beamPipeInfoIn),
59 magnetType(typeIn),
60 magnetOuterInfo(magnetOuterInfoIn),
61 vacuumFieldInfo(vacuumFieldInfoIn),
62 outerFieldInfo(outerFieldInfoIn),
63 beampipe(nullptr),
64 placeBeamPipe(false),
65 magnetOuterOffset(G4ThreeVector(0,0,0)),
66 outer(nullptr),
67 beamPipePlacementTransform(G4Transform3D()),
68 isThin(isThinIn)
69{
70 magnetOuterInfo->name += "_outer";
71 horizontalWidth = magnetOuterInfoIn->horizontalWidth;
73
74 beampipe = nullptr;
75 outer = nullptr;
76
77 placeBeamPipe = false;
78
79 // It's not possible to build advanced outer geometry for a very thin magnet.
80 if (lengthIn < 1e-4*CLHEP::m) // 100um minimum length for geometry
81 {magnetOuterInfo->geometryType = BDSMagnetGeometryType::none;}
82 // No beam pipe geometry for really short 'magnets'
83 if (lengthIn < 1e-6*CLHEP::m)
84 {
85 GetBeamPipeInfo()->beamPipeType = BDSBeamPipeType::circularvacuum;
86 isThin = true;
87 }
88}
89
91{
92 G4String result = "none";
93 switch (typeIn.underlying())
94 {
95 case BDSMagnetType::hkicker:
96 case BDSMagnetType::vkicker:
97 case BDSMagnetType::muonspoiler:
98 case BDSMagnetType::sectorbend:
99 case BDSMagnetType::rectangularbend:
100 {result = "field"; break;}
101 case BDSMagnetType::quadrupole:
102 {result = "k1"; break;}
103 case BDSMagnetType::sextupole:
104 {result = "k2"; break;}
105 case BDSMagnetType::octupole:
106 {result = "k3"; break;}
107 case BDSMagnetType::decapole:
108 {result = "k4"; break;}
109 default:
110 {break;} // leave as none without complaint
111 };
112
113 return result;
114}
115
116void BDSMagnet::SetInputFaceNormal(const G4ThreeVector& input)
117{
118 if (outer)
119 {outer->SetInputFaceNormal(input);}
120}
121
122void BDSMagnet::SetOutputFaceNormal(const G4ThreeVector& output)
123{
124 if (outer)
125 {outer->SetOutputFaceNormal(output);}
126}
127
128G4String BDSMagnet::Material() const
129{
130 if (magnetOuterInfo)
131 {return magnetOuterInfo->outerMaterial->GetName();}
132 else
134}
135
137{
141 BuildOuter();
142 // Instead of BDSAcceleratorComponent::Build just call BuildContainerLogicalVolume
143 // to control user limits in the case where there is no container and we just inherit
144 // the beam pipe container
146 BuildOuterField(); // must be done when the containerLV exists
147 PlaceComponents(); // place things (if needed) in container
148}
149
167
169{
170 if (vacuumFieldInfo)
171 {
172 if (beamPipePlacementTransform != G4Transform3D::Identity)
173 {
174 G4Transform3D newFieldTransform = vacuumFieldInfo->Transform() * beamPipePlacementTransform;
175 vacuumFieldInfo->SetTransform(newFieldTransform);
176 }
177 // can use containerLV for field as we don't construct any geometry with thin elements.
178 if (isThin)
179 {
182 true);
183 }
184 else
185 {
188 true);
189 }
190 }
191}
192
194{
195 G4double outerLength = chordLength - 2*lengthSafety;
196 // The outerFieldInfo is required only so we don't reuse geometry when we need a unique field on it.
199 outerLength,
201 beampipe);
202
203 if (outer)
204 {
205 // copy necessary bits out of BDSGeometryComponent that holds
206 // container information for whole magnet object provided by
207 // magnet outer factory.
209 containerSolid = container->GetContainerSolid()->Clone();
210 G4ThreeVector contOffset = container->GetPlacementOffset();
211 // set the main offset of the whole magnet which is placed w.r.t. the
212 // zero coordinate of the container solid
213 SetPlacementOffset(contOffset);
214
216 InheritExtents(container, contOffset); // update extents
217
218 // Only clear after extents etc have been used
220
221 endPieceBefore = outer->EndPieceBefore();
222 endPieceAfter = outer->EndPieceAfter();
223
227 }
228}
229
231{
232 if (outer && outerFieldInfo)
233 {
234 // determine key for this specific magnet instance
235 G4String scalingKey = DetermineScalingKey(magnetType);
236
237 BDSMagnetStrength* scalingStrength = vacuumFieldInfo ? vacuumFieldInfo->MagnetStrength() : nullptr;
238 G4LogicalVolume* vol = outer->GetContainerLogicalVolume();
240 vol,
241 true,
242 scalingStrength,
243 scalingKey);
244 // Attach to the container but don't propagate to daughter volumes. This ensures
245 // any gap between the beam pipe and the outer also has a field.
247 containerLogicalVolume,
248 false,
249 scalingStrength,
250 scalingKey);
251
252 // in the case of LHC-style geometry, override the second beam pipe (which is a daughter of the outer)
253 // field to be the opposite sign of the main vacuum field (same strength)
254 auto mgt = magnetOuterInfo->geometryType;
255 if (mgt == BDSMagnetGeometryType::lhcleft || mgt == BDSMagnetGeometryType::lhcright)
256 {
257 std::set<BDSGeometryComponent*> daughtersSet = outer->GetAllDaughters();
258 std::vector<BDSGeometryComponent*> daughters(daughtersSet.begin(), daughtersSet.end());
259 if (daughters.size() == 1 && vacuumFieldInfo)
260 {
261 BDSFieldInfo* secondBPField = new BDSFieldInfo(*vacuumFieldInfo);
262 G4double sign = mgt == BDSMagnetGeometryType::lhcleft ? 1.0 : -1.0;
263 secondBPField->Translate(G4ThreeVector(sign * BDSMagnetOuterFactoryLHC::beamSeparation, 0, 0));
264
265 if (magnetType != BDSMagnetType::quadrupole)
266 {
267 (*(secondBPField->MagnetStrength()))["field"] *= -1; // flip the sign
268 if (BDS::IsFinite((*(secondBPField->MagnetStrength()))["k1"]))
269 {(*(secondBPField->MagnetStrength()))["k1"] *= -1;}
270 }
271
272 secondBPField->SetIntegratorType(BDSIntegratorType::g4classicalrk4);
274 daughters[0]->GetContainerLogicalVolume(),
275 true);
276 }
277 }
278 }
279}
280
282{
283 // note beam pipe is not optional!
284 if (outer)
285 {//build around that
286 // container solid will have been updated in BuildOuter if the outer exists
287 containerLogicalVolume = new G4LogicalVolume(containerSolid,
289 name + "_container_lv");
290
291 // user limits - provided by BDSAcceleratorComponent
292 containerLogicalVolume->SetUserLimits(userLimits);
293 containerLogicalVolume->SetVisAttributes(containerVisAttr);
294
295 placeBeamPipe = true;
296 }
297 else
298 {
299 // use beam pipe container volume as ours and no need to place beam pipe
300 containerSolid = beampipe->GetContainerSolid();
301 containerLogicalVolume = beampipe->GetContainerLogicalVolume();
303 placeBeamPipe = false;
304 }
305}
306
308{
309 if (placeBeamPipe)
310 {
311 G4ThreeVector beamPipeOffset = -1*GetPlacementOffset();
312 // place beampipe
313 G4PVPlacement* beamPipePV = new G4PVPlacement(nullptr, // rotation
314 beamPipeOffset, // position in container
315 beampipe->GetContainerLogicalVolume(), // its logical volume
316 name + "_beampipe_pv", // its name
317 containerLogicalVolume, // its mother volume
318 false, // no boolean operation
319 0, // copy number
321
322 RegisterPhysicalVolume(beamPipePV);
323 }
324
325 if (outer)
326 {
327 //G4ThreeVector placementOffset = magnetOuterOffset + outer->GetPlacementOffset();
328 G4ThreeVector outerOffset = outer->GetPlacementOffset();
329
330 // place outer volume
331 G4PVPlacement* magnetOuterPV = new G4PVPlacement(nullptr, // rotation
332 outerOffset, // at normally (0,0,0)
333 outer->GetContainerLogicalVolume(), // its logical volume
334 name+"_outer_pv", // its name
335 containerLogicalVolume, // its mother volume
336 false, // no boolean operation
337 0, // copy number
339
340 RegisterPhysicalVolume(magnetOuterPV);
341 }
342}
343
345{
346 delete outerFieldInfo;
347 outerFieldInfo = outerFieldInfoIn;
348}
349
350void BDSMagnet::SetVacuumField(BDSFieldInfo* vacuumFieldInfoIn)
351{
352 delete vacuumFieldInfo;
353 vacuumFieldInfo = vacuumFieldInfoIn;
354}
355
356BDSMagnet::~BDSMagnet()
357{
358 delete magnetOuterInfo;
359 delete vacuumFieldInfo;
360 delete outerFieldInfo;
361}
362
364{
366 if (vacuumFieldInfo)
367 {vacuumFieldInfo->SetUsePlacementWorldTransform(true);}
368 if (outerFieldInfo)
369 {outerFieldInfo->SetUsePlacementWorldTransform(true);}
370}
Abstract class that represents a component of an accelerator.
G4UserLimits * userLimits
Cache of user limits.
virtual G4String Material() const
Return the name of a material associated with the component - ie the primary material.
void SetAcceleratorVacuumLogicalVolume(G4LogicalVolume *accVacLVIn)
const G4String name
Const protected member variable that may not be changed by derived classes.
static G4Material * emptyMaterial
Useful variable often used in construction.
static G4double lengthSafety
Useful variable often used in construction.
static G4bool checkOverlaps
Useful variable often used in construction.
G4double angle
Protected member variable that can be modified by derived classes.
BDSBeamPipeInfo * GetBeamPipeInfo() const
G4double chordLength
Protected member variable that can be modified by derived classes.
static G4VisAttributes * containerVisAttr
Useful variable often used in construction.
BDSBeamPipeInfo * beamPipeInfo
Optional beam pipe recipe that is written out to the survey if it exists.
virtual void SetFieldUsePlacementWorldTransform()
static BDSBeamPipeFactory * Instance()
Singleton accessor.
Holder class for all information required to describe a beam pipe model.
BDSBeamPipeType beamPipeType
Public member for direct access.
G4LogicalVolume * GetVacuumLogicalVolume() const
Access the vacuum volume to set fields and limits.
G4ThreeVector InputFaceNormal() const
Accessor.
G4ThreeVector OutputFaceNormal() const
Accessor.
std::set< G4LogicalVolume * > GetVolumesForField() const
void RegisterFieldForConstruction(const BDSFieldInfo *info, G4LogicalVolume *logicalVolume, const G4bool propagateToDaughters=false, const BDSMagnetStrength *magnetStrengthForScaling=nullptr, const G4String &scalingKey="none")
static BDSFieldBuilder * Instance()
Singleton pattern accessor.
All info required to build complete field of any type.
void SetTransform(const G4Transform3D &transformIn)
Set the field definition transform.
G4Transform3D Transform() const
Transform for the field definition only.
void Translate(const G4ThreeVector &translationIn)
BDSMagnetStrength * MagnetStrength() const
Accessor.
A generic geometry component for a bdsim model.
virtual std::set< BDSGeometryComponent * > GetAllDaughters() const
Accessor - see member for more info.
G4LogicalVolume * GetContainerLogicalVolume() const
Accessor - see member for more info.
void InheritExtents(BDSGeometryComponent const *const anotherComponent)
Update the extents of this object with those of another object.
G4Transform3D GetPlacementTransform() const
Accessor - see member for more info.
void SetPlacementOffset(const G4ThreeVector &offsetIn)
Set the offset from 0,0,0 that the object should ideally be placed in its parent.
void RegisterDaughter(BDSGeometryComponent *anotherComponent)
void RegisterPhysicalVolume(G4VPhysicalVolume *physicalVolume)
G4VSolid * GetContainerSolid() const
Accessor - see member for more info.
G4ThreeVector GetPlacementOffset() const
Accessor - see member for more info.
static const G4double beamSeparation
Used in many places - make it a constant in the code and put here as most relevant.
static BDSMagnetOuterFactory * Instance()
Singleton accessor.
BDSMagnetOuter * CreateMagnetOuter(BDSMagnetType magnetType, BDSMagnetOuterInfo *outerInfo, G4double outerLength, G4double chordLength, BDSBeamPipe *beampipe)
Holder struct of all information required to create the outer geometry of a magnet.
BDSGeometryComponent * GetMagnetContainer() const
void ClearMagnetContainer()
Clear the memory of the now unneeded magnet container object.
void SetInputFaceNormal(const G4ThreeVector &input)
Setter for face normals.
G4ThreeVector InputFaceNormal() const
Accessor.
BDSSimpleComponent * EndPieceAfter() const
Access the end piece.
G4ThreeVector OutputFaceNormal() const
Accessor.
void SetOutputFaceNormal(const G4ThreeVector &output)
Setter for face normals.
BDSSimpleComponent * EndPieceBefore() const
Access the end piece.
Efficient storage of magnet strengths.
virtual void SetOutputFaceNormal(const G4ThreeVector &output)
Update face normal and also to beam pipe and magnet outer.
Definition BDSMagnet.cc:122
G4Transform3D beamPipePlacementTransform
Definition BDSMagnet.hh:161
BDSFieldInfo * vacuumFieldInfo
Field information for vacuum field.
Definition BDSMagnet.hh:131
G4bool isThin
Boolean to store if the element is thin - will have no geometry constructed.
Definition BDSMagnet.hh:164
G4double horizontalWidth
For outer volume construction.
Definition BDSMagnet.hh:145
BDSMagnetType magnetType
Magnet type.
Definition BDSMagnet.hh:125
BDSMagnetOuterInfo * magnetOuterInfo
Model information for the outer volume construction.
Definition BDSMagnet.hh:128
virtual void SetFieldUsePlacementWorldTransform()
Override function as we have different field recipe objects.
Definition BDSMagnet.cc:363
BDSBeamPipe * beampipe
The constructed beampipe.
Definition BDSMagnet.hh:137
virtual void BuildBeampipe()
Definition BDSMagnet.cc:150
virtual void BuildVacuumField()
Construct the field for the vacuum and attach it.
Definition BDSMagnet.cc:168
G4bool placeBeamPipe
Definition BDSMagnet.hh:142
virtual void BuildContainerLogicalVolume()
Definition BDSMagnet.cc:281
BDSFieldInfo * outerFieldInfo
Field information for outer magnetic field (optional)
Definition BDSMagnet.hh:134
BDSMagnet()=delete
Private default constructor to force the use of the supplied one.
virtual void Build()
Definition BDSMagnet.cc:136
BDSMagnetOuter * outer
The assembled outer magnet geometry.
Definition BDSMagnet.hh:157
virtual G4String Material() const
Accessor to outer material if it exists.
Definition BDSMagnet.cc:128
virtual void BuildOuter()
Definition BDSMagnet.cc:193
static G4String DetermineScalingKey(BDSMagnetType typeIn)
Definition BDSMagnet.cc:90
void SetOuterField(BDSFieldInfo *outerFieldInfoIn)
@ { Delete existing field info and replace.
Definition BDSMagnet.cc:344
virtual void SetInputFaceNormal(const G4ThreeVector &input)
Update face normal and also to beam pipe and magnet outer.
Definition BDSMagnet.cc:116
virtual void BuildOuterField()
Construct the magnetic field for the outer magnet geometry.
Definition BDSMagnet.cc:230
G4double containerRadius
Definition BDSMagnet.hh:149
virtual void PlaceComponents()
Definition BDSMagnet.cc:307
type underlying() const
return underlying value (can be used in switch statement)
G4ThreeVector RotateToReferenceFrame(G4ThreeVector faceNormal, G4double fullAngle)
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())