OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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"
38 #include "Structure/LossDataSink.h"
40 
41 // fairly generous tolerance here... maybe too generous? Maybe should be
42 // user parameter?
43 const double Ring::lengthTolerance_m = 1e-2;
44 const double Ring::angleTolerance_m = 1e-2;
45 
46 Ring::Ring(std::string ring)
47  : Component(ring), planarArcGeometry_m(1, 1),
48  refPartBunch_m(NULL),
49  lossDS_m(NULL),
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(NULL);
58 }
59 
60 void Ring::accept(BeamlineVisitor& visitor) const {
61  visitor.visitRing(*this);
62 }
63 
64 Ring::Ring(const Ring& ring)
65  : Component(ring.getName()),
66  planarArcGeometry_m(ring.planarArcGeometry_m),
67  lossDS_m(NULL),
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 != NULL)
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  delete lossDS_m;
96  for (size_t i = 0; i < section_list_m.size(); ++i)
97  delete section_list_m[i];
98 }
99 
100 bool Ring::apply(const size_t &id, const double &t, Vector_t &E,
101  Vector_t &B) {
102  bool flagNeedUpdate =
103  apply(refPartBunch_m->R[id], refPartBunch_m->P[id], t, E, B);
104  if(flagNeedUpdate) {
105  Inform gmsgALL("OPAL ", INFORM_ALL_NODES);
106  gmsgALL << getName() << ": particle " << id
107  << " at " << refPartBunch_m->R[id]
108  << " m out of the field map boundary" << endl;
110  refPartBunch_m->R[id] * Vector_t(1000.0), refPartBunch_m->P[id],
111  t,
112  refPartBunch_m->Q[id], refPartBunch_m->M[id]));
113  lossDS_m->save();
114 
115  refPartBunch_m->Bin[id] = -1;
116  }
117 
118  return flagNeedUpdate;
119 }
120 
121 bool Ring::apply(const Vector_t &R, const Vector_t &/*P*/,
122  const double &t, Vector_t &E, Vector_t &B) {
123  B = Vector_t(0.0, 0.0, 0.0);
124  E = Vector_t(0.0, 0.0, 0.0);
125 
126  std::vector<RingSection*> sections = getSectionsAt(R); // I think this doesn't actually use R -DW
127  bool outOfBounds = true;
128  // assume field maps don't set B, E to 0...
129  if (willDoAperture_m) {
130  double rSquared = R[0]*R[0]+R[1]*R[1];
131  if (rSquared < minR2_m || rSquared > maxR2_m) {
132  return true;
133  }
134  }
135 
136  for (size_t i = 0; i < sections.size(); ++i) {
137  Vector_t B_temp(0.0, 0.0, 0.0);
138  Vector_t E_temp(0.0, 0.0, 0.0);
139  // Super-TEMP! cyclotron tracker now uses m internally, have to change to mm here to match old field limits -DW
140  outOfBounds &= sections[i]->getFieldValue(R * Vector_t(1000.0), refPartBunch_m->get_centroid() * Vector_t(1000.0), t, E_temp, B_temp);
141  B += (scale_m * B_temp);
142  E += (scale_m * E_temp);
143  }
144  return outOfBounds;
145 }
146 
148  delete lossDS_m;
149  lossDS_m = sink;
150 }
151 
152 void Ring::getDimensions(double &/*zBegin*/, double &/*zEnd*/) const {
153  throw GeneralClassicException("Ring::getDimensions",
154  "Cannot get s-dimension of a ring");
155 }
156 
158  online_m = true;
159  setRefPartBunch(bunch);
160  setLossDataSink(new LossDataSink(getName(), false));
161 }
162 
163 void Ring::initialise(PartBunchBase<double, 3> * bunch, double &/*startField*/,
164  double &/*endField*/) {
165  initialise(bunch);
166 }
167 
169  online_m = false;
170  setRefPartBunch(NULL);
171  setLossDataSink(NULL);
172 }
173 
175  RefPartBunch_m = bunch; // inherited from Component
176  refPartBunch_m = bunch; // private data (obeys style guide)
177 }
178 
179 std::vector<RingSection*> Ring::getSectionsAt(const Vector_t& /*r*/) {
180  return section_list_m;
181 }
182 
184  // rotation from start to end in local coordinates
185  // Euclid3D/Rotation3D doesnt have a "getAngle" method so we use fairly
186  // obscure technique to extract it.
187  Vector3D rotationTest(1., 0., 0.);
188  rotationTest = delta.getRotation()*rotationTest;
189  double deltaAngle = std::atan2(rotationTest(2), rotationTest(0));
190  Rotation3D elementRotation = Rotation3D::ZRotation(deltaAngle);
191  return elementRotation;
192 }
193 
194 void Ring::checkMidplane(Euclid3D delta) const {
195  if (std::abs(delta.getVector()(2)) > lengthTolerance_m ||
196  std::abs(delta.getRotation().getAxis()(0)) > angleTolerance_m ||
197  std::abs(delta.getRotation().getAxis()(1)) > angleTolerance_m) {
198  throw GeneralClassicException("Ring::checkMidplane",
199  std::string("Placement of elements out of the ")+
200  "midplane is not supported by Ring");
201  }
202 }
203 
205  Vector3D v = delta.getVector();
206  Vector3D r = delta.getRotation().getAxis();
207  // Euclid3D euclid(v(0), -v(2), v(1), r(0), -r(2), r(1));
208  Euclid3D euclid(v(2), v(0), -v(1), r(2), r(0), -r(1));
209  delta = euclid;
210 }
211 
212 
214  if (section_list_m.size() > 0) {
215  return section_list_m.back()->getEndPosition();
216  }
219  0.);
220 }
221 
223  if (section_list_m.size() > 0) {
224  return section_list_m.back()->getEndNormal();
225  }
228  0.);
229 }
230 
231 void Ring::appendElement(const Component &element) {
232  if (isLocked_m) {
233  throw GeneralClassicException("Ring::appendElement",
234  "Attempt to append element "+element.getName()+
235  " when ring is locked");
236  }
237  // delta is transform from start of bend to end with x, z as horizontal
238  // I failed to get Rotation3D to work so use rotations written by hand.
239  // Probably an error in my call to Rotation3D.
240  Euclid3D delta = element.getGeometry().getTotalTransform();
242  checkMidplane(delta);
243 
244  RingSection* section = new RingSection();
245  Vector_t startPos = getNextPosition();
246  Vector_t startNorm = getNextNormal();
247 
248  section->setComponent(dynamic_cast<Component*>(element.clone()));
249  section->setStartPosition(startPos);
250  section->setStartNormal(startNorm);
251 
252  double startF = std::atan2(startNorm(1), startNorm(0));
253  Vector_t endPos = Vector_t(
254  +delta.getVector()(0)*std::cos(startF)-delta.getVector()(1)*std::sin(startF),
255  +delta.getVector()(0)*std::sin(startF)+delta.getVector()(1)*std::cos(startF),
256  0)+startPos;
257  section->setEndPosition(endPos);
258 
259  double endF = delta.getRotation().getAxis()(2);//+
260  //atan2(delta.getVector()(1), delta.getVector()(0));
261  Vector_t endNorm = Vector_t(
262  +startNorm(0)*std::cos(endF) + startNorm(1)*std::sin(endF),
263  -startNorm(0)*std::sin(endF) + startNorm(1)*std::cos(endF),
264  0);
265  section->setEndNormal(endNorm);
266 
267  section->setComponentPosition(startPos);
268  section->setComponentOrientation(Vector_t(0, 0, startF));
269 
270  section_list_m.push_back(section);
271 
272  double dphi = atan2(startNorm(0), startNorm(1));
273  Inform msg("OPAL");
274  msg << "* Added " << element.getName() << " to Ring" << endl;
275  msg << "* 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) << "), phi " << dphi << endl;
282  msg << "* 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  Inform msg("OPAL ");
293  if (isLocked_m) {
294  throw GeneralClassicException("Ring::lockRing",
295  "Attempt to lock ring when it is already locked");
296  }
297  // check for any elements at all
298  size_t sectionListSize = section_list_m.size();
299  if (sectionListSize == 0) {
300  throw GeneralClassicException("Ring::lockRing",
301  "Failed to find any elements in Ring");
302  }
303  // Apply symmetry properties; I think it is fastest to just duplicate
304  // elements rather than try to do some angle manipulations when we do field
305  // lookups because we do field lookups in Cartesian coordinates in general.
306  msg << "Applying symmetry to Ring" << endl;
307  for (int i = 1; i < symmetry_m; ++i) {
308  for (size_t j = 0; j < sectionListSize; ++j) {
309  appendElement(*section_list_m[j]->getComponent());
310  }
311  }
312  //resetAzimuths();
313  // Check that the ring is closed within tolerance and close exactly
314  if (isClosed_m)
315  checkAndClose();
317  isLocked_m = true;
318  for (size_t i = 0; i < section_list_m.size(); i++) {
319  }
320 }
321 
323  for (size_t i = 0; i < section_list_m.size(); ++i) {
324  Vector_t startPos = section_list_m[i]->getEndPosition();
325  Vector_t startDir = section_list_m[i]->getEndNormal();
326  Vector_t endPos = section_list_m[i]->getEndPosition();
327  Vector_t endDir = section_list_m[i]->getEndNormal();
328  if (!section_list_m[i]->isOnOrPastStartPlane(endPos)) {
329  section_list_m[i]->setEndPosition(startPos);
330  section_list_m[i]->setEndNormal(startDir);
331  section_list_m[i]->setStartPosition(endPos);
332  section_list_m[i]->setStartNormal(endDir);
333  }
334  }
335 }
336 
338  Vector_t first_pos = section_list_m[0]->getStartPosition();
339  Vector_t first_norm = section_list_m[0]->getStartNormal();
340  Vector_t last_pos = section_list_m.back()->getEndPosition();
341  Vector_t last_norm = section_list_m.back()->getEndNormal();
342  for (int i = 0; i < 3; ++i) {
343  if (std::abs(first_pos(i) - last_pos(i)) > lengthTolerance_m ||
344  std::abs(first_norm(i) - last_norm(i)) > angleTolerance_m)
345  throw GeneralClassicException("Ring::lockRing",
346  "Ring is not closed");
347  }
348  section_list_m.back()->setEndPosition(first_pos);
349  section_list_m.back()->setEndNormal(first_norm);
350 }
351 
353  size_t nSections = 2.*Physics::pi/phiStep_m+1;
354  ringSections_m = std::vector< std::vector<RingSection*> >(nSections);
355  for (size_t i = 0; i < ringSections_m.size(); ++i) {
356  double phi0 = i*phiStep_m;
357  double phi1 = (i+1)*phiStep_m;
358  // std::cerr << phi0 << " " << phi1 << std::endl;
359  for (size_t j = 0; j < section_list_m.size(); ++j) {
360  if (section_list_m[j]->doesOverlap(phi0, phi1))
361  ringSections_m[i].push_back(section_list_m[j]);
362  }
363  }
364 }
365 
367  if (section_list_m.size() == 0) {
368  return NULL;
369  }
370  return section_list_m.back();
371 }
372 
373 bool Ring::sectionCompare(RingSection const* const sec1,
374  RingSection const* const sec2) {
375  return sec1 > sec2;
376 }
377 
378 void Ring::setRingAperture(double minR, double maxR) {
379  if (minR < 0 || maxR < 0) {
380  throw GeneralClassicException("Ring::setRingAperture",
381  "Could not parse negative or undefined aperture limit");
382  }
383 
384  willDoAperture_m = true;
385  minR2_m = minR*minR;
386  maxR2_m = maxR*maxR;
387 }
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:195
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:194
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:213
void buildRingSections()
Definition: Ring.cpp:352
std::vector< RingSection * > getSectionsAt(const Vector_t &pos)
Definition: Ring.cpp:179
double maxR2_m
Definition: Ring.h:382
Rotation3D getRotationStartToEnd(Euclid3D delta) const
Definition: Ring.cpp:183
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:373
Vector_t getNextNormal() const
Definition: Ring.cpp:222
virtual void finalise() override
Definition: Ring.cpp:168
void checkAndClose()
Definition: Ring.cpp:337
void resetAzimuths()
Definition: Ring.cpp:322
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:100
RingSection * getLastSectionPlaced() const
Definition: Ring.cpp:366
void setRefPartBunch(PartBunchBase< double, 3 > *bunch)
Definition: Ring.cpp:174
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: Ring.cpp:163
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:378
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:194
void setLossDataSink(LossDataSink *sink)
Definition: Ring.cpp:147
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:152
double phiStep_m
Definition: Ring.h:403
void lockRing()
Definition: Ring.cpp:291
bool isLocked_m
Definition: Ring.h:385
void appendElement(const Component &element)
Definition: Ring.cpp:231
void rotateToCyclCoordinates(Euclid3D &euclid3d) const
Definition: Ring.cpp:204
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 addParticle(const OpalParticle &, const boost::optional< std::pair< int, short int >> &turnBunchNumPair=boost::none)
void save(unsigned int numSets=1, OpalData::OPENMODE openMode=OpalData::OPENMODE::UNDEFINED)
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