OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
MultipoleT.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017, Titus Dascalu
3 * Copyright (c) 2018, Martin Duy Tat
4 * Copyright (c) 2019-2023, Chris Rogers
5 * Copyright (c) 2025, Jon Thompson
6 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * 3. Neither the name of STFC nor the names of its contributors may be used to
15 * endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "MultipoleT.h"
32
33#include "BeamlineVisitor.h"
35#include "MultipoleTStraight.h"
38#include <boost/algorithm/string/case_conv.hpp>
39
40using namespace endfieldmodel;
41
42MultipoleT::MultipoleT(const std::string& name)
43 : Component(name) {
45}
46
48 : Component(right),
49 fringeField_l(right.fringeField_l),
50 fringeField_r(right.fringeField_r),
51 maxFOrder_m(right.maxFOrder_m),
52 maxXOrder_m(right.maxXOrder_m),
53 transProfile_m(right.transProfile_m),
54 transMaxOrder_m(right.transMaxOrder_m),
55 length_m(right.length_m),
56 entranceAngle_m(right.entranceAngle_m),
57 rotation_m(right.rotation_m),
58 bendAngle_m(right.bendAngle_m),
59 variableRadius_m(right.variableRadius_m),
60 boundingBoxLength_m(right.boundingBoxLength_m),
61 verticalApert_m(right.verticalApert_m),
62 horizontalApert_m(right.horizontalApert_m),
63 scalingName_m(right.scalingName_m),
64 scalingTD_m(right.scalingTD_m) {
67}
68
70 return new MultipoleT(*this);
71}
72
73void MultipoleT::accept(BeamlineVisitor& visitor) const {
75 visitor.visitMultipoleT(*this);
76}
77
79 Vector_t R_prime(3), R_pprime(3);
84 // 1st rotation
85 R_prime[0] = R[0] * std::cos(rotation_m) + R[1] * std::sin(rotation_m);
86 R_prime[1] = - R[0] * std::sin(rotation_m) + R[1] * std::cos(rotation_m);
87 R_prime[2] = R[2];
88 // 2nd rotation
89 R_pprime[0] = R_prime[2] * std::sin(entranceAngle_m) +
90 R_prime[0] * std::cos(entranceAngle_m);
91 R_pprime[1] = R_prime[1];
92 R_pprime[2] = R_prime[2] * std::cos(entranceAngle_m) -
93 R_prime[0] * std::sin(entranceAngle_m);
94 return R_pprime;
95
96}
97
99 return std::abs(R[1]) <= verticalApert_m / 2.0 &&
100 std::abs(R[0]) <= horizontalApert_m / 2.0;
101}
102
104 return boundingBoxLength_m == 0.0 || fabs(R[2]) <= boundingBoxLength_m / 2.0;
105}
106
109 /* TODO: I'm not sure this is the correct thing to do */
110 Vector_t result = rotateFrame(R);
112 result[2] *= -1; // OPAL uses a different sign convention...
113 implementation_->transformCoords(result);
114 return result;
115}
116
118 Vector_t result;
120 result[0] = implementation_->getBx(magnetCoords);
121 result[1] = implementation_->getBz(magnetCoords);
122 result[2] = implementation_->getBs(magnetCoords);
124 implementation_->transformBField(result, magnetCoords);
125 result[2] *= -1; // OPAL uses a different sign convention...
126 return result;
127}
128
129bool MultipoleT::apply(const Vector_t& R, const Vector_t& /*P*/, const double& t,
130 Vector_t& /*E*/, Vector_t& B) {
131 const Vector_t R_prime = toMagnetCoords(R);
132 bool result;
133 if (insideAperture(R_prime) && insideBoundingBox(R_prime)) {
134 B = getField(R_prime);
135 if (scalingTD_m) {
136 B *= scalingTD_m->getValue(t);
137 }
138 result = false;
139 } else {
140 B = {0.0, 0.0, 0.0};
142 }
143 return result;
144}
145
146void MultipoleT::setFringeField(const double& s0, const double& lambda_l, const double& lambda_r) {
147 fringeField_l.setLambda(lambda_l);
149 fringeField_r.setLambda(lambda_r);
151 Tanh::setTanhDiffIndices(2 * maxFOrder_m + 1); // Static table builds highest order encountered
152 implementation_->initialise();
153}
154
155std::tuple<double, double, double> MultipoleT::getFringeField() const {
157}
158
159double MultipoleT::getFringeDeriv(const std::size_t& n, const double& s) {
160 double result;
161 if (n <= 10) {
162 result = (fringeField_l.getTanh(s, static_cast<int>(n)) -
163 fringeField_r.getNegTanh(s, static_cast<int>(n))) / 2;
164 } else {
165 result = tanhderiv::integrate(
167 fringeField_r.getLambda(), static_cast<int>(n));
168 }
169 return result;
170}
171
172double MultipoleT::getTransDeriv(const std::size_t& n, const double& x) const {
173 double func = 0.0;
174 std::size_t transMaxOrder = getTransMaxOrder();
175 if (n > transMaxOrder) {
176 return func;
177 }
178 std::vector<double> temp = getTransProfile();
179 for (std::size_t i = 1; i <= n; i++) {
180 for (std::size_t j = 0; j <= transMaxOrder; j++) {
181 if (j <= transMaxOrder_m - i) {
182 temp[j] = temp[j + 1] * static_cast<double>(j + 1);
183 } else {
184 temp[j] = 0.0;
185 }
186 }
187 }
188 std::size_t k = transMaxOrder - n + 1;
189 while (k != 0) {
190 k--;
191 func = func * x + temp[k];
192 }
193 return func;
194}
195
196double MultipoleT::getFnDerivX(const std::size_t& n, const double& x, const double& s) {
197 if (n == 0) {
198 return getTransDeriv(1, x) * getFringeDeriv(0, s);
199 }
200 double deriv = 0.0;
201 double stepSize = 1e-3;
202 deriv += 1. * implementation_->getFn(n, x - 2. * stepSize, s);
203 deriv += -8. * implementation_->getFn(n, x - stepSize, s);
204 deriv += 8. * implementation_->getFn(n, x + stepSize, s);
205 deriv += -1. * implementation_->getFn(n, x + 2. * stepSize, s);
206 deriv /= 12 * stepSize;
207 return deriv;
208}
209
210double MultipoleT::getFnDerivS(const std::size_t& n, const double& x, const double& s) {
211 if (n == 0) {
212 return getTransDeriv(0, x) * getFringeDeriv(1, s);
213 }
214 double deriv = 0.0;
215 double stepSize = 1e-3;
216 deriv += 1. * implementation_->getFn(n, x, s - 2. * stepSize);
217 deriv += -8. * implementation_->getFn(n, x, s - stepSize);
218 deriv += 8. * implementation_->getFn(n, x, s + stepSize);
219 deriv += -1. * implementation_->getFn(n, x, s + 2. * stepSize);
220 deriv /= 12 * stepSize;
221 return deriv;
222}
223
225 RefPartBunch_m = nullptr;
226}
227
228bool MultipoleT::apply(const size_t& i, const double& t, Vector_t& E, Vector_t& B) {
229 return apply(RefPartBunch_m->R[i], RefPartBunch_m->P[i], t, E, B);
230}
231
232void MultipoleT::setElementLength(double length) {
233 // Base class first
235 // Then me
236 length_m = length;
237 implementation_->initialise();
238}
239
240void MultipoleT::setBendAngle(double angle, bool variableRadius) {
241 // Record information
242 bendAngle_m = angle;
243 variableRadius_m = variableRadius;
245}
246
248 if(bendAngle_m == 0.0) {
249 implementation_ = std::make_unique<MultipoleTStraight>(this);
250 } else if(variableRadius_m) {
251 implementation_ = std::make_unique<MultipoleTCurvedVarRadius>(this);
252 } else {
253 implementation_ = std::make_unique<MultipoleTCurvedConstRadius>(this);
254 }
255 implementation_->initialise();
256}
257
258void MultipoleT::setAperture(const double& vertAp, const double& horizAp) {
259 verticalApert_m = vertAp;
260 horizontalApert_m = horizAp;
261}
262
263void MultipoleT::setBoundingBoxLength(double boundingBoxLength) {
264 boundingBoxLength_m = boundingBoxLength;
265}
266
267void MultipoleT::setTransProfile(const std::vector<double>& profile) {
268 transProfile_m = profile;
269 if(transProfile_m.empty()) {
270 transProfile_m = {0.0};
271 }
272 transMaxOrder_m = transProfile_m.size() - 1;
273}
274
275void MultipoleT::setMaxOrder(size_t orderZ, size_t orderX) {
276 maxFOrder_m = orderZ;
277 maxXOrder_m = orderX;
279}
280
281void MultipoleT::setRotation(double rot) {
282 rotation_m = rot;
283}
284
285void MultipoleT::setEntranceAngle(double entranceAngle) {
286 entranceAngle_m = entranceAngle;
287}
288
289void MultipoleT::setEntryOffset(double offset){
290 entryOffset_m = offset;
291}
292
293bool MultipoleT::bends() const {
294 return transProfile_m[0] != 0 || bendAngle_m != 0.0;
295}
296
298 double& /*startField*/, double& /*endField*/) {
299 RefPartBunch_m = bunch;
300 implementation_->initialise();
301}
302
303void MultipoleT::setScalingName(const std::string& name) {
304 // Element names are stored in upper case
305 scalingName_m = boost::to_upper_copy<std::string>(name);
306}
307
309 scalingTD_m.reset();
310 if (!scalingName_m.empty()) {
312 }
313}
314
316 return implementation_->getGeometry();
317}
318
320 return implementation_->getGeometry();
321}
322
324 return implementation_->localCartesianToOpalCartesian(r);
325}
326
328 return implementation_->localCartesianRotation();
329}
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:732
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
const std::string name
double integrate(const double &a, const double &s0, const double &lambdaleft, const double &lambdaright, const int &n)
Perform Cauchy's integral to find derivative.
Definition: tanhDeriv.cpp:66
constexpr double e
The value of.
Definition: Physics.h:39
ParticlePos_t & R
ParticleAttrib< Vector_t > P
virtual void visitMultipoleT(const MultipoleT &)=0
Apply the algorithm to an arbitrary multipole.
Interface for a single beam element.
Definition: Component.h:50
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
bool getFlagDeleteOnTransverseExit() const
Definition: ElementBase.h:614
virtual void setElementLength(double length)
Set design length.
Definition: ElementBase.h:419
double getNegTanh(double x, int n) const
Returns the value of tanh((x-x0)/lambda) or its derivative.
Definition: Tanh.cpp:56
void setX0(double x0)
Set x0 (flat top length)
Definition: Tanh.h:110
double getX0() const
Return x0 (flat top length)
Definition: Tanh.h:104
void setLambda(double lambda)
Set lambda (end length)
Definition: Tanh.h:107
double getLambda() const
Return lambda (end length)
Definition: Tanh.h:101
double getTanh(double x, int n) const
Returns the value of tanh((x+x0)/lambda) or its derivative.
Definition: Tanh.cpp:45
Vector_t toMagnetCoords(const Vector_t &R)
Definition: MultipoleT.cpp:107
void setRotation(double rot)
Set the angle of rotation of the magnet around its axis To make skew components.
Definition: MultipoleT.cpp:281
std::size_t getTransMaxOrder() const
Get the maximum order in the given transverse profile.
Definition: MultipoleT.h:151
std::vector< double > transProfile_m
List of transverse profile coefficients.
Definition: MultipoleT.h:283
double entryOffset_m
Definition: MultipoleT.h:292
void setScalingName(const std::string &name)
Definition: MultipoleT.cpp:303
Vector_t localCartesianToOpalCartesian(const Vector_t &r)
Definition: MultipoleT.cpp:323
std::size_t maxFOrder_m
Number of terms in z expansion used in calculating field components.
Definition: MultipoleT.h:279
void setBendAngle(double angle, bool variableRadius)
Set the bending angle of the magnet.
Definition: MultipoleT.cpp:240
std::size_t maxXOrder_m
Highest order of polynomial expansions in x.
Definition: MultipoleT.h:281
double entranceAngle_m
Definition: MultipoleT.h:287
double getFringeDeriv(const std::size_t &n, const double &s)
Returns the value of the fringe field n-th derivative at s.
Definition: MultipoleT.cpp:159
size_t transMaxOrder_m
Definition: MultipoleT.h:284
void setElementLength(double length) override
Set the length of the magnet If straight-> Actual length If curved -> Arc length.
Definition: MultipoleT.cpp:232
endfieldmodel::Tanh fringeField_r
Definition: MultipoleT.h:277
endfieldmodel::Tanh fringeField_l
Definition: MultipoleT.h:276
void setEntranceAngle(double entranceAngle)
Set the entrance angle.
Definition: MultipoleT.cpp:285
void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Initialise the MultipoleT.
Definition: MultipoleT.cpp:297
ElementBase * clone() const override
Inheritable copy constructor.
Definition: MultipoleT.cpp:69
std::string scalingName_m
Definition: MultipoleT.h:299
EMField & getField() override
Return a dummy field value.
Definition: MultipoleT.h:107
void accept(BeamlineVisitor &visitor) const override
Accept a beamline visitor.
Definition: MultipoleT.cpp:73
double verticalApert_m
Assume rectangular aperture with these dimensions.
Definition: MultipoleT.h:294
void setAperture(const double &vertAp, const double &horizAp)
Set the aperture dimensions This element only supports a rectangular aperture.
Definition: MultipoleT.cpp:258
double rotation_m
Definition: MultipoleT.h:288
void setMaxOrder(size_t orderZ, size_t orderX)
Set the number of terms used in calculation of field components .
Definition: MultipoleT.cpp:275
double length_m
Magnet parameters.
Definition: MultipoleT.h:286
const std::vector< double > & getTransProfile() const
Get all terms of transverse profile.
Definition: MultipoleT.h:157
double localCartesianRotation()
Definition: MultipoleT.cpp:327
bool apply(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) override
Calculate the field at some arbitrary position If particle is outside field map true is returned,...
Definition: MultipoleT.cpp:129
void finalise() override
Finalise the MultipoleT - sets bunch to nullptr.
Definition: MultipoleT.cpp:224
Vector_t rotateFrame(const Vector_t &R) const
Rotate the frame to account for the rotation and entry angles.
Definition: MultipoleT.cpp:78
double bendAngle_m
Definition: MultipoleT.h:289
bool insideAperture(const Vector_t &R) const
Definition: MultipoleT.cpp:98
double getTransDeriv(const std::size_t &n, const double &x) const
Returns the value of the transverse field n-th derivative at x Transverse field is a polynomial in x...
Definition: MultipoleT.cpp:172
BGeometryBase & getGeometry() override
Return the cell geometry.
Definition: MultipoleT.cpp:315
bool bends() const override
Return true if dipole component not zero.
Definition: MultipoleT.cpp:293
void initialiseTimeDepencencies() const
Definition: MultipoleT.cpp:308
std::shared_ptr< AbstractTimeDependence > scalingTD_m
Definition: MultipoleT.h:300
double getFnDerivS(const std::size_t &n, const double &x, const double &s)
Calculate partial derivative of fn wrt s using a 5-point finite difference formula Error of order ste...
Definition: MultipoleT.cpp:210
double getFnDerivX(const std::size_t &n, const double &x, const double &s)
Calculate partial derivative of fn wrt x using a 5-point finite difference formula Error of order ste...
Definition: MultipoleT.cpp:196
void chooseImplementation()
Definition: MultipoleT.cpp:247
bool variableRadius_m
Definition: MultipoleT.h:290
bool insideBoundingBox(const Vector_t &R) const
Definition: MultipoleT.cpp:103
double boundingBoxLength_m
Definition: MultipoleT.h:291
MultipoleT(const std::string &name)
Constructor.
Definition: MultipoleT.cpp:42
void setFringeField(const double &s0, const double &lambda_left, const double &lambda_right)
Set fringe field model Tanh model used here .
Definition: MultipoleT.cpp:146
std::tuple< double, double, double > getFringeField() const
Get the fringe field model.
Definition: MultipoleT.cpp:155
void setEntryOffset(double offset)
Set the offset of the entry point from the standard position.
Definition: MultipoleT.cpp:289
double horizontalApert_m
Definition: MultipoleT.h:295
void setBoundingBoxLength(double boundingBoxLength)
Set the bounding box size.
Definition: MultipoleT.cpp:263
void setTransProfile(const std::vector< double > &profile)
Set the the transverse profile.
Definition: MultipoleT.cpp:267
std::unique_ptr< MultipoleTBase > implementation_
Definition: MultipoleT.h:302
static std::shared_ptr< AbstractTimeDependence > getTimeDependence(std::string name)
Look up the time dependence that has a given name.
Abstract base class for accelerator geometry classes.
Definition: Geometry.h:43