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