OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
Ring.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2014, Chris Rogers
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * 1. Redistributions of source code must retain the above copyright notice,
7 * this list of conditions and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright notice,
9 * this list of conditions and the following disclaimer in the documentation
10 * and/or other materials provided with the distribution.
11 * 3. Neither the name of STFC nor the names of its contributors may be used to
12 * endorse or promote products derived from this software without specific
13 * prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "AbsBeamline/Ring.h"
29
30#include <sstream>
31#include <limits>
32#include <cmath>
33
34#include "Utility/Inform.h" // ippl
35
36#include "Fields/EMField.h"
40
41// fairly generous tolerance here... maybe too generous? Maybe should be
42// user parameter?
43const double Ring::lengthTolerance_m = 1e-2;
44const double Ring::angleTolerance_m = 1e-2;
45
46Ring::Ring(std::string ring)
47 : Component(ring), planarArcGeometry_m(1, 1),
48 refPartBunch_m(nullptr),
49 lossDS_m(nullptr),
50 beamRInit_m(0.), beamPRInit_m(0.), beamPhiInit_m(0.),
51 latticeRInit_m(0.), latticePhiInit_m(0.), latticeThetaInit_m(0.),
52 isLocked_m(false), isClosed_m(true),
53 symmetry_m(0), cyclHarm_m(0), rfFreq_m(0),
54 phiStep_m(Physics::pi/100.),
55 ringSections_m(),
56 section_list_m() {
57 setRefPartBunch(nullptr);
58}
59
60void Ring::accept(BeamlineVisitor& visitor) const {
61 visitor.visitRing(*this);
62}
63
64Ring::Ring(const Ring& ring)
65 : Component(ring.getName()),
66 planarArcGeometry_m(ring.planarArcGeometry_m),
67 lossDS_m(nullptr),
68 beamRInit_m(ring.beamRInit_m),
69 beamPRInit_m(ring.beamPRInit_m),
70 beamPhiInit_m(ring.beamPhiInit_m),
71 latticeRInit_m(ring.latticeRInit_m),
72 latticePhiInit_m(ring.latticePhiInit_m),
73 latticeThetaInit_m(ring.latticeThetaInit_m),
74 willDoAperture_m(ring.willDoAperture_m),
75 minR2_m(ring.minR2_m),
76 maxR2_m(ring.maxR2_m),
77 isLocked_m(ring.isLocked_m),
78 isClosed_m(ring.isClosed_m),
79 symmetry_m(ring.symmetry_m),
80 cyclHarm_m(ring.cyclHarm_m),
81 phiStep_m(ring.phiStep_m),
82 ringSections_m(),
83 section_list_m(ring.section_list_m.size()) {
85 if (ring.lossDS_m != nullptr)
86 throw GeneralClassicException("Ring::Ring(const Ring&)",
87 "Can't copy construct LossDataSink so copy constructor fails");
88 for (size_t i = 0; i < section_list_m.size(); ++i) {
89 section_list_m[i] = new RingSection(*ring.section_list_m[i]);
90 }
92}
93
95 for (size_t i = 0; i < section_list_m.size(); ++i)
96 delete section_list_m[i];
97}
98
99bool Ring::apply(const size_t &id, const double &t, Vector_t &E,
100 Vector_t &B) {
101 bool flagNeedUpdate =
102 apply(refPartBunch_m->R[id], refPartBunch_m->P[id], t, E, B);
103 if(flagNeedUpdate) {
104 Inform gmsgALL("OPAL ", INFORM_ALL_NODES);
105 gmsgALL << getName() << ": particle " << id
106 << " at " << refPartBunch_m->R[id]
107 << " m out of the field map boundary" << endl;
109 refPartBunch_m->R[id] * Vector_t(1000.0), refPartBunch_m->P[id],
110 t,
111 refPartBunch_m->Q[id], refPartBunch_m->M[id]));
112 lossDS_m->save();
113
114 refPartBunch_m->Bin[id] = -1;
115 }
116
117 return flagNeedUpdate;
118}
119
120bool Ring::apply(const Vector_t &R, const Vector_t &/*P*/,
121 const double &t, Vector_t &E, Vector_t &B) {
122 B = Vector_t(0.0, 0.0, 0.0);
123 E = Vector_t(0.0, 0.0, 0.0);
124
125 std::vector<RingSection*> sections = getSectionsAt(R); // I think this doesn't actually use R -DW
126 bool outOfBounds = true;
127 // assume field maps don't set B, E to 0...
128 if (willDoAperture_m) {
129 double rSquared = R[0]*R[0]+R[1]*R[1];
130 if (rSquared < minR2_m || rSquared > maxR2_m) {
131 return true;
132 }
133 }
134
135 for (size_t i = 0; i < sections.size(); ++i) {
136 Vector_t B_temp(0.0, 0.0, 0.0);
137 Vector_t E_temp(0.0, 0.0, 0.0);
138 // Super-TEMP! cyclotron tracker now uses m internally, have to change to mm here to match old field limits -DW
139 outOfBounds &= sections[i]->getFieldValue(R * Vector_t(1000.0), refPartBunch_m->get_centroid() * Vector_t(1000.0), t, E_temp, B_temp);
140 B += (scale_m * B_temp);
141 E += (scale_m * E_temp);
142 }
143 return outOfBounds;
144}
145
147 // lossDS_m is a borrowed pointer - we never delete it
148 lossDS_m = sink;
149}
150
151void Ring::getDimensions(double &/*zBegin*/, double &/*zEnd*/) const {
152 throw GeneralClassicException("Ring::getDimensions",
153 "Cannot get s-dimension of a ring");
154}
155
157 online_m = true;
158 setRefPartBunch(bunch);
159 setLossDataSink(new LossDataSink(getName(), false));
160}
161
162void Ring::initialise(PartBunchBase<double, 3> * bunch, double &/*startField*/,
163 double &/*endField*/) {
164 initialise(bunch);
165}
166
168 online_m = false;
169 setLossDataSink(nullptr);
170}
171
173 RefPartBunch_m = bunch; // inherited from Component
174 refPartBunch_m = bunch; // private data (obeys style guide)
175}
176
177std::vector<RingSection*> Ring::getSectionsAt(const Vector_t& /*r*/) {
178 return section_list_m;
179}
180
182 // rotation from start to end in local coordinates
183 // Euclid3D/Rotation3D doesnt have a "getAngle" method so we use fairly
184 // obscure technique to extract it.
185 Vector3D rotationTest(1., 0., 0.);
186 rotationTest = delta.getRotation()*rotationTest;
187 double deltaAngle = std::atan2(rotationTest(2), rotationTest(0));
188 Rotation3D elementRotation = Rotation3D::ZRotation(deltaAngle);
189 return elementRotation;
190}
191
192void Ring::checkMidplane(Euclid3D delta) const {
193 if (std::abs(delta.getVector()(2)) > lengthTolerance_m ||
196 throw GeneralClassicException("Ring::checkMidplane",
197 std::string("Placement of elements out of the ")+
198 "midplane is not supported by Ring");
199 }
200}
201
203 Vector3D v = delta.getVector();
204 Vector3D r = delta.getRotation().getAxis();
205 // Euclid3D euclid(v(0), -v(2), v(1), r(0), -r(2), r(1));
206 Euclid3D euclid(v(2), v(0), -v(1), r(2), r(0), -r(1));
207 delta = euclid;
208}
209
210
212 if (!section_list_m.empty()) {
213 return section_list_m.back()->getEndPosition();
214 }
217 0.);
218}
219
221 if (!section_list_m.empty()) {
222 return section_list_m.back()->getEndNormal();
223 }
226 0.);
227}
228
229void Ring::appendElement(const Component &element) {
230 if (isLocked_m) {
231 throw GeneralClassicException("Ring::appendElement",
232 "Attempt to append element "+element.getName()+
233 " when ring is locked");
234 }
235 // delta is transform from start of bend to end with x, z as horizontal
236 // I failed to get Rotation3D to work so use rotations written by hand.
237 // Probably an error in my call to Rotation3D.
238 Euclid3D delta = element.getGeometry().getTotalTransform();
240 checkMidplane(delta);
241
242 RingSection* section = new RingSection();
243 Vector_t startPos = getNextPosition();
244 Vector_t startNorm = getNextNormal();
245
246 section->setComponent(dynamic_cast<Component*>(element.clone()));
247 section->setStartPosition(startPos);
248 section->setStartNormal(startNorm);
249
250 double startF = std::atan2(startNorm(1), startNorm(0));
251 Vector_t endPos = Vector_t(
252 +delta.getVector()(0)*std::cos(startF)-delta.getVector()(1)*std::sin(startF),
253 +delta.getVector()(0)*std::sin(startF)+delta.getVector()(1)*std::cos(startF),
254 0)+startPos;
255 section->setEndPosition(endPos);
256
257 double endF = delta.getRotation().getAxis()(2);//+
258 //atan2(delta.getVector()(1), delta.getVector()(0));
259 Vector_t endNorm = Vector_t(
260 +startNorm(0)*std::cos(endF) + startNorm(1)*std::sin(endF),
261 -startNorm(0)*std::sin(endF) + startNorm(1)*std::cos(endF),
262 0);
263 section->setEndNormal(endNorm);
264
265 section->setComponentPosition(startPos);
266 section->setComponentOrientation(Vector_t(0, 0, startF));
267
268 section_list_m.push_back(section);
269
270 double dphi = atan2(startNorm(0), startNorm(1));
271 Inform msg("OPAL");
272 msg << "* Added " << element.getName() << " to Ring" << endl;
273 msg << "* Start position ("
274 << section->getStartPosition()(0) << ", "
275 << section->getStartPosition()(1) << ", "
276 << section->getStartPosition()(2) << ") normal ("
277 << section->getStartNormal()(0) << ", "
278 << section->getStartNormal()(1) << ", "
279 << section->getStartNormal()(2) << "), phi " << dphi << endl;
280 msg << "* End position ("
281 << section->getEndPosition()(0) << ", "
282 << section->getEndPosition()(1) << ", "
283 << section->getEndPosition()(2) << ") normal ("
284 << section->getEndNormal()(0) << ", "
285 << section->getEndNormal()(1) << ", "
286 << section->getEndNormal()(2) << ")" << endl;
287}
288
290 Inform msg("OPAL ");
291 if (isLocked_m) {
292 throw GeneralClassicException("Ring::lockRing",
293 "Attempt to lock ring when it is already locked");
294 }
295 // check for any elements at all
296 size_t sectionListSize = section_list_m.size();
297 if (sectionListSize == 0) {
298 throw GeneralClassicException("Ring::lockRing",
299 "Failed to find any elements in Ring");
300 }
301 // Apply symmetry properties; I think it is fastest to just duplicate
302 // elements rather than try to do some angle manipulations when we do field
303 // lookups because we do field lookups in Cartesian coordinates in general.
304 msg << "Applying symmetry to Ring" << endl;
305 for (int i = 1; i < symmetry_m; ++i) {
306 for (size_t j = 0; j < sectionListSize; ++j) {
307 appendElement(*section_list_m[j]->getComponent());
308 }
309 }
310 //resetAzimuths();
311 // Check that the ring is closed within tolerance and close exactly
312 if (isClosed_m)
315 isLocked_m = true;
316 for (size_t i = 0; i < section_list_m.size(); i++) {
317 }
318}
319
321 for (size_t i = 0; i < section_list_m.size(); ++i) {
322 Vector_t startPos = section_list_m[i]->getEndPosition();
323 Vector_t startDir = section_list_m[i]->getEndNormal();
324 Vector_t endPos = section_list_m[i]->getEndPosition();
325 Vector_t endDir = section_list_m[i]->getEndNormal();
326 if (!section_list_m[i]->isOnOrPastStartPlane(endPos)) {
327 section_list_m[i]->setEndPosition(startPos);
328 section_list_m[i]->setEndNormal(startDir);
329 section_list_m[i]->setStartPosition(endPos);
330 section_list_m[i]->setStartNormal(endDir);
331 }
332 }
333}
334
336 Vector_t first_pos = section_list_m[0]->getStartPosition();
337 Vector_t first_norm = section_list_m[0]->getStartNormal();
338 Vector_t last_pos = section_list_m.back()->getEndPosition();
339 Vector_t last_norm = section_list_m.back()->getEndNormal();
340 for (int i = 0; i < 3; ++i) {
341 if (std::abs(first_pos(i) - last_pos(i)) > lengthTolerance_m ||
342 std::abs(first_norm(i) - last_norm(i)) > angleTolerance_m)
343 throw GeneralClassicException("Ring::lockRing",
344 "Ring is not closed");
345 }
346 section_list_m.back()->setEndPosition(first_pos);
347 section_list_m.back()->setEndNormal(first_norm);
348}
349
351 size_t nSections = 2.*Physics::pi/phiStep_m+1;
352 ringSections_m = std::vector< std::vector<RingSection*> >(nSections);
353 for (size_t i = 0; i < ringSections_m.size(); ++i) {
354 double phi0 = i*phiStep_m;
355 double phi1 = (i+1)*phiStep_m;
356 // std::cerr << phi0 << " " << phi1 << std::endl;
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}
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
const double pi
Definition: fftpack.cpp:894
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define INFORM_ALL_NODES
Definition: Inform.h:39
Definition: Air.h:27
constexpr double e
The value of.
Definition: Physics.h:39
constexpr double pi
The value of.
Definition: Physics.h:30
ParticlePos_t & R
ParticleAttrib< int > Bin
ParticleAttrib< double > M
ParticleAttrib< Vector_t > P
ParticleAttrib< double > Q
Vector_t get_centroid() const
virtual void visitRing(const Ring &)=0
Apply the algorithm to a ring.
Interface for a single beam element.
Definition: Component.h:50
bool online_m
Definition: Component.h:192
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.
Ring describes a ring type geometry for tracking.
Definition: Ring.h:64
bool isClosed_m
Definition: Ring.h:389
LossDataSink * lossDS_m
Definition: Ring.h:366
Vector_t getNextPosition() const
Definition: Ring.cpp:211
void buildRingSections()
Definition: Ring.cpp:350
std::vector< RingSection * > getSectionsAt(const Vector_t &pos)
Definition: Ring.cpp:177
double maxR2_m
Definition: Ring.h:382
Rotation3D getRotationStartToEnd(Euclid3D delta) const
Definition: Ring.cpp:181
double minR2_m
Definition: Ring.h:381
bool willDoAperture_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:167
void checkAndClose()
Definition: Ring.cpp:335
void resetAzimuths()
Definition: Ring.cpp:320
virtual ~Ring()
Definition: Ring.cpp:94
virtual bool apply(const size_t &id, const double &t, Vector_t &E, Vector_t &B) override
Definition: Ring.cpp:99
RingSection * getLastSectionPlaced() const
Definition: Ring.cpp:364
void setRefPartBunch(PartBunchBase< double, 3 > *bunch)
Definition: Ring.cpp:172
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: Ring.cpp:162
double latticeThetaInit_m
Definition: Ring.h:376
std::vector< RingSectionList > ringSections_m
Definition: Ring.h:404
virtual void accept(BeamlineVisitor &visitor) const override
Definition: Ring.cpp:60
void setRingAperture(double minR, double maxR)
Definition: Ring.cpp:376
double latticePhiInit_m
Definition: Ring.h:375
RingSectionList section_list_m
Definition: Ring.h:405
double scale_m
Definition: Ring.h:394
void checkMidplane(Euclid3D delta) const
Definition: Ring.cpp:192
void setLossDataSink(LossDataSink *sink)
Definition: Ring.cpp:146
int symmetry_m
Definition: Ring.h:392
double latticeRInit_m
Definition: Ring.h:374
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition: Ring.cpp:151
double phiStep_m
Definition: Ring.h:403
void lockRing()
Definition: Ring.cpp:289
bool isLocked_m
Definition: Ring.h:385
void appendElement(const Component &element)
Definition: Ring.cpp:229
void rotateToCyclCoordinates(Euclid3D &euclid3d) const
Definition: Ring.cpp:202
static const double lengthTolerance_m
Definition: Ring.h:408
PartBunchBase< double, 3 > * refPartBunch_m
Definition: Ring.h:361
static const double angleTolerance_m
Definition: Ring.h:409
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.
Definition: Rotation3D.cpp:147
Vector3D getAxis() const
Get axis vector.
Definition: Rotation3D.cpp:91
A 3-dimension vector.
Definition: Vector3D.h:31
void save(unsigned int numSets=1, OpalData::OpenMode openMode=OpalData::OpenMode::UNDEFINED)
void addParticle(const OpalParticle &, const boost::optional< std::pair< int, short int > > &turnBunchNumPair=boost::none)
Component placement handler in ring geometry.
Definition: RingSection.h:67
void setStartNormal(Vector_t orientation)
Definition: RingSection.h:206
void setComponentPosition(Vector_t position)
Definition: RingSection.h:166
void setComponent(Component *component)
Definition: RingSection.h:133
void setStartPosition(Vector_t pos)
Definition: RingSection.h:142
Vector_t getStartNormal() const
Definition: RingSection.h:151
void setComponentOrientation(Vector_t orientation)
Definition: RingSection.h:201
Vector_t getEndPosition() const
Definition: RingSection.h:157
Vector_t getStartPosition() const
Definition: RingSection.h:145
void setEndPosition(Vector_t pos)
Definition: RingSection.h:154
Vector_t getEndNormal() const
Definition: RingSection.h:163
void setEndNormal(Vector_t orientation)
Definition: RingSection.h:210
Definition: Inform.h:42
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6