BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSCollimatorJaw.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2023.
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 "BDSAcceleratorModel.hh"
20#include "BDSCollimatorJaw.hh"
21#include "BDSBeamPipeInfo.hh"
22#include "BDSColours.hh"
23#include "BDSDebug.hh"
24#include "BDSException.hh"
25#include "BDSMaterials.hh"
26#include "BDSSDType.hh"
27#include "BDSUtilities.hh"
28
29#include "G4Box.hh"
30#include "G4Para.hh"
31#include "G4GenericTrap.hh"
32#include "G4LogicalVolume.hh"
33#include "G4PVPlacement.hh"
34#include "G4VisAttributes.hh"
35
36#include <cmath>
37#include <vector>
38#include <map>
39#include <set>
40
41BDSCollimatorJaw::BDSCollimatorJaw(const G4String& nameIn,
42 G4double lengthIn,
43 G4double horizontalWidthIn,
44 G4double xHalfGapIn,
45 G4double yHalfHeightIn,
46 G4double xSizeLeftIn,
47 G4double xSizeRightIn,
48 G4double leftJawTiltIn,
49 G4double rightJawTiltIn,
50 G4bool buildLeftJawIn,
51 G4bool buildRightJawIn,
52 G4Material* collimatorMaterialIn,
53 G4Material* vacuumMaterialIn,
54 G4Colour* colourIn):
55BDSCollimator(nameIn, lengthIn, horizontalWidthIn, "jcol", collimatorMaterialIn, vacuumMaterialIn,
56 xHalfGapIn, yHalfHeightIn, xHalfGapIn, yHalfHeightIn, colourIn),
57 jawSolid(nullptr),
58 xSizeLeft(xSizeLeftIn),
59 xSizeRight(xSizeRightIn),
60 xHalfGap(xHalfGapIn),
61 jawTiltLeft(leftJawTiltIn),
62 jawTiltRight(rightJawTiltIn),
63 jawHalfWidth(0),
64 yHalfHeight(yHalfHeightIn),
65 buildLeftJaw(buildLeftJawIn),
66 buildRightJaw(buildRightJawIn),
67 buildAperture(true)
68{
69 jawHalfWidth = 0.5 * (0.5*horizontalWidth - lengthSafetyLarge - xHalfGap);
70}
71
72BDSCollimatorJaw::~BDSCollimatorJaw()
73{;}
74
76{
77 // BDSCollimator::CheckParameters() <- we replace this and don't call it - 'tapered' is never set
78 if (!colour)
79 {colour = BDSColours::Instance()->GetColour("collimator");}
80
81 if (jawHalfWidth < 1e-3) // 1um minimum, could also be negative
82 {throw BDSException(__METHOD_NAME__, "horizontalWidth insufficient given xsize of jcol \"" + name + "\"");}
83
84 // set half height to half horizontal width if zero - finite height required.
87
88 if (BDS::IsFinite(yHalfHeight) && (yHalfHeight < 1e-3)) // 1um minimum
89 {throw BDSException(__METHOD_NAME__, "insufficient ysize for jcol \"" + name + "\"");}
90
91 if ((yHalfHeight < 0) || ((yHalfHeight > 0) && (yHalfHeight < 1e-3))) // 1um minimum and not negative
92 {throw BDSException(__METHOD_NAME__, "insufficient ysize for jcol \"" + name + "\"");}
93
94 if (xSizeLeft < 0)
95 {throw BDSException(__METHOD_NAME__, "left jcol jaw cannot have negative half aperture size: \"" + name + "\"");}
96 if (xSizeRight < 0)
97 {throw BDSException(__METHOD_NAME__, "left jcol jaw cannot have negative half aperture size: \"" + name + "\"");}
98
99 if (std::abs(xSizeLeft) > 0.5*horizontalWidth)
100 {
101 G4cerr << __METHOD_NAME__ << "jcol \"" << name
102 << "\" left jaw offset is greater the element half width, jaw "
103 << "will not be constructed" << G4endl;
104 buildLeftJaw = false;
105 }
106 if (std::abs(xSizeRight) > 0.5*horizontalWidth)
107 {
108 G4cerr << __METHOD_NAME__ << "jcol \"" << name
109 << "\" right jaw offset is greater the element half width, jaw "
110 << "will not be constructed" << G4endl;
111 buildRightJaw = false;
112 }
113
114 if (std::abs(jawTiltLeft) > 0 && std::tan(std::abs(jawTiltLeft)) * chordLength / 2. > std::max(xHalfGap, xSizeLeft))
115 {throw BDSException(__METHOD_NAME__, "tilted left jaw not allowed to cross the mid-plane: \"" + name + "\"");}
116
117 if (std::abs(jawTiltRight) > 0 && std::tan(std::abs(jawTiltRight)) * chordLength / 2. > std::max(xHalfGap, xSizeLeft))
118 {throw BDSException(__METHOD_NAME__, "tilted right jaw not allowed to cross the mid-plane: \"" + name + "\"");}
119
121 {throw BDSException(__METHOD_NAME__, "no jaws being built: \"" + name + "\"");}
122
124 {buildAperture = false;}
125}
126
128{
129 G4double horizontalHalfWidth = horizontalWidth * 0.5;
130 if (jawTiltLeft != 0 || jawTiltRight != 0)
131 {
132 // The box must encompass everything, so pick the largest absolute angle
133 horizontalHalfWidth = horizontalWidth * 0.5 + chordLength * 0.5 * std::sin(std::max(std::abs(jawTiltLeft), std::abs(jawTiltRight)));
134 }
135
136 // For the case of jaw tilt, adjust the horizontal size, but keep the container length the same
137 // This results in small drifts either side of the collimator, but preserves the overall size
138 containerSolid = new G4Box(name + "_container_solid",
139 horizontalHalfWidth,
141 chordLength*0.5);
142
143 containerLogicalVolume = new G4LogicalVolume(containerSolid,
145 name + "_container_lv");
146 BDSExtent ext(horizontalHalfWidth, yHalfHeight, chordLength*0.5);
147 SetExtent(ext);
148}
149
151{
153 BDSAcceleratorComponent::Build(); // calls BuildContainer and sets limits and vis for container
154
155 // set each jaws half gap default to aperture half size
156 G4double leftJawHalfGap = xHalfGap;
157 G4double rightJawHalfGap = xHalfGap;
158
159 // update jaw half gap with offsets
160 // if one jaw is not constructed, set the opening to xSize/2 for the aperture vacuum volume creation
162 {
163 if (buildLeftJaw)
164 {leftJawHalfGap = xSizeLeft;}
165 else
166 {leftJawHalfGap = 0.5 * horizontalWidth;}
167 }
168
170 {
171 if (buildRightJaw)
172 {rightJawHalfGap = xSizeRight;}
173 else
174 {rightJawHalfGap = 0.5 * horizontalWidth;}
175 }
176
177 // jaws have to fit inside containerLogicalVolume so calculate full jaw widths given offsets
178 G4double leftJawWidth = 0.5 * horizontalWidth - leftJawHalfGap;
179 G4double rightJawWidth = 0.5 * horizontalWidth - rightJawHalfGap;
180 G4double vacuumWidth = 0.5 * (leftJawHalfGap + rightJawHalfGap);
181
182 // centre of jaw and vacuum volumes for placements
183 G4double leftJawCentre = 0.5*leftJawWidth + leftJawHalfGap;
184 G4double rightJawCentre = 0.5*rightJawWidth + rightJawHalfGap;
185 G4double vacuumCentre = 0.5*(leftJawHalfGap - rightJawHalfGap);
186
187 G4ThreeVector leftJawPos = G4ThreeVector(leftJawCentre, 0, 0);
188 G4ThreeVector rightJawPos = G4ThreeVector(-rightJawCentre, 0, 0);
189 G4ThreeVector vacuumOffset = G4ThreeVector(vacuumCentre, 0, 0);
190
191 G4VisAttributes* collimatorVisAttr = new G4VisAttributes(*colour);
192 RegisterVisAttributes(collimatorVisAttr);
193
194 // get appropriate user limits for jaw material
195 G4UserLimits* collUserLimits = CollimatorUserLimits();
196
197 // build jaws as appropriate
199 {
200 G4VSolid* leftJawSolid = nullptr;
201
202 if (jawTiltLeft != 0)
203 {
204 // Adjust the length of the parallelepiped to match the inside edges in Z
205 // Due to the straight parallelepiped edges, it will never match the volume an angled box,
206 // so it is chosen to underestimate the volume, but preserve the jaw x-y cutting plane.
207 G4double leftHalfLength = chordLength * 0.5 * std::cos(jawTiltLeft);
208
209 leftJawSolid = new G4Para(name + "_leftjaw_solid",
210 leftJawWidth * 0.5 - lengthSafety,
212 leftHalfLength - lengthSafety,
213 0,
215 0);
216 }
217 else
218 {
219 leftJawSolid = new G4Box(name + "_leftjaw_solid",
220 leftJawWidth * 0.5 - lengthSafety,
222 chordLength * 0.5 - lengthSafety);
223 }
224
225 RegisterSolid(leftJawSolid);
226
227 G4LogicalVolume* leftJawLV = new G4LogicalVolume(leftJawSolid, // solid
228 collimatorMaterial, // material
229 name + "_leftjaw_lv"); // name
230 leftJawLV->SetVisAttributes(collimatorVisAttr);
231
232 // user limits - provided by BDSAcceleratorComponent
233 leftJawLV->SetUserLimits(collUserLimits);
234
235 // register with base class (BDSGeometryComponent)
236 RegisterLogicalVolume(leftJawLV);
237 // register it in a set of collimator logical volumes
238 BDSAcceleratorModel::Instance()->VolumeSet("collimators")->insert(leftJawLV);
239 if (sensitiveOuter)
240 {RegisterSensitiveVolume(leftJawLV, BDSSDType::collimatorcomplete);}
241
242 // place the jaw
243 G4PVPlacement* leftJawPV = new G4PVPlacement(nullptr, // rotation
244 leftJawPos, // position
245 leftJawLV, // its logical volume
246 name + "_leftjaw_pv", // its name
247 containerLogicalVolume, // its mother volume
248 false, // no boolean operation
249 0, // copy number
251 RegisterPhysicalVolume(leftJawPV);
252 }
254 {
255 G4VSolid* rightJawSolid = nullptr;
256
257 if (jawTiltRight != 0)
258 {
259 // Adjust the length of the parallelepiped to match the inside edges in Z
260 // Due to the straight parallelepiped edges, it will never match the volume an angled box,
261 // so it is chosen to underestimate the volume, but preserve the jaw x-y cutting plane.
262 G4double rightHalfLength = chordLength * 0.5 * std::cos(jawTiltRight);
263
264 rightJawSolid = new G4Para(name + "_rightjaw_solid",
265 rightJawWidth * 0.5 - lengthSafety,
267 rightHalfLength - lengthSafety,
268 0,
270 0);
271 }
272 else
273 {
274 rightJawSolid = new G4Box(name + "_rightjaw_solid",
275 rightJawWidth * 0.5 - lengthSafety,
277 chordLength * 0.5 - lengthSafety);
278 }
279
280 RegisterSolid(rightJawSolid);
281
282 G4LogicalVolume* rightJawLV = new G4LogicalVolume(rightJawSolid, // solid
283 collimatorMaterial, // material
284 name + "_rightjaw_lv"); // name
285 rightJawLV->SetVisAttributes(collimatorVisAttr);
286
287 // user limits - provided by BDSAcceleratorComponent
288 rightJawLV->SetUserLimits(collUserLimits);
289
290 // register with base class (BDSGeometryComponent)
291 RegisterLogicalVolume(rightJawLV);
292 // register it in a set of collimator logical volumes
293 BDSAcceleratorModel::Instance()->VolumeSet("collimators")->insert(rightJawLV);
294 if (sensitiveOuter)
295 {RegisterSensitiveVolume(rightJawLV, BDSSDType::collimatorcomplete);}
296
297 // place the jaw
298 G4PVPlacement* rightJawPV = new G4PVPlacement(nullptr, // rotation
299 rightJawPos, // position
300 rightJawLV, // its logical volume
301 name + "_rightjaw_pv", // its name
302 containerLogicalVolume, // its mother volume
303 false, // no boolean operation
304 0, // copy number
306 RegisterPhysicalVolume(rightJawPV);
307 }
308 // if no aperture but the code has got to this stage, build the collimator as a simple box.
309 if (!buildAperture)
310 {
311 collimatorSolid = new G4Box(name + "_solid",
314 chordLength * 0.5 - lengthSafety);
316
317 G4LogicalVolume* collimatorLV = new G4LogicalVolume(collimatorSolid, // solid
318 collimatorMaterial, // material
319 name + "_lv"); // name
320 collimatorLV->SetVisAttributes(collimatorVisAttr);
321
322 // user limits - provided by BDSAcceleratorComponent - don't use collUserLimits
323 collimatorLV->SetUserLimits(userLimits);
324
325 // register with base class (BDSGeometryComponent)
326 RegisterLogicalVolume(collimatorLV);
327 if (sensitiveOuter)
328 {RegisterSensitiveVolume(collimatorLV, BDSSDType::collimatorcomplete);}
329
330 // place the jaw
331 G4PVPlacement* collimatorPV = new G4PVPlacement(nullptr, // rotation
332 (G4ThreeVector) 0, // position
333 collimatorLV, // its logical volume
334 name + "_pv", // its name
335 containerLogicalVolume, // its mother volume
336 false, // no boolean operation
337 0, // copy number
339 RegisterPhysicalVolume(collimatorPV);
340 }
341
342 // build and place the vacuum volume only if the aperture is finite.
343 if (buildAperture)
344 {
345 if (jawTiltLeft != 0 || jawTiltRight != 0)
346 {
348 G4double tiltLeft = buildLeftJaw ? jawTiltLeft : 0.;
349 G4double tiltRight = buildRightJaw ? jawTiltRight : 0.;
350
353 G4double halfLengthLeftEff = (chordLength * 0.5) / std::cos(tiltLeft);
354 G4double halfLengthRightEff = (chordLength * 0.5) / std::cos(tiltRight);
355
358 G4double xGapLeftUpstream = -halfLengthLeftEff * std::sin(tiltLeft) + leftJawHalfGap;
359 G4double xGapLeftDownstream = halfLengthLeftEff * std::sin(tiltLeft) + leftJawHalfGap;
360 G4double xGapRightUpstream = -halfLengthRightEff * std::sin(tiltRight) - rightJawHalfGap;
361 G4double xGapRightDownstream = halfLengthRightEff * std::sin(tiltRight) - rightJawHalfGap;
362
363 std::vector<G4TwoVector> vertices {G4TwoVector(xGapRightUpstream + lengthSafety, -(yHalfHeight - lengthSafety)),
364 G4TwoVector(xGapRightUpstream + lengthSafety, (yHalfHeight - lengthSafety)),
365 G4TwoVector(xGapLeftUpstream - lengthSafety, (yHalfHeight - lengthSafety)),
366 G4TwoVector(xGapLeftUpstream - lengthSafety, -(yHalfHeight - lengthSafety)),
367 G4TwoVector(xGapRightDownstream + lengthSafety, -(yHalfHeight - lengthSafety)),
368 G4TwoVector(xGapRightDownstream + lengthSafety, (yHalfHeight - lengthSafety)),
369 G4TwoVector(xGapLeftDownstream - lengthSafety, (yHalfHeight - lengthSafety)),
370 G4TwoVector(xGapLeftDownstream - lengthSafety, -(yHalfHeight - lengthSafety))};
371
372 vacuumSolid = new G4GenericTrap(name + "_vacuum_solid",
374 vertices);
375 // The for tilted jaws, the vacuum trapezoid is constructed from absolute coordinates
376 // need to rese the vacuum offset, which is intended for a box
377 vacuumOffset = G4ThreeVector(0, 0, 0);
378 }
379 else
380 {
381 vacuumSolid = new G4Box(name + "_vacuum_solid", // name
382 vacuumWidth - lengthSafety, // x half width
383 yHalfHeight - lengthSafety, // y half width
384 chordLength * 0.5); // z half length
385 }
386
388
389 G4LogicalVolume* vacuumLV = new G4LogicalVolume(vacuumSolid, // solid
390 vacuumMaterial, // material
391 name + "_vacuum_lv"); // name
392
393 vacuumLV->SetVisAttributes(containerVisAttr);
394 // user limits - provided by BDSAcceleratorComponent
395 vacuumLV->SetUserLimits(userLimits);
397 RegisterLogicalVolume(vacuumLV);
398 if (sensitiveVacuum)
399 {RegisterSensitiveVolume(vacuumLV, BDSSDType::energydepvacuum);}
400
401 G4PVPlacement* vacPV = new G4PVPlacement(nullptr, // rotation
402 vacuumOffset, // position
403 vacuumLV, // its logical volume
404 name + "_vacuum_pv", // its name
405 containerLogicalVolume, // its mother volume
406 false, // no boolean operation
407 0, // copy number
410 }
411}
G4UserLimits * userLimits
Cache of user limits.
void SetAcceleratorVacuumLogicalVolume(G4LogicalVolume *accVacLVIn)
const G4String name
Const protected member variable that may not be changed by derived classes.
static G4bool sensitiveOuter
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 chordLength
Protected member variable that can be modified by derived classes.
static G4VisAttributes * containerVisAttr
Useful variable often used in construction.
static G4bool sensitiveVacuum
Useful variable often used in construction.
std::set< G4LogicalVolume * > * VolumeSet(const G4String &name)
Returns pointer to a set of logical volumes. If no set by that name exits, create it.
G4double jawHalfWidth
Half width of each jaw.
G4bool buildAperture
Build aperture or not.
virtual void Build() override
Override function in BDSCollimator for totally different construction.
G4double xSizeRight
Offset of jaw 2.
virtual void BuildContainerLogicalVolume() override
Override function in BDSCollimator for different size based container.
G4double xSizeLeft
Offset of jaw 1.
G4double jawTiltLeft
Tilt of jaw 1 (angle in x-z plane)
G4double jawTiltRight
Tilt of jaw 2 (angle in x-z plane)
G4double yHalfHeight
Half height of each jaw.
G4bool buildRightJaw
Build right jaw or not.
virtual void CheckParameters() override
G4double xHalfGap
Half gap separation between jaws.
G4bool buildLeftJaw
Build left jaw or not.
BDSCollimatorJaw()=delete
Private default constructor to force the use of the supplied one.
Base class for collimators with common construction.
G4UserLimits * CollimatorUserLimits()
Return either default user limits or custom ones based on optional minimumKineticEnergy.
G4Material * vacuumMaterial
Vacuum material.
G4double horizontalWidth
Horizontal width.
G4VSolid * vacuumSolid
Geometrical objects:
G4Material * collimatorMaterial
Material.
G4VSolid * collimatorSolid
Geometrical objects:
G4Colour * colour
Colour of collimator.
static BDSColours * Instance()
singleton pattern
Definition: BDSColours.cc:33
G4Colour * GetColour(const G4String &type, G4bool normaliseTo255=true)
Get colour from name.
Definition: BDSColours.cc:204
General exception with possible name of object and message.
Definition: BDSException.hh:35
Holder for +- extents in 3 dimensions.
Definition: BDSExtent.hh:39
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)
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())