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) Royal Holloway,
3University of London 2001 - 2024.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "BDSFieldMagMultipoleOuterOld.hh"
20
21#include "globals.hh"
22#include "G4RotationMatrix.hh"
23#include "G4ThreeVector.hh"
24#include "G4TwoVector.hh"
25
26#include "CLHEP/Units/PhysicalConstants.h"
27
28#include <cmath>
29#include <vector>
30
31BDSFieldMagMultipoleOuterOld::BDSFieldMagMultipoleOuterOld(G4int orderIn,
32 G4double poleTipRadiusIn,
33 const BDSFieldMag* innerFieldIn,
34 G4bool kPositive,
35 G4double arbitraryScaling):
36 order(orderIn),
37 normalisation(1), // we have to get field first to calculate the normalisation which uses it, so start with 1
38 positiveField(kPositive),
39 poleTipRadius(poleTipRadiusIn)
40{
41 G4int nPoles = 2*order;
42
43 // prepare vector of infinite wire current sources
44 G4TwoVector firstCurrent(poleTipRadius, 0);
45 for (G4int i = 0; i < nPoles; ++i)
46 {
47 G4TwoVector c = firstCurrent; // copy it
48 c.rotate((G4double)i*CLHEP::twopi / nPoles); // rotate copy
49 currents.push_back(c);
50 }
51
52 // query inner field - at point just outside pole tip
53 G4ThreeVector poleTipPoint = G4ThreeVector(0, poleTipRadius, 0);
54 G4double angleOffset = CLHEP::twopi/(G4double)nPoles;
55 poleTipPoint.rotateZ(0.5*angleOffset); // rotate from 0,1 to the pole position (different for each magnet).
56 G4ThreeVector fieldAtPoleTip = innerFieldIn->GetField(poleTipPoint,/*t=*/0);
57 G4double fieldAtPoleTipMag = fieldAtPoleTip.mag();
58
59 // we query this field object but with the normalisation initialised to 1 so it won't
60 // affect the result despite using the same code
61 // the inner field is by default OFF just now so won't affect this
62 G4ThreeVector rawOuterlFieldAtPoleTip = GetField(poleTipPoint);
63 G4double rawOuterlFieldAtPoleTipMag = rawOuterlFieldAtPoleTip.mag();
64
65 // normalisation
66 normalisation = arbitraryScaling * fieldAtPoleTipMag / rawOuterlFieldAtPoleTipMag;
67 if (!std::isfinite(normalisation))
68 {
69 normalisation = 0;
70 finiteStrength = false;
71 }
72}
73
74G4ThreeVector BDSFieldMagMultipoleOuterOld::GetField(const G4ThreeVector& position,
75 const G4double /*t*/) const
76{
77 G4TwoVector pos(position.x(), position.y());
78
79 // temporary variables
80 G4TwoVector result;
81 G4TwoVector cToPos;
82 G4double cToPosMag = 0;
83 G4double reciprocal = 0;
84 G4TwoVector cToPosPerp;
85
86 // loop over linear sum from all infinite wire sources
87 G4int pole = 1; // counter
88 const G4double spatialLimit = 6; // mm
89 G4bool closeToPole = false;
90 for (const auto& c : currents)
91 {
92 cToPos = pos - c; // distance to this wire
93 cToPosMag = cToPos.mag();
94 if (cToPosMag < spatialLimit)
95 {// we're close to a pole
96 // for the contribution from this pole, resample at spatial limit r
97 // from the current point - will give same direction
98 pos += cToPos.unit() * spatialLimit;
99 cToPos = pos - c;
100 cToPosMag = cToPos.mag();
101 closeToPole = true;
102 }
103
104 reciprocal = 1/cToPosMag;
105 if (!std::isnormal(reciprocal))
106 {reciprocal = 1.0;} // protect against bad values
107 cToPosPerp = G4TwoVector(-cToPos.y(), cToPos.x());
108 G4TwoVector val = std::pow(-1, pole+1)*cToPosPerp.unit() * reciprocal;
109 if (std::isfinite(val.x()) && std::isfinite(val.y())) // tolerate bad values
110 {result += val;}
111 pole++;
112 }
113
114 // limit to pole tip maximum - 0.1 empirical factor to match
115 if (closeToPole)
116 {result = result.unit()*0.1;}
117
118 // get sign right to match convention
119 if (positiveField)
120 {result *= -1;}
121
122 // normalisation
123 result *= normalisation;
124
125 return G4ThreeVector(result.x(), result.y(), 0);
126}
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