OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
MultipoleTCurvedVarRadius.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2017, Titus Dascalu
3 * Copyright (c) 2018, Martin Duy Tat
4 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * 3. Neither the name of STFC nor the names of its contributors may be used to
13 * endorse or promote products derived from this software without specific
14 * prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28#include <vector>
29#include "gsl/gsl_sf_pow_int.h"
31#include "MultipoleT.h"
33
38
40 // Record geometry information
41 varRadiusGeometry_m.setElementLength(element_m->getLength() +
42 2.0 * element_m->getEntryOffset());
43 varRadiusGeometry_m.setRadius(element_m->getLength() / element_m->getBendAngle());
44 auto [s0, leftFringe, rightFringe] = element_m->getFringeField();
45 varRadiusGeometry_m.setS0(s0);
46 varRadiusGeometry_m.setLambdaLeft(leftFringe);
47 varRadiusGeometry_m.setLambdaRight(rightFringe);
48 setMaxOrder(element_m->getMaxFOrder(), element_m->getMaxXOrder());
49 // Now work out where the entry point will be in the local cartesian coordinate system
50 // whose origin is at the center of the magnet.
52 Vector_t{0.0, 0.0, element_m->getLength() / 2.0 + element_m->getEntryOffset()});
53 // The tangent to the curve at this point forms the z axis of the coordinate system
54 // opal addresses us in, so we can calculate the rotation required
55 auto secondPoint = curvilinearToLocalCartesian(
56 Vector_t{0.0, 0.0,
57 element_m->getLength() / 2.0 + element_m->getEntryOffset() + TangentStep});
59 secondPoint[2] - localCartesianEntryPoint_[2]);
60}
61
63 // Rotate Opal supplied cartesian coordinates around its origin
64 auto x_rotated = R[0] * cos(localCartesianRotation_) -
66 auto z_rotated = R[0] * sin(localCartesianRotation_) +
68 // Offset to the center of the magnet
69 R = {x_rotated + localCartesianEntryPoint_[0], R[1],
70 z_rotated + localCartesianEntryPoint_[2]};
71 // And finally into curvilinear coordinates
73}
74
76 // Offset to the Opal origin
77 auto x_offset = r[0] - localCartesianEntryPoint_[0];
78 auto z_offset = r[2] - localCartesianEntryPoint_[2];
79 // And rotate
80 auto x_rotated = x_offset * cos(-localCartesianRotation_) -
81 z_offset * sin(-localCartesianRotation_);
82 auto z_rotated = x_offset * sin(-localCartesianRotation_) +
83 z_offset * cos(-localCartesianRotation_);
84 return {x_rotated, r[1], -z_rotated};
85}
86
88 auto [s0, leftFringe, rightFringe] = element_m->getFringeField();
89 double rho = element_m->getLength() / element_m->getBendAngle();
90 coordinatetransform::CoordinateTransform t(r[0], r[1], r[2], s0, leftFringe, rightFringe, rho);
91 std::vector<double> result = t.getTransformation();
92 return {result[0], result[1], result[2]};
93}
94
96 auto [s0, leftFringe, rightFringe] = element_m->getFringeField();
97 double rho = element_m->getLength() / element_m->getBendAngle();
98 double prefactor = rho * (tanh(s0 / leftFringe) + tanh(s0 / rightFringe));
99 double theta = leftFringe * log(cosh((R[2] + s0) / leftFringe)) -
100 rightFringe * log(cosh((R[2] - s0) / rightFringe));
101 theta /= prefactor;
102 double Bx = B[0], Bs = B[2];
103 B[0] = Bx * cos(theta) - Bs * sin(theta);
104 B[2] = Bx * sin(theta) + Bs * cos(theta);
105}
106
107void MultipoleTCurvedVarRadius::setMaxOrder(size_t orderZ, size_t orderX) {
108 std::size_t N = recursion_m.size();
109 while (orderZ >= N) {
110 polynomial::RecursionRelationTwo r(N, 2 * (N + orderX + 1));
111 r.resizeX(element_m->getTransMaxOrder());
112 r.truncate(orderX);
113 recursion_m.push_back(r);
114 N = recursion_m.size();
115 }
116}
117
119 double result = 1.0;
120 if (element_m->getFringeDeriv(0, s) > 1.0e-12) {
121 double radius = element_m->getLength() * element_m->getFringeDeriv(0, 0) /
122 (element_m->getFringeDeriv(0, s) * element_m->getBendAngle());
123 result += x / radius;
124 }
125 return result;
126}
127
128double MultipoleTCurvedVarRadius::getFn(size_t n, double x, double s) {
129 double result{};
130 if (n == 0) {
131 result = element_m->getTransDeriv(0, x) * element_m->getFringeDeriv(0, s);
132 } else {
133 double rho = element_m->getLength() / element_m->getBendAngle();
134 double S_0 = element_m->getFringeDeriv(0, 0);
135 double y = element_m->getFringeDeriv(0, s) / (S_0 * rho);
136 std::vector<double> fringeDerivatives;
137 for (std::size_t j = 0; j <= recursion_m.at(n).getMaxSDerivatives(); j++) {
138 fringeDerivatives.push_back(element_m->getFringeDeriv(j, s) / (S_0 * rho));
139 }
140 for (std::size_t i = 0; i <= recursion_m.at(n).getMaxXDerivatives(); i++) {
141 double temp = 0.0;
142 for (std::size_t j = 0; j <= recursion_m.at(n).getMaxSDerivatives(); j++) {
143 temp += recursion_m.at(n).evaluatePolynomial(x, y, i, j, fringeDerivatives)
144 * fringeDerivatives.at(j);
145 }
146 result += temp * element_m->getTransDeriv(i, x);
147 }
148 result *= gsl_sf_pow_int(-1.0, static_cast<int>(n)) * S_0 * rho;
149 }
150 return result;
151}
152
154 const Vector_t& target) {
155 // Return the distance between the vector r and the target.
156 // We only consider the first and last coordinates as the height coordinate
157 // is invariant across these transforms.
159 double dx = c[0] - target[0];
160 double ds = c[2] - target[2];
161 return sqrt(dx * dx + ds * ds);
162}
163
165 // This functions uses a minimize loop and coordinate descent with backtracking
166 // to implement the inverse coordinate transform from the magnet's curvilinear
167 // system to the local cartesian system whose origins are the centre of the magnet.
168 // Note that this function is iterative and should therefore only be used occasionally.
169 Vector_t result{r};
170 double step = 1.0;
171 double best_res = reverseTransformResidual(result, r);
172 for (size_t iter = 0; iter < ReverseTransformMaxIterations; ++iter) {
173 bool improved = false;
174 for (int dim = 0; dim < 2; ++dim) {
175 for (int dir = -1; dir <= 1; dir += 2) {
176 Vector_t trial = result;
177 if (dim == 0) {
178 trial[0] += dir * step;
179 } else {
180 trial[2] += dir * step;
181 }
182 double res = reverseTransformResidual(trial, r);
183 if (res < best_res) {
184 result = trial;
185 best_res = res;
186 improved = true;
187 break;
188 }
189 }
190 if (improved) {
191 break;
192 }
193 }
194 if (!improved) {
195 step *= 0.5;
196 }
197 if (step < ReverseTransformTolerance) {
198 break;
199 }
200 }
201 return result;
202}
Tps< T > log(const Tps< T > &x)
Natural logarithm.
Definition TpsMath.h:182
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition TpsMath.h:129
Tps< T > cosh(const Tps< T > &x)
Hyperbolic cosine.
Definition TpsMath.h:222
Tps< T > tanh(const Tps< T > &x)
Hyperbolic tangent.
Definition TpsMath.h:240
Tps< T > sin(const Tps< T > &x)
Sine.
Definition TpsMath.h:111
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition TpsMath.h:91
constexpr double c
The velocity of light in m/s.
Definition Physics.h:45
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
MultipoleT * element_m
MultipoleTBase(MultipoleT *element)
std::vector< polynomial::RecursionRelationTwo > recursion_m
void transformBField(Vector_t &, const Vector_t &) override
double getScaleFactor(double x, double s) override
double reverseTransformResidual(const Vector_t &r, const Vector_t &target)
static constexpr double TangentStep
double getFn(size_t n, double x, double s) override
MultipoleTCurvedVarRadius(MultipoleT *element)
static constexpr size_t ReverseTransformMaxIterations
void setMaxOrder(size_t orderZ, size_t orderX) override
Vector_t localCartesianToCurvilinear(const Vector_t &r)
void transformCoords(Vector_t &) override
static constexpr double ReverseTransformTolerance
Vector_t localCartesianToOpalCartesian(const Vector_t &r) override
Vector_t curvilinearToLocalCartesian(const Vector_t &r)
std::vector< double > getTransformation() const
void truncate(std::size_t highestXorder)
void resizeX(const std::size_t &xDerivatives)
Vektor< double, 3 > Vector_t