OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
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 <cmath>
31#include <limits>
32#include <sstream>
33
34#include "Utility/Inform.h" // ippl
35
37#include "Fields/EMField.h"
38#include "PartBunch/PartBunch.h"
39#include "Physics/Physics.h"
41
42// fairly generous tolerance here... maybe too generous? Maybe should be
43// user parameter?
44const double Ring::lengthTolerance_m = 1e-2;
45const double Ring::angleTolerance_m = 1e-2;
46
47Ring::Ring(std::string ring)
48 : Component(ring),
50 refPartBunch_m(nullptr),
51 lossDS_m(nullptr),
52 beamRInit_m(0.),
53 beamPRInit_m(0.),
54 beamPhiInit_m(0.),
58 isLocked_m(false),
59 isClosed_m(true),
60 symmetry_m(0),
61 cyclHarm_m(0),
62 rfFreq_m(0),
63 phiStep_m(Physics::pi / 100.),
66 setRefPartBunch(nullptr);
67}
68
69void Ring::accept(BeamlineVisitor& visitor) const {
70 visitor.visitRing(*this);
71}
72
73Ring::Ring(const Ring& ring)
74 : Component(ring.getName()),
76 lossDS_m(nullptr),
84 minR2_m(ring.minR2_m),
85 maxR2_m(ring.maxR2_m),
90 phiStep_m(ring.phiStep_m),
92 section_list_m(ring.section_list_m.size()) {
94 if (ring.lossDS_m != nullptr)
96 "Ring::Ring(const Ring&)",
97 "Can't copy construct LossDataSink so copy constructor fails");
98 for (size_t i = 0; i < section_list_m.size(); ++i) {
99 section_list_m[i] = new RingSection(*ring.section_list_m[i]);
100 }
102}
103
105 for (size_t i = 0; i < section_list_m.size(); ++i)
106 delete section_list_m[i];
107}
108
110 const size_t& id, const double& t, Vector_t<double, 3>& E, Vector_t<double, 3>& B) {
111 std::shared_ptr<ParticleContainer_t> pc = RefPartBunch_m->getParticleContainer();
112 auto Rview = pc->R.getView();
113 auto Pview = pc->P.getView();
114
115 const Vector_t<double, 3> R = Rview(id);
116 const Vector_t<double, 3> P = Pview(id);
117
118 bool flagNeedUpdate = apply(R, P, t, E, B);
119 if (flagNeedUpdate) {
120 Inform gmsgALL("OPAL ", INFORM_ALL_NODES);
121
122 auto Qview = pc->Q.getView();
123 auto Mview = pc->M.getView();
124 auto Binview = pc->Bin.getView();
125
126 const double Q = Qview(id);
127 const double M = Mview(id);
128 // const short int Bin = Binview(id);
129
130 gmsgALL << getName() << ": particle " << id << " at " << R
131 << " m out of the field map boundary" << endl;
132 lossDS_m->addParticle(OpalParticle(id, R * Vector_t<double, 3>(1000.0), P, t, Q, M));
133
134 Binview(id) = -1;
135 }
136
137 return flagNeedUpdate;
138}
139
141 const Vector_t<double, 3>& R, const Vector_t<double, 3>& /*P*/, const double& t,
143 B = Vector_t<double, 3>({0.0, 0.0, 0.0});
144 E = Vector_t<double, 3>({0.0, 0.0, 0.0});
145
146 std::vector<RingSection*> sections =
147 getSectionsAt(R); // I think this doesn't actually use R -DW
148 bool outOfBounds = true;
149 // assume field maps don't set B, E to 0...
150 if (willDoAperture_m) {
151 double rSquared = R[0] * R[0] + R[1] * R[1];
152 if (rSquared < minR2_m || rSquared > maxR2_m) {
153 return true;
154 }
155 }
156
157 for (size_t i = 0; i < sections.size(); ++i) {
158 Vector_t<double, 3> B_temp({0.0, 0.0, 0.0});
159 Vector_t<double, 3> E_temp({0.0, 0.0, 0.0});
160 // Super-TEMP! cyclotron tracker now uses m internally, have to change to mm here to match
161 // old field limits -DW
162 outOfBounds &= sections[i]->getFieldValue(
163 R * Vector_t<double, 3>(1000.0),
164 refPartBunch_m->get_centroid() * Vector_t<double, 3>(1000.0), t, E_temp, B_temp);
165 B += (scale_m * B_temp);
166 E += (scale_m * E_temp);
167 }
168 return outOfBounds;
169}
170
172 // lossDS_m is a borrowed pointer - we never delete it
173 lossDS_m = sink;
174}
175
176void Ring::getDimensions(double& /*zBegin*/, double& /*zEnd*/) const {
177 throw GeneralClassicException("Ring::getDimensions", "Cannot get s-dimension of a ring");
178}
179
181 online_m = true;
182 setRefPartBunch(bunch);
183 setLossDataSink(new LossDataSink(getName(), false));
184}
185
186void Ring::initialise(PartBunch_t* bunch, double& /*startField*/, double& /*endField*/) {
187 initialise(bunch);
188}
189
191 lossDS_m->save();
192 online_m = false;
193 setLossDataSink(nullptr);
194}
195
197 RefPartBunch_m = bunch; // inherited from Component
198 refPartBunch_m = bunch; // private data (obeys style guide)
199}
200
201std::vector<RingSection*> Ring::getSectionsAt(const Vector_t<double, 3>& /*r*/) {
202 return section_list_m;
203}
204
206 // rotation from start to end in local coordinates
207 // Euclid3D/Rotation3D doesnt have a "getAngle" method so we use fairly
208 // obscure technique to extract it.
209 Vector3D rotationTest(1., 0., 0.);
210 rotationTest = delta.getRotation() * rotationTest;
211 double deltaAngle = std::atan2(rotationTest(2), rotationTest(0));
212 Rotation3D elementRotation = Rotation3D::ZRotation(deltaAngle);
213 return elementRotation;
214}
215
216void Ring::checkMidplane(Euclid3D delta) const {
217 if (std::abs(delta.getVector()(2)) > lengthTolerance_m
218 || std::abs(delta.getRotation().getAxis()(0)) > angleTolerance_m
219 || std::abs(delta.getRotation().getAxis()(1)) > angleTolerance_m) {
221 "Ring::checkMidplane",
222 std::string("Placement of elements out of the ") + "midplane is not supported by Ring");
223 }
224}
225
227 Vector3D v = delta.getVector();
228 Vector3D r = delta.getRotation().getAxis();
229 // Euclid3D euclid(v(0), -v(2), v(1), r(0), -r(2), r(1));
230 Euclid3D euclid(v(2), v(0), -v(1), r(2), r(0), -r(1));
231 delta = euclid;
232}
233
235 if (!section_list_m.empty()) {
236 return section_list_m.back()->getEndPosition();
237 }
238 return Vector_t<double, 3>(
240 0.});
241}
242
244 if (!section_list_m.empty()) {
245 return section_list_m.back()->getEndNormal();
246 }
247 return Vector_t<double, 3>(
249 -std::sin(latticePhiInit_m + latticeThetaInit_m), 0.});
250}
251
252void Ring::appendElement(const Component& element) {
253 if (isLocked_m) {
255 "Ring::appendElement",
256 "Attempt to append element " + element.getName() + " when ring is locked");
257 }
258 // delta is transform from start of bend to end with x, z as horizontal
259 // I failed to get Rotation3D to work so use rotations written by hand.
260 // Probably an error in my call to Rotation3D.
261 Euclid3D delta = element.getGeometry().getTotalTransform();
263 checkMidplane(delta);
264
265 RingSection* section = new RingSection();
268
269 section->setComponent(dynamic_cast<Component*>(element.clone()));
270 section->setStartPosition(startPos);
271 section->setStartNormal(startNorm);
272
273 double startF = std::atan2(startNorm(1), startNorm(0));
274 Vector_t<double, 3> endPos =
276 {+delta.getVector()(0) * std::cos(startF) - delta.getVector()(1) * std::sin(startF),
277 +delta.getVector()(0) * std::sin(startF) + delta.getVector()(1) * std::cos(startF), 0})
278 + startPos;
279 section->setEndPosition(endPos);
280
281 double endF = delta.getRotation().getAxis()(2); //+
282 // atan2(delta.getVector()(1), delta.getVector()(0));
284 {+startNorm(0) * std::cos(endF) + startNorm(1) * std::sin(endF),
285 -startNorm(0) * std::sin(endF) + startNorm(1) * std::cos(endF), 0});
286 section->setEndNormal(endNorm);
287
288 section->setComponentPosition(startPos);
289 section->setComponentOrientation(Vector_t<double, 3>({0, 0, startF}));
290
291 section_list_m.push_back(section);
292
293 double dphi = atan2(startNorm(0), startNorm(1));
294 Inform msg("OPAL");
295 msg << "* Added " << element.getName() << " to Ring" << endl;
296 msg << "* Start position (" << section->getStartPosition()(0) << ", "
297 << section->getStartPosition()(1) << ", " << section->getStartPosition()(2) << ") normal ("
298 << section->getStartNormal()(0) << ", " << section->getStartNormal()(1) << ", "
299 << section->getStartNormal()(2) << "), phi " << dphi << endl;
300 msg << "* End position (" << section->getEndPosition()(0) << ", "
301 << section->getEndPosition()(1) << ", " << section->getEndPosition()(2) << ") normal ("
302 << section->getEndNormal()(0) << ", " << section->getEndNormal()(1) << ", "
303 << section->getEndNormal()(2) << ")" << endl;
304}
305
307 Inform msg("OPAL ");
308 if (isLocked_m) {
310 "Ring::lockRing", "Attempt to lock ring when it is already locked");
311 }
312 // check for any elements at all
313 size_t sectionListSize = section_list_m.size();
314 if (sectionListSize == 0) {
315 throw GeneralClassicException("Ring::lockRing", "Failed to find any elements in Ring");
316 }
317 // Apply symmetry properties; I think it is fastest to just duplicate
318 // elements rather than try to do some angle manipulations when we do field
319 // lookups because we do field lookups in Cartesian coordinates in general.
320 msg << "Applying symmetry to Ring" << endl;
321 for (int i = 1; i < symmetry_m; ++i) {
322 for (size_t j = 0; j < sectionListSize; ++j) {
323 appendElement(*section_list_m[j]->getComponent());
324 }
325 }
326 // resetAzimuths();
327 // Check that the ring is closed within tolerance and close exactly
328 if (isClosed_m)
331 isLocked_m = true;
332 for (size_t i = 0; i < section_list_m.size(); i++) {
333 }
334}
335
337 for (size_t i = 0; i < section_list_m.size(); ++i) {
338 Vector_t<double, 3> startPos = section_list_m[i]->getEndPosition();
339 Vector_t<double, 3> startDir = section_list_m[i]->getEndNormal();
340 Vector_t<double, 3> endPos = section_list_m[i]->getEndPosition();
341 Vector_t<double, 3> endDir = section_list_m[i]->getEndNormal();
342 if (!section_list_m[i]->isOnOrPastStartPlane(endPos)) {
343 section_list_m[i]->setEndPosition(startPos);
344 section_list_m[i]->setEndNormal(startDir);
345 section_list_m[i]->setStartPosition(endPos);
346 section_list_m[i]->setStartNormal(endDir);
347 }
348 }
349}
350
352 Vector_t<double, 3> first_pos = section_list_m[0]->getStartPosition();
353 Vector_t<double, 3> first_norm = section_list_m[0]->getStartNormal();
354 Vector_t<double, 3> last_pos = section_list_m.back()->getEndPosition();
355 Vector_t<double, 3> last_norm = section_list_m.back()->getEndNormal();
356 for (int i = 0; i < 3; ++i) {
357 if (std::abs(first_pos(i) - last_pos(i)) > lengthTolerance_m
358 || std::abs(first_norm(i) - last_norm(i)) > angleTolerance_m)
359 throw GeneralClassicException("Ring::lockRing", "Ring is not closed");
360 }
361 section_list_m.back()->setEndPosition(first_pos);
362 section_list_m.back()->setEndNormal(first_norm);
363}
364
366 size_t nSections = 2. * Physics::pi / phiStep_m + 1;
367 ringSections_m = std::vector<std::vector<RingSection*> >(nSections);
368 for (size_t i = 0; i < ringSections_m.size(); ++i) {
369 double phi0 = i * phiStep_m;
370 double phi1 = (i + 1) * phiStep_m;
371 // std::cerr << phi0 << " " << phi1 << std::endl;
372 for (size_t j = 0; j < section_list_m.size(); ++j) {
373 if (section_list_m[j]->doesOverlap(phi0, phi1))
374 ringSections_m[i].push_back(section_list_m[j]);
375 }
376 }
377}
378
380 if (section_list_m.empty()) {
381 return nullptr;
382 }
383 return section_list_m.back();
384}
385
386bool Ring::sectionCompare(RingSection const* const sec1, RingSection const* const sec2) {
387 return sec1 > sec2;
388}
389
390void Ring::setRingAperture(double minR, double maxR) {
391 if (minR < 0 || maxR < 0) {
393 "Ring::setRingAperture", "Could not parse negative or undefined aperture limit");
394 }
395
396 willDoAperture_m = true;
397 minR2_m = minR * minR;
398 maxR2_m = maxR * maxR;
399}
PartBunch< PLayout_t< double, 3 >, double, 3 > PartBunch_t
ippl::Vector< T, Dim > Vector_t
const double pi
Definition datatypes.h:4
Definition Air.h:27
constexpr double e
The value of.
Definition Physics.h:39
constexpr double pi
The value of.
Definition Physics.h:30
virtual void visitRing(const Ring &)=0
Apply the algorithm to a Ring element.
bool online_m
Definition Component.h:186
Component(const std::string &name)
Constructor with given name.
Definition Component.cpp:44
PartBunch_t * RefPartBunch_m
Definition Component.h:185
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:455
bool isClosed_m
Definition Ring.h:444
LossDataSink * lossDS_m
Definition Ring.h:421
void buildRingSections()
Definition Ring.cpp:365
double maxR2_m
Definition Ring.h:437
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField) override
Definition Ring.cpp:186
Rotation3D getRotationStartToEnd(Euclid3D delta) const
Definition Ring.cpp:205
double beamPhiInit_m
Definition Ring.h:426
double minR2_m
Definition Ring.h:436
bool willDoAperture_m
Definition Ring.h:435
static bool sectionCompare(RingSection const *const sec1, RingSection const *const sec2)
Definition Ring.cpp:386
virtual void finalise() override
Definition Ring.cpp:190
void checkAndClose()
Definition Ring.cpp:351
Vector_t< double, 3 > getNextPosition() const
Definition Ring.cpp:234
void resetAzimuths()
Definition Ring.cpp:336
virtual ~Ring()
Definition Ring.cpp:104
Vector_t< double, 3 > getNextNormal() const
Definition Ring.cpp:243
RingSection * getLastSectionPlaced() const
Definition Ring.cpp:379
virtual bool apply(const size_t &id, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) override
Definition Ring.cpp:109
double latticeThetaInit_m
Definition Ring.h:431
std::vector< RingSectionList > ringSections_m
Definition Ring.h:459
virtual void accept(BeamlineVisitor &visitor) const override
Definition Ring.cpp:69
void setRingAperture(double minR, double maxR)
Definition Ring.cpp:390
double beamRInit_m
Definition Ring.h:424
double latticePhiInit_m
Definition Ring.h:430
RingSectionList section_list_m
Definition Ring.h:460
double scale_m
Definition Ring.h:449
std::vector< RingSection * > getSectionsAt(const Vector_t< double, 3 > &pos)
Definition Ring.cpp:201
void checkMidplane(Euclid3D delta) const
Definition Ring.cpp:216
double beamPRInit_m
Definition Ring.h:425
void setLossDataSink(LossDataSink *sink)
Definition Ring.cpp:171
PartBunch_t * refPartBunch_m
Definition Ring.h:416
int symmetry_m
Definition Ring.h:447
double latticeRInit_m
Definition Ring.h:429
void setRefPartBunch(PartBunch_t *bunch)
Definition Ring.cpp:196
PlanarArcGeometry planarArcGeometry_m
Definition Ring.h:410
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition Ring.cpp:176
Ring(std::string ring)
Definition Ring.cpp:47
double phiStep_m
Definition Ring.h:458
void lockRing()
Definition Ring.cpp:306
bool isLocked_m
Definition Ring.h:440
void appendElement(const Component &element)
Definition Ring.cpp:252
void rotateToCyclCoordinates(Euclid3D &euclid3d) const
Definition Ring.cpp:226
double cyclHarm_m
Definition Ring.h:452
static const double lengthTolerance_m
Definition Ring.h:463
static const double angleTolerance_m
Definition Ring.h:464
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:67
void setComponentOrientation(Vector_t< double, 3 > orientation)
Vector_t< double, 3 > getStartPosition() const
void setEndPosition(Vector_t< double, 3 > pos)
Vector_t< double, 3 > getEndPosition() const
void setComponent(Component *component)
void setStartNormal(Vector_t< double, 3 > orientation)
Vector_t< double, 3 > getEndNormal() const
void setComponentPosition(Vector_t< double, 3 > position)
Vector_t< double, 3 > getStartNormal() const
void setEndNormal(Vector_t< double, 3 > orientation)
void setStartPosition(Vector_t< double, 3 > pos)