36 KOKKOS_INLINE_FUNCTION
37 double factorial(
unsigned int n) {
38 if (n == 0)
return 1.0;
39 if (n == 1)
return 1.0;
40 if (n == 2)
return 2.0;
41 if (n == 3)
return 6.0;
42 if (n == 4)
return 24.0;
43 if (n == 5)
return 120.0;
44 if (n > 5) Kokkos::abort(
"factorial out of bounds");
59 NormalComponents(
"Multipole::Normal", right.NormalComponents.extent(0)),
60 NormalComponentErrors(
"Multipole::NormalErr", right.NormalComponentErrors.extent(0)),
61 SkewComponents(
"Multipole::Skew", right.SkewComponents.extent(0)),
62 SkewComponentErrors(
"Multipole::SkewErr", right.SkewComponentErrors.extent(0)),
64 max_SkewComponent_m(right.max_SkewComponent_m),
65 max_NormalComponent_m(right.max_NormalComponent_m),
67 nSlices_m(right.nSlices_m) {
81 NormalComponents(
"Multipole::Normal", 1),
82 NormalComponentErrors(
"Multipole::NormalErr", 1),
83 SkewComponents(
"Multipole::Skew", 1),
84 SkewComponentErrors(
"Multipole::SkewErr", 1),
85 max_SkewComponent_m(1),
86 max_NormalComponent_m(1),
112 "Multipole::getNormalComponent",
113 "component index " + std::to_string(n) +
" out of bounds");
136 "Multipole::getSkewComponent",
137 "component index " + std::to_string(n) +
" out of bounds");
161 "Multipole::setNormalComponent",
162 "component index " + std::to_string(n) +
" out of bounds");
171 double valComp, valErr;
175 valComp = (v + vError) / 2.0;
178 double fact = factorial(n);
179 valComp = (v + vError) / fact;
180 valErr = vError / fact;
187 Kokkos::deep_copy(sub_comp, valComp);
188 Kokkos::deep_copy(sub_err, valErr);
205 "Multipole::setSkewComponent",
206 "component index " + std::to_string(n) +
" out of bounds");
215 double valComp, valErr;
218 valComp = (v + vError) / 2.0;
221 double fact = factorial(n);
222 valComp = (v + vError) / fact;
223 valErr = vError / fact;
229 Kokkos::deep_copy(sub_comp, valComp);
230 Kokkos::deep_copy(sub_err, valErr);
246 *
gmsg << level3 <<
"Multipole::apply() called" << endl;
248 auto Rview = pc->R.getView();
249 auto Eview = pc->E.getView();
250 auto Bview = pc->B.getView();
251 const size_t nLocal = pc->getLocalNum();
263 Kokkos::parallel_for(
264 "Multipole::apply()", nLocal, KOKKOS_LAMBDA(
const size_t i) {
266 if (Rview(i)(2) > 0 && Rview(i)(2) <= elemLength) {
270 Rview(i), Ef, Bf, normalComponents, skewComponents, maxNormal, maxSkew);
271 for (
unsigned d = 0; d < 3; ++d) {
272 Eview(i)(d) += Ef(d);
273 Bview(i)(d) += Bf(d);
293 std::shared_ptr<ParticleContainer_t> pc =
RefPartBunch_m->getParticleContainer();
294 auto Rview = pc->
R.getView();
306 for (
unsigned int d = 0; d < 3; ++d) {
404KOKKOS_INLINE_FUNCTION
407 const Kokkos::View<double*> NormalComponents,
const Kokkos::View<double*> SkewComponents,
408 int max_NormalComponent,
int max_SkewComponent) {
424 for (
int i = 0; i < count; ++i) {
439 Rn_x[i + 1] = Rn_x[i] * R(0);
440 Rn_y[i + 1] = Rn_y[i] * R(1);
441 fact[i + 1] = fact[i] / (double)(i + 1);
453 for (
int i = 0; i < count; ++i) {
467 Rn_x[i + 1] = Rn_x[i] * R(0);
468 Rn_y[i + 1] = Rn_y[i] * R(1);
469 fact[i + 1] = fact[i] / (double)(i + 1);
491 auto SkewComponents_host = Kokkos::create_mirror_view(
SkewComponents);
502 for (
int i = 0; i < count; ++i) {
504 double norm = NormalComponents_host(i);
517 B(0) += 2 * norm * R(0) * R(1);
518 B(1) += norm * (Rn[2](0) - Rn[2](1));
522 B(0) += norm * (3 * Rn[2](0) * Rn[1](1) - Rn[3](1));
523 B(1) += norm * (Rn[3](0) - 3 * Rn[1](0) * Rn[2](1));
527 B(0) += 4 * norm * (Rn[3](0) * Rn[1](1) - Rn[1](0) * Rn[3](1));
528 B(1) += norm * (Rn[4](0) - 6 * Rn[2](0) * Rn[2](1) + Rn[4](1));
532 double powMinusOne = 1.0;
533 double Bx = 0.0, By = 0.0;
534 for (
int j = 1; j <= (i + 1) / 2; ++j) {
535 Bx += powMinusOne * norm
536 * (Rn[i - 2 * j + 1](0) * fact[i - 2 * j + 1] * Rn[2 * j - 1](1)
538 By += powMinusOne * norm
539 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
544 if ((i + 1) / 2 == i / 2) {
546 By += powMinusOne * norm
547 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
555 Rn[i + 1](0) = Rn[i](0) * R(0);
556 Rn[i + 1](1) = Rn[i](1) * R(1);
557 fact[i + 1] = fact[i] / (double)(i + 1);
568 for (
int i = 0; i < count; ++i) {
569 double skew = SkewComponents_host(i);
582 B(0) -= skew * (Rn[2](0) - Rn[2](1));
583 B(1) += 2 * skew * R(0) * R(1);
587 B(0) -= skew * (Rn[3](0) - 3 * Rn[1](0) * Rn[2](1));
588 B(1) += skew * (3 * Rn[2](0) * Rn[1](1) - Rn[3](1));
592 B(0) -= skew * (Rn[4](0) - 6 * Rn[2](0) * Rn[2](1) + Rn[4](1));
593 B(1) += 4 * skew * (Rn[3](0) * Rn[1](1) - Rn[1](0) * Rn[3](1));
597 double powMinusOne = 1.0;
598 double Bx = 0.0, By = 0.0;
599 for (
int j = 1; j <= (i + 1) / 2; ++j) {
600 Bx -= powMinusOne * skew
601 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
603 By += powMinusOne * skew
604 * (Rn[i - 2 * j + 1](0) * fact[i - 2 * j + 1] * Rn[2 * j - 1](1)
609 if ((i + 1) / 2 == i / 2) {
611 Bx -= powMinusOne * skew
612 * (Rn[i - 2 * j + 2](0) * fact[i - 2 * j + 2] * Rn[2 * j - 2](1)
621 Rn[i + 1](0) = Rn[i](0) * R(0);
622 Rn[i + 1](1) = Rn[i](1) * R(1);
623 fact[i + 1] = fact[i] / (double)(i + 1);
662 else if (
static_cast<unsigned long>(component) >=
NormalComponents.extent(0))
ippl::Vector< T, Dim > Vector_t
constexpr int MAX_MP_ORDER
Template PIC bunch: IPPL PicManager, shared field mesh/solver, and multiple particle containers.
virtual void visitMultipole(const Multipole &)=0
Apply the algorithm to a multipole.
PartBunch_t * RefPartBunch_m
bool getFlagDeleteOnTransverseExit() const
virtual double getElementLength() const
Get design length.
bool isInsideTransverse(const Vector_t< double, 3 > &r) const
Interface for general multipole.
void setSkewComponent(int n, double)
virtual void accept(BeamlineVisitor &) const override
Accepts a BeamlineVisitor.
int max_NormalComponent_m
void setNormalComponent(int n, double)
virtual void initialise(PartBunch_t *bunch, double &startField, double &endField) override
Setup, multipole goes online.
bool isFocusing(int n) const
virtual bool applyToReferenceParticle(const Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, const double &t, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) override
Apply to reference particle with position R and momemtum P.
virtual void finalise() override
void setNSlices(const std::size_t &nSlices)
virtual bool bends() const override
void computeFieldHost(Vector_t< double, 3 > R, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B) const
Computes the E and B field at position R of the reference particle.
Kokkos::View< double * > SkewComponents
virtual ElementType getType() const override
Get element type std::string.
virtual bool isInside(const Vector_t< double, 3 > &r) const override
virtual bool apply(const std::shared_ptr< ParticleContainer_t > &pc) override
Apply to all particles. Kernel launch moved inside the function.
Kokkos::View< double * > SkewComponentErrors
Kokkos::View< double * > NormalComponentErrors
Kokkos::View< double * > NormalComponents
static KOKKOS_INLINE_FUNCTION void computeField(Vector_t< double, 3 > R, Vector_t< double, 3 > &E, Vector_t< double, 3 > &B, const Kokkos::View< double * > NormalComponents, const Kokkos::View< double * > SkewComponents, int max_NormalComponent, int max_SkewComponent)
Computes the E and B field at position R.
double getSkewComponent(int n) const
Gets the n-th skew component of the multipole expansion.
virtual void getFieldExtend(double &zBegin, double &zEnd) const override
Return the field-support extent of the component.
std::size_t getNSlices() const
double getNormalComponent(int n) const
Gets the n-th normal component of the multipole expansion.
Vector_t< double, Dim > R(size_t)
Do not use; throws (access positions via ParticleContainer::R).
double getChargePerParticle(size_t containerIndex=0) const
Get the charge per particle for a given particle container.