From 78bbfa08b2161af90132b76884faa999ab75539a Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Mon, 1 Sep 2025 09:56:42 +0200 Subject: [PATCH 01/21] Add unmodified passmethod from simon --- atintegrators/FeedbackPass.c | 73 ++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100755 atintegrators/FeedbackPass.c diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c new file mode 100755 index 000000000..5d4ba7461 --- /dev/null +++ b/atintegrators/FeedbackPass.c @@ -0,0 +1,73 @@ +/* IdentityPass.c + Accelerator Toolbox + Revision 7/16/03 + A.Terebilo +*/ + +#include "atelem.c" +#include "atlalib.c" + +struct elem +{ + double GX; + double GY; + double GZ; + double syncZ; +}; + +void FeedbackPass(double *r_in, double gx, double gy, double gz, double syncZ, int num_particles) +{ + double *r6; + int c; + double mx, my, mz, npart; + mx=0.0; + my=0.0; + mz=0.0; + npart = 0.0; + + for (c = 0; c0.0){ + mx /= npart; + my /= npart; + mz /= npart; + for (c = 0; cGX=GX; + Elem->GY=GY; + Elem->GZ=GZ; + } + FeedbackPass(r_in,Elem->GX,Elem->GY,Elem->GZ,num_particles); + return Elem; +} + +MODULE_DEF(IdentityPass) /* Dummy module initialisation */ + +#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ From 33133bab9b044433e6ccf11bfa627369848d69bb Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Mon, 1 Sep 2025 10:26:46 +0200 Subject: [PATCH 02/21] Add MPI, add mex function --- atintegrators/FeedbackPass.c | 78 ++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 7 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 5d4ba7461..6219a9bc5 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -6,16 +6,20 @@ #include "atelem.c" #include "atlalib.c" +#ifdef MPI +#include +#include +#endif struct elem { double GX; double GY; double GZ; - double syncZ; + double closed_orbit; }; -void FeedbackPass(double *r_in, double gx, double gy, double gz, double syncZ, int num_particles) +void FeedbackPass(double *r_in, double gx, double gy, double gz, double *closed_orbit, int num_particles) { double *r6; int c; @@ -35,6 +39,15 @@ void FeedbackPass(double *r_in, double gx, double gy, double gz, double syncZ, i } } + #ifdef MPI + MPI_Allreduce(MPI_IN_PLACE, npart, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, mx, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, my, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, mz, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Barrier(MPI_COMM_WORLD); + #endif + + if (npart>0.0){ mx /= npart; my /= npart; @@ -42,9 +55,9 @@ void FeedbackPass(double *r_in, double gx, double gy, double gz, double syncZ, i for (c = 0; cGX=GX; Elem->GY=GY; Elem->GZ=GZ; + Elem->closed_orbit = closed_orbit; } - FeedbackPass(r_in,Elem->GX,Elem->GY,Elem->GZ,num_particles); + FeedbackPass(r_in,Elem->GX,Elem->GY,Elem->GZ,Elem->closed_orbit,num_particles); return Elem; } MODULE_DEF(IdentityPass) /* Dummy module initialisation */ #endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ + + +#ifdef MATLAB_MEX_FILE + +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + if (nrhs >= 2) { + + double *r_in; + const mxArray *ElemData = prhs[0]; + int num_particles = mxGetN(prhs[1]); + struct elem El, *Elem=&El; + + double GX,GY,GZ,*closed_orbit; + + GX=atGetDouble(ElemData,"GX"); check_error(); + GY=atGetDouble(ElemData,"GY"); check_error(); + GZ=atGetDouble(ElemData,"GZ"); check_error(); + closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit"); + + + Elem = (struct elem*)atMalloc(sizeof(struct elem)); + Elem->GX=GX; + Elem->GY=GY; + Elem->GZ=GZ; + Elem->closed_orbit = closed_orbit; + + if (mxGetM(prhs[1]) != 6) mexErrMsgIdAndTxt("AT:WrongArg","Second argument must be a 6 x N matrix: particle array"); + + /* ALLOCATE memory for the output array of the same size as the input */ + plhs[0] = mxDuplicateArray(prhs[1]); + r_in = mxGetDoubles(plhs[0]); + FeedbackPass(r_in,0.0,0.0,0.0,closed_orbit,Elem); + } + else if (nrhs == 0) { + /* list of required fields */ + plhs[0] = mxCreateCellMatrix(4,1); + mxSetCell(plhs[0],0,mxCreateString("GX")); + mxSetCell(plhs[0],1,mxCreateString("GY")); + mxSetCell(plhs[0],2,mxCreateString("GZ")); + mxSetCell(plhs[0],3,mxCreateString("closed_orbit")); + } + else { + mexErrMsgIdAndTxt("AT:WrongArg","Needs 2 or 0 arguments"); + } +} +#endif + From 537614727b26467c05f637559a6045e5b4ab8961 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Mon, 1 Sep 2025 10:32:01 +0200 Subject: [PATCH 03/21] Check build --- atintegrators/FeedbackPass.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 6219a9bc5..131720fd5 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -19,11 +19,16 @@ struct elem double closed_orbit; }; -void FeedbackPass(double *r_in, double gx, double gy, double gz, double *closed_orbit, int num_particles) +void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) { double *r6; int c; - double mx, my, mz, npart; + double mx = 0.0; + double my = 0.0; + double mz = 0.0; + double npart; + double *closed_orbit = Elem->closed_orbit; + mx=0.0; my=0.0; mz=0.0; @@ -72,7 +77,7 @@ ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, GX=atGetDouble(ElemData,"GX"); check_error(); GY=atGetDouble(ElemData,"GY"); check_error(); GZ=atGetDouble(ElemData,"GZ"); check_error(); - closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit"); + closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit"); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); Elem->GX=GX; @@ -80,7 +85,7 @@ ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, Elem->GZ=GZ; Elem->closed_orbit = closed_orbit; } - FeedbackPass(r_in,Elem->GX,Elem->GY,Elem->GZ,Elem->closed_orbit,num_particles); + FeedbackPass(r_in,num_particles,Elem); return Elem; } @@ -105,7 +110,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) GX=atGetDouble(ElemData,"GX"); check_error(); GY=atGetDouble(ElemData,"GY"); check_error(); GZ=atGetDouble(ElemData,"GZ"); check_error(); - closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit"); + closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit"); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); @@ -119,7 +124,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* ALLOCATE memory for the output array of the same size as the input */ plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); - FeedbackPass(r_in,0.0,0.0,0.0,closed_orbit,Elem); + FeedbackPass(r_in,num_particles,Elem); } else if (nrhs == 0) { /* list of required fields */ From 08586f0f02ce2db9c8952a57a98a0adc8fa9d9dc Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Mon, 1 Sep 2025 10:33:56 +0200 Subject: [PATCH 04/21] build --- atintegrators/FeedbackPass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 131720fd5..054fcfa66 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -16,7 +16,7 @@ struct elem double GX; double GY; double GZ; - double closed_orbit; + double *closed_orbit; }; void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) From 86d58db96472218848fa5f420bf7f007fbe60e1e Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Mon, 1 Sep 2025 10:37:27 +0200 Subject: [PATCH 05/21] build --- atintegrators/FeedbackPass.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 054fcfa66..dc0b3180e 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -26,13 +26,11 @@ void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) double mx = 0.0; double my = 0.0; double mz = 0.0; - double npart; + double npart = 0.0; double *closed_orbit = Elem->closed_orbit; - - mx=0.0; - my=0.0; - mz=0.0; - npart = 0.0; + double gx = Elem->GX; + double gy = Elem->GY; + double gz = Elem->GZ; for (c = 0; c Date: Mon, 1 Sep 2025 10:41:12 +0200 Subject: [PATCH 06/21] rebuild --- atintegrators/FeedbackPass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index dc0b3180e..a9d918480 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -108,7 +108,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) GX=atGetDouble(ElemData,"GX"); check_error(); GY=atGetDouble(ElemData,"GY"); check_error(); GZ=atGetDouble(ElemData,"GZ"); check_error(); - closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit"); check_error(); + closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit");check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); From 1afef0f70658ec1dbe235cb3b31724943fe20f5b Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Mon, 1 Sep 2025 13:27:04 +0200 Subject: [PATCH 07/21] Wrong Dummy mode --- atintegrators/FeedbackPass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index a9d918480..b247b47a7 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -87,7 +87,7 @@ ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, return Elem; } -MODULE_DEF(IdentityPass) /* Dummy module initialisation */ +MODULE_DEF(FeedbackPass) /* Dummy module initialisation */ #endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ From 198df6aa0ab8e7ea161eec465799121863f8a207 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Tue, 2 Sep 2025 10:03:09 +0200 Subject: [PATCH 08/21] Add orbit to simple_ring --- pyat/at/physics/fastring.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pyat/at/physics/fastring.py b/pyat/at/physics/fastring.py index 9ab7455a2..8e5b802c4 100644 --- a/pyat/at/physics/fastring.py +++ b/pyat/at/physics/fastring.py @@ -141,7 +141,9 @@ def simple_ring( U0: float = 0.0, name: str = "", particle: str | Particle = "relativistic", - TimeLag: float | Sequence[float] = 0.0 + TimeLag: float | Sequence[float] = 0.0, + orb6: Sequence[float] = np.zeros(6), + ) -> Lattice: """Generates a "simple ring" based on a given dictionary of global parameters @@ -201,7 +203,8 @@ def simple_ring( or a Particle object TimeLag: Set the timelag of the cavities, Default=0. Can be scalar or sequence of scalars (as with harmonic_number and Vrf). - + orb6: 6d closed orbit. Needed for inclusion of feedbacks. + If the given emitx, emity or espread is 0, then no equlibrium emittance is applied in this plane. If the given tau is 0, then no radiation damping is applied for this plane. @@ -265,7 +268,8 @@ def simple_ring( # generate the linear tracking element, we set a length # which is needed to give the lattice object the correct length # (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) # Generate the simple radiation element simplerad = SimpleRadiation( From e93858defd98111a9dbf9a37325375194d20ade3 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Tue, 2 Sep 2025 10:03:34 +0200 Subject: [PATCH 09/21] Add Feedback element --- pyat/at/lattice/elements/basic_elements.py | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pyat/at/lattice/elements/basic_elements.py b/pyat/at/lattice/elements/basic_elements.py index ba07aa35a..33f719188 100644 --- a/pyat/at/lattice/elements/basic_elements.py +++ b/pyat/at/lattice/elements/basic_elements.py @@ -18,6 +18,7 @@ "SimpleRadiation", "QuantumDiffusion", "EnergyLoss", + "Feedback" ] import warnings @@ -626,5 +627,35 @@ def __init__(self, family_name: str, energy_loss: float, **kwargs): kwargs.setdefault("PassMethod", self.default_pass[False]) super().__init__(family_name, EnergyLoss=energy_loss, **kwargs) +class Feedback(Element): + """Transverse and Longitudinal Feedback element""" + + def __init__(self, family_name: str, + GX: float = 0.0, + GY: float = 0.0, + GZ: float = 0.0, + closed_orbit: float = np.zeros(6), + **kwargs): + """ + Args: + family_name: Name of the element + GX: Feedback Gain in Horizontal + GY: Feedback Gain in Vertical + GZ: Feedback Gain in Longitudinal + closed_orbit: 6D closed orbit to feedback around + + Default PassMethod: ``FeedbackPass`` + + Note that this element does not SET the closed orbit. That + must be handled in the linear maps for x and y, or the timelag + for the longitudinal plane. But an accurate closed orbit must be + provided in order to have a well behaving feedback. + """ + kwargs.setdefault("PassMethod", "FeedbackPass") + super().__init__(family_name, GX=GX, GY=GY, GZ=GZ, closed_orbit=closed_orbit, **kwargs) + + + + Radiative.register(EnergyLoss) From 087f2f19346aa70c0b08d1a222c39c67138d9349 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Tue, 2 Sep 2025 10:03:53 +0200 Subject: [PATCH 10/21] Fix all pointers --- atintegrators/FeedbackPass.c | 61 +++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index b247b47a7..32b4a1343 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -21,27 +21,36 @@ struct elem void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) { - double *r6; int c; - double mx = 0.0; - double my = 0.0; - double mz = 0.0; - double npart = 0.0; - double *closed_orbit = Elem->closed_orbit; + double *mx = atMalloc(sizeof(double)); + double *my = atMalloc(sizeof(double)); + double *mz = atMalloc(sizeof(double)); + long *npart = atMalloc(sizeof(long)); + + *mx = 0.0; + *my = 0.0; + *mz = 0.0; + *npart = 0; + + double *closed_orbit; + closed_orbit = Elem->closed_orbit; + double gx = Elem->GX; double gy = Elem->GY; double gz = Elem->GZ; for (c = 0; c0.0){ - mx /= npart; - my /= npart; - mz /= npart; + if (*npart>0.0){ + *mx /= *npart; + *my /= *npart; + *mz /= *npart; for (c = 0; cGX=GX; @@ -108,7 +125,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) GX=atGetDouble(ElemData,"GX"); check_error(); GY=atGetDouble(ElemData,"GY"); check_error(); GZ=atGetDouble(ElemData,"GZ"); check_error(); - closed_orbit = atGetDoubleArray(ElemData,"_closed_orbit");check_error(); + closed_orbit = atGetDoubleArray(ElemData,"closed_orbit");check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); From 0316aace70c6892e6b6aab9539bc9c8edfd69b97 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Tue, 2 Sep 2025 13:07:06 +0200 Subject: [PATCH 11/21] Stash --- atintegrators/FeedbackPass.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 32b4a1343..ac57474b0 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -41,7 +41,6 @@ void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) for (c = 0; c Date: Tue, 2 Sep 2025 15:39:40 +0200 Subject: [PATCH 12/21] remove comments --- atintegrators/FeedbackPass.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index ac57474b0..a8eab89d3 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -73,13 +73,6 @@ void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) } } - - /* - printf("%.8f \n", *mz); - printf("%.4f \n", closed_orbit[5]); - printf("%d \n", *npart); - printf("%.2f \n", gz); - */ atFree(mx); atFree(my); atFree(mz); From 6e1ec0ef6a8dcef1354618a6a284c33e5674f03f Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Tue, 2 Sep 2025 16:17:44 +0200 Subject: [PATCH 13/21] Better pointers --- atintegrators/FeedbackPass.c | 74 +++++++++++++++++------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index a8eab89d3..9e51cfeba 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -22,16 +22,11 @@ struct elem void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) { int c; - double *mx = atMalloc(sizeof(double)); - double *my = atMalloc(sizeof(double)); - double *mz = atMalloc(sizeof(double)); - long *npart = atMalloc(sizeof(long)); - - *mx = 0.0; - *my = 0.0; - *mz = 0.0; - *npart = 0; - + double mx = 0.0; + double my = 0.0; + double mz = 0.0; + long npart = 0.0; + double *closed_orbit; closed_orbit = Elem->closed_orbit; @@ -43,40 +38,35 @@ void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) double *r6 = r_in+c*6; if (!atIsNaN(r6[0])) { - *npart += 1; - *mx += r6[0]; - *my += r6[2]; - *mz += r6[5]; + npart += 1; + mx += r6[0]; + my += r6[2]; + mz += r6[5]; } } #ifdef MPI - MPI_Allreduce(MPI_IN_PLACE, npart, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, mx, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, my, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(MPI_IN_PLACE, mz, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &npart, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &mx, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &my, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(MPI_IN_PLACE, &mz, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD); #endif - if (*npart>0.0){ - *mx /= *npart; - *my /= *npart; - *mz /= *npart; + if (npart>0.0){ + mx /= npart; + my /= npart; + mz /= npart; for (c = 0; c1) /* optional fields */ + { + plhs[1] = mxCreateCellMatrix(3,1); + mxSetCell(plhs[1],0,mxCreateString("GX")); + mxSetCell(plhs[1],1,mxCreateString("GY")); + mxSetCell(plhs[1],2,mxCreateString("GZ")); + } } else { mexErrMsgIdAndTxt("AT:WrongArg","Needs 2 or 0 arguments"); From c6b320a62343b9e930f840db0642ac98e7ce961c Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Tue, 2 Sep 2025 16:25:44 +0200 Subject: [PATCH 14/21] Add optionals --- atintegrators/FeedbackPass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 9e51cfeba..2579f069b 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -108,9 +108,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) double GX,GY,GZ,*closed_orbit; - GX=atGetOptionalDouble(ElemData,"GX"); check_error(); - GY=atGetOptionalDouble(ElemData,"GY"); check_error(); - GZ=atGetDouble(ElemData,"GZ"); check_error(); + GX=atGetOptionalDouble(ElemData,"GX",0.0); check_error(); + GY=atGetOptionalDouble(ElemData,"GY",0.0); check_error(); + GZ=atGetOptionalDouble(ElemData,"GZ",0.0); check_error(); closed_orbit = atGetDoubleArray(ElemData,"closed_orbit");check_error(); From 85d1e885e9c2b5cc54ed2134d232cfe6066a6958 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Wed, 3 Sep 2025 09:59:47 +0200 Subject: [PATCH 15/21] Change capitals, add Sequence, remove kwaargs, modify help --- pyat/at/lattice/elements/basic_elements.py | 29 ++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/pyat/at/lattice/elements/basic_elements.py b/pyat/at/lattice/elements/basic_elements.py index 33f719188..ffb344b88 100644 --- a/pyat/at/lattice/elements/basic_elements.py +++ b/pyat/at/lattice/elements/basic_elements.py @@ -23,7 +23,7 @@ import warnings from collections.abc import Iterable -from typing import Optional +from typing import Optional, Sequence import numpy as np @@ -631,28 +631,31 @@ class Feedback(Element): """Transverse and Longitudinal Feedback element""" def __init__(self, family_name: str, - GX: float = 0.0, - GY: float = 0.0, - GZ: float = 0.0, - closed_orbit: float = np.zeros(6), - **kwargs): + Gx: float = 0.0, + Gy: float = 0.0, + Gz: float = 0.0, + closed_orbit: Sequence[float] = np.zeros(6) + ): """ Args: family_name: Name of the element - GX: Feedback Gain in Horizontal - GY: Feedback Gain in Vertical - GZ: Feedback Gain in Longitudinal - closed_orbit: 6D closed orbit to feedback around + Gx: Feedback Gain in Horizontal (no units: + damping_time [turns] = 2 / Gx ) + Gy: Feedback Gain in Vertical (no units: + damping_time [turns] = 2 / Gy ) + Gz: Feedback Gain in Longitudinal (no units: + damping_time [turns] = 2 / Gz ) + closed_orbit: 6D closed orbit to feedback onto Default PassMethod: ``FeedbackPass`` Note that this element does not SET the closed orbit. That - must be handled in the linear maps for x and y, or the timelag - for the longitudinal plane. But an accurate closed orbit must be + is handled by the lattice (either full ring or linear maps for x and y, + or the ct for the longitudinal plane). Aan accurate closed orbit must be provided in order to have a well behaving feedback. """ kwargs.setdefault("PassMethod", "FeedbackPass") - super().__init__(family_name, GX=GX, GY=GY, GZ=GZ, closed_orbit=closed_orbit, **kwargs) + super().__init__(family_name, Gx=Gx, Gy=Gy, Gz=Gz, closed_orbit=closed_orbit) From 9e51f093663c04ed3340ae7f89998cb894c324ab Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Wed, 3 Sep 2025 10:00:21 +0200 Subject: [PATCH 16/21] black --- pyat/at/lattice/elements/basic_elements.py | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pyat/at/lattice/elements/basic_elements.py b/pyat/at/lattice/elements/basic_elements.py index ffb344b88..ca0dbf416 100644 --- a/pyat/at/lattice/elements/basic_elements.py +++ b/pyat/at/lattice/elements/basic_elements.py @@ -18,7 +18,7 @@ "SimpleRadiation", "QuantumDiffusion", "EnergyLoss", - "Feedback" + "Feedback", ] import warnings @@ -627,15 +627,18 @@ def __init__(self, family_name: str, energy_loss: float, **kwargs): kwargs.setdefault("PassMethod", self.default_pass[False]) super().__init__(family_name, EnergyLoss=energy_loss, **kwargs) + class Feedback(Element): """Transverse and Longitudinal Feedback element""" - def __init__(self, family_name: str, - Gx: float = 0.0, - Gy: float = 0.0, - Gz: float = 0.0, - closed_orbit: Sequence[float] = np.zeros(6) - ): + def __init__( + self, + family_name: str, + Gx: float = 0.0, + Gy: float = 0.0, + Gz: float = 0.0, + closed_orbit: Sequence[float] = np.zeros(6), + ): """ Args: family_name: Name of the element @@ -646,19 +649,16 @@ def __init__(self, family_name: str, Gz: Feedback Gain in Longitudinal (no units: damping_time [turns] = 2 / Gz ) closed_orbit: 6D closed orbit to feedback onto - + Default PassMethod: ``FeedbackPass`` - - Note that this element does not SET the closed orbit. That + + Note that this element does not SET the closed orbit. That is handled by the lattice (either full ring or linear maps for x and y, or the ct for the longitudinal plane). Aan accurate closed orbit must be - provided in order to have a well behaving feedback. + provided in order to have a well behaving feedback. """ kwargs.setdefault("PassMethod", "FeedbackPass") super().__init__(family_name, Gx=Gx, Gy=Gy, Gz=Gz, closed_orbit=closed_orbit) - - - Radiative.register(EnergyLoss) From f0257867dff9cc33c0119d9a69a034fed3851dce Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Wed, 3 Sep 2025 10:05:17 +0200 Subject: [PATCH 17/21] put back kwargs as it is needed for passmethod --- pyat/at/lattice/elements/basic_elements.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyat/at/lattice/elements/basic_elements.py b/pyat/at/lattice/elements/basic_elements.py index ca0dbf416..71ede9048 100644 --- a/pyat/at/lattice/elements/basic_elements.py +++ b/pyat/at/lattice/elements/basic_elements.py @@ -638,6 +638,7 @@ def __init__( Gy: float = 0.0, Gz: float = 0.0, closed_orbit: Sequence[float] = np.zeros(6), + **kwargs ): """ Args: @@ -658,7 +659,7 @@ def __init__( provided in order to have a well behaving feedback. """ kwargs.setdefault("PassMethod", "FeedbackPass") - super().__init__(family_name, Gx=Gx, Gy=Gy, Gz=Gz, closed_orbit=closed_orbit) + super().__init__(family_name, Gx=Gx, Gy=Gy, Gz=Gz, closed_orbit=closed_orbit, **kwargs) Radiative.register(EnergyLoss) From 680072dee0bfc6f4c6afbd33733d6fb91bd07681 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Wed, 3 Sep 2025 10:34:14 +0200 Subject: [PATCH 18/21] Change case in C too --- atintegrators/FeedbackPass.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 2579f069b..83e704f36 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -75,9 +75,9 @@ ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, { if (!Elem) { double GX, GY, GZ, *closed_orbit; - GX=atGetOptionalDouble(ElemData,"GX",0.0); check_error(); - GY=atGetOptionalDouble(ElemData,"GY",0.0); check_error(); - GZ=atGetOptionalDouble(ElemData,"GZ",0.0); check_error(); + GX=atGetOptionalDouble(ElemData,"Gx",0.0); check_error(); + GY=atGetOptionalDouble(ElemData,"Gy",0.0); check_error(); + GZ=atGetOptionalDouble(ElemData,"Gz",0.0); check_error(); closed_orbit = atGetDoubleArray(ElemData,"closed_orbit"); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); @@ -108,9 +108,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) double GX,GY,GZ,*closed_orbit; - GX=atGetOptionalDouble(ElemData,"GX",0.0); check_error(); - GY=atGetOptionalDouble(ElemData,"GY",0.0); check_error(); - GZ=atGetOptionalDouble(ElemData,"GZ",0.0); check_error(); + GX=atGetOptionalDouble(ElemData,"Gx",0.0); check_error(); + GY=atGetOptionalDouble(ElemData,"Gy",0.0); check_error(); + GZ=atGetOptionalDouble(ElemData,"Gz",0.0); check_error(); closed_orbit = atGetDoubleArray(ElemData,"closed_orbit");check_error(); @@ -134,9 +134,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if(nlhs>1) /* optional fields */ { plhs[1] = mxCreateCellMatrix(3,1); - mxSetCell(plhs[1],0,mxCreateString("GX")); - mxSetCell(plhs[1],1,mxCreateString("GY")); - mxSetCell(plhs[1],2,mxCreateString("GZ")); + mxSetCell(plhs[1],0,mxCreateString("Gx")); + mxSetCell(plhs[1],1,mxCreateString("Gy")); + mxSetCell(plhs[1],2,mxCreateString("Gz")); } } else { From 052d1a5a20130d9982277c15290f02cd19c9c493 Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Tue, 27 Jan 2026 14:00:45 +0100 Subject: [PATCH 19/21] add buffer to feedback pass --- atintegrators/FeedbackPass.c | 171 ++++++++++++++++++--- pyat/at/lattice/elements/basic_elements.py | 18 ++- 2 files changed, 167 insertions(+), 22 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index 83e704f36..d436e39e4 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -17,14 +17,64 @@ struct elem double GY; double GZ; double *closed_orbit; + double *xbuffer; + double *ybuffer; + double *zbuffer; + long bufferlength_x; + long bufferlength_y; + long bufferlength_z; }; +void write_buffer(double *data, double *buffer, int datasize, int buffersize){ + if(buffersize>1){ + memmove(buffer, buffer + datasize, datasize*(buffersize-1)*sizeof(double)); + } + memcpy(buffer + datasize*(buffersize-1), data, datasize*sizeof(double)); +} + +int check_buffer_length(double *buffer, long buffersize, long numcolumns){ + int c; + int bufferlengthnow=0; + for (c=0; cGY; double gz = Elem->GZ; + double *xbuffer = Elem->xbuffer; + double *ybuffer = Elem->ybuffer; + double *zbuffer = Elem->zbuffer; + long bufferlength_x = Elem->bufferlength_x; + long bufferlength_y = Elem->bufferlength_y; + long bufferlength_z = Elem->bufferlength_z; + + long bufferlengthnow_x = 0; + long bufferlengthnow_y = 0; + long bufferlengthnow_z = 0; + for (c = 0; c0.0){ - mx /= npart; - my /= npart; - mz /= npart; - for (c = 0; c0){ + write_buffer(mx, xbuffer, 1, bufferlength_x); + bufferlengthnow_x = check_buffer_length(xbuffer, bufferlength_x, 1); + if(bufferlengthnow_x == bufferlength_x){ + compute_buffer_mean(mx_set, xbuffer, bufferlength_x, bufferlength_x, 1); + } + + }else{ + mx_set[0] = mx[0]; + } + + // vertical + if(bufferlength_y>0){ + write_buffer(my, ybuffer, 1, bufferlength_y); + bufferlengthnow_y = check_buffer_length(ybuffer, bufferlength_y, 1); + if(bufferlengthnow_y == bufferlength_y){ + compute_buffer_mean(my_set, ybuffer, bufferlength_y, bufferlength_y, 1); + } + + }else{ + my_set[0] = my[0]; + } + + // longitudinal + if(bufferlength_z>0){ + write_buffer(mz, zbuffer, 1, bufferlength_z); + bufferlengthnow_z = check_buffer_length(zbuffer, bufferlength_z, 1); + if(bufferlengthnow_z == bufferlength_z){ + compute_buffer_mean(mz_set, zbuffer, bufferlength_z, bufferlength_z, 1); + } + + }else{ + mz_set[0] = mz[0]; + } + + for (c = 0; cGX=GX; Elem->GY=GY; Elem->GZ=GZ; Elem->closed_orbit = closed_orbit; + Elem->xbuffer = xbuffer; + Elem->ybuffer = ybuffer; + Elem->zbuffer = zbuffer; + Elem->bufferlength_x = bufferlength_x; + Elem->bufferlength_y = bufferlength_y; + Elem->bufferlength_z = bufferlength_z; + } FeedbackPass(r_in,num_particles,Elem); return Elem; @@ -107,18 +219,30 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) struct elem El, *Elem=&El; double GX,GY,GZ,*closed_orbit; - + double *xbuffer, *ybuffer, *zbuffer; + long bufferlength_x, bufferlength_y, bufferlength_z; GX=atGetOptionalDouble(ElemData,"Gx",0.0); check_error(); GY=atGetOptionalDouble(ElemData,"Gy",0.0); check_error(); GZ=atGetOptionalDouble(ElemData,"Gz",0.0); check_error(); closed_orbit = atGetDoubleArray(ElemData,"closed_orbit");check_error(); - + xbuffer=atGetDoubleArray(ElemData,"_xbuffer"); check_error(); + ybuffer=atGetDoubleArray(ElemData,"_ybuffer"); check_error(); + zbuffer=atGetDoubleArray(ElemData,"_zbuffer"); check_error(); + bufferlength_x=atGetLong(ElemData,"_bufferlength_x"); check_error(); + bufferlength_y=atGetLong(ElemData,"_bufferlength_y"); check_error(); + bufferlength_z=atGetLong(ElemData,"_bufferlength_z"); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); Elem->GX=GX; Elem->GY=GY; Elem->GZ=GZ; Elem->closed_orbit = closed_orbit; + Elem->xbuffer = xbuffer; + Elem->ybuffer = ybuffer; + Elem->zbuffer = zbuffer; + Elem->bufferlength_x = bufferlength_x; + Elem->bufferlength_y = bufferlength_y; + Elem->bufferlength_z = bufferlength_z; if (mxGetM(prhs[1]) != 6) mexErrMsgIdAndTxt("AT:WrongArg","Second argument must be a 6 x N matrix: particle array"); @@ -129,8 +253,15 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } else if (nrhs == 0) { /* list of required fields */ - plhs[0] = mxCreateCellMatrix(1,1); + plhs[0] = mxCreateCellMatrix(7,1); mxSetCell(plhs[0],0,mxCreateString("closed_orbit")); + mxSetCell(plhs[0],1,mxCreateString("_xbuffer")); + mxSetCell(plhs[0],2,mxCreateString("_ybuffer")); + mxSetCell(plhs[0],3,mxCreateString("_zbuffer")); + mxSetCell(plhs[0],4,mxCreateString("_bufferlength_x")); + mxSetCell(plhs[0],5,mxCreateString("_bufferlength_y")); + mxSetCell(plhs[0],6,mxCreateString("_bufferlength_z")); + if(nlhs>1) /* optional fields */ { plhs[1] = mxCreateCellMatrix(3,1); diff --git a/pyat/at/lattice/elements/basic_elements.py b/pyat/at/lattice/elements/basic_elements.py index 82892cc90..a1f68c640 100644 --- a/pyat/at/lattice/elements/basic_elements.py +++ b/pyat/at/lattice/elements/basic_elements.py @@ -641,6 +641,9 @@ def __init__( Gy: float = 0.0, Gz: float = 0.0, closed_orbit: Sequence[float] = np.zeros(6), + bufferlength_x: int = 0, + bufferlength_y: int = 0, + bufferlength_z: int = 0, **kwargs ): """ @@ -653,16 +656,27 @@ def __init__( Gz: Feedback Gain in Longitudinal (no units: damping_time [turns] = 2 / Gz ) closed_orbit: 6D closed orbit to feedback onto + bufferlength_x: How many turns to use for a rolling + buffer in horizontal? + bufferlength_y: How many turns to use for a rolling + buffer in vertical? + bufferlength_z: How many turns to use for a rolling + buffer in longitudinal? Default PassMethod: ``FeedbackPass`` Note that this element does not SET the closed orbit. That is handled by the lattice (either full ring or linear maps for x and y, - or the ct for the longitudinal plane). Aan accurate closed orbit must be + or the ct for the longitudinal plane). An accurate closed orbit must be provided in order to have a well behaving feedback. """ kwargs.setdefault("PassMethod", "FeedbackPass") + self._bufferlength_x = bufferlength_x + self._bufferlength_y = bufferlength_y + self._bufferlength_z = bufferlength_z + self._xbuffer = np.zeros(bufferlength_x) + self._ybuffer = np.zeros(bufferlength_y) + self._zbuffer = np.zeros(bufferlength_z) super().__init__(family_name, Gx=Gx, Gy=Gy, Gz=Gz, closed_orbit=closed_orbit, **kwargs) - Radiative.register(EnergyLoss) From 9d3057c8251a7e39d17fe5d6af6562edb3b4ccdd Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Thu, 23 Apr 2026 16:33:28 +0200 Subject: [PATCH 20/21] Checkpoint, but ultimately this is not a good implementation --- atintegrators/FeedbackPass.c | 216 ++++++++++----------- pyat/at/lattice/elements/basic_elements.py | 67 ++++--- 2 files changed, 143 insertions(+), 140 deletions(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index d436e39e4..f27e68248 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -13,16 +13,16 @@ struct elem { - double GX; - double GY; - double GZ; + double Gxp; + double Gyp; + double Gdp; double *closed_orbit; - double *xbuffer; - double *ybuffer; - double *zbuffer; - long bufferlength_x; - long bufferlength_y; - long bufferlength_z; + double *xpbuffer; + double *ypbuffer; + double *dpbuffer; + long bufferlength_xp; + long bufferlength_yp; + long bufferlength_dp; }; void write_buffer(double *data, double *buffer, int datasize, int buffersize){ @@ -69,100 +69,100 @@ static void compute_buffer_mean(double *out_array, double *buffer, long windowle void FeedbackPass(double *r_in, int num_particles, struct elem *Elem) { int c; - double mx[] = {0.0}; - double mx_set[1] = {0.0}; - double my[] = {0.0}; - double my_set[1] = {0.0}; - double mz[] = {0.0}; - double mz_set[1] = {0.0}; + double mxp[] = {0.0}; // the mean that will be computed + double mxp_set[1] = {0.0}; // define pointer for the mean that will be set (buffer or one turn) + double myp[] = {0.0}; + double myp_set[1] = {0.0}; + double mdp[] = {0.0}; + double mdp_set[1] = {0.0}; long npart = 0.0; double *closed_orbit; closed_orbit = Elem->closed_orbit; - double gx = Elem->GX; - double gy = Elem->GY; - double gz = Elem->GZ; + double gxp = Elem->Gxp; + double gyp = Elem->Gyp; + double gdp = Elem->Gdp; - double *xbuffer = Elem->xbuffer; - double *ybuffer = Elem->ybuffer; - double *zbuffer = Elem->zbuffer; - long bufferlength_x = Elem->bufferlength_x; - long bufferlength_y = Elem->bufferlength_y; - long bufferlength_z = Elem->bufferlength_z; + double *xpbuffer = Elem->xpbuffer; + double *ypbuffer = Elem->ypbuffer; + double *dpbuffer = Elem->dpbuffer; + long bufferlength_xp = Elem->bufferlength_xp; + long bufferlength_yp = Elem->bufferlength_yp; + long bufferlength_dp = Elem->bufferlength_dp; - long bufferlengthnow_x = 0; - long bufferlengthnow_y = 0; - long bufferlengthnow_z = 0; + long bufferlengthnow_xp = 0; + long bufferlengthnow_yp = 0; + long bufferlengthnow_dp = 0; for (c = 0; c0.0){ - mx[0] /= npart; - my[0] /= npart; - mz[0] /= npart; + mxp[0] /= npart; + myp[0] /= npart; + mdp[0] /= npart; } // horizonal - if(bufferlength_x>0){ - write_buffer(mx, xbuffer, 1, bufferlength_x); - bufferlengthnow_x = check_buffer_length(xbuffer, bufferlength_x, 1); - if(bufferlengthnow_x == bufferlength_x){ - compute_buffer_mean(mx_set, xbuffer, bufferlength_x, bufferlength_x, 1); + if(bufferlength_xp>0){ + write_buffer(mxp, xpbuffer, 1, bufferlength_xp); + bufferlengthnow_xp = check_buffer_length(xpbuffer, bufferlength_xp, 1); + if(bufferlengthnow_xp == bufferlength_xp){ + compute_buffer_mean(mxp_set, xpbuffer, bufferlength_xp, bufferlength_xp, 1); } }else{ - mx_set[0] = mx[0]; + mxp_set[0] = mxp[0]; } // vertical - if(bufferlength_y>0){ - write_buffer(my, ybuffer, 1, bufferlength_y); - bufferlengthnow_y = check_buffer_length(ybuffer, bufferlength_y, 1); - if(bufferlengthnow_y == bufferlength_y){ - compute_buffer_mean(my_set, ybuffer, bufferlength_y, bufferlength_y, 1); + if(bufferlength_yp>0){ + write_buffer(myp, ypbuffer, 1, bufferlength_yp); + bufferlengthnow_yp = check_buffer_length(ypbuffer, bufferlength_yp, 1); + if(bufferlengthnow_yp == bufferlength_yp){ + compute_buffer_mean(myp_set, ypbuffer, bufferlength_yp, bufferlength_yp, 1); } }else{ - my_set[0] = my[0]; + myp_set[0] = myp[0]; } // longitudinal - if(bufferlength_z>0){ - write_buffer(mz, zbuffer, 1, bufferlength_z); - bufferlengthnow_z = check_buffer_length(zbuffer, bufferlength_z, 1); - if(bufferlengthnow_z == bufferlength_z){ - compute_buffer_mean(mz_set, zbuffer, bufferlength_z, bufferlength_z, 1); + if(bufferlength_dp>0){ + write_buffer(mdp, dpbuffer, 1, bufferlength_dp); + bufferlengthnow_dp = check_buffer_length(dpbuffer, bufferlength_dp, 1); + if(bufferlengthnow_dp == bufferlength_dp){ + compute_buffer_mean(mdp_set, dpbuffer, bufferlength_dp, bufferlength_dp, 1); } }else{ - mz_set[0] = mz[0]; + mdp_set[0] = mdp[0]; } for (c = 0; cGX=GX; - Elem->GY=GY; - Elem->GZ=GZ; + Elem->Gxp=Gxp; + Elem->Gyp=Gyp; + Elem->Gdp=Gdp; Elem->closed_orbit = closed_orbit; - Elem->xbuffer = xbuffer; - Elem->ybuffer = ybuffer; - Elem->zbuffer = zbuffer; - Elem->bufferlength_x = bufferlength_x; - Elem->bufferlength_y = bufferlength_y; - Elem->bufferlength_z = bufferlength_z; + Elem->xpbuffer = xpbuffer; + Elem->ypbuffer = ypbuffer; + Elem->dpbuffer = dpbuffer; + Elem->bufferlength_xp = bufferlength_xp; + Elem->bufferlength_yp = bufferlength_yp; + Elem->bufferlength_dp = bufferlength_dp; } FeedbackPass(r_in,num_particles,Elem); @@ -218,31 +218,31 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) int num_particles = mxGetN(prhs[1]); struct elem El, *Elem=&El; - double GX,GY,GZ,*closed_orbit; - double *xbuffer, *ybuffer, *zbuffer; - long bufferlength_x, bufferlength_y, bufferlength_z; - GX=atGetOptionalDouble(ElemData,"Gx",0.0); check_error(); - GY=atGetOptionalDouble(ElemData,"Gy",0.0); check_error(); - GZ=atGetOptionalDouble(ElemData,"Gz",0.0); check_error(); + double Gxp,Gyp,Gdp,*closed_orbit; + double *xpbuffer, *ypbuffer, *zpbuffer; + long bufferlength_xp, bufferlength_yp, bufferlength_dp; + Gxp=atGetOptionalDouble(ElemData,"Gxp",0.0); check_error(); + Gyp=atGetOptionalDouble(ElemData,"Gyp",0.0); check_error(); + Gdp=atGetOptionalDouble(ElemData,"Gdp",0.0); check_error(); closed_orbit = atGetDoubleArray(ElemData,"closed_orbit");check_error(); - xbuffer=atGetDoubleArray(ElemData,"_xbuffer"); check_error(); - ybuffer=atGetDoubleArray(ElemData,"_ybuffer"); check_error(); - zbuffer=atGetDoubleArray(ElemData,"_zbuffer"); check_error(); - bufferlength_x=atGetLong(ElemData,"_bufferlength_x"); check_error(); - bufferlength_y=atGetLong(ElemData,"_bufferlength_y"); check_error(); - bufferlength_z=atGetLong(ElemData,"_bufferlength_z"); check_error(); + xpbuffer=atGetDoubleArray(ElemData,"_xpbuffer"); check_error(); + ypbuffer=atGetDoubleArray(ElemData,"_ypbuffer"); check_error(); + dpbuffer=atGetDoubleArray(ElemData,"_dpbuffer"); check_error(); + bufferlength_xp=atGetLong(ElemData,"_bufferlength_xp"); check_error(); + bufferlength_yp=atGetLong(ElemData,"_bufferlength_yp"); check_error(); + bufferlength_dp=atGetLong(ElemData,"_bufferlength_dp"); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->GX=GX; - Elem->GY=GY; - Elem->GZ=GZ; + Elem->Gxp=Gxp; + Elem->Gyp=Gyp; + Elem->Gdp=Gdp; Elem->closed_orbit = closed_orbit; - Elem->xbuffer = xbuffer; - Elem->ybuffer = ybuffer; - Elem->zbuffer = zbuffer; - Elem->bufferlength_x = bufferlength_x; - Elem->bufferlength_y = bufferlength_y; - Elem->bufferlength_z = bufferlength_z; + Elem->xpbuffer = xpbuffer; + Elem->ypbuffer = ypbuffer; + Elem->dpbuffer = dpbuffer; + Elem->bufferlength_xp = bufferlength_xp; + Elem->bufferlength_yp = bufferlength_yp; + Elem->bufferlength_dp = bufferlength_dp; if (mxGetM(prhs[1]) != 6) mexErrMsgIdAndTxt("AT:WrongArg","Second argument must be a 6 x N matrix: particle array"); @@ -255,19 +255,19 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* list of required fields */ plhs[0] = mxCreateCellMatrix(7,1); mxSetCell(plhs[0],0,mxCreateString("closed_orbit")); - mxSetCell(plhs[0],1,mxCreateString("_xbuffer")); - mxSetCell(plhs[0],2,mxCreateString("_ybuffer")); - mxSetCell(plhs[0],3,mxCreateString("_zbuffer")); - mxSetCell(plhs[0],4,mxCreateString("_bufferlength_x")); - mxSetCell(plhs[0],5,mxCreateString("_bufferlength_y")); - mxSetCell(plhs[0],6,mxCreateString("_bufferlength_z")); + mxSetCell(plhs[0],1,mxCreateString("_xpbuffer")); + mxSetCell(plhs[0],2,mxCreateString("_ypbuffer")); + mxSetCell(plhs[0],3,mxCreateString("_dpbuffer")); + mxSetCell(plhs[0],4,mxCreateString("_bufferlength_xp")); + mxSetCell(plhs[0],5,mxCreateString("_bufferlength_yp")); + mxSetCell(plhs[0],6,mxCreateString("_bufferlength_dp")); if(nlhs>1) /* optional fields */ { plhs[1] = mxCreateCellMatrix(3,1); - mxSetCell(plhs[1],0,mxCreateString("Gx")); - mxSetCell(plhs[1],1,mxCreateString("Gy")); - mxSetCell(plhs[1],2,mxCreateString("Gz")); + mxSetCell(plhs[1],0,mxCreateString("Gxp")); + mxSetCell(plhs[1],1,mxCreateString("Gyp")); + mxSetCell(plhs[1],2,mxCreateString("Gdp")); } } else { diff --git a/pyat/at/lattice/elements/basic_elements.py b/pyat/at/lattice/elements/basic_elements.py index 231a94c43..0f1e5c3c4 100644 --- a/pyat/at/lattice/elements/basic_elements.py +++ b/pyat/at/lattice/elements/basic_elements.py @@ -637,46 +637,49 @@ class Feedback(Element): def __init__( self, family_name: str, - Gx: float = 0.0, - Gy: float = 0.0, - Gz: float = 0.0, - closed_orbit: Sequence[float] = np.zeros(6), - bufferlength_x: int = 0, - bufferlength_y: int = 0, - bufferlength_z: int = 0, + Gxp: float = 0.0, + Gyp: float = 0.0, + Gdp: float = 0.0, + closed_orbit: Sequence[float] = np.zeros(3), + bufferlength_xp: int = 0, + bufferlength_yp: int = 0, + bufferlength_dp: int = 0, **kwargs ): """ Args: - family_name: Name of the element - Gx: Feedback Gain in Horizontal (no units: - damping_time [turns] = 2 / Gx ) - Gy: Feedback Gain in Vertical (no units: - damping_time [turns] = 2 / Gy ) - Gz: Feedback Gain in Longitudinal (no units: - damping_time [turns] = 2 / Gz ) - closed_orbit: 6D closed orbit to feedback onto - bufferlength_x: How many turns to use for a rolling - buffer in horizontal? - bufferlength_y: How many turns to use for a rolling - buffer in vertical? - bufferlength_z: How many turns to use for a rolling - buffer in longitudinal? + 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: + damping_time [turns] = 2 / Gy ) + Gdp: Feedback Gain in Longitudinal (no units: + damping_time [turns] = 2 / Gdp ) + 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? + bufferlength_yp: How many turns to use for a rolling + buffer in vertical? + bufferlength_dp: How many turns to use for a rolling + buffer in longitudinal? Default PassMethod: ``FeedbackPass`` - Note that this element does not SET the closed orbit. That - is handled by the lattice (either full ring or linear maps for x and y, - or the ct for the longitudinal plane). An accurate closed orbit must be - provided in order to have a well behaving feedback. """ kwargs.setdefault("PassMethod", "FeedbackPass") - self._bufferlength_x = bufferlength_x - self._bufferlength_y = bufferlength_y - self._bufferlength_z = bufferlength_z - self._xbuffer = np.zeros(bufferlength_x) - self._ybuffer = np.zeros(bufferlength_y) - self._zbuffer = np.zeros(bufferlength_z) - super().__init__(family_name, Gx=Gx, Gy=Gy, Gz=Gz, closed_orbit=closed_orbit, **kwargs) + self._bufferlength_xp = bufferlength_xp + self._bufferlength_yp = bufferlength_yp + self._bufferlength_dp = bufferlength_dp + self._xpbuffer = np.zeros(bufferlength_xp) + self._ypbuffer = np.zeros(bufferlength_yp) + self._dpbuffer = np.zeros(bufferlength_dp) + + assert_msg = 'closed_orbit must have length 3' + \ + 'referring to [xp,yp,dp] set points' + + assert len(closed_orbit)==3, assert_msg + + super().__init__(family_name, Gxp=Gxp, Gyp=Gyp, Gdp=Gdp, closed_orbit=closed_orbit, **kwargs) Radiative.register(EnergyLoss) From 5612a569df5066512f303b1eba52da78f2d3cd0a Mon Sep 17 00:00:00 2001 From: Lee Carver Date: Thu, 23 Apr 2026 17:19:13 +0200 Subject: [PATCH 21/21] pass test --- atintegrators/FeedbackPass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atintegrators/FeedbackPass.c b/atintegrators/FeedbackPass.c index f27e68248..e9f5104c0 100755 --- a/atintegrators/FeedbackPass.c +++ b/atintegrators/FeedbackPass.c @@ -219,7 +219,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) struct elem El, *Elem=&El; double Gxp,Gyp,Gdp,*closed_orbit; - double *xpbuffer, *ypbuffer, *zpbuffer; + double *xpbuffer, *ypbuffer, *dpbuffer; long bufferlength_xp, bufferlength_yp, bufferlength_dp; Gxp=atGetOptionalDouble(ElemData,"Gxp",0.0); check_error(); Gyp=atGetOptionalDouble(ElemData,"Gyp",0.0); check_error();