Skip to content

Add the option for particle RF phase-wrapping#1380

Open
cemitch99 wants to merge 151 commits intoBLAST-ImpactX:developmentfrom
cemitch99:add_phase_wrapping
Open

Add the option for particle RF phase-wrapping#1380
cemitch99 wants to merge 151 commits intoBLAST-ImpactX:developmentfrom
cemitch99:add_phase_wrapping

Conversation

@cemitch99
Copy link
Copy Markdown
Member

@cemitch99 cemitch99 commented Apr 2, 2026

This PR adds the capability of applying particle boundary conditions, related to the RF bucket (for example, wrapping particles modulo 2pi in RF phase).

  • add bucket length to particle container
  • add user-facing input options for bucket length
  • add function applying periodic particle boundary conditions
  • add functionality for alternative boundary options (e.g. reflection)
  • add Python bindings
  • add user-facing example (periodic bc)
  • add Python unit tests
  • update documentation

Longitudinal particle boundary condition options to target:

  1. open/off (no action)
  2. periodic (phase wrapping)
  3. cut (particle lost)
  4. reflection (particle bounces back with reversed momentum)

Comment thread examples/phase_wrapper/input_drift_phase_wrap.in Outdated
Comment thread src/particles/ImpactXParticleContainer.H Outdated
Comment thread src/particles/ImpactXParticleContainer.H Outdated
Comment thread src/particles/ImpactXParticleContainer.cpp Outdated
std::list<std::unordered_map<std::string, amrex::ParticleReal> > m_beam_moments;

//! the RF bucket length for particles in the particle container
amrex::ParticleReal m_bucket_length;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would store this as std::optional so it is clear when this is thought to be undefined/None:

Suggested change
amrex::ParticleReal m_bucket_length;
std::optional<amrex::ParticleReal> m_bucket_length;

Maybe even store like store_beam_moments as a public member and document that instead.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo to myself: do at the end

Comment thread src/particles/ParticleBoundary.cpp Outdated
amrex::ParmParse pp_algo("algo");
std::string particle_bc = "open";
pp_algo.queryAdd("particle_bc", particle_bc);
int particle_bc_int;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good case for an enum, in our case we can use AMREX_ENUM that supports string conversion.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks; I will revisit here.

Comment thread src/particles/ParticleBoundary.cpp Outdated
} else if (particle_bc == "reflecting") {
particle_bc_int = 3;
} else {
particle_bc_int = 0;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic bug: else seems to imply open, but open already returned above.

Usability: we should throw an error if an unknown other BC is set than the ones we know/handle. (This does not prevent handling no input as open by default.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed; will replace this line with an error message.

Comment thread src/particles/ParticleBoundary.cpp Outdated
Comment on lines +71 to +82
// Gather particles and apply boundary condition
amrex::ParallelFor(np, [=] AMREX_GPU_DEVICE (int i)
{
// Access SoA Real data
amrex::ParticleReal & AMREX_RESTRICT t = part_t[i];
amrex::ParticleReal & AMREX_RESTRICT pt = part_pt[i];

if (particle_bc_int==1) {

// Periodic particle boundary condition: apply phase wrapping in t (modulo bucket_duration):
amrex::ParticleReal ttest = std::fmod(t+bucket_half_duration, bucket_duration);
t = (bucket_duration != 0.0)? std::fmod(ttest+bucket_duration, bucket_duration)-bucket_half_duration : t;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: we can write the if/switch on the enum particle_bc_int outside the amrex::ParallelFor and create 3 unique, performant ParallelFor kernels; instead of one branching (slow) one.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I thought about branching outside the ParallelFor, but it introduces a lot of duplication. It's ok with me to rework things this way if there is an expected performance advantage.


namespace impactx::particles
{
/** Function to apply longitudinal particle boundary (periodic, etc.)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the AMREX_ENUM on the types of boundaries we have here.

Comment on lines +27 to +28
amrex::ParmParse pp_algo("algo");
std::string particle_bc = "open";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feel like something we could set on beam.[...] was well... (probably need to generalize the section heading here)

But no super strong opinion.

Co-authored-by: Axel Huebl <axel.huebl@plasma.ninja>
Comment thread src/particles/ImpactXParticleContainer.cpp
Comment thread src/particles/ImpactXParticleContainer.cpp Outdated
std::list<std::unordered_map<std::string, amrex::ParticleReal> > m_beam_moments;

//! the RF bucket length for particles in the particle container
std::optional<amrex::ParticleReal> m_bucket_length;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ax3l Making this optional is introducing build problems that are taking time to fix. Reverting to the previous behavior for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, I just drafted the implementation. I can do it when the PR is ready from your end.

Comment thread src/particles/ImpactXParticleContainer.H Outdated
Comment thread src/particles/ImpactXParticleContainer.cpp Outdated
Co-authored-by: Chad Mitchell <46825199+cemitch99@users.noreply.github.com>
@ax3l ax3l mentioned this pull request Apr 15, 2026
Comment thread examples/phase_wrapper/run_drift_phase_wrap.py Outdated
Comment on lines +33 to +35
if (particle_bc == "periodic") {
particle_bc_int = 1;
} else if (particle_bc == "absorbing") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo for @ax3l : use AMREX_ENUM (define in ParticleBoundary.H)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants