71 :
Tracker(beamline, revBeam, false),
73 itsOpalBeamline_m(beamline.getOrigin3D(), beamline.getInitialDirection()),
76 dtCurrentTrack_m(0.0),
78 timeIntegrationTimer1_m(IpplTimings::getTimer(
"TIntegration1")),
79 timeIntegrationTimer2_m(IpplTimings::getTimer(
"TIntegration2")),
80 fieldEvaluationTimer_m(IpplTimings::getTimer(
"External field eval")),
81 PluginElemTimer_m(IpplTimings::getTimer(
"PluginElements")),
82 BinRepartTimer_m(IpplTimings::getTimer(
"Binaryrepart")),
83 OrbThreader_m(IpplTimings::getTimer(
"OrbThreader")) {}
90 const std::vector<unsigned long long>& maxSteps,
double zstart,
91 const std::vector<double>& zstop,
const std::vector<double>& dt,
92 const std::vector<std::vector<std::shared_ptr<SamplingBase>>>& emittingSamplers)
93 :
Tracker(beamline, bunch, revBeam, false),
95 itsOpalBeamline_m(beamline.getOrigin3D(), beamline.getInitialDirection()),
98 dtCurrentTrack_m(0.0),
100 emittingSamplers_m(emittingSamplers),
101 timeIntegrationTimer1_m(IpplTimings::getTimer(
"TIntegration1")),
102 timeIntegrationTimer2_m(IpplTimings::getTimer(
"TIntegration2")),
103 fieldEvaluationTimer_m(IpplTimings::getTimer(
"External field eval")),
104 BinRepartTimer_m(IpplTimings::getTimer(
"Binaryrepart")),
105 OrbThreader_m(IpplTimings::getTimer(
"OrbThreader")) {
106 for (
unsigned int i = 0; i < zstop.size(); ++i) {
126 "ParallelTracker::visitComponent()",
127 "Tracking of the \"LASER\" element is not implemented yet.");
134 "ParallelTracker::visitLaser()",
135 "Tracking of the \"LASER\" element is not implemented yet.");
166 Inform m(
"ParallelTracker::execute");
176 m << level3 <<
"Initialized Boris pusher." << endl;
186 m << level3 <<
"Selected minimum time step from configuration: " << minTimeStep << endl;
190 m << level3 <<
"Activated all beamline elements." << endl;
197 const auto& particleContainers =
itsBunch_m->getParticleContainers();
198 for (
size_t ci = 0; ci < particleContainers.size(); ++ci) {
199 const auto& pc = particleContainers[ci];
203 if (!pc->getReference()) {
205 "ParallelTracker::execute",
206 "Particle container has null PartData reference during lab-frame init.");
208 pc->setToLabTrafo(beamlineToLab);
210 if (pc->getTotalNum() > 0) {
211 pc->getRefPartP() = beamlineToLab.
rotateTo(pc->getMeanP());
213 bool useSamplerReference =
false;
217 if (sampler && sampler->hasInitialReferenceMomentum()) {
218 samplerRefP = sampler->getInitialReferenceMomentum();
219 useSamplerReference =
true;
225 if (useSamplerReference) {
226 if (
dot(samplerRefP, samplerRefP) <= 0.0) {
228 "ParallelTracker::execute",
229 "Sampler-provided initial reference momentum is zero.");
231 pc->getRefPartP() = beamlineToLab.
rotateTo(samplerRefP);
233 const PartData& pref = *pc->getReference();
234 const double P0 = pref.
getP() / pref.
getM();
241 <<
"Transformed reference particle position and momentum to lab frame (all containers)."
256 m << level4 <<
"Initial bunch bounds:\n"
257 <<
" rmin = " << rmin <<
"\n"
258 <<
" rmax = " << rmax << endl;
268 bool const psDump0 = 0;
269 bool const statDump0 = 0;
273 m << level2 <<
"Dump initial phase space done." << endl;
278 itsBunch_m->getParticleContainer(0)->getRefPartR(),
279 itsBunch_m->getParticleContainer(0)->getRefPartP(),
280 itsBunch_m->getParticleContainer(0)->get_sPos(),
289 m << level4 <<
"Orbit threader execution done." << endl;
299 m << level4 <<
"Set time view of particle bunch." << endl;
306 m << level4 <<
"Reset bunch time to " << time <<
"." << endl;
333 m << level5 <<
">>>>>>>>>>>>>>>>>> Starting Tracking Loop >>>>>>>>>>>>>>>>>>" << endl;
346 <<
", track steps = " << step <<
" to " << trackSteps <<
"." << endl;
347 for (; step < trackSteps; ++step) {
349 m << level4 <<
"No active particle containers; ending inner track segment." << endl;
368 m << level4 <<
"timeIntegration1 done at step " << step <<
"." << endl;
370 if (nSourceMarkedAfterPush > 0) {
374 m << level5 <<
"Bunch updated after timeIntegration1." << endl;
378 m << level4 <<
"E and B fields reset at step " << step <<
"." << endl;
386 m << level4 <<
"Space charge field computation done at step " << step <<
"." << endl;
397 m << level5 <<
"Set time view of particle bunch to dt = "
403 m << level4 <<
"Emit particles from emission sources done at step " << step <<
"."
406 if (nSourceMarkedAfterEmission > 0) {
410 m << level5 <<
"Bunch updated after emission." << endl;
414 m << level4 <<
"External field computation done at step " << step <<
"." << endl;
419 m << level5 <<
"Spin T-BMT update done at step " << step <<
"." << endl;
423 m << level4 <<
"timeIntegration2 done at step " << step <<
"." << endl;
425 if (nSourceMarkedAfterStep > 0) {
429 m << level5 <<
"Bunch updated after timeIntegration2." << endl;
433 m << level5 <<
"Applied global processes at step " << step <<
"." << endl;
434 if (nProcessMarked > 0) {
440 m << level5 <<
"WARNING: No particles in the bunch at step " << step <<
" on rank "
441 << ippl::Comm->rank() <<
". This has no effect on the simulation." << endl;
452 m << level4 <<
"Updated reference particle at step " << step <<
"." << endl;
457 const auto& particleContainersStep =
itsBunch_m->getParticleContainers();
458 size_t nBoundpMarked = 0;
459 for (
size_t i = 0; i < particleContainersStep.size(); ++i) {
460 const auto& pc = particleContainersStep[i];
465 nMarked = pc->markParticlesOutside(sigmas);
466 nBoundpMarked += nMarked;
468 m << level2 <<
"Marked " << nMarked <<
" particles outside " << sigmas
469 <<
"-sigma boundary for deletion (container " << i <<
")." << endl;
475 if (nBoundpMarked > 0) {
479 for (
size_t i = 0; i < particleContainersStep.size(); ++i) {
480 const auto& pc = particleContainersStep[i];
484 m << level4 <<
"Current path length (container " << i <<
") is " << pc->get_sPos()
494 bool const statDump =
501 m << level5 <<
"Track steps incremented." << endl;
506 for (
size_t i = 0; i < particleContainers.size(); ++i) {
507 const auto& pc = particleContainers[i];
511 ippl::Vector<double, 3> pdivg =
515 m << level4 <<
"Calculated drift per time step (container " << i
520 <<
"Approaching end of current step size configuration for container " << i
529 <<
"All active containers reached current zstop. Preparing to switch to "
530 <<
"next configuration." << endl;
538 ippl::Comm->allreduce(
globalEOL_m, 1, std::logical_and<bool>());
546 bool const statDump =
552 *
gmsg << level2 <<
"* Dump phase space of last step" << endl;
565 *
gmsg << level1 << endl
566 <<
"* Done executing ParallelTracker at " << myt3.
time() << endl
576 Inform m(
"ParallelTracker::timeIntegration1");
578 const size_t n =
itsBunch_m->getNumParticleContainers();
579 for (
size_t i = 0; i < n; ++i) {
583 auto pc =
itsBunch_m->getParticleContainer(i);
590 m << level4 <<
"Push particles done for all containers." << endl;
600 Inform m(
"ParallelTracker::timeIntegration2");
603 const size_t n =
itsBunch_m->getNumParticleContainers();
604 for (
size_t i = 0; i < n; ++i) {
608 auto pc =
itsBunch_m->getParticleContainer(i);
616 m << level4 <<
"Kick/push particles done for all containers." << endl;
637 Inform m(
"ParallelTracker::computeSpaceChargeFields");
646 *
gmsg << level1 <<
"no solver available!" << endl;
648 "ParallelTracker::computeSpaceChargeFields",
649 "Bunch has no field solver assigned! If you want to run without "
650 "space charge effects, please use TYPE=NONE for the field solver.");
654 m << level4 <<
"Calculate beam parameters done." << endl;
658 const double pmean_tol = 1e-12;
660 double pmean_len2 =
dot(pmean, pmean);
661 if (pmean_len2 < pmean_tol * pmean_tol) {
662 pmean =
itsBunch_m->getParticleContainer()->getRefPartP();
663 pmean_len2 =
dot(pmean, pmean);
665 if (pmean_len2 < pmean_tol * pmean_tol) {
679 itsBunch_m->getParticleContainer()->getLocalNum());
680 m << level4 <<
"Transform particle positions to beam coordinate system done." << endl;
682 m << level5 <<
"Bunch updated for positions in beam coordinate system." << endl;
689 m << level4 <<
"Binary repartition done." << endl;
695 m << level3 <<
"Compute self fields done." << endl;
698 const size_t nLocRef =
itsBunch_m->getParticleContainer()->getLocalNum();
700 itsBunch_m->getParticleContainer()->
R.getView(), nLocRef);
701 m << level5 <<
"Transform particle positions back to reference coordinate system done." << endl;
704 m << level5 <<
"Rotate E fields back to reference coordinate system done." << endl;
707 <<
"Rotate B fields back to reference coordinate system done. ComputeSelfFields done."
711 m << level5 <<
"Bunch updated for positions in reference coordinate system." << endl;
719 Inform msg(
"ParallelTracker ", *
gmsg);
721 const size_t nContainers =
itsBunch_m->getNumParticleContainers();
722 for (
size_t ci = 0; ci < nContainers; ++ci) {
726 auto pc =
itsBunch_m->getParticleContainer(ci);
733 if (pc->getTotalNum() > 0) {
734 pc->computeMinMaxR();
735 rmin = pc->getMinR();
736 rmax = pc->getMaxR();
743 if (!std::isfinite(rmin(2)) || !std::isfinite(rmax(2))) {
751 elements = oth.
query(pc->get_sPos() + 0.5 * (rmax(2) + rmin(2)), rmax(2) - rmin(2));
758 IndexMap::value_t::const_iterator it =
elements.begin();
759 const IndexMap::value_t::const_iterator end =
elements.end();
760 for (; it != end; ++it) {
767 (*it)->setCurrentSCoordinate(pc->get_sPos() + rmin(2));
769 pc->transformBunch(refToLocalCSTrafo);
774 pc->transformBunch(localToRefCSTrafo);
785 const auto& containers =
itsBunch_m->getParticleContainers();
786 for (
size_t ci = 0; ci < containers.size(); ++ci) {
787 const auto& pc = containers[ci];
798 const size_t extentBeforeEmission = pc->
R.size();
802 pc->transformBunch(refToGun);
806 sampler->emitParticles(t, dt);
810 pc->transformBunch(refToGun.
inverted());
812 pc->setM(pc->getMassPerParticle());
813 pc->setQ(pc->getChargePerParticle());
822 const size_t extentAfterEmission = pc->R.size();
823 if (extentAfterEmission != extentBeforeEmission) {
825 "ParallelTracker::emitFromEmissionSources",
826 "Local particle storage was resized during emission (likely due to "
827 "over-emission causing a Kokkos::realloc). This leads to loss of "
828 "previously tracked particles. Please increase the total number of "
829 "macroparticles or adjust NPARTDIST / the emission profile. If you are "
830 "using emission sources, please check the emission profile and adjust "
831 "the number of particles emitted.");
838 const size_t nContainers =
itsBunch_m->getNumParticleContainers();
842 for (
size_t ci = 0; ci < nContainers; ++ci) {
843 auto pc =
itsBunch_m->getParticleContainer(ci);
847 const auto& processes = pc->getGlobalProcesses();
848 if (processes.empty()) {
851 for (
const auto& process : processes) {
853 nMarked += process->apply(*pc, dt, globalTrackStep, ci);
861 bool activeOnly, Inform& m,
const std::string& reason) {
862 const size_t nContainers =
itsBunch_m->getNumParticleContainers();
865 for (
size_t ci = 0; ci < nContainers; ++ci) {
869 auto pc =
itsBunch_m->getParticleContainer(ci);
874 const size_t nContainerDeleted = pc->deleteInvalidParticles();
875 nDeleted += nContainerDeleted;
876 if (nContainerDeleted > 0) {
877 m << level2 <<
"Deleted " << nContainerDeleted <<
" particles marked by " << reason
878 <<
", " << pc->getTotalNum() <<
" remaining (container " << ci <<
")." << endl;
894 const bool shiftedGreensConfigured = bsolver->isShiftedGreensEnabled();
895 if (!imageChargeConfigured && !shiftedGreensConfigured) {
899 const double sourcePlaneZ = imageChargeConfigured ? bsolver->getImageChargePlaneZ()
900 : bsolver->getShiftedGreensPlaneZ();
903 const size_t nContainers =
itsBunch_m->getNumParticleContainers();
904 for (
size_t ci = 0; ci < nContainers; ++ci) {
909 auto pc =
itsBunch_m->getParticleContainer(ci);
910 if (!pc || pc->getLocalNum() == 0) {
919 auto Rview = pc->R.getView();
920 auto Pview = pc->P.getView();
921 auto invalid = pc->InvalidMask.getView();
925 Kokkos::parallel_reduce(
926 "ParallelTracker::markBackwardParticlesAtSourcePlane", nLocal,
929 for (
unsigned d = 0; d < 3; ++d) {
930 delta[d] = Rview(i)[d] - origin[d];
934 const bool backwards = localR[2] < sourcePlaneZ && localP[2] < 0.0;
935 const bool newlyMarked = backwards && !invalid(i);
936 invalid(i) = invalid(i) || backwards;
937 count += newlyMarked ? 1 : 0;
942 localTotalMarked += localMarked;
946 ippl::Comm->allreduce(localTotalMarked, globalTotalMarked, 1, std::plus<size_type>());
947 return static_cast<size_t>(globalTotalMarked);
954 const size_t n =
itsBunch_m->getNumParticleContainers();
955 for (
size_t i = 0; i < n; ++i) {
959 auto pc =
itsBunch_m->getParticleContainer(i);
979 auto Rview = pc.R.getView();
980 auto Pview = pc.
P.getView();
983 Kokkos::parallel_for(
984 "pushParticles", pc.getLocalNum(), KOKKOS_LAMBDA(
const size_t i) {
998 ippl::Comm->barrier();
1010 Inform m(
"ParallelTracker::kickParticles");
1013 auto Pview = pc.
P.getView();
1014 auto dtview = pc.
dt.getView();
1015 auto Efview = pc.
E.getView();
1016 auto Bfview = pc.
B.getView();
1017 m << level5 <<
"Got particle views for kick operation." << endl;
1022 const double mass = ref.
getM();
1023 const double charge = ref.
getQ();
1024 Kokkos::parallel_for(
1025 "kickParticles", pc.getLocalNum(), KOKKOS_LAMBDA(
const size_t i) {
1030 pusher.
kick(0, p, Efview(i), Bfview(i), dtview(i), mass, charge);
1039 ippl::Comm->barrier();
1042 m << level5 <<
"Completed parallel kick operation." << endl;
1046 const size_t n =
itsBunch_m->getNumParticleContainers();
1047 for (
size_t i = 0; i < n; ++i) {
1051 auto pc =
itsBunch_m->getParticleContainer(i);
1052 if (!pc || !pc->hasSpin()) {
1056 const PartData& ref = *pc->getReference();
1057 const double mass = ref.
getM();
1058 const double charge = ref.
getQ();
1061 auto Polview = pc->Pol.getView();
1062 auto Pview = pc->P.getView();
1063 auto Efview = pc->E.getView();
1064 auto Bfview = pc->B.getView();
1065 auto dtview = pc->dt.getView();
1068 Kokkos::parallel_for(
1069 "evolveSpinTBMT", pc->getLocalNum(), KOKKOS_LAMBDA(
const size_t j) {
1071 Polview(j), Pview(j), Efview(j), Bfview(j), dtview(j), mass, charge,
1109 double emissionDt = std::numeric_limits<double>::max();
1110 bool hasEmissionDt =
false;
1114 for (
const auto& sampler : samplers) {
1115 if (!sampler || sampler->isEmissionDone(currentTime)) {
1118 const double samplerDt = sampler->getEmissionTimeStep();
1119 if (samplerDt > 0.0) {
1120 emissionDt = std::min(emissionDt, samplerDt);
1121 hasEmissionDt =
true;
1126 if (hasEmissionDt) {
1127 selectedDt = emissionDt;
1136 Inform m(
"ParallelTracker::changeDT");
1139 for (
const auto& pc :
itsBunch_m->getParticleContainers()) {
1144 m << level5 <<
"Changed particle container time step to " << newdT <<
"." << endl;
1153 if (sampler && !sampler->isEmissionDone(t)) {
1165 Inform m(
"ParallelTracker::doBinaryRepartition");
1167 <<
"Binary load-balancer repartition is disabled while the ORB path is "
1168 "not wired for the current multi-container bunch state; skipping."
1176 const auto& particleContainers =
itsBunch_m->getParticleContainers();
1177 bool hasNonEmpty =
false;
1178 ippl::Vector<double, 3> rminLoc(0.0), rmaxLoc(0.0);
1180 for (
const auto& pc : particleContainers) {
1181 if (!pc || pc->getTotalNum() == 0) {
1184 pc->computeMinMaxR();
1185 const ippl::Vector<double, 3> mn = pc->getMinR();
1186 const ippl::Vector<double, 3> mx = pc->getMaxR();
1192 for (
int i = 0; i < 3; ++i) {
1193 rminLoc[i] = std::min(rminLoc[i], mn[i]);
1194 rmaxLoc[i] = std::max(rmaxLoc[i], mx[i]);
1200 if (particleContainers.empty() || !particleContainers[0]) {
1202 "ParallelTracker::computeInitialBounds",
1203 "No valid particle container for initial bounds.");
1205 particleContainers[0]->computeMinMaxR();
1206 rminLoc = particleContainers[0]->getMinR();
1207 rmaxLoc = particleContainers[0]->getMaxR();
1212 ippl::Comm->allreduce(rmax, 1, std::greater<ippl::Vector<double, 3>>());
1213 ippl::Comm->allreduce(rmin, 1, std::less<ippl::Vector<double, 3>>());
1214 ippl::Comm->barrier();
1221 const auto& particleContainers =
itsBunch_m->getParticleContainers();
1222 for (
size_t i = 0; i < particleContainers.size(); ++i) {
1223 const auto& pc = particleContainers[i];
1225 m << level3 <<
"ParallelTrack: container " << i <<
" is null." << endl;
1228 if (pc->getTotalNum() > 0) {
1229 m << level3 <<
"ParallelTrack (container " << i
1230 <<
"): momentum z = " << pc->getMeanP()(2) <<
"\n"
1231 <<
"RefPartR (container " << i <<
") = " << pc->getRefPartR() <<
"\n"
1232 <<
"RefPartP (container " << i <<
") = " << pc->getRefPartP() << endl;
1234 m << level3 <<
"ParallelTrack: container " << i
1236 <<
"RefPartR (container " << i <<
") = " << pc->getRefPartR() <<
"\n"
1237 <<
"RefPartP (container " << i <<
") = " << pc->getRefPartP() << endl;
1246 Inform m(
"ParallelTracker::updateReference");
1249 m << level5 <<
"Updated reference particles." << endl;
1259 const size_t n =
itsBunch_m->getNumParticleContainers();
1260 for (
size_t i = 0; i < n; ++i) {
1264 auto pcPtr =
itsBunch_m->getParticleContainer(i);
1269 const PartData& refKick = *pc.getReference();
1272 pc.getRefPartR() /= scaleFactor;
1273 pusher.
push(pc.getRefPartR(), pc.getRefPartP(), dt);
1274 pc.getRefPartR() *= scaleFactor;
1277 IndexMap::value_t::const_iterator it =
elements.begin();
1278 const IndexMap::value_t::const_iterator end =
elements.end();
1280 for (; it != end; ++it) {
1288 if ((*it)->applyToReferenceParticle(
1289 localR, localP,
itsBunch_m->
getT() - 0.5 * dt, localE, localB)) {
1290 *
gmsg << level1 <<
"The reference particle hit an element" << endl;
1298 pusher.
kick(pc.getRefPartR(), pc.getRefPartP(), Ef, Bf, dt, refKick.
getM(), refKick.
getQ());
1300 pc.getRefPartR() /= scaleFactor;
1301 pusher.
push(pc.getRefPartR(), pc.getRefPartP(), dt);
1302 pc.getRefPartR() *= scaleFactor;
1313 const size_t n =
itsBunch_m->getNumParticleContainers();
1314 for (
size_t i = 0; i < n; ++i) {
1318 auto pc =
itsBunch_m->getParticleContainer(i);
1320 pc->updateRefToLabCSTrafo(bunchDT);
1330 auto primary =
itsBunch_m->getParticleContainer(0);
1332 if (zstart_m <= primary->get_sPos()) {
1344 const auto& containers =
itsBunch_m->getParticleContainers();
1352 std::vector<Vector_t<double, 3>> oldRs(containers.size());
1353 for (
size_t i = 0; i < containers.size(); ++i) {
1354 if (containers[i]) {
1355 oldRs[i] = containers[i]->getRefPartR();
1361 for (
size_t i = 0; i < containers.size(); ++i) {
1362 if (!containers[i]) {
1366 containers[i]->set_sPos(containers[i]->get_sPos() +
euclidean_norm(dR));
1373 if (primary->get_sPos() > stepSizesCopy.
getZStop()) {
1378 const double zTarget = stepSizesCopy.
getZStop();
1379 const double tauPrimary = (zTarget - primary->get_sPos()) / speed;
1381 for (
const auto& pc : containers) {
1388 double tau_i = (zTarget - pc->get_sPos()) / speed_i;
1389 pc->applyFractionalStep(pusher, tau_i,
zstart_m);
1401 const double tauPrimary = (zTarget - primary->get_sPos()) / speed;
1403 for (
const auto& pc : containers) {
1410 double tau_i = (zTarget - pc->get_sPos()) / speed_i;
1411 pc->applyFractionalStep(pusher, tau_i,
zstart_m);
1430 if (totalAll == 0 && printStepInfo) {
1431 *
gmsg << level1 <<
"* " << myt2.
time() <<
" "
1432 <<
"Step " << std::setw(6) << globalStep <<
"; "
1433 <<
" -- no emission yet -- "
1437 bool anyLogged =
false;
1438 const auto& containers =
itsBunch_m->getParticleContainers();
1439 for (
size_t ci = 0; ci < containers.size(); ++ci) {
1440 const auto& pc = containers[ci];
1441 if (!pc || pc->getTotalNum() == 0) {
1445 const double sPos = pc->get_sPos();
1446 if (std::isnan(sPos) || std::isinf(sPos)) {
1448 "ParallelTracker::dumpStats()",
1449 "invalid path length s for particle container " + std::to_string(ci));
1451 if (printStepInfo) {
1452 *
gmsg << level1 <<
"* " << myt2.
time() <<
" "
1453 <<
"Step " << std::setw(6) << globalStep <<
" "
1454 <<
"container[" << ci <<
"] "
1462 if (anyLogged || statDump) {
1479 Inform m(
"ParallelTracker::setOptionalVariables");
1487 if (ippl::Comm->size() == 1) {
1488 m << level3 <<
"Binary load-balancer repartition disabled on one rank." << endl;
1494 requestedRepartFreq =
static_cast<long long>(rep->
getReal());
1496 if (requestedRepartFreq > 0) {
1497 m << level2 <<
"REPARTFREQ = " << requestedRepartFreq
1498 <<
" requested, but binary load-balancer repartition is disabled." << endl;
1500 m << level3 <<
"Binary load-balancer repartition disabled." << endl;
1512 ippl::Comm->allreduce(
globalEOL_m, 1, std::logical_and<bool>());
1523 for (
const auto& pc :
itsBunch_m->getParticleContainers()) {
1534 Inform m(
"ParallelTracker::writePhaseSpace");
1539 m << level5 <<
"Bunch bounds in REFERENCE frame: rmin = " << rmin <<
", rmax = " << rmax
1542 const size_t nContainers =
itsBunch_m->getNumParticleContainers();
1543 std::vector<std::array<Vector_t<double, 3>, 2>> fdByContainer(nContainers);
1545 if (psDump || statDump) {
1546 for (
size_t i = 0; i < nContainers; ++i) {
1547 auto pc =
itsBunch_m->getParticleContainer(i);
1548 if (!pc || pc->getTotalNum() == 0) {
1556 pc->getRefPartR(), pc->getRefPartP(),
1558 fdByContainer[i][0] = externalB;
1560 m << level5 <<
"External fields (container " << i <<
"): externalE = " << externalE
1561 <<
", externalB = " << externalB << endl;
1567 *
gmsg << level3 <<
"* Wrote beam statistics." << endl;
1640 *
gmsg << level3 <<
"* Wrote beam phase space." << endl;
1650 Inform m(
"ParallelTracker::updateRFElement");
1653 cavities.insert(cavities.end(), travelingwaves.begin(), travelingwaves.end());
1654 m << level5 <<
"Got cavities and traveling waves." << endl;
1656 for (FieldList::iterator fit = cavities.begin(); fit != cavities.end(); ++fit) {
1657 if ((*fit).getElement()->getName() == elName) {
1663 m << level3 <<
"Restored cavity phase from the h5 file. Name: " << element->
getName()
1664 <<
", phase: " << maxPhase <<
" rad" << endl;
1679 typedef std::vector<MaxPhasesT>::iterator iterator_t;
1684 for (; it < end; ++it) {
1702 for (
auto element : elementSet) {
1709 element,
itsBunch_m->getParticleContainer()->getRefPartR()),
1711 element,
itsBunch_m->getParticleContainer()->getRefPartP()),
1721 element,
itsBunch_m->getParticleContainer()->getRefPartR()),
1723 element,
itsBunch_m->getParticleContainer()->getRefPartP()),
std::list< BeamlineFieldElement > FieldList
ippl::Vector< T, Dim > Vector_t
KOKKOS_INLINE_FUNCTION T prod_vector(const matrix_t< Rows, Cols > &rotation, const T &vect)
Visitor-based parallel tracker with time as the independent variable.
ippl::detail::size_type size_type
Quaternion getQuaternion(ippl::Vector< double, 3 > u, ippl::Vector< double, 3 > ref)
Return a unit quaternion that rotates vec onto reference.
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
KOKKOS_INLINE_FUNCTION double euclidean_norm(const Vector_t< T, D > &v)
An abstract sequence of beam line components.
bool isImageChargeEnabled() const
KOKKOS_INLINE_FUNCTION void kick(const Vector_t< double, 3 > &R, Vector_t< double, 3 > &P, const Vector_t< double, 3 > &Ef, const Vector_t< double, 3 > &Bf, const double &dt, const double &mass, const double &charge) const
KOKKOS_INLINE_FUNCTION void push(Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, const double &dt) const
bool isOutside(const Vector_t< double, 3 > &position) const
double getPhaseAtMaxEnergy(const Vector_t< double, 3 > &R, const Vector_t< double, 3 > &P, double t, double dt)
virtual ElementType getType() const
Get element type std::string.
Rigid spatial transform between a parent frame and a local frame.
ippl::Vector< double, 3 > getOrigin() const
ippl::Vector< double, 3 > rotateFrom(const ippl::Vector< double, 3 > &r) const
Rotate a vector from the local frame back into the parent frame.
matrix3x3_t getRotationMatrix() const
ippl::Vector< double, 3 > rotateTo(const ippl::Vector< double, 3 > &r) const
Rotate a vector from the parent frame into the local frame.
void rotateBunchTo(ViewType Pview, size_t nLocal) const
Apply rotateTo() to a Kokkos view of vectors such as momenta.
void transformBunchTo(ViewType Rview, size_t nLocal) const
Apply transformTo() to a Kokkos view of particle positions.
ippl::Vector< double, 3 > transformTo(const ippl::Vector< double, 3 > &r) const
Map a point from the parent frame to the local frame.
CoordinateSystemTrafo inverted() const
Return the inverse transform.
void dumpH5(PartBunch_t &beam, Vector_t< double, 3 > FDext[]) const
Write H5 phase-space data for all particle containers.
void storeCavityInformation()
Write cavity information from H5 file.
void dumpSDDS(PartBunch_t &beam, const std::vector< std::array< Vector_t< double, 3 >, 2 > > &fdextPerContainer, const double &azimuth) const
Write SDDS statistics with per-container external fields.
static void writeFields(const std::set< std::shared_ptr< Component > > &elements)
virtual const std::string & getName() const
Get element name.
virtual void accept(BeamlineVisitor &visitor) const =0
Apply visitor.
std::set< std::shared_ptr< Component > > value_t
Passive OPALX laser element.
std::string time() const
Return time.
FieldList getElementByType(ElementType)
Vector_t< double, 3 > rotateToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t< double, 3 > &r) const
CoordinateSystemTrafo getMisalignment(const std::shared_ptr< Component > &comp) const
unsigned long getFieldAt(const unsigned int &, const Vector_t< double, 3 > &, const long &, const double &, Vector_t< double, 3 > &, Vector_t< double, 3 > &)
CoordinateSystemTrafo getCSTrafoLab2Local(const std::shared_ptr< Component > &comp) const
Return the nominal rigid placement transform .
Vector_t< double, 3 > transformToLocalCS(const std::shared_ptr< Component > &comp, const Vector_t< double, 3 > &r) const
std::set< std::shared_ptr< Component > > getElements(const Vector_t< double, 3 > &x)
std::vector< MaxPhasesT >::iterator getLastMaxPhases()
double getGlobalPhaseShift()
units: (sec)
std::vector< MaxPhasesT >::iterator getFirstMaxPhases()
Object * find(const std::string &name)
Find entry.
static OpalData * getInstance()
IndexMap::value_t query(IndexMap::key_t::first_type step, IndexMap::key_t::second_type length)
BoundingBox getBoundingBox() const
void activateEmittingContainers(double t)
Force-activate containers whose emitting samplers have not yet finished.
void saveCavityPhases()
Persist cavity phases to the data sink.
void updateRFElement(std::string elName, double maxPhi)
Set stored RF phase on the named cavity or traveling-wave element.
double dtCurrentTrack_m
Global for the current track segment.
void printInitialContainerRefs(Inform &m) const
Log reference state for each container at track start.
void restoreCavityPhases()
Restore cavity phases from a prior track or restart.
void evolveSpinTBMT()
Thomas-BMT spin precession across all active containers that store Pol. Must be called after external...
size_t deleteInvalidParticles(bool activeOnly, Inform &m, const std::string &reason)
Delete particles marked invalid by the central per-container mask.
void prepareSections()
Accept beamline visitor, prepare sections, compute and save 3D lattice.
DataSink * itsDataSink_m
Borrowed beam statistics and phase-space output sink.
void resetFields()
Zero E and B on all active particle containers.
void doBinaryRepartition()
Trigger binary repartition for the field solver if configured.
void updateRefToLabCSTrafo()
Refresh each container's reference-to-lab transform from current state.
void kickParticles(const BorisPusher &pusher, PartBunch_t::ParticleContainer_t &pc)
Boris half-kick using E, B and per-particle dt on one container.
void autophaseCavities(const BorisPusher &pusher)
Autophase TRAVELINGWAVE and RFCAVITY elements along the reference orbit.
IpplTimings::TimerRef OrbThreader_m
void emitFromEmissionSources(double t, double dt)
Emit macroparticles from configured samplers per container.
void setTime()
Reset per-particle dt views to the current global bunch dt.
virtual void execute()
Run the main tracking loop until all step-size segments complete.
std::vector< std::vector< std::shared_ptr< SamplingBase > > > emittingSamplers_m
Per-container emitters.
void setOptionalVariables()
Load REPARTFREQ and related options from input.
unsigned long long repartFreq_m
Space-charge repartition period (steps); 0 disables it.
void updateReferenceParticles(const BorisPusher &pusher)
Advance reference positions/momenta through the beamline for one step.
void writePhaseSpace(const long long step, bool psDump, bool statDump)
Write phase space and/or statistics when flags request it.
ParallelTracker(const Beamline &bl, bool revBeam)
Construct tracker with beamline only (no bunch attached here).
void timeIntegration2(BorisPusher &pusher)
Second half: kick then push all active containers.
size_t applyGlobalProcesses(double dt)
Apply global processes and return the global number of particles marked invalid.
virtual void visitBeamline(const Beamline &)
Visit the full beamline (iterates elements into OpalBeamline). Overrides DefaultVisitor.
virtual void visitLaser(const Laser &)
Reject laser tracking until dedicated laser tracking is implemented.
void selectDT()
Set global bunch dt to dtCurrentTrack_m.
double zstart_m
Path-length start position for the track (m).
void changeDT()
Set bunch dt from StepSizeConfig and copy to all container dt views.
size_t markBackwardParticlesAtSourcePlane()
Mark particles moving backward behind an active source/cathode plane.
void updateReference(const BorisPusher &pusher)
Update reference trajectories and lab/reference coordinate transforms.
IpplTimings::TimerRef timeIntegrationTimer2_m
void computeExternalFields(OrbitThreader &oth)
Apply external fields from elements intersecting each active container.
void computeSpaceChargeFields(unsigned long long step)
Self-fields in beam frame (primary container); optional binary repartition.
bool hasEndOfLineReached(const BoundingBox &globalBoundingBox)
Whether tracking should stop at end-of-line (global reduction).
void findStartPositions(const BorisPusher &pusher)
Integrate references in time until path length reaches zstart_m.
bool globalEOL_m
End-of-line flag (e.g. orbit threader out of bounds).
void dumpStats(long long step, bool psDump, bool statDump)
Log per-container stats and trigger dumps according to dump flags.
virtual void visitComponent(const Component &)
Visit a generic component using the base tracker behavior.
IpplTimings::TimerRef timeIntegrationTimer1_m
void computeInitialBounds(Vector_t< double, 3 > &rmin, Vector_t< double, 3 > &rmax)
Union of per-container spatial bounds over MPI.
IpplTimings::TimerRef fieldEvaluationTimer_m
void pushParticles(const BorisPusher &pusher, PartBunch_t::ParticleContainer_t &pc)
Boris position push (unitless positions) on one container.
void timeIntegration1(BorisPusher &pusher)
First half of the leapfrog step: push all active containers.
StepSizeConfig stepSizes_m
virtual ~ParallelTracker()
Destructor; releases tracker resources.
OpalBeamline itsOpalBeamline_m
Cloned field elements and coordinate transforms.
Vector_t< double, Dim > R(size_t)
Do not use; throws (access positions via ParticleContainer::R).
void setdT(double dt)
Set the global time step.
void performBunchSanityChecks() const
Validate BC handler, solver wiring, field pointers, and layout extents.
void computeSelfFields()
Compute the bunch self-fields (binned when available).
void incTrackSteps()
Increment globalTrackStep_m by one.
double getdT() const
Get the global time step.
void setT(double t)
Set the current simulation time.
bool pcAtZStop(size_t i) const
void calcBeamParameters()
Update moments and set rmin_m / rmax_m from the primary (first) container.
bool hasFieldSolver() const
double getT() const
Get the current simulation time.
void incrementT()
Advance time by one global time step.
void setPcAtZStop(size_t i)
Deactivate container i until the next step-size segment (z-stop reached).
const PartData * getReference() const
void bunchUpdate()
Refresh mesh from particle extents, update layouts, and recompute moments.
size_t getTotalNumAllContainers() const
Sum of getTotalNum() over all particle containers.
void refreshPcActiveAfterEmit()
After emission: reactivate non-empty containers not marked at z-stop.
long long getGlobalTrackStep() const
Current global tracking step.
BinnedFieldSolver_t * getFieldSolver()
Non-const pointer to the concrete BinnedFieldSolver.
bool isPcActive(size_t i) const
void get_bounds(Vector_t< double, Dim > &rmin, Vector_t< double, Dim > &rmax)
Copy cached bunch extent (rmin_m, rmax_m) from calcBeamParameters.
void resetPcActive()
At segment start: active if container is non-empty; inactive if empty.
void setPcActive(size_t i)
Force container i active (e.g. for containers with pending emission).
double getAnomaly() const
double getP() const
The constant reference momentum per particle.
KOKKOS_INLINE_FUNCTION double getM() const
The constant mass per particle.
KOKKOS_INLINE_FUNCTION double getQ() const
The constant charge per particle.
Container for all per-particle (and per-simulation) fields tracked during OPALX tracking.
ippl::ParticleAttrib< double > dt
timestep in [s]
Base::particle_position_type B
electric field for gun simulation with bins
void switchOffUnitlessPositions()
Restore physical positions from unitless form using each particle's dt[i].
const PartData * getReference() const
Get reference particle data.
Base::particle_position_type E
electric field at particle position
Base::particle_position_type P
particle momenta [\beta\gamma]
void switchToUnitlessPositions()
Transform positions to unitless coordinates using each particle's dt[i].
Quaternion storage and rotation algebra used by OPALX geometry code.
Quaternion conjugate() const
Return the quaternion conjugate .
Interface for standing wave cavities.
virtual bool getAutophaseVeto() const
virtual void setPhasem(double phase)
virtual void setAutophaseVeto(bool veto=true)
virtual double getReal() const
Return value.
KOKKOS_INLINE_FUNCTION void evolve(SpinVec &Pol, const Vector_t< double, 3 > &P, const Vector_t< double, 3 > &Ef, const Vector_t< double, 3 > &Bf, const double &dt, const double &mass, const double &charge, const double &anom) const
double getMinTimeStep() const
StepSizeConfig & advanceToPos(double spos)
void printDirect(Inform &out) const
void push_back(double dt, double zstop, unsigned long numSteps)
unsigned long getNumSteps() const
unsigned long long getMaxSteps() const
void sortAscendingZStop()
virtual void iterate(BeamlineVisitor &, bool r2l) const
Apply visitor to all elements of the line.
const Beamline & itsBeamline_m
virtual void visitComponent(const Component &)
Store the bunch.
PartBunch_t * itsBunch_m
The bunch of particles to be tracked. Borrowed; lifetime is managed by TrackRun.
Interface for traveling wave cavities.
int stepInfoFreq
The frequency to print per-step tracking status lines; 0 disables them.
int psDumpFreq
The frequency to dump the phase space, i.e.dump data when steppsDumpFreq==0.
int repartFreq
The frequency to do particles repartition for better load balance between nodes.
double boundpDestroy
Governs how many sigmas away particles are deleted.
int statDumpFreq
The frequency to dump statistical values, e.e. dump data when stepstatDumpFreq==0.
constexpr double c
The velocity of light in m/s.
constexpr double Vpm2MVpm
double getGamma(ippl::Vector< double, 3 > p)
std::string getEnergyString(double energyInMeV, unsigned int precision=3)
std::string getTimeString(double time, unsigned int precision=3)
std::string getLengthString(double spos, unsigned int precision=3)