10#include "Particle/ParticleAttrib.h"
21template <
typename T,
unsigned Dim>
23 std::vector<double> qi, std::vector<double> mi,
const std::vector<Beam*>& beams,
24 std::vector<size_t> totalParticlesPerBeam,
double lbt, std::string integration_method,
30 integration_method_m(integration_method),
33 isFirstRepartition_m(true),
34 OPALFieldSolver_m(OPALFieldSolver),
42 Inform m(
"PartBunch::PartBunch");
43 m << level4 <<
"PartBunch Constructor" << endl;
45 const size_t num_containers = beams.size();
46 if (num_containers == 0) {
47 throw OpalException(
"PartBunch::PartBunch",
"num_containers must be > 0.");
50 throw OpalException(
"PartBunch::PartBunch",
"OPALFieldSolver must not be null.");
53 throw OpalException(
"PartBunch::PartBunch",
"dataSink must not be null.");
55 if (qi.size() != num_containers) {
56 throw OpalException(
"PartBunch::PartBunch",
"qi size must match num_containers.");
58 if (mi.size() != num_containers) {
59 throw OpalException(
"PartBunch::PartBunch",
"mi size must match num_containers.");
61 if (totalParticlesPerBeam.size() != num_containers) {
63 "PartBunch::PartBunch",
"totalParticlesPerBeam size must match num_containers.");
65 for (
size_t i = 0; i < num_containers; ++i) {
66 if (beams[i] ==
nullptr) {
67 throw OpalException(
"PartBunch::PartBunch",
"beams must not contain null pointers.");
79 for (
unsigned i = 0; i <
Dim; i++) {
81 this->
decomp_m[i] = domainDecomposition[i];
88 m << level5 <<
"* FieldContainer set to isAllPeriodic = " << isAllPeriodic << endl;
102 this->setFieldContainer(
103 std::make_shared<FieldContainer_t>(
106 this->setParticleContainer(
107 std::make_shared<ParticleContainer_t>(
108 this->fcontainer_m->getMesh(), this->fcontainer_m->getFL(),
109 beams[0]->hasPolarization()));
113 for (
size_t i = 1; i < num_containers; ++i) {
114 auto pc = std::make_shared<ParticleContainer_t>(
115 this->fcontainer_m->getMesh(), this->fcontainer_m->getFL(),
116 beams[i]->hasPolarization());
118 this->addParticleContainer(pc);
120 const auto& containers = this->getParticleContainers();
122 for (
size_t i = 0; i < containers.size(); ++i) {
123 containers[i]->setQ(qi[i]);
124 containers[i]->setM(mi[i]);
127 containers[i]->Sp =
static_cast<short>(
133 const double nRanks =
static_cast<double>(ippl::Comm->size());
134 for (
size_t i = 0; i < num_containers; ++i) {
135 const size_t maxLocalNum =
136 static_cast<size_t>(totalParticlesPerBeam[i] / nRanks + 2 * nRanks + 1);
137 containers[i]->allocateParticles(maxLocalNum);
138 *
gmsg << level3 <<
"* Container " << i <<
": capacity for " << maxLocalNum
139 <<
" particles allocated." << endl;
147 this->
getTempEField()->initialize(this->fcontainer_m->getMesh(), this->fcontainer_m->getFL());
149 this->
getTempBField()->initialize(this->fcontainer_m->getMesh(), this->fcontainer_m->getFL());
159 m << level5 <<
"* PartBunch constructor done." << endl;
165template <
typename T,
unsigned Dim>
167 const auto& containers = this->getParticleContainers();
168 const size_t n = containers.size();
169 pcActive_m.resize(n);
170 pcAtZStop_m.resize(n);
171 for (
size_t i = 0; i < n; ++i) {
172 pcAtZStop_m[i] =
false;
173 const auto& pc = containers[i];
174 if (!pc || pc->getTotalNum() == 0) {
175 pcActive_m[i] =
false;
177 pcActive_m[i] =
true;
185template <
typename T,
unsigned Dim>
187 if (i >= pcActive_m.size()) {
190 pcActive_m[i] =
false;
191 pcAtZStop_m[i] =
true;
197template <
typename T,
unsigned Dim>
199 const auto& containers = this->getParticleContainers();
200 const size_t n = containers.size();
201 if (pcActive_m.size() != n) {
204 for (
size_t i = 0; i < n; ++i) {
205 if (pcAtZStop_m[i]) {
208 const auto& pc = containers[i];
209 if (pc && pc->getTotalNum() > 0) {
210 pcActive_m[i] =
true;
218template <
typename T,
unsigned Dim>
220 Inform m(
"PartBunch::do_binaryRepart");
222 <<
"Binary load-balancer repartition is disabled while the ORB path is "
223 "not wired for the current multi-container bunch state; skipping."
230template <
typename T,
unsigned Dim>
232 std::fill_n(globalPartPerNode_m.get(), ippl::Comm->size(), 0);
233 globalPartPerNode_m[ippl::Comm->rank()] = this->getParticleContainer()->getLocalNum();
234 ippl::Comm->allreduce(globalPartPerNode_m.get(), ippl::Comm->size(), std::plus<size_t>());
240template <
typename T,
unsigned Dim>
242 Inform m(
"PartBunch::setSolver");
243 m << level2 <<
"Initializing solver: " << OPALFieldSolver_m->getType() << endl;
244 if (this->solver_m !=
"")
245 m << level1 <<
"Warning solver already initiated but overwrite ..." << endl;
247 this->solver_m = OPALFieldSolver_m->getType();
249 this->fcontainer_m->initializeFields(this->solver_m);
254 BinningCmd* binningCmd = OPALFieldSolver_m->getBinningCmd();
255 auto binnedSolver = std::make_shared<BinnedFieldSolver<T, Dim>>(
256 this->solver_m, &this->fcontainer_m->getRho(), &this->fcontainer_m->getE(),
257 &this->fcontainer_m->getPhi(), this->getBCHandler(),
260 this->setFieldSolver(binnedSolver);
261 m << level4 <<
"Binned field solver set (binned or legacy at runtime)." << endl;
263 this->fsolver_m->initSolver();
264 m << level4 <<
"Field solver initialized." << endl;
267 this->setLoadBalancer(
268 std::make_shared<LoadBalancer_t>(
269 this->lbt_m, this->fcontainer_m, this->pcontainer_m, this->fsolver_m));
270 m << level3 <<
"Solver and Load Balancer set." << endl;
276template <
typename T,
unsigned Dim>
281template <
typename T,
unsigned Dim>
286template <
typename T,
unsigned Dim>
288 return this->getFieldSolver()->getStype();
291template <
typename T,
unsigned Dim>
293 Inform m(
"PartBunch::setBins");
295 BinningCmd* binningCmd = OPALFieldSolver_m->getBinningCmd();
297 if (!OPALFieldSolver_m->hasBinningCmd()) {
298 m << level2 <<
"Solver " << OPALFieldSolver_m->
getOpalName()
299 <<
" has no binning command attached, not using binning." << endl;
303 m << level4 <<
"Using binning command: " << binningCmd->
getOpalName() << endl;
326 "PartBunch::setBins",
328 +
" not supported yet! Only VELOCITYZ and GAMMAZ.");
330 m << level3 <<
"Bins set." << endl;
331 this->getBins()->debug();
337template <
typename T,
unsigned Dim>
339 Inform m(
"PartBunch::calcBeamParameters");
340 std::shared_ptr<ParticleContainer_t> pc = this->pcontainer_m;
345 this->getParticleContainer()->updateMoments();
346 m << level5 <<
"Moments updated." << endl;
352 using MomentsVec = ippl::Vector<double, 2 * Dim>;
353 using MomentsMat = ippl::Vector<MomentsVec, 2 * Dim>;
355 MomentsVec loc_centroid(0.0);
356 MomentsMat loc_moment(MomentsVec(0.0));
358 MomentsVec centroid(0.0);
359 MomentsMat moment(MomentsVec(0.0));
361 for (
unsigned i = 0; i < 2 *
Dim; ++i) {
362 const size_t nLocal = pc->getLocalNum();
363 Kokkos::parallel_reduce(
364 "calc moments of particle distr.", nLocal,
366 const size_t k,
double& cent,
double& mom0,
double& mom1,
double& mom2,
367 double& mom3,
double& mom4,
double& mom5) {
368 double part[2 *
Dim];
369 part[0] = Rview(k)[0];
370 part[1] = Pview(k)[0];
371 part[2] = Rview(k)[1];
372 part[3] = Pview(k)[1];
373 part[4] = Rview(k)[2];
374 part[5] = Pview(k)[2];
377 mom0 += part[i] * part[0];
378 mom1 += part[i] * part[1];
379 mom2 += part[i] * part[2];
380 mom3 += part[i] * part[3];
381 mom4 += part[i] * part[4];
382 mom5 += part[i] * part[5];
384 Kokkos::Sum<T>(loc_centroid[i]), Kokkos::Sum<T>(loc_moment[i][0]),
385 Kokkos::Sum<T>(loc_moment[i][1]), Kokkos::Sum<T>(loc_moment[i][2]),
386 Kokkos::Sum<T>(loc_moment[i][3]), Kokkos::Sum<T>(loc_moment[i][4]),
387 Kokkos::Sum<T>(loc_moment[i][5]));
390 m << level5 <<
"Local moments calculated." << endl;
393 centroid = loc_centroid;
394 ippl::Comm->allreduce(moment, 1, std::plus<MomentsMat>());
395 ippl::Comm->allreduce(centroid, 1, std::plus<MomentsVec>());
396 ippl::Comm->barrier();
397 m << level5 <<
"Global moments calculated." << endl;
399 ippl::Vector<double, Dim> rmax_loc(0.0);
400 ippl::Vector<double, Dim> rmin_loc(0.0);
401 ippl::Vector<double, Dim> rmax(0.0);
402 ippl::Vector<double, Dim> rmin(0.0);
405 for (
unsigned d = 0; d <
Dim; ++d) {
406 Kokkos::parallel_reduce(
407 "rel max", pc->getLocalNum(),
408 KOKKOS_LAMBDA(
const int i,
double& mm) {
409 double tmp_vel = Rview(i)[d];
410 mm = tmp_vel > mm ? tmp_vel : mm;
412 Kokkos::Max<T>(rmax_loc[d]));
414 Kokkos::parallel_reduce(
415 "rel min", pc->getLocalNum(),
416 KOKKOS_LAMBDA(
const int i,
double& mm) {
417 double tmp_vel = Rview(i)[d];
418 mm = tmp_vel < mm ? tmp_vel : mm;
420 Kokkos::Min<T>(rmin_loc[d]));
422 m << level5 <<
"Local min/max calculated." << endl;
426 ippl::Comm->allreduce(rmax, 1, std::greater<ippl::Vector<double, Dim>>());
427 ippl::Comm->allreduce(rmin, 1, std::less<ippl::Vector<double, Dim>>());
428 ippl::Comm->barrier();
429 m << level5 <<
"Global min/max calculated." << endl;
438template <
typename T,
unsigned Dim>
440 Inform m(
"PartBunch::pre_run");
441 m << level2 <<
"Starting pre_run..." << endl;
442 auto rhoView = this->fcontainer_m->getRho().getView();
443 Kokkos::deep_copy(rhoView, 0.0);
444 m << level4 <<
"Rho initialized to zero." << endl;
450 this->getFieldSolver()->runSolver(
true);
451 m << level4 <<
"Field solver ran during pre_run." << endl;
452 this->getFieldSolver()->resetCallCounter();
453 m << level4 <<
"Call counter reset. pre_run done." << endl;
459template <
typename T,
unsigned Dim>
462 Inform::FmtFlags_t ff = os.flags();
464 const auto& containers = this->getParticleContainers();
465 for (
size_t ci = 0; ci < containers.size(); ++ci) {
466 const auto& pc = containers[ci];
468 os << level1 <<
"Skipping null particle container: " << ci << endl;
472 const double ek = pc->getMeanKineticEnergy();
473 const double dek = pc->getStdKineticEnergy();
476 std::string qmStorageModeStr =
"SINGLE";
477 const auto qmMode = pc->getQMStorageMode();
479 qmStorageModeStr =
"ATTRIBUTES";
482 os << level1 << std::scientific <<
"\n"
483 <<
"* ************** B U N C H "
484 "********************************************************* \n"
485 <<
"* CONTAINER = " << ci <<
"\n"
486 <<
"* PARTICLES = " << pc->getTotalNum() <<
"\n"
487 <<
"* CHARGE = " << pc->getTotalCharge() <<
" (Cb) \n"
488 <<
"* QM STORAGE MODE = " << qmStorageModeStr <<
"\n"
491 <<
"* INTEGRATOR = " << integration_method_m <<
"\n"
495 <<
"* RMS P = " << pc->getRmsP() <<
" [beta gamma]\n"
496 <<
"* Mean R = " << pc->getMeanR() <<
" [m]\n"
497 <<
"* Mean P = " << pc->getMeanP() <<
" [beta gamma]\n"
498 <<
"* MESH SPACING = "
500 <<
"* COMPDOM INCR = " << this->OPALFieldSolver_m->getBoxIncr() <<
" (%) \n"
501 <<
"* FIELD LAYOUT = " << this->fcontainer_m->getFL() <<
"\n"
502 <<
"* Centroid : \n* ";
503 for (
unsigned int i = 0; i < 2 *
Dim; i++) {
504 os << level1 << pc->getCentroid()[i] <<
" ";
506 os << level1 << endl <<
"* Cov Matrix : \n* ";
507 for (
unsigned int i = 0; i < 2 *
Dim; i++) {
508 for (
unsigned int j = 0; j < 2 *
Dim; j++) {
509 os << level1 << pc->getCovMatrix()(i, j) <<
" ";
511 os << level1 <<
"\n* ";
515 "********************************************************************************"
527template <
typename T,
unsigned Dim>
529 if (nr_m[
Dim - 1] == nrZ) {
533 Inform m(
"PartBunch::reinitializeGridZ");
534 m << level3 <<
"Resizing z grid: " << nr_m[
Dim - 1] <<
" -> " << nrZ <<
" cells." << endl;
537 domain_m[
Dim - 1] = ippl::Index(nrZ);
539 const bool isAllPeriodic = this->getBCHandler()->isAll(BCHandler_t::PERIODIC);
540 const auto decomp = this->fcontainer_m->getDecomp();
543 this->fcontainer_m->getFL().initialize(domain_m, decomp, isAllPeriodic);
547 auto& fl = this->fcontainer_m->getFL();
548 this->fcontainer_m->getRho().updateLayout(fl);
549 this->fcontainer_m->getE().updateLayout(fl);
550 if (solver_m ==
"CG") {
551 this->fcontainer_m->getPhi().updateLayout(fl);
553 this->getTempEField()->updateLayout(fl);
554 this->getTempBField()->updateLayout(fl);
556 m << level3 <<
"Grid z reinit complete (nrZ=" << nrZ <<
")." << endl;
559template <
typename T,
unsigned Dim>
561 Inform m(
"PartBunch::bunchUpdate");
562 m << level4 <<
"Updating bunch and doing repartitioning if needed." << endl;
568 const bool imageActive =
570 reinitializeGridZ(imageActive ? nrZBase_m * 2 : nrZBase_m);
574 computeBoundsForFieldSolve(lower, upper);
575 applyGridUpdate(lower, upper);
577 isFirstRepartition_m =
true;
578 m << level5 <<
"Bunch grid update done without load-balancer repartitioning." << endl;
582 const auto& containers = this->getParticleContainers();
583 for (
size_t i = 0; i < containers.size(); ++i) {
584 if (!containers[i]) {
587 this->getParticleContainer(i)->updateMoments();
589 m << level5 <<
"Moments updated for all particle containers." << endl;
592template <
typename T,
unsigned Dim>
595 Inform m(
"PartBunch::computeBoundsForFieldSolve");
597 const auto& containers = this->getParticleContainers();
599 bool hasNonEmptyContainer =
false;
600 for (
const auto& pc : containers) {
601 if (!pc || pc->getTotalNum() == 0) {
605 pc->computeMinMaxR();
606 const ippl::Vector<double, 3> minR = pc->getMinR();
607 const ippl::Vector<double, 3> maxR = pc->getMaxR();
609 if (!hasNonEmptyContainer) {
612 hasNonEmptyContainer =
true;
614 for (
int i = 0; i < 3; ++i) {
615 lower[i] = std::min(lower[i], minR[i]);
616 upper[i] = std::max(upper[i], maxR[i]);
621 if (!hasNonEmptyContainer) {
622 if (containers.empty() || !containers[0]) {
624 "PartBunch::bunchUpdate",
625 "No valid particle container available for bunch update.");
627 containers[0]->computeMinMaxR();
628 lower = containers[0]->getMinR();
629 upper = containers[0]->getMaxR();
638 const double mirroredMinZ = 2.0 * planeZ - upper[2];
639 const double mirroredMaxZ = 2.0 * planeZ - lower[2];
640 lower[2] = std::min(lower[2], mirroredMinZ);
641 upper[2] = std::max(upper[2], mirroredMaxZ);
642 m << level4 <<
"Image-charge bounds enabled at zPlane=" << planeZ << endl;
646 for (
unsigned i = 0; i <
Dim; ++i) {
647 if (span[i] < 1e-6) {
649 m << level3 <<
"Mesh spacing in dimension " << i <<
" too small. Set to 1e-6." << endl;
653 lower = lower - span * this->OPALFieldSolver_m->getBoxIncr() / 100.0;
654 upper = upper + span * this->OPALFieldSolver_m->getBoxIncr() / 100.0;
657template <
typename T,
unsigned Dim>
660 Inform m(
"PartBunch::applyGridUpdate");
661 auto* mesh = &this->fcontainer_m->getMesh();
662 auto* FL = &this->fcontainer_m->getFL();
663 std::shared_ptr<ParticleContainer_t> pc = this->getParticleContainer();
666 hr_m = span / this->nr_m;
668 mesh->setMeshSpacing(hr_m);
669 mesh->setOrigin(lower);
671 this->getFieldContainer()->setRMin(lower);
672 this->getFieldContainer()->setRMax(upper);
673 this->getFieldContainer()->setHr(hr_m);
675 m << level3 <<
"Field Container updated with new mesh boundaries and spacing:" << endl;
676 m << level3 <<
"\t\t> Mesh origin: " << mesh->getOrigin() << endl;
677 m << level3 <<
"\t\t> Mesh spacing: " << hr_m << endl;
678 m << level3 <<
"\t\t> Box increment: " << this->OPALFieldSolver_m->getBoxIncr() <<
"%" << endl;
680 const auto& containers = this->getParticleContainers();
681 for (
size_t i = 0; i < containers.size(); ++i) {
682 const auto& pc = containers[i];
686 pc->getLayout().updateLayout(*FL, *mesh);
688 pc->markMomentsDirty();
691 m << level5 <<
"Particle container " << i <<
" updated with new layout." << endl;
695template <
typename T,
unsigned Dim>
697 this->getFieldSolver()->setImageChargeConfiguration(enabled, zPlane);
700template <
typename T,
unsigned Dim>
702 this->getFieldSolver()->setShiftedGreensConfiguration(enabled, zPlane);
705template <
typename T,
unsigned Dim>
707 this->getFieldSolver()->setZeroFacePlaneDumpFrequency(frequency);
710template <
typename T,
unsigned Dim>
712 this->getFieldSolver()->setZerofaceMaxSteps(maxSteps);
718template <
typename T,
unsigned Dim>
728template <
typename T,
unsigned Dim>
730 if (!hasBinning() || !dataSink_m) {
732 "PartBunch::dumpBinConfig",
733 "No binning or data sink set, but dumpBinConfig() was called.");
736 Inform m(
"PartBunch::dumpBinConfig");
738 BinningCmd* binningCmd = OPALFieldSolver_m->getBinningCmd();
749 const long long step = getGlobalTrackStep();
751 if (dumpFreq <= 0 || (step % dumpFreq) != 0) {
755 std::shared_ptr<AdaptBins_t> bins = getBins();
760 std::vector<typename AdaptBins_t::size_type> countsHost;
761 std::vector<typename AdaptBins_t::value_type> widthsHost;
762 const auto xMin = bins->getBinConfigHost(countsHost, widthsHost);
764 std::vector<std::size_t> counts(countsHost.begin(), countsHost.end());
765 std::vector<double> widths(widthsHost.begin(), widthsHost.end());
767 m << level5 <<
"Dumping bin configuration (preMerge=" << (preMerge ? 1 : 0)
768 <<
") at globalTrackStep=" << step <<
" with nBins=" << counts.size() <<
" to file \""
771 dataSink_m->dumpBinConfig(
772 step, getT(), preMerge, counts, widths,
static_cast<double>(xMin),
779template <
typename T,
unsigned Dim>
781 Inform ms(
"PartBunch::performBunchSanityChecks");
782 ms << level4 <<
"========== Performing sanity checks on PartBunch... ==========" << endl;
786 if (!this->getBCHandler()) {
788 "PartBunch::performBunchSanityChecks",
"BC Handler not initialized properly.");
790 ms << level4 <<
"BC Handler initialized properly." << endl;
792 if (!this->getBunchStateHandler()) {
794 "PartBunch::performBunchSanityChecks",
"BunchStateHandler not initialized.");
796 ms << level4 <<
"BunchStateHandler initialized." << endl;
798 if (!hasFieldSolver()) {
800 "PartBunch::performBunchSanityChecks",
"Field Solver was not initialized.");
802 ms << level4 <<
"Field Solver object was initialized." << endl;
805 auto fs = std::dynamic_pointer_cast<BinnedFieldSolver_t>(this->fsolver_m);
808 "PartBunch::performBunchSanityChecks",
"FieldSolver is not set in PartBunch.");
812 const std::shared_ptr<FieldContainer<T, Dim>> fctr = this->fcontainer_m;
815 "PartBunch::performBunchSanityChecks",
816 "FieldContainer isn't initialized correctly.");
820 if (fs->getRho() ==
nullptr || fs->getE() ==
nullptr || fs->getPhi() ==
nullptr) {
822 "PartBunch::performBunchSanityChecks",
823 "FieldSolver internal fields (rho/E/phi) not assigned.");
825 ms << level4 <<
"FieldSolver internal field pointers are set." << endl;
828 if (fs->getRho() != &fctr->getRho() || fs->getE() != &fctr->getE()
829 || fs->getPhi() != &fctr->getPhi()) {
831 "PartBunch::performBunchSanityChecks",
832 "FieldSolver fields do not match FieldContainer.");
834 ms << level4 <<
"FieldSolver fields match FieldContainer." << endl;
851 const std::string stype = fs->getStype();
854 "PartBunch::performBunchSanityChecks",
"FieldSolver type string is empty.");
856 if (stype !=
"FFT" && stype !=
"OPEN" && stype !=
"CG" && stype !=
"NONE") {
858 "PartBunch::performBunchSanityChecks",
"Unsupported FieldSolver type: " + stype);
860 ms << level4 <<
"FieldSolver type: " << stype << endl;
863 auto Eview = fctr->getE().getView();
864 if (stype !=
"NONE" && (Eview.extent(0) == 0 || Eview.extent(1) == 0 || Eview.extent(2) == 0)) {
866 "PartBunch::performBunchSanityChecks",
867 "E-field layout not initialized (zero extent). ");
869 ms << level4 <<
"E-field layout initialized." << endl;
872 if (!this->Etmp_m || !this->Btmp_m) {
874 "PartBunch::performBunchSanityChecks",
875 "Temporary E field (Etmp) and/or B field (Btmp) not initialized.");
877 auto EtmpView = this->Etmp_m->getView();
878 auto BtmpView = this->Btmp_m->getView();
879 if (EtmpView.extent(0) == 0 || EtmpView.extent(1) == 0 || EtmpView.extent(2) == 0) {
881 "PartBunch::performBunchSanityChecks",
882 "Etmp field layout not initialized (zero extent). ");
884 if (BtmpView.extent(0) == 0 || BtmpView.extent(1) == 0 || BtmpView.extent(2) == 0) {
886 "PartBunch::performBunchSanityChecks",
887 "Btmp field layout not initialized (zero extent). ");
889 if (&this->Etmp_m->get_mesh() != &fctr->getMesh()
890 || &this->Btmp_m->get_mesh() != &fctr->getMesh()) {
892 "PartBunch::performBunchSanityChecks",
893 "Etmp/Btmp fields do not use the FieldContainer mesh.");
895 ms << level4 <<
"Etmp and Btmp fields initialized on the FieldContainer mesh." << endl;
897 if (!this->pcontainer_m) {
899 "PartBunch::performBunchSanityChecks",
900 "Primary ParticleContainer not initialized.");
902 ms << level4 <<
"Primary ParticleContainer present." << endl;
904 ms << level2 <<
"========= Done performing PartBunch sanity checks... =========" << endl;
ippl::Vector< T, Dim > Vector_t
typename ippl::detail::ViewType< ippl::Vector< double, Dim >, 1 >::view_type view_type
ippl::Field< ippl::Vector< T, Dim >, Dim, ViewArgs... > VField_t
Template PIC bunch: IPPL PicManager, shared field mesh/solver, and multiple particle containers.
typename ippl::detail::ViewType< ippl::Vector< double, 3 >, 1 >::view_type view_type
Field solver wrapper that implements the full binned self-field algorithm.
double getImageChargePlaneZ() const
bool isImageChargeActiveForStep(size_t step) const
Check whether the explicit image-charge pass should run for a given timestep.
void computeSelfFields(PartBunch_t &bunch)
Compute space-charge self-fields for the given particle bunch.
double getDesiredWidth() const
int getDumpBinsFrequency() const
Get the frequency of dumping bins to a file.
double getBinningAlpha() const
int getTablePrintFrequency() const
bool getAdaptiveBinning() const
BinningParameter getParameterType() const
bool dumpBinsToFile() const
Check if dumping bins to a file is enabled.
std::string getParameter()
std::string getDumpBinsFileName() const
Get the file name for dumping bins to a file.
double getBinningBeta() const
BCHandler< 3 > constructBCHandler() const
Returns solver boundary conditions handler object.
double getNX() const
Return meshsize.
double getNY() const
Return meshsize.
double getNZ() const
Return meshsize.
ippl::Vector< bool, 3 > getDomDec() const
const std::string & getOpalName() const
Return object name.
void computeBoundsForFieldSolve(Vector_t< double, Dim > &lower, Vector_t< double, Dim > &upper)
Computes the spatial bounds for the field solver based on the current particle distribution.
Vector_t< double, Dim > rmax_m
Current bunch spatial maximum (from primary container stats).
typename ParticleBinning::CoordinateSelector< ParticleContainer_t > CoordinateSelector_t
void gatherLoadBalanceStatistics()
void performBunchSanityChecks() const
Validate BC handler, solver wiring, field pointers, and layout extents.
std::string getParticleName(size_t i) const
Particle species name for container i (from BEAM PARTICLE input).
std::shared_ptr< VField_t< T, Dim > > getTempEField()
Scratch E field used by the binned solver path.
void computeSelfFields()
Compute the bunch self-fields (binned when available).
std::vector< std::string > particleNames_m
Per-container beam particle names.
void pre_run() override
Warm-up: zero rho and run the field solver once (skip full dumps).
void setT(double t)
Set the current simulation time.
Vector_t< int, Dim > nr_m
Mesh cell count per dimension.
DataSink * dataSink_m
Borrowed diagnostics and dump output sink.
std::array< bool, Dim > decomp_m
Domain decomposition flags (per axis).
Vector_t< double, Dim > rmin_m
void dumpBinConfig(bool preMerge)
Write bin edges/counts to the data sink when configured.
FieldSolverCmd * OPALFieldSolver_m
Borrowed parsed FIELD_SOLVER command.
void reinitializeGridZ(int nrZ)
Reinitialize the z dimension of the field grid to nrZ cells.
Vector_t< double, Dim > origin_m
Mesh origin (lab coordinates).
void calcBeamParameters()
Update moments and set rmin_m / rmax_m from the primary (first) container.
int nrZBase_m
Base z grid count before any image-charge doubling; used to reset nr_m.
void do_binaryRepart()
ORB/binary repartition when the load balancer requests it (primary container).
Vector_t< double, Dim > hr_m
Mesh spacing (m).
typename ParticleBinning::GammaSelector< ParticleContainer_t > GammaSelector_t
void setBCHandler(std::shared_ptr< BCHandler_t > bcHandler)
void setSolver()
Build field solver and load balancer from OPALFieldSolver_m.
double dt_m
Global time step (s).
void setPcAtZStop(size_t i)
Deactivate container i until the next step-size segment (z-stop reached).
ippl::NDIndex< Dim > domain_m
Global mesh index extent per dimension.
void setImageChargeConfiguration(bool enabled, double zPlane)
Set the image-charge configuration for the field solver.
std::shared_ptr< BunchStateHandler > bunchState_m
Bunch state: unitless flag, repartition flag, etc.
void setTempEField(std::shared_ptr< VField_t< T, Dim > > Etmp)
std::shared_ptr< VField_t< T, Dim > > getTempBField()
Scratch B field used by the binned solver path.
void setTempBField(std::shared_ptr< VField_t< T, Dim > > Btmp)
void setShiftedGreensConfiguration(bool enabled, double zPlane)
Set the shifted Green's function Dirichlet-correction configuration.
PartBunch(std::vector< double > qi, std::vector< double > mi, const std::vector< Beam * > &beams, std::vector< size_t > totalParticlesPerBeam, double lbt, std::string integration_method, FieldSolverCmd *OPALFieldSolver, DataSink *dataSink)
Construct a multi-beam bunch: mesh, solver, containers, and capacity.
const PartData * getReference() const
void setZerofaceMaxSteps(int maxSteps)
Set the maximum number of timesteps for which image charges are active (0 = unlimited).
void bunchUpdate()
Refresh mesh from particle extents, update layouts, and recompute moments.
std::string getFieldSolverType()
Backend type string (e.g. FFT, OPEN, CG, NONE).
void refreshPcActiveAfterEmit()
After emission: reactivate non-empty containers not marked at z-stop.
std::shared_ptr< BCHandler_t > getBCHandler() const
Current boundary-condition handler.
Inform & print(Inform &os)
Human-readable dump of each container to os.
BinnedFieldSolver_t * getFieldSolver()
Non-const pointer to the concrete BinnedFieldSolver.
void applyGridUpdate(const Vector_t< double, Dim > &lower, const Vector_t< double, Dim > &upper)
Updates the mesh/grid and internal data structures to match the given spatial bounds.
void setBins()
Create adaptive bins from the binning command (VELOCITYZ / GAMMAZ).
std::vector< double > qi_m
Charge per macroparticle [C], one entry per container.
void setZeroFacePlaneDumpFrequency(int frequency)
Configure diagnostic dump frequency for the ZEROFACE plane potential.
void resetPcActive()
At segment start: active if container is non-empty; inactive if empty.
std::unique_ptr< size_t[]> globalPartPerNode_m
Per-rank particle counts for load-balance stats.
std::vector< double > mi_m
Mass per macroparticle [GeV], one entry per container.
A class that bins particles in energy bins and allows for adaptive runtime rebinning.
Container for all per-particle (and per-simulation) fields tracked during OPALX tracking.
static ParticleType getParticleType(const std::string &str)
std::string getEnergyString(double energyInMeV, unsigned int precision=3)
std::string getLengthString(double spos, unsigned int precision=3)