21#include "BDSAcceleratorComponent.hh"
22#include "BDSBeamPipeInfo.hh"
23#include "BDSBendBuilder.hh"
24#include "BDSComponentFactory.hh"
26#include "BDSException.hh"
27#include "BDSFieldType.hh"
28#include "BDSGlobalConstants.hh"
29#include "BDSIntegratorSet.hh"
30#include "BDSIntegratorType.hh"
31#include "BDSIntegratorSetType.hh"
32#include "BDSMagnetStrength.hh"
34#include "BDSMagnet.hh"
35#include "BDSMagnetOuterInfo.hh"
36#include "BDSModulatorInfo.hh"
37#include "BDSUtilities.hh"
39#include "parser/element.h"
40#include "parser/elementtype.h"
42#include "G4Transform3D.hh"
50 return !(finiteAngle || finiteField);
58 G4double incomingFaceAngle,
59 G4double outgoingFaceAngle,
60 G4bool buildFringeFields,
65 const G4String baseName = elementName;
68 const G4double arcLength = element->
l * CLHEP::m;
69 const G4double angle = (*st)[
"angle"];
70 G4double fint = element->
fint;
71 G4double fintx = element->
fintx;
72 G4double hgap = element->
hgap * CLHEP::m;
73 G4double synchronousT0AtStart = (*st)[
"synchronousT0"];
74 G4double synchronousT0AtEnd = synchronousT0AtStart + (arcLength/CLHEP::c_light);
75 G4double synchronousT0AtMiddle = synchronousT0AtStart + (0.5*arcLength/CLHEP::c_light);
76 (*st)[
"synchronousT0"] = synchronousT0AtMiddle;
82 G4bool buildFringeIncoming = buildFringeFields;
83 G4bool buildFringeOutgoing = buildFringeFields;
86 BDSFieldType dipoleFieldType = finiteK1 ? BDSFieldType::dipolequadrupole : BDSFieldType::dipole;
88 if (buildFringeFields)
93 {buildFringeIncoming =
false;}
95 {buildFringeOutgoing =
false;}
106 {buildFringeIncoming =
true;}
108 {buildFringeOutgoing =
true;}
117 {buildFringeIncoming =
false;}
119 {buildFringeOutgoing =
false;}
126 if (prevElement->
type == ElementType::_SBEND)
128 buildFringeIncoming =
false;
130 {
throw BDSException( __METHOD_NAME__, prevElement->name +
" e2 clashes with " + elementName +
" e1");}
135 if (nextElement->
type == ElementType::_SBEND)
136 {buildFringeOutgoing =
false;}
142 buildFringeIncoming =
false;
143 buildFringeOutgoing =
false;
154 buildFringeIncoming =
false;
155 buildFringeOutgoing =
false;
183 vacuumField->SetModulatorInfo(fieldModulator);
185 BDSFieldType::dipole,
209 G4double centralArcLength = arcLength;
210 G4double centralAngle = angle;
211 G4double oneFringeAngle = 0;
213 {oneFringeAngle = (thinElementArcLength / arcLength) * angle;}
215 if (buildFringeIncoming)
217 centralArcLength -= thinElementArcLength;
218 centralAngle -= oneFringeAngle;
220 if (buildFringeOutgoing)
222 centralArcLength -= thinElementArcLength;
223 centralAngle -= oneFringeAngle;
227 G4double semiAngle = centralAngle / (G4double) nSBends;
228 G4double semiArcLength = centralArcLength / (G4double) nSBends;
231 (*semiStrength)[
"angle"] = semiAngle;
232 (*semiStrength)[
"length"] = semiArcLength;
234 G4double zExtentIn = 0;
235 G4double zExtentOut = 0;
236 G4bool fadeIn =
true;
237 G4bool fadeOut =
true;
245 if (incomingFaceAngle > 0)
246 {zExtentIn = 0.5*horizontalWidth*std::tan(incomingFaceAngle - 0.5*std::abs(semiAngle));}
247 else if (incomingFaceAngle < 0)
248 {zExtentIn = 0.5*horizontalWidth*std::tan(0.5*std::abs(semiAngle) + incomingFaceAngle);}
249 if (outgoingFaceAngle > 0)
250 {zExtentOut = 0.5*horizontalWidth*std::tan(outgoingFaceAngle - 0.5*std::abs(semiAngle));}
251 else if (outgoingFaceAngle < 0)
252 {zExtentOut = 0.5*horizontalWidth*std::tan(0.5*std::abs(semiAngle) + outgoingFaceAngle);}
255 if (std::abs(zExtentIn) < semiArcLength/4.0)
257 if (std::abs(zExtentOut) < semiArcLength/4.0)
261 G4String centralName = baseName +
"_even_ang";
267 0.5*semiAngle, 0.5*semiAngle, bpInfo,
277 semiVacuumField->SetModulatorInfo(fieldModulator);
279 BDSFieldType::dipole,
288 mgInfo->name = centralName;
304 G4double minimalRadius = 2*magnetOuterInfoCheck->MinimumIntersectionRadiusRequired();
306 if (!magnetOuterInfoCheck->hStyle)
308 switch (magnetOuterInfoCheck->geometryType.underlying())
310 case BDSMagnetGeometryType::polescircular:
311 case BDSMagnetGeometryType::polesfacet:
312 case BDSMagnetGeometryType::polesfacetcrop:
313 case BDSMagnetGeometryType::polessquare:
315 minimalRadius *= element->yokeOnInside ? 2.0 : 0.5;
323 delete magnetOuterInfoCheck;
326 if (buildFringeIncoming)
328 G4double e1 = element->
e1;
336 BDSMagnetStrength* fringeStIn = BDS::GetFringeMagnetStrength(element, st, oneFringeAngle,
337 e1, element->
e2, fintx,
true);
338 (*fringeStIn)[
"synchronousT0"] = synchronousT0AtStart;
339 G4String segmentName = baseName +
"_e1_fringe";
340 G4double fringeAngleIn = 0.5*oneFringeAngle - incomingFaceAngle;
341 G4double fringeAngleOut = 0.5*oneFringeAngle + incomingFaceAngle;
343 segmentName, fringeStIn, brho,
344 integratorSet, dipoleFieldType, fieldModulator);
354 G4double segmentAngleIn = 0;
355 G4double segmentAngleOut = 0;
356 G4int numberOfUniqueComponents = 1;
358 G4bool centralWedgeUsed =
false;
359 const G4int numSegmentsEitherSide = (nSBends - 1) / 2;
360 for (G4int i = 0; i < nSBends; ++i)
362 G4String name = baseName;
363 if (i < numSegmentsEitherSide)
366 {oneBend = centralWedge;}
369 name +=
"_"+std::to_string(numberOfUniqueComponents);
370 numberOfUniqueComponents++;
371 BDS::UpdateSegmentAngles(i,nSBends,semiAngle,incomingFaceAngle,outgoingFaceAngle,segmentAngleIn,segmentAngleOut);
373 segmentAngleIn, segmentAngleOut, semiStrength,
374 brho, integratorSet, yokeOnLeft, semiOuterField);
380 name +=
"_"+std::to_string(numberOfUniqueComponents);
381 numberOfUniqueComponents++;
382 segmentAngleIn = 0.5*semiAngle - incomingFaceAngle;
383 segmentAngleOut = 0.5*semiAngle;
385 segmentAngleIn, segmentAngleOut, semiStrength,
386 brho, integratorSet, yokeOnLeft, semiOuterField);
389 {oneBend = centralWedge;}
392 else if (i > numSegmentsEitherSide)
395 {oneBend = centralWedge;}
398 name +=
"_"+std::to_string(numberOfUniqueComponents);
399 numberOfUniqueComponents++;
400 BDS::UpdateSegmentAngles(i,nSBends,semiAngle,incomingFaceAngle,outgoingFaceAngle,segmentAngleIn,segmentAngleOut);
402 segmentAngleIn, segmentAngleOut, semiStrength,
403 brho, integratorSet, yokeOnLeft, semiOuterField);
407 if (i == (nSBends-1))
409 name +=
"_"+std::to_string(numberOfUniqueComponents);
410 numberOfUniqueComponents++;
411 segmentAngleIn = 0.5*semiAngle;
412 segmentAngleOut = 0.5*semiAngle - outgoingFaceAngle;
414 segmentAngleIn, segmentAngleOut, semiStrength,
415 brho, integratorSet, yokeOnLeft, semiOuterField);
418 {oneBend = centralWedge;}
422 {oneBend = centralWedge;}
427 centralWedgeUsed = centralWedgeUsed || (oneBend == centralWedge);
430 if (!centralWedgeUsed)
431 {
delete centralWedge;}
434 if (buildFringeOutgoing)
436 G4double e2 = element->
e2;
444 BDSMagnetStrength* fringeStOut = BDS::GetFringeMagnetStrength(element, st, oneFringeAngle,
445 element->
e1, e2, fintx,
false);
446 (*fringeStOut)[
"synchronousT0"] = synchronousT0AtEnd;
447 G4double fringeAngleIn = 0.5*oneFringeAngle + outgoingFaceAngle;
448 G4double fringeAngleOut = 0.5*oneFringeAngle - outgoingFaceAngle;
449 G4String segmentName = baseName +
"_e2_fringe";
452 segmentName, fringeStOut, brho,
453 integratorSet, dipoleFieldType);
459void BDS::UpdateSegmentAngles(G4int index,
462 G4double incomingFaceAngle,
463 G4double outgoingFaceAngle,
464 G4double& segmentAngleIn,
465 G4double& segmentAngleOut)
469 G4bool central = index == (nSBends - 1) / 2;
472 segmentAngleIn = 0.5*semiAngle;
473 segmentAngleOut = 0.5*semiAngle;
477 G4bool firstHalf = index + 1 < (nSBends + 1) / 2;
478 G4int numberToFadeOver = (nSBends - 1) / 2;
481 G4double delta = incomingFaceAngle / (G4double) numberToFadeOver;
482 G4double inputFaceAngle = incomingFaceAngle - ((G4double)index * delta);
483 G4double outputFaceAngle = incomingFaceAngle - ((G4double)(index+1) * delta);
485 segmentAngleIn = 0.5*semiAngle - inputFaceAngle;
486 segmentAngleOut = 0.5*semiAngle + outputFaceAngle;
490 G4double delta = outgoingFaceAngle / (G4double) numberToFadeOver;
491 G4int secondHalfIndex = index - ((nSBends + 1) / 2);
493 G4double inputFaceAngle = outgoingFaceAngle - ( (G4double)(numberToFadeOver - secondHalfIndex) * delta);
494 G4double outputFaceAngle = outgoingFaceAngle - ( (G4double)(numberToFadeOver - (secondHalfIndex + 1)) * delta);
496 segmentAngleIn = 0.5*semiAngle + inputFaceAngle;
497 segmentAngleOut = 0.5*semiAngle - outputFaceAngle;
502 const G4String& name,
519 magnetOuterInfo->name = name;
524 BDSFieldType dipoleFieldType = finiteK1 ? BDSFieldType::dipolequadrupole : BDSFieldType::dipole;
537 vacuumField->SetModulatorInfo(fieldModulator);
560 G4double incomingFaceAngle,
561 G4double outgoingFaceAngle,
562 G4bool buildFringeFields,
565 const G4String name = elementName;
570 G4bool buildFringeIncoming = buildFringeFields;
571 G4bool buildFringeOutgoing = buildFringeFields;
572 G4double fint = element->
fint;
573 G4double fintx = element->
fintx;
574 G4double hgap = element->
hgap * CLHEP::m;
577 const G4double angle = (*st)[
"angle"];
578 const G4double arcLength = (*st)[
"length"];
580 G4double synchronousT0AtStart = (*st)[
"synchronousT0"];
581 G4double synchronousT0AtEnd = synchronousT0AtStart + (arcLength/CLHEP::c_light);
582 G4double synchronousT0AtMiddle = synchronousT0AtStart + (0.5*arcLength/CLHEP::c_light);
583 (*st)[
"synchronousT0"] = synchronousT0AtMiddle;
590 BDSFieldType dipoleFieldType = finiteK1 ? BDSFieldType::dipolequadrupole : BDSFieldType::dipole;
594 G4double incomingFaceAngleWRTSBend = incomingFaceAngle + angle*0.5;
595 G4double outgoingFaceangleWRTSBend = outgoingFaceAngle + angle*0.5;
597 {buildFringeIncoming =
false;}
599 {buildFringeOutgoing =
false;}
610 {buildFringeIncoming =
true;}
612 {buildFringeOutgoing =
true;}
615 G4double trackingPolefaceAngleIn = element->
e1;
616 G4double trackingPolefaceAngleOut = element->
e2;
619 trackingPolefaceAngleIn += angle*0.5;
620 trackingPolefaceAngleOut += angle*0.5;
623 G4double e1 = -incomingFaceAngle;
624 G4double e2 = -outgoingFaceAngle;
630 throw BDSException(__METHOD_NAME__, prevElement->name +
" has finite e2!\n Clashes with " + elementName +
" with finite e1");
632 if (prevElement->
type == ElementType::_RBEND)
634 buildFringeIncoming =
false;
642 throw BDSException(__METHOD_NAME__ + nextElement->name +
" has finite e1!\n Clashes with " + elementName +
" with finite e2");
644 if (nextElement->
type == ElementType::_RBEND)
646 buildFringeOutgoing =
false;
653 buildFringeIncoming =
false;
654 buildFringeOutgoing =
false;
668 G4double angleIn = incomingFaceAngle;
669 G4double angleOut = outgoingFaceAngle;
670 G4double fringeInOutputAngle = 0;
671 G4double centralInputFaceAngle = angleIn;
672 G4double centralOutputFaceAngle = angleOut;
673 G4double fringeOutInputAngle = 0;
674 G4double centralArcLength = arcLength;
675 G4double centralAngle = angle;
676 G4double oneFringeAngle = 0;
678 {oneFringeAngle = (thinElementArcLength / arcLength) * angle;}
680 if (buildFringeIncoming && buildFringeOutgoing)
682 centralArcLength -= 2*thinElementArcLength;
683 centralAngle -= 2*oneFringeAngle;
684 angleIn = e1 + (0.5*oneFringeAngle - 0.5*angle);
685 fringeInOutputAngle = -angleIn;
686 centralInputFaceAngle = e1;
687 centralOutputFaceAngle = e2;
688 fringeOutInputAngle = - (e2 + (0.5*oneFringeAngle - 0.5*angle));
689 angleOut = -fringeOutInputAngle;
691 else if (buildFringeIncoming)
693 centralArcLength -= thinElementArcLength;
694 centralAngle -= oneFringeAngle;
695 angleIn = e1 + (0.5*oneFringeAngle - 0.5*angle);
696 fringeInOutputAngle = -angleIn;
697 centralInputFaceAngle = e1 + 0.5*oneFringeAngle;
698 centralOutputFaceAngle = e2 - 0.5*oneFringeAngle;
700 else if (buildFringeOutgoing)
702 centralArcLength -= thinElementArcLength;
703 centralAngle -= oneFringeAngle;
704 centralInputFaceAngle = e1 - 0.5*oneFringeAngle;
705 centralOutputFaceAngle = e2 + 0.5*oneFringeAngle;
706 fringeOutInputAngle = - (e2 + (0.5*oneFringeAngle - 0.5*angle));;
707 angleOut = e2 + (0.5*oneFringeAngle - 0.5*angle);;
713 centralInputFaceAngle = e1;
714 centralOutputFaceAngle = e2;
717 if (buildFringeIncoming)
719 G4double trackingPolefaceAngle = trackingPolefaceAngleIn;
725 {trackingPolefaceAngle -= element->
e1;}
727 BDSMagnetStrength* fringeStIn = BDS::GetFringeMagnetStrength(element, st, oneFringeAngle,
728 trackingPolefaceAngle, trackingPolefaceAngleOut,
730 (*fringeStIn)[
"synchronousT0"] = synchronousT0AtStart;
731 G4String fringeName = name +
"_e1_fringe";
737 integratorSet, dipoleFieldType, fieldModulator);
742 (*st)[
"length"] = centralArcLength;
743 (*st)[
"angle"] = centralAngle;
750 mgInfo->name = elementName;
759 vacuumField->SetModulatorInfo(fieldModulator);
761 BDSFieldType::dipole,
775 elementName+
"_centre",
786 if (buildFringeOutgoing)
788 G4double trackingPolefaceAngle = trackingPolefaceAngleOut;
794 {trackingPolefaceAngle -= element->
e2;}
795 BDSMagnetStrength* fringeStOut = BDS::GetFringeMagnetStrength(element, st, oneFringeAngle,
796 trackingPolefaceAngleIn, trackingPolefaceAngle,
798 (*fringeStOut)[
"synchronousT0"] = synchronousT0AtEnd;
799 G4String fringeName = name +
"_e2_fringe";
804 integratorSet, dipoleFieldType);
814 const G4String& name,
822 beamPipeInfo->
beamPipeType = BDSBeamPipeType::circularvacuum;
824 angleIn, angleOut, beamPipeInfo);
825 magnetOuterInfo->geometryType = BDSMagnetGeometryType::none;
826 magnetOuterInfo->name = name;
827 magnetOuterInfo->buildEndPieces =
false;
838 vacuumField->SetModulatorInfo(fieldModulator);
840 return new BDSMagnet(BDSMagnetType::dipolefringe,
853 G4double incomingFaceAngle,
854 G4double outgoingFaceAngle,
855 G4double aperturePrecision)
862 G4double totalAngle = std::abs(angle) + std::abs(incomingFaceAngle) + std::abs(outgoingFaceAngle);
863 G4int nSBends = (G4int) ceil(std::sqrt(length*totalAngle/2/aperturePrecision));
868 if (nSBends % 2 == 0)
871 G4cout << __METHOD_NAME__ <<
" splitting sbend into " << nSBends <<
" sbends" << G4endl;
884 {intType = integratorSet->
Integrator(BDSFieldType::dipolequadrupole);}
894 G4double fringeAngle,
902 (*fringeSt)[
"angle"] = fringeAngle;
903 (*fringeSt)[
"e1"] = e1;
904 (*fringeSt)[
"e2"] = e2;
905 (*fringeSt)[
"fint"] = element->
fint;
906 (*fringeSt)[
"fintx"] = fintx;
907 (*fringeSt)[
"fintk2"] = element->
fintK2;
908 (*fringeSt)[
"fintk2"] = element->
fintxK2;
909 (*fringeSt)[
"hgap"] = element->
hgap * CLHEP::m;
910 (*fringeSt)[
"isentrance"] = isEntrance;
911 (*fringeSt)[
"h1"] = element->
h1 / CLHEP::m;
912 (*fringeSt)[
"h2"] = element->
h2 / CLHEP::m;
Abstract class that represents a component of an accelerator.
Holder class for all information required to describe a beam pipe model.
BDSBeamPipeType beamPipeType
Public member for direct access.
static G4bool YokeOnLeft(const GMAD::Element *el, const BDSMagnetStrength *st)
static G4double PrepareHorizontalWidth(GMAD::Element const *el, G4double defaultHorizontalWidth=-1)
Prepare the element horizontal width in Geant4 units - if not set, use the global default.
static G4Transform3D CreateFieldTransform(const BDSTiltOffset *tiltOffset)
Create a transform from a tilt offset. If nullptr, returns identity transform.
static BDSFieldInfo * PrepareMagnetOuterFieldInfo(const BDSMagnetStrength *vacuumSt, const BDSFieldType &fieldType, const BDSBeamPipeInfo *bpInfo, const BDSMagnetOuterInfo *outerInfo, const G4Transform3D &fieldTransform, const BDSIntegratorSet *integratorSetIn, G4double brhoIn, G4double outerFieldScaling=1.0, BDSModulatorInfo *modulatorInfo=nullptr)
Prepare the field definition for the yoke of a magnet.
static BDSMagnetOuterInfo * PrepareMagnetOuterInfo(const G4String &elementNameIn, const GMAD::Element *el, const BDSMagnetStrength *st, const BDSBeamPipeInfo *beamPipe, G4double defaultHorizontalWidth=-1, G4double defaultVHRatio=1.0, G4double defaultCoilWidthFraction=-1, G4double defaultCoilHeightFraction=-1)
static void CheckBendLengthAngleWidthCombo(G4double arcLength, G4double angle, G4double horizontalWidth, const G4String &name="not given")
static BDSBeamPipeInfo * PrepareBeamPipeInfo(GMAD::Element const *el, const G4ThreeVector &inputFaceNormal=G4ThreeVector(0, 0,-1), const G4ThreeVector &outputFaceNormal=G4ThreeVector(0, 0, 1))
static G4double ScalingFieldOuter(const GMAD::Element *ele)
Get the scaling factor for a particular outer field depending on the global and individual setting.
General exception with possible name of object and message.
All info required to build complete field of any type.
static BDSGlobalConstants * Instance()
Access method.
Which integrator to use for each type of magnet / field object.
G4bool IsMatrixIntegratorSet() const
Accessor for bool of is the integrator set matrix style.
BDSIntegratorType Integrator(const BDSFieldType field) const
Get appropriate integrator based on the field type.
A class that hold multiple accelerator components.
void AddComponent(BDSAcceleratorComponent *component)
Add a component to the line.
Efficient storage of magnet strengths.
Abstract base class that implements features common to all magnets.
Holder class for all information required to describe a modulator.
G4bool ZeroStrengthDipole(const BDSMagnetStrength *st)
Return whether finite angle or field for a dipole.
G4int CalculateNSBendSegments(G4double length, G4double angle, G4double incomingFaceAngle=0, G4double outgoingFaceAngle=0, G4double aperturePrecision=1.0)
BDSMagnet * BuildSingleSBend(const GMAD::Element *element, const G4String &name, G4double arcLength, G4double angle, G4double angleIn, G4double angleOut, const BDSMagnetStrength *strength, G4double brho, const BDSIntegratorSet *integratorSet, G4bool yokeOnLeft, const BDSFieldInfo *outerFieldIn, BDSModulatorInfo *fieldModulator=nullptr)
Function to return a single sector bend section.
BDSMagnet * BuildDipoleFringe(const GMAD::Element *element, G4double angleIn, G4double angleOut, const G4String &name, BDSMagnetStrength *st, G4double brho, const BDSIntegratorSet *integratorSet, BDSFieldType dipoleFieldType, BDSModulatorInfo *fieldModulator=nullptr)
BDSLine * BuildRBendLine(const G4String &elementName, const GMAD::Element *element, const GMAD::Element *prevElement, const GMAD::Element *nextElement, G4double brho, BDSMagnetStrength *st, const BDSIntegratorSet *integratorSet, G4double incomingFaceAngle, G4double outgoingFaceAngle, G4bool buildFringeFields, BDSModulatorInfo *fieldModulator=nullptr)
BDSIntegratorType GetDipoleIntegratorType(const BDSIntegratorSet *integratorSet, const GMAD::Element *element)
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())
BDSAcceleratorComponent * BuildSBendLine(const G4String &elementName, const GMAD::Element *element, BDSMagnetStrength *st, G4double brho, const BDSIntegratorSet *integratorSet, G4double incomingFaceAngle, G4double outgoingFaceAngle, G4bool buildFringeFields, const GMAD::Element *prevElement, const GMAD::Element *nextElement, BDSModulatorInfo *fieldModulator=nullptr)
Parser namespace for GMAD language. Combination of Geant4 and MAD.
double hgap
half distance of pole separation for purposes of fringe fields - 'half gap'
double fintx
fringe field integral at the dipole exit
double h2
output pole face curvature for bends
double h1
input pole face curvature for bends
double fintxK2
second fringe field integral at the dipole exit - for TRANSPORT matching
double fint
fringe field integral at the dipole entrance
double e2
output pole face rotation for bends
double e1
input pole face rotation for bends
double fintK2
second fringe field integral at the dipole entrance - for TRANSPORT matching
ElementType type
element enum