20#include "BDSAcceleratorComponent.hh"
21#include "BDSBeamline.hh"
22#include "BDSBeamlineElement.hh"
23#include "BDSException.hh"
24#include "BDSExtentGlobal.hh"
25#include "BDSGlobalConstants.hh"
27#include "BDSOutput.hh"
28#include "BDSSamplerPlane.hh"
29#include "BDSSimpleComponent.hh"
30#include "BDSTiltOffset.hh"
31#include "BDSTransform3D.hh"
32#include "BDSUtilities.hh"
33#include "BDSWarning.hh"
36#include "G4RotationMatrix.hh"
37#include "G4ThreeVector.hh"
38#include "G4Transform3D.hh"
40#include "CLHEP/Vector/AxisAngle.h"
50BDSBeamline::BDSBeamline(
const G4ThreeVector& initialGlobalPosition,
51 G4RotationMatrix* initialGlobalRotation,
56 previousReferencePositionEnd(initialGlobalPosition),
57 previousSPositionEnd(initialS),
58 transformHasJustBeenApplied(false)
65 if (initialGlobalRotation)
76 G4cout << __METHOD_NAME__ <<
"with initial position and rotation" << G4endl;
77 G4cout <<
"Initial position: " << initialGlobalPosition << G4endl;
82BDSBeamline::BDSBeamline(G4Transform3D initialTransform,
85 new G4RotationMatrix(initialTransform.getRotation()),
89BDSBeamline::~BDSBeamline()
102 for (
const auto& element : *
this)
108 G4cout << __METHOD_NAME__ <<
"container size: " <<
sizeof(
beamline) << G4endl;
113std::ostream& operator<< (std::ostream& out,
BDSBeamline const &bl)
115 out <<
"Beamline with " << bl.
size() <<
" elements" << G4endl;
116 out <<
"Total arc length: " << bl.
totalArcLength <<
" mm" << G4endl;
128 G4String samplerName = samplerInfo ? samplerInfo->name :
"no_sampler_name_given";
129 throw BDSException(__METHOD_NAME__,
"invalid accelerator component " + samplerName);
135 G4String samplerName = samplerInfo->name;
138 G4cerr << __METHOD_NAME__ <<
"invalid sampler name \"" << samplerName <<
"\"" << G4endl;
151 G4int sizeLine = (G4int)line->size();
152 for (G4int i = 0; i < sizeLine; ++i)
168 if (samplerInfo->samplerType == BDSSamplerType::cylinder)
174 G4ThreeVector aaMidAxis;
181 aaMidAxis = aaFinish.axis();
182 aaMidAngle = 0.5 * aaFinish.delta();
186 aaMidAxis = aaStart.axis();
187 aaMidAngle = 0.5 * aaStart.delta();
191 aaMidAxis = (aaFinish.axis() + aaStart.axis()) / 2.0;
192 aaMidAngle = (aaFinish.delta() + aaStart.delta()) / 2.0;
194 auto aaCSampler = CLHEP::HepAxisAngle(aaMidAxis, aaMidAngle);
195 G4RotationMatrix rmCSampler = G4RotationMatrix(aaCSampler);
196 G4Transform3D trCSampler(rmCSampler, midRefPosition);
212 G4cout << G4endl << __METHOD_NAME__ <<
"adding component to beamline and calculating coordinates" << G4endl;
213 G4cout <<
"component name: " << component->
GetName() << G4endl;
229 G4double angle = component->
GetAngle();
232 G4bool hasFiniteTilt, hasFiniteOffset;
233 G4ThreeVector offset;
242 hasFiniteTilt =
false;
243 hasFiniteOffset =
false;
244 offset = G4ThreeVector();
249 G4bool hasFinitePlacementOffset =
BDS::IsFinite(placementOffset);
253 G4cout <<
"chord length " << chordLength <<
" mm" << G4endl;
254 G4cout <<
"angle " << angle <<
" rad" << G4endl;
256 {G4cout <<
"tilt offsetX offsetY " << *tiltOffset <<
" rad mm mm " << G4endl;}
258 {G4cout <<
"no tilt offset" << G4endl;}
259 G4cout <<
"has finite length " << hasFiniteLength << G4endl;
260 G4cout <<
"has finite angle " << hasFiniteAngle << G4endl;
261 G4cout <<
"has finite tilt " << hasFiniteTilt << G4endl;
262 G4cout <<
"has finite offset " << hasFiniteOffset << G4endl;
263 G4cout <<
"extent positive " << eP << G4endl;
264 G4cout <<
"extent negative " << eN << G4endl;
265 G4cout <<
"object placement offset " << placementOffset << G4endl;
266 G4cout <<
"has finite placement offset " << hasFinitePlacementOffset << G4endl;
267 G4cout <<
"output face normal " << oFNormal << G4endl;
272 if (!
empty() && (component->
GetType() !=
"drift") && (component->
GetType() !=
"thinmultipole"))
274 G4bool keepGoing =
true;
275 G4bool checkFaces =
true;
276 G4double zSeparation = 0;
279 G4ThreeVector iFNormal;
280 G4String clasherName =
"Unknown";
283 if (inspectedElement)
285 if ((inspectedElement->
GetType() ==
"drift")||(inspectedElement->
GetType() ==
"thinmultipole"))
304 G4cout <<
"input face normal " << iFNormal << G4endl;
313 G4bool willIntersect =
BDS::WillIntersect(iFNormal, oFNormal, zSeparation, extIF, extOF);
316 G4cout << __METHOD_NAME__ <<
"Error - angled faces of objects will cause overlap in beam line geometry" << G4endl;
317 G4cout <<
"\"" << component->
GetName() <<
"\" will overlap with \""
318 << clasherName <<
"\"" << G4endl;
328 G4RotationMatrix* referenceRotationStart;
338 G4RotationMatrix* referenceRotationMiddle =
new G4RotationMatrix(*referenceRotationStart);
339 G4RotationMatrix* referenceRotationEnd =
new G4RotationMatrix(*referenceRotationStart);
349 G4ThreeVector rotationAxisOfBend = G4ThreeVector(0,1,0);
350 G4ThreeVector rotationAxisOfBendEnd = rotationAxisOfBend;
353 G4double tilt = tiltOffset->
GetTilt();
354 G4RotationMatrix rotationAxisRM = G4RotationMatrix();
355 rotationAxisRM.rotateZ(tilt);
356 rotationAxisOfBend.transform(rotationAxisRM);
357 rotationAxisOfBendEnd.transform(rotationAxisRM);
364 G4RotationMatrix* rotationStart =
new G4RotationMatrix(*referenceRotationStart);
365 G4RotationMatrix* rotationMiddle =
new G4RotationMatrix(*referenceRotationMiddle);
366 G4RotationMatrix* rotationEnd =
new G4RotationMatrix(*referenceRotationEnd);
370 G4double tilt = tiltOffset->
GetTilt();
374 G4ThreeVector unitZ = G4ThreeVector(0,0,1);
375 rotationStart ->rotate(tilt, unitZ.transform(*referenceRotationStart));
376 unitZ = G4ThreeVector(0,0,1);
377 rotationMiddle->rotate(tilt, unitZ.transform(*referenceRotationMiddle));
378 unitZ = G4ThreeVector(0,0,1);
379 rotationEnd ->rotate(tilt, unitZ.transform(*referenceRotationEnd));
397 if (samplerType != BDSSamplerType::none)
406 G4ThreeVector componentGap = pad.transform(*previousReferenceRotationEnd2);
410 G4ThreeVector referencePositionStart, referencePositionMiddle, referencePositionEnd;
416 G4ThreeVector md = G4ThreeVector(0, 0, 0.5 * chordLength);
417 md.transform(*referenceRotationMiddle);
418 referencePositionMiddle = referencePositionStart + md;
421 G4ThreeVector delta = G4ThreeVector(0, 0, chordLength).transform(*referenceRotationMiddle);
422 referencePositionEnd = referencePositionStart + delta;
434 G4ThreeVector positionStart, positionMiddle, positionEnd;
435 if (hasFiniteOffset || hasFinitePlacementOffset)
437 if (hasFiniteOffset && hasFiniteAngle)
439 G4String name = component->
GetName();
440 G4String message =
"element has x offset, but this will cause geometry overlaps: " + name
441 +
" - omitting x offset";
442 BDS::Warning(__METHOD_NAME__, message);
447 G4ThreeVector total = offset + placementOffset;
448 G4ThreeVector displacement = total.transform(*referenceRotationMiddle);
449 positionStart = referencePositionStart + displacement;
450 positionMiddle = referencePositionMiddle + displacement;
451 positionEnd = referencePositionEnd + displacement;
455 positionStart = referencePositionStart;
456 positionMiddle = referencePositionMiddle;
457 positionEnd = referencePositionEnd;
482 G4cout <<
"calculated coordinates in mm and rad are " << G4endl;
483 G4cout <<
"reference position start: " << referencePositionStart << G4endl;
484 G4cout <<
"reference position middle: " << referencePositionMiddle << G4endl;
485 G4cout <<
"reference position end: " << referencePositionEnd << G4endl;
486 G4cout <<
"reference rotation start: " << *referenceRotationStart;
487 G4cout <<
"reference rotation middle: " << *referenceRotationMiddle;
488 G4cout <<
"reference rotation end: " << *referenceRotationEnd;
489 G4cout <<
"position start: " << positionStart << G4endl;
490 G4cout <<
"position middle: " << positionMiddle << G4endl;
491 G4cout <<
"position end: " << positionEnd << G4endl;
492 G4cout <<
"rotation start: " << *rotationStart;
493 G4cout <<
"rotation middle: " << *rotationMiddle;
494 G4cout <<
"rotation end: " << *rotationEnd;
510 referencePositionStart,
511 referencePositionMiddle,
512 referencePositionEnd,
513 referenceRotationStart,
514 referenceRotationMiddle,
515 referenceRotationEnd,
530 sEnd.push_back(sPositionEnd);
541 G4double dx = component->dx;
542 G4double dy = component->dy;
543 G4double dz = component->dz;
548 G4cerr << __METHOD_NAME__ <<
"Caution: Transform3d: " << component->
GetName() << G4endl;
549 G4cerr << __METHOD_NAME__ <<
"dz = " << dz <<
" < 0 -> could overlap previous element" << G4endl;
567 G4RotationMatrix trRotInverse = component->rotationMatrix.inverse();
568 (*previousReferenceRotationEnd) *= trRotInverse;
574 {
throw BDSException(__METHOD_NAME__,
"invalid BDSBeamlineElement");}
576 {
throw BDSException(__METHOD_NAME__,
"invalid BDSAcceleratorComponent");}
593 for (
int i=0; i<3; i++)
599 G4int* indexOfFoundElement)
const
605 G4String msg =
"s position " + std::to_string(s/CLHEP::m) +
" m is beyond length of accelerator (";
606 msg += std::to_string(
totalArcLength/CLHEP::m) +
" m)\nReturning identify transform";
607 BDS::Warning(__METHOD_NAME__, msg);
608 return G4Transform3D();
614 G4cout << __METHOD_NAME__ << G4endl;
615 G4cout <<
"S position requested: " << s << G4endl;
616 G4cout <<
"Index: " << indexOfFoundElement << G4endl;
617 G4cout <<
"Element: " << *element << G4endl;
629 G4double dS = s - element->GetSPositionMiddle();
630 G4double localZ = dS * (chordLength / arcLength);
631 G4double angle = component->
GetAngle();
632 G4RotationMatrix rotation;
633 G4RotationMatrix* rotMiddle = element->GetReferenceRotationMiddle();
639 G4ThreeVector localUnitY = G4ThreeVector(0,1,0);
640 localUnitY.transform(*(element->GetReferenceRotationStart()));
642 G4double partialAngle = angle * std::fabs(( (0.5*arcLength + dS) / arcLength));
643 rotation = G4RotationMatrix(*(element->GetReferenceRotationStart()));
644 rotation.rotate(partialAngle, localUnitY);
645 dx = localZ*tan(partialAngle);
648 {rotation = G4RotationMatrix(*rotMiddle);}
651 G4ThreeVector dLocal = G4ThreeVector(x + dx, y , localZ);
653 G4cout <<
"Local offset from middle: " << dLocal << G4endl;
656 G4ThreeVector globalPos = element->GetReferencePositionMiddle() + dLocal.transform(*rotMiddle);
658 G4Transform3D result = G4Transform3D(rotation, globalPos);
661 G4cout <<
"Global offset from middle: " << dLocal << G4endl;
662 G4cout <<
"Resultant global position: " << globalPos << G4endl;
668 G4int* indexOfFoundElement)
const
671 auto lower = std::lower_bound(
sEnd.begin(),
sEnd.end(), S);
672 G4int index = G4int(lower -
sEnd.begin());
673 if (indexOfFoundElement)
674 {*indexOfFoundElement = index;}
680 auto lower = std::lower_bound(
sEnd.begin(),
sEnd.end(), S);
682 std::advance(iter, std::distance(
sEnd.begin(), lower));
700 if (index < 1 || index > (G4int)(
beamline.size()-1))
712 return GetNext(G4int(result -
beamline.begin()));
720 if (index < 0 || index > (G4int)(
beamline.size()-2))
741 G4String suffix =
"_" + std::to_string(i);
742 G4String placementName = acceleratorComponentName + suffix;
743 const auto search =
components.find(placementName);
753 std::vector<const BDSBeamlineElement*> candidates;
754 std::for_each(this->
begin(),
759 if (candidates.empty())
763 auto foundItem = std::find_if(candidates.begin(),
766 {return BDS::EndsWith(el->GetPlacementName(), suffix);});
767 return foundItem != candidates.end() ? *foundItem :
nullptr;
771 {
return search->second;}
780 G4cerr << __METHOD_NAME__ <<
"No element named \""
781 << acceleratorComponentName <<
"\" found for placement number "
783 G4cout <<
"Note, this may be because the element is a bend and split into " << G4endl;
784 G4cout <<
"multiple sections with unique names." << G4endl;
799 for (
const auto& point : boundaryPoints)
801 for (
int i = 0; i < 3; ++i)
825 G4ThreeVector elPosStart = element->
GetPositionStart() - G4ThreeVector(0,0,2*pl).transform(*elRotStart);
826 G4ThreeVector positionMiddle = elPosStart - G4ThreeVector(0,0,endPieceLength*0.5).transform(*elRotStart);
827 G4ThreeVector positionStart = elPosStart - G4ThreeVector(0,0,endPieceLength).transform(*elRotStart);
837 new G4RotationMatrix(*elRotStart),
838 new G4RotationMatrix(*elRotStart),
839 new G4RotationMatrix(*elRotStart),
843 new G4RotationMatrix(*elRotStart),
844 new G4RotationMatrix(*elRotStart),
845 new G4RotationMatrix(*elRotStart),
846 elSPosStart - endPieceLength,
847 elSPosStart - 0.5*endPieceLength,
863 G4RotationMatrix* elRotEnd =
new G4RotationMatrix(*(element->
GetRotationMiddle()));
864 G4ThreeVector elPosEnd = element->
GetPositionEnd() + G4ThreeVector(0,0,pl).transform(*elRotEnd);
865 G4ThreeVector positionMiddle = elPosEnd + G4ThreeVector(0,0,endPieceLength*0.5).transform(*elRotEnd);
866 G4ThreeVector positionEnd = elPosEnd + G4ThreeVector(0,0,endPieceLength).transform(*elRotEnd);
869 G4ThreeVector localUnitY = G4ThreeVector(0,1,0).transform(*elRotEnd);
870 elRotEnd->rotate(CLHEP::pi, localUnitY);
881 new G4RotationMatrix(*elRotEnd),
882 new G4RotationMatrix(*elRotEnd),
883 new G4RotationMatrix(*elRotEnd),
887 new G4RotationMatrix(*elRotEnd),
888 new G4RotationMatrix(*elRotEnd),
889 new G4RotationMatrix(*elRotEnd),
891 elSPosEnd + 0.5*endPieceLength,
892 elSPosEnd + endPieceLength,
900 if (index < 0 || index > (G4int)(
beamline.size()-1))
908 std::vector<G4double> sPos;
914 if (sPos.size() == 1)
915 {sPos.push_back(1*CLHEP::m);}
921 return (std::abs(
totalAngle) > 0.99 * 2.0 * CLHEP::pi) and (std::abs(
totalAngle) < 1.01 * 2.0 * CLHEP::pi);
933 std::vector<G4int> result;
936 if (element->
GetType() == type)
937 {result.push_back(element->
GetIndex());}
944 std::vector<G4int> result;
947 G4String type = element->
GetType();
948 if (types.find(type) != types.end())
949 {result.push_back(element->
GetIndex());}
956 std::set<G4String> collimatorTypes = {
"ecol",
"rcol",
"jcol",
"crystalcol",
"element-collimator"};
Abstract class that represents a component of an accelerator.
G4double GetAngle() const
virtual G4String GetName() const
The name of the component without modification.
virtual G4double GetChordLength() const
G4ThreeVector OutputFaceNormal() const
virtual G4double GetArcLength() const
G4ThreeVector InputFaceNormal() const
G4String GetType() const
Get a string describing the type of the component.
A class that holds a fully constructed BDSAcceleratorComponent as well as any information relevant to...
G4double GetChordLength() const
Accessor.
G4ThreeVector GetPositionMiddle() const
Accessor.
G4ThreeVector GetReferencePositionEnd() const
Accessor.
G4ThreeVector GetPositionEnd() const
Accessor.
G4RotationMatrix * GetReferenceRotationStart() const
Accessor.
G4ThreeVector GetPositionStart() const
Accessor.
G4String GetPlacementName() const
Accessor.
BDSTiltOffset * GetTiltOffset() const
Accessor.
void UpdateSamplerPlacementTransform(const G4Transform3D &tranfsormIn)
G4RotationMatrix * GetReferenceRotationEnd() const
Accessor.
G4String GetName() const
Accessor.
BDSSamplerInfo * GetSamplerInfo() const
Accessor.
G4int GetIndex() const
Accessor.
G4double GetSPositionEnd() const
Accessor.
G4ThreeVector GetReferencePositionStart() const
Accessor.
BDSAcceleratorComponent * GetAcceleratorComponent() const
Accessor.
G4RotationMatrix * GetRotationMiddle() const
Accessor.
G4String GetType() const
Accessor.
BDSExtentGlobal GetExtentGlobal() const
Create a global extent object from the extent of the component.
G4double GetSPositionStart() const
Accessor.
A vector of BDSBeamlineElement instances - a beamline.
G4double totalChordLength
Sum of all chord lengths.
std::vector< G4double > GetEdgeSPositions() const
G4ThreeVector previousReferencePositionEnd
Current reference position at the end of the previous element.
const BDSBeamlineElement * GetPrevious(const BDSBeamlineElement *element) const
void PrintAllComponents(std::ostream &out) const
const BDSBeamlineElement * GetElement(G4String acceleratorComponentName, G4int i=0) const
Get the ith placement of an element in the beam line. Returns null pointer if not found.
BDSBeamlineElement * back() const
Return a reference to the last element.
G4ThreeVector maximumExtentPositive
maximum extent in the positive coordinates in each dimension
G4double previousSPositionEnd
Current s coordinate at the end of the previous element.
G4bool ElementAnglesSumToCircle() const
Check if the sum of the angle of all elements is two pi.
G4double totalAngle
Sum of all angles.
BDSBeamlineElement * ProvideEndPieceElementAfter(BDSSimpleComponent *endPiece, G4int index, G4bool flip=false) const
G4RotationMatrix * previousReferenceRotationEnd
Current reference rotation at the end of the previous element.
G4bool transformHasJustBeenApplied
void RegisterElement(BDSBeamlineElement *element)
void UpdateExtents(BDSBeamlineElement *element)
G4ThreeVector GetMaximumExtentAbsolute() const
Get the maximum extent absolute in each dimension.
void PrintMemoryConsumption() const
void ApplyTransform3D(BDSTransform3D *component)
static G4double paddingLength
The gap added for padding between each component.
const BDSBeamlineElement * at(int iElement) const
Return a reference to the element at i.
G4bool IndexOK(G4int index) const
Whether the supplied index will lie within the beam line vector.
BeamlineVector::size_type size() const
Get the number of elements.
void AddBeamlineElement(BDSBeamlineElement *element)
G4Transform3D GetTransformForElement(const G4String &acceleratorComponentName, G4int i=0) const
const_iterator FindFromS(G4double S) const
Returns an iterator to the beamline element at s.
G4double totalArcLength
Sum of all arc lengths.
BeamlineVector beamline
Vector of beam line elements - the data.
const BDSBeamlineElement * GetElementFromGlobalS(G4double S, G4int *indexOfFoundElement=nullptr) const
Return the element in this beam line according to a given s coordinate.
G4bool empty() const
Iterator mechanics.
void AddSingleComponent(BDSAcceleratorComponent *component, BDSTiltOffset *tiltOffset=nullptr, BDSSamplerInfo *samplerInfo=nullptr)
G4Transform3D GetGlobalEuclideanTransform(G4double s, G4double x=0, G4double y=0, G4int *indexOfFoundElement=nullptr) const
BDSExtentGlobal GetExtentGlobal() const
Get the global extents for this beamline.
iterator begin()
Iterator mechanics.
std::map< G4String, BDSBeamlineElement * > components
Map of objects by placement name stored in this beam line.
void AddComponent(BDSAcceleratorComponent *component, BDSTiltOffset *tiltOffset=nullptr, BDSSamplerInfo *samplerInfo=nullptr)
iterator end()
Iterator mechanics.
std::vector< G4int > GetIndicesOfElementsOfType(const G4String &type) const
Return vector of indices for this beam line where element of type name 'type' is found.
std::vector< G4double > sEnd
BeamlineVector::const_iterator const_iterator
Iterator mechanics.
std::vector< G4int > GetIndicesOfCollimators() const
Return indices in order of ecol, rcol, jcol and crystalcol elements.
G4ThreeVector maximumExtentNegative
maximum extent in the negative coordinates in each dimension
General exception with possible name of object and message.
Holder for +- extents in 3 dimensions with a rotation and translation.
std::vector< G4ThreeVector > AllBoundaryPointsGlobal() const
All 8 boundary points of the bounding box.
Holder for +- extents in 3 dimensions.
BDSExtent GetExtent() const
Accessor - see member for more info.
G4ThreeVector GetExtentPositive() const
Get the extent of the object in the positive direction in all dimensions.
G4ThreeVector GetExtentNegative() const
Get the extent of the object in the negative direction in all dimensions.
G4ThreeVector GetPlacementOffset() const
Accessor - see member for more info.
static BDSGlobalConstants * Instance()
Access method.
A class that hold multiple accelerator components.
static void PrintProtectedNames(std::ostream &out)
Feedback for protected names.
static G4bool InvalidSamplerName(const G4String &samplerName)
Test whether a sampler name is invalid or not.
All info required to build a sampler but not place it.
static G4double ChordLength()
Access the sampler plane length in other classes.
A BDSAcceleratorComponent wrapper for BDSGeometryComponent.
A holder for any placement offsets and rotations for a BDSAcceleratorComponent.
G4bool HasFiniteTilt() const
Inspector.
G4double GetTilt() const
Accessor.
G4bool HasFiniteOffset() const
Inspector.
G4ThreeVector GetOffset() const
More advance accessor for offset - only in x,y.
G4bool WillIntersect(const G4ThreeVector &incomingNormal, const G4ThreeVector &outgoingNormal, const G4double &zSeparation, const BDSExtent &incomingExtent, const BDSExtent &outgoingExtent)
G4bool StartsWith(const std::string &expression, const std::string &prefix)
Return true if a string "expression" starts with "prefix".
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())