BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSUndulator.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 "BDSAcceleratorComponent.hh"
19#include "BDSBeamPipe.hh"
20#include "BDSBeamPipeFactory.hh"
21#include "BDSBeamPipeInfo.hh"
22#include "BDSColours.hh"
23#include "BDSDebug.hh"
24#include "BDSException.hh"
25#include "BDSFieldBuilder.hh"
26#include "BDSFieldInfo.hh"
27#include "BDSGlobalConstants.hh"
28#include "BDSMaterials.hh"
29#include "BDSSDType.hh"
30#include "BDSUndulator.hh"
31#include "BDSUtilities.hh"
32#include "BDSWarning.hh"
33
34#include "globals.hh" // geant4 globals / types
35#include "G4Box.hh"
36#include "G4PVPlacement.hh"
37#include "G4VisAttributes.hh"
38
39#include <cmath>
40
41BDSUndulator::BDSUndulator(const G4String& nameIn,
42 G4double lengthIn,
43 G4double periodIn,
44 G4double undulatorMagnetHeightIn,
45 G4double horizontalWidthIn,
46 G4double undulatorGapIn,
47 BDSBeamPipeInfo* beamPipeInfoIn,
48 BDSFieldInfo* vacuumFieldInfoIn,
49 BDSFieldInfo* outerFieldInfoIn,
50 G4Material* materialIn):
51 BDSAcceleratorComponent(nameIn, lengthIn, 0, "undulator", beamPipeInfoIn),
52 vacuumFieldInfo(vacuumFieldInfoIn),
53 outerFieldInfo(outerFieldInfoIn),
54 undulatorPeriod(periodIn),
55 horizontalWidth(horizontalWidthIn),
56 undulatorMagnetHeight(undulatorMagnetHeightIn),
57 undulatorGap(undulatorGapIn),
58 numMagnets(0),
59 material(materialIn)
60{
61 if (vacuumFieldInfo)
62 {vacuumFieldInfo->SetBeamPipeRadius(beamPipeInfoIn->IndicativeRadius());}
63}
64
65BDSUndulator::~BDSUndulator()
66{;}
67
69{
70 // input Checks
72 if (!BDS::IsFinite(undulatorPeriod))
73 {throw BDSException(__METHOD_NAME__, "undulator period is 0, period must be finite.");}
74
75 // check if the undulator period is an integer factor of the element length
76 if (BDS::IsFinite(std::fmod(chordLength, undulatorPeriod)))
77 {throw BDSException(__METHOD_NAME__, "undulator length \"arcLength\" does not divide into an integer number of\n undulator periods (length \"undulatorPeriod\".");}
78
79 // can now cast num magnets to integer as above check should catch if it isn't an integer.
80 numMagnets = (G4int)(2*chordLength/undulatorPeriod);
81
82 G4double beampipeThickness = BDSGlobalConstants::Instance()->DefaultBeamPipeModel()->beamPipeThickness;
84 {
85 G4cout << __METHOD_NAME__ << "\"undulatorGap\" = 0 -> using 2x beam pipe height." << G4endl;
86 undulatorGap = 2*(bp.DY() + 2*beampipeThickness);
87 }
88 if (undulatorGap < (bp.DY() + 2*beampipeThickness + lengthSafetyLarge))
89 {throw BDSException(__METHOD_NAME__, "\"undulatorGap\" for element: \"" + name + "\" smaller than beam pipe aperture.");}
90
92 {throw BDSException(__METHOD_NAME__, "\"undulatorGap\" for element: \"" + name + "\" larger than horizontalWidth.");}
93
95 {
96 // update single magnet box height in case of undulator gap change.
98 }
100 {throw BDSException(__METHOD_NAME__, "\"undulatorMagnetHeight\" larger than 0.5*horizontalWidth in component " + name);}
102 {
103 throw BDSException(__METHOD_NAME__, "Total undulator height (2*undulatorMagnetHeight + undulatorGap) is larger than horizontalWidth in component " + name);
104 }
105
106 G4double halfWidth = 0.5 * (horizontalWidth + lengthSafetyLarge);
107 containerSolid = new G4Box(name + "_container_solid",
108 halfWidth,
109 halfWidth,
110 chordLength*0.5);
111
112 containerLogicalVolume = new G4LogicalVolume(containerSolid,
114 name + "_container_lv");
115
116 BDSExtent ext = BDSExtent(2 * halfWidth, 2 * halfWidth, chordLength);
117 SetExtent(ext);
118}
119
121{
123
125 BDSBeamPipe* pipe = factory->CreateBeamPipe(name, chordLength, beamPipeInfo);
126 RegisterDaughter(pipe);
127
128 G4double singleMagnetLength = (undulatorPeriod * 0.5) - lengthSafetyLarge;
129
130 // magnet geometry
131 G4Box* magnet = new G4Box(name + "_single_magnet_solid",
134 0.5*singleMagnetLength);
135 RegisterSolid(magnet);
136
137 G4LogicalVolume* lowerBoxLV = new G4LogicalVolume(magnet,
138 material,
139 name + "_lower_box_lv");
140
141 G4LogicalVolume* upperBoxLV = new G4LogicalVolume(magnet,
142 material,
143 name + "_upper_box_lv");
144 RegisterLogicalVolume(lowerBoxLV);
145 RegisterLogicalVolume(upperBoxLV);
146 if (sensitiveOuter)
147 {
148 RegisterSensitiveVolume(lowerBoxLV, BDSSDType::energydep);
149 RegisterSensitiveVolume(upperBoxLV, BDSSDType::energydep);
150 }
151
152 // colour
153 G4VisAttributes* lowerBoxcolour = new G4VisAttributes(*BDSColours::Instance()->GetColour("quadrupole"));
154 lowerBoxLV->SetVisAttributes(lowerBoxcolour);
155 RegisterVisAttributes(lowerBoxcolour);
156
157 G4VisAttributes* upperBoxcolour = new G4VisAttributes(*BDSColours::Instance()->GetColour("sectorbend"));
158 upperBoxLV->SetVisAttributes(upperBoxcolour);
159 RegisterVisAttributes(upperBoxcolour);
160
161 G4double verticalOffset = 0.5 * (undulatorGap + undulatorMagnetHeight);
162 // place upper and lower magnets in a loop
163 for (G4int i = 1; i <= numMagnets; i++)
164 {
165 G4bool sign = BDS::IsFinite(std::fmod(i, 2));
166 G4LogicalVolume* uVol = sign ? upperBoxLV : lowerBoxLV;
167 G4LogicalVolume* lVol = !sign ? upperBoxLV : lowerBoxLV;
168
169 G4ThreeVector upperBoxPos(0, verticalOffset, (0.5*chordLength - undulatorPeriod/4.0) - ((i-1) *undulatorPeriod/2.0));
170 G4ThreeVector lowerBoxPos(0, -verticalOffset, (0.5*chordLength - undulatorPeriod/4.0) - ((i-1) *undulatorPeriod/2.0));
171
172 G4PVPlacement* upperBoxPV = new G4PVPlacement(nullptr, // rotation
173 upperBoxPos, // position
174 uVol, // logical volume
175 name + "_upper_pos_" + std::to_string(i) + "_pv", // name
176 containerLogicalVolume, // mother volume
177 false, // no boolean operation
178 i, // copy number
180
181 G4PVPlacement* lowerBoxPV= new G4PVPlacement(nullptr,
182 lowerBoxPos,
183 lVol,
184 name + "_lower_pos_" + std::to_string(i) + "_pv",
185 containerLogicalVolume,
186 false,
187 i,
189 RegisterPhysicalVolume(upperBoxPV);
190 RegisterPhysicalVolume(lowerBoxPV);
191 }
192
193 // place beam pipe volume
197 G4PVPlacement* bpPV = new G4PVPlacement(nullptr,
198 G4ThreeVector(),
200 name+"_beampipe_pv",
201 containerLogicalVolume,
202 false,
203 0,
206
209 true);
210
211 if (outerFieldInfo)
212 {
213 // Attach to the container but don't propagate to daughter volumes. This ensures
214 // any gap between the beam pipe and the outer also has a field.
216 containerLogicalVolume,
217 false,
218 vacuumFieldInfo->MagnetStrength(),
219 "field");
220 }
221}
Abstract class that represents a component of an accelerator.
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 G4bool sensitiveOuter
Useful variable often used in construction.
virtual void SetOutputFaceNormal(const G4ThreeVector &output)
Allow updating of face normals. Virtual so derived class may apply it to daughters.
static G4bool checkOverlaps
Useful variable often used in construction.
virtual void SetInputFaceNormal(const G4ThreeVector &input)
Allow updating of face normals. Virtual so derived class may apply it to daughters.
G4double chordLength
Protected member variable that can be modified by derived classes.
BDSBeamPipeInfo * beamPipeInfo
Optional beam pipe recipe that is written out to the survey if it exists.
The main interface for using the beam pipe factories.
static BDSBeamPipeFactory * Instance()
Singleton accessor.
Holder class for all information required to describe a beam pipe model.
BDSExtent Extent() const
G4double beamPipeThickness
Public member for direct access.
G4double IndicativeRadius() const
Return an indicative extent of the beam pipe - typically the maximum of x or y extent.
A holder class for a piece of beam pipe geometry.
G4LogicalVolume * GetVacuumLogicalVolume() const
Access the vacuum volume to set fields and limits.
G4ThreeVector InputFaceNormal() const
Accessor.
G4ThreeVector OutputFaceNormal() const
Accessor.
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
G4double DY() const
The difference in a dimension.
Definition BDSExtent.hh:83
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.
BDSMagnetStrength * MagnetStrength() const
Accessor.
G4LogicalVolume * GetContainerLogicalVolume() const
Accessor - see member for more info.
void RegisterDaughter(BDSGeometryComponent *anotherComponent)
void RegisterLogicalVolume(G4LogicalVolume *logicalVolume)
void RegisterPhysicalVolume(G4VPhysicalVolume *physicalVolume)
void SetExtent(const BDSExtent &extIn)
Set extent.
void RegisterVisAttributes(G4VisAttributes *visAttribute)
void RegisterSolid(G4VSolid *solid)
void RegisterSensitiveVolume(G4LogicalVolume *sensitiveVolume, BDSSDType sensitivityType)
static BDSGlobalConstants * Instance()
Access method.
G4double undulatorGap
Full undulator gap.
const G4double horizontalWidth
Element width (and height)
G4double undulatorMagnetHeight
Full magnet box height.
G4int numMagnets
Total number of magnets (1 undulator period is 2 magnets)
G4Material * material
Undulator magnet material.
virtual void BuildContainerLogicalVolume()
virtual void Build()
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())