BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
BDSMagnetOuterFactoryPolesSquare.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 "BDSExtent.hh"
20#include "BDSGlobalConstants.hh"
21#include "BDSMagnetOuter.hh"
22#include "BDSMagnetOuterFactoryPolesSquare.hh"
23#include "BDSMaterials.hh"
24#include "BDSSDType.hh"
25
26#include "globals.hh"
27#include "G4Box.hh"
28#include "G4Colour.hh"
29#include "G4IntersectionSolid.hh"
30#include "G4LogicalVolume.hh"
31#include "G4Material.hh"
32#include "G4PVPlacement.hh"
33#include "G4SubtractionSolid.hh"
34#include "G4Tubs.hh"
35#include "G4VisAttributes.hh"
36#include "G4VSolid.hh"
37
38#include <map>
39#include <set>
40#include <vector>
41
42BDSMagnetOuterFactoryPolesSquare::BDSMagnetOuterFactoryPolesSquare():
43 BDSMagnetOuterFactoryPolesBase(/*poleStopFactor=*/1.5)
44{
45 CleanUp();
46}
47
49{
52}
53
55{
56 poleRotations.clear();
57 poleSolids.clear();
58 poleLVs.clear();
59 order = 0;
60}
61
63 G4double length,
64 G4int /*order*/,
65 G4double magnetContainerLength,
66 G4double magnetContainerRadiusIn)
67{
68 // square yoke - have to do subtraction between two solid boxes
69 G4VSolid* yokeOuter = new G4Box(name + "_yoke_outer_solid", // name
70 yokeFinishRadius, // x half width
71 yokeFinishRadius, // y half width
72 length*0.5 - lengthSafety); // z half length
73
74 G4VSolid* yokeInner = new G4Box(name + "_yoke_inner_solid", // name
75 yokeStartRadius, // x half width
76 yokeStartRadius, // y half width
77 length); // z half length
78 // inner length is 2x as long for unambiguous subtraction
79 allSolids.insert(yokeOuter);
80 allSolids.insert(yokeInner);
81
82 yokeSolid = new G4SubtractionSolid(name + "_yoke_solid", // name
83 yokeOuter,
84 yokeInner);
85
86 // note container must have hole in it for the beampipe to fit in!
87 // poled geometry doesn't fit tightly to beampipe so can alays use a circular aperture
88
89 G4VSolid* containerOuter = new G4Box(name + "_container_outer_solid", // name
90 yokeFinishRadius, // x half width
91 yokeFinishRadius, // y half width
92 length*0.5); // x half width
93
94 G4VSolid* containerInner = new G4Tubs(name + "_container_inner_solid", // name
95 0, // inner radius
96 poleStartRadius, // finish radius
97 length, // z half length
98 0, // start angle
99 CLHEP::twopi); // sweep angle
100 // length of inner is long for unambiguous subtraction
101 allSolids.insert(containerOuter);
102 allSolids.insert(containerInner);
103
104 // pole intersection solid
105 G4double croppingBoxRadius = yokeStartRadius - lengthSafety;
106 poleIntersectionSolid = new G4Box(name + "_pole_intersection_solid", // name
107 croppingBoxRadius, // x half width
108 croppingBoxRadius, // y half width
109 length); // z length
110 allSolids.insert(poleIntersectionSolid);
111 // z length long for unambiguous intersection
112
113 containerSolid = new G4SubtractionSolid(name + "_outer_container_solid", // name
114 containerOuter,
115 containerInner);
116
117 magnetContainerSolid = new G4Box(name + "_container_solid", // name
118 magnetContainerRadiusIn, // x half length
119 magnetContainerRadiusIn, // y half length
120 magnetContainerLength*0.5);// z half length
121
122 magContExtent = BDSExtent(magnetContainerRadiusIn, magnetContainerRadiusIn, magnetContainerLength*0.5);
123}
124
126 G4double /*length*/,
127 G4int orderIn)
128{
129 order = orderIn; // copy to member variable - this is the first function to be called with order
130
131 G4int nPoles = 2*orderIn;
132 segmentAngle = CLHEP::twopi/nPoles; // angle per pole
133 // create different poles to fit inside square yoke
134 for (G4int i = 0; i < nPoles; ++i)
135 {
136 G4RotationMatrix* iPoleRM = new G4RotationMatrix();
137 G4double rotationAngle = (0.5-i)*segmentAngle + CLHEP::pi*0.5;
138 iPoleRM->rotateZ(rotationAngle);
139 allRotationMatrices.insert(iPoleRM);
140 // crop the singlepolesolid with the cropping box so it'll fit inside the outer square yoke
141 G4IntersectionSolid* aSolid = new G4IntersectionSolid(name + "_pole_solid", // name
142 poleSolid, // solid 1 - the pole
143 poleIntersectionSolid,// solid 2 - the one to be shifted
144 iPoleRM, // rotation matrix
145 G4ThreeVector()); // translation vector
146
147 poleSolids.push_back(aSolid);
148 }
149}
150
152 G4Colour* colour,
153 G4Material* outerMaterial)
154{
155 G4VisAttributes* outerVisAttr = new G4VisAttributes(*colour);
156 outerVisAttr->SetVisibility(true);
157 outerVisAttr->SetForceLineSegmentsPerCircle(nSegmentsPerCircle);
158 allVisAttributes.insert(outerVisAttr);
159
160 for (G4int n = 0; n < 2*order; ++n)
161 {
162 G4LogicalVolume* thisPole = new G4LogicalVolume(poleSolids[n],
163 outerMaterial,
164 name + "_pole_lv");
165 thisPole->SetVisAttributes(outerVisAttr);
166 poleLVs.push_back(thisPole);
167 allLogicalVolumes.insert(thisPole);
168 }
169
170 // yoke
171 yokeLV = new G4LogicalVolume(yokeSolid,
172 outerMaterial,
173 name + "_yoke_lv");
174 yokeLV->SetVisAttributes(outerVisAttr);
175
176 // container
177 G4Material* worldMaterial = BDSMaterials::Instance()->GetMaterial(BDSGlobalConstants::Instance()->WorldMaterial());
178 containerLV = new G4LogicalVolume(containerSolid,
179 worldMaterial,
180 name + "_container_lv");
181 containerLV->SetVisAttributes(containerVisAttr);
182
183 magnetContainerLV = new G4LogicalVolume(magnetContainerSolid,
184 worldMaterial,
185 name + "_container_lv");
186 magnetContainerLV->SetVisAttributes(containerVisAttr);
187
188 // user limits
189 yokeLV->SetUserLimits(defaultUserLimits);
190 containerLV->SetUserLimits(defaultUserLimits);
191 magnetContainerLV->SetUserLimits(defaultUserLimits);
192 for (auto& lv : poleLVs)
193 {lv->SetUserLimits(defaultUserLimits);}
194 for (auto& lv : allLogicalVolumes)
195 {lv->SetUserLimits(defaultUserLimits);}
196
197 // create logical volumes for the coils using base class method
199}
200
202 G4int orderIn)
203{
204 // PLACEMENT
205 // place the components inside the container
206 // note we don't need the pointer for placements - it's registered upon construction with g4
207 yokePV = new G4PVPlacement(nullptr, // no rotation
208 G4ThreeVector(), // position
209 yokeLV, // lv to be placed
210 name + "_yoke_pv", // name
211 containerLV, // mother lv to be placed in
212 false, // no boolean operation
213 0, // copy number
214 checkOverlaps); // whether to check overlaps
215
216 // place poles
217 if (!buildPole)
218 {return;}
219 G4double nPoles = 2*orderIn;
220 segmentAngle = CLHEP::twopi/nPoles; // angle per pole
221 G4PVPlacement* aPlacement = nullptr;
222 for (G4int n = 0; n < 2*orderIn; ++n)
223 {
224 G4RotationMatrix* rm = new G4RotationMatrix();
225 G4double rotationAngle = (0.5-n)*segmentAngle + CLHEP::pi*0.5;
226 rm->rotateZ(-rotationAngle);
227 allRotationMatrices.insert(rm);
228 G4String pvName = name + "_pole_" + std::to_string(n) + "_pv";
229 // only need to test the end of one iterator as both should be the same length
230 aPlacement = new G4PVPlacement(rm, // rotation
231 G4ThreeVector(), // position
232 poleLVs[n], // logical volume
233 pvName, // name
234 containerLV, // mother lv to be placed in
235 false, // no boolean operation
236 n, // copy number
237 checkOverlaps); // check overlaps
238 allPhysicalVolumes.insert(aPlacement);
239 }
240}
241
243 G4double length,
244 BDSBeamPipe* beamPipe,
245 G4int orderIn,
246 G4double magnetContainerRadiusIn,
247 const BDSMagnetOuterInfo* recipe)
248{
250 orderIn, magnetContainerRadiusIn, recipe);
251
252 std::set<G4LogicalVolume*> tempLVs(poleLVs.begin(), poleLVs.end());
253 outer->RegisterLogicalVolume(tempLVs);
254 if (sensitiveOuter)
255 {outer->RegisterSensitiveVolume(tempLVs, BDSSDType::energydep);}
256
257 return outer;
258}
259
A holder class for a piece of beam pipe geometry.
Definition: BDSBeamPipe.hh:45
Holder for +- extents in 3 dimensions.
Definition: BDSExtent.hh:39
G4bool checkOverlaps
Cache of global constants variable.
G4double nSegmentsPerCircle
Cache of global constants variable.
G4double lengthSafety
Cache of global constants variable.
G4VisAttributes * containerVisAttr
Cache of global constants variable.
G4UserLimits * defaultUserLimits
Cache of global constants variable.
void RegisterLogicalVolume(G4LogicalVolume *logicalVolume)
void RegisterSensitiveVolume(G4LogicalVolume *sensitiveVolume, BDSSDType sensitivityType)
static BDSGlobalConstants * Instance()
Access method.
G4VSolid * poleSolid
Solid for an individual pole that will be placed multiple times.
G4bool sensitiveOuter
Cache of global constants variable.
G4VSolid * yokeSolid
Solid for outer part that connects all poles.
Factory class for outer volume of magnets. Produces magnets with 2N-poles around the beampipe with a ...
G4double yokeFinishRadius
Finish radius of yoke geometry from magnet centre - less than horizontalWidth.
G4double segmentAngle
2PI / # of poles - angle per segment allocated for each pole.
G4VSolid * poleIntersectionSolid
Solid used to chop off pole.
virtual void CleanUp()
Empty containers for next use - this class is never deleted so can't rely on scope.
virtual void CreateLogicalVolumesCoil(const G4String &name)
G4double poleStartRadius
Start radius of the pole from magnet centre.
G4bool buildPole
Whether or not to build poles (and therefore coils).
G4double yokeStartRadius
Start radius of yoke geometry from magnet cetnre.
virtual BDSMagnetOuter * CommonConstructor(const G4String &name, G4double length, BDSBeamPipe *beamPipe, G4int order, G4double magnetContainerLength, const BDSMagnetOuterInfo *recipe)
Common construction tasks to all methods - assemble yoke and poles in container.
void CleanUpPolesSquare()
Clean up for this factory. Non-virtual as used in constructor.
virtual void IntersectPoleWithYoke(const G4String &name, G4double length, G4int orderIn)
Chop off the top of the pole to match the appropriate yoke geometry.
virtual BDSMagnetOuter * CommonConstructor(const G4String &name, G4double length, BDSBeamPipe *beamPipe, G4int order, G4double magnetContainerLength, const BDSMagnetOuterInfo *recipe)
virtual void CreateLogicalVolumes(const G4String &name, G4Colour *colour, G4Material *outerMaterial)
std::vector< G4RotationMatrix * > poleRotations
virtual void PlaceComponents(const G4String &name, G4int order)
Place the poles and yoke in the container volume.
virtual void CreateYokeAndContainerSolid(const G4String &name, G4double length, G4int order, G4double magnetContainerLength, G4double magnetContainerRadiusIn)
Create yoke that connects poles and container to put them in.
virtual void CleanUp()
Clean up all memebers used.
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.