OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
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 
33 #include "Utility/Inform.h" // ippl
34 
35 #include "Fields/EMField.h"
37 #include "Structure/LossDataSink.h"
39 
40 // fairly generous tolerance here... maybe too generous? Maybe should be
41 // user parameter?
42 const double Ring::lengthTolerance_m = 1e-2;
43 const double Ring::angleTolerance_m = 1e-2;
44 
45 Ring::Ring(std::string ring)
46  : Component(ring), planarArcGeometry_m(1, 1),
47  refPartBunch_m(NULL),
48  lossDS_m(NULL),
49  beamRInit_m(0.), beamPRInit_m(0.), beamPhiInit_m(0.),
50  latticeRInit_m(0.), latticePhiInit_m(0.), latticeThetaInit_m(0.),
51  isLocked_m(false), isClosed_m(true),
52  symmetry_m(0), cyclHarm_m(0), rfFreq_m(0),
53  phiStep_m(Physics::pi/100.),
54  ringSections_m(),
55  section_list_m() {
56  setRefPartBunch(NULL);
57 }
58 
59 void Ring::accept(BeamlineVisitor& visitor) const {
60  visitor.visitRing(*this);
61 }
62 
63 Ring::Ring(const Ring& ring)
64  : Component(ring.getName()),
65  planarArcGeometry_m(ring.planarArcGeometry_m),
66  lossDS_m(NULL),
67  beamRInit_m(ring.beamRInit_m),
68  beamPRInit_m(ring.beamPRInit_m),
69  beamPhiInit_m(ring.beamPhiInit_m),
70  latticeRInit_m(ring.latticeRInit_m),
71  latticePhiInit_m(ring.latticePhiInit_m),
72  latticeThetaInit_m(ring.latticeThetaInit_m),
73  willDoAperture_m(ring.willDoAperture_m),
74  minR2_m(ring.minR2_m),
75  maxR2_m(ring.maxR2_m),
76  isLocked_m(ring.isLocked_m),
77  isClosed_m(ring.isClosed_m),
78  symmetry_m(ring.symmetry_m),
79  cyclHarm_m(ring.cyclHarm_m),
80  phiStep_m(ring.phiStep_m),
81  ringSections_m(),
82  section_list_m(ring.section_list_m.size()) {
84  if (ring.lossDS_m != NULL)
85  throw GeneralClassicException("Ring::Ring(const Ring&)",
86  "Can't copy construct LossDataSink so copy constructor fails");
87  for (size_t i = 0; i < section_list_m.size(); ++i) {
88  section_list_m[i] = new RingSection(*ring.section_list_m[i]);
89  }
91 }
92 
94  delete lossDS_m;
95  for (size_t i = 0; i < section_list_m.size(); ++i)
96  delete section_list_m[i];
97 }
98 
99 bool 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;
108  lossDS_m->addParticle(refPartBunch_m->R[id] * Vector_t(1000.0), refPartBunch_m->P[id], id);
109  lossDS_m->save();
110 
111  refPartBunch_m->Bin[id] = -1;
112  }
113 
114  return flagNeedUpdate;
115 }
116 
117 bool Ring::apply(const Vector_t &R, const Vector_t &P,
118  const double &t, Vector_t &E, Vector_t &B) {
119  B = Vector_t(0.0, 0.0, 0.0);
120  E = Vector_t(0.0, 0.0, 0.0);
121 
122  std::vector<RingSection*> sections = getSectionsAt(R); // I think this doesn't actually use R -DW
123  bool outOfBounds = true;
124  // assume field maps don't set B, E to 0...
125  if (willDoAperture_m) {
126  double rSquared = R[0]*R[0]+R[1]*R[1];
127  if (rSquared < minR2_m || rSquared > maxR2_m) {
128  return true;
129  }
130  }
131 
132  for (size_t i = 0; i < sections.size(); ++i) {
133  Vector_t B_temp(0.0, 0.0, 0.0);
134  Vector_t E_temp(0.0, 0.0, 0.0);
135  // Super-TEMP! cyclotron tracker now uses m internally, have to change to mm here to match old field limits -DW
136  outOfBounds &= sections[i]->getFieldValue(R * Vector_t(1000.0), refPartBunch_m->get_centroid() * Vector_t(1000.0), t, E_temp, B_temp);
137  B += (scale_m * B_temp);
138  E += (scale_m * E_temp);
139  }
140  return outOfBounds;
141 }
142 
144  delete lossDS_m;
145  lossDS_m = sink;
146 }
147 
148 void Ring::getDimensions(double &zBegin, double &zEnd) const {
149  throw GeneralClassicException("Ring::getDimensions",
150  "Cannot get s-dimension of a ring");
151 }
152 
154  online_m = true;
155  setRefPartBunch(bunch);
156  setLossDataSink(new LossDataSink(getName(), false));
157 }
158 
159 void Ring::initialise(PartBunchBase<double, 3> * bunch, double &startField,
160  double &endField) {
161  initialise(bunch);
162 }
163 
165  online_m = false;
166  setRefPartBunch(NULL);
167  setLossDataSink(NULL);
168 }
169 
171  RefPartBunch_m = bunch; // inherited from Component
172  refPartBunch_m = bunch; // private data (obeys style guide)
173 }
174 
175 std::vector<RingSection*> Ring::getSectionsAt(const Vector_t& r) {
176  return section_list_m;
177 }
178 
180  // rotation from start to end in local coordinates
181  // Euclid3D/Rotation3D doesnt have a "getAngle" method so we use fairly
182  // obscure technique to extract it.
183  Vector3D rotationTest(1., 0., 0.);
184  rotationTest = delta.getRotation()*rotationTest;
185  double deltaAngle = atan2(rotationTest(2), rotationTest(0));
186  Rotation3D elementRotation = Rotation3D::ZRotation(deltaAngle);
187  return elementRotation;
188 }
189 
190 void Ring::checkMidplane(Euclid3D delta) const {
191  if (fabs(delta.getVector()(2)) > lengthTolerance_m ||
192  fabs(delta.getRotation().getAxis()(0)) > angleTolerance_m ||
193  fabs(delta.getRotation().getAxis()(1)) > angleTolerance_m) {
194  throw GeneralClassicException("Ring::checkMidplane",
195  std::string("Placement of elements out of the ")+
196  "midplane is not supported by Ring");
197  }
198 }
199 
201  Vector3D v = delta.getVector();
202  Vector3D r = delta.getRotation().getAxis();
203  // Euclid3D euclid(v(0), -v(2), v(1), r(0), -r(2), r(1));
204  Euclid3D euclid(v(2), v(0), -v(1), r(2), r(0), -r(1));
205  delta = euclid;
206 }
207 
208 
210  if (section_list_m.size() > 0) {
211  return section_list_m.back()->getEndPosition();
212  }
215  0.);
216 }
217 
219  if (section_list_m.size() > 0) {
220  return section_list_m.back()->getEndNormal();
221  }
224  0.);
225 }
226 
227 void Ring::appendElement(const Component &element) {
228  if (isLocked_m) {
229  throw GeneralClassicException("Ring::appendElement",
230  "Attempt to append element "+element.getName()+
231  " when ring is locked");
232  }
233  // delta is transform from start of bend to end with x, z as horizontal
234  // I failed to get Rotation3D to work so use rotations written by hand.
235  // Probably an error in my call to Rotation3D.
236  Euclid3D delta = element.getGeometry().getTotalTransform();
238  checkMidplane(delta);
239 
240  RingSection* section = new RingSection();
241  Vector_t startPos = getNextPosition();
242  Vector_t startNorm = getNextNormal();
243 
244  section->setComponent(dynamic_cast<Component*>(element.clone()));
245  section->setStartPosition(startPos);
246  section->setStartNormal(startNorm);
247 
248  double startF = atan2(startNorm(1), startNorm(0));
249  Vector_t endPos = Vector_t(
250  +delta.getVector()(0)*cos(startF)-delta.getVector()(1)*sin(startF),
251  +delta.getVector()(0)*sin(startF)+delta.getVector()(1)*cos(startF),
252  0)+startPos;
253  section->setEndPosition(endPos);
254 
255  double endF = delta.getRotation().getAxis()(2);//+
256  //atan2(delta.getVector()(1), delta.getVector()(0));
257  Vector_t endNorm = Vector_t(
258  +startNorm(0)*cos(endF) + startNorm(1)*sin(endF),
259  -startNorm(0)*sin(endF) + startNorm(1)*cos(endF),
260  0);
261  section->setEndNormal(endNorm);
262 
263  section->setComponentPosition(startPos);
264  section->setComponentOrientation(Vector_t(0, 0, startF));
265 
266  section_list_m.push_back(section);
267 
268  double dphi = atan2(startNorm(0), startNorm(1));
269  Inform msg("OPAL");
270  msg << "* Added " << element.getName() << " to Ring" << endl;
271  msg << "* Start position ("
272  << section->getStartPosition()(0) << ", "
273  << section->getStartPosition()(1) << ", "
274  << section->getStartPosition()(2) << ") normal ("
275  << section->getStartNormal()(0) << ", "
276  << section->getStartNormal()(1) << ", "
277  << section->getStartNormal()(2) << "), phi " << dphi << endl;
278  msg << "* End position ("
279  << section->getEndPosition()(0) << ", "
280  << section->getEndPosition()(1) << ", "
281  << section->getEndPosition()(2) << ") normal ("
282  << section->getEndNormal()(0) << ", "
283  << section->getEndNormal()(1) << ", "
284  << section->getEndNormal()(2) << ")" << endl;
285 }
286 
288  Inform msg("OPAL ");
289  if (isLocked_m) {
290  throw GeneralClassicException("Ring::lockRing",
291  "Attempt to lock ring when it is already locked");
292  }
293  // check for any elements at all
294  size_t sectionListSize = section_list_m.size();
295  if (sectionListSize == 0) {
296  throw GeneralClassicException("Ring::lockRing",
297  "Failed to find any elements in Ring");
298  }
299  // Apply symmetry properties; I think it is fastest to just duplicate
300  // elements rather than try to do some angle manipulations when we do field
301  // lookups because we do field lookups in Cartesian coordinates in general.
302  msg << "Applying symmetry to Ring" << endl;
303  for (int i = 1; i < symmetry_m; ++i) {
304  for (size_t j = 0; j < sectionListSize; ++j) {
305  appendElement(*section_list_m[j]->getComponent());
306  }
307  }
308  //resetAzimuths();
309  // Check that the ring is closed within tolerance and close exactly
310  if (isClosed_m)
311  checkAndClose();
313  isLocked_m = true;
314  for (size_t i = 0; i < section_list_m.size(); i++) {
315  }
316 }
317 
319  for (size_t i = 0; i < section_list_m.size(); ++i) {
320  Vector_t startPos = section_list_m[i]->getEndPosition();
321  Vector_t startDir = section_list_m[i]->getEndNormal();
322  Vector_t endPos = section_list_m[i]->getEndPosition();
323  Vector_t endDir = section_list_m[i]->getEndNormal();
324  if (!section_list_m[i]->isOnOrPastStartPlane(endPos)) {
325  section_list_m[i]->setEndPosition(startPos);
326  section_list_m[i]->setEndNormal(startDir);
327  section_list_m[i]->setStartPosition(endPos);
328  section_list_m[i]->setStartNormal(endDir);
329  }
330  }
331 }
332 
334  Vector_t first_pos = section_list_m[0]->getStartPosition();
335  Vector_t first_norm = section_list_m[0]->getStartNormal();
336  Vector_t last_pos = section_list_m.back()->getEndPosition();
337  Vector_t last_norm = section_list_m.back()->getEndNormal();
338  for (int i = 0; i < 3; ++i) {
339  if (fabs(first_pos(i) - last_pos(i)) > lengthTolerance_m ||
340  fabs(first_norm(i) - last_norm(i)) > angleTolerance_m)
341  throw GeneralClassicException("Ring::lockRing",
342  "Ring is not closed");
343  }
344  section_list_m.back()->setEndPosition(first_pos);
345  section_list_m.back()->setEndNormal(first_norm);
346 }
347 
349  size_t nSections = 2.*Physics::pi/phiStep_m+1;
350  ringSections_m = std::vector< std::vector<RingSection*> >(nSections);
351  for (size_t i = 0; i < ringSections_m.size(); ++i) {
352  double phi0 = i*phiStep_m;
353  double phi1 = (i+1)*phiStep_m;
354  // std::cerr << phi0 << " " << phi1 << std::endl;
355  for (size_t j = 0; j < section_list_m.size(); ++j) {
356  if (section_list_m[j]->doesOverlap(phi0, phi1))
357  ringSections_m[i].push_back(section_list_m[j]);
358  }
359  }
360 }
361 
363  if (section_list_m.size() == 0) {
364  return NULL;
365  }
366  return section_list_m.back();
367 }
368 
369 bool Ring::sectionCompare(RingSection const* const sec1,
370  RingSection const* const sec2) {
371  return sec1 > sec2;
372 }
373 
374 void Ring::setRingAperture(double minR, double maxR) {
375  if (minR < 0 || maxR < 0) {
376  throw GeneralClassicException("Ring::setRingAperture",
377  "Could not parse negative or undefined aperture limit");
378  }
379 
380  willDoAperture_m = true;
381  minR2_m = minR*minR;
382  maxR2_m = maxR*maxR;
383 }
384 
bool willDoAperture_m
Definition: Ring.h:380
void setStartNormal(Vector_t orientation)
Definition: RingSection.h:206
ParticleAttrib< Vector_t > P
bool isClosed_m
Definition: Ring.h:389
void setComponentPosition(Vector_t position)
Definition: RingSection.h:166
void setEndNormal(Vector_t orientation)
Definition: RingSection.h:210
constexpr double e
The value of .
Definition: Physics.h:40
PartBunchBase< double, 3 > * refPartBunch_m
Definition: Ring.h:361
virtual bool apply(const size_t &id, const double &t, Vector_t &E, Vector_t &B) override
Definition: Ring.cpp:99
#define INFORM_ALL_NODES
Definition: Inform.h:38
virtual BGeometryBase & getGeometry()=0
Get geometry.
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:815
std::vector< RingSectionList > ringSections_m
Definition: Ring.h:404
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
double phiStep_m
Definition: Ring.h:403
double latticeThetaInit_m
Definition: Ring.h:376
void lockRing()
Definition: Ring.cpp:287
RingSection * getLastSectionPlaced() const
Definition: Ring.cpp:362
bool online_m
Definition: Component.h:201
virtual const std::string & getName() const
Get element name.
Definition: ElementBase.cpp:95
static bool sectionCompare(RingSection const *const sec1, RingSection const *const sec2)
Definition: Ring.cpp:369
double minR2_m
Definition: Ring.h:381
double scale_m
Definition: Ring.h:394
bool isLocked_m
Definition: Ring.h:385
void setRefPartBunch(PartBunchBase< double, 3 > *bunch)
Definition: Ring.cpp:170
double latticePhiInit_m
Definition: Ring.h:375
double maxR2_m
Definition: Ring.h:382
virtual void visitRing(const Ring &)=0
Apply the algorithm to an Ring.
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: Ring.cpp:159
void setComponentOrientation(Vector_t orientation)
Definition: RingSection.h:201
void setComponent(Component *component)
Definition: RingSection.h:133
void save(unsigned int numSets=1, OpalData::OPENMODE openMode=OpalData::OPENMODE::UNDEFINED)
void setStartPosition(Vector_t pos)
Definition: RingSection.h:142
std::vector< RingSection * > getSectionsAt(const Vector_t &pos)
Definition: Ring.cpp:175
Vector_t getNextPosition() const
Definition: Ring.cpp:209
constexpr double pi
The value of .
Definition: Physics.h:31
Vector_t getStartNormal() const
Definition: RingSection.h:151
LossDataSink * lossDS_m
Definition: Ring.h:366
static const double angleTolerance_m
Definition: Ring.h:409
virtual ~Ring()
Definition: Ring.cpp:93
const double pi
Definition: fftpack.cpp:894
void setRingAperture(double minR, double maxR)
Definition: Ring.cpp:374
Vector_t getEndPosition() const
Definition: RingSection.h:157
virtual Euclid3D getTotalTransform() const
Get transform.
Definition: Geometry.cpp:51
void buildRingSections()
Definition: Ring.cpp:348
Displacement and rotation in space.
Definition: Euclid3D.h:68
virtual void finalise() override
Definition: Ring.cpp:164
virtual void getDimensions(double &zBegin, double &zEnd) const override
Definition: Ring.cpp:148
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:200
static Rotation3D ZRotation(double angle)
Make rotation.
Definition: Rotation3D.cpp:147
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
Component placement handler in ring geometry.
Definition: RingSection.h:67
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
void checkAndClose()
Definition: Ring.cpp:333
void setLossDataSink(LossDataSink *sink)
Definition: Ring.cpp:143
const Rotation3D & getRotation() const
Get rotation.
Definition: Euclid3D.cpp:64
Vector_t get_centroid() const
virtual ElementBase * clone() const =0
Return clone.
RingSectionList section_list_m
Definition: Ring.h:405
Rotation3D getRotationStartToEnd(Euclid3D delta) const
Definition: Ring.cpp:179
A 3-dimension vector.
Definition: Vector3D.h:31
void setEndPosition(Vector_t pos)
Definition: RingSection.h:154
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
static const double lengthTolerance_m
Definition: Ring.h:408
double latticeRInit_m
Definition: Ring.h:374
void appendElement(const Component &element)
Definition: Ring.cpp:227
Vector_t getStartPosition() const
Definition: RingSection.h:145
Vector_t getNextNormal() const
Definition: Ring.cpp:218
ParticleAttrib< int > Bin
void resetAzimuths()
Definition: Ring.cpp:318
Ring describes a ring type geometry for tracking.
Definition: Ring.h:64
virtual void accept(BeamlineVisitor &visitor) const override
Definition: Ring.cpp:59
ParticlePos_t & R
Vector_t getEndNormal() const
Definition: RingSection.h:163
Interface for a single beam element.
Definition: Component.h:51
Abstract algorithm.
Definition: Inform.h:41
Rotation in 3-dimensional space.
Definition: Rotation3D.h:46
void rotateToCyclCoordinates(Euclid3D &euclid3d) const
Definition: Ring.cpp:200
Vector3D getAxis() const
Get axis vector.
Definition: Rotation3D.cpp:91
void addParticle(const Vector_t &x, const Vector_t &p, const size_t id)
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
void checkMidplane(Euclid3D delta) const
Definition: Ring.cpp:190
const Vector3D & getVector() const
Get displacement.
Definition: Euclid3D.cpp:59
int symmetry_m
Definition: Ring.h:392