20#include "BDSAcceleratorComponent.hh"
21#include "BDSBeamline.hh"
22#include "BDSBeamlineElement.hh"
23#include "BDSBeamlineIntegral.hh"
24#include "BDSException.hh"
25#include "BDSExtentGlobal.hh"
26#include "BDSGlobalConstants.hh"
28#include "BDSOutput.hh"
29#include "BDSSamplerPlane.hh"
30#include "BDSSimpleComponent.hh"
31#include "BDSTiltOffset.hh"
32#include "BDSTransform3D.hh"
33#include "BDSUtilities.hh"
34#include "BDSWarning.hh"
37#include "G4RotationMatrix.hh"
38#include "G4ThreeVector.hh"
39#include "G4Transform3D.hh"
41#include "CLHEP/Vector/AxisAngle.h"
51BDSBeamline::BDSBeamline(
const G4ThreeVector& initialGlobalPosition,
52 G4RotationMatrix* initialGlobalRotation,
59 previousReferencePositionEnd(initialGlobalPosition),
60 previousSPositionEnd(sInitial),
61 transformHasJustBeenApplied(false)
68 if (initialGlobalRotation)
79 G4cout << __METHOD_NAME__ <<
"with initial position and rotation" << G4endl;
80 G4cout <<
"Initial position: " << initialGlobalPosition << G4endl;
85BDSBeamline::BDSBeamline(G4Transform3D initialTransform,
88 new G4RotationMatrix(initialTransform.getRotation()),
92BDSBeamline::~BDSBeamline()
105 for (
const auto& element : *
this)
111 G4cout << __METHOD_NAME__ <<
"container size: " <<
sizeof(
beamline) << G4endl;
116std::ostream& operator<< (std::ostream& out,
BDSBeamline const &bl)
118 out <<
"Beamline with " << bl.
size() <<
" elements" << G4endl;
119 out <<
"Total arc length: " << bl.
totalArcLength <<
" mm" << G4endl;
132 G4String samplerName = samplerInfo ? samplerInfo->name :
"no_sampler_name_given";
133 throw BDSException(__METHOD_NAME__,
"invalid accelerator component " + samplerName);
139 G4String samplerName = samplerInfo->name;
142 G4cerr << __METHOD_NAME__ <<
"invalid sampler name \"" << samplerName <<
"\"" << G4endl;
155 G4int sizeLine = (G4int)line->size();
156 for (G4int i = 0; i < sizeLine; ++i)
172 if (samplerInfo->samplerType == BDSSamplerType::cylinder)
178 G4ThreeVector aaMidAxis;
185 aaMidAxis = aaFinish.axis();
186 aaMidAngle = 0.5 * aaFinish.delta();
190 aaMidAxis = aaStart.axis();
191 aaMidAngle = 0.5 * aaStart.delta();
195 aaMidAxis = (aaFinish.axis() + aaStart.axis()) / 2.0;
196 aaMidAngle = (aaFinish.delta() + aaStart.delta()) / 2.0;
198 auto aaCSampler = CLHEP::HepAxisAngle(aaMidAxis, aaMidAngle);
199 G4RotationMatrix rmCSampler = G4RotationMatrix(aaCSampler);
200 G4Transform3D trCSampler(rmCSampler, midRefPosition);
217 G4cout << G4endl << __METHOD_NAME__ <<
"adding component to beamline and calculating coordinates" << G4endl;
218 G4cout <<
"component name: " << component->
GetName() << G4endl;
234 G4double angle = component->
GetAngle();
237 G4bool hasFiniteTilt, hasFiniteOffset;
238 G4ThreeVector offset;
247 hasFiniteTilt =
false;
248 hasFiniteOffset =
false;
249 offset = G4ThreeVector();
254 G4bool hasFinitePlacementOffset =
BDS::IsFinite(placementOffset);
258 G4cout <<
"chord length " << chordLength <<
" mm" << G4endl;
259 G4cout <<
"angle " << angle <<
" rad" << G4endl;
261 {G4cout <<
"tilt offsetX offsetY " << *tiltOffset <<
" rad mm mm " << G4endl;}
263 {G4cout <<
"no tilt offset" << G4endl;}
264 G4cout <<
"has finite length " << hasFiniteLength << G4endl;
265 G4cout <<
"has finite angle " << hasFiniteAngle << G4endl;
266 G4cout <<
"has finite tilt " << hasFiniteTilt << G4endl;
267 G4cout <<
"has finite offset " << hasFiniteOffset << G4endl;
268 G4cout <<
"extent positive " << eP << G4endl;
269 G4cout <<
"extent negative " << eN << G4endl;
270 G4cout <<
"object placement offset " << placementOffset << G4endl;
271 G4cout <<
"has finite placement offset " << hasFinitePlacementOffset << G4endl;
272 G4cout <<
"output face normal " << oFNormal << G4endl;
277 if (!
empty() && (component->
GetType() !=
"drift") && (component->
GetType() !=
"thinmultipole"))
279 G4bool keepGoing =
true;
280 G4bool checkFaces =
true;
281 G4double zSeparation = 0;
284 G4ThreeVector iFNormal;
285 G4String clasherName =
"Unknown";
288 if (inspectedElement)
290 if ((inspectedElement->
GetType() ==
"drift")||(inspectedElement->
GetType() ==
"thinmultipole"))
309 G4cout <<
"input face normal " << iFNormal << G4endl;
318 G4bool willIntersect =
BDS::WillIntersect(iFNormal, oFNormal, zSeparation, extIF, extOF);
321 G4cout << __METHOD_NAME__ <<
"Error - angled faces of objects will cause overlap in beam line geometry" << G4endl;
322 G4cout <<
"\"" << component->
GetName() <<
"\" will overlap with \""
323 << clasherName <<
"\"" << G4endl;
333 G4RotationMatrix* referenceRotationStart;
343 G4RotationMatrix* referenceRotationMiddle =
new G4RotationMatrix(*referenceRotationStart);
344 G4RotationMatrix* referenceRotationEnd =
new G4RotationMatrix(*referenceRotationStart);
354 G4ThreeVector rotationAxisOfBend = G4ThreeVector(0,1,0);
355 G4ThreeVector rotationAxisOfBendEnd = rotationAxisOfBend;
358 G4double tilt = tiltOffset->
GetTilt();
359 G4RotationMatrix rotationAxisRM = G4RotationMatrix();
360 rotationAxisRM.rotateZ(tilt);
361 rotationAxisOfBend.transform(rotationAxisRM);
362 rotationAxisOfBendEnd.transform(rotationAxisRM);
369 G4RotationMatrix* rotationStart =
new G4RotationMatrix(*referenceRotationStart);
370 G4RotationMatrix* rotationMiddle =
new G4RotationMatrix(*referenceRotationMiddle);
371 G4RotationMatrix* rotationEnd =
new G4RotationMatrix(*referenceRotationEnd);
375 G4double tilt = tiltOffset->
GetTilt();
379 G4ThreeVector unitZ = G4ThreeVector(0,0,1);
380 rotationStart ->rotate(tilt, unitZ.transform(*referenceRotationStart));
381 unitZ = G4ThreeVector(0,0,1);
382 rotationMiddle->rotate(tilt, unitZ.transform(*referenceRotationMiddle));
383 unitZ = G4ThreeVector(0,0,1);
384 rotationEnd ->rotate(tilt, unitZ.transform(*referenceRotationEnd));
402 if (samplerType != BDSSamplerType::none)
411 G4ThreeVector componentGap = pad.transform(*previousReferenceRotationEnd2);
415 G4ThreeVector referencePositionStart, referencePositionMiddle, referencePositionEnd;
421 G4ThreeVector md = G4ThreeVector(0, 0, 0.5 * chordLength);
422 md.transform(*referenceRotationMiddle);
423 referencePositionMiddle = referencePositionStart + md;
426 G4ThreeVector delta = G4ThreeVector(0, 0, chordLength).transform(*referenceRotationMiddle);
427 referencePositionEnd = referencePositionStart + delta;
439 G4ThreeVector positionStart, positionMiddle, positionEnd;
440 if (hasFiniteOffset || hasFinitePlacementOffset)
442 if (hasFiniteOffset && hasFiniteAngle)
444 G4String name = component->
GetName();
445 G4String message =
"element has x offset, but this will cause geometry overlaps: " + name
446 +
" - omitting x offset";
447 BDS::Warning(__METHOD_NAME__, message);
452 G4ThreeVector total = offset + placementOffset;
453 G4ThreeVector displacement = total.transform(*referenceRotationMiddle);
454 positionStart = referencePositionStart + displacement;
455 positionMiddle = referencePositionMiddle + displacement;
456 positionEnd = referencePositionEnd + displacement;
460 positionStart = referencePositionStart;
461 positionMiddle = referencePositionMiddle;
462 positionEnd = referencePositionEnd;
481 sMaximum += arcLength;
488 G4cout <<
"calculated coordinates in mm and rad are " << G4endl;
489 G4cout <<
"reference position start: " << referencePositionStart << G4endl;
490 G4cout <<
"reference position middle: " << referencePositionMiddle << G4endl;
491 G4cout <<
"reference position end: " << referencePositionEnd << G4endl;
492 G4cout <<
"reference rotation start: " << *referenceRotationStart;
493 G4cout <<
"reference rotation middle: " << *referenceRotationMiddle;
494 G4cout <<
"reference rotation end: " << *referenceRotationEnd;
495 G4cout <<
"position start: " << positionStart << G4endl;
496 G4cout <<
"position middle: " << positionMiddle << G4endl;
497 G4cout <<
"position end: " << positionEnd << G4endl;
498 G4cout <<
"rotation start: " << *rotationStart;
499 G4cout <<
"rotation middle: " << *rotationMiddle;
500 G4cout <<
"rotation end: " << *rotationEnd;
511 if (beamlineIntegral)
513 midT = beamlineIntegral->synchronousTAtMiddleOfLastElement;
514 staP = beamlineIntegral->MomentumAtStartOfLastElement();
515 staEk = beamlineIntegral->KineticEnergyAtStartOfLastElement();
526 referencePositionStart,
527 referencePositionMiddle,
528 referencePositionEnd,
529 referenceRotationStart,
530 referenceRotationMiddle,
531 referenceRotationEnd,
549 sEnd.push_back(sPositionEnd);
560 G4double dx = component->dx;
561 G4double dy = component->dy;
562 G4double dz = component->dz;
567 G4cerr << __METHOD_NAME__ <<
"Caution: Transform3d: " << component->
GetName() << G4endl;
568 G4cerr << __METHOD_NAME__ <<
"dz = " << dz <<
" < 0 -> could overlap previous element" << G4endl;
586 G4RotationMatrix trRotInverse = component->rotationMatrix.inverse();
587 (*previousReferenceRotationEnd) *= trRotInverse;
593 {
throw BDSException(__METHOD_NAME__,
"invalid BDSBeamlineElement");}
595 {
throw BDSException(__METHOD_NAME__,
"invalid BDSAcceleratorComponent");}
612 for (
int i=0; i<3; i++)
618 G4int* indexOfFoundElement)
const
624 G4String msg =
"s position " + std::to_string(s/CLHEP::m) +
" m is beyond length of accelerator (";
625 msg += std::to_string(
totalArcLength/CLHEP::m) +
" m)\nReturning identify transform";
626 BDS::Warning(__METHOD_NAME__, msg);
627 return G4Transform3D();
633 G4cout << __METHOD_NAME__ << G4endl;
634 G4cout <<
"S position requested: " << s << G4endl;
635 G4cout <<
"Index: " << indexOfFoundElement << G4endl;
636 G4cout <<
"Element: " << *element << G4endl;
648 G4double dS = s - element->GetSPositionMiddle();
649 G4double localZ = dS * (chordLength / arcLength);
650 G4double angle = component->
GetAngle();
651 G4RotationMatrix rotation;
652 G4RotationMatrix* rotMiddle = element->GetReferenceRotationMiddle();
658 G4ThreeVector localUnitY = G4ThreeVector(0,1,0);
659 localUnitY.transform(*(element->GetReferenceRotationStart()));
661 G4double partialAngle = angle * std::fabs(( (0.5*arcLength + dS) / arcLength));
662 rotation = G4RotationMatrix(*(element->GetReferenceRotationStart()));
663 rotation.rotate(partialAngle, localUnitY);
664 dx = localZ*tan(partialAngle);
667 {rotation = G4RotationMatrix(*rotMiddle);}
670 G4ThreeVector dLocal = G4ThreeVector(x + dx, y , localZ);
672 G4cout <<
"Local offset from middle: " << dLocal << G4endl;
675 G4ThreeVector globalPos = element->GetReferencePositionMiddle() + dLocal.transform(*rotMiddle);
677 G4Transform3D result = G4Transform3D(rotation, globalPos);
680 G4cout <<
"Global offset from middle: " << dLocal << G4endl;
681 G4cout <<
"Resultant global position: " << globalPos << G4endl;
687 G4int* indexOfFoundElement)
const
690 auto lower = std::lower_bound(
sEnd.begin(),
sEnd.end(), S);
691 G4int index = G4int(lower -
sEnd.begin());
692 if (indexOfFoundElement)
693 {*indexOfFoundElement = index;}
699 auto lower = std::lower_bound(
sEnd.begin(),
sEnd.end(), S);
701 std::advance(iter, std::distance(
sEnd.begin(), lower));
719 if (index < 1 || index > (G4int)(
beamline.size()-1))
731 return GetNext(G4int(result -
beamline.begin()));
739 if (index < 0 || index > (G4int)(
beamline.size()-2))
760 G4String suffix =
"_" + std::to_string(i);
761 G4String placementName = acceleratorComponentName + suffix;
762 const auto search =
components.find(placementName);
772 std::vector<const BDSBeamlineElement*> candidates;
773 std::for_each(this->
begin(),
778 if (candidates.empty())
782 auto foundItem = std::find_if(candidates.begin(),
785 {return BDS::EndsWith(el->GetPlacementName(), suffix);});
786 return foundItem != candidates.end() ? *foundItem :
nullptr;
790 {
return search->second;}
799 G4cerr << __METHOD_NAME__ <<
"No element named \""
800 << acceleratorComponentName <<
"\" found for placement number "
802 G4cout <<
"Note, this may be because the element is a bend and split into " << G4endl;
803 G4cout <<
"multiple sections with unique names." << G4endl;
818 for (
const auto& point : boundaryPoints)
820 for (
int i = 0; i < 3; ++i)
844 G4ThreeVector elPosStart = element->
GetPositionStart() - G4ThreeVector(0,0,2*pl).transform(*elRotStart);
845 G4ThreeVector positionMiddle = elPosStart - G4ThreeVector(0,0,endPieceLength*0.5).transform(*elRotStart);
846 G4ThreeVector positionStart = elPosStart - G4ThreeVector(0,0,endPieceLength).transform(*elRotStart);
856 new G4RotationMatrix(*elRotStart),
857 new G4RotationMatrix(*elRotStart),
858 new G4RotationMatrix(*elRotStart),
862 new G4RotationMatrix(*elRotStart),
863 new G4RotationMatrix(*elRotStart),
864 new G4RotationMatrix(*elRotStart),
865 elSPosStart - endPieceLength,
866 elSPosStart - 0.5*endPieceLength,
885 G4RotationMatrix* elRotEnd =
new G4RotationMatrix(*(element->
GetRotationMiddle()));
886 G4ThreeVector elPosEnd = element->
GetPositionEnd() + G4ThreeVector(0,0,pl).transform(*elRotEnd);
887 G4ThreeVector positionMiddle = elPosEnd + G4ThreeVector(0,0,endPieceLength*0.5).transform(*elRotEnd);
888 G4ThreeVector positionEnd = elPosEnd + G4ThreeVector(0,0,endPieceLength).transform(*elRotEnd);
891 G4ThreeVector localUnitY = G4ThreeVector(0,1,0).transform(*elRotEnd);
892 elRotEnd->rotate(CLHEP::pi, localUnitY);
903 new G4RotationMatrix(*elRotEnd),
904 new G4RotationMatrix(*elRotEnd),
905 new G4RotationMatrix(*elRotEnd),
909 new G4RotationMatrix(*elRotEnd),
910 new G4RotationMatrix(*elRotEnd),
911 new G4RotationMatrix(*elRotEnd),
913 elSPosEnd + 0.5*endPieceLength,
914 elSPosEnd + endPieceLength,
925 if (index < 0 || index > (G4int)(
beamline.size()-1))
933 std::vector<G4double> sPos;
936 sPos.push_back(GetSMinimum()/CLHEP::m);
939 if (sPos.size() == 1)
940 {sPos.push_back(1*CLHEP::m);}
946 return (std::abs(
totalAngle) > 0.99 * 2.0 * CLHEP::pi) and (std::abs(
totalAngle) < 1.01 * 2.0 * CLHEP::pi);
958 std::vector<G4int> result;
961 if (element->
GetType() == type)
962 {result.push_back(element->
GetIndex());}
969 std::vector<G4int> result;
972 G4String type = element->
GetType();
973 if (types.find(type) != types.end())
974 {result.push_back(element->
GetIndex());}
981 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.
G4double GetSynchronousTMiddle() const
Accessor.
G4ThreeVector GetPositionMiddle() const
Accessor.
G4double GetStartMomentum() 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.
G4double GetStartKineticEnergy() 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 class that holds the current integrated quantities along a beam line.
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 AddComponent(BDSAcceleratorComponent *component, BDSTiltOffset *tiltOffset=nullptr, BDSSamplerInfo *samplerInfo=nullptr, const BDSBeamlineIntegral *beamlineIntegral=nullptr)
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.
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.
void AddSingleComponent(BDSAcceleratorComponent *component, BDSTiltOffset *tiltOffset=nullptr, BDSSamplerInfo *samplerInfo=nullptr, const BDSBeamlineIntegral *beamlineIntegral=nullptr)
std::map< G4String, BDSBeamlineElement * > components
Map of objects by placement name stored in this beam line.
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())