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
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);
148 fringeField_l.setX0(s0);
149 fringeField_r.setLambda(lambda_r);
150 fringeField_r.setX0(s0);
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 {
156 return {fringeField_l.getX0(), fringeField_l.getLambda(), fringeField_r.getLambda()};
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(
166 s, fringeField_l.getX0(), fringeField_l.getLambda(),
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
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}
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition PETE.h:732
const std::string name
double integrate(const double &a, const double &s0, const double &lambdaleft, const double &lambdaright, const int &n)
Definition tanhDeriv.cpp:66
virtual void visitMultipoleT(const MultipoleT &)=0
Apply the algorithm to an arbitrary multipole.
Component(const std::string &name)
Constructor with given name.
Definition Component.cpp:53
PartBunchBase< double, 3 > * RefPartBunch_m
Definition Component.h:191
bool getFlagDeleteOnTransverseExit() const
virtual void setElementLength(double length)
Set design length.
ElementBase(const std::string &name)
Constructor with given name.
static void setTanhDiffIndices(size_t n)
Definition Tanh.cpp:77
Vector_t toMagnetCoords(const Vector_t &R)
void setRotation(double rot)
std::size_t getTransMaxOrder() const
Definition MultipoleT.h:151
std::vector< double > transProfile_m
Definition MultipoleT.h:283
double entryOffset_m
Definition MultipoleT.h:292
void setScalingName(const std::string &name)
Vector_t localCartesianToOpalCartesian(const Vector_t &r)
std::size_t maxFOrder_m
Definition MultipoleT.h:279
void setBendAngle(double angle, bool variableRadius)
std::size_t maxXOrder_m
Definition MultipoleT.h:281
double entranceAngle_m
Definition MultipoleT.h:287
double getFringeDeriv(const std::size_t &n, const double &s)
size_t transMaxOrder_m
Definition MultipoleT.h:284
void setElementLength(double length) override
endfieldmodel::Tanh fringeField_r
Definition MultipoleT.h:277
endfieldmodel::Tanh fringeField_l
Definition MultipoleT.h:276
void setEntranceAngle(double entranceAngle)
void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
ElementBase * clone() const override
std::string scalingName_m
Definition MultipoleT.h:299
EMField & getField() override
Definition MultipoleT.h:107
void accept(BeamlineVisitor &visitor) const override
double verticalApert_m
Definition MultipoleT.h:294
void setAperture(const double &vertAp, const double &horizAp)
double rotation_m
Definition MultipoleT.h:288
void setMaxOrder(size_t orderZ, size_t orderX)
double length_m
Definition MultipoleT.h:286
const std::vector< double > & getTransProfile() const
Definition MultipoleT.h:157
double localCartesianRotation()
bool apply(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) override
void finalise() override
Vector_t rotateFrame(const Vector_t &R) const
double bendAngle_m
Definition MultipoleT.h:289
bool insideAperture(const Vector_t &R) const
double getTransDeriv(const std::size_t &n, const double &x) const
BGeometryBase & getGeometry() override
bool bends() const override
void initialiseTimeDepencencies() const
std::shared_ptr< AbstractTimeDependence > scalingTD_m
Definition MultipoleT.h:300
double getFnDerivS(const std::size_t &n, const double &x, const double &s)
double getFnDerivX(const std::size_t &n, const double &x, const double &s)
void chooseImplementation()
bool variableRadius_m
Definition MultipoleT.h:290
bool insideBoundingBox(const Vector_t &R) const
double boundingBoxLength_m
Definition MultipoleT.h:291
MultipoleT(const std::string &name)
void setFringeField(const double &s0, const double &lambda_left, const double &lambda_right)
std::tuple< double, double, double > getFringeField() const
void setEntryOffset(double offset)
double horizontalApert_m
Definition MultipoleT.h:295
void setBoundingBoxLength(double boundingBoxLength)
void setTransProfile(const std::vector< double > &profile)
std::unique_ptr< MultipoleTBase > implementation_
Definition MultipoleT.h:302
static std::shared_ptr< AbstractTimeDependence > getTimeDependence(std::string name)
Abstract base class for accelerator geometry classes.
Definition Geometry.h:43
Vektor< double, 3 > Vector_t