OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
Ring.cpp
Go to the documentation of this file.
1//
2// Class Ring
3// Defines the abstract interface for a ring type geometry.
4//
5// Copyright (c) 2012 - 2023, Chris Rogers, STFC Rutherford Appleton Laboratory, Didcot, UK
6// All rights reserved
7//
8// This file is part of OPAL.
9//
10// OPAL is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// You should have received a copy of the GNU General Public License
16// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17//
18#include "AbsBeamline/Ring.h"
19
20#include "Utility/Inform.h"
21
25#include "Fields/EMField.h"
26#include "Physics/Units.h"
28
29
30#include <limits>
31#include <sstream>
32
33// fairly generous tolerance here... maybe too generous? Maybe should be
34// user parameter?
35const double Ring::lengthTolerance_m = 1e-2;
36const double Ring::angleTolerance_m = 1e-2;
37
38extern Inform* gmsg;
39extern Inform* gmsgALL;
40
41Ring::Ring(const std::string& ring)
42 : Component(ring), planarArcGeometry_m(1, 1),
43 refPartBunch_m(nullptr),
44 lossDS_m(nullptr),
47 isLocked_m(false), isClosed_m(true),
49 phiStep_m(Physics::pi/100.),
52 setRefPartBunch(nullptr);
53}
54
55void Ring::accept(BeamlineVisitor& visitor) const {
56 visitor.visitRing(*this);
57}
58
59Ring::Ring(const Ring& ring)
60 : Component(ring.getName()),
62 lossDS_m(nullptr),
71 minR2_m(ring.minR2_m),
72 maxR2_m(ring.maxR2_m),
77 phiStep_m(ring.phiStep_m),
79 section_list_m(ring.section_list_m.size()) {
81 if (ring.lossDS_m != nullptr)
82 throw GeneralClassicException("Ring::Ring(const Ring&)",
83 "Can't copy construct LossDataSink so copy constructor fails");
84 for (size_t i = 0; i < section_list_m.size(); ++i) {
85 section_list_m[i] = new RingSection(*ring.section_list_m[i]);
86 }
88}
89
91 for (size_t i = 0; i < section_list_m.size(); ++i)
92 delete section_list_m[i];
93}
94
95bool Ring::apply(const size_t& id, const double& t,
96 Vector_t& E, Vector_t& B) {
97
98 bool flagNeedUpdate = apply(refPartBunch_m->R[id], refPartBunch_m->P[id], t, E, B);
99
100 if (flagNeedUpdate) {
101 *gmsgALL << level4 << getName() << ": particle " << id
102 << " at " << refPartBunch_m->R[id]
103 << " m out of the field map boundary" << endl;
104
105 lossDS_m->addParticle(OpalParticle(id,
106 refPartBunch_m->R[id] , refPartBunch_m->P[id],
107 t,
108 refPartBunch_m->Q[id], refPartBunch_m->M[id]));
109
110 refPartBunch_m->Bin[id] = -1;
111 }
112
113 return flagNeedUpdate;
114}
115
116bool Ring::apply(const Vector_t& R, const Vector_t& /*P*/,
117 const double& t, Vector_t& E, Vector_t& B) {
118 B = Vector_t(0.0, 0.0, 0.0);
119 E = Vector_t(0.0, 0.0, 0.0);
120
121 std::vector<RingSection*> sections = getSectionsAt(R); // I think this doesn't actually use R -DW
122 bool outOfBounds = true;
123 // assume field maps don't set B, E to 0...
124 if (willDoAperture_m) {
125 double rSquared = R[0] * R[0] + R[1] * R[1];
126 if (rSquared < minR2_m || rSquared > maxR2_m) {
127 return true;
128 }
129 }
130 for (size_t i = 0; i < sections.size(); ++i) {
131 Vector_t B_temp(0.0, 0.0, 0.0);
132 Vector_t E_temp(0.0, 0.0, 0.0);
133 outOfBounds &= sections[i]->getFieldValue(R, refPartBunch_m->get_centroid(), t, E_temp, B_temp);
134 B += (scale_m * B_temp);
135 E += (scale_m * E_temp);
136 }
137 return outOfBounds;
138}
139
141 // lossDS_m is a borrowed pointer - we never delete it
142 lossDS_m = sink;
143}
144
145void Ring::getDimensions(double& /*zBegin*/, double& /*zEnd*/) const {
146 throw GeneralClassicException("Ring::getDimensions",
147 "Cannot get s-dimension of a ring");
148}
149
151 online_m = true;
152 setRefPartBunch(bunch);
153 setLossDataSink(new LossDataSink(getName(), false));
154}
155
157 double& /*startField*/, double& /*endField*/) {
158 initialise(bunch);
159}
160
162 lossDS_m->save();
163 online_m = false;
164 setLossDataSink(nullptr);
165}
166
168 RefPartBunch_m = bunch; // inherited from Component
169 refPartBunch_m = bunch; // private data (obeys style guide)
170}
171
172std::vector<RingSection*> Ring::getSectionsAt(const Vector_t& /*r*/) {
173 return section_list_m;
174}
175
177 // rotation from start to end in local coordinates
178 // Euclid3D/Rotation3D doesnt have a "getAngle" method so we use fairly
179 // obscure technique to extract it.
180 Vector3D rotationTest(1., 0., 0.);
181 rotationTest = delta.getRotation() * rotationTest;
182 double deltaAngle = std::atan2(rotationTest(2), rotationTest(0));
183 Rotation3D elementRotation = Rotation3D::ZRotation(deltaAngle);
184 return elementRotation;
185}
186
187void Ring::checkMidplane(Euclid3D delta) const {
188 if (std::abs(delta.getVector()(2)) > lengthTolerance_m ||
189 std::abs(delta.getRotation().getAxis()(0)) > angleTolerance_m ||
190 std::abs(delta.getRotation().getAxis()(1)) > angleTolerance_m) {
191 throw GeneralClassicException("Ring::checkMidplane",
192 std::string("Placement of elements out of the ")+
193 "midplane is not supported by Ring");
194 }
195}
196
198 Vector3D v = delta.getVector();
199 Vector3D r = delta.getRotation().getAxis();
200 // Euclid3D euclid(v(0), -v(2), v(1), r(0), -r(2), r(1));
201 Euclid3D euclid(v(2), v(0), -v(1), r(2), r(0), -r(1));
202 delta = euclid;
203}
204
205
207 if (!section_list_m.empty()) {
208 return section_list_m.back()->getEndPosition();
209 } else {
210 return getStartPosition();
211 }
212}
213
215 return Vector_t(latticeRInit_m * std::cos(latticePhiInit_m),
217 0.);
218}
219
221 if (!section_list_m.empty()) {
222 return section_list_m.back()->getEndNormal();
223 } else {
224 return getStartNormal();
225 }
226}
227
233
234void Ring::appendElement(const Component& element) {
235 if (isLocked_m) {
236 throw GeneralClassicException("Ring::appendElement",
237 "Attempt to append element " + element.getName() +
238 " when ring is locked");
239 }
240
241 RingSection* section = new RingSection();
242 Vector_t startPos = getNextPosition();
243 Vector_t startNorm = getNextNormal();
244
245 section->setComponent(dynamic_cast<Component*>(element.clone()));
246 section->setStartPosition(startPos);
247 section->setStartNormal(startNorm);
248 section->handleOffset();
249 // delta is transform from start of bend to end with x, z as horizontal
250 // I failed to get Rotation3D to work so use rotations written by hand.
251 // Probably an error in my call to Rotation3D.
252 Euclid3D delta = section->getComponent()->getGeometry().getTotalTransform();
254 checkMidplane(delta);
255
256 double placeF = std::atan2(startNorm(0), startNorm(1)); // angle between y axis and norm
257 Vector_t endPos = Vector_t(+delta.getVector()(0) * std::sin(placeF) + delta.getVector()(1) * std::cos(placeF),
258 +delta.getVector()(0) * std::cos(placeF) - delta.getVector()(1) * std::sin(placeF),
259 0) + startPos;
260 section->setEndPosition(endPos);
261
262 double endF = delta.getRotation().getAxis()(2);//+
263 //atan2(delta.getVector()(1), delta.getVector()(0));
264 Vector_t endNorm = Vector_t(+startNorm(0) * std::cos(endF) - startNorm(1) * std::sin(endF),
265 +startNorm(0) * std::sin(endF) + startNorm(1) * std::cos(endF),
266 0);
267 section->setEndNormal(endNorm);
268
269 section->setComponentPosition(startPos);
270 double orientation = std::atan2(startNorm(1), startNorm(0));
271 section->setComponentOrientation(Vector_t(0, 0, orientation));
272
273 section_list_m.push_back(section);
274 *gmsg << "* Added " << element.getName() << " to Ring" << endl;
275 *gmsg << "* Start position ("
276 << section->getStartPosition()(0) << ", "
277 << section->getStartPosition()(1) << ", "
278 << section->getStartPosition()(2) << ") normal ("
279 << section->getStartNormal()(0) << ", "
280 << section->getStartNormal()(1) << ", "
281 << section->getStartNormal()(2) << ")" << endl;
282 *gmsg << "* End position ("
283 << section->getEndPosition()(0) << ", "
284 << section->getEndPosition()(1) << ", "
285 << section->getEndPosition()(2) << ") normal ("
286 << section->getEndNormal()(0) << ", "
287 << section->getEndNormal()(1) << ", "
288 << section->getEndNormal()(2) << ")" << endl;
289}
290
292 if (isLocked_m) {
293 throw GeneralClassicException("Ring::lockRing",
294 "Attempt to lock ring when it is already locked");
295 }
296 // check for any elements at all
297 size_t sectionListSize = section_list_m.size();
298 if (sectionListSize == 0) {
299 throw GeneralClassicException("Ring::lockRing",
300 "Failed to find any elements in Ring");
301 }
302 // Apply symmetry properties; I think it is fastest to just duplicate
303 // elements rather than try to do some angle manipulations when we do field
304 // lookups because we do field lookups in Cartesian coordinates in general.
305 *gmsg << "Applying symmetry to Ring" << endl;
306 for (int i = 1; i < symmetry_m; ++i) {
307 for (size_t j = 0; j < sectionListSize; ++j) {
308 appendElement(*section_list_m[j]->getComponent());
309 }
310 }
311 //resetAzimuths();
312 // Check that the ring is closed within tolerance and close exactly
313 if (isClosed_m)
316 isLocked_m = true;
317 for (size_t i = 0; i < section_list_m.size(); i++) {
318 }
319}
320
322 for (size_t i = 0; i < section_list_m.size(); ++i) {
323 Vector_t startPos = section_list_m[i]->getEndPosition();
324 Vector_t startDir = section_list_m[i]->getEndNormal();
325 Vector_t endPos = section_list_m[i]->getEndPosition();
326 Vector_t endDir = section_list_m[i]->getEndNormal();
327 if (!section_list_m[i]->isOnOrPastStartPlane(endPos)) {
328 section_list_m[i]->setEndPosition(startPos);
329 section_list_m[i]->setEndNormal(startDir);
330 section_list_m[i]->setStartPosition(endPos);
331 section_list_m[i]->setStartNormal(endDir);
332 }
333 }
334}
335
337 Vector_t first_pos = section_list_m[0]->getStartPosition();
338 Vector_t first_norm = section_list_m[0]->getStartNormal();
339 Vector_t last_pos = section_list_m.back()->getEndPosition();
340 Vector_t last_norm = section_list_m.back()->getEndNormal();
341 for (int i = 0; i < 3; ++i) {
342 if (std::abs(first_pos(i) - last_pos(i)) > lengthTolerance_m ||
343 std::abs(first_norm(i) - last_norm(i)) > angleTolerance_m)
344 throw GeneralClassicException("Ring::lockRing",
345 "Ring is not closed");
346 }
347 section_list_m.back()->setEndPosition(first_pos);
348 section_list_m.back()->setEndNormal(first_norm);
349}
350
352 size_t nSections = Physics::two_pi/phiStep_m+1;
353 ringSections_m = std::vector< std::vector<RingSection*> >(nSections);
354 for (size_t i = 0; i < ringSections_m.size(); ++i) {
355 double phi0 = i*phiStep_m;
356 double phi1 = (i+1)*phiStep_m;
357 for (size_t j = 0; j < section_list_m.size(); ++j) {
358 if (section_list_m[j]->doesOverlap(phi0, phi1))
359 ringSections_m[i].push_back(section_list_m[j]);
360 }
361 }
362}
363
365 if (section_list_m.empty()) {
366 return nullptr;
367 }
368 return section_list_m.back();
369}
370
371bool Ring::sectionCompare(RingSection const* const sec1,
372 RingSection const* const sec2) {
373 return sec1 > sec2;
374}
375
376void Ring::setRingAperture(double minR, double maxR) {
377 if (minR < 0 || maxR < 0) {
378 throw GeneralClassicException("Ring::setRingAperture",
379 "Could not parse negative or undefined aperture limit");
380 }
381
382 willDoAperture_m = true;
383 minR2_m = minR * minR;
384 maxR2_m = maxR * maxR;
385}
386
388 if (i < 0 || i >= int(getNumberOfRingSections())) {
389 std::stringstream err;
390 err << "Attempt to get RingSection for element " << i
391 << ". Should be in range 0 <= i < " << getNumberOfRingSections();
392 throw GeneralClassicException("Ring::getSection(int)", err.str());
393 }
395 if (sec == nullptr) {
396 throw GeneralClassicException("Ring::getSection",
397 "Opal internal error - RingSection was null");
398 }
399 return sec;
400}
401
403 return section_list_m.size();
404}
Tps< T > sec(const Tps< T > &x)
Secant.
Definition TpsMath.h:153
Inform * gmsgALL
Definition Main.cpp:71
Inform * gmsg
Definition Main.cpp:70
const double pi
Definition fftpack.cpp:894
Inform & level4(Inform &inf)
Definition Inform.cpp:48
Inform & endl(Inform &inf)
Definition Inform.cpp:42
Definition Air.h:27
constexpr double two_pi
The value of.
Definition Physics.h:33
constexpr double e
The value of.
Definition Physics.h:39
virtual void visitRing(const Ring &)=0
Apply the algorithm to a ring.
bool online_m
Definition Component.h:192
Component(const std::string &name)
Constructor with given name.
Definition Component.cpp:53
PartBunchBase< double, 3 > * RefPartBunch_m
Definition Component.h:191
virtual const std::string & getName() const
Get element name.
virtual ElementBase * clone() const =0
Return clone.
virtual BGeometryBase & getGeometry()=0
Get geometry.
double rfFreq_m
Definition Ring.h:409
bool isClosed_m
Definition Ring.h:398
LossDataSink * lossDS_m
Definition Ring.h:374
Vector_t getNextPosition() const
Definition Ring.cpp:206
void buildRingSections()
Definition Ring.cpp:351
std::vector< RingSection * > getSectionsAt(const Vector_t &pos)
Definition Ring.cpp:172
double maxR2_m
Definition Ring.h:391
Rotation3D getRotationStartToEnd(Euclid3D delta) const
Definition Ring.cpp:176
double beamPhiInit_m
Definition Ring.h:379
size_t getNumberOfRingSections() const
Definition Ring.cpp:402
double minR2_m
Definition Ring.h:390
bool willDoAperture_m
Definition Ring.h:389
double beamThetaInit_m
Definition Ring.h:380
static bool sectionCompare(RingSection const *const sec1, RingSection const *const sec2)
Definition Ring.cpp:371
Vector_t getNextNormal() const
Definition Ring.cpp:220
virtual void finalise() override
Definition Ring.cpp:161
void checkAndClose()
Definition Ring.cpp:336
void resetAzimuths()
Definition Ring.cpp:321
virtual ~Ring()
Definition Ring.cpp:90
virtual bool apply(const size_t &id, const double &t, Vector_t &E, Vector_t &B) override
Definition Ring.cpp:95
Ring(const std::string &ring)
Definition Ring.cpp:41
RingSection * getLastSectionPlaced() const
Definition Ring.cpp:364
void setRefPartBunch(PartBunchBase< double, 3 > *bunch)
Definition Ring.cpp:167
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition Ring.cpp:156
double latticeThetaInit_m
Definition Ring.h:385
std::vector< RingSectionList > ringSections_m
Definition Ring.h:413
virtual void accept(BeamlineVisitor &visitor) const override
Definition Ring.cpp:55
void setRingAperture(double minR, double maxR)
Definition Ring.cpp:376
double beamRInit_m
Definition Ring.h:377
double latticePhiInit_m
Definition Ring.h:384
RingSectionList section_list_m
Definition Ring.h:414
double scale_m
Definition Ring.h:403
void checkMidplane(Euclid3D delta) const
Definition Ring.cpp:187
double beamPRInit_m
Definition Ring.h:378
void setLossDataSink(LossDataSink *sink)
Definition Ring.cpp:140
int symmetry_m
Definition Ring.h:401
double latticeRInit_m
Definition Ring.h:383
PlanarArcGeometry planarArcGeometry_m
Definition Ring.h:363
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition Ring.cpp:145
double phiStep_m
Definition Ring.h:412
void lockRing()
Definition Ring.cpp:291
bool isLocked_m
Definition Ring.h:394
void appendElement(const Component &element)
Definition Ring.cpp:234
Vector_t getStartNormal() const
Definition Ring.cpp:228
void rotateToCyclCoordinates(Euclid3D &euclid3d) const
Definition Ring.cpp:197
double cyclHarm_m
Definition Ring.h:406
static const double lengthTolerance_m
Definition Ring.h:417
RingSection * getSection(int i) const
Definition Ring.cpp:387
Vector_t getStartPosition() const
Definition Ring.cpp:214
PartBunchBase< double, 3 > * refPartBunch_m
Definition Ring.h:369
static const double angleTolerance_m
Definition Ring.h:418
Displacement and rotation in space.
Definition Euclid3D.h:68
const Vector3D & getVector() const
Get displacement.
Definition Euclid3D.cpp:59
const Rotation3D & getRotation() const
Get rotation.
Definition Euclid3D.cpp:64
virtual Euclid3D getTotalTransform() const
Get transform.
Definition Geometry.cpp:51
Rotation in 3-dimensional space.
Definition Rotation3D.h:46
static Rotation3D ZRotation(double angle)
Make rotation.
Vector3D getAxis() const
Get axis vector.
A 3-dimension vector.
Definition Vector3D.h:31
Component placement handler in ring geometry.
Definition RingSection.h:58
void setStartNormal(Vector_t orientation)
void setComponentPosition(Vector_t position)
void setComponent(Component *component)
void handleOffset()
void setStartPosition(Vector_t pos)
Vector_t getStartNormal() const
void setComponentOrientation(Vector_t orientation)
Component * getComponent() const
Vector_t getEndPosition() const
Vector_t getStartPosition() const
void setEndPosition(Vector_t pos)
Vector_t getEndNormal() const
void setEndNormal(Vector_t orientation)
Vektor< double, 3 > Vector_t