BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSBeamlineEndPieceBuilder.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 "BDSBeamline.hh"
20#include "BDSBeamlineEndPieceBuilder.hh"
21#include "BDSBeamlineElement.hh"
22#include "BDSExtent.hh"
23#include "BDSGlobalConstants.hh"
24#include "BDSSimpleComponent.hh"
25#include "BDSTiltOffset.hh"
26#include "BDSUtilities.hh"
27
28#include "globals.hh" // geant4 types / globals
29#include "G4ThreeVector.hh"
30
32 const G4bool circularMachine)
33{
34 const G4double lengthSafetyLarge = BDSGlobalConstants::Instance()->LengthSafetyLarge();
35
36 // the beamline of end pieces to be placed.
37 BDSBeamline* endPieces = new BDSBeamline();
38 if (beamline->empty())
39 {return endPieces;}
40
41 // references to first and last item for checking
42 const BDSBeamlineElement* firstItem = beamline->GetFirstItem();
43 const BDSBeamlineElement* lastItem = beamline->GetLastItem();
44
45 // loop over main beamline
46 G4int currentIndex = 0;
47 for (auto element : *beamline)
48 {
49 const auto accComponent = element->GetAcceleratorComponent();
50 const auto accComponentTO = element->GetTiltOffset();
51 const auto endPieceBefore = accComponent->EndPieceBefore();
52 const auto endPieceAfter = accComponent->EndPieceAfter();
53
54 G4bool placeBefore = true;
55 G4bool placeAfter = true;
56 if (!endPieceBefore && !endPieceAfter)
57 {// no end piece on either side - skip this element
58 currentIndex++;
59 continue;
60 }
61 else if (!endPieceBefore)
62 {placeBefore = false;}
63 else if (!endPieceAfter)
64 {placeAfter = false;}
65
66 G4double requiredBeforeLength = 0; // required length for previous end piece
67 G4double requiredAfterLength = 0; // required length for next end piece
68 if (endPieceBefore)
69 {requiredBeforeLength = endPieceBefore->GetChordLength() + 2*lengthSafetyLarge;}
70 if (endPieceAfter)
71 {requiredAfterLength = endPieceAfter->GetChordLength() + 2*lengthSafetyLarge;}
72
73 if (placeBefore)
74 {
75 // search behind current element until we hit a previous component that's not a drift.
76 // ie work out the amount of drift space available. If we hit a previous element, check
77 // if it has an end piece and take that length out of the available space. if there's then
78 // available space for this end piece we place it.
79 G4bool keepGoing = true;
80 const BDSBeamlineElement* inspectedElement = element; // start with current element
81 G4double availableLength = 0;
82 G4double previousNonDriftEndPieceL = 0;
83 G4bool driftIsFirstItem = false;
84 BDSExtent endPieceInnerExtent = endPieceBefore->GetInnerExtent();
85 G4bool driftsAreTooBigBefore = false;
86 while (keepGoing)
87 {
88 inspectedElement = beamline->GetPrevious(inspectedElement);
89 if (inspectedElement)
90 { // there is a previous element - inspect it
91 G4String inspectedElementType = inspectedElement->GetType();
92 if (inspectedElementType == "drift" || inspectedElementType == "dipolefringe" || inspectedElementType == "element")
93 {// leave keepGoing true here to keep going
94 // check extents first
95 BDSExtent extPipe = inspectedElement->GetAcceleratorComponent()->GetExtent();
96 G4double tiltPipe = inspectedElement->GetTilt();
97 if (accComponentTO) // could be nullptr
98 {extPipe = extPipe.Tilted(accComponentTO->GetTilt() - tiltPipe);}
99 if (extPipe.TransverselyGreaterThan(endPieceInnerExtent))
100 {
101 keepGoing = false;
102 if (inspectedElementType != "element")
103 {driftsAreTooBigBefore = true;}
104 }
105 if (keepGoing)
106 {
107 availableLength += inspectedElement->GetChordLength();
108 driftIsFirstItem = inspectedElement == firstItem;
109 }
110 }
111 else
112 {
113 keepGoing = false;
114 auto previousNonDriftAccCompEndPiece = inspectedElement->GetAcceleratorComponent()->EndPieceAfter();
115 if (previousNonDriftAccCompEndPiece)
116 {previousNonDriftEndPieceL = previousNonDriftAccCompEndPiece->GetChordLength();}
117 } // not a drift - can't be used
118 }
119 else
120 {keepGoing = false;} // quit the loop - no previous element
121 }
122
123 // don't place if there isn't enough space for BOTH endpieces - the previous one and this one
124 if (requiredBeforeLength > (availableLength - previousNonDriftEndPieceL))
125 {placeBefore = false;}
126
127 // don't place if the drifts on either side are too big for the end pieces to fit around
128 if (driftsAreTooBigBefore)
129 {placeBefore = false;}
130
131 // place the last item anyway even if there technically isn't space - either too short
132 // a drift or the magnet is first in the line
133 if ( (element == firstItem) || (driftIsFirstItem && !driftsAreTooBigBefore) )
134 {placeBefore = true;}
135
136 // If it's a circular machine the end piece will overlap with the teleporter or
137 // terminator or previous element which we don't check against, so play it safe
138 // and don't build it.
139 if ( (element == firstItem) && circularMachine )
140 {placeBefore = false;}
141
142 // Now check if the coil volumes will overlap
143 // This check is only done on before, as something can always be naturally added
144 // afterwards - this just sets a precedence of after over before.
145 if (placeBefore && !endPieces->empty() ) // only look backwards if we have already placed an end piece
146 {
147 // endPieces is a beam line of only end pieces
148 BDSAcceleratorComponent* prevEndPiece = (endPieces->back())->GetAcceleratorComponent();
149 // OF = outgoing face, IF = incoming face
150 // outgoing is end of next element being added, incoming is front face previous already added
151 BDSExtent extOF = endPieceBefore->GetExtent();
152 BDSExtent extIF = prevEndPiece->GetExtent();
153 G4ThreeVector oFNormal = endPieceBefore->InputFaceNormal();
154 G4ThreeVector iFNormal = prevEndPiece->OutputFaceNormal();
155 G4double lastEndPieceL = prevEndPiece->GetChordLength();
156 G4double zSeparation = availableLength - requiredBeforeLength - lastEndPieceL;
157 G4bool willIntersect = BDS::WillIntersect(iFNormal, oFNormal, zSeparation, extIF, extOF);
158 if (willIntersect)
159 {placeBefore = false;}
160
161 /*
162 // 3d check
163 auto thisEl = beamline->ProvideEndPieceElementBefore(endPieceBefore,
164 currentIndex);
165
166 G4bool willIntersect3D = endPieces->back()->Overlaps(thisEl);
167 if (willIntersect3D)
168 {
169 placeBefore = false;
170 delete thisEl;
171 }
172 */
173 }
174 if (placeBefore)
175 { // provide a BDSBeamlineElement for the end piece w.r.t. the original beam line
176 auto beforeEl = beamline->ProvideEndPieceElementBefore(endPieceBefore,
177 currentIndex);
178 endPieces->AddBeamlineElement(beforeEl); // append to end piece beam line
179 }
180 }
181
182 if (placeAfter)
183 {
184 // search after current element until we hit another component that's not a drift.
185 // ie work out the amount of drift space available. If we hit another element, check
186 // if it has an end piece and take that length out of the available space. if
187 // there's then available space for this end piece we place it.
188 G4bool keepGoing = true;
189 const BDSBeamlineElement* inspectedElement = element; // start with current element
190 G4double availableLength = 0;
191 G4double nextNonDriftEndPieceL = 0;
192 G4bool driftIsLastItem = false;
193 BDSExtent endPieceInnerExtent = endPieceAfter->GetInnerExtent();
194 G4bool driftsAreTooBigAfter = false;
195 while (keepGoing)
196 {
197 inspectedElement = beamline->GetNext(inspectedElement);
198 if (inspectedElement)
199 { // there is a next element - inspect it
200 G4String inspectedElementType = inspectedElement->GetType();
201 if (inspectedElementType == "drift" || inspectedElementType == "dipolefringe" || inspectedElementType == "element")
202 {// leave keepGoing true here to keep going
203 // check extents first
204 BDSExtent extPipe = inspectedElement->GetAcceleratorComponent()->GetExtent();
205 G4double tiltPipe = inspectedElement->GetTilt();
206 if (accComponentTO) // could be nullptr
207 {extPipe = extPipe.Tilted(accComponentTO->GetTilt() - tiltPipe);}
208 if (extPipe.TransverselyGreaterThan(endPieceInnerExtent))
209 {
210 keepGoing = false;
211 if (inspectedElementType != "element")
212 {driftsAreTooBigAfter = true;}
213 }
214 if (keepGoing)
215 {
216 availableLength += inspectedElement->GetChordLength();
217 driftIsLastItem = inspectedElement == lastItem;
218 }
219 }
220 else
221 {
222 keepGoing = false;
223 auto nextNonDriftAccCompEndPiece = inspectedElement->GetAcceleratorComponent()->EndPieceBefore();
224 if (nextNonDriftAccCompEndPiece)
225 {nextNonDriftEndPieceL = nextNonDriftAccCompEndPiece->GetChordLength();}
226 } // not a drift - can't be used
227 }
228 else
229 {keepGoing = false;} // quit the loop - no previous element
230 }
231
232 // don't place if there isn't enough space for BOTH endpieces - this one and the upcoming one
233 if (requiredAfterLength > (availableLength - nextNonDriftEndPieceL))
234 {placeAfter = false;}
235
236 // don't place if the drifts on either side are too big for the end pieces to fit around
237 if (driftsAreTooBigAfter)
238 {placeAfter = false;}
239
240 // place the last item anyway even if there technically isn't space - either too short
241 // a drift or the magnet is last in the line
242 if ( (element == lastItem) || (driftIsLastItem && !driftsAreTooBigAfter) )
243 {placeAfter = true;}
244
245 if (placeAfter)
246 { // provide a BDSBeamlineElement for the end piece w.r.t. the original beam line
247 G4bool flip = endPieceAfter == endPieceBefore; // sometimes the after piece is a copy of the before one
248 auto afterEl = beamline->ProvideEndPieceElementAfter(endPieceAfter,
249 currentIndex,
250 flip); // flip it round for placement
251 endPieces->AddBeamlineElement(afterEl); // append to end piece beam line
252 }
253 }
254 currentIndex++; // increment iterator index on beamline
255 }
256
257 return endPieces;
258}
Abstract class that represents a component of an accelerator.
BDSSimpleComponent * EndPieceBefore() const
virtual G4double GetChordLength() const
G4ThreeVector OutputFaceNormal() const
A class that holds a fully constructed BDSAcceleratorComponent as well as any information relevant to...
G4double GetChordLength() const
Accessor.
BDSAcceleratorComponent * GetAcceleratorComponent() const
Accessor.
G4double GetTilt() const
Convenience accessor.
G4String GetType() const
Accessor.
A vector of BDSBeamlineElement instances - a beamline.
const BDSBeamlineElement * GetPrevious(const BDSBeamlineElement *element) const
BDSBeamlineElement * back() const
Return a reference to the last element.
const BDSBeamlineElement * GetLastItem() const
Return a reference to the last element.
BDSBeamlineElement * ProvideEndPieceElementAfter(BDSSimpleComponent *endPiece, G4int index, G4bool flip=false) const
const BDSBeamlineElement * GetFirstItem() const
Return a reference to the first element.
void AddBeamlineElement(BDSBeamlineElement *element)
G4bool empty() const
Iterator mechanics.
Holder for +- extents in 3 dimensions.
Definition BDSExtent.hh:38
BDSExtent Tilted(G4double angle) const
Provide a new copy of this extent but rotated along Z by a given tilt angle.
Definition BDSExtent.cc:120
G4bool TransverselyGreaterThan(const BDSExtent &r) const
Comparison operator for x,y only. Ignores z (length).
Definition BDSExtent.hh:101
BDSExtent GetExtent() const
Accessor - see member for more info.
static BDSGlobalConstants * Instance()
Access method.
BDSBeamline * BuildEndPieceBeamline(const BDSBeamline *beamline, const G4bool circularMachine)
G4bool WillIntersect(const G4ThreeVector &incomingNormal, const G4ThreeVector &outgoingNormal, const G4double &zSeparation, const BDSExtent &incomingExtent, const BDSExtent &outgoingExtent)