Skip to content

Conversation

@YigitElma
Copy link
Collaborator

@YigitElma YigitElma commented Jul 21, 2025

This PR is a combination of #734 and #1410.

The main structure is under discussion in #1657.

  • Adds particle tracing capabilities in desc.particles module.
    • Particle tracing is done via desc.particles.trace_particles function.
    • Particles can be initialized in couple different ways:
      • ManualParticleInitializerLab : Initializes particles at given positions in lab coordinates.
      • ManualParticleInitializerFlux : Initializes particles at given positions in flux coordinates.
      • CurveParticleInitializer : Initializes N particles on a given curve.
      • SurfaceParticleInitializer : Initializes N particles on a given surface.
    • Implemented particle trajectory models are:
      • VacuumGuidingCenterTrajectory : Integrates the particle motion by vacuum guiding center ODEs, conserving energy and mu.
    • Particle trajectories can be plotted with desc.plotting.plot_particle_trajectories function.

We can delete #734 and #1410 once this is merged.

@YigitElma YigitElma requested a review from dpanici November 12, 2025 05:50
@YigitElma
Copy link
Collaborator Author

YigitElma commented Nov 13, 2025

I was playing around with different PID coefficients, with scaled precise_QA with 20 particles. Looks like pcoeff=0.3, icoeff=0.3, dcoeff=0 takes less number of steps for harder particles, if the integration happens very quickly then it performs a bit worse but those are very fast so doesn't matter.

image
rtz_1, _, aux_1 = _trace_particles(
    field=eq,
    y0=x0,
    model=model,
    model_args=args,
    ts=ts,
    params=eq.params_dict,
    max_steps=int((ts[-1] - ts[0]) / 1e-8),
    min_step_size=1e-8,
    stepsize_controller=PIDController(
        rtol=1e-4, atol=1e-4, dtmin=1e-8, pcoeff=0.4, icoeff=0.3, dcoeff=0
    ),
    saveat=SaveAt(ts=ts),
    solver=Tsit5(),
    adjoint=RecursiveCheckpointAdjoint(),
    event=event,
    chunk_size=None,
    options={},
    throw=False,
    return_aux=True,
)

dpanici
dpanici previously approved these changes Dec 2, 2025
Copy link
Member

@f0uriest f0uriest left a comment

Choose a reason for hiding this comment

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

a few minor points, otherwise looks fine

x, eq_or_field, params, m, q, mu, **kwargs
)
elif self.frame == "lab":
assert isinstance(eq_or_field, _MagneticField), (
Copy link
Member

Choose a reason for hiding this comment

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

Note that this might break in the future, I think @ddudt and @maya-avida were planning on making Equilibrium subclass from MagneticField as part of #996 #

Copy link
Member

Choose a reason for hiding this comment

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

though depending on how efficient the implementation is maybe this would be fine since it would still avoid the rootfinding

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Based on their API, I can adapt the check later.

@YigitElma YigitElma requested a review from f0uriest December 4, 2025 01:34
@YigitElma YigitElma requested review from dpanici and f0uriest and removed request for dpanici and f0uriest December 8, 2025 17:50
@YigitElma YigitElma merged commit 09d8b43 into master Dec 8, 2025
27 of 28 checks passed
@YigitElma YigitElma deleted the rc/particles branch December 8, 2025 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run_benchmarks Run timing benchmarks on this PR against current master branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants