Skip to content

Add feedback passmethod#983

Open
lcarver wants to merge 24 commits intomasterfrom
add_feedback_passmethod
Open

Add feedback passmethod#983
lcarver wants to merge 24 commits intomasterfrom
add_feedback_passmethod

Conversation

@lcarver
Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

lcarver commented Sep 2, 2025

image

@lcarver lcarver requested a review from swhite2401 September 2, 2025 13:50
Comment thread atintegrators/FeedbackPass.c Outdated
Comment thread atintegrators/FeedbackPass.c Outdated
Comment thread atintegrators/FeedbackPass.c Outdated
Comment thread atintegrators/FeedbackPass.c
@lcarver
Copy link
Copy Markdown
Contributor Author

lcarver commented Sep 2, 2025

ready for re-review

Comment thread pyat/at/lattice/elements/basic_elements.py Outdated
Comment thread pyat/at/lattice/elements/basic_elements.py Outdated
Comment thread pyat/at/lattice/elements/basic_elements.py Outdated
Comment thread pyat/at/lattice/elements/basic_elements.py Outdated
Comment thread pyat/at/lattice/elements/basic_elements.py Outdated
Comment thread pyat/at/physics/fastring.py
@lcarver
Copy link
Copy Markdown
Contributor Author

lcarver commented Sep 3, 2025

ready for re-re-review

@lcarver
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

@lcarver
Copy link
Copy Markdown
Contributor Author

lcarver commented Apr 23, 2026

ready for review, should pass

def __init__(
self,
family_name: str,
Gxp: float = 0.0,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rename to gpx, gpy

family_name: Name of the element
Gxp: Feedback Gain in Horizontal (no units:
damping_time [turns] = 2 / Gx )
Gyp: Feedback Gain in Vertical (no units:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rename here as well

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

also it is 2/gpx

closed_orbit: [xp, yp, dp] - desired angle set points
default = [0, 0, 0]
bufferlength_xp: How many turns to use for a rolling
buffer in horizontal?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why a question mark?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In the end the rolling buffer is useful or not?


assert len(closed_orbit)==3, assert_msg

super().__init__(family_name, Gxp=Gxp, Gyp=Gyp, Gdp=Gdp, closed_orbit=closed_orbit, **kwargs)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rename here as well

assert_msg = 'closed_orbit must have length 3' + \
'referring to [xp,yp,dp] set points'

assert len(closed_orbit)==3, assert_msg
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should you raise an AtError?

particle: str | Particle = "relativistic",
TimeLag: float | Sequence[float] = 0.0
TimeLag: float | Sequence[float] = 0.0,
orb6: Sequence[float] = np.zeros(6),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is this needed for feedback?

# (although it is not used for anything else)
lin_elem = M66("Linear", m66=Mat66, Length=circumference)

lin_elem = M66("Linear", m66=Mat66, Length=circumference, T1=-orb6, T2=orb6)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't understand why you had to change this

void FeedbackPass(double *r_in, int num_particles, struct elem *Elem)
{
int c;
double mxp[] = {0.0}; // the mean that will be computed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

could you change to px, py here as well, thisi s what we use in AT

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.

2 participants