BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSFieldMagMultipoleOuterOld.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 "BDSFieldMagMultipoleOuterOld.hh"
19
20#include "globals.hh"
21#include "G4RotationMatrix.hh"
22#include "G4ThreeVector.hh"
23#include "G4TwoVector.hh"
24
25#include "CLHEP/Units/PhysicalConstants.h"
26
27#include <cmath>
28#include <vector>
29
30BDSFieldMagMultipoleOuterOld::BDSFieldMagMultipoleOuterOld(G4int orderIn,
31 G4double poleTipRadiusIn,
32 const BDSFieldMag* innerFieldIn,
33 G4bool kPositive,
34 G4double arbitraryScaling):
35 order(orderIn),
36 normalisation(1), // we have to get field first to calculate the normalisation which uses it, so start with 1
37 positiveField(kPositive),
38 poleTipRadius(poleTipRadiusIn)
39{
40 G4int nPoles = 2*order;
41
42 // prepare vector of infinite wire current sources
43 G4TwoVector firstCurrent(poleTipRadius, 0);
44 for (G4int i = 0; i < nPoles; ++i)
45 {
46 G4TwoVector c = firstCurrent; // copy it
47 c.rotate((G4double)i*CLHEP::twopi / nPoles); // rotate copy
48 currents.push_back(c);
49 }
50
51 // query inner field - at point just outside pole tip
52 G4ThreeVector poleTipPoint = G4ThreeVector(0, poleTipRadius, 0);
53 G4double angleOffset = CLHEP::twopi/(G4double)nPoles;
54 poleTipPoint.rotateZ(0.5*angleOffset); // rotate from 0,1 to the pole position (different for each magnet).
55 G4ThreeVector fieldAtPoleTip = innerFieldIn->GetField(poleTipPoint,/*t=*/0);
56 G4double fieldAtPoleTipMag = fieldAtPoleTip.mag();
57
58 // we query this field object but with the normalisation initialised to 1 so it won't
59 // affect the result despite using the same code
60 // the inner field is by default OFF just now so won't affect this
61 G4ThreeVector rawOuterlFieldAtPoleTip = GetField(poleTipPoint);
62 G4double rawOuterlFieldAtPoleTipMag = rawOuterlFieldAtPoleTip.mag();
63
64 // normalisation
65 normalisation = arbitraryScaling * fieldAtPoleTipMag / rawOuterlFieldAtPoleTipMag;
66 if (!std::isfinite(normalisation))
67 {
68 normalisation = 0;
69 finiteStrength = false;
70 }
71}
72
73G4ThreeVector BDSFieldMagMultipoleOuterOld::GetField(const G4ThreeVector& position,
74 const G4double /*t*/) const
75{
76 G4TwoVector pos(position.x(), position.y());
77
78 // temporary variables
79 G4TwoVector result;
80 G4TwoVector cToPos;
81 G4double cToPosMag = 0;
82 G4double reciprocal = 0;
83 G4TwoVector cToPosPerp;
84
85 // loop over linear sum from all infinite wire sources
86 G4int pole = 1; // counter
87 const G4double spatialLimit = 6; // mm
88 G4bool closeToPole = false;
89 for (const auto& c : currents)
90 {
91 cToPos = pos - c; // distance to this wire
92 cToPosMag = cToPos.mag();
93 if (cToPosMag < spatialLimit)
94 {// we're close to a pole
95 // for the contribution from this pole, resample at spatial limit r
96 // from the current point - will give same direction
97 pos += cToPos.unit() * spatialLimit;
98 cToPos = pos - c;
99 cToPosMag = cToPos.mag();
100 closeToPole = true;
101 }
102
103 reciprocal = 1/cToPosMag;
104 if (!std::isnormal(reciprocal))
105 {reciprocal = 1.0;} // protect against bad values
106 cToPosPerp = G4TwoVector(-cToPos.y(), cToPos.x());
107 G4TwoVector val = std::pow(-1, pole+1)*cToPosPerp.unit() * reciprocal;
108 if (std::isfinite(val.x()) && std::isfinite(val.y())) // tolerate bad values
109 {result += val;}
110 pole++;
111 }
112
113 // limit to pole tip maximum - 0.1 empirical factor to match
114 if (closeToPole)
115 {result = result.unit()*0.1;}
116
117 // get sign right to match convention
118 if (positiveField)
119 {result *= -1;}
120
121 // normalisation
122 result *= normalisation;
123
124 return G4ThreeVector(result.x(), result.y(), 0);
125}
G4bool positiveField
Sign of magnetic field.
virtual G4ThreeVector GetField(const G4ThreeVector &position, const double t=0) const
Access the field value.
std::vector< G4TwoVector > currents
Locations of inifite wire current sources.
G4double normalisation
Storage of the overal normalisation factor.
Interface for static magnetic fields that may or may not be local.
virtual G4ThreeVector GetField(const G4ThreeVector &position, const G4double t=0) const =0