OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
Bend2D.cpp
Go to the documentation of this file.
1 // ------------------------------------------------------------------------
2 // $RCSfile: Bend2D.cpp,v $
3 // ------------------------------------------------------------------------
4 // $Revision: 1.1.1.1 $
5 // ------------------------------------------------------------------------
6 // Copyright: see Copyright.readme
7 // ------------------------------------------------------------------------
8 //
9 // Definitions for class: Bend2D
10 // Defines the abstract interface for a sector bend magnet.
11 //
12 // ------------------------------------------------------------------------
13 // Class category: AbsBeamline
14 // ------------------------------------------------------------------------
15 //
16 // $Date: 2000/03/27 09:32:31 $
17 // $Author: fci $
18 //
19 // ------------------------------------------------------------------------
20 
21 #include "AbsBeamline/Bend2D.h"
24 #include "Algorithms/BoostMatrix.h"
26 #include "Fields/Fieldmap.h"
27 #include "Physics/Units.h"
29 #include "Utilities/Options.h"
30 #include "Utilities/Util.h"
31 
32 #include "gsl/gsl_poly.h"
33 
34 #include <iostream>
35 #include <fstream>
36 
37 extern Inform *gmsg;
38 
39 // Class Bend2D
40 // ------------------------------------------------------------------------
41 
43  Bend2D("")
44 {}
45 
46 Bend2D::Bend2D(const Bend2D &right):
47  BendBase(right),
48  messageHeader_m(" * "),
49  pusher_m(right.pusher_m),
50  designRadius_m(right.designRadius_m),
51  exitAngle_m(right.exitAngle_m),
52  fieldIndex_m(right.fieldIndex_m),
53  startField_m(right.startField_m),
54  endField_m(right.endField_m),
55  widthEntranceFringe_m(right.widthEntranceFringe_m),
56  widthExitFringe_m(right.widthExitFringe_m),
57  reinitialize_m(right.reinitialize_m),
58  entranceParameter1_m(right.entranceParameter1_m),
59  entranceParameter2_m(right.entranceParameter2_m),
60  entranceParameter3_m(right.entranceParameter3_m),
61  exitParameter1_m(right.exitParameter1_m),
62  exitParameter2_m(right.exitParameter2_m),
63  exitParameter3_m(right.exitParameter3_m),
64  engeCoeffsEntry_m(right.engeCoeffsEntry_m),
65  engeCoeffsExit_m(right.engeCoeffsExit_m),
66  entryFieldValues_m(nullptr),
67  exitFieldValues_m(nullptr),
68  entryFieldAccel_m(nullptr),
69  exitFieldAccel_m(nullptr),
70  deltaBeginEntry_m(right.deltaBeginEntry_m),
71  deltaEndEntry_m(right.deltaEndEntry_m),
72  polyOrderEntry_m(right.polyOrderEntry_m),
73  deltaBeginExit_m(right.deltaBeginExit_m),
74  deltaEndExit_m(right.deltaEndExit_m),
75  polyOrderExit_m(right.polyOrderExit_m),
76  cosEntranceAngle_m(right.cosEntranceAngle_m),
77  sinEntranceAngle_m(right.sinEntranceAngle_m),
78  tanEntranceAngle_m(right.tanEntranceAngle_m),
79  tanExitAngle_m(right.tanExitAngle_m),
80  beginToEnd_m(right.beginToEnd_m),
81  beginToEnd_lcs_m(right.beginToEnd_lcs_m),
82  toEntranceRegion_m(right.toEntranceRegion_m),
83  toExitRegion_m(right.toExitRegion_m),
84  computeAngleTrafo_m(right.computeAngleTrafo_m),
85  maxAngle_m(right.maxAngle_m),
86  nSlices_m(right.nSlices_m){
87 }
88 
89 Bend2D::Bend2D(const std::string &name):
90  BendBase(name),
91  messageHeader_m(" * "),
92  pusher_m(),
93  designRadius_m(0.0),
94  exitAngle_m(0.0),
95  fieldIndex_m(0.0),
96  startField_m(0.0),
97  endField_m(0.0),
98  widthEntranceFringe_m(0.0),
99  widthExitFringe_m(0.0),
100  reinitialize_m(false),
101  entranceParameter1_m(0.0),
102  entranceParameter2_m(0.0),
103  entranceParameter3_m(0.0),
104  exitParameter1_m(0.0),
105  exitParameter2_m(0.0),
106  exitParameter3_m(0.0),
107  entryFieldValues_m(nullptr),
108  exitFieldValues_m(nullptr),
109  entryFieldAccel_m(nullptr),
110  exitFieldAccel_m(nullptr),
111  deltaBeginEntry_m(0.0),
112  deltaEndEntry_m(0.0),
113  polyOrderEntry_m(0),
114  deltaBeginExit_m(0.0),
115  deltaEndExit_m(0.0),
116  polyOrderExit_m(0),
117  cosEntranceAngle_m(1.0),
118  sinEntranceAngle_m(0.0),
119  tanEntranceAngle_m(0.0),
120  tanExitAngle_m(0.0),
121  maxAngle_m(0.0),
122  nSlices_m(1){
123 }
124 
126  if (entryFieldAccel_m != nullptr) {
127  for (unsigned int i = 0; i < 3u; ++ i) {
128  gsl_spline_free(entryFieldValues_m[i]);
129  gsl_spline_free(exitFieldValues_m[i]);
130  entryFieldValues_m[i] = nullptr;
131  exitFieldValues_m[i] = nullptr;
132  }
133  delete[] entryFieldValues_m;
134  delete[] exitFieldValues_m;
135 
136  gsl_interp_accel_free(entryFieldAccel_m);
137  gsl_interp_accel_free(exitFieldAccel_m);
138  }
139 }
140 /*
141  * OPAL-T Methods.
142  * ===============
143  */
144 
145 /*
146  * This function merely repackages the field arrays as type Vector_t and calls
147  * the equivalent method but with the Vector_t data types.
148  */
149 bool Bend2D::apply(const size_t &i,
150  const double &t,
151  Vector_t &E,
152  Vector_t &B) {
153  Vector_t P;
154  return apply(RefPartBunch_m->R[i], P, t, E, B);
155 }
156 
158  const Vector_t &/*P*/,
159  const double &/*t*/,
160  Vector_t &/*E*/,
161  Vector_t &B) {
162 
163  if (designRadius_m > 0.0) {
164 
165  Vector_t X = R;
166  Vector_t bField(0.0);
167  if (!calculateMapField(X, bField)) {
168 
169  B += fieldAmplitude_m * bField;
170 
171  return false;
172  }
173 
175  }
176  return false;
177 
178 }
179 
181  const Vector_t &P,
182  const double &t,
183  Vector_t &E,
184  Vector_t &B) {
185  return apply(R, P, t, E, B);
186 }
187 
188 void Bend2D::goOnline(const double &) {
189  online_m = true;
190 }
191 
193  double &startField,
194  double &endField) {
195 
196  Inform msg(messageHeader_m.c_str(), *gmsg);
197 
198  if (initializeFieldMap()) {
199  std::string name = Util::toUpper(getName()) + " ";
200  msg << level2
201  << "======================================================================\n"
202  << "===== " << std::left << std::setw(64) << std::setfill('=') << name << "\n"
203  << "======================================================================\n";
204 
205  setupPusher(bunch);
206  readFieldMap(msg);
207  setupBendGeometry(startField, endField);
208 
209  double bendAngleX = 0.0;
210  double bendAngleY = 0.0;
211  calculateRefTrajectory(bendAngleX, bendAngleY);
212  print(msg, bendAngleX, bendAngleY);
214  // Pass start and end of field to calling function.
215  startField = startField_m;
216  endField = endField_m;
217 
220  elementEdge_m = 0.0;
221 
223  msg << level2
224  << "======================================================================\n"
225  << "======================================================================\n"
226  << endl;
227  } else {
228  ERRORMSG("There is something wrong with your field map '"
229  << fileName_m << "'");
230  endField = startField - 1.0e-3;
231  }
232 }
233 
234 void Bend2D::adjustFringeFields(double ratio) {
236 
238  entranceParameter1_m = entranceParameter2_m - delta * ratio;
239 
241  entranceParameter3_m = entranceParameter2_m + delta * ratio;
242 
244  exitParameter1_m = exitParameter2_m - delta * ratio;
245 
247  exitParameter3_m = exitParameter2_m + delta * ratio;
248 
250 }
251 
253 
254  const double betaGamma = calcBetaGamma();
255  // const double beta = betaGamma / gamma;
256  const double deltaT = RefPartBunch_m->getdT();
257  const double cdt = Physics::c * deltaT;
258  // Integrate through field for initial angle.
259  Vector_t oldX;
261  Vector_t P = betaGamma * Vector_t(sinEntranceAngle_m, 0.0, cosEntranceAngle_m);
262  double deltaS = 0.0;
263  double bendLength = endField_m - startField_m;
264  const Vector_t eField(0.0);
265 
266  while (deltaS < bendLength) {
267  oldX = X;
268  X /= cdt;
269  pusher_m.push(X, P, deltaT);
270  X *= cdt;
271 
272  Vector_t bField(0.0, 0.0, 0.0);
273  calculateMapField(X, bField);
274  bField = fieldAmplitude_m * bField;
275 
276  X /= cdt;
277  pusher_m.kick(X, P, eField, bField, deltaT);
278 
279  pusher_m.push(X, P, deltaT);
280  X *= cdt;
281 
282  deltaS += euclidean_norm(X - oldX);
283 
284  }
285 
286  double angle = - std::atan2(P(0), P(2)) + entranceAngle_m;
287 
288  return angle;
289 }
290 
291 void Bend2D::calcEngeFunction(double zNormalized,
292  const std::vector<double> &engeCoeff,
293  int polyOrder,
294  double &engeFunc,
295  double &engeFuncDeriv,
296  double &engeFuncSecDerivNorm) {
297 
298  double expSum = 0.0;
299  double expSumDeriv = 0.0;
300  double expSumSecDeriv = 0.0;
301 
302  if (polyOrder >= 2) {
303 
304  expSum = engeCoeff.at(0)
305  + engeCoeff.at(1) * zNormalized;
306  expSumDeriv = engeCoeff.at(1);
307 
308  for (int index = 2; index <= polyOrder; index++) {
309  expSum += engeCoeff.at(index) * std::pow(zNormalized, index);
310  expSumDeriv += index * engeCoeff.at(index)
311  * std::pow(zNormalized, index - 1);
312  expSumSecDeriv += index * (index - 1) * engeCoeff.at(index)
313  * std::pow(zNormalized, index - 2);
314  }
315 
316  } else if (polyOrder == 1) {
317 
318  expSum = engeCoeff.at(0)
319  + engeCoeff.at(1) * zNormalized;
320  expSumDeriv = engeCoeff.at(1);
321 
322  } else
323  expSum = engeCoeff.at(0);
324 
325  double engeExp = std::exp(expSum);
326  engeFunc = 1.0 / (1.0 + engeExp);
327 
328  if (!std::isnan(engeFunc)) {
329 
330  expSumDeriv /= gap_m;
331  expSumSecDeriv /= std::pow(gap_m, 2.0);
332  double engeExpDeriv = expSumDeriv * engeExp;
333  double engeExpSecDeriv = (expSumSecDeriv + std::pow(expSumDeriv, 2.0))
334  * engeExp;
335  double engeFuncSq = std::pow(engeFunc, 2.0);
336 
337  engeFuncDeriv = -engeExpDeriv * engeFuncSq;
338  if (std::isnan(engeFuncDeriv) || std::isinf(engeFuncDeriv))
339  engeFuncDeriv = 0.0;
340 
341  engeFuncSecDerivNorm = -engeExpSecDeriv * engeFunc
342  + 2.0 * std::pow(engeExpDeriv, 2.0)
343  * engeFuncSq;
344  if (std::isnan(engeFuncSecDerivNorm) || std::isinf(engeFuncSecDerivNorm))
345  engeFuncSecDerivNorm = 0.0;
346 
347  } else {
348  engeFunc = 0.0;
349  engeFuncDeriv = 0.0;
350  engeFuncSecDerivNorm = 0.0;
351 
352  }
353 }
354 
355 // :FIXME: is this correct?
356 Vector_t Bend2D::calcCentralField(const Vector_t &/*R*/, double /*deltaX*/) {
357 
358  Vector_t B(0, 0, 0);
359  //double nOverRho = fieldIndex_m / designRadius_m;
360  //double expFactor = exp(-nOverRho * deltaX);
361  //double bxBzFactor = expFactor * nOverRho * R(1);
362  //Vector_t rotationCenter(-designRadius_m, R(1), 0.0);
363  //double cosangle = dot(R - rotationCenter, Vector_t(1, 0, 0)) / euclidean_norm(R - rotationCenter);
364 
365  //B(0) = -bxBzFactor * cosangle;
366  //B(1) = expFactor * (1.0 - std::pow(nOverRho * R(1), 2.0) / 2.0);
367  //B(2) = -bxBzFactor * std::sqrt(1 - std::pow(cosangle, 2));
368 
369  B(1) = 1.0;
370 
371  return B;
372 }
373 
375  double /*deltaX*/) {
376 
377  const CoordinateSystemTrafo toEntranceRegion(Vector_t(0, 0, entranceParameter2_m),
378  Quaternion(0, 0, 1, 0));
379  const Vector_t Rprime = toEntranceRegion.transformTo(R);
380 
381  Vector_t B(0.0);
382 
383  if (Rprime(2) <= -entranceParameter3_m) {
384  B(1) = 1;
385  } else if (Rprime(2) < -entranceParameter1_m) {
386  double engeFunc = gsl_spline_eval(entryFieldValues_m[0], Rprime(2), entryFieldAccel_m);
387  double engeFuncDeriv = gsl_spline_eval(entryFieldValues_m[1], Rprime(2), entryFieldAccel_m);
388  double engeFuncSecDeriv = gsl_spline_eval(entryFieldValues_m[2], Rprime(2), entryFieldAccel_m);
389 
390  //double nOverRho = fieldIndex_m / designRadius_m;
391  //double expFactor = exp(-nOverRho * deltaX);
392  //double trigFactor = pow(nOverRho, 2.0) + engeFuncSecDerivNorm;
393 
394  //double bXEntrance = -nOverRho * expFactor * Rprime(1) * engeFunc;
395  //double bYEntrance = (expFactor * engeFunc *
396  // (1.0 - 0.5 * trigFactor * pow(Rprime(1), 2.0)));
397  //double bZEntrance = expFactor * Rprime(1) * engeFuncDeriv;
398 
399 
400  // B(1) = (engeFunc *
401  // (1.0 - 0.5 * engeFuncSecDerivNorm * pow(Rprime(1), 2.0)));
402 
403  B(1) = (engeFunc - 0.5 * engeFuncSecDeriv * std::pow(Rprime(1), 2.0));
404 
405  B(2) = engeFuncDeriv * Rprime(1);
406  }
407 
408  return toEntranceRegion.rotateFrom(B);
409 }
410 
412  double /*deltaX*/) {
413 
414  const CoordinateSystemTrafo fromEndToExitRegion(Vector_t(0, 0, exitParameter2_m),
415  Quaternion(1, 0, 0, 0));
416  const CoordinateSystemTrafo toExitRegion = (fromEndToExitRegion *
418  const Vector_t Rprime = toExitRegion.transformTo(R);
419 
420  Vector_t B(0.0);
421 
422  if (Rprime(2) <= exitParameter1_m) {
423  B(1) = 1;
424  } else if (Rprime(2) < exitParameter3_m) {
425  double engeFunc = gsl_spline_eval(exitFieldValues_m[0], Rprime(2), exitFieldAccel_m);
426  double engeFuncDeriv = gsl_spline_eval(exitFieldValues_m[1], Rprime(2), exitFieldAccel_m);
427  double engeFuncSecDeriv = gsl_spline_eval(exitFieldValues_m[2], Rprime(2), exitFieldAccel_m);
428 
429  //double nOverRho = fieldIndex_m / designRadius_m;
430  //double expFactor = exp(-nOverRho * deltaX);
431  //double trigFactor = pow(nOverRho, 2.0) + engeFuncSecDerivNorm;
432 
433  //double bXExit = -nOverRho * expFactor * Rprime(1) * engeFunc;
434  //double bYExit = (expFactor * engeFunc *
435  // (1.0 - 0.5 * trigFactor * pow(Rprime(1), 2.0)));
436  //double bZExit = expFactor * Rprime(1) * engeFuncDeriv;
437 
438  //B(1) = (engeFunc *
439  // (1.0 - 0.5 * engeFuncSecDerivNorm * pow(Rprime(1), 2.0)));
440  B(1) = (engeFunc - 0.5 * engeFuncSecDeriv * std::pow(Rprime(1), 2.0));
441 
442  B(2) = engeFuncDeriv * Rprime(1);
443  }
444  return toExitRegion.rotateFrom(B);
445 }
446 
448 
449  B = Vector_t(0.0);
450  bool verticallyInside = (std::abs(R(1)) < 0.5 * gap_m);
451  bool horizontallyInside = false;
453  if (inMagnetCentralRegion(R)) {
454  if (verticallyInside) {
455  double deltaX = 0.0;//euclidean_norm(R - rotationCenter) - designRadius_m;
456  bool inEntranceRegion = isPositionInEntranceField(R);
457  bool inExitRegion = isPositionInExitField(R);
458 
459  if (inEntranceRegion && inExitRegion) {
462 
463  if (std::abs(Rp[2]) < std::abs(Rpp[2])) {
464  inExitRegion = false;
465  } else {
466  inEntranceRegion = false;
467  }
468  }
469  if (inEntranceRegion) {
470  B = calcEntranceFringeField(R, deltaX);
471  } else if (inExitRegion) {
472  B = calcExitFringeField(R, deltaX);
473  } else {
474  B = calcCentralField(R, deltaX);
475  }
476 
477  return false;
478  }
479  return true;
480  }
481 
482  Vector_t BEntrance(0.0), BExit(0.0);
483  verticallyInside = (std::abs(R(1)) < gap_m);
484 
485  bool inEntranceRegion = inMagnetEntranceRegion(R);
486  bool inExitRegion = inMagnetExitRegion(R);
487 
488  if (inEntranceRegion) {
489  horizontallyInside = true;
490  if (verticallyInside) {
491  BEntrance = calcEntranceFringeField(R, R(0));
492  }
493  }
494 
495  if (inExitRegion) {
496  horizontallyInside = true;
497  if (verticallyInside) {
499 
500  BExit = calcExitFringeField(R, Rprime(0));
501  }
502  }
503 
504  B = BEntrance + BExit;
505 
506  bool hitMaterial = (horizontallyInside && (!verticallyInside));
507  return hitMaterial;
508 }
509 
510 void Bend2D::calculateRefTrajectory(double &angleX, double &/*angleY*/) {
511 
512  std::ofstream trajectoryOutput;
514  std::string fname = Util::combineFilePath({
516  OpalData::getInstance()->getInputBasename() + "_" + getName() + "_traj.dat"
517  });
518  trajectoryOutput.open(fname);
519  trajectoryOutput.precision(12);
520  trajectoryOutput << "# " << std::setw(18) << "s"
521  << std::setw(20) << "x"
522  << std::setw(20) << "z"
523  << std::setw(20) << "By"
524  << std::endl;
525  }
526 
527  const double gamma = calcGamma();
528  const double betaGamma = calcBetaGamma();
530  Vector_t P = betaGamma * Vector_t(sinEntranceAngle_m, 0.0, cosEntranceAngle_m);
531 
532  if (!refTrajMap_m.empty())
533  refTrajMap_m.clear();
534 
535  refTrajMap_m.push_back(X);
536 
537  const Vector_t eField(0.0);
538  const double dt = RefPartBunch_m->getdT();
539  const Vector_t scaleFactor(Physics::c * dt);
540  const double stepSize = betaGamma / gamma * Physics::c * dt;
541  const double bendLength = endField_m - startField_m;
542  double deltaS = 0.0;
543  while (deltaS < bendLength) {
544 
545  X /= scaleFactor;
546  pusher_m.push(X, P, dt);
547  X *= scaleFactor;
548 
549  Vector_t bField(0.0, 0.0, 0.0);
550  Vector_t XInBendFrame = X;
551 
552  calculateMapField(XInBendFrame, bField);
553  bField = fieldAmplitude_m * bField;
554 
556  trajectoryOutput << std::setw(20) << deltaS + 0.5 * stepSize
557  << std::setw(20) << X(0)
558  << std::setw(20) << X(2)
559  << std::setw(20) << bField(1)
560  << std::endl;
561  }
562 
563  X /= scaleFactor;
564  pusher_m.kick(X, P, eField, bField, dt);
565 
566  pusher_m.push(X, P, dt);
567  X *= scaleFactor;
568 
569  refTrajMap_m.push_back(X);
570 
571  deltaS += stepSize;
572  }
573 
574  angleX = -std::atan2(P(0), P(2)) + entranceAngle_m;
575 }
576 
577 double Bend2D::estimateFieldAdjustmentStep(double actualBendAngle) {
578 
579  // Estimate field adjustment step.
580  double effectiveLength = angle_m * designRadius_m;
581  double effectiveFieldAmplitude = calcFieldAmplitude(2.0 * effectiveLength);
582  double ratioSquared = std::pow(fieldAmplitude_m / effectiveFieldAmplitude, 2.0);
583  double fieldStep = (angle_m - actualBendAngle) * effectiveFieldAmplitude;
584  if (ratioSquared < 1.0) {
585  fieldStep = (angle_m - actualBendAngle) * effectiveFieldAmplitude * std::sqrt(1.0 - ratioSquared);
586  }
588 
589  return fieldStep;
590 
591 }
592 
593 void Bend2D::findBendEffectiveLength(double startField, double endField) {
594 
595  /*
596  * Use an iterative procedure to set the width of the
597  * default field map for the defined field amplitude
598  * and bend angle.
599  */
600  setEngeOriginDelta(0.0);
602  setFieldBoundaries(startField, endField);
603 
604  double actualBendAngle = calculateBendAngle();
605  double error = std::abs(actualBendAngle - angle_m);
606 
607  if (error > 1.0e-6) {
608 
609  double deltaStep = 0.0;
610  if (std::abs(actualBendAngle) < std::abs(angle_m))
611  deltaStep = -gap_m / 2.0;
612  else
613  deltaStep = gap_m / 2.0;
614 
615  double delta1 = 0.0;
616  double bendAngle1 = actualBendAngle;
617 
618  double delta2 = deltaStep;
619  setEngeOriginDelta(delta2);
621  setFieldBoundaries(startField, endField);
622  double bendAngle2 = calculateBendAngle();
623 
624  if (std::abs(bendAngle1) > std::abs(angle_m)) {
625  while (std::abs(bendAngle2) > std::abs(angle_m)) {
626  delta2 += deltaStep;
627  setEngeOriginDelta(delta2);
629  setFieldBoundaries(startField, endField);
630  bendAngle2 = calculateBendAngle();
631  }
632  } else {
633  while (std::abs(bendAngle2) < std::abs(angle_m)) {
634  delta2 += deltaStep;
635  setEngeOriginDelta(delta2);
637  setFieldBoundaries(startField, endField);
638  bendAngle2 = calculateBendAngle();
639  }
640  }
641 
642  // Now we should have the proper field map width bracketed.
643  unsigned int iterations = 1;
644  error = std::abs(actualBendAngle - angle_m);
645  while (error > 1.0e-6 && iterations < 100) {
646 
647  double delta = (delta1 + delta2) / 2.0;
648  setEngeOriginDelta(delta);
650  setFieldBoundaries(startField, endField);
651  double newBendAngle = calculateBendAngle();
652 
653  error = std::abs(newBendAngle - angle_m);
654 
655  if (error > 1.0e-6) {
656 
657  if (bendAngle1 - angle_m < 0.0) {
658 
659  if (newBendAngle - angle_m < 0.0) {
660  bendAngle1 = newBendAngle;
661  delta1 = delta;
662  } else {
663  // bendAngle2 = newBendAngle;
664  delta2 = delta;
665  }
666 
667  } else {
668 
669  if (newBendAngle - angle_m < 0.0) {
670  // bendAngle2 = newBendAngle;
671  delta2 = delta;
672  } else {
673  bendAngle1 = newBendAngle;
674  delta1 = delta;
675  }
676  }
677  }
678  iterations++;
679  }
680  }
681 }
682 
684 
685  /*
686  * Use an iterative procedure to set the magnet field amplitude
687  * for the defined bend angle.
688  */
689 
690  const double tolerance = 1e-7; // [deg]
691  double actualBendAngle = calculateBendAngle();
692  double error = std::abs(actualBendAngle - angle_m) * Units::rad2deg;
693  if (error < tolerance)
694  return;
695 
696  double fieldStep = std::copysign(1.0, fieldAmplitude_m) * std::abs(estimateFieldAdjustmentStep(actualBendAngle));
697  double amplitude1 = fieldAmplitude_m;
698  double amplitude2 = amplitude1;
699  double bendAngle1 = actualBendAngle;
700  double bendAngle2 = bendAngle1;
701 
702  int stepSign = std::abs(bendAngle1) > std::abs(angle_m) ? -1: 1;
703  while (true) {
704  amplitude1 = amplitude2;
705  bendAngle1 = bendAngle2;
706 
707  amplitude2 += stepSign * fieldStep;
708  fieldAmplitude_m = amplitude2;
709  bendAngle2 = calculateBendAngle();
710  if (stepSign * (std::abs(bendAngle2) - std::abs(angle_m)) > 0) {
711  break;
712  }
713  }
714 
715  // Now we should have the proper field amplitude bracketed.
716  unsigned int iterations = 1;
717  while (error > tolerance && iterations < 100) {
718 
719  fieldAmplitude_m = (amplitude1 + amplitude2) / 2.0;
720  double newBendAngle = calculateBendAngle();
721 
722  error = std::abs(newBendAngle - angle_m) * Units::rad2deg;
723 
724  if (error > tolerance) {
725 
726  if (bendAngle1 - angle_m < 0.0) {
727 
728  if (newBendAngle - angle_m < 0.0) {
729  bendAngle1 = newBendAngle;
730  amplitude1 = fieldAmplitude_m;
731  } else {
732  // bendAngle2 = newBendAngle;
733  amplitude2 = fieldAmplitude_m;
734  }
735 
736  } else {
737 
738  if (newBendAngle - angle_m < 0.0) {
739  // bendAngle2 = newBendAngle;
740  amplitude2 = fieldAmplitude_m;
741  } else {
742  bendAngle1 = newBendAngle;
743  amplitude1 = fieldAmplitude_m;
744  }
745  }
746  }
747  iterations++;
748  }
749 }
750 
751 bool Bend2D::findIdealBendParameters(double chordLength) {
752 
753  bool reinitialize = false;
754 
755  if (angle_m != 0.0) {
756 
757  if (angle_m < 0.0) {
758  // Negative angle is a positive bend rotated 180 degrees.
763  }
764  designRadius_m = calcDesignRadius(chordLength, angle_m);
766  reinitialize = true;
767  } else {
768 
770  double refCharge = RefPartBunch_m->getQ();
771  if (refCharge < 0.0) {
773  }
774 
775  fieldAmplitude_m = std::copysign(1.0, refCharge) * std::hypot(fieldAmplitudeX_m, fieldAmplitudeY_m);
777  angle_m = calcBendAngle(chordLength, designRadius_m);
778  reinitialize = false;
779  }
780  return reinitialize;
781 }
782 
784 
786 
787  if (fieldmap_m != nullptr) {
788  if (fileName_m != "1DPROFILE1-DEFAULT")
789  return true;
790  else
791  return setupDefaultFieldMap();
792 
793  } else
794  return false;
795 
796 }
797 
799 
801  double distFromRotCenter = euclidean_norm(R - rotationCenter);
804 
805  double effectiveAngle = std::fmod(Physics::two_pi - std::atan2(Rpprime(0), Rpprime(2)), Physics::two_pi);
806 
807  if (std::abs(distFromRotCenter - designRadius_m) < 0.5 * aperture_m.second[0] &&
808  effectiveAngle >= 0.0 && effectiveAngle < maxAngle_m) {
809  if (effectiveAngle < 0.5 * maxAngle_m) return R(2) >= 0.0;
810  return Rprime(2) < 0.0;
811  }
812 
813  return false;
814 }
815 
817 
818  return (R(2) >= entranceParameter1_m &&
819  R(2) < 0.0 &&
820  std::abs(R(0)) < aperture_m.second[0]);
821 }
822 
824 
826 
827  return (Rprime(2) >= 0 &&
828  Rprime(2) < exitParameter3_m &&
829  std::abs(Rprime(0)) < aperture_m.second[0]);
830 }
831 
833 
834  return (polyOrderEntry_m >= 0 &&
835  R(2) >= entranceParameter1_m &&
836  R(2) < entranceParameter3_m);
837 }
838 
841 
842  return (polyOrderExit_m >= 0 &&
843  Rprime(2) >= exitParameter1_m &&
844  Rprime(2) < exitParameter3_m);
845 }
846 
847 void Bend2D::print(Inform &msg, double bendAngleX, double bendAngleY) {
848  msg << level2 << "\n"
849  << "Start of field map: "
850  << startField_m
851  << " m (in s coordinates)"
852  << "\n";
853  msg << "End of field map: "
854  << endField_m
855  << " m (in s coordinates)"
856  << "\n";
857  msg << "Entrance edge of magnet: "
858  << elementEdge_m
859  << " m (in s coordinates)"
860  << "\n";
861  msg << "\n"
862  << "Reference Trajectory Properties"
863  << "\n"
864  << "======================================================================"
865  << "\n\n";
866  msg << "Bend angle magnitude: "
867  << angle_m
868  << " rad ("
870  << " degrees)"
871  << "\n";
872  msg << "Entrance edge angle: "
873  << entranceAngle_m
874  << " rad ("
875  << entranceAngle_m * Units::rad2deg
876  << " degrees)"
877  << "\n";
878  msg << "Exit edge angle: "
879  << exitAngle_m
880  << " rad ("
881  << exitAngle_m * Units::rad2deg
882  << " degrees)"
883  << "\n";
884  msg << "Bend design radius: "
885  << designRadius_m
886  << " m"
887  << "\n";
888  msg << "Bend design energy: "
889  << designEnergy_m
890  << " eV"
891  << "\n";
892  msg << "\n"
893  << "Bend Field and Rotation Properties"
894  << "\n"
895  << "======================================================================"
896  << "\n\n";
897  msg << "Field amplitude: "
899  << " T"
900  << "\n";
901  msg << "Field index: "
902  << fieldIndex_m
903  << "\n";
904  msg << "Rotation about z axis: "
905  << rotationZAxis_m
906  << " rad ("
907  << rotationZAxis_m * Units::rad2deg
908  << " degrees)"
909  << "\n";
910  msg << "\n"
911  << "Reference Trajectory Properties Through Bend Magnet with Fringe Fields"
912  << "\n"
913  << "======================================================================"
914  << "\n\n";
915  msg << "Reference particle is bent: "
916  << bendAngleX
917  << " rad ("
918  << bendAngleX * Units::rad2deg
919  << " degrees) in x plane"
920  << "\n";
921  msg << "Reference particle is bent: "
922  << bendAngleY
923  << " rad ("
924  << bendAngleY * Units::rad2deg
925  << " degrees) in y plane"
926  << "\n";
927 
928  if (fileName_m == "1DPROFILE1-DEFAULT") {
929  msg << "\n"
930  << "Effective Field Map\n"
931  << "======================================================================\n"
932  << "\n"
933  << "1DProfile1 " << polyOrderEntry_m << " " << polyOrderExit_m << " " << gap_m * 100 << "\n"
934  << entranceParameter1_m * 100 << " " << entranceParameter2_m * 100 << " " << entranceParameter3_m * 100 << " 0\n"
935  << exitParameter1_m * 100 << " " << exitParameter2_m * 100 << " " << exitParameter3_m * 100 << " 0\n";
936  for (auto coef: engeCoeffsEntry_m) {
937  msg << coef << "\n";
938  }
939  for (auto coef: engeCoeffsExit_m) {
940  msg << coef << "\n";
941  }
942  }
943  msg << endl;
944 }
945 
946 
948  msg << level2 << getName() << " using file ";
949  fieldmap_m->getInfo(&msg);
950 
952  fieldmap_m->get1DProfile1EntranceParam(entranceParameter1_m,
955  fieldmap_m->get1DProfile1ExitParam(exitParameter1_m,
958 
960  fieldmap_m->get1DProfile1EngeCoeffs(engeCoeffsEntry_m,
962  polyOrderEntry_m = engeCoeffsEntry_m.size() - 1;
963  polyOrderExit_m = engeCoeffsExit_m.size() - 1;
964 
965  double stepSize = Physics::c * Units::ps2s;
966  double entryLength = std::abs(entranceParameter3_m - entranceParameter1_m);
967  unsigned int numStepsEntry = std::ceil(entryLength / stepSize) + 3;
968  double stepSizeEntry = entryLength / (numStepsEntry - 3);
969  std::vector<double> zvalsEntry(numStepsEntry);
970  std::vector<std::vector<double> > fieldValuesEntry(3);
971 
972  double exitLength = std::abs(exitParameter3_m - exitParameter1_m);
973  unsigned int numStepsExit = std::ceil(exitLength / stepSize) + 3;
974  double stepSizeExit = exitLength / (numStepsExit - 3);
975  std::vector<double> zvalsExit(numStepsExit);
976  std::vector<std::vector<double> > fieldValuesExit(3);
977 
978  entryFieldValues_m = new gsl_spline*[3];
979  exitFieldValues_m = new gsl_spline*[3];
980  entryFieldAccel_m = gsl_interp_accel_alloc();
981  exitFieldAccel_m = gsl_interp_accel_alloc();
982 
983  for (unsigned int i = 0; i < 3u; ++ i) {
984  fieldValuesEntry[i].resize(numStepsEntry);
985  fieldValuesExit[i].resize(numStepsExit);
986 
987  entryFieldValues_m[i] = gsl_spline_alloc(gsl_interp_cspline, numStepsEntry);
988  exitFieldValues_m[i] = gsl_spline_alloc(gsl_interp_cspline, numStepsExit);
989  }
990 
991  for (unsigned int j = 0; j < numStepsEntry; ++ j) {
992  if (j == 0) {
993  zvalsEntry[j] = -entranceParameter3_m - stepSizeEntry;
994  } else {
995  zvalsEntry[j] = zvalsEntry[j - 1] + stepSizeEntry;
996  }
997  calcEngeFunction(zvalsEntry[j] / gap_m,
1000  fieldValuesEntry[0][j],
1001  fieldValuesEntry[1][j],
1002  fieldValuesEntry[2][j]);
1003  fieldValuesEntry[2][j] *= fieldValuesEntry[0][j];
1004  }
1005 
1006  for (unsigned int j = 0; j < numStepsExit; ++ j) {
1007  if (j == 0) {
1008  zvalsExit[j] = exitParameter1_m - stepSizeExit;
1009  } else {
1010  zvalsExit[j] = zvalsExit[j - 1] + stepSizeExit;
1011  }
1012  calcEngeFunction(zvalsExit[j] / gap_m,
1015  fieldValuesExit[0][j],
1016  fieldValuesExit[1][j],
1017  fieldValuesExit[2][j]);
1018  fieldValuesExit[2][j] *= fieldValuesExit[0][j];
1019  }
1020 
1021  for (unsigned int i = 0; i < 3u; ++ i) {
1022  gsl_spline_init(entryFieldValues_m[i], &(zvalsEntry[0]), &(fieldValuesEntry[i][0]), numStepsEntry);
1023  gsl_spline_init(exitFieldValues_m[i], &(zvalsExit[0]), &(fieldValuesExit[i][0]), numStepsExit);
1024  }
1025 }
1026 
1027 void Bend2D::setBendEffectiveLength(double startField, double endField) {
1028 
1029  // Find initial angle.
1030  double actualBendAngle = calculateBendAngle();
1031 
1032  // Adjust field map to match bend angle.
1033  double error = std::abs(actualBendAngle - angle_m);
1034  if (error > 1.0e-6)
1035  findBendEffectiveLength(startField, endField);
1036 
1037 }
1038 
1040 
1041  // Estimate bend field magnitude.
1043 
1044  // Search for angle if initial guess is not good enough.
1045  findBendStrength();
1046 }
1047 
1048 void Bend2D::setEngeOriginDelta(double delta) {
1049  /*
1050  * This function is used to shift the perpendicular distance of the
1051  * entrance and exit Enge function origins with respect to the entrance
1052  * and exit points in the magnet. A positive delta shifts them towards
1053  * the center of the magnet.
1054  */
1056 
1061  entranceParameter2_m = delta;
1062 
1065  exitParameter2_m = -delta;
1066 
1068 }
1069 
1071 
1074 
1077 
1078  double bendAngle = getBendAngle();
1079  double entranceAngle = getEntranceAngle();
1080 
1081  double rotationAngleAboutZ = getRotationAboutZ();
1082  Quaternion_t rotationAboutZ(std::cos(0.5 * rotationAngleAboutZ),
1083  std::sin(0.5 * rotationAngleAboutZ) * Vector_t(0, 0, 1));
1084 
1085  Vector_t rotationAxis(0, -1, 0);
1086  Quaternion_t halfRotationAboutAxis(std::cos(0.5 * (0.5 * bendAngle - entranceAngle)),
1087  std::sin(0.5 * (0.5 * bendAngle - entranceAngle)) * rotationAxis);
1088  Quaternion_t exitFaceRotation(std::cos(0.5 * (bendAngle - entranceAngle - exitAngle_m)),
1089  std::sin(0.5 * (bendAngle - entranceAngle - exitAngle_m)) * rotationAxis);
1090  Vector_t chord = getChordLength() * halfRotationAboutAxis.rotate(Vector_t(0, 0, 1));
1091  beginToEnd_lcs_m = CoordinateSystemTrafo(chord, exitFaceRotation.conjugate());
1094  Quaternion(0, 0, 1, 0));
1095  const CoordinateSystemTrafo fromEndToExitRegion(Vector_t(0, 0, exitParameter2_m),
1096  Quaternion(1, 0, 0, 0));
1097  toExitRegion_m = CoordinateSystemTrafo(fromEndToExitRegion *
1099 
1101 
1102  Vector_t maxAngleEntranceAperture;
1103  if (rotationCenter(2) < 0.0) {
1104  double tau, tmp;
1105  Vector_t P(0.5 * aperture_m.second[0], 0.0, 0.0), &R = rotationCenter;
1106  gsl_poly_solve_quadratic(dot(P,P),
1107  -2 * dot(P,R),
1108  dot(R,R) - std::pow(designRadius_m + 0.5 * aperture_m.second[0], 2),
1109  &tau,
1110  &tmp);
1111  tau = (std::abs(1.0 - tmp) < std::abs(1.0 - tau)? tmp: tau);
1112  maxAngleEntranceAperture = tau * P;
1113  } else {
1114  double tau, tmp;
1115  Vector_t P(-0.5 * aperture_m.second[0], 0.0, 0.0), &R = rotationCenter;
1116  gsl_poly_solve_quadratic(dot(P,P),
1117  -2 * dot(P,R),
1118  dot(R,R) - std::pow(designRadius_m - 0.5 * aperture_m.second[0], 2),
1119  &tau,
1120  &tmp);
1121  tau = (std::abs(1.0 - tmp) < std::abs(1.0 - tau)? tmp: tau);
1122  maxAngleEntranceAperture = tau * P;
1123  }
1124  Vector_t maxAngleExitAperture;
1125  if (getBeginToEnd_local().transformTo(rotationCenter)(2) > 0.0) {
1126  double tau, tmp;
1127  Vector_t P(0.5 * aperture_m.second[0], 0.0, 0.0), R = getBeginToEnd_local().transformTo(rotationCenter);
1128  gsl_poly_solve_quadratic(dot(P,P),
1129  -2 * dot(P,R),
1130  dot(R,R) - std::pow(designRadius_m + 0.5 * aperture_m.second[0], 2),
1131  &tau,
1132  &tmp);
1133  tau = (std::abs(1.0 - tmp) < std::abs(1.0 - tau)? tmp: tau);
1134  maxAngleExitAperture = getBeginToEnd_local().transformFrom(tau * P);
1135  } else {
1136  double tau, tmp;
1137  Vector_t P(-0.5 * aperture_m.second[0], 0.0, 0.0), R = getBeginToEnd_local().transformTo(rotationCenter);
1138  gsl_poly_solve_quadratic(dot(P,P),
1139  -2 * dot(P,R),
1140  dot(R,R) - std::pow(designRadius_m - 0.5 * aperture_m.second[0], 2),
1141  &tau,
1142  &tmp);
1143  tau = (std::abs(1.0 - tmp) < std::abs(1.0 - tau)? tmp: tau);
1144  maxAngleExitAperture = getBeginToEnd_local().transformFrom(tau * P);
1145  }
1146 
1147  maxAngleEntranceAperture -= rotationCenter;
1148 
1149  Quaternion rotation = getQuaternion(maxAngleEntranceAperture, Vector_t(0, 0, 1));
1150  computeAngleTrafo_m = CoordinateSystemTrafo(rotationCenter,
1151  rotation);
1152  Vector_t tmp = computeAngleTrafo_m.transformTo(maxAngleExitAperture);
1154 
1155  maxAngleExitAperture -= rotationCenter;
1156 }
1157 
1159 
1160  if (gap_m <= 0.0)
1161  gap_m = fieldmap_m->getFieldGap();
1162  else if (gap_m != fieldmap_m->getFieldGap())
1163  adjustFringeFields(gap_m / fieldmap_m->getFieldGap());
1164 
1165 }
1166 
1167 bool Bend2D::setupBendGeometry(double &startField, double &endField) {
1168 
1169  chordLength_m = 0.0;
1171  return false;
1172 
1173  if (isFieldZero()) {
1174  // treat as drift
1175  startField_m = startField;
1176  endField_m = startField + chordLength_m;
1177  return true;
1178  }
1179 
1181  if (getType() == ElementType::RBEND) {
1183  }
1184 
1185  /*
1186  * Set field map geometry.
1187  */
1188  if (aperture_m.second[0] <= 0.0)
1189  aperture_m.second[0] = designRadius_m / 2.0;
1191 
1192  /*
1193  * If we are using the default field map, then the origins for the
1194  * Enge functions will be shifted so that we get the desired bend
1195  * angle for the given bend strength. (We match the effective length
1196  * of our field map to the ideal bend length.)
1197  *
1198  * If we are not using the default field map, we assume it cannot
1199  * change so we either leave everything alone (if the user defines
1200  * the bend strength) or we adjust the bend field to get the right
1201  * angle.
1202  */
1203  elementEdge_m = startField;
1204  setFieldBoundaries(startField, endField);
1205 
1206  if (fileName_m != "1DPROFILE1-DEFAULT") {
1207  if (reinitialize_m)
1208  setBendStrength();
1209  } else {
1210  setBendEffectiveLength(startField, endField);
1211  }
1212 
1213  startField = startField_m;
1214  endField = endField_m;
1215  return true;
1216 
1217 }
1218 
1220 
1221  if (getElementLength() <= 0.0) {
1222  ERRORMSG("If using \"1DPROFILE1-DEFAULT\" field map you must set the "
1223  "chord length of the bend using the L attribute in the OPAL "
1224  "input file."
1225  << endl);
1226  return false;
1227  } else {
1228  // msg << level2;
1229  // fieldmap_m->getInfo(&msg);
1230  return true;
1231  }
1232 
1233 }
1234 
1235 void Bend2D::setFieldBoundaries(double startField, double /*endField*/) {
1236 
1238  endField_m = (startField + angle_m * designRadius_m +
1240 }
1241 
1243 
1244  RefPartBunch_m = bunch;
1245  pusher_m.initialise(bunch->getReference());
1246 
1247 }
1248 
1250  if (designEnergy_m <= 0.0) {
1251  WARNMSG("Warning: bend design energy is zero. Treating as drift."
1252  << endl);
1253  designRadius_m = 0.0;
1254  return true;
1255  } else if (angle_m == 0.0 &&
1256  std::pow(fieldAmplitudeX_m, 2.0) + std::pow(fieldAmplitudeY_m, 2.0) > 0.0) {
1257 
1258  double radius = calcDesignRadius(fieldAmplitude_m);
1259  double sinArgument = chordLength_m / (2.0 * radius);
1260 
1261  if (std::abs(sinArgument) > 1.0) {
1262  WARNMSG("Warning: bend strength and defined reference trajectory "
1263  << "chord length are not consistent. Treating bend as drift."
1264  << endl);
1265  designRadius_m = 0.0;
1266  return true;
1267  } else
1268  return false;
1269 
1270  } else if (angle_m == 0.0) {
1271 
1272  WARNMSG("Warning bend angle/strength is zero. Treating as drift."
1273  << endl);
1274  designRadius_m = 0.0;
1275  return true;
1276 
1277  } else
1278  return false;
1279 }
1280 
1281 std::vector<Vector_t> Bend2D::getOutline() const {
1282  std::vector<Vector_t> outline;
1284  unsigned int numSteps = 2;
1285 
1286  outline.push_back(Vector_t(-0.5 * widthEntranceFringe_m, 0.0, 0.0));
1288  outline.push_back(Vector_t(entranceParameter1_m * tanEntranceAngle_m, 0.0, entranceParameter1_m));
1289  outline.push_back(Vector_t(0.5 * widthEntranceFringe_m + entranceParameter1_m * tanEntranceAngle_m, 0.0, entranceParameter1_m));
1290  outline.push_back(Vector_t(0.5 * widthEntranceFringe_m, 0.0, 0.0));
1291 
1292  {
1293  double tau1, tau2;
1294  Vector_t P(0.5 * aperture_m.second[0], 0.0, 0.0), R = rotationCenter;
1295  gsl_poly_solve_quadratic(dot(P,P),
1296  -2 * dot(P,R),
1297  dot(R,R) - std::pow(designRadius_m + 0.5 * aperture_m.second[0], 2),
1298  &tau1,
1299  &tau2);
1300  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1301  Vector_t upperCornerAtEntry = tau1 * P;
1302 
1303  R = getBeginToEnd_local().transformTo(rotationCenter);
1304  gsl_poly_solve_quadratic(dot(P,P),
1305  -2 * dot(P,R),
1306  dot(R,R) - std::pow(designRadius_m + 0.5 * aperture_m.second[0], 2),
1307  &tau1,
1308  &tau2);
1309  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1310  Vector_t upperCornerAtExit = getBeginToEnd_local().transformFrom(tau1 * P);
1311 
1312  Quaternion rotation = getQuaternion(upperCornerAtEntry - rotationCenter, Vector_t(0,0,1));
1313  Vector_t tmp = CoordinateSystemTrafo(rotationCenter, rotation).transformTo(upperCornerAtExit);
1314  double totalAngle = -std::fmod(Physics::two_pi - std::atan2(tmp(0), tmp(2)), Physics::two_pi);
1315  numSteps = std::max(2.0, std::ceil(-totalAngle / (5.0 * Units::deg2rad)));
1316  double dAngle = 0.5 * totalAngle / (1.0 * numSteps - 1.0);
1317 
1318  outline.push_back(upperCornerAtEntry);
1319  double angle = 0.0;
1320  for (unsigned int i = 0; i < numSteps; ++ i, angle += dAngle) {
1321  Quaternion rot(std::cos(angle), 0.0, std::sin(angle), 0.0);
1322  outline.push_back(rot.rotate(upperCornerAtEntry - rotationCenter) + rotationCenter);
1323  }
1324  outline.push_back(upperCornerAtExit);
1325  }
1326 
1327  outline.push_back(getBeginToEnd_local().transformFrom(Vector_t(0.5 * widthExitFringe_m, 0.0, 0.0)));
1328  outline.push_back(getBeginToEnd_local().transformFrom(Vector_t(0.5 * widthExitFringe_m - exitParameter3_m * tanExitAngle_m, 0.0, exitParameter3_m)));
1329  outline.push_back(getBeginToEnd_local().transformFrom(Vector_t(-exitParameter3_m * tanExitAngle_m, 0.0, exitParameter3_m)));
1330  outline.push_back(getBeginToEnd_local().transformFrom(Vector_t(-0.5 * widthExitFringe_m - exitParameter3_m * tanExitAngle_m, 0.0, exitParameter3_m)));
1331  outline.push_back(getBeginToEnd_local().transformFrom(Vector_t(-0.5 * widthExitFringe_m, 0.0, 0.0)));
1332 
1333  {
1334  double tau1, tau2;
1335  Vector_t P(-0.5 * aperture_m.second[0], 0.0, 0.0), R = rotationCenter;
1336  gsl_poly_solve_quadratic(dot(P,P),
1337  -2 * dot(P,R),
1338  dot(R,R) - std::pow(designRadius_m - 0.5 * aperture_m.second[0], 2),
1339  &tau1,
1340  &tau2);
1341  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1342  Vector_t lowerCornerAtEntry = tau1 * P;
1343 
1344  R = getBeginToEnd_local().transformTo(rotationCenter);
1345  gsl_poly_solve_quadratic(dot(P,P),
1346  -2 * dot(P,R),
1347  dot(R,R) - std::pow(designRadius_m - 0.5 * aperture_m.second[0], 2),
1348  &tau1,
1349  &tau2);
1350  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1351  Vector_t lowerCornerAtExit = getBeginToEnd_local().transformFrom(tau1 * P);
1352 
1353  Quaternion rotation = getQuaternion(lowerCornerAtEntry - rotationCenter, Vector_t(0,0,1));
1354  Vector_t tmp = CoordinateSystemTrafo(rotationCenter, rotation).transformTo(lowerCornerAtExit);
1355  double totalAngle = -std::fmod(Physics::two_pi - std::atan2(tmp(0), tmp(2)), Physics::two_pi);
1356  double dAngle = 0.5 * totalAngle / (1.0 * numSteps - 1.0);
1357 
1358  outline.push_back(lowerCornerAtExit);
1359  double angle = 0.5 * totalAngle;
1360  for (unsigned int i = 0; i < numSteps; ++ i, angle -= dAngle) {
1361  Quaternion rot(std::cos(angle), 0.0, std::sin(angle), 0.0);
1362  outline.push_back(rot.rotate(lowerCornerAtEntry - rotationCenter) + rotationCenter);
1363  }
1364  outline.push_back(lowerCornerAtEntry);
1365  }
1366 
1367  std::ofstream outlineOutput;
1369  std::string fname = Util::combineFilePath({
1371  OpalData::getInstance()->getInputBasename() + "_" + getName() + "_outline.dat"
1372  });
1373  outlineOutput.open(fname);
1374  outlineOutput.precision(8);
1375 
1376  for (auto a: outline) {
1377  outlineOutput << std::setw(18) << a(2)
1378  << std::setw(18) << a(0)
1379  << "\n";
1380  }
1381  outlineOutput << std::setw(18) << outline.front()(2)
1382  << std::setw(18) << outline.front()(0)
1383  << std::endl;
1384  }
1385  return outline;
1386 }
1387 
1389  MeshData mesh;
1390  const Vector_t hgap(0, 0.5 * getFullGap(), 0);
1391  std::vector<Vector_t> outline = getOutline();
1392 
1393  unsigned int size = outline.size();
1394  unsigned int last = size - 1;
1395  unsigned int numSteps = (size - 14) / 2;
1396  unsigned int midIdx = numSteps + 7;
1397 
1398  for (unsigned int i = 0; i < 6; ++ i) {
1399  mesh.vertices_m.push_back(outline[i] + 2 * hgap);
1400  }
1401  for (unsigned int i = 6; i < 6 + numSteps; ++ i) {
1402  mesh.vertices_m.push_back(outline[i] + hgap);
1403  }
1404  for (unsigned int i = 6 + numSteps; i < 13 + numSteps; ++ i) {
1405  mesh.vertices_m.push_back(outline[i] + 2 * hgap);
1406  }
1407  for (unsigned int i = 13 + numSteps; i < 13 + 2 * numSteps; ++ i) {
1408  mesh.vertices_m.push_back(outline[i] + hgap);
1409  }
1410  mesh.vertices_m.push_back(outline[last] + 2 * hgap);
1411 
1412  for (unsigned int i = 0; i < 6; ++ i) {
1413  mesh.vertices_m.push_back(outline[i] - 2 * hgap);
1414  }
1415  for (unsigned int i = 6; i < 6 + numSteps; ++ i) {
1416  mesh.vertices_m.push_back(outline[i] - hgap);
1417  }
1418  for (unsigned int i = 6 + numSteps; i < 13 + numSteps; ++ i) {
1419  mesh.vertices_m.push_back(outline[i] - 2 * hgap);
1420  }
1421  for (unsigned int i = 13 + numSteps; i < 13 + 2 * numSteps; ++ i) {
1422  mesh.vertices_m.push_back(outline[i] - hgap);
1423  }
1424  mesh.vertices_m.push_back(outline[last] - 2 * hgap);
1425 
1426  mesh.vertices_m.push_back(outline[0]);
1427  mesh.vertices_m.push_back(outline[4]);
1428  mesh.vertices_m.push_back(outline[midIdx]);
1429  mesh.vertices_m.push_back(outline[midIdx + 4]);
1430 
1431  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2, 1, 0));
1432  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2, 4, 3));
1433  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2, 5, 4));
1434  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2, 0, last));
1435  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2, last, 5));
1436  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(last, last - 1, 5));
1437  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(5, last - 1, 6));
1438 
1439  // exit region top
1440  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(midIdx + 2, midIdx + 1, midIdx));
1441  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(midIdx + 2, midIdx + 4, midIdx + 3));
1442  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(midIdx + 2, midIdx + 5, midIdx + 4));
1443  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(midIdx + 2, midIdx, midIdx - 1));
1444  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(midIdx + 2, midIdx - 1, midIdx + 5));
1445  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(midIdx - 1, midIdx - 2, midIdx + 5));
1446  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(midIdx + 5, midIdx - 2, midIdx + 6));
1447 
1448  // entry region bottom
1449  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 2, size + 0, size + 1));
1450  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 2, size + 3, size + 4));
1451  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 2, size + 4, size + 5));
1452  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 2, size + last, size + 0));
1453  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 2, size + 5, size + last));
1454  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + last, size + 5, size + last - 1));
1455  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 5, size + 6, size + last - 1));
1456 
1457  // exit region bottom
1458  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + midIdx + 2, size + midIdx + 0, size + midIdx + 1));
1459  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + midIdx + 2, size + midIdx + 3, size + midIdx + 4));
1460  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + midIdx + 2, size + midIdx + 4, size + midIdx + 5));
1461  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + midIdx + 2, size + midIdx - 1, size + midIdx + 0));
1462  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + midIdx + 2, size + midIdx + 5, size + midIdx - 1));
1463  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + midIdx - 1, size + midIdx + 5, size + midIdx - 2));
1464  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + midIdx + 5, size + midIdx + 6, size + midIdx - 2));
1465 
1466  // central region
1467  for (unsigned int i = 6; i < 5 + numSteps; ++ i) {
1468  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(i, last + 5 - i, i + 1));
1469  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(last + 5 - i, last + 4 - i, i + 1));
1470 
1471  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + i, size + i + 1, size + last + 5 - i));
1472  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + last + 5 - i, size + i + 1, size + last + 4 - i));
1473  }
1474 
1475  // side
1476  for (unsigned int i = 0; i < size - 2; ++ i) {
1477  if (i == 4u || i == 5u ||
1478  i == 5 + numSteps || i == 6 + numSteps ||
1479  i == 11 + numSteps || i == 12 + numSteps) continue;
1480 
1481  unsigned int next = (i + 1) % size;
1482  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(i, next, next + size));
1483  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(i, next + size, i + size));
1484  }
1485 
1486  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(last, 0, last-1));
1487  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2*size, last - 1, 0));
1488  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2*size, size + last - 1, last - 1));
1489  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2*size, size, size + last - 1));
1490  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + last, size + last - 1, size));
1491 
1492  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(4, 5, 6));
1493  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(4, 6, 2*size + 1));
1494  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2*size + 1, 6, size + 6));
1495  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 4, 2*size + 1, size + 6));
1496  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 4, size + 6, size + 5));
1497 
1498  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(6 + numSteps, midIdx, 5 + numSteps));
1499  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(5 + numSteps, midIdx, 2*size + 2));
1500  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(5 + numSteps, 2*size + 2, size + 5 + numSteps));
1501  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 5 + numSteps, 2*size + 2, size + midIdx));
1502  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 6 + numSteps, size + 5 + numSteps, size + midIdx));
1503 
1504  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(6 + midIdx, 4 + midIdx, 5 + midIdx));
1505  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(6 + midIdx, 2*size + 3, 4 + midIdx));
1506  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(2*size + 3, 6 + midIdx, size + 6 + midIdx));
1507  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 4 + midIdx, 2*size + 3, size + 6 + midIdx));
1508  mesh.triangles_m.push_back(Vektor<unsigned int, 3>(size + 4 + midIdx, size + 6 + midIdx, size + 5 + midIdx));
1509 
1511 
1514 
1515  Vector_t T = cross(P1 - rotationCenter, P2 - rotationCenter);
1516  if (T[1] > 0) { // fringe fields are overlapping
1518  if (this->getType() == ElementType::RBEND ||
1520  mesh.decorations_m.push_back(std::make_pair(0.5 * (P1 + P2) - 0.25 * dir1,
1521  0.5 * (P1 + P2) + 0.25 * dir1));
1522  } else {
1523  Vector_t dir2 = toExitRegion_m.rotateFrom(Vector_t(-1, 0, 0));
1524  matrix_t inv(3,3);
1525  double det = -dir1[0] * dir2[2] + dir1[2] * dir2[0];
1526  inv(0, 0) = -dir2[2] / det;
1527  inv(0, 2) = dir2[0] / det;
1528  inv(1,1) = 1.0;
1529  inv(2, 0) = -dir1[2] / det;
1530  inv(2, 2) = dir1[0] / det;
1531 
1532  boost::numeric::ublas::vector<double> Tau(3);
1533  Vector_t Pdiff = P2 - P1;
1534  Tau(0) = Pdiff[0];
1535  Tau(1) = Pdiff[1];
1536  Tau(2) = Pdiff[2];
1537  Tau = boost::numeric::ublas::prod(inv, Tau);
1538 
1539  Vector_t crossPoint = P1 + Tau[0] * dir1;
1540  double angle = std::asin(cross(dir1, dir2)[1]);
1541  Quaternion halfRot(std::cos(0.25 * angle), std::sin(0.25 * angle) * Vector_t(0, 1, 0));
1542  Vector_t P = halfRot.rotate(dir1);
1543  Vector_t R = crossPoint - rotationCenter;
1544 
1545  double radius = designRadius_m - 0.5 * aperture_m.second[0];
1546  double tau1, tau2;
1547  gsl_poly_solve_quadratic(dot(P,P),
1548  2 * dot(P,R),
1549  dot(R,R) - std::pow(radius, 2),
1550  &tau1,
1551  &tau2);
1552  if (euclidean_norm(crossPoint + tau1 * P - P1) > euclidean_norm(crossPoint + tau2 * P - P1)) {
1553  std::swap(tau1, tau2);
1554  }
1555  Vector_t lowerCornerFringeLimit = crossPoint + tau1 * P;
1556 
1557  radius = designRadius_m + 0.5 * aperture_m.second[0];
1558  gsl_poly_solve_quadratic(dot(P,P),
1559  2 * dot(P,R),
1560  dot(R,R) - std::pow(radius, 2),
1561  &tau1,
1562  &tau2);
1563  if (euclidean_norm(crossPoint + tau1 * P - P1) > euclidean_norm(crossPoint + tau2 * P - P1)) {
1564  std::swap(tau1, tau2);
1565  }
1566  Vector_t upperCornerFringeLimit = crossPoint + tau1 * P;
1567 
1568  mesh.decorations_m.push_back(std::make_pair(lowerCornerFringeLimit,
1569  upperCornerFringeLimit));
1570  }
1571  } else {
1572 
1573  double tau1, tau2;
1574  Vector_t P(-0.5 * aperture_m.second[0], 0.0, 0.0);
1575  Vector_t R = Vector_t(0, 0, entranceParameter3_m) - rotationCenter;
1576  gsl_poly_solve_quadratic(dot(P,P),
1577  2 * dot(P,R),
1578  dot(R,R) - std::pow(designRadius_m - 0.5 * aperture_m.second[0],2),
1579  &tau1,
1580  &tau2);
1581  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1582  Vector_t lowerCornerFringeLimitEntrance = Vector_t(0, 0, entranceParameter3_m) + tau1 * P;
1583 
1584  gsl_poly_solve_quadratic(dot(P,P),
1585  -2 * dot(P,R),
1586  dot(R,R) - std::pow(designRadius_m + 0.5 * aperture_m.second[0],2),
1587  &tau1,
1588  &tau2);
1589  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1590  Vector_t upperCornerFringeLimitEntrance = Vector_t(0, 0, entranceParameter3_m) - tau1 * P;
1591 
1592  P = Vector_t(0.5 * aperture_m.second[0], 0.0, 0.0);
1593  R = Vector_t(0, 0, exitParameter1_m) - getBeginToEnd_local().transformTo(rotationCenter);
1594  gsl_poly_solve_quadratic(dot(P,P),
1595  2 * dot(P,R),
1596  dot(R,R) - std::pow(designRadius_m + 0.5 * aperture_m.second[0],2),
1597  &tau1,
1598  &tau2);
1599  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1600  Vector_t upperCornerFringeLimitExit = getBeginToEnd_local().transformFrom(Vector_t(0, 0, exitParameter1_m) + tau1 * P);
1601 
1602  gsl_poly_solve_quadratic(dot(P,P),
1603  -2 * dot(P,R),
1604  dot(R,R) - std::pow(designRadius_m - 0.5 * aperture_m.second[0],2),
1605  &tau1,
1606  &tau2);
1607  tau1 = (std::abs(1.0 - tau2) < std::abs(1.0 - tau1)? tau2: tau1);
1608  Vector_t lowerCornerFringeLimitExit = getBeginToEnd_local().transformFrom(Vector_t(0, 0, exitParameter1_m) - tau1 * P);
1609 
1610  mesh.decorations_m.push_back(std::make_pair(lowerCornerFringeLimitEntrance, upperCornerFringeLimitEntrance));
1611  mesh.decorations_m.push_back(std::make_pair(lowerCornerFringeLimitExit, upperCornerFringeLimitExit));
1612 
1613  }
1614 
1616  Vector_t(0.0)));
1617  mesh.decorations_m.push_back(std::make_pair(getBeginToEnd_local().transformFrom(Vector_t(0.0)),
1619 
1620  return mesh;
1621 }
1622 
1623 bool Bend2D::isInside(const Vector_t &R) const {
1624  if (std::abs(R(1)) > gap_m) return false;
1625 
1626  if (inMagnetEntranceRegion(R)) {
1627  return true;
1628  }
1629 
1630  if (inMagnetExitRegion(R)) {
1631  return true;
1632  }
1633 
1634  return (std::abs(R(1)) < 0.5 * gap_m && inMagnetCentralRegion(R));
1635 }
1636 
1638 {
1641 }
1642 
1643 //set the number of slices for map tracking
1644 void Bend2D::setNSlices(const std::size_t& nSlices) {
1645  nSlices_m = nSlices;
1646 }
1647 
1648 //get the number of slices for map tracking
1649 std::size_t Bend2D::getNSlices() const {
1650  return nSlices_m;
1651 }
1652 
1654 // Used to create fringe fields in ThickTracker, (before edge[m], after edge[m])
1655 std::array<double,2> Bend2D::getEntranceFringeFieldLength() const {
1656  double entrParam1, entrParam2, entrParam3;
1657 
1658  fieldmap_m->get1DProfile1EntranceParam(entrParam1,
1659  entrParam2,
1660  entrParam3);
1661 
1662  std::array<double,2> entFFL;
1663  entFFL[0]=entrParam2-entrParam1; //before edge
1664  entFFL[1]=entrParam3-entrParam2; //after edge
1665 
1666 
1667  entFFL[0] = ( entranceParameter2_m - entranceParameter1_m ); //before edge
1668  entFFL[1] = ( entranceParameter3_m - entranceParameter2_m ); //after edge
1669 
1670  return entFFL;
1671 }
1672 
1674 // Used to create fringe fields in ThickTracker, (after edge[m], before edge[m])
1675 std::array<double,2> Bend2D::getExitFringeFieldLength() const {
1676  std::array<double,2> extFFL;
1677 
1678  double exitParam1, exitParam2, exitParam3;
1679 
1680  fieldmap_m->get1DProfile1ExitParam(exitParam1,
1681  exitParam2,
1682  exitParam3);
1683 
1684  extFFL[0]=exitParam3-exitParam2; //after edge
1685  extFFL[1]=exitParam2-exitParam1; //before edge
1686 
1687  extFFL[0] = ( exitParameter3_m-exitParameter2_m ); //after edge
1688  extFFL[1] = ( exitParameter2_m-exitParameter1_m ); //before edge
1689 
1690  return extFFL;
1691 }
1692 
1696 
1697  std::vector<Vector_t> outline = getOutline();
1698 
1699  BoundingBox bb;
1700  Vector_t dY(0, 0.5 * getFullGap(), 0);
1701  for (int i : {-1, 1}) {
1702  for (const Vector_t & vec: outline) {
1703  Vector_t vecInLabCoords = csTrafoGlobal2Local_m.transformFrom(vec + i * dY);
1704  bb.enlargeToContainPosition(vecInLabCoords);
1705  }
1706  }
1707 
1708  return bb;
1709 }
BorisPusher pusher_m
Definition: Bend2D.h:196
bool findIdealBendParameters(double chordLength)
Definition: Bend2D.cpp:751
double entranceParameter3_m
Definition: Bend2D.h:231
void findBendStrength()
Definition: Bend2D.cpp:683
static OpalData * getInstance()
Definition: OpalData.cpp:196
boost::numeric::ublas::matrix< double > matrix_t
Definition: BoostMatrix.h:23
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
double tanEntranceAngle_m
Definition: Bend2D.h:263
std::size_t getNSlices() const
Definition: Bend2D.cpp:1649
void setFieldBoundaries(double startField, double endField)
Definition: Bend2D.cpp:1235
bool isPositionInExitField(const Vector_t &R) const
Definition: Bend2D.cpp:839
Quaternion conjugate() const
Definition: Quaternion.h:103
std::vector< Vector_t > getOutline() const
Definition: Bend2D.cpp:1281
Vector_t rotate(const Vector_t &) const
Definition: Quaternion.cpp:122
double designRadius_m
through the bend.
Definition: Bend2D.h:199
int polyOrderEntry_m
function origin that Enge function ends.
Definition: Bend2D.h:253
bool setupBendGeometry(double &startField, double &endField)
Definition: Bend2D.cpp:1167
double startField_m
Dipole field index.
Definition: Bend2D.h:204
double chordLength_m
Definition: BendBase.h:52
T det(const AntiSymTenzor< T, 3 > &)
item[EANGLE] Entrance edge angle(radians).\item[ROTATION] Rotation of the magnet about its central axis(radians
bool reinitialize_m
Definition: Bend2D.h:216
PETE_TBTree< FnCopysign, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > copysign(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
std::array< double, 2 > getEntranceFringeFieldLength() const
Get entrance fringe field length.
Definition: Bend2D.cpp:1655
double deltaEndEntry_m
function origin where Enge function starts.
Definition: Bend2D.h:251
constexpr double two_pi
The value of .
Definition: Physics.h:33
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
double endField_m
Start of magnet field map in s coordinates (m).
Definition: Bend2D.h:205
Vector_t transformToEntranceRegion(const Vector_t &R) const
Definition: Bend2D.h:370
virtual bool isInside(const Vector_t &r) const override
Definition: Bend2D.cpp:1623
gsl_interp_accel * entryFieldAccel_m
Definition: Bend2D.h:242
CoordinateSystemTrafo toEntranceRegion_m
Definition: Bend2D.h:268
gsl_spline ** exitFieldValues_m
Definition: Bend2D.h:241
static int myNode()
Definition: IpplInfo.cpp:691
Vector_t calcCentralField(const Vector_t &R, double deltaX)
Definition: Bend2D.cpp:356
double calcGamma() const
Calculate gamma from design energy.
Definition: BendBase.cpp:89
Vektor< double, 3 > Vector_t
Definition: Vektor.h:6
void setBendStrength()
Definition: Bend2D.cpp:1039
double entranceParameter2_m
Definition: Bend2D.h:230
std::array< double, 2 > getExitFringeFieldLength() const
Get exit fringe field length.
Definition: Bend2D.cpp:1675
Definition: Bend2D.h:51
virtual ElementType getType() const override=0
Get element type std::string.
#define ERRORMSG(msg)
Definition: IpplInfo.h:350
double getChordLength() const
Definition: BendBase.h:82
double calcBetaGamma() const
Calculate beta*gamma from design energy.
Definition: BendBase.cpp:95
#define WARNMSG(msg)
Definition: IpplInfo.h:349
void enlargeToContainPosition(const Vector_t &position)
Definition: BoundingBox.cpp:41
Vector_t calcEntranceFringeField(const Vector_t &R, double deltaX)
Definition: Bend2D.cpp:374
double widthEntranceFringe_m
End of magnet field map in s coordinates (m).
Definition: Bend2D.h:207
double calcBendAngle(double chordLength, double radius) const
Calculate bend angle from chord length and design radius.
Definition: BendBase.cpp:79
bool setupDefaultFieldMap()
Definition: Bend2D.cpp:1219
PartBunchBase< double, 3 > * RefPartBunch_m
Definition: Component.h:191
void push(Vector_t &R, const Vector_t &P, const double &dt) const
Definition: BorisPusher.h:131
std::size_t nSlices_m
Definition: Bend2D.h:274
bool calculateMapField(const Vector_t &R, Vector_t &B)
Definition: Bend2D.cpp:447
void findBendEffectiveLength(double startField, double endField)
Definition: Bend2D.cpp:593
Tps< T > exp(const Tps< T > &x)
Exponential.
Definition: TpsMath.h:165
double widthExitFringe_m
Definition: Bend2D.h:208
bool inMagnetEntranceRegion(const Vector_t &R) const
Definition: Bend2D.cpp:816
bool writeBendTrajectories
Definition: Options.cpp:95
void initialise(const PartData *ref)
Definition: BorisPusher.h:60
virtual const std::string & getName() const
Get element name.
virtual bool findChordLength(double &chordLength)=0
double getQ() const
Access to reference data.
constexpr double pi
The value of .
Definition: Physics.h:30
double calculateBendAngle()
Definition: Bend2D.cpp:252
std::string toUpper(const std::string &str)
Definition: Util.cpp:147
virtual bool apply(const size_t &i, const double &t, Vector_t &E, Vector_t &B) override
Apply field to particles with coordinates in magnet frame.
Definition: Bend2D.cpp:149
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Vector_t transformFrom(const Vector_t &r) const
std::vector< Vector_t > vertices_m
Definition: MeshGenerator.h:24
double getdT() const
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
double tanExitAngle_m
Definition: Bend2D.h:264
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
bool initializeFieldMap()
Definition: Bend2D.cpp:783
double getBendAngle() const
Definition: BendBase.h:92
double fieldIndex_m
and the exit face of the magnet (radians).
Definition: Bend2D.h:203
void setFieldCalcParam()
Definition: Bend2D.cpp:1070
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition: Bend2D.cpp:192
double exitParameter1_m
Definition: Bend2D.h:232
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
double elementEdge_m
Definition: ElementBase.h:371
double calcDesignRadius(double fieldAmplitude) const
Calculate design radius from design energy and field amplitude.
Definition: BendBase.cpp:61
Vector_t rotateFrom(const Vector_t &r) const
double getEntranceAngle() const
Definition: BendBase.h:103
virtual bool applyToReferenceParticle(const Vector_t &R, const Vector_t &P, const double &t, Vector_t &E, Vector_t &B) override
Definition: Bend2D.cpp:180
bool isPositionInEntranceField(const Vector_t &R) const
Definition: Bend2D.cpp:832
constexpr double ps2s
Definition: Units.h:53
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition: Vector.h:243
CoordinateSystemTrafo getBeginToEnd_local() const
Definition: Bend2D.h:354
virtual void readMap()=0
double exitAngle_m
Bend design radius (m).
Definition: Bend2D.h:201
bool getFlagDeleteOnTransverseExit() const
Definition: ElementBase.h:614
void setupFringeWidths()
Definition: Bend2D.cpp:1637
bool inMagnetCentralRegion(const Vector_t &R) const
Definition: Bend2D.cpp:798
double fieldAmplitudeX_m
Definition: BendBase.h:66
std::vector< std::pair< Vector_t, Vector_t > > decorations_m
Definition: MeshGenerator.h:26
bool isFieldZero()
Definition: Bend2D.cpp:1249
virtual CoordinateSystemTrafo getEdgeToBegin() const
Definition: ElementBase.h:503
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition: OpalData.cpp:666
CoordinateSystemTrafo csTrafoGlobal2Local_m
Definition: ElementBase.h:366
constexpr double deg2rad
Definition: Units.h:143
bool online_m
Definition: Component.h:192
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
Definition: Vector3D.cpp:111
double rotationZAxis_m
Definition: ElementBase.h:373
T::PETE_Expr_t::PETE_Return_t prod(const PETE_Expr< T > &expr)
Definition: PETE.h:1121
std::string messageHeader_m
Definition: Bend2D.h:194
double deltaBeginEntry_m
Definition: Bend2D.h:249
Definition: Vec.h:21
double deltaBeginExit_m
Enge function order for entry region.
Definition: Bend2D.h:255
Definition: Inform.h:42
double sinEntranceAngle_m
Definition: Bend2D.h:262
double angle_m
Bend angle.
Definition: BendBase.h:53
bool inMagnetExitRegion(const Vector_t &R) const
Definition: Bend2D.cpp:823
void adjustFringeFields(double ratio)
Definition: Bend2D.cpp:234
CoordinateSystemTrafo beginToEnd_lcs_m
Definition: Bend2D.h:267
MeshData getSurfaceMesh() const
Definition: Bend2D.cpp:1388
std::vector< Vektor< unsigned int, 3 > > triangles_m
Definition: MeshGenerator.h:25
gsl_spline ** entryFieldValues_m
Definition: Bend2D.h:240
Vector_t calcExitFringeField(const Vector_t &R, double deltaX)
Definition: Bend2D.cpp:411
double exitParameter3_m
Definition: Bend2D.h:234
void calcEngeFunction(double zNormalized, const std::vector< double > &engeCoeff, int polyOrder, double &engeFunc, double &engeFuncDeriv, double &engeFuncSecDerivNorm)
Definition: Bend2D.cpp:291
virtual double getElementLength() const
Get design length.
Definition: ElementBase.h:415
void setGapFromFieldMap()
Definition: Bend2D.cpp:1158
#define X(arg)
Definition: fftpack.cpp:112
std::string fileName_m
Definition: BendBase.h:73
double getFullGap() const
Definition: BendBase.h:113
double getRotationAboutZ() const
Definition: ElementBase.h:574
void setEngeOriginDelta(double delta)
Definition: Bend2D.cpp:1048
Vector_t transformTo(const Vector_t &r) const
std::vector< double > engeCoeffsEntry_m
Enge coefficients for map entry and exit regions.
Definition: Bend2D.h:237
constexpr double rad2deg
Definition: Units.h:146
void setExitAngle(double exitAngle)
Definition: Bend2D.h:341
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Bend2D()
Definition: Bend2D.cpp:42
PETE_TBTree< FnFmod, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > fmod(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
const std::string name
double cosEntranceAngle_m
Enge function order for entry region.
Definition: Bend2D.h:261
ParticlePos_t & R
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition: Util.cpp:197
Fieldmap fieldmap_m
Magnet field map.
Definition: BendBase.h:56
void setupPusher(PartBunchBase< double, 3 > *bunch)
Definition: Bend2D.cpp:1242
virtual CoordinateSystemTrafo getEdgeToEnd() const override
Definition: Bend2D.h:348
double entranceAngle_m
Definition: BendBase.h:54
Quaternion getQuaternion(Vector_t u, Vector_t ref)
Definition: Quaternion.cpp:34
void calculateRefTrajectory(double &angleX, double &angleY)
Definition: Bend2D.cpp:510
const bool fast_m
Flag to turn on fast field calculation.
Definition: BendBase.h:57
gsl_interp_accel * exitFieldAccel_m
Definition: Bend2D.h:243
std::string getInputBasename()
get input file name without extension
Definition: OpalData.cpp:674
virtual void setElementLength(double length)
Set design length.
Definition: ElementBase.h:419
CoordinateSystemTrafo computeAngleTrafo_m
Definition: Bend2D.h:271
virtual void goOnline(const double &kineticEnergy) override
Definition: Bend2D.cpp:188
void print(Inform &msg, double bendAngleX, double bendAngle)
Definition: Bend2D.cpp:847
T isnan(T x)
isnan function with adjusted return type
Definition: matheval.hpp:67
constexpr double e
The value of .
Definition: Physics.h:39
CoordinateSystemTrafo toExitRegion_m
Definition: Bend2D.h:269
Inform & level2(Inform &inf)
Definition: Inform.cpp:46
double designEnergy_m
Bend design energy (eV).
Definition: BendBase.h:61
PETE_TUTree< FnCeil, typename T::PETE_Expr_t > ceil(const PETE_Expr< T > &l)
Definition: PETE.h:728
const PartData * getReference() const
double fieldAmplitude_m
Field amplitude.
Definition: BendBase.h:71
PETE_TUTree< FnArcSin, typename T::PETE_Expr_t > asin(const PETE_Expr< T > &l)
Definition: PETE.h:726
double maxAngle_m
Definition: Bend2D.h:272
virtual ~Bend2D()
Definition: Bend2D.cpp:125
void setBendEffectiveLength(double startField, double endField)
Definition: Bend2D.cpp:1027
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
std::vector< Vector_t > refTrajMap_m
Map of reference particle trajectory.
Definition: BendBase.h:64
double gap_m
Full vertical gap of the magnets.
Definition: BendBase.h:59
virtual void setEntranceAngle(double entranceAngle) override
Definition: Bend2D.h:332
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
void kick(const Vector_t &R, Vector_t &P, const Vector_t &Ef, const Vector_t &Bf, const double &dt) const
Definition: BorisPusher.h:65
double exitParameter2_m
Definition: Bend2D.h:233
BoundingBox getBoundingBoxInLabCoords() const override
Definition: Bend2D.cpp:1693
int polyOrderExit_m
function origin that Enge function ends.
Definition: Bend2D.h:259
static Fieldmap getFieldmap(std::string Filename, bool fast=false)
Definition: Fieldmap.cpp:48
std::pair< ApertureType, std::vector< double > > aperture_m
Definition: ElementBase.h:369
Inform * gmsg
Definition: Main.cpp:70
double calcFieldAmplitude(double radius) const
Calculate field amplitude from design energy and radius.
Definition: BendBase.cpp:70
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition: Vector3D.cpp:118
CoordinateSystemTrafo beginToEnd_m
Definition: Bend2D.h:266
double estimateFieldAdjustmentStep(double actualBendAngle)
Definition: Bend2D.cpp:577
T isinf(T x)
isinf function with adjusted return type
Definition: matheval.hpp:71
double deltaEndExit_m
function origin that Enge function starts.
Definition: Bend2D.h:257
void readFieldMap(Inform &msg)
Definition: Bend2D.cpp:947
double fieldAmplitudeY_m
Definition: BendBase.h:68
std::vector< double > engeCoeffsExit_m
Definition: Bend2D.h:238
void setNSlices(const std::size_t &nSlices)
Definition: Bend2D.cpp:1644
double entranceParameter1_m
Definition: Bend2D.h:229
Vector_t transformToExitRegion(const Vector_t &R) const
Definition: Bend2D.h:375