Skip to content

Conversation

@lcarver
Copy link
Contributor

@lcarver lcarver commented Sep 2, 2025

Adding a simple passmethod to compute the mean position of the full beam and feedback with a gain.

The feedback takes simply a gain in x,y, and z, and an optional closed_orbit array (6d).

In this module, a closed_orbit is needed to make sure that the feedback is working. But this does not dictate what the closed_orbit is. To account for this, I added the orbit6 into at.simple_ring to allow an appropriate closed_orbit to feedback to to check that it is working.

Tested with mpi and without, all working fine.

Below is an example script.

from mpi4py import MPI
import at
import numpy as np 
import matplotlib.pyplot as plt


comm = MPI.COMM_WORLD


size = comm.Get_size()
rank = comm.Get_rank()
rank0 = rank == 0

plane = 2
gx = 0.0
gy = 0.01
gz = 0
orb = 3.e-3

closed_orbit = np.array([0.0, 0, 0, 0, 0, 0])
closed_orbit[plane] = orb



ring = at.simple_ring(6e9, 844, 992, 0.1, 0.18, 6e6, 8.5e-5, orb6=closed_orbit, tauy=0,  emity=0) #no radiation damping
ring.set_fillpattern(1)
sigma_matrix = at.sigma_matrix(betax=1, betay=1, alphax=0, alphay=0, emitx=100e-12, emity=10e-18, espread=1e-3, blength=3e-3)

nparts = 1000
nturns = 10000


fb = at.Feedback('fb', gx,gy,gz, closed_orbit)
ring.append(fb)


bmon = at.BeamMoments('bmon')
ring.append(bmon)


parts = at.beam(nparts, sigma_matrix)
parts[plane,:] += 1e-3

if rank0:
    all_means_fb = np.zeros((6,nturns))

for i in np.arange(nturns):
    ring.track(parts, in_place=True, refpts=None)
    
    if rank0:
        all_means_fb[:,i] = bmon.means[:,0,0]       

if rank0:
    plt.plot(1e3*all_means_fb[plane,:])
    plt.xlabel('Turn')
    plt.ylabel('y pos [mm]')
    plt.suptitle('CO_y = {:.0f}mm'.format(orb*1e3))
    plt.show()


@lcarver
Copy link
Contributor Author

lcarver commented Sep 2, 2025

image

@lcarver lcarver requested a review from swhite2401 September 2, 2025 13:50
Elem->GZ=GZ;
Elem->closed_orbit = closed_orbit;
}
FeedbackPass(r_in,num_particles,Elem);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think in other element we pass num_particles as the last argument but this is cosmetic

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What I put here follows what is in BeamMomentsPass and SliceMomentsPass.

@lcarver
Copy link
Contributor Author

lcarver commented Sep 2, 2025

ready for re-review

name: str = "",
particle: str | Particle = "relativistic",
TimeLag: float | Sequence[float] = 0.0
TimeLag: float | Sequence[float] = 0.0,
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't is possible to generate a simple ring from just an AT lattice?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, that is typically what fast_ring is for. Simple_ring is more for inputs by hand. But you are right i could pass a lattice and make an even simpler fast_ring from a lattice. That is separate to this though.

@lcarver
Copy link
Contributor Author

lcarver commented Sep 3, 2025

ready for re-re-review

@lcarver
Copy link
Contributor Author

lcarver commented Sep 3, 2025

Please re-approve. I made a last check of my script and realised I had forgotten to change the GX->Gx in the C, as it is optional it was not doing any damping!

@swhite2401
Copy link
Contributor

Please re-approve. I made a last check of my script and realised I had forgotten to change the GX->Gx in the C, as it is optional it was not doing any damping!

Could you please add unit tests first? Thanks!

swhite2401
swhite2401 previously approved these changes Nov 6, 2025
@swhite2401 swhite2401 self-requested a review January 14, 2026 15:44
@swhite2401 swhite2401 dismissed their stale review January 14, 2026 15:44

Not ready

@lcarver
Copy link
Contributor Author

lcarver commented Jan 27, 2026

I added an optional rolling buffer for each plane. Can be used by specifying bufferlength_x/y/z. Then the mean for each turn is added to the buffer and the loop uses the mean of the buffer instead of the one turn mean.

Some points/questions I want to make/ask:

  1. I stole most of the buffer functions from atimplib.c and BeamLoadingCavityPass.c. So now they are repeated, which is clearly not efficient. I think we should consider a new library for C functions relating to buffers and array manipulations. Do you think it is needed?
  2. I am sure there are improvements to be made on the memory handling and the pointer usage in the PassMethod.
  3. At the moment it feeds back directly on the horizontal/vertical/longitudinal position rather than the angle. I plan to change this as I think it is a bit problematic. For sure it works for a lumped model, but there is no reason this cannot be used in a full lattice, so this should be considered.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants