OPAL (Object Oriented Parallel Accelerator Library) 2024.2
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"
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
37extern Inform *gmsg;
38
39// Class Bend2D
40// ------------------------------------------------------------------------
41
43 Bend2D("")
44{}
45
46Bend2D::Bend2D(const Bend2D &right):
47 BendBase(right),
48 messageHeader_m(" * "),
49 pusher_m(right.pusher_m),
66 entryFieldValues_m(nullptr),
67 exitFieldValues_m(nullptr),
68 entryFieldAccel_m(nullptr),
69 exitFieldAccel_m(nullptr),
86 nSlices_m(right.nSlices_m){
87}
88
89Bend2D::Bend2D(const std::string &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),
100 reinitialize_m(false),
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),
112 deltaEndEntry_m(0.0),
114 deltaBeginExit_m(0.0),
115 deltaEndExit_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 */
149bool 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
188void 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
234void Bend2D::adjustFringeFields(double ratio) {
236
237 double delta = std::abs(entranceParameter1_m - entranceParameter2_m);
239
240 delta = std::abs(entranceParameter2_m - entranceParameter3_m);
242
243 delta = std::abs(exitParameter1_m - exitParameter2_m);
244 exitParameter1_m = exitParameter2_m - delta * ratio;
245
246 delta = std::abs(exitParameter2_m - exitParameter3_m);
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;
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
291void 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?
356Vector_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
510void 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();
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
577double 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 }
587 fieldStep *= fieldAmplitude_m / std::abs(fieldAmplitude_m);
588
589 return fieldStep;
590
591}
592
593void 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 */
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
751bool 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.
759 setEntranceAngle(std::copysign(1, angle_m) * entranceAngle_m);
760 setExitAngle(std::copysign(1, angle_m) * exitAngle_m);
761 angle_m = std::abs(angle_m);
763 }
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);
803 Vector_t Rpprime = computeAngleTrafo_m.transformTo(R);
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
847void 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: "
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: "
874 << " rad ("
876 << " degrees)"
877 << "\n";
878 msg << "Exit edge angle: "
879 << exitAngle_m
880 << " rad ("
882 << " degrees)"
883 << "\n";
884 msg << "Bend design radius: "
886 << " m"
887 << "\n";
888 msg << "Bend design energy: "
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: "
906 << " rad ("
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,
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
1027void 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.
1046}
1047
1048void 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
1063 exitParameter1_m = -delta - std::abs(exitParameter1_m - exitParameter2_m);
1064 exitParameter3_m = -delta + std::abs(exitParameter2_m - exitParameter3_m);
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));
1151 rotation);
1152 Vector_t tmp = computeAngleTrafo_m.transformTo(maxAngleExitAperture);
1153 maxAngle_m = std::fmod(Physics::two_pi - std::atan2(tmp(0), tmp(2)), Physics::two_pi);
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
1167bool 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)
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
1235void Bend2D::setFieldBoundaries(double startField, double /*endField*/) {
1236
1237 startField_m = startField - deltaBeginEntry_m / std::cos(entranceAngle_m);
1238 endField_m = (startField + angle_m * designRadius_m +
1239 deltaEndExit_m / std::cos(exitAngle_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
1281std::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));
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
1512 Vector_t P1 = toEntranceRegion_m.transformFrom(Vector_t(0, 0, entranceParameter1_m));
1513 Vector_t P2 = toExitRegion_m.transformFrom(Vector_t(0, 0, exitParameter1_m));
1514
1515 Vector_t T = cross(P1 - rotationCenter, P2 - rotationCenter);
1516 if (T[1] > 0) { // fringe fields are overlapping
1517 Vector_t dir1 = toEntranceRegion_m.rotateFrom(Vector_t(1, 0, 0));
1518 if (this->getType() == ElementType::RBEND ||
1519 std::abs(entranceAngle_m + exitAngle_m - angle_m) < 1e-8) {
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
1623bool 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{
1640 widthExitFringe_m = 2 * std::min(exitParameter3_m - exitParameter1_m, aperture_m.second[0]) + aperture_m.second[0];
1641}
1642
1643//set the number of slices for map tracking
1644void Bend2D::setNSlices(const std::size_t& nSlices) {
1645 nSlices_m = nSlices;
1646}
1647
1648//get the number of slices for map tracking
1649std::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])
1655std::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])
1675std::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}
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
Definition Vector3D.cpp:111
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
Definition Vector3D.cpp:118
Quaternion Quaternion_t
Definition Quaternion.h:42
Quaternion getQuaternion(Vector_t u, Vector_t ref)
std::vector< std::pair< Vector_t, Vector_t > > decorations_m
std::vector< Vektor< unsigned int, 3 > > triangles_m
std::vector< Vector_t > vertices_m
T euclidean_norm(const Vector< T > &)
Euclidean norm.
Definition Vector.h:243
boost::numeric::ublas::matrix< double > matrix_t
Definition BoostMatrix.h:23
Inform * gmsg
Definition Main.cpp:70
#define X(arg)
Definition fftpack.cpp:106
std::complex< double > a
T det(const AntiSymTenzor< T, 3 > &)
Inform & level2(Inform &inf)
Definition Inform.cpp:46
Inform & endl(Inform &inf)
Definition Inform.cpp:42
#define ERRORMSG(msg)
Definition IpplInfo.h:350
#define WARNMSG(msg)
Definition IpplInfo.h:349
const std::string name
constexpr double two_pi
The value of.
Definition Physics.h:33
constexpr double c
The velocity of light in m/s.
Definition Physics.h:45
constexpr double pi
The value of.
Definition Physics.h:30
constexpr double ps2s
Definition Units.h:53
constexpr double rad2deg
Definition Units.h:146
constexpr double deg2rad
Definition Units.h:143
bool writeBendTrajectories
Definition Options.cpp:95
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:197
std::string toUpper(const std::string &str)
Definition Util.cpp:147
const PartData * getReference() const
std::string getInputBasename()
get input file name without extension
Definition OpalData.cpp:674
static OpalData * getInstance()
Definition OpalData.cpp:196
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:666
void calculateRefTrajectory(double &angleX, double &angleY)
Definition Bend2D.cpp:510
double exitParameter3_m
Definition Bend2D.h:234
double widthExitFringe_m
Definition Bend2D.h:208
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
void setupFringeWidths()
Definition Bend2D.cpp:1637
Vector_t transformToExitRegion(const Vector_t &R) const
Definition Bend2D.h:375
void readFieldMap(Inform &msg)
Definition Bend2D.cpp:947
bool reinitialize_m
Definition Bend2D.h:216
int polyOrderExit_m
function origin that Enge function ends.
Definition Bend2D.h:259
double exitParameter1_m
Definition Bend2D.h:232
Vector_t calcExitFringeField(const Vector_t &R, double deltaX)
Definition Bend2D.cpp:411
virtual ElementType getType() const override=0
Get element type std::string.
virtual bool findChordLength(double &chordLength)=0
gsl_interp_accel * entryFieldAccel_m
Definition Bend2D.h:242
bool inMagnetCentralRegion(const Vector_t &R) const
Definition Bend2D.cpp:798
std::vector< double > engeCoeffsEntry_m
Enge coefficients for map entry and exit regions.
Definition Bend2D.h:237
std::array< double, 2 > getEntranceFringeFieldLength() const
Get entrance fringe field length.
Definition Bend2D.cpp:1655
virtual void initialise(PartBunchBase< double, 3 > *bunch, double &startField, double &endField) override
Definition Bend2D.cpp:192
double deltaEndEntry_m
function origin where Enge function starts.
Definition Bend2D.h:251
double deltaBeginEntry_m
Definition Bend2D.h:249
void setExitAngle(double exitAngle)
Definition Bend2D.h:341
double maxAngle_m
Definition Bend2D.h:272
bool inMagnetExitRegion(const Vector_t &R) const
Definition Bend2D.cpp:823
CoordinateSystemTrafo beginToEnd_m
Definition Bend2D.h:266
CoordinateSystemTrafo getBeginToEnd_local() const
Definition Bend2D.h:354
double deltaBeginExit_m
Enge function order for entry region.
Definition Bend2D.h:255
Vector_t calcCentralField(const Vector_t &R, double deltaX)
Definition Bend2D.cpp:356
void setEngeOriginDelta(double delta)
Definition Bend2D.cpp:1048
double entranceParameter3_m
Definition Bend2D.h:231
bool calculateMapField(const Vector_t &R, Vector_t &B)
Definition Bend2D.cpp:447
void setBendStrength()
Definition Bend2D.cpp:1039
void findBendStrength()
Definition Bend2D.cpp:683
double widthEntranceFringe_m
End of magnet field map in s coordinates (m).
Definition Bend2D.h:207
gsl_spline ** exitFieldValues_m
Definition Bend2D.h:241
std::vector< double > engeCoeffsExit_m
Definition Bend2D.h:238
double entranceParameter1_m
Definition Bend2D.h:229
double designRadius_m
through the bend.
Definition Bend2D.h:199
void setFieldCalcParam()
Definition Bend2D.cpp:1070
double sinEntranceAngle_m
Definition Bend2D.h:262
BorisPusher pusher_m
Definition Bend2D.h:196
void setBendEffectiveLength(double startField, double endField)
Definition Bend2D.cpp:1027
void setNSlices(const std::size_t &nSlices)
Definition Bend2D.cpp:1644
Vector_t calcEntranceFringeField(const Vector_t &R, double deltaX)
Definition Bend2D.cpp:374
bool setupBendGeometry(double &startField, double &endField)
Definition Bend2D.cpp:1167
bool findIdealBendParameters(double chordLength)
Definition Bend2D.cpp:751
Bend2D()
Definition Bend2D.cpp:42
std::string messageHeader_m
Definition Bend2D.h:194
double tanEntranceAngle_m
Definition Bend2D.h:263
virtual void setEntranceAngle(double entranceAngle) override
Definition Bend2D.h:332
double startField_m
Dipole field index.
Definition Bend2D.h:204
virtual void goOnline(const double &kineticEnergy) override
Definition Bend2D.cpp:188
std::size_t nSlices_m
Definition Bend2D.h:274
double exitParameter2_m
Definition Bend2D.h:233
double endField_m
Start of magnet field map in s coordinates (m).
Definition Bend2D.h:205
CoordinateSystemTrafo toEntranceRegion_m
Definition Bend2D.h:268
bool isPositionInExitField(const Vector_t &R) const
Definition Bend2D.cpp:839
void setFieldBoundaries(double startField, double endField)
Definition Bend2D.cpp:1235
gsl_interp_accel * exitFieldAccel_m
Definition Bend2D.h:243
double deltaEndExit_m
function origin that Enge function starts.
Definition Bend2D.h:257
Vector_t transformToEntranceRegion(const Vector_t &R) const
Definition Bend2D.h:370
bool inMagnetEntranceRegion(const Vector_t &R) const
Definition Bend2D.cpp:816
Bend2D(const std::string &name)
Constructor with given name.
Definition Bend2D.cpp:89
void adjustFringeFields(double ratio)
Definition Bend2D.cpp:234
double exitAngle_m
Bend design radius (m).
Definition Bend2D.h:201
double fieldIndex_m
and the exit face of the magnet (radians).
Definition Bend2D.h:203
virtual ~Bend2D()
Definition Bend2D.cpp:125
MeshData getSurfaceMesh() const
Definition Bend2D.cpp:1388
bool isFieldZero()
Definition Bend2D.cpp:1249
std::array< double, 2 > getExitFringeFieldLength() const
Get exit fringe field length.
Definition Bend2D.cpp:1675
CoordinateSystemTrafo beginToEnd_lcs_m
Definition Bend2D.h:267
double entranceParameter2_m
Definition Bend2D.h:230
int polyOrderEntry_m
function origin that Enge function ends.
Definition Bend2D.h:253
double estimateFieldAdjustmentStep(double actualBendAngle)
Definition Bend2D.cpp:577
virtual bool isInside(const Vector_t &r) const override
Definition Bend2D.cpp:1623
virtual CoordinateSystemTrafo getEdgeToEnd() const override
Definition Bend2D.h:348
bool setupDefaultFieldMap()
Definition Bend2D.cpp:1219
BoundingBox getBoundingBoxInLabCoords() const override
Definition Bend2D.cpp:1693
std::vector< Vector_t > getOutline() const
Definition Bend2D.cpp:1281
CoordinateSystemTrafo toExitRegion_m
Definition Bend2D.h:269
gsl_spline ** entryFieldValues_m
Definition Bend2D.h:240
bool initializeFieldMap()
Definition Bend2D.cpp:783
CoordinateSystemTrafo computeAngleTrafo_m
Definition Bend2D.h:271
void calcEngeFunction(double zNormalized, const std::vector< double > &engeCoeff, int polyOrder, double &engeFunc, double &engeFuncDeriv, double &engeFuncSecDerivNorm)
Definition Bend2D.cpp:291
std::size_t getNSlices() const
Definition Bend2D.cpp:1649
void setupPusher(PartBunchBase< double, 3 > *bunch)
Definition Bend2D.cpp:1242
double tanExitAngle_m
Definition Bend2D.h:264
void print(Inform &msg, double bendAngleX, double bendAngle)
Definition Bend2D.cpp:847
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
void findBendEffectiveLength(double startField, double endField)
Definition Bend2D.cpp:593
void setGapFromFieldMap()
Definition Bend2D.cpp:1158
bool isPositionInEntranceField(const Vector_t &R) const
Definition Bend2D.cpp:832
double cosEntranceAngle_m
Enge function order for entry region.
Definition Bend2D.h:261
double calculateBendAngle()
Definition Bend2D.cpp:252
double calcGamma() const
Calculate gamma from design energy.
Definition BendBase.cpp:89
std::vector< Vector_t > refTrajMap_m
Map of reference particle trajectory.
Definition BendBase.h:64
const bool fast_m
Flag to turn on fast field calculation.
Definition BendBase.h:57
double calcBendAngle(double chordLength, double radius) const
Calculate bend angle from chord length and design radius.
Definition BendBase.cpp:79
double fieldAmplitude_m
Field amplitude.
Definition BendBase.h:71
double calcBetaGamma() const
Calculate beta*gamma from design energy.
Definition BendBase.cpp:95
double getChordLength() const
Definition BendBase.h:82
double designEnergy_m
Bend design energy (eV).
Definition BendBase.h:61
double entranceAngle_m
Definition BendBase.h:54
double getBendAngle() const
Definition BendBase.h:92
Fieldmap fieldmap_m
Magnet field map.
Definition BendBase.h:56
double gap_m
Full vertical gap of the magnets.
Definition BendBase.h:59
double fieldAmplitudeY_m
Definition BendBase.h:68
std::string fileName_m
Definition BendBase.h:73
double chordLength_m
Definition BendBase.h:52
double getEntranceAngle() const
Definition BendBase.h:103
double calcFieldAmplitude(double radius) const
Calculate field amplitude from design energy and radius.
Definition BendBase.cpp:70
double calcDesignRadius(double fieldAmplitude) const
Calculate design radius from design energy and field amplitude.
Definition BendBase.cpp:61
double fieldAmplitudeX_m
Definition BendBase.h:66
double getFullGap() const
Definition BendBase.h:113
double angle_m
Bend angle.
Definition BendBase.h:53
bool online_m
Definition Component.h:192
PartBunchBase< double, 3 > * RefPartBunch_m
Definition Component.h:191
virtual const std::string & getName() const
Get element name.
bool getFlagDeleteOnTransverseExit() const
virtual double getElementLength() const
Get design length.
virtual void setElementLength(double length)
Set design length.
std::pair< ApertureType, std::vector< double > > aperture_m
virtual CoordinateSystemTrafo getEdgeToBegin() const
double getRotationAboutZ() const
double rotationZAxis_m
double elementEdge_m
CoordinateSystemTrafo csTrafoGlobal2Local_m
Vector_t rotateFrom(const Vector_t &r) const
Vector_t transformFrom(const Vector_t &r) const
Vector_t transformTo(const Vector_t &r) const
Vector_t rotate(const Vector_t &) const
Quaternion conjugate() const
Definition Quaternion.h:103
virtual void readMap()=0
static Fieldmap getFieldmap(std::string Filename, bool fast=false)
Definition Fieldmap.cpp:48
void enlargeToContainPosition(const Vector_t &position)
static int myNode()
Definition IpplInfo.cpp:691
Definition Vec.h:22
Vektor< double, 3 > Vector_t