From f44fb3f845be9b78b1a7b36eb3a85a8ba4d4080f Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Mon, 1 Jun 2026 11:08:32 +0200 Subject: [PATCH 01/10] Refactoring of magnet integrators --- atintegrators/BeamLoadingCavityPass.c | 1 + atintegrators/BendLinearPass.c | 8 +- atintegrators/BndMPoleSymplectic4E2Pass.c | 308 +--------- atintegrators/BndMPoleSymplectic4E2RadPass.c | 379 +------------ atintegrators/BndMPoleSymplectic4Pass.c | 310 +--------- atintegrators/BndMPoleSymplectic4QuantPass.c | 374 +------------ atintegrators/BndMPoleSymplectic4RadPass.c | 328 +---------- atintegrators/BndOldRadPass.c | 305 ---------- atintegrators/BndStrMPoleSymplectic4Pass.c | 22 +- atintegrators/CrabCavityPass.c | 7 +- atintegrators/DriftPass.c | 5 +- atintegrators/E2_dipole.h | 135 +++++ atintegrators/ExactDriftPass.c | 4 +- atintegrators/ExactHamiltonianPass.cc | 207 ------- atintegrators/ExactHamiltonianPass.m | 23 - atintegrators/ExactMultipolePass.c | 228 +------- atintegrators/ExactMultipoleRadPass.c | 260 +-------- atintegrators/ExactRectBendPass.c | 337 +---------- atintegrators/ExactRectBendRadPass.c | 321 +---------- atintegrators/ExactRectangularBendPass.c | 303 +--------- atintegrators/ExactRectangularBendRadPass.c | 323 +---------- atintegrators/ExactSectorBendPass.c | 318 +---------- atintegrators/ExactSectorBendQuantPass.c | 10 + atintegrators/ExactSectorBendRadPass.c | 305 +--------- atintegrators/IdTablePass.c | 5 +- atintegrators/QuadLinearFPass.c | 5 +- atintegrators/QuadLinearPass.c | 5 +- atintegrators/RFCavityPass.c | 3 +- atintegrators/StrMPoleSymplectic4Pass.c | 244 +------- atintegrators/StrMPoleSymplectic4QuantPass.c | 308 +--------- atintegrators/StrMPoleSymplectic4RadPass.c | 269 +-------- atintegrators/StrOldRadPass.c | 241 -------- atintegrators/TestRandomPass.c | 2 +- atintegrators/ThinMPolePass.c | 21 +- atintegrators/VariableThinMPolePass.c | 4 +- atintegrators/atelem.c | 29 + atintegrators/atlalib.c | 23 +- atintegrators/atphyslib.c | 158 ------ atintegrators/attrackfunc.c | 6 +- atintegrators/bendfringe.h | 256 +++++++++ atintegrators/curved_dipole.h | 75 +++ atintegrators/diff_bend_fringe.c | 53 -- atintegrators/diff_bnd_kick.c | 174 ------ atintegrators/diff_str_exactkick.c | 83 --- atintegrators/diff_str_kick.c | 83 --- atintegrators/diff_thinkick.c | 8 +- atintegrators/diff_yrot.c | 65 --- atintegrators/drift_E2.h | 19 + .../{diff_exactdrift.c => drift_exact.h} | 4 +- .../{exactbend.c => drift_exactbend.h} | 35 +- atintegrators/drift_exactstrbend.h | 42 ++ .../{diff_drift.c => drift_expanded.h} | 16 +- atintegrators/drift_fast.h | 21 + atintegrators/driftkick.c | 115 ---- atintegrators/driftkickrad.c | 198 ------- atintegrators/exactbendfringe.c | 162 ------ atintegrators/exactdrift.c | 16 - atintegrators/exactkickrad.c | 186 ------ atintegrators/exactmultipolefringe.c | 95 ---- atintegrators/integrators.h | 85 +++ atintegrators/kick_E2.h | 102 ++++ atintegrators/kick_exactkn.h | 109 ++++ atintegrators/kick_h_k0h_k1h_kn.h | 115 ++++ atintegrators/kick_k1h_kn.h | 111 ++++ atintegrators/kick_kn.h | 110 ++++ .../{quadfringe.c => linearquadfringe.h} | 116 ++-- atintegrators/magnet_template.h | 357 ++++++++++++ atintegrators/multipolefringe.h | 154 +++++ .../{atquantlib.c => quantum_diffusion.h} | 41 ++ atintegrators/straight_dipole.h | 74 +++ atintegrators/straight_multipole.h | 46 ++ atintegrators/track.cc | 528 ------------------ atintegrators/track.h | 37 -- .../Radiation/findmpoleraddiffmatrix.c | 50 +- atmat/attests/pytests.m | 2 +- pyat/at/lattice/elements/rectangular_bend.py | 8 +- pyat/at/load/xsuite.py | 181 ++++-- pyat/test/test_physics.py | 21 +- 78 files changed, 2332 insertions(+), 7765 deletions(-) delete mode 100644 atintegrators/BndOldRadPass.c create mode 100644 atintegrators/E2_dipole.h delete mode 100644 atintegrators/ExactHamiltonianPass.cc delete mode 100644 atintegrators/ExactHamiltonianPass.m create mode 100644 atintegrators/ExactSectorBendQuantPass.c delete mode 100644 atintegrators/StrOldRadPass.c delete mode 100644 atintegrators/atphyslib.c create mode 100644 atintegrators/bendfringe.h create mode 100644 atintegrators/curved_dipole.h delete mode 100644 atintegrators/diff_bend_fringe.c delete mode 100644 atintegrators/diff_bnd_kick.c delete mode 100644 atintegrators/diff_str_exactkick.c delete mode 100644 atintegrators/diff_str_kick.c delete mode 100644 atintegrators/diff_yrot.c create mode 100644 atintegrators/drift_E2.h rename atintegrators/{diff_exactdrift.c => drift_exact.h} (93%) rename atintegrators/{exactbend.c => drift_exactbend.h} (54%) create mode 100644 atintegrators/drift_exactstrbend.h rename atintegrators/{diff_drift.c => drift_expanded.h} (77%) create mode 100644 atintegrators/drift_fast.h delete mode 100644 atintegrators/driftkick.c delete mode 100644 atintegrators/driftkickrad.c delete mode 100644 atintegrators/exactbendfringe.c delete mode 100644 atintegrators/exactdrift.c delete mode 100644 atintegrators/exactkickrad.c delete mode 100644 atintegrators/exactmultipolefringe.c create mode 100644 atintegrators/integrators.h create mode 100644 atintegrators/kick_E2.h create mode 100644 atintegrators/kick_exactkn.h create mode 100644 atintegrators/kick_h_k0h_k1h_kn.h create mode 100644 atintegrators/kick_k1h_kn.h create mode 100644 atintegrators/kick_kn.h rename atintegrators/{quadfringe.c => linearquadfringe.h} (54%) create mode 100644 atintegrators/magnet_template.h create mode 100644 atintegrators/multipolefringe.h rename atintegrators/{atquantlib.c => quantum_diffusion.h} (93%) create mode 100644 atintegrators/straight_dipole.h create mode 100644 atintegrators/straight_multipole.h delete mode 100644 atintegrators/track.cc delete mode 100644 atintegrators/track.h diff --git a/atintegrators/BeamLoadingCavityPass.c b/atintegrators/BeamLoadingCavityPass.c index f3f7f30a97..c29e9bc76e 100644 --- a/atintegrators/BeamLoadingCavityPass.c +++ b/atintegrators/BeamLoadingCavityPass.c @@ -1,5 +1,6 @@ #include "atconstants.h" #include "atelem.c" +#include "atlalib.c" #include "atimplib.c" #include "attrackfunc.c" diff --git a/atintegrators/BendLinearPass.c b/atintegrators/BendLinearPass.c index bcf4aa44db..59b373bd43 100644 --- a/atintegrators/BendLinearPass.c +++ b/atintegrators/BendLinearPass.c @@ -7,7 +7,7 @@ #include "atelem.c" #include "atlalib.c" -#include "atphyslib.c" +#include "bendfringe.h" #define SQR(X) ((X)*(X)) @@ -77,7 +77,7 @@ void bend6(double* r, double L, double b_angle, double grd, double ByError) { sqrtG2 = sqrt(G2); arg2 = L*sqrtG2; - MVD = cos(arg2);; + MVD = cos(arg2); M34 = sin(arg2)/sqrtG2; M43 = -sin(arg2)*sqrtG2; } @@ -160,10 +160,10 @@ void BendLinearPass(double *r, double le, double grd ,double ba, double bye, if (T1) ATaddvv(r6,T1); if (R1) ATmultmv(r6,R1); /* edge focus */ - edge_fringe_entrance(r6, irho, entrance_angle, fint1, gap, 1); + bend_linear_fringe(r6, irho, entrance_angle, gap*fint1, 1, 1.0, NULL); bend6(r6, le, ba, grd, bye); /* edge focus */ - edge_fringe_exit(r6, irho, exit_angle, fint2, gap, 1); + bend_linear_fringe(r6, irho, exit_angle, gap*fint2, 1, -1.0, NULL); /* Misalignment at exit */ if (R2) ATmultmv(r6,R2); if (T2) ATaddvv(r6,T2); diff --git a/atintegrators/BndMPoleSymplectic4E2Pass.c b/atintegrators/BndMPoleSymplectic4E2Pass.c index 28329151d4..e15988e330 100644 --- a/atintegrators/BndMPoleSymplectic4E2Pass.c +++ b/atintegrators/BndMPoleSymplectic4E2Pass.c @@ -1,310 +1,14 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "atphyslib.c" - -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - /* Optional fields */ - double FringeInt1; - double FringeInt2; - double FullGap; - double Scaling; - double h1; - double h2; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#define MAGNET_PASS BndMPoleSymplectic4E2Pass +#define INTEGRATOR_4 +#include "drift_E2.h" +#include "kick_E2.h" +#include "E2_dipole.h" /* This code was modified from the original BndMPoleSymplectic4Pass.c of AT to correctly integrate the Hamiltonian in the curvilinear coordinate system of the dipole and to include the second order Transport map of the fringe field. New version created by Xiaobiao Huang in March 2009, in final verified version in August 2009. - */ -static void bndthinkick(double* r, double* A, double* B, double L, double h, int max_order) -/***************************************************************************** -(1) PolynomA is neglected. -(2) The vector potential is expanded up to 4th order of x and y. -(3) Coefficients in PolynomB higher than 4th order is treated as if they are on straight geometry. -(4) The Hamiltonian is H2 = - h x delta - (1+h x)As/Brho-B0 x/Brho -*/ -{ - int i; - double ReSum = 0; /*B[max_order];*/ - double ImSum = 0; /*A[max_order];*/ - - double ReSumTemp; - double K1,K2; - - K1 = B[1]; - K2 = (max_order>=2) ? B[2] : 0; - - ReSum = B[max_order]; - for(i=max_order-1;i>=0;i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] ; - ReSum = ReSumTemp; - } - - r[1] -= L*(-h*r[4] + ReSum + h*(h*r[0]+K1*(r[0]*r[0]-0.5*r[2]*r[2])+K2*(r[0]*r[0]*r[0]-4.0/3.0*r[0]*r[2]*r[2])) ); - r[3] += L*(ImSum+h*(K1*r[0]*r[2]+4.0/3.0*K2*r[0]*r[0]*r[2]+(h/6.0*K1-K2/3.0)*r[2]*r[2]*r[2])) ; - r[5] += L*h*r[0]; /* pathlength */ - -} - -/* the pseudo-drift element described by Hamiltonian H1 = (1+hx) (px^2+py^2)/2(1+delta), */ -static void ATbendhxdrift6(double* r, double L,double h) -{ - double hs = h*L; - double i1pd = 1.0/(1+r[4]); - double x=r[0],px=r[1],py=r[3]; - - r[0] += (1+h*x)*px*i1pd*L+1/4.*hs*L*(px*px-py*py)*i1pd*i1pd; /* (1.0/h+x)*((1.0+hs*px*i1pd/2.)*(1.0+hs*px*i1pd/2.)-(hs*py*i1pd/2.)*(hs*py*i1pd/2.))-1./h;*/ - r[1] -= hs*(px*px+py*py)*i1pd/2.0; - - r[2]+= (1.0+h*x)*i1pd*py*L*(1.+px*hs/2.0); - r[5]+= (1.0+h*x)*i1pd*i1pd*L/2.0*(px*px+py*py); -} - -void BndMPoleSymplectic4E2Pass(double *r, double le, double irho, double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - double fint1, double fint2, double gap,double h1,double h2, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useFringe1 = (fint1 != 0) && (gap != 0); - bool useFringe2 = (fint2 != 0) && (gap != 0); - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gap,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - entrance_angle,useFringe1,fint1,h1,exit_angle,useFringe2,fint2,h2) - for (int c = 0; cLength=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->FullGap=FullGap; - Elem->Scaling=Scaling; - Elem->FringeInt1=FringeInt1; - Elem->FringeInt2=FringeInt2; - Elem->h1=h1; - Elem->h2=h2; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - irho = Elem->BendingAngle/Elem->Length; - BndMPoleSymplectic4E2Pass(r_in, Elem->Length, irho, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeInt1, Elem->FringeInt2, Elem->FullGap, - Elem->h1, Elem->h2, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, num_particles); - return Elem; -} - -MODULE_DEF(BndMPoleSymplectic4E2Pass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double irho; - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, FringeInt1, FringeInt2; - int MaxOrder, NumIntSteps; - double *PolynomA, *PolynomB, h1, h2, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *KickAngle; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - FullGap=atGetOptionalDouble(ElemData,"FullGap", 0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1", 0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2", 0); check_error(); - h1=atGetOptionalDouble(ElemData,"H1", 0); check_error(); - h2=atGetOptionalDouble(ElemData,"H2", 0); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - irho = BendingAngle/Length; - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - BndMPoleSymplectic4E2Pass(r_in, Length, irho, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeInt1, FringeInt2, FullGap, - h1, h2, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(8,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("BendingAngle")); - mxSetCell(plhs[0],2,mxCreateString("EntranceAngle")); - mxSetCell(plhs[0],3,mxCreateString("ExitAngle")); - mxSetCell(plhs[0],4,mxCreateString("PolynomA")); - mxSetCell(plhs[0],5,mxCreateString("PolynomB")); - mxSetCell(plhs[0],6,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],7,mxCreateString("NumIntSteps")); - - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(12,1); - mxSetCell(plhs[1],0,mxCreateString("FullGap")); - mxSetCell(plhs[1],1,mxCreateString("FringeInt1")); - mxSetCell(plhs[1],2,mxCreateString("FringeInt2")); - mxSetCell(plhs[1],3,mxCreateString("H1")); - mxSetCell(plhs[1],4,mxCreateString("H2")); - mxSetCell(plhs[1],5,mxCreateString("T1")); - mxSetCell(plhs[1],6,mxCreateString("T2")); - mxSetCell(plhs[1],7,mxCreateString("R1")); - mxSetCell(plhs[1],8,mxCreateString("R2")); - mxSetCell(plhs[1],9,mxCreateString("RApertures")); - mxSetCell(plhs[1],10,mxCreateString("EApertures")); - mxSetCell(plhs[1],11,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/BndMPoleSymplectic4E2RadPass.c b/atintegrators/BndMPoleSymplectic4E2RadPass.c index ad5e1c161b..33d7c1dc10 100644 --- a/atintegrators/BndMPoleSymplectic4E2RadPass.c +++ b/atintegrators/BndMPoleSymplectic4E2RadPass.c @@ -1,362 +1,17 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "atphyslib.c" - -#define SQR(X) ((X)*(X)) - -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - double Energy; - /* Optional fields */ - double FringeInt1; - double FringeInt2; - double FullGap; - double Scaling; - double h1; - double h2; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; - -/* - This code was modified from the original BndMPoleSymplectic4RadPass.c of AT to correctly integrate the Hamiltonian in - the curvilinear coordinate system of the dipole and to include the second order Transport map of the fringe field. Also - modified is the field Bx, By to include the curvature effect. - New version created by Xiaobiao Huang on 08/13/2009. - Last modified on 8/26/2009 - */ - -static double B2perp(double bx, double by, double irho, - double x, double xpr, double y, double ypr) -/* Calculates sqr(|e x B|) , where e is a unit vector in the direction of velocity */ -{ - double v_norm2; - v_norm2 = 1/(SQR(1+x*irho)+ SQR(xpr) + SQR(ypr)); - - /* components of the velocity vector - double ex, ey, ez; - ex = xpr; - ey = ypr; - ez = (1+x*irho); - */ - return((SQR(by*(1+x*irho)) + SQR(bx*(1+x*irho)) + SQR(bx*ypr - by*xpr) )*v_norm2) ; -} - - -static void bndthinkickrad(double* r, double* A, double* B, double L, double h, double E0,int max_order) -/***************************************************************************** -(1) PolynomA is neglected. -(2) The vector potential is expanded up to 4th order of x and y. -(3) Coefficients in PolynomB higher than 4th order is treated as if they are on straight geometry. -*/ -{ - int i; - double ReSum = 0; /*B[max_order];*/ - double ImSum = 0; /*A[max_order];*/ - - double ReSumTemp; - double K1,K2; - double x ,xpr, y, ypr, p_norm, B2P; - - double CRAD = CGAMMA*E0*E0*E0/(TWOPI*1e27); /* [m]/[GeV^3] M.Sands (4.1) */ - - K1 = B[1]; - K2 = (max_order>=2) ? B[2] : 0; - - ReSum = B[max_order]; - for(i=max_order-1;i>=0;i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] ; - ReSum = ReSumTemp; - } - /* calculate angles from momentums */ - p_norm = 1/(1+r[4]); - x = r[0]; - xpr = r[1]*p_norm; - y = r[2]; - ypr = r[3]*p_norm; - /* see Iselin Part. Accel. 1985 */ - ImSum += h*(K1*h-K2)*y*y*y/6.0; - ReSum += -K1*h*y*y/2.0 + h*(K1*h-K2)*x*y*y/2.0; - - B2P = B2perp(ImSum, ReSum +h, h, x , xpr, y ,ypr); - - r[4] = r[4] - CRAD*SQR(1+r[4])*B2P*(1 + x*h + (SQR(xpr)+SQR(ypr))/2 )*L; - - /* recalculate momentums from angles after losing energy for radiation */ - p_norm = 1/(1+r[4]); - r[1] = xpr/p_norm; - r[3] = ypr/p_norm; - r[1] -= L*(-h*r[4] + ReSum + h*(h*r[0]+K1*(r[0]*r[0]-0.5*r[2]*r[2])+K2*(r[0]*r[0]*r[0]-4.0/3.0*r[0]*r[2]*r[2])) ); - r[3] += L*(ImSum+h*(K1*r[0]*r[2]+4.0/3.0*K2*r[0]*r[0]*r[2]+(h/6.0*K1-K2/3.0)*r[2]*r[2]*r[2])) ; - r[5] += L*h*r[0]; /* pathlength */ - -} - -/* the pseudo-drift element described by Hamiltonian H1 = (1+hx) (px^2+py^2)/2(1+delta), */ -static void ATbendhxdrift6(double* r, double L,double h) -{ - double hs = h*L; - double i1pd = 1.0/(1+r[4]); - double x=r[0],px=r[1],py=r[3]; - - r[0] += (1+h*x)*px*i1pd*L+1/4.*hs*L*(px*px-py*py)*i1pd*i1pd; /* (1.0/h+x)*((1.0+hs*px*i1pd/2.)*(1.0+hs*px*i1pd/2.)-(hs*py*i1pd/2.)*(hs*py*i1pd/2.))-1./h;*/ - r[1] -= hs*(px*px+py*py)*i1pd/2.0; - - r[2]+= (1.0+h*x)*i1pd*py*L*(1.+px*hs/2.0); - r[5]+= (1.0+h*x)*i1pd*i1pd*L/2.0*(px*px+py*py); -} - -void BndMPoleSymplectic4E2RadPass(double *r, double le, double irho, double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - double fint1, double fint2, double gap,double h1,double h2, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double E0, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useFringe1 = (fint1 != 0) && (gap != 0); - bool useFringe2 = (fint2 != 0) && (gap != 0); - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gap,A,B,L1,L2,K1,K2,max_order,num_int_steps,E0,scaling,\ - entrance_angle,useFringe1,fint1,h1,exit_angle,useFringe2,fint2,h2) - for (int c = 0; cenergy); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - h1=atGetOptionalDouble(ElemData,"H1",0); check_error(); - h2=atGetOptionalDouble(ElemData,"H2",0); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - Elem->Energy=Energy; - /*optional fields*/ - Elem->FullGap=FullGap; - Elem->Scaling=Scaling; - Elem->FringeInt1=FringeInt1; - Elem->FringeInt2=FringeInt2; - Elem->h1=h1; - Elem->h2=h2; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - irho = Elem->BendingAngle/Elem->Length; - energy = atEnergy(Param->energy, Elem->Energy); check_error(); - - BndMPoleSymplectic4E2RadPass(r_in, Elem->Length, irho, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeInt1, Elem->FringeInt2, Elem->FullGap, - Elem->h1, Elem->h2, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, energy, num_particles); - return Elem; -} - -MODULE_DEF(BndMPoleSymplectic4E2RadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double irho; - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, FringeInt1, FringeInt2, Energy; - int MaxOrder, NumIntSteps; - double *PolynomA, *PolynomB, h1, h2, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *KickAngle; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap", 0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1", 0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2", 0); check_error(); - h1=atGetOptionalDouble(ElemData,"H1", 0); check_error(); - h2=atGetOptionalDouble(ElemData,"H2", 0); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - irho = BendingAngle/Length; - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - BndMPoleSymplectic4E2RadPass(r_in, Length, irho, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeInt1, FringeInt2, FullGap, - h1, h2, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Energy, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(9,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("BendingAngle")); - mxSetCell(plhs[0],2,mxCreateString("EntranceAngle")); - mxSetCell(plhs[0],3,mxCreateString("ExitAngle")); - mxSetCell(plhs[0],4,mxCreateString("PolynomA")); - mxSetCell(plhs[0],5,mxCreateString("PolynomB")); - mxSetCell(plhs[0],6,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],7,mxCreateString("NumIntSteps")); - - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(12,1); - mxSetCell(plhs[1],0,mxCreateString("FullGap")); - mxSetCell(plhs[1],1,mxCreateString("FringeInt1")); - mxSetCell(plhs[1],2,mxCreateString("FringeInt2")); - mxSetCell(plhs[1],3,mxCreateString("H1")); - mxSetCell(plhs[1],4,mxCreateString("H2")); - mxSetCell(plhs[1],5,mxCreateString("T1")); - mxSetCell(plhs[1],6,mxCreateString("T2")); - mxSetCell(plhs[1],7,mxCreateString("R1")); - mxSetCell(plhs[1],8,mxCreateString("R2")); - mxSetCell(plhs[1],9,mxCreateString("RApertures")); - mxSetCell(plhs[1],10,mxCreateString("EApertures")); - mxSetCell(plhs[1],11,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#define MAGNET_PASS BndMPoleSymplectic4E2RadPass +#define INTEGRATOR_4 +#define RADIATION + +#include "drift_E2.h" +#include "kick_E2.h" +#include "E2_dipole.h" + +/* + This code was modified from the original BndMPoleSymplectic4RadPass.c of AT to correctly integrate the Hamiltonian in + the curvilinear coordinate system of the dipole and to include the second order Transport map of the fringe field. Also + modified is the field Bx, By to include the curvature effect. + New version created by Xiaobiao Huang on 08/13/2009. + Last modified on 8/26/2009 + */ + +#include "magnet_template.h" diff --git a/atintegrators/BndMPoleSymplectic4Pass.c b/atintegrators/BndMPoleSymplectic4Pass.c index 1aef9d8e26..144831255d 100644 --- a/atintegrators/BndMPoleSymplectic4Pass.c +++ b/atintegrators/BndMPoleSymplectic4Pass.c @@ -1,305 +1,9 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "atphyslib.c" -#include "driftkick.c" /* fastdrift and bndthinkick */ -#include "quadfringe.c" /* QuadFringePassP, QuadFringePassN */ +#define MAGNET_PASS BndMPoleSymplectic4Pass +#define DEFAULT_BEND_FRINGE 1 +#define INTEGRATOR_4 -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - /* Optional fields */ - int FringeBendEntrance; - int FringeBendExit; - double FringeInt1; - double FringeInt2; - double FullGap; - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *fringeIntM0; - double *fringeIntP0; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_fast.h" +#include "kick_h_k0h_k1h_kn.h" +#include "curved_dipole.h" -void BndMPoleSymplectic4Pass(double *r, double le, double irho, double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - double fint1, double fint2, double gap, - int FringeQuadEntrance, int FringeQuadExit, - double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ - double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useLinFrEleEntrance = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadEntrance==2); - bool useLinFrEleExit = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadExit==2); - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gap,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - FringeBendEntrance,entrance_angle,fint1,FringeBendExit,exit_angle,fint2,\ - FringeQuadEntrance,useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0,fringeIntP0) - for (int c = 0; cLength=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FullGap=FullGap; - Elem->Scaling=Scaling; - Elem->FringeInt1=FringeInt1; - Elem->FringeInt2=FringeInt2; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - irho = Elem->BendingAngle/Elem->Length; - BndMPoleSymplectic4Pass(r_in, Elem->Length, irho, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeInt1, Elem->FringeInt2, Elem->FullGap, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, num_particles); - return Elem; -} - -MODULE_DEF(BndMPoleSymplectic4Pass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, - FringeInt1, FringeInt2; - int MaxOrder, NumIntSteps, FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - double irho; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - irho = BendingAngle/Length; - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - BndMPoleSymplectic4Pass(r_in, Length, irho, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeInt1, FringeInt2, FullGap, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(8,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("BendingAngle")); - mxSetCell(plhs[0],2,mxCreateString("EntranceAngle")); - mxSetCell(plhs[0],3,mxCreateString("ExitAngle")); - mxSetCell(plhs[0],4,mxCreateString("PolynomA")); - mxSetCell(plhs[0],5,mxCreateString("PolynomB")); - mxSetCell(plhs[0],6,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],7,mxCreateString("NumIntSteps")); - - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(17,1); - mxSetCell(plhs[1],0,mxCreateString("FullGap")); - mxSetCell(plhs[1],1,mxCreateString("FringeInt1")); - mxSetCell(plhs[1],2,mxCreateString("FringeInt2")); - mxSetCell(plhs[1],3,mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1],4,mxCreateString("FringeBendExit")); - mxSetCell(plhs[1],5,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1],6,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1],7,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1],8,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1],9,mxCreateString("T1")); - mxSetCell(plhs[1],10,mxCreateString("T2")); - mxSetCell(plhs[1],11,mxCreateString("R1")); - mxSetCell(plhs[1],12,mxCreateString("R2")); - mxSetCell(plhs[1],13,mxCreateString("RApertures")); - mxSetCell(plhs[1],14,mxCreateString("EApertures")); - mxSetCell(plhs[1],15,mxCreateString("KickAngle")); - mxSetCell(plhs[1],16,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/BndMPoleSymplectic4QuantPass.c b/atintegrators/BndMPoleSymplectic4QuantPass.c index 059becdbea..ecc7af9497 100644 --- a/atintegrators/BndMPoleSymplectic4QuantPass.c +++ b/atintegrators/BndMPoleSymplectic4QuantPass.c @@ -1,367 +1,11 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "atphyslib.c" -#include "atquantlib.c" -#include "driftkick.c" /* fastdrift and bndthinkick */ -#include "quadfringe.c" /* QuadFringePassP, QuadFringePassN */ -#include +#define MAGNET_PASS BndMPoleSymplectic4QuantPass +#define DEFAULT_BEND_FRINGE 1 +#define INTEGRATOR_4 +#define QUANTUM +#define NO_OMP /* because of problems with random generator and OpenMP */ -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - double Energy; - /* Optional fields */ - int FringeBendEntrance; - int FringeBendExit; - double FringeInt1; - double FringeInt2; - double FullGap; - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *fringeIntM0; - double *fringeIntP0; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_fast.h" +#include "kick_h_k0h_k1h_kn.h" +#include "curved_dipole.h" -void BndMPoleSymplectic4QuantPass(double *r, double le, double irho, double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - double fint1, double fint2, double gap, - int FringeQuadEntrance, int FringeQuadExit, - double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ - double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double E0, - pcg32_random_t* rng, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useLinFrEleEntrance = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadEntrance==2); - bool useLinFrEleExit = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadExit==2); - double qe = 1.60217733e-19; - double epsilon0 = 8.854187817e-12; - double clight = 2.99792458e8; - double emass = 510998.9461; /* electron mass in eV */ /* 9.10938188e-31; in kg*/ - double hbar = 1.054571726e-34; - double pi = 3.14159265358979; - double alpha0 = qe * qe / (4 * pi * epsilon0 * hbar * clight); - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - -/* The behaviour of random generators with OpenMP is doubtful. OpenMP disabled until - it's understood - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures, \ - irho,gap,A,B,L1,L2,K1,K2,max_order,num_int_steps,rng,E0,scaling, \ - FringeBendEntrance,entrance_angle,fint1,FringeBendExit,exit_angle,fint2, \ - FringeQuadEntrance,useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0, ringeIntP0, \ - emass,hbar,clight,alpha0,qe,SL) -*/ - for (int c = 0; c < num_particles; c++) { /* Loop over particles */ - double *r6 = r + 6*c; - if (!atIsNaN(r6[0])) { - int m; - /* Check for change of reference momentum */ - if (scaling != 1.0) ATChangePRef(r6, scaling); - /* misalignment at entrance */ - if (T1) ATaddvv(r6,T1); - if (R1) ATmultmv(r6,R1); - /* Check physical apertures at the entrance of the magnet */ - if (RApertures) checkiflostRectangularAp(r6,RApertures); - if (EApertures) checkiflostEllipticalAp(r6,EApertures); - /* edge focus */ - edge_fringe_entrance(r6, irho, entrance_angle, fint1, gap, FringeBendEntrance); - /* quadrupole gradient fringe entrance*/ - if (FringeQuadEntrance && B[1]!=0) { - if (useLinFrEleEntrance) /*Linear fringe fields from elegant*/ - linearQuadFringeElegantEntrance(r6, B[1], fringeIntM0, fringeIntP0); - else - QuadFringePassP(r6, B[1]); - } - /* integrator */ - for (m=0; m < num_int_steps; m++) { /* Loop over slices */ - int i; - double ng, ec, de, energy, gamma, cstec, cstng; - double ds, rho, dxp, dyp; - int nph; - double p_norm = 1 / (1 + r6[4]); - double NormL1 = L1 * p_norm; - double NormL2 = L2 * p_norm; - double dpp0 = r6[4]; - double xp0 = r6[1] * p_norm; - double yp0 = r6[3] * p_norm; - double s0 = r6[5]; - - fastdrift(r6, NormL1); - bndthinkick(r6, A, B, K1, irho, max_order); - fastdrift(r6, NormL2); - bndthinkick(r6, A, B, K2, irho, max_order); - fastdrift(r6, NormL2); - bndthinkick(r6, A, B, K1, irho, max_order); - fastdrift(r6, NormL1); - - energy = dpp0 * E0 + E0; - - gamma = energy / emass; /* emass in eV */ - cstec = 3.0 * gamma * gamma * gamma * clight / (2.0) * hbar / qe; - cstng = 5.0 * sqrt(3.0) * alpha0 * gamma / (6.0); - - dxp = r6[1] * p_norm - xp0 - irho * SL; - dyp = r6[3] * p_norm - yp0; - ds = r6[5] - s0; - - rho = (SL + ds) / sqrt(dxp * dxp + dyp * dyp); - - ng = cstng / rho * (SL + ds); - ec = cstec / rho; - - nph = atrandp_r(rng, ng); - - de = 0.0; - for (i = 0; i < nph; i++) { - de = de + getEnergy(rng, ec); - }; - r6[4] = r6[4] - de / E0; - r6[1] = r6[1] * p_norm * (1 + r6[4]); - r6[3] = r6[3] * p_norm * (1 + r6[4]); - } - /* quadrupole gradient fringe */ - if (FringeQuadExit && B[1]!=0) { - if (useLinFrEleExit) /*Linear fringe fields from elegant*/ - linearQuadFringeElegantExit(r6, B[1], fringeIntM0, fringeIntP0); - else - QuadFringePassN(r6, B[1]); - } - /* edge focus */ - edge_fringe_exit(r6, irho, exit_angle, fint2, gap, FringeBendExit); - /* Check physical apertures at the exit of the magnet */ - if (RApertures) checkiflostRectangularAp(r6,RApertures); - if (EApertures) checkiflostEllipticalAp(r6,EApertures); - /* Misalignment at exit */ - if (R2) ATmultmv(r6,R2); - if (T2) ATaddvv(r6,T2); - /* Check for change of reference momentum */ - if (scaling != 1.0) ATChangePRef(r6, 1.0/scaling); - } - } - if (KickAngle) { /* Remove corrector component in polynomial coefficients */ - B[0] = B0; - A[0] = A0; - } -} - -#if defined(MATLAB_MEX_FILE) || defined(PYAT) -ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, - double *r_in, int num_particles, struct parameters *Param) -{ - double irho, energy; - if (!Elem) { - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, - FringeInt1, FringeInt2, Energy; - int MaxOrder, NumIntSteps, FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",Param->energy); check_error(); - FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - Elem->Energy=Energy; - /*optional fields*/ - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FullGap=FullGap; - Elem->Scaling=Scaling; - Elem->FringeInt1=FringeInt1; - Elem->FringeInt2=FringeInt2; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - irho = Elem->BendingAngle/Elem->Length; - energy = atEnergy(Param->energy, Elem->Energy); check_error(); - - BndMPoleSymplectic4QuantPass(r_in, Elem->Length, irho, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeInt1, Elem->FringeInt2, Elem->FullGap, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, energy, - Param->thread_rng, num_particles); - return Elem; -} - -MODULE_DEF(BndMPoleSymplectic4QuantPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, - FringeInt1, FringeInt2, Energy; - int MaxOrder, NumIntSteps, FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - double rest_energy = 0.0; - double charge = -1.0; - double irho; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - irho = BendingAngle/Length; - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - - BndMPoleSymplectic4QuantPass(r_in, Length, irho, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeInt1, FringeInt2, FullGap, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Energy, &pcg32_global, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(9,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("BendingAngle")); - mxSetCell(plhs[0],2,mxCreateString("EntranceAngle")); - mxSetCell(plhs[0],3,mxCreateString("ExitAngle")); - mxSetCell(plhs[0],4,mxCreateString("PolynomA")); - mxSetCell(plhs[0],5,mxCreateString("PolynomB")); - mxSetCell(plhs[0],6,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],7,mxCreateString("NumIntSteps")); - mxSetCell(plhs[0],8,mxCreateString("Energy")); - - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(17,1); - mxSetCell(plhs[1],0,mxCreateString("FullGap")); - mxSetCell(plhs[1],1,mxCreateString("FringeInt1")); - mxSetCell(plhs[1],2,mxCreateString("FringeInt2")); - mxSetCell(plhs[1],3,mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1],4,mxCreateString("FringeBendExit")); - mxSetCell(plhs[1],5,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1],6,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1],7,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1],8,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1],9,mxCreateString("T1")); - mxSetCell(plhs[1],10,mxCreateString("T2")); - mxSetCell(plhs[1],11,mxCreateString("R1")); - mxSetCell(plhs[1],12,mxCreateString("R2")); - mxSetCell(plhs[1],13,mxCreateString("RApertures")); - mxSetCell(plhs[1],14,mxCreateString("EApertures")); - mxSetCell(plhs[1],15,mxCreateString("KickAngle")); - mxSetCell(plhs[1],16,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/BndMPoleSymplectic4RadPass.c b/atintegrators/BndMPoleSymplectic4RadPass.c index 897906ff94..670f488247 100644 --- a/atintegrators/BndMPoleSymplectic4RadPass.c +++ b/atintegrators/BndMPoleSymplectic4RadPass.c @@ -1,321 +1,11 @@ -#include "atelem.c" -#include "atlalib.c" -#include "diff_bend_fringe.c" -#include "diff_bnd_kick.c" -#include "diff_drift.c" -#include "quadfringe.c" /* QuadFringePassP, QuadFringePassN */ +#define MAGNET_PASS BndMPoleSymplectic4RadPass +#define DEFAULT_BEND_FRINGE 1 +#define INTEGRATOR_4 +#define RADIATION +#define DIFFUSION -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - double Energy; - /* Optional fields */ - int FringeBendEntrance; - int FringeBendExit; - double FringeInt1; - double FringeInt2; - double FullGap; - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *fringeIntM0; - double *fringeIntP0; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_expanded.h" +#include "kick_h_k0h_k1h_kn.h" +#include "curved_dipole.h" -void BndMPoleSymplectic4RadPass(double *r, double le, double irho, double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - double fint1, double fint2, double gap, - int FringeQuadEntrance, int FringeQuadExit, - double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ - double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double gamma, int num_particles, - double *bdiff) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useLinFrEleEntrance = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadEntrance==2); - bool useLinFrEleExit = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadExit==2); - double B0 = B[0]; - double A0 = A[0]; - double rad_const = RAD_CONST*pow(gamma, 3); - double diff_const = DIF_CONST*pow(gamma, 5); - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,bdiff,\ - irho,gap,A,B,L1,L2,K1,K2,max_order,num_int_steps,rad_const, diff_const,scaling,\ - FringeBendEntrance,entrance_angle,fint1,FringeBendExit,exit_angle,fint2,\ - FringeQuadEntrance,useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0,fringeIntP0) - for (int c = 0; cbdiff; - - if (!Elem) { - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, - FringeInt1, FringeInt2, Energy; - int MaxOrder, NumIntSteps, FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",Param->energy); check_error(); - FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - Elem->Energy=Energy; - /*optional fields*/ - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FullGap=FullGap; - Elem->Scaling=Scaling; - Elem->FringeInt1=FringeInt1; - Elem->FringeInt2=FringeInt2; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - irho = Elem->BendingAngle/Elem->Length; - gamma = atGamma(Param->energy, Elem->Energy, Param->rest_energy); check_error(); - - BndMPoleSymplectic4RadPass(r_in, Elem->Length, irho, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeInt1, Elem->FringeInt2, Elem->FullGap, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, gamma, num_particles, bdiff); - return Elem; -} - -MODULE_DEF(BndMPoleSymplectic4RadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, - FringeInt1, FringeInt2, Energy; - int MaxOrder, NumIntSteps, FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - double irho; - double *r_in; - double Gamma; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - irho = BendingAngle/Length; - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - Gamma = atGamma(Energy, Energy, rest_energy); - r_in = mxGetDoubles(plhs[0]); - - BndMPoleSymplectic4RadPass(r_in, Length, irho, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeInt1, FringeInt2, FullGap, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Gamma, num_particles, NULL); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(9,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("BendingAngle")); - mxSetCell(plhs[0],2,mxCreateString("EntranceAngle")); - mxSetCell(plhs[0],3,mxCreateString("ExitAngle")); - mxSetCell(plhs[0],4,mxCreateString("PolynomA")); - mxSetCell(plhs[0],5,mxCreateString("PolynomB")); - mxSetCell(plhs[0],6,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],7,mxCreateString("NumIntSteps")); - mxSetCell(plhs[0],8,mxCreateString("Energy")); - - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(17,1); - mxSetCell(plhs[1],0,mxCreateString("FullGap")); - mxSetCell(plhs[1],1,mxCreateString("FringeInt1")); - mxSetCell(plhs[1],2,mxCreateString("FringeInt2")); - mxSetCell(plhs[1],3,mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1],4,mxCreateString("FringeBendExit")); - mxSetCell(plhs[1],5,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1],6,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1],7,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1],8,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1],9,mxCreateString("T1")); - mxSetCell(plhs[1],10,mxCreateString("T2")); - mxSetCell(plhs[1],11,mxCreateString("R1")); - mxSetCell(plhs[1],12,mxCreateString("R2")); - mxSetCell(plhs[1],13,mxCreateString("RApertures")); - mxSetCell(plhs[1],14,mxCreateString("EApertures")); - mxSetCell(plhs[1],15,mxCreateString("KickAngle")); - mxSetCell(plhs[1],16,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/BndOldRadPass.c b/atintegrators/BndOldRadPass.c deleted file mode 100644 index 3f07485c81..0000000000 --- a/atintegrators/BndOldRadPass.c +++ /dev/null @@ -1,305 +0,0 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "atphyslib.c" -#include "driftkickrad.c" /* bndthinkickrad.c */ -#include "quadfringe.c" /* QuadFringePassP, QuadFringePassN */ - -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - double Energy; - /* Optional fields */ - int FringeBendEntrance; - int FringeBendExit; - double FringeInt1; - double FringeInt2; - double FullGap; - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *fringeIntM0; - double *fringeIntP0; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; - -void BndOldRadPass(double *r, double le, double irho, double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - double fint1, double fint2, double gap, - int FringeQuadEntrance, int FringeQuadExit, - double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ - double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double E0, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useLinFrEleEntrance = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadEntrance==2); - bool useLinFrEleExit = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadExit==2); - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gap,A,B,L1,L2,K1,K2,max_order,num_int_steps,E0,scaling,\ - FringeBendEntrance,entrance_angle,fint1,FringeBendExit,exit_angle,fint2,\ - FringeQuadEntrance,useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0,fringeIntP0) - for (int c = 0; cenergy); check_error(); - /*optional fields*/ - FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - Elem->Energy=Energy; - /*optional fields*/ - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FullGap=FullGap; - Elem->Scaling=Scaling; - Elem->FringeInt1=FringeInt1; - Elem->FringeInt2=FringeInt2; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - irho = Elem->BendingAngle/Elem->Length; - BndOldRadPass(r_in, Elem->Length, irho, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeInt1, Elem->FringeInt2, Elem->FullGap, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, Elem->Energy, num_particles); - return Elem; -} - -MODULE_DEF(BndOldRadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs == 2) { - double Length, BendingAngle, EntranceAngle, ExitAngle, FullGap, Scaling, - FringeInt1, FringeInt2, Energy; - int MaxOrder, NumIntSteps, FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - double irho; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - BendingAngle=atGetDouble(ElemData,"BendingAngle"); check_error(); - EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - Energy=atGetDouble(ElemData,"Energy"); check_error(); - /*optional fields*/ - FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - FullGap=atGetOptionalDouble(ElemData,"FullGap",0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0); check_error(); - FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - irho = BendingAngle/Length; - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - BndOldRadPass(r_in, Length, irho, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeInt1, FringeInt2, FullGap, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Energy, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(9,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("BendingAngle")); - mxSetCell(plhs[0],2,mxCreateString("EntranceAngle")); - mxSetCell(plhs[0],3,mxCreateString("ExitAngle")); - mxSetCell(plhs[0],4,mxCreateString("PolynomA")); - mxSetCell(plhs[0],5,mxCreateString("PolynomB")); - mxSetCell(plhs[0],6,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],7,mxCreateString("NumIntSteps")); - mxSetCell(plhs[0],8,mxCreateString("Energy")); - - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(17,1); - mxSetCell(plhs[1],0,mxCreateString("FullGap")); - mxSetCell(plhs[1],1,mxCreateString("FringeInt1")); - mxSetCell(plhs[1],2,mxCreateString("FringeInt2")); - mxSetCell(plhs[1],3,mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1],4,mxCreateString("FringeBendExit")); - mxSetCell(plhs[1],5,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1],6,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1],7,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1],8,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1],9,mxCreateString("T1")); - mxSetCell(plhs[1],10,mxCreateString("T2")); - mxSetCell(plhs[1],11,mxCreateString("R1")); - mxSetCell(plhs[1],12,mxCreateString("R2")); - mxSetCell(plhs[1],13,mxCreateString("RApertures")); - mxSetCell(plhs[1],14,mxCreateString("EApertures")); - mxSetCell(plhs[1],15,mxCreateString("KickAngle")); - mxSetCell(plhs[1],16,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ diff --git a/atintegrators/BndStrMPoleSymplectic4Pass.c b/atintegrators/BndStrMPoleSymplectic4Pass.c index b626574b83..3b631abed8 100644 --- a/atintegrators/BndStrMPoleSymplectic4Pass.c +++ b/atintegrators/BndStrMPoleSymplectic4Pass.c @@ -1,8 +1,7 @@ #include "atconstants.h" #include "atelem.c" #include "atlalib.c" -#include "atphyslib.c" -#include "driftkick.c" /* strthinkick.c */ +#include "kick_kn.h" /* kick */ /* Straight dipole w/ multipole using Symplectic Integration and rotation at * dipole faces. @@ -133,14 +132,13 @@ void BndStrMPoleSymplectic4Pass(double *r, double le, double irho, double *A, do double K2 = SL*KICK2; bool useFringe1 = (fint1 != 0) && (gap != 0); bool useFringe2 = (fint2 != 0) && (gap != 0); - double B0 = B[0]; - double A0 = A[0]; + double B0 = irho; + double A0 = 0.0; - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; + if (KickAngle) { /* Convert corrector component to polynomial coefficients */ + B0 -= sin(KickAngle[0]) / le; + A0 = sin(KickAngle[1]) / le; } - B[0] += irho; for (int c = 0; c +#include "bendfringe.h" +#include "multipolefringe.h" + +static void edge_fringe2A(double* r, double h, double edge_angle, double gK, double h1, double K1) +{ /* Entrance Fringe field transport map to second order in dipoles with fringe field */ + double ca = cos(edge_angle); + double sa = sin(edge_angle); + double dpsi = h*gK*(1.0+sa*sa)/ca; /* /(1+r[4]); */ + double psi_bar = edge_angle-dpsi; + double tpsi=sa/ca, tpsib=tan(psi_bar); + double fx = h*tpsi; + double fy = h*tpsib; + double spsi=1.0/ca; /* spsib=1.0/cos(psi_bar) */ + double T111,T234,T414, T212,T313, T133,T423,T211,T233,T413; + + double r0=r[0],r2=r[2],r1=r[1]; + T111 = -0.5*h*tpsi*tpsi; + /* T234= -0.5*h*tpsi*tpsib; */ + T234= -0.5*h*tpsi*tpsi; + T414=T234; + T212 = -T111; + T313 = -T234; + T133 = 0.5*h*spsi*spsi; T423=-T133; + T211 = 0.5*h*h1*spsi*spsi*spsi + K1*tpsi; + T233 = -0.5*h*h1*spsi*spsi*spsi -K1*tpsi+0.5*h*h*tpsi*(tpsib*tpsib+spsi*spsi); + T413 = -0.5*h*h1*spsi*spsi*spsi -K1*tpsi; /*-0.5*h*h*tpsi*(spsi*spsi+tpsib*tpsib);*/ + + r[0] += T111*r[0]*r[0]+T133*r[2]*r[2]; + r[1] += r0*fx + 2*T212*r0*r[1]+2*T234*r[2]*r[3]+T211*r0*r0+T233*r[2]*r[2] ; + r[2] += 2*T313*r0*r[2]; + r[3] += -r2*fy + 2*T414*r0*r[3]+2*T413*r0*r2+2*T423*r1*r2 ; + +} + +static void edge_fringe2B(double* r, double h, double edge_angle, double gK, double h2,double K1) +{ /* Exit Fringe field transport map to second order in dipoles with fringe field */ + double ca = cos(edge_angle); + double sa = sin(edge_angle); + double dpsi = h*gK*(1.0+sa*sa)/ca; /* /(1+r[4]); */ + double psi_bar = edge_angle-dpsi; + double tpsi=sa/ca, tpsib=tan(psi_bar); + double fx = h*tpsi; + double fy = h*tpsib; + double spsi=1.0/ca; /* spsib=1.0/cos(psi_bar) */ + double T111,T234,T414, T212,T313, T133,T423,T211,T233,T413; + + double r0=r[0],r2=r[2],r1=r[1]; + T111 = 0.5*h*tpsi*tpsi; + /* T234= 0.5*h*tpsi*tpsib; */ + T234= 0.5*h*tpsi*tpsi; + T414=T234; + T212 = -T111; + T313 = -T234; + T133 = -0.5*h*spsi*spsi; T423=-T133; + T211 = 0.5*h*h2*spsi*spsi*spsi +K1*tpsi-0.5*h*h*tpsi*tpsi*tpsi; + T233 = -0.5*h*h2*spsi*spsi*spsi -K1*tpsi-0.5*h*h*tpsi*tpsib*tpsib; + T413 = -0.5*h*h2*spsi*spsi*spsi -K1*tpsi+0.5*h*h*tpsi*(spsi*spsi); + + r[0] += T111*r[0]*r[0]+T133*r[2]*r[2]; + r[1] += r0*fx + 2*T212*r0*r[1]+2*T234*r[2]*r[3]+T211*r0*r0+T233*r[2]*r[2] ; + r[2] += 2*T313*r0*r[2]; + r[3] += -r2*fy + 2*T414*r0*r[3]+2*T413*r0*r2+2*T423*r1*r2 ; + +} + +#define MAGNET_ENTRY \ + /* Entry face */ \ + if (FringeBendEntrance == 4) { \ + Yrot(r6, entrance_angle, bdiff); \ + bend_fringe(r6, irho, gK_entrance); \ + multipole_fringe(r6, FringeQuadEntrance, B1, A, B, max_order, fringeIntM0, fringeIntP0, 1.0); \ + if (entrance_angle != 0.0) { \ + if (B1 != 0.0 && FringeQuadEntrance) quad_wedge(r6, -B1 * entrance_angle); \ + bend_wedge(r6, irho, -entrance_angle, bdiff); \ + } \ + } \ + else if (FringeBendEntrance > 0) { \ + edge_fringe2A(r6, irho, entrance_angle, gK_entrance, h1, B1); \ + multipole_fringe(r6, FringeQuadEntrance, B1, A, B, max_order, fringeIntM0, fringeIntP0, 1.0); \ + } + +#define MAGNET_EXIT \ + /* Exit face */ \ + if (FringeBendExit == 4) { \ + if (exit_angle != 0.0) { \ + bend_wedge(r6, irho, -exit_angle, bdiff); \ + if (B1 != 0.0 && FringeQuadExit) quad_wedge(r6, -B1 * exit_angle); \ + } \ + multipole_fringe(r6, FringeQuadExit, B1, A, B, max_order, fringeIntM0, fringeIntP0, -1.0); \ + bend_fringe(r6, -irho, gK_exit); \ + Yrot(r6, exit_angle, bdiff); \ + } \ + else if (FringeBendExit > 0) { \ + multipole_fringe(r6, FringeQuadExit, B1, A, B, max_order, fringeIntM0, fringeIntP0, -1.0); \ + edge_fringe2B(r6, irho, exit_angle, gK_exit, h2, B1); \ + } + +#define MAGNET_ARGUMENTS \ + double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle", 0.0); check_error(); \ + double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); \ + double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); \ + int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance", 1); check_error(); \ + int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit", 1); check_error(); \ + double FullGap=atGetOptionalDouble(ElemData,"FullGap",0.0); check_error(); \ + double FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0.0); check_error(); \ + double FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0.0); check_error(); \ + double H1=atGetOptionalDouble(ElemData,"H1",0.0); check_error(); \ + double H2=atGetOptionalDouble(ElemData,"H2",0.0); check_error(); + +#define MAGNET_ITEMS \ + Elem->BendingAngle=BendingAngle; \ + Elem->EntranceAngle=EntranceAngle; \ + Elem->ExitAngle=ExitAngle; \ + Elem->FringeBendEntrance=FringeBendEntrance; \ + Elem->FringeBendExit=FringeBendExit; \ + Elem->gK_entrance=FullGap*FringeInt1; \ + Elem->gK_exit=FullGap*FringeInt2; \ + Elem->H1 = H1; \ + Elem->H2 = H2; + +#ifdef MATLAB_MEX_FILE +#define MAGNET_MEX_ITEMS \ + double gK_entrance=FullGap*FringeInt1; \ + double gK_exit=FullGap*FringeInt2; + +const char *required[] = {"BendingAngle", "EntranceAngle", "ExitAngle"}; +const char *optional[] = {"FringeBendEntrance", "FringeBendExit", "FullGap", "FringeInt1", "FringeInt2", "H1", "H2"}; +#define N_REQUIRED 3 +#define N_OPTIONAL 7 +#endif /*MATLAB_MEX_FILE*/ + +#endif /*E2_DIPOLE*/ diff --git a/atintegrators/ExactDriftPass.c b/atintegrators/ExactDriftPass.c index 5f6df8af0d..3887fc49fb 100644 --- a/atintegrators/ExactDriftPass.c +++ b/atintegrators/ExactDriftPass.c @@ -1,6 +1,6 @@ #include "atelem.c" #include "atlalib.c" -#include "exactdrift.c" +#include "drift_exact.h" struct elem { double Length; @@ -35,7 +35,7 @@ static void drift_pass(double *r_in, double le, const double *T1, const double * if (RApertures) checkiflostRectangularAp(r6, RApertures); if (EApertures) checkiflostEllipticalAp(r6, EApertures); - exact_drift(r6, le); + drift(r6, le, 0.0, NULL); /* Convert absolute path length to path lengthening */ r6[5] -= le; diff --git a/atintegrators/ExactHamiltonianPass.cc b/atintegrators/ExactHamiltonianPass.cc deleted file mode 100644 index c4c5893334..0000000000 --- a/atintegrators/ExactHamiltonianPass.cc +++ /dev/null @@ -1,207 +0,0 @@ -/* See ExactHamiltonianPass.m for further notes. */ -#include "atelem.c" -#include -#include "atlalib.c" - -#define AT_MODE -#include "track.cc" - -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - /* type is defined in track.h: - - 0: drift - - 1: dipole - - 2: multipole - - 3: marker - */ - int Type; - /* Optional fields */ - double gK; /* g * K, required for bend */ - double BendingAngle; /* required for bend */ - int MultipoleFringe; /* bool, whether to calculate multipole fringe */ - double *R1; - double *R2; - double *T1; - double *T2; -}; - -static const char * FirstOptionalName = "gK"; - -#define NUM_FIELDS_2_REMEMBER (sizeof(FieldNames) / sizeof(FieldNames[0])) - -void ExactHamiltonianPass(double *r_in, double le, - double *A, double *B, - const double *T1, const double *T2, - const double *R1, const double *R2, - int max_order, int num_int_steps, - double phi, int type, - double gK, int multipole_fringe, - int num_particles) -{ - int c, n; - double * r6; - - // copy AT structure into pass method structure - - element e = {0}; - - for(n = 0; n < max_order+1; n++) - { - e.F[2 * n] = B[n]; - e.F[2 * n + 1] = A[n]; - } - - e.L = le; - e.phi = phi; - e.gK = gK; - e.nF = max_order+1; - e.slices = num_int_steps; - e.type = type; - e.do_multipole_fringe = multipole_fringe; - - for(c = 0; cLength=le; - Elem->PolynomA=polynom_a; - Elem->PolynomB=polynom_b; - Elem->MaxOrder=max_order; - Elem->NumIntSteps=num_int_steps; - Elem->Type = type; - /*optional fields*/ - Elem->MultipoleFringe = multipole_fringe; - Elem->BendingAngle = bending_angle; - Elem->gK = gK; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - } - ExactHamiltonianPass(r_in, Elem->Length, Elem->PolynomA, Elem->PolynomB, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->MaxOrder, Elem->NumIntSteps, - Elem->BendingAngle, Elem->Type, Elem->gK, - Elem->MultipoleFringe, num_particles); - - return Elem; -} - -MODULE_DEF(ExactHamiltonianPass) /* Dummy module initialisation */ - -#endif /* defined(PYAT) || defined(MATLAB_MEX_FILE) */ - - -#if defined(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]); - int m = mxGetM(prhs[1]); - if (m!=6) - mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - double le, bending_angle; - double *polynom_a, *polynom_b; - long max_order, num_int_steps, type, multipole_fringe; - double *R1, *R2, *T1, *T2; - double phi, gK; - le = atGetDouble(ElemData,"Length"); check_error(); - polynom_a = atGetDoubleArray(ElemData,"PolynomA"); check_error(); - polynom_b = atGetDoubleArray(ElemData,"PolynomB"); check_error(); - max_order = atGetLong(ElemData, "MaxOrder"); check_error(); - num_int_steps = atGetLong(ElemData, "NumIntSteps"); check_error(); - type = atGetLong(ElemData, "Type"); check_error(); - /*optional fields*/ - multipole_fringe = atGetOptionalLong(ElemData, "MultipoleFringe", 0); check_error(); - bending_angle = atGetOptionalDouble(ElemData,"BendingAngle", 0.0); check_error(); - gK = atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetPr(plhs[0]); - ExactHamiltonianPass(r_in, le, polynom_a, polynom_b, T1, T2, R1, R2, max_order, - num_int_steps, bending_angle, type, gK, multipole_fringe, num_particles); - } - else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(6,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("PolynomA")); - mxSetCell(plhs[0],2,mxCreateString("PolynomB")); - mxSetCell(plhs[0],3,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],4,mxCreateString("NumIntSteps")); - mxSetCell(plhs[0],5,mxCreateString("Type")); - if (nlhs>1) { - /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(7,1); - mxSetCell(plhs[1],0,mxCreateString("MultipoleFringe")); - mxSetCell(plhs[1],1,mxCreateString("BendingAngle")); - mxSetCell(plhs[1],2,mxCreateString("gK")); - mxSetCell(plhs[1],3,mxCreateString("T1")); - mxSetCell(plhs[1],4,mxCreateString("T2")); - mxSetCell(plhs[1],5,mxCreateString("R1")); - mxSetCell(plhs[1],6,mxCreateString("R2")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /*MATLAB_MEX_FILE*/ diff --git a/atintegrators/ExactHamiltonianPass.m b/atintegrators/ExactHamiltonianPass.m deleted file mode 100644 index 4782b41013..0000000000 --- a/atintegrators/ExactHamiltonianPass.m +++ /dev/null @@ -1,23 +0,0 @@ -% ExactHamiltonianPass.m Help file for ExactHamiltonianPass.c -% ExactHamiltonian.c - Exact integrator for different element types -% -% This method will work for a drift, a quadrupole, a sextupole or a -% bending magnet. It distinguishes between these using the Class field -% on the element. -% -% The 'ExactHamiltonianPass' method uses the square root hamiltonian in -% cartesian co-ordinates (see other notes for derivation). -% This is equivalent to setting exact=true in MADX-PTC. -% Multipole fringe fields are also enabled for quadrupoles -% (fringe = true option in MADX-PTC). -% -% Note that the PolynomB array in the exact cartesian rectangular bend -% refers to the normalized straight multipole components of the vector -% potential, so PolynomB(1) should be set to 1/rho (B_bend / Brho). -% The conjugate momenta in the curvilinear co-ordinate system are not -% the same as in the cartesian system so PolynomB(1) must be set back -% to zero when using a curvilinear symplectic integrator method such -% as the 'BndMPoleSymplectic4E2Pass'. See Forest p362 for a detailed -% explanation of the vector potential in curvilinear co-ordinates. -% -%see also: ExactHamiltonianPass.c diff --git a/atintegrators/ExactMultipolePass.c b/atintegrators/ExactMultipolePass.c index f0e3f8030a..460502da2f 100644 --- a/atintegrators/ExactMultipolePass.c +++ b/atintegrators/ExactMultipolePass.c @@ -1,224 +1,8 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "driftkick.c" /* fastdrift.c, strthinkick.c */ -#include "exactdrift.c" -#include "exactmultipolefringe.c" +#define MAGNET_PASS ExactMultipolePass +#define INTEGRATOR_6 -struct elem { - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - /* Optional fields */ - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_exact.h" +#include "kick_exactkn.h" /* kick */ +#include "straight_multipole.h" -static void multipole_pass( - double *r, double le, double *A, double *B, int max_order, int num_int_steps, - int FringeQuadEntrance, int FringeQuadExit, /* 0 (no fringe), else */ - double *T1, double *T2, double *R1, double *R2, double *RApertures, - double *EApertures, double *KickAngle, double scaling, int num_particles) -{ - double SL = le / num_int_steps; - double L1 = SL * DRIFT1; - double L2 = SL * DRIFT2; - double K1 = SL * KICK1; - double K2 = SL * KICK2; - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0]) / le; - A[0] += sin(KickAngle[1]) / le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) \ - default(none) \ - shared(r, num_particles, R1, T1, R2, T2, RApertures, \ - EApertures, A, B, L1, L2, K1, K2, max_order, \ - FringeQuadEntrance, FringeQuadExit, \ - num_int_steps, scaling, le) - for (int c = 0; c < num_particles; c++) { /*Loop over particles */ - double *r6 = r + c * 6; - if (!atIsNaN(r6[0])) { - int m; - - /* Check for change of reference momentum */ - if (scaling != 1.0) ATChangePRef(r6, scaling); - - /* misalignment at entrance */ - if (T1) ATaddvv(r6, T1); - if (R1) ATmultmv(r6, R1); - - /* Check physical apertures at the entrance of the magnet */ - if (RApertures) checkiflostRectangularAp(r6, RApertures); - if (EApertures) checkiflostEllipticalAp(r6, EApertures); - - /* Fringe field effect */ - if (FringeQuadEntrance) multipole_fringe(r6, le, A, B, max_order, 1.0, 0); - - /* integrator */ - for (m = 0; m < num_int_steps; m++) { /* Loop over slices */ - exact_drift(r6, L1); - strthinkick(r6, A, B, K1, max_order); - exact_drift(r6, L2); - strthinkick(r6, A, B, K2, max_order); - exact_drift(r6, L2); - strthinkick(r6, A, B, K1, max_order); - exact_drift(r6, L1); - } - - /* Convert absolute path length to path lengthening */ - r6[5] -= le; - - /* Fringe field effect */ - if (FringeQuadExit) multipole_fringe(r6, le, A, B, max_order, -1.0, 0); - - /* Check physical apertures at the exit of the magnet */ - if (RApertures) checkiflostRectangularAp(r6, RApertures); - if (EApertures) checkiflostEllipticalAp(r6, EApertures); - - /* Misalignment at exit */ - if (R2) ATmultmv(r6, R2); - if (T2) ATaddvv(r6, T2); - - /* Check for change of reference momentum */ - if (scaling != 1.0) ATChangePRef(r6, 1.0/scaling); - } - } - /* Remove corrector component in polynomial coefficients */ - B[0] = B0; - A[0] = A0; -} - -#if defined(MATLAB_MEX_FILE) || defined(PYAT) -ExportMode struct elem *trackFunction(const atElem *ElemData, struct elem *Elem, - double *r_in, int num_particles, - struct parameters *Param) { - if (!Elem) { - double Length = atGetDouble(ElemData, "Length"); check_error(); - double *PolynomA = atGetDoubleArray(ElemData, "PolynomA"); check_error(); - double *PolynomB = atGetDoubleArray(ElemData, "PolynomB"); check_error(); - int MaxOrder = atGetLong(ElemData, "MaxOrder"); check_error(); - int NumIntSteps = atGetLong(ElemData, "NumIntSteps"); check_error(); - /*optional fields*/ - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); - double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); - double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); - double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); - double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); - double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); - double *KickAngle = atGetOptionalDoubleArray(ElemData, "KickAngle"); check_error(); - - if (NumIntSteps <= 0) { - atError("NumIntSteps must be positive"); check_error(); - } - - Elem = (struct elem *)atMalloc(sizeof(struct elem)); - Elem->Length = Length; - Elem->PolynomA = PolynomA; - Elem->PolynomB = PolynomB; - Elem->MaxOrder = MaxOrder; - Elem->NumIntSteps = NumIntSteps; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->R1 = R1; - Elem->R2 = R2; - Elem->T1 = T1; - Elem->T2 = T2; - Elem->EApertures = EApertures; - Elem->RApertures = RApertures; - Elem->KickAngle = KickAngle; - } - multipole_pass(r_in, Elem->Length, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, num_particles); - return Elem; -} - -MODULE_DEF(ExactMultipolePass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - - double Length = atGetDouble(ElemData, "Length"); check_error(); - double *PolynomA = atGetDoubleArray(ElemData, "PolynomA"); check_error(); - double *PolynomB = atGetDoubleArray(ElemData, "PolynomB"); check_error(); - int MaxOrder = atGetLong(ElemData, "MaxOrder"); check_error(); - int NumIntSteps = atGetLong(ElemData, "NumIntSteps"); check_error(); - /*optional fields*/ - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); - double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); - double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); - double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); - double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); - double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); - double *KickAngle = atGetOptionalDoubleArray(ElemData, "KickAngle"); check_error(); - - if (NumIntSteps <= 0) { - atError("NumIntSteps must be positive"); check_error(); - } - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - multipole_pass(r_in, Length, PolynomA, PolynomB, MaxOrder, NumIntSteps, - FringeQuadEntrance, FringeQuadExit, - T1, T2, R1, R2, - RApertures, EApertures, - KickAngle, Scaling, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(5, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - if (nlhs > 1) { - /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(10, 1); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - } - } else { - mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); - } -} -#endif /*MATLAB_MEX_FILE*/ +#include "magnet_template.h" diff --git a/atintegrators/ExactMultipoleRadPass.c b/atintegrators/ExactMultipoleRadPass.c index e4a2f1a946..1018ea8d25 100644 --- a/atintegrators/ExactMultipoleRadPass.c +++ b/atintegrators/ExactMultipoleRadPass.c @@ -1,254 +1,10 @@ -#include "atelem.c" -#include "atlalib.c" -#include "diff_exactdrift.c" -#include "diff_str_exactkick.c" -#include "exactmultipolefringe.c" +#define MAGNET_PASS ExactMultipoleRadPass +#define INTEGRATOR_6 +#define RADIATION +#define DIFFUSION -struct elem { - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - /* Optional fields */ - double Energy; - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_exact.h" +#include "kick_exactkn.h" +#include "straight_multipole.h" -static void multipole_pass(double *r, double le, double *A, double *B, - int max_order, int num_int_steps, - int FringeQuadEntrance, int FringeQuadExit, /* 0 (no fringe), else */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double gamma, int num_particles, - double *bdiff) -{ - double SL = le / num_int_steps; - double L1 = SL * DRIFT1; - double L2 = SL * DRIFT2; - double K1 = SL * KICK1; - double K2 = SL * KICK2; - double B0 = B[0]; - double A0 = A[0]; - double rad_const = RAD_CONST*pow(gamma, 3); - double diff_const = DIF_CONST*pow(gamma, 5); - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0]) / le; - A[0] += sin(KickAngle[1]) / le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) \ - default(none) \ - shared(r, num_particles, R1, T1, R2, T2, \ - RApertures, EApertures, bdiff, \ - A, B, L1, L2, K1, K2, max_order, num_int_steps, \ - rad_const, diff_const, \ - FringeQuadEntrance, FringeQuadExit, \ - scaling, le) - for (int c = 0; c < num_particles; c++) { /*Loop over particles */ - double *r6 = r + c * 6; - if (!atIsNaN(r6[0])) { - - /* Check for change of reference momentum */ - if (scaling != 1.0) ATChangePRef(r6, scaling); - - /* misalignment at entrance */ - if (T1) ATaddvv(r6, T1); - if (R1) ATmultmv(r6, R1); - - /* Check physical apertures at the entrance of the magnet */ - if (RApertures) checkiflostRectangularAp(r6, RApertures); - if (EApertures) checkiflostEllipticalAp(r6, EApertures); - - /* Fringe field effect */ - if (FringeQuadEntrance) multipole_fringe(r6, le, A, B, max_order, 1.0, 0); - - /* integrator */ - for (int m = 0; m < num_int_steps; m++) { /* Loop over slices */ - diff_exactdrift(r6, L1, bdiff); - diff_str_exactkick(r6, A, B, max_order, K1, rad_const, diff_const, bdiff); - diff_exactdrift(r6, L2, bdiff); - diff_str_exactkick(r6, A, B, max_order, K2, rad_const, diff_const, bdiff); - diff_exactdrift(r6, L2, bdiff); - diff_str_exactkick(r6, A, B, max_order, K1, rad_const, diff_const, bdiff); - diff_exactdrift(r6, L1, bdiff); - } - - /* Convert absolute path length to path lengthening */ - r6[5] -= le; - - /* Fringe field effect */ - if (FringeQuadExit) multipole_fringe(r6, le, A, B, max_order, -1.0, 0); - - /* Check physical apertures at the exit of the magnet */ - if (RApertures) checkiflostRectangularAp(r6, RApertures); - if (EApertures) checkiflostEllipticalAp(r6, EApertures); - - /* Misalignment at exit */ - if (R2) ATmultmv(r6, R2); - if (T2) ATaddvv(r6, T2); - - /* Check for change of reference momentum */ - if (scaling != 1.0) ATChangePRef(r6, 1.0/scaling); - } - } - /* Remove corrector component in polynomial coefficients */ - B[0] = B0; - A[0] = A0; -} - -#if defined(MATLAB_MEX_FILE) || defined(PYAT) -ExportMode struct elem *trackFunction(const atElem *ElemData, struct elem *Elem, - double *r_in, int num_particles, - struct parameters *Param) -{ - double gamma; - double *bdiff = Param->bdiff; - - if (!Elem) { - double Length = atGetDouble(ElemData, "Length"); check_error(); - double *PolynomA = atGetDoubleArray(ElemData, "PolynomA"); check_error(); - double *PolynomB = atGetDoubleArray(ElemData, "PolynomB"); check_error(); - int MaxOrder = atGetLong(ElemData, "MaxOrder"); check_error(); - int NumIntSteps = atGetLong(ElemData, "NumIntSteps"); check_error(); - /*optional fields*/ - double Energy=atGetOptionalDouble(ElemData,"Energy",Param->energy); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); - double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); - double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); - double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); - double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); - double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); - double *KickAngle = atGetOptionalDoubleArray(ElemData, "KickAngle"); check_error(); - - if (NumIntSteps <= 0) { - atError("NumIntSteps must be positive"); check_error(); - } - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); - if (Energy == 0) { - atError("Energy needs to be defined. Check lattice parameters or pass method options.\n"); - check_error(); - } - - Elem = (struct elem *)atMalloc(sizeof(struct elem)); - Elem->Length = Length; - Elem->PolynomA = PolynomA; - Elem->PolynomB = PolynomB; - Elem->MaxOrder = MaxOrder; - Elem->NumIntSteps = NumIntSteps; - Elem->Energy=Energy; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->R1 = R1; - Elem->R2 = R2; - Elem->T1 = T1; - Elem->T2 = T2; - Elem->EApertures = EApertures; - Elem->RApertures = RApertures; - Elem->KickAngle = KickAngle; - } - gamma = atGamma(Param->energy, Elem->Energy, Param->rest_energy); check_error(); - - multipole_pass(r_in, Elem->Length, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, gamma, num_particles, bdiff); - return Elem; -} - -MODULE_DEF(ExactMultipoleRadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double *r_in; - double Gamma; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - - double Length = atGetDouble(ElemData, "Length"); check_error(); - double *PolynomA = atGetDoubleArray(ElemData, "PolynomA"); check_error(); - double *PolynomB = atGetDoubleArray(ElemData, "PolynomB"); check_error(); - int MaxOrder = atGetLong(ElemData, "MaxOrder"); check_error(); - int NumIntSteps = atGetLong(ElemData, "NumIntSteps"); check_error(); - /*optional fields*/ - double Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); - double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); - double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); - double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); - double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); - double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); - double *KickAngle = atGetOptionalDoubleArray(ElemData, "KickAngle"); check_error(); - - if (NumIntSteps <= 0) { - atError("NumIntSteps must be positive"); check_error(); - } - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - Gamma = atGamma(Energy, Energy, rest_energy); - r_in = mxGetDoubles(plhs[0]); - - multipole_pass(r_in, Length, PolynomA, PolynomB, MaxOrder, NumIntSteps, - FringeQuadEntrance, FringeQuadExit, - T1, T2, R1, R2, - RApertures, EApertures, - KickAngle, Scaling, Gamma, num_particles, NULL); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(5, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - if (nlhs > 1) { - /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(11, 1); - mxSetCell(plhs[1], i0++, mxCreateString("Energy")); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - } - } else { - mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); - } -} -#endif /*MATLAB_MEX_FILE*/ +#include "magnet_template.h" diff --git a/atintegrators/ExactRectBendPass.c b/atintegrators/ExactRectBendPass.c index f8ab7a8596..a0681e9ad4 100644 --- a/atintegrators/ExactRectBendPass.c +++ b/atintegrators/ExactRectBendPass.c @@ -1,309 +1,28 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "driftkick.c" /* strthinkick.c */ -#include "exactbend.c" -#include "exactbendfringe.c" -#include "exactmultipolefringe.c" - -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - /* Optional fields */ - double Scaling; - int FringeBendEntrance; - int FringeBendExit; - int FringeQuadEntrance; - int FringeQuadExit; - double gK; - double x0ref; - double refdz; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; - -static void ExactRectangularBend(double *r, double le, double bending_angle, - double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - int FringeQuadEntrance, int FringeQuadExit, - double gK, double x0ref, double refdz, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, int num_particles) -{ - double irho = bending_angle / le; - double phi2 = 0.5 * bending_angle; - double LR = phi2 < 1.e-10 ? le : le *sin(phi2) / phi2; - double SL = LR/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gK,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - entrance_angle,exit_angle,x0ref,refdz,\ - FringeBendEntrance,FringeBendExit,FringeQuadEntrance,FringeQuadExit,\ - LR,le,phi2) - for (int c = 0; c=0; i--) { - if ((PolynomA[i] != 0.0) || (PolynomB[i] != 0.0)) { - atError("NumIntSteps == 0 not allowed with multipoles"); check_error(); - } - } - } - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->gK=gK; - Elem->x0ref=x0ref; - Elem->refdz=refdz; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - ExactRectangularBend(r_in, Elem->Length, Elem->BendingAngle, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->gK,Elem->x0ref,Elem->refdz, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, num_particles); - return Elem; -} - -MODULE_DEF(ExactRectBendPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - double Length=atGetDouble(ElemData,"Length"); check_error(); - double *PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - double *PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - int MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - int NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle",0.0); check_error(); - double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double x0ref=atGetOptionalDouble(ElemData,"X0ref", 0.0); check_error(); - double refdz=atGetOptionalDouble(ElemData,"RefDZ", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps == 0) { - for (int i=MaxOrder; i>=0; i--) { - if ((PolynomA[i] != 0.0) || (PolynomB[i] != 0.0)) { - atError("NumIntSteps == 0 not allowed with multipoles"); check_error(); - } - } - } - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - ExactRectangularBend(r_in, Length, BendingAngle, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit, - gK, x0ref, refdz, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(8, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - mxSetCell(plhs[0], i0++, mxCreateString("BendingAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("EntranceAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("ExitAngle")); - if (nlhs>1) { /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(15, 1); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendExit")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("gK")); - mxSetCell(plhs[1], i1++, mxCreateString("X0ref")); - mxSetCell(plhs[1], i1++, mxCreateString("RefDZ")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#define MAGNET_PASS ExactRectBendPass +#define INTEGRATOR_6 + +#include "drift_exactstrbend.h" +#include "kick_exactkn.h" +#include "straight_dipole.h" + +#define INTEGRATOR(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + if (num_int_steps == 0) \ + drift(r6, slength, irho, bdiff); \ + else \ + integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); + +#define CHECK_NSTEPS \ + int ForceSplit = atGetOptionalLong(ElemData,"ForceSplit",0); check_error(); \ + int nsteps = ForceSplit ? NumIntSteps : 0; \ + for (int i=MaxOrder; i>=0; i--) { \ + if ((PolynomA[i] != 0.0) || (PolynomB[i] != 0.0)) { \ + if (NumIntSteps == 0) { \ + atError("NumIntSteps == 0 not allowed with multipoles"); check_error(); \ + } \ + nsteps = NumIntSteps; \ + break; \ + } \ + } \ + NumIntSteps=nsteps; + +#include "magnet_template.h" diff --git a/atintegrators/ExactRectBendRadPass.c b/atintegrators/ExactRectBendRadPass.c index 203385f0d6..7a984e2b8b 100644 --- a/atintegrators/ExactRectBendRadPass.c +++ b/atintegrators/ExactRectBendRadPass.c @@ -1,316 +1,9 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "exactkickrad.c" -#include "exactbend.c" -#include "exactbendfringe.c" -#include "exactmultipolefringe.c" +#define MAGNET_PASS ExactRectBendRadPass +#define INTEGRATOR_6 +#define RADIATION -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - double Energy; - /* Optional fields */ - double Scaling; - int FringeBendEntrance; - int FringeBendExit; - int FringeQuadEntrance; - int FringeQuadExit; - double gK; - double x0ref; - double refdz; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_exactstrbend.h" +#include "kick_exactkn.h" +#include "straight_dipole.h" -static void ExactRectangularBendRad(double *r, double le, double bending_angle, - double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - int FringeQuadEntrance, int FringeQuadExit, - double gK, double x0ref, double refdz, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double gamma, int num_particles) -{ - double irho = bending_angle / le; - double phi2 = 0.5 * bending_angle; - double LR = phi2 < 1.e-10 ? le : le *sin(phi2) / phi2; - double SL = LR/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - double B0 = B[0]; - double A0 = A[0]; - double rad_const = RAD_CONST*pow(gamma, 3); - double diff_const = DIF_CONST*pow(gamma, 5); - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gK,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - entrance_angle,exit_angle,x0ref,refdz,\ - FringeBendEntrance,FringeBendExit,FringeQuadEntrance,FringeQuadExit,\ - le,phi2,rad_const,diff_const) - for (int c = 0; cenergy); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double x0ref=atGetOptionalDouble(ElemData,"X0ref", 0.0); check_error(); - double refdz=atGetOptionalDouble(ElemData,"RefDZ", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps == 0) { - atError("NumIntSteps == 0 not allowed with radiation"); check_error(); - } - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->Energy=Energy; - Elem->Scaling=Scaling; - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->gK=gK; - Elem->x0ref=x0ref; - Elem->refdz=refdz; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - gamma = atGamma(Param->energy, Elem->Energy, Param->rest_energy); check_error(); - - ExactRectangularBendRad(r_in, Elem->Length, Elem->BendingAngle, - Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->gK,Elem->x0ref,Elem->refdz, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, gamma, num_particles); - return Elem; -} - -MODULE_DEF(ExactRectBendRadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double Gamma; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - double Length=atGetDouble(ElemData,"Length"); check_error(); - double *PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - double *PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - int MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - int NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle",0.0); check_error(); - double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - double Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double x0ref=atGetOptionalDouble(ElemData,"X0ref", 0.0); check_error(); - double refdz=atGetOptionalDouble(ElemData,"RefDZ", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps == 0) { - atError("NumIntSteps == 0 not allowed with radiation"); check_error(); - } - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - Gamma = atGamma(Energy, Energy, rest_energy); - r_in = mxGetDoubles(plhs[0]); - - ExactRectangularBendRad(r_in, Length, BendingAngle, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit, - gK, x0ref, refdz, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Gamma, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(8, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - mxSetCell(plhs[0], i0++, mxCreateString("BendingAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("EntranceAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("ExitAngle")); - if (nlhs>1) { /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(16, 1); - mxSetCell(plhs[1], i1++, mxCreateString("Energy")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendExit")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("gK")); - mxSetCell(plhs[1], i1++, mxCreateString("X0ref")); - mxSetCell(plhs[1], i1++, mxCreateString("RefDZ")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/ExactRectangularBendPass.c b/atintegrators/ExactRectangularBendPass.c index a91fa447b8..882b5b2654 100644 --- a/atintegrators/ExactRectangularBendPass.c +++ b/atintegrators/ExactRectangularBendPass.c @@ -1,298 +1,9 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "exactdrift.c" -#include "driftkick.c" /* strthinkick.c */ -#include "exactbendfringe.c" -#include "exactmultipolefringe.c" +#define MAGNET_PASS ExactRectangularBendPass +#define INTEGRATOR_6 +#define CURVATURE_IN_B0 -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - /* Optional fields */ - double Scaling; - int FringeBendEntrance; - int FringeBendExit; - int FringeQuadEntrance; - int FringeQuadExit; - double gK; - double x0ref; - double refdz; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_exact.h" +#include "kick_exactkn.h" +#include "straight_dipole.h" -static void ExactRectangularBend(double *r, double le, double bending_angle, - double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - int FringeQuadEntrance, int FringeQuadExit, - double gK, double x0ref, double refdz, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, int num_particles) -{ - double irho = bending_angle / le; - double phi2 = 0.5 * bending_angle; - double LR = phi2 < 1.e-10 ? le : le *sin(phi2) / phi2; - double SL = LR/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - B[0] += irho; - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gK,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - entrance_angle,exit_angle,x0ref,refdz,\ - FringeBendEntrance,FringeBendExit,FringeQuadEntrance,FringeQuadExit,\ - LR,le,phi2) - for (int c = 0; cLength=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->gK=gK; - Elem->x0ref=x0ref; - Elem->refdz=refdz; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - ExactRectangularBend(r_in, Elem->Length, Elem->BendingAngle, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->gK,Elem->x0ref,Elem->refdz, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, num_particles); - return Elem; -} - -MODULE_DEF(ExactRectangularBendPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - double Length=atGetDouble(ElemData,"Length"); check_error(); - double *PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - double *PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - int MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - int NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle",0.0); check_error(); - double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double x0ref=atGetOptionalDouble(ElemData,"X0ref", 0.0); check_error(); - double refdz=atGetOptionalDouble(ElemData,"RefDZ", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps <= 0) { - atError("NumIntSteps must be positive"); check_error(); - } - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - ExactRectangularBend(r_in, Length, BendingAngle, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit, - gK, x0ref, refdz, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(8, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - mxSetCell(plhs[0], i0++, mxCreateString("BendingAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("EntranceAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("ExitAngle")); - if (nlhs>1) { /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(15, 1); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendExit")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("gK")); - mxSetCell(plhs[1], i1++, mxCreateString("X0ref")); - mxSetCell(plhs[1], i1++, mxCreateString("RefDZ")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/ExactRectangularBendRadPass.c b/atintegrators/ExactRectangularBendRadPass.c index 66f2d9d61d..eb158fa63e 100644 --- a/atintegrators/ExactRectangularBendRadPass.c +++ b/atintegrators/ExactRectangularBendRadPass.c @@ -1,317 +1,10 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "exactdrift.c" -#include "exactkickrad.c" -#include "exactbendfringe.c" -#include "exactmultipolefringe.c" +#define MAGNET_PASS ExactRectangularBendRadPass +#define INTEGRATOR_6 +#define CURVATURE_IN_B0 +#define RADIATION -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - double Energy; - /* Optional fields */ - double Scaling; - int FringeBendEntrance; - int FringeBendExit; - int FringeQuadEntrance; - int FringeQuadExit; - double gK; - double x0ref; - double refdz; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_exact.h" +#include "kick_exactkn.h" +#include "straight_dipole.h" -static void ExactRectangularBendRad(double *r, double le, double bending_angle, - double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - int FringeQuadEntrance, int FringeQuadExit, - double gK, double x0ref, double refdz, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double gamma, int num_particles) -{ - double irho = bending_angle / le; - double phi2 = 0.5 * bending_angle; - double LR = phi2 < 1.e-10 ? le : le *sin(phi2) / phi2; - double SL = LR/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - double B0 = B[0]; - double A0 = A[0]; - double rad_const = RAD_CONST*pow(gamma, 3); - double diff_const = DIF_CONST*pow(gamma, 5); - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - B[0] += irho; - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gK,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - entrance_angle,exit_angle,x0ref,refdz,\ - FringeBendEntrance,FringeBendExit,FringeQuadEntrance,FringeQuadExit,\ - LR,le,phi2,rad_const,diff_const) - for (int c = 0; cenergy); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double x0ref=atGetOptionalDouble(ElemData,"X0ref", 0.0); check_error(); - double refdz=atGetOptionalDouble(ElemData,"RefDZ", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps <= 0) { - atError("NumIntSteps must be positive"); check_error(); - } - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->Energy=Energy; - Elem->Scaling=Scaling; - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->gK=gK; - Elem->x0ref=x0ref; - Elem->refdz=refdz; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - gamma = atGamma(Param->energy, Elem->Energy, Param->rest_energy); check_error(); - - ExactRectangularBendRad(r_in, Elem->Length, Elem->BendingAngle, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->gK,Elem->x0ref,Elem->refdz, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, gamma, num_particles); - return Elem; -} - -MODULE_DEF(ExactRectangularBendRadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double Gamma; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - double Length=atGetDouble(ElemData,"Length"); check_error(); - double *PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - double *PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - int MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - int NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle",0.0); check_error(); - double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - double Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double x0ref=atGetOptionalDouble(ElemData,"X0ref", 0.0); check_error(); - double refdz=atGetOptionalDouble(ElemData,"RefDZ", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps <= 0) { - atError("NumIntSteps must be positive"); check_error(); - } - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - Gamma = atGamma(Energy, Energy, rest_energy); - r_in = mxGetDoubles(plhs[0]); - - ExactRectangularBendRad(r_in, Length, BendingAngle, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit, - gK, x0ref, refdz, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Gamma, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(8, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - mxSetCell(plhs[0], i0++, mxCreateString("BendingAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("EntranceAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("ExitAngle")); - if (nlhs>1) { /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(16, 1); - mxSetCell(plhs[1], i1++, mxCreateString("Energy")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendExit")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("gK")); - mxSetCell(plhs[1], i1++, mxCreateString("X0ref")); - mxSetCell(plhs[1], i1++, mxCreateString("RefDZ")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/ExactSectorBendPass.c b/atintegrators/ExactSectorBendPass.c index 44b9108349..41ddc20de5 100644 --- a/atintegrators/ExactSectorBendPass.c +++ b/atintegrators/ExactSectorBendPass.c @@ -1,290 +1,28 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "driftkick.c" /* strthinkick.c */ -#include "exactbend.c" -#include "exactbendfringe.c" -#include "exactmultipolefringe.c" - -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - /* Optional fields */ - double Scaling; - int FringeBendEntrance; - int FringeBendExit; - int FringeQuadEntrance; - int FringeQuadExit; - double gK; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; - -static void ExactSectorBend(double *r, double le, double bending_angle, - double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - int FringeQuadEntrance, int FringeQuadExit, - double gK, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, int num_particles) -{ - double irho = bending_angle / le; - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gK,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - entrance_angle,exit_angle,\ - FringeBendEntrance,FringeBendExit,FringeQuadEntrance,FringeQuadExit,le) - for (int c = 0; c=0; i--) { - if ((PolynomA[i] != 0.0) || (PolynomB[i] != 0.0)) { - atError("NumIntSteps == 0 not allowed with multipoles"); check_error(); - } - } - } - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->gK=gK; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - ExactSectorBend(r_in, Elem->Length, Elem->BendingAngle, - Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->gK, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, num_particles); - return Elem; -} - -MODULE_DEF(ExactSectorBendPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - double Length=atGetDouble(ElemData,"Length"); check_error(); - double *PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - double *PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - int MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - int NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle",0.0); check_error(); - double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps == 0) { - for (int i=MaxOrder; i>=0; i--) { - if ((PolynomA[i] != 0.0) || (PolynomB[i] != 0.0)) { - atError("NumIntSteps == 0 not allowed with multipoles"); check_error(); - } - } - } - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - ExactSectorBend(r_in, Length, BendingAngle, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit, - gK, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(8, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - mxSetCell(plhs[0], i0++, mxCreateString("BendingAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("EntranceAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("ExitAngle")); - if (nlhs>1) { /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(13, 1); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendExit")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("gK")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#define MAGNET_PASS ExactSectorBendPass +#define INTEGRATOR_6 + +#include "drift_exactbend.h" +#include "kick_k1h_kn.h" +#include "curved_dipole.h" + +#define INTEGRATOR(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + if (num_int_steps == 0) \ + drift(r6, slength, irho, bdiff); \ + else \ + integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); + +#define CHECK_NSTEPS \ + int ForceSplit = atGetOptionalLong(ElemData,"ForceSplit",0); check_error(); \ + int nsteps = ForceSplit ? NumIntSteps : 0; \ + for (int i=MaxOrder; i>=0; i--) { \ + if ((PolynomA[i] != 0.0) || (PolynomB[i] != 0.0)) { \ + if (NumIntSteps == 0) { \ + atError("NumIntSteps == 0 not allowed with multipoles"); check_error(); \ + } \ + nsteps = NumIntSteps; \ + break; \ + } \ + } \ + NumIntSteps=nsteps; + +#include "magnet_template.h" diff --git a/atintegrators/ExactSectorBendQuantPass.c b/atintegrators/ExactSectorBendQuantPass.c new file mode 100644 index 0000000000..786b59f4ed --- /dev/null +++ b/atintegrators/ExactSectorBendQuantPass.c @@ -0,0 +1,10 @@ +#define MAGNET_PASS ExactSectorBendQuantPass +#define INTEGRATOR_6 +#define QUANTUM +#define NO_OMP /* because of problems with random generator and OpenMP */ + +#include "drift_exactbend.h" +#include "kick_k1h_kn.h" +#include "curved_dipole.h" + +#include "magnet_template.h" diff --git a/atintegrators/ExactSectorBendRadPass.c b/atintegrators/ExactSectorBendRadPass.c index d4ed0b06bf..9dac4ef749 100644 --- a/atintegrators/ExactSectorBendRadPass.c +++ b/atintegrators/ExactSectorBendRadPass.c @@ -1,300 +1,9 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "exactkickrad.c" -#include "exactbend.c" -#include "exactbendfringe.c" -#include "exactmultipolefringe.c" +#define MAGNET_PASS ExactSectorBendRadPass +#define INTEGRATOR_6 +#define RADIATION -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double BendingAngle; - double EntranceAngle; - double ExitAngle; - double Energy; - /* Optional fields */ - double Scaling; - int FringeBendEntrance; - int FringeBendExit; - int FringeQuadEntrance; - int FringeQuadExit; - double gK; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_exactbend.h" +#include "kick_k1h_kn.h" +#include "curved_dipole.h" -static void ExactSectorBendRad(double *r, double le, double irho, - double *A, double *B, - int max_order, int num_int_steps, - double entrance_angle, double exit_angle, - int FringeBendEntrance, int FringeBendExit, - int FringeQuadEntrance, int FringeQuadExit, - double gK, - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double gamma, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - double B0 = B[0]; - double A0 = A[0]; - double rad_const = RAD_CONST*pow(gamma, 3); - double diff_const = DIF_CONST*pow(gamma, 5); - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - irho,gK,A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - entrance_angle,exit_angle,\ - FringeBendEntrance,FringeBendExit,FringeQuadEntrance,FringeQuadExit,le,\ - rad_const, diff_const) - for (int c = 0; cenergy); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps == 0) { - atError("NumIntSteps == 0 not allowed with radiation"); check_error(); - } - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->BendingAngle=BendingAngle; - Elem->EntranceAngle=EntranceAngle; - Elem->ExitAngle=ExitAngle; - /*optional fields*/ - Elem->Energy=Energy; - Elem->Scaling=Scaling; - Elem->FringeBendEntrance=FringeBendEntrance; - Elem->FringeBendExit=FringeBendExit; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->gK=gK; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - irho = Elem->BendingAngle/Elem->Length; - gamma = atGamma(Param->energy, Elem->Energy, Param->rest_energy); check_error(); - - ExactSectorBendRad(r_in, Elem->Length, irho, - Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, - Elem->FringeBendEntrance,Elem->FringeBendExit, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->gK, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, gamma, num_particles); - return Elem; -} - -MODULE_DEF(ExactSectorBendRadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double irho; - double Gamma; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - double Length=atGetDouble(ElemData,"Length"); check_error(); - double *PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - double *PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - int MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - int NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle",0.0); check_error(); - double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); - double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); - /*optional fields*/ - double Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",1); check_error(); - int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",1); check_error(); - int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - double gK=atGetOptionalDouble(ElemData,"gK", 0.0); check_error(); - double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - if (NumIntSteps == 0) { - atError("NumIntSteps == 0 not allowed with radiation"); check_error(); - } - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - irho = BendingAngle/Length; - Gamma = atGamma(Energy, Energy, rest_energy); - r_in = mxGetDoubles(plhs[0]); - - ExactSectorBendRad(r_in, Length, irho, PolynomA, PolynomB, - MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, - FringeBendEntrance, FringeBendExit, - FringeQuadEntrance, FringeQuadExit, - gK, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Gamma, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(9, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); - mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); - mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); - mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); - mxSetCell(plhs[0], i0++, mxCreateString("BendingAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("EntranceAngle")); - mxSetCell(plhs[0], i0++, mxCreateString("ExitAngle")); - if (nlhs>1) { /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(14, 1); - mxSetCell(plhs[1], i1++, mxCreateString("Energy")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeBendExit")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], i1++, mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], i1++, mxCreateString("gK")); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("KickAngle")); - mxSetCell(plhs[1], i1++, mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/IdTablePass.c b/atintegrators/IdTablePass.c index a2863fb8b4..e30677b0fd 100644 --- a/atintegrators/IdTablePass.c +++ b/atintegrators/IdTablePass.c @@ -12,6 +12,7 @@ #include "atelem.c" #include "atlalib.c" +#include "drift_expanded.h" #include "interpolate.c" struct elem { @@ -77,7 +78,7 @@ void IdKickMapModelPass(double *r, double le, double *xkick1, double *ykick1, checkiflostRectangularAp(r6, limitsptr); /*Tracking in the main body*/ for (ns=0; ns OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - A,B,L1,L2,K1,K2,max_order,num_int_steps,scaling,\ - FringeQuadEntrance,useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0,fringeIntP0) - for (int c = 0; cLength=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - StrMPoleSymplectic4Pass(r_in, Elem->Length, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, num_particles); - return Elem; -} - -MODULE_DEF(StrMPoleSymplectic4Pass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - double Length, Scaling; - int MaxOrder, NumIntSteps, FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - /*optional fields*/ - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - StrMPoleSymplectic4Pass(r_in, Length, PolynomA, PolynomB, - MaxOrder, NumIntSteps, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(5,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("PolynomA")); - mxSetCell(plhs[0],2,mxCreateString("PolynomB")); - mxSetCell(plhs[0],3,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],4,mxCreateString("NumIntSteps")); - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(12,1); - mxSetCell(plhs[1], 0,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], 1,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], 2,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1], 3,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1], 4,mxCreateString("T1")); - mxSetCell(plhs[1], 5,mxCreateString("T2")); - mxSetCell(plhs[1], 6,mxCreateString("R1")); - mxSetCell(plhs[1], 7,mxCreateString("R2")); - mxSetCell(plhs[1], 8,mxCreateString("RApertures")); - mxSetCell(plhs[1], 9,mxCreateString("EApertures")); - mxSetCell(plhs[1],10,mxCreateString("KickAngle")); - mxSetCell(plhs[1],11,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/StrMPoleSymplectic4QuantPass.c b/atintegrators/StrMPoleSymplectic4QuantPass.c index d2bcbe79b9..1cdae7dec0 100644 --- a/atintegrators/StrMPoleSymplectic4QuantPass.c +++ b/atintegrators/StrMPoleSymplectic4QuantPass.c @@ -1,302 +1,10 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "atquantlib.c" -#include "driftkick.c" /* fastdrift.c, strthinkick.c */ -#include "quadfringe.c" /* QuadFringePassP, QuadFringePassN */ +#define MAGNET_PASS StrMPoleSymplectic4QuantPass +#define INTEGRATOR_4 +#define QUANTUM +#define NO_OMP /* because of problems with random generator and OpenMP */ -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double Energy; - /* Optional fields */ - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *fringeIntM0; - double *fringeIntP0; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_fast.h" /* drift */ +#include "kick_kn.h" /* kick */ +#include "straight_multipole.h" -void StrMPoleSymplectic4QuantPass(double *r, double le, double *A, double *B, - int max_order, int num_int_steps, - int FringeQuadEntrance, int FringeQuadExit, /* 0 (no fringe), 1 (lee-whiting) or 2 (lee-whiting+elegant-like) */ - double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ - double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double E0, - pcg32_random_t* rng, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useLinFrEleEntrance = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadEntrance==2); - bool useLinFrEleExit = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadExit==2); - double qe = 1.60217733e-19; - double epsilon0 = 8.854187817e-12; - double clight = 2.99792458e8; - double emass = 510998.9461; /* electron mass in eV */ /* 9.10938188e-31; in kg*/ - double hbar = 1.054571726e-34; - double pi = 3.14159265358979; - double alpha0 = qe * qe / (4 * pi * epsilon0 * hbar * clight); - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } -/* The behaviour of random generators with OpenMP is doubtful. OpenMP disabled until - it's understood - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures, \ - A,B,L1,L2,K1,K2,max_order,num_int_steps,rng,scaling, \ - FringeQuadEntrance, useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0,fringeIntP0, \ - emass,E0,hbar,clight,alpha0,qe,SL) -*/ - for (int c = 0; cenergy); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->Energy=Energy; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - energy = atEnergy(Param->energy, Elem->Energy); check_error(); - - StrMPoleSymplectic4QuantPass(r_in, Elem->Length, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, - energy, Param->thread_rng, num_particles); - return Elem; -} - -MODULE_DEF(StrMPoleSymplectic4QuantPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double *r_in; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - double Length, Energy, Scaling; - int MaxOrder, NumIntSteps, FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - - StrMPoleSymplectic4QuantPass(r_in, Length, PolynomA, PolynomB, - MaxOrder, NumIntSteps, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Energy, &pcg32_global, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(6, 1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("PolynomA")); - mxSetCell(plhs[0],2,mxCreateString("PolynomB")); - mxSetCell(plhs[0],3,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],4,mxCreateString("NumIntSteps")); - mxSetCell(plhs[0],5,mxCreateString("Energy")); - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(12,1); - mxSetCell(plhs[1], 0,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], 1,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], 2,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1], 3,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1], 4,mxCreateString("T1")); - mxSetCell(plhs[1], 5,mxCreateString("T2")); - mxSetCell(plhs[1], 6,mxCreateString("R1")); - mxSetCell(plhs[1], 7,mxCreateString("R2")); - mxSetCell(plhs[1], 8,mxCreateString("RApertures")); - mxSetCell(plhs[1], 9,mxCreateString("EApertures")); - mxSetCell(plhs[1],10,mxCreateString("KickAngle")); - mxSetCell(plhs[1],11,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/StrMPoleSymplectic4RadPass.c b/atintegrators/StrMPoleSymplectic4RadPass.c index 546ad8b787..2f7f3c059e 100644 --- a/atintegrators/StrMPoleSymplectic4RadPass.c +++ b/atintegrators/StrMPoleSymplectic4RadPass.c @@ -1,263 +1,10 @@ -#include "atelem.c" -#include "atlalib.c" -#include "diff_str_kick.c" -#include "diff_drift.c" -#include "quadfringe.c" /* QuadFringePassP, QuadFringePassN */ +#define MAGNET_PASS StrMPoleSymplectic4RadPass +#define INTEGRATOR_4 +#define RADIATION +#define DIFFUSION -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double Energy; - /* Optional fields */ - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *fringeIntM0; - double *fringeIntP0; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; +#include "drift_expanded.h" +#include "kick_kn.h" +#include "straight_multipole.h" -void StrMPoleSymplectic4RadPass(double *r, double le, double *A, double *B, - int max_order, int num_int_steps, - int FringeQuadEntrance, int FringeQuadExit, /* 0 (no fringe), 1 (lee-whiting) or 2 (lee-whiting+elegant-like) */ - double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ - double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double gamma, int num_particles, - double *bdiff) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useLinFrEleEntrance = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadEntrance==2); - bool useLinFrEleExit = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadExit==2); - double B0 = B[0]; - double A0 = A[0]; - double rad_const = RAD_CONST*pow(gamma, 3); - double diff_const = DIF_CONST*pow(gamma, 5); - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,bdiff,\ - A,B,L1,L2,K1,K2,max_order,num_int_steps,rad_const, diff_const,scaling,\ - FringeQuadEntrance,useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0,fringeIntP0) - for (int c = 0; cbdiff; - if (!Elem) { - double Length, Energy, Scaling; - int MaxOrder, NumIntSteps, FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",Param->energy); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - /* Check energy */ - Energy = atEnergy(Param->energy, Energy); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->Energy=Energy; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - gamma = atGamma(Param->energy, Elem->Energy, Param->rest_energy); check_error(); - - StrMPoleSymplectic4RadPass(r_in, Elem->Length, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, gamma, num_particles, bdiff); - return Elem; -} - -MODULE_DEF(StrMPoleSymplectic4RadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(MATLAB_MEX_FILE) -void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) -{ - if (nrhs >= 2) { - double rest_energy = 0.0; - double charge = -1.0; - double *r_in; - double Gamma; - const mxArray *ElemData = prhs[0]; - int num_particles = mxGetN(prhs[1]); - double Length, Energy, Scaling; - int MaxOrder, NumIntSteps, FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - /*optional fields*/ - Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - Gamma = atGamma(Energy, Energy, rest_energy); - r_in = mxGetDoubles(plhs[0]); - - StrMPoleSymplectic4RadPass(r_in, Length, PolynomA, PolynomB, - MaxOrder, NumIntSteps, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Gamma, num_particles, NULL); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(6,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("PolynomA")); - mxSetCell(plhs[0],2,mxCreateString("PolynomB")); - mxSetCell(plhs[0],3,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],4,mxCreateString("NumIntSteps")); - mxSetCell(plhs[0],5,mxCreateString("Energy")); - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(12,1); - mxSetCell(plhs[1], 0,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], 1,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], 2,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1], 3,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1], 4,mxCreateString("T1")); - mxSetCell(plhs[1], 5,mxCreateString("T2")); - mxSetCell(plhs[1], 6,mxCreateString("R1")); - mxSetCell(plhs[1], 7,mxCreateString("R2")); - mxSetCell(plhs[1], 8,mxCreateString("RApertures")); - mxSetCell(plhs[1], 9,mxCreateString("EApertures")); - mxSetCell(plhs[1],10,mxCreateString("KickAngle")); - mxSetCell(plhs[1],11,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ +#include "magnet_template.h" diff --git a/atintegrators/StrOldRadPass.c b/atintegrators/StrOldRadPass.c deleted file mode 100644 index ae97dc50b3..0000000000 --- a/atintegrators/StrOldRadPass.c +++ /dev/null @@ -1,241 +0,0 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "driftkickrad.c" /* strthinkickrad.c */ -#include "quadfringe.c" /* QuadFringePassP, QuadFringePassN */ - -struct elem -{ - double Length; - double *PolynomA; - double *PolynomB; - int MaxOrder; - int NumIntSteps; - double Energy; - /* Optional fields */ - double Scaling; - int FringeQuadEntrance; - int FringeQuadExit; - double *fringeIntM0; - double *fringeIntP0; - double *R1; - double *R2; - double *T1; - double *T2; - double *RApertures; - double *EApertures; - double *KickAngle; -}; - -void StrOldRadPass(double *r, double le, double *A, double *B, - int max_order, int num_int_steps, - int FringeQuadEntrance, int FringeQuadExit, /* 0 (no fringe), 1 (lee-whiting) or 2 (lee-whiting+elegant-like) */ - double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ - double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ - double *T1, double *T2, - double *R1, double *R2, - double *RApertures, double *EApertures, - double *KickAngle, double scaling, double E0, int num_particles) -{ - double SL = le/num_int_steps; - double L1 = SL*DRIFT1; - double L2 = SL*DRIFT2; - double K1 = SL*KICK1; - double K2 = SL*KICK2; - bool useLinFrEleEntrance = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadEntrance==2); - bool useLinFrEleExit = (fringeIntM0 != NULL && fringeIntP0 != NULL && FringeQuadExit==2); - double B0 = B[0]; - double A0 = A[0]; - - if (KickAngle) { /* Convert corrector component to polynomial coefficients */ - B[0] -= sin(KickAngle[0])/le; - A[0] += sin(KickAngle[1])/le; - } - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,R1,T1,R2,T2,RApertures,EApertures,\ - A,B,L1,L2,K1,K2,max_order,num_int_steps,E0,scaling,\ - FringeQuadEntrance,useLinFrEleEntrance,FringeQuadExit,useLinFrEleExit,fringeIntM0,fringeIntP0) - for (int c = 0; cenergy); check_error(); - /*optional fields*/ - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - Elem = (struct elem*)atMalloc(sizeof(struct elem)); - Elem->Length=Length; - Elem->PolynomA=PolynomA; - Elem->PolynomB=PolynomB; - Elem->MaxOrder=MaxOrder; - Elem->NumIntSteps=NumIntSteps; - Elem->Energy=Energy; - /*optional fields*/ - Elem->Scaling=Scaling; - Elem->FringeQuadEntrance=FringeQuadEntrance; - Elem->FringeQuadExit=FringeQuadExit; - Elem->fringeIntM0=fringeIntM0; - Elem->fringeIntP0=fringeIntP0; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - Elem->KickAngle=KickAngle; - } - StrOldRadPass(r_in, Elem->Length, Elem->PolynomA, Elem->PolynomB, - Elem->MaxOrder, Elem->NumIntSteps, - Elem->FringeQuadEntrance, Elem->FringeQuadExit, - Elem->fringeIntM0, Elem->fringeIntP0, - Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, - Elem->KickAngle, Elem->Scaling, Elem->Energy, num_particles); - return Elem; -} - -MODULE_DEF(StrOldRadPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - double Length, Energy, Scaling; - int MaxOrder, NumIntSteps, FringeQuadEntrance, FringeQuadExit; - double *PolynomA, *PolynomB, *R1, *R2, *T1, *T2, *EApertures, *RApertures, *fringeIntM0, *fringeIntP0, *KickAngle; - if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); - - Length=atGetDouble(ElemData,"Length"); check_error(); - PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); - PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); - MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); - NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); - Energy=atGetDouble(ElemData,"Energy"); check_error(); - /*optional fields*/ - Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); - FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); - FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); - fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); - fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); - - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - StrOldRadPass(r_in, Length, PolynomA, PolynomB, - MaxOrder, NumIntSteps, - FringeQuadEntrance, FringeQuadExit, - fringeIntM0, fringeIntP0, - T1, T2, R1, R2, RApertures, EApertures, - KickAngle, Scaling, Energy, num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(6,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("PolynomA")); - mxSetCell(plhs[0],2,mxCreateString("PolynomB")); - mxSetCell(plhs[0],3,mxCreateString("MaxOrder")); - mxSetCell(plhs[0],4,mxCreateString("NumIntSteps")); - mxSetCell(plhs[0],5,mxCreateString("Energy")); - if (nlhs>1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(12,1); - mxSetCell(plhs[1], 0,mxCreateString("FringeQuadEntrance")); - mxSetCell(plhs[1], 1,mxCreateString("FringeQuadExit")); - mxSetCell(plhs[1], 2,mxCreateString("fringeIntM0")); - mxSetCell(plhs[1], 3,mxCreateString("fringeIntP0")); - mxSetCell(plhs[1], 4,mxCreateString("T1")); - mxSetCell(plhs[1], 5,mxCreateString("T2")); - mxSetCell(plhs[1], 6,mxCreateString("R1")); - mxSetCell(plhs[1], 7,mxCreateString("R2")); - mxSetCell(plhs[1], 8,mxCreateString("RApertures")); - mxSetCell(plhs[1], 9,mxCreateString("EApertures")); - mxSetCell(plhs[1],10,mxCreateString("KickAngle")); - mxSetCell(plhs[1],11,mxCreateString("FieldScaling")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /* MATLAB_MEX_FILE */ diff --git a/atintegrators/TestRandomPass.c b/atintegrators/TestRandomPass.c index 2b3163ca49..0cf9715fb4 100644 --- a/atintegrators/TestRandomPass.c +++ b/atintegrators/TestRandomPass.c @@ -43,7 +43,7 @@ static void RandomPass(double *r_in, shared(r_in, num_particles, common_val, thread_rng) for (int c = 0; c OMP_PARTICLE_THRESHOLD) default(none) \ - shared(r,num_particles,A,B,max_order,bax,bay,T1,T2,R1,R2,EApertures,RApertures,scaling) + shared(r,num_particles,A0,B0,A,B,max_order,bax,bay,T1,T2,R1,R2,EApertures,RApertures,scaling) for (int c = 0; c= 1) markaslost(r6,5); } +#endif /*ATLALIB_H*/ diff --git a/atintegrators/atphyslib.c b/atintegrators/atphyslib.c deleted file mode 100644 index 3d8a1e7677..0000000000 --- a/atintegrators/atphyslib.c +++ /dev/null @@ -1,158 +0,0 @@ -/* File: atphyslib.c - * Common physics functions for Accelerator Toolbox - * A.Terebilo 10/28/04 - * - * functions edge_fringe2A and edge_fringe2B were added by Xiaobiao Huang, August 2009 - * - * Two additional methods for bending magnet fringe fields added, February 2017 - * method 1 legacy version Brown First Order - * Version 2 SOLEIL close to second order of Brown - * Version 3 THOMX - */ - -#include - -static void edge_fringe_entrance(double* r, double inv_rho, double edge_angle, - double fint, double gap, int method) -{ - /* method 0 no fringe field - * method 1 legacy version Brown First Order - * method 2 SOLEIL close to second order of Brown - * method 3 THOMX - */ - double fringecorr, fx, fy; - /* Fringe field correction */ - if ((fint==0.0) || (gap==0.0) || (method==0)) - fringecorr = 0.0; - else { - register double sedge = sin(edge_angle); - register double cedge = cos(edge_angle); - fringecorr = inv_rho*gap*fint*(1+sedge*sedge)/cedge; - } - - /* Edge angle focusing */ - fx = inv_rho*tan(edge_angle); - if (method==1) - fy = inv_rho*tan(edge_angle-fringecorr/(1+r[4])); - else if (method==2) - fy = inv_rho*tan(edge_angle-fringecorr/(1+r[4]))/(1+r[4]); - else if (method==3) - fy = inv_rho*tan(edge_angle-fringecorr+r[1]/(1+r[4])); - else /* fall back to legacy version */ - fy = inv_rho*tan(edge_angle-fringecorr/(1+r[4])); - - r[1]+=r[0]*fx; - r[3]-=r[2]*fy; -} - -static void edge_fringe_exit(double* r, double inv_rho, double edge_angle, - double fint, double gap, int method) -{ - /* method 0 no fringe field - * method 1 legacy version Brown First Order - * method 2 SOLEIL close to second order of Brown - * method 3 THOMX - */ - /* Fringe field correction */ - double fringecorr, fx, fy; - if ((fint==0.0) || (gap==0.0) || (method==0)) - fringecorr = 0.0; - else { - register double sedge = sin(edge_angle); - register double cedge = cos(edge_angle); - fringecorr = inv_rho*gap*fint*(1+sedge*sedge)/cedge; - } - - /* Edge angle focusing */ - fx = inv_rho*tan(edge_angle); - if (method==1) - fy = inv_rho*tan(edge_angle-fringecorr/(1+r[4])); - else if (method==2) - fy = inv_rho*tan(edge_angle-fringecorr/(1+r[4]))/(1+r[4]); - else if (method==3) - fy = inv_rho*tan(edge_angle-fringecorr-r[1]/(1+r[4])); - else /* fall back to legacy version */ - fy = inv_rho*tan(edge_angle-fringecorr/(1+r[4])); - - r[1]+=r[0]*fx; - r[3]-=r[2]*fy; -} - - -static void edge_fringe2A(double* r, double inv_rho, double edge_angle, double fint, double gap,double h1,double K1) -{ /* Entrance Fringe field transport map to second order in dipoles with fringe field */ - double fx = inv_rho*tan(edge_angle); - double dpsi = inv_rho*gap*fint*(1+sin(edge_angle)*sin(edge_angle))/cos(edge_angle); /* /(1+r[4]); */ - double psi_bar = edge_angle-dpsi; - double fy = inv_rho*tan(psi_bar); - double h = inv_rho; - double tpsi=tan(edge_angle), tpsib=tan(psi_bar); - double spsi=1.0/cos(edge_angle); /* spsib=1.0/cos(psi_bar) */ - double T111,T234,T414, T212,T313, T133,T423,T211,T233,T413; - - double r0=r[0],r2=r[2],r1=r[1]; - T111 = -0.5*h*tpsi*tpsi; - /* T234= -0.5*h*tpsi*tpsib; */ - T234= -0.5*h*tpsi*tpsi; - T414=T234; - T212 = -T111; - T313 = -T234; - T133 = 0.5*h*spsi*spsi; T423=-T133; - T211 = 0.5*h*h1*spsi*spsi*spsi + K1*tpsi; - T233 = -0.5*h*h1*spsi*spsi*spsi -K1*tpsi+0.5*h*h*tpsi*(tpsib*tpsib+spsi*spsi); - T413 = -0.5*h*h1*spsi*spsi*spsi -K1*tpsi; /*-0.5*h*h*tpsi*(spsi*spsi+tpsib*tpsib);*/ - - r[0] += T111*r[0]*r[0]+T133*r[2]*r[2]; - r[1] += r0*fx + 2*T212*r0*r[1]+2*T234*r[2]*r[3]+T211*r0*r0+T233*r[2]*r[2] ; - r[2] += 2*T313*r0*r[2]; - r[3] += -r2*fy + 2*T414*r0*r[3]+2*T413*r0*r2+2*T423*r1*r2 ; - -} - -static void edge_fringe2B(double* r, double inv_rho, double edge_angle, double fint, double gap,double h2,double K1) -{ /* Exit Fringe field transport map to second order in dipoles with fringe field */ - double fx = inv_rho*tan(edge_angle); - double dpsi = inv_rho*gap*fint*(1+sin(edge_angle)*sin(edge_angle))/cos(edge_angle); /* /(1+r[4]); */ - double psi_bar = edge_angle-dpsi; - double fy = inv_rho*tan(psi_bar); - double h = inv_rho; - double tpsi=tan(edge_angle), tpsib=tan(psi_bar); - double spsi=1.0/cos(edge_angle); /* spsib=1.0/cos(psi_bar) */ - double T111,T234,T414, T212,T313, T133,T423,T211,T233,T413; - - double r0=r[0],r2=r[2],r1=r[1]; - T111 = 0.5*h*tpsi*tpsi; - /* T234= 0.5*h*tpsi*tpsib; */ - T234= 0.5*h*tpsi*tpsi; - T414=T234; - T212 = -T111; - T313 = -T234; - T133 = -0.5*h*spsi*spsi; T423=-T133; - T211 = 0.5*h*h2*spsi*spsi*spsi +K1*tpsi-0.5*h*h*tpsi*tpsi*tpsi; - T233 = -0.5*h*h2*spsi*spsi*spsi -K1*tpsi-0.5*h*h*tpsi*tpsib*tpsib; - T413 = -0.5*h*h2*spsi*spsi*spsi -K1*tpsi+0.5*h*h*tpsi*(spsi*spsi); - - r[0] += T111*r[0]*r[0]+T133*r[2]*r[2]; - r[1] += r0*fx + 2*T212*r0*r[1]+2*T234*r[2]*r[3]+T211*r0*r0+T233*r[2]*r[2] ; - r[2] += 2*T313*r0*r[2]; - r[3] += -r2*fy + 2*T414*r0*r[3]+2*T413*r0*r2+2*T423*r1*r2 ; - -} - -static void edge(double* r, double inv_rho, double edge_angle) -{ /* Edge focusing in dipoles with hard-edge field */ - double psi = inv_rho*tan(edge_angle); - - r[1]+=r[0]*psi; - r[3]-=r[2]*psi; -} - - -static void edge_fringe(double* r, double inv_rho, double edge_angle, double fint, double gap) -{ /* Edge focusing in dipoles with fringe field */ - double fx = inv_rho*tan(edge_angle); - double psi_bar = edge_angle-inv_rho*gap*fint*(1+sin(edge_angle)*sin(edge_angle))/cos(edge_angle)/(1+r[4]); - double fy = inv_rho*tan(psi_bar); - r[1]+=r[0]*fx; - r[3]-=r[2]*fy; -} diff --git a/atintegrators/attrackfunc.c b/atintegrators/attrackfunc.c index c2be65e83a..2d2de5c83f 100644 --- a/atintegrators/attrackfunc.c +++ b/atintegrators/attrackfunc.c @@ -1,6 +1,6 @@ #include #include "atelem.c" -#include "driftkickrad.c" +#include "drift_expanded.h" void trackRFCavity(double *r_in, double le, double nv, double freq, double h, double lag, double philag, int nturn, double T0, int num_particles) @@ -31,11 +31,11 @@ void trackRFCavity(double *r_in, double le, double nv, double freq, double h, do double *r6 = r_in+c*6; if(!atIsNaN(r6[0])) { /* Propagate through a drift equal to half cavity length */ - drift6(r6, halflength); + drift(r6, halflength, 0.0, NULL); /* Longitudinal momentum kick */ if(nv!=0.0) r6[4] += -nv*sin(TWOPI*freq*((r6[5]-lag)/C0 - (h/freq-T0)*nturn) - philag); /* Propagate through a drift equal to half cavity length */ - drift6(r6, halflength); + drift(r6, halflength, 0.0, NULL); } } } diff --git a/atintegrators/bendfringe.h b/atintegrators/bendfringe.h new file mode 100644 index 0000000000..2838ff5a0b --- /dev/null +++ b/atintegrators/bendfringe.h @@ -0,0 +1,256 @@ +#include +#include "atlalib.c" +#define SQR(X) ((X)*(X)) + +static double Sec(double x) +{ + return 1.0 / cos(x); +} + +#ifndef PXYZ +#define PXYZ +static double pxyz(double dp1, double px, double py) +{ + return sqrt(dp1*dp1 - px*px - py*py); +} +#endif /*PXYZ*/ + +static void yrot_propagate(double *r6, double c, double s, double pz, double p, double *bdiff) +{ + double dp1 = 1.0 + r6[delta_]; + double px = r6[px_]; + double py = r6[py_]; + double x_s_pz_p2 = r6[x_]*s/pz/p/p; + double yrotmat[36]; + + for (int m = 0; m < 36; m++) + yrotmat[m] = 0.0; + /* Set diagonal elements to 1 */ + for (int m = 0; m < 6; m++) + yrotmat[m * 7] = 1.0; + + yrotmat[0] = pz / p; /* [0,0] */ + yrotmat[6] = x_s_pz_p2 * (SQR(px) + SQR(pz)); /* [0, 1] */ + yrotmat[18] = x_s_pz_p2 * px * py; /* [0, 3] */ + yrotmat[24] = -x_s_pz_p2 * px * dp1; /* [0, 4] */ + yrotmat[7] = c - s*px/pz; /* [1, 1] */ + yrotmat[19] = -s*py/pz; /* [1, 3] */ + yrotmat[25] = s*dp1/pz; /* [1, 4] */ + yrotmat[2] = s*py/p; /* [2, 0] */ + yrotmat[8] = x_s_pz_p2 * py * (c*px + s*pz); /* [2, 1] */ + yrotmat[20] = x_s_pz_p2 * (c*(SQR(pz)+SQR(py)) - s*px*pz); /* [2, 3] */ + yrotmat[26] = -x_s_pz_p2 * c*py*dp1; /* [2, 4] */ + yrotmat[5] = s*dp1/p; /* 5, 0] */ + yrotmat[11] = x_s_pz_p2 * dp1*(c*px + s*pz); /* [5, 1] */ + yrotmat[23] = x_s_pz_p2 * c*dp1*py; /* [5, 3] */ + yrotmat[29] = -x_s_pz_p2 * (c*(SQR(px)+SQR(py)) + s*px*pz); /* 5, 4] */ + + ATsandwichmmt(yrotmat, bdiff); +} + +static void Yrot(double *r6, double phi, double *bdiff) +{ + /* Forest 10.26, rotation in free space */ + + double dp1 = 1.0 + r6[delta_]; + double x = r6[x_]; + double px = r6[px_]; + double py = r6[py_]; + double c = cos(phi); + double s = sin(phi); + double pz = pxyz(dp1, px, py); + double p = c*pz - s*px; + double new_px = s*pz + c*px; + double new_x = x*pz/p; + double dy = x*py*s/p; + double dct = dp1*x*s/p; + + if (bdiff) { + yrot_propagate(r6, c, s, pz, p, bdiff); + } + r6[x_] = new_x; + r6[px_] = new_px; + r6[y_] += dy; + r6[ct_] += dct; + } + +static void bend_wedge_propagate(const double *r6, double irho, double fx, double fy, double fringecorr, double *bdiff) +{ + double p_norm = 1.0 / (1.0+r6[4]); + + for (int m = 0; m < 6; m++) { + bdiff[1 + 6*m] += fx * bdiff[6*m]; + bdiff[3 + 6*m] -= fy * bdiff[2 + 6*m]; + } + if (fringecorr != 0.0) + for (int m = 0; m < 6; m++) + bdiff[3 + 6*m] -= bdiff[4 + 6*m] * r6[2] * (irho*irho + fy*fy) * fringecorr * p_norm * p_norm / irho; + + for (int m = 0; m < 6; m++) { + bdiff[m + 6*1] += fx * bdiff[m + 6*0]; + bdiff[m + 6*3] -= fy * bdiff[m + 6*2]; + } + if (fringecorr != 0.0) + for (int m = 0; m < 6; m++) + bdiff[m + 6*3] -= bdiff[m + 6*4] * r6[2] * (irho*irho + fy*fy) * fringecorr * p_norm * p_norm / irho; +} + +static void bend_linear_fringe(double* r6, double irho, double edge_angle, + double gK, int method, double sign, double *bdiff) +{ + /* method 0 no fringe field + * method 1 legacy version Brown First Order + * method 2 SOLEIL close to second order of Brown + * method 3 THOMX + */ + double p_norm = 1.0 / (1.0+r6[4]); + double fringecorr, fx, fy; + + /* Fringe field correction */ + if ((gK==0.0) || (method==0)) { + fringecorr = 0.0; + } + else { + register double sedge = sin(edge_angle); + register double cedge = cos(edge_angle); + fringecorr = irho * gK * (1.0 + sedge*sedge) / cedge; + } + + /* Edge angle focusing */ + fx = irho * tan(edge_angle); + if (method==1) + fy = irho * tan(edge_angle - fringecorr*p_norm); + else if (method==2) + fy = irho * tan(edge_angle - fringecorr*p_norm) * p_norm; + else if (method==3) + fy = irho * tan(edge_angle - fringecorr + r6[1]*p_norm); + else /* fall back to legacy version */ + fy = irho * tan(edge_angle - fringecorr*p_norm); + + /* Propagate B */ + if (bdiff) bend_wedge_propagate(r6, irho, fx, fy, fringecorr, bdiff); + + /* Propagate particle */ + r6[px_] += r6[x_] * fx; + r6[py_] -= r6[y_] * fy; +} + +static void bend_wedge(double *r6, double rhoinv, double theta, double *bdiff) +{ + /* Forest 12.41, ideal wedge, map U(theta, rhoinv) */ + + if (fabs(rhoinv) >= 1.e-6) { + double dp1 = 1.0 + r6[4]; + double c = cos(theta); + double s = sin(theta); + double x = r6[x_]; + double px = r6[px_]; + double py = r6[py_]; + double pz = pxyz(dp1, px, py); + double d2 = pxyz(dp1, 0.0, py); + double new_px = px*c + (pz - rhoinv*x)*s; + double dasin = asin(px/d2) - asin(new_px/d2); + double num = x*s*(2.0*px*c + s*(2.0*pz - rhoinv*x)); + double den = pxyz(dp1, new_px, py) + pz*c - px*s; + double new_x = x*c + num/den; + double dy = py*theta/rhoinv + py/rhoinv*dasin; + double dct = dp1/rhoinv*(theta + dasin); + + if (bdiff) { + /* Propagation of the diffusion matrix temporarily computed as in bend_linear_fringe + by using -theta */ + double fx = -rhoinv * tan(theta); + double fy = fx; + bend_wedge_propagate(r6, rhoinv, fx, fy, 0.0, bdiff); + } + + r6[x_] = new_x; + r6[px_] = new_px; + r6[y_] += dy; + r6[ct_] += dct; + } + else { + Yrot(r6, theta, bdiff); + } +} + +static void quad_wedge(double *r6, double k1_theta) +{ + double x = r6[x_]; + double y = r6[y_]; + double dpx = k1_theta * (x*x - 0.5*y*y); + double dpy = k1_theta * x * y; + r6[px_] -= dpx; + r6[py_] += dpy; +} + +void bend_fringe(double *r6, double irho, double gK) +{ + double factor = 0.0; + if (fabs(gK) > 1.0e-6) { + factor = SQR(irho) / 9.0 / gK; + } + const double irho_g_fint = irho * gK; + const double y = r6[y_]; + const double px = r6[px_]; + const double py = r6[py_]; + const double dp1 = r6[delta_] + 1.0; + + const double pz2 = SQR(dp1) - SQR(px) - SQR(py); + const double pz = sqrt(pz2); + const double xp = px / pz; + const double yp = py / pz; + + const double dpz_dpx = -xp; + const double dpz_dpy = -yp; + const double dpz_ddelta = dp1 / pz; + + const double dxp_dpx = -px/pz2 * dpz_dpx + 1/pz; + const double dxp_dpy = -px/pz2 * dpz_dpy; + const double dxp_ddelta = -px/pz2 * dpz_ddelta; + + const double dyp_dpx = -py/pz2 * dpz_dpx; + const double dyp_dpy = -py/pz2 * dpz_dpy + 1/pz; + const double dyp_ddelta = -py/pz2 * dpz_ddelta; + + const double phi0 = xp / (1.0 + SQR(yp)); + const double dphi0_dxp = 1.0 / (1.0 + SQR(yp)); + const double dphi0_dyp = -2 * xp * yp / SQR(1.0 + SQR(yp)); + + const double dphi0_dpx = dphi0_dxp * dxp_dpx + dphi0_dyp * dyp_dpx; + const double dphi0_dpy = dphi0_dxp * dxp_dpy + dphi0_dyp * dyp_dpy; + const double dphi0_ddelta = dphi0_dxp * dxp_ddelta + dphi0_dyp * dyp_ddelta; + + const double phi1 = 1.0 + 2.0 * SQR(xp) + SQR(xp) * SQR(yp); + const double dphi1_dxp = 4.0 * xp + 2.0 * SQR(yp) * xp; + const double dphi1_dyp = 2.0 * SQR(xp) * yp; + + const double dphi1_dpx = dphi1_dxp * dxp_dpx + dphi1_dyp * dyp_dpx; + const double dphi1_dpy = dphi1_dxp * dxp_dpy + dphi1_dyp * dyp_dpy; + const double dphi1_ddelta = dphi1_dxp * dxp_ddelta + dphi1_dyp * dyp_ddelta; + + const double phi2 = atan(phi0) - irho_g_fint * pz * phi1; + const double dphi2_dpx = dphi0_dpx / (1.0 + SQR(phi0)) + - irho_g_fint * (pz * dphi1_dpx + phi1 * dpz_dpx); + const double dphi2_dpy = dphi0_dpy / (1.0 + SQR(phi0)) + - irho_g_fint * (pz * dphi1_dpy + phi1 * dpz_dpy); + const double dphi2_ddelta = dphi0_ddelta / (1.0 + SQR(phi0)) + - irho_g_fint * (pz * dphi1_ddelta + phi1 * dpz_ddelta); + + const double Phi0 = irho * tan(phi2); + const double cphi2 = cos(phi2); + const double irho_c2 = irho / cphi2 / cphi2; + const double dPhi0_dpx = irho_c2 * dphi2_dpx; + const double dPhi0_dpy = irho_c2 * dphi2_dpy; + const double dPhi0_ddelta = irho_c2 * dphi2_ddelta; + + const double new_y = 2.0 * y / (1.0 + sqrt(1.0 - 2.0 * dPhi0_dpy * y)); + const double delta_x = dPhi0_dpx * SQR(new_y) / 2; + const double delta_py = -Phi0 * new_y - factor / dp1 * SQR(new_y) * new_y; + const double delta_l = -dPhi0_ddelta * SQR(new_y) / 2.0; + + r6[x_] += delta_x; + r6[y_] = new_y; + r6[py_] += delta_py; + r6[ct_] += delta_l; +} diff --git a/atintegrators/curved_dipole.h b/atintegrators/curved_dipole.h new file mode 100644 index 0000000000..700972e4d2 --- /dev/null +++ b/atintegrators/curved_dipole.h @@ -0,0 +1,75 @@ +#ifndef BENT_DIPOLE +#define BENT_DIPOLE +#include "bendfringe.h" +#include "multipolefringe.h" + +#ifndef DEFAULT_BEND_FRINGE +#define DEFAULT_BEND_FRINGE 4 +#endif + +#ifndef MAGNET_ENTRY +#define MAGNET_ENTRY \ + /* Entry face */ \ + if (FringeBendEntrance == 4) { \ + Yrot(r6, entrance_angle, bdiff); \ + bend_fringe(r6, irho, gK_entrance); \ + multipole_fringe(r6, FringeQuadEntrance, B1, A, B, max_order, fringeIntM0, fringeIntP0, 1.0); \ + if (entrance_angle != 0.0) { \ + if (B1 != 0.0 && FringeQuadEntrance) quad_wedge(r6, -B1 * entrance_angle); \ + bend_wedge(r6, irho, -entrance_angle, bdiff); \ + } \ + } \ + else if (FringeBendEntrance > 0) { \ + bend_linear_fringe(r6, irho, entrance_angle, gK_entrance, FringeBendEntrance, 1.0, bdiff); \ + multipole_fringe(r6, FringeQuadEntrance, B1, A, B, max_order, fringeIntM0, fringeIntP0, 1.0); \ + } +#endif /*MAGNET_ENTRY*/ + +#ifndef MAGNET_EXIT +#define MAGNET_EXIT \ + /* Exit face */ \ + if (FringeBendExit == 4) { \ + if (exit_angle != 0.0) { \ + bend_wedge(r6, irho, -exit_angle, bdiff); \ + if (B1 != 0.0 && FringeQuadExit) quad_wedge(r6, -B1 * exit_angle); \ + } \ + multipole_fringe(r6, FringeQuadExit, B1, A, B, max_order, fringeIntM0, fringeIntP0, -1.0); \ + bend_fringe(r6, -irho, gK_exit); \ + Yrot(r6, exit_angle, bdiff); \ + } \ + else if (FringeBendExit > 0) { \ + multipole_fringe(r6, FringeQuadExit, B1, A, B, max_order, fringeIntM0, fringeIntP0, -1.0); \ + bend_linear_fringe(r6, irho, exit_angle, gK_exit, FringeBendExit, -1.0, bdiff); \ + } +#endif /*MAGNET_EXIT*/ + +#define MAGNET_ARGUMENTS \ + double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle", 0.0); check_error(); \ + double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); \ + double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); \ + int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",DEFAULT_BEND_FRINGE); check_error(); \ + int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",DEFAULT_BEND_FRINGE); check_error(); \ + double FullGap=atGetOptionalDouble(ElemData,"FullGap",0.0); check_error(); \ + double FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0.0); check_error(); \ + double FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0.0); check_error(); + +#define MAGNET_ITEMS \ + Elem->BendingAngle=BendingAngle; \ + Elem->EntranceAngle=EntranceAngle; \ + Elem->ExitAngle=ExitAngle; \ + Elem->FringeBendEntrance=FringeBendEntrance; \ + Elem->FringeBendExit=FringeBendExit; \ + Elem->gK_entrance=FullGap*FringeInt1; \ + Elem->gK_exit=FullGap*FringeInt2; + +#ifdef MATLAB_MEX_FILE +#define MAGNET_MEX_ITEMS \ + double gK_entrance=FullGap*FringeInt1; \ + double gK_exit=FullGap*FringeInt2; + +const char *required[] = {"BendingAngle", "EntranceAngle", "ExitAngle"}; +const char *optional[] = {"FringeBendEntrance", "FringeBendExit", "FullGap", "FringeInt1", "FringeInt2"}; +#define N_REQUIRED 3 +#define N_OPTIONAL 5 +#endif /*MATLAB_MEX_FILE*/ +#endif /*BENT_DIPOLE*/ diff --git a/atintegrators/diff_bend_fringe.c b/atintegrators/diff_bend_fringe.c deleted file mode 100644 index e7e22f693f..0000000000 --- a/atintegrators/diff_bend_fringe.c +++ /dev/null @@ -1,53 +0,0 @@ - -static void diff_bend_fringe(double *r6, double inv_rho, double edge_angle, double fint, - double gap, int method, double sign, double *bdiff) { - /* method 0 no fringe field - * method 1 legacy version Brown First Order - * method 2 SOLEIL close to second order of Brown - * method 3 THOMX - */ - double psi, fx, fy; - double p_norm = 1.0 / (1.0+r6[4]); - /* Fringe field correction */ - if ((fint == 0.0) || (gap == 0.0) || (method == 0)) - psi = 0.0; - else { - register double sedge = sin(edge_angle); - register double cedge = cos(edge_angle); - psi = inv_rho * gap * fint * (1.0 + sedge*sedge) / cedge; - } - - /* Edge angle focusing */ - fx = inv_rho * tan(edge_angle); - if (method == 1) - fy = inv_rho * tan(edge_angle - psi*p_norm); - else if (method == 2) - fy = inv_rho * tan(edge_angle - psi*p_norm) * p_norm; - else if (method == 3) - fy = inv_rho * tan(edge_angle - psi + sign*r6[1]*p_norm); - else /* fall back to legacy version */ - fy = inv_rho * tan(edge_angle - psi*p_norm); - - /* Propagate B */ - if (bdiff) { - for (int m = 0; m < 6; m++) { - bdiff[1 + 6*m] += fx * bdiff[6*m]; - bdiff[3 + 6*m] -= fy * bdiff[2 + 6*m]; - } - if (fint > 0 && gap > 0) - for (int m = 0; m < 6; m++) - bdiff[3 + 6*m] -= bdiff[4 + 6*m] * r6[2] * (inv_rho*inv_rho + fy*fy) * psi * p_norm * p_norm / inv_rho; - - for (int m = 0; m < 6; m++) { - bdiff[m + 6*1] += fx * bdiff[m + 6*0]; - bdiff[m + 6*3] -= fy * bdiff[m + 6*2]; - } - if (fint > 0 && gap > 0) - for (int m = 0; m < 6; m++) - bdiff[m + 6*3] -= bdiff[m + 6*4] * r6[2] * (inv_rho*inv_rho + fy*fy) * psi * p_norm * p_norm / inv_rho; - } - /* Propagate particle */ - - r6[1] += r6[0] * fx; - r6[3] -= r6[2] * fy; -} diff --git a/atintegrators/diff_bnd_kick.c b/atintegrators/diff_bnd_kick.c deleted file mode 100644 index 69ac383930..0000000000 --- a/atintegrators/diff_bnd_kick.c +++ /dev/null @@ -1,174 +0,0 @@ -static void thinkickM(const double *r6, double *A, double *B, int max_order, - double L, double irho, double *bdiff) -/* Calculate the symplectic (no radiation) transfer matrix of a - thin multipole kick near the entrance point r6 - For elements with straight coordinate system irho = 0 - For curved elements the B polynomial (PolynomB in MATLAB) - MUST NOT include the guide field By0 = irho * E0 /(c*e) -*/ -{ - double M66[36]; - double ReSumNTemp; - double ImSumN = max_order * A[max_order]; - double ReSumN = max_order * B[max_order]; - - /* Recursively calculate the derivatives - ReSumN = (irho/B0)*Re(d(By + iBx)/dx) - ImSumN = (irho/B0)*Im(d(By + iBx)/dy) - */ - for (int n = max_order - 1; n > 0; n--) { - ReSumNTemp = (ReSumN * r6[0] - ImSumN * r6[2]) + n * B[n]; - ImSumN = ImSumN * r6[0] + ReSumN * r6[2] + n * A[n]; - ReSumN = ReSumNTemp; - } - - /* Initialize M66 to a 6-by-6 identity matrix */ - for (int m = 0; m < 36; m++) - M66[m] = 0.0; - for (int m = 0; m < 6; m++) - M66[m*7] = 1.0; - - /* The relationship between indexes when a 6-by-6 matrix is - represented in MATLAB as one-dimentional array containing - 36 elements arranged column-by-column is - [i][j] <---> [i+6*j] - */ - - M66[1] = -L * ReSumN; /* [1][0] */ - M66[13] = L * ImSumN; /* [1][2] */ - M66[3] = L * ImSumN; /* [3][0] */ - M66[15] = L * ReSumN; /* [3][2] */ - M66[25] = L * irho; /* [1][4] */ - M66[1] += -L * irho * irho; /* [1][0] */ - M66[5] = L * irho; /* [5][0] */ - - ATsandwichmmt(M66, bdiff); -} - -static void thinkickB(double *r6, double ReSum, double ImSum, - double diff_const, double B2P, double factor, double *bdiff) - -/* Calculate Ohmi's diffusion matrix of a thin multipole element */ - -{ - double B66[36]; - - double p_norm = 1.0 / (1.0+r6[4]); - double p_norm2 = SQR(p_norm); - double B3P = B2P * sqrt(B2P); - double BB = diff_const * B3P * factor / p_norm2; /* m^-1 */ - - /* When a 6-by-6 matrix is represented in MATLAB as one-dimentional - array containing 36 elements arranged column-by-column, - the relationship between indexes is - [i][j] <---> [i+6*j] - */ - - /* initialize B66 to 0 */ - for (int i = 0; i < 36; i++) - B66[i] = 0.0; - - /* Populate B66 */ - B66[7] = BB * SQR(r6[1]) * p_norm2; /* [1][1] */ - B66[19] = BB * r6[1] * r6[3] * p_norm2; /* [1][3] */ - B66[9] = B66[19]; /* [3][1] */ - B66[21] = BB * SQR(r6[3]) * p_norm2; /* [3][3] */ - B66[10] = BB * r6[1] * p_norm; /* [4][1] */ - B66[25] = B66[10]; /* [1][4] */ - B66[22] = BB * r6[3] * p_norm; /* [4][3] */ - B66[27] = B66[22]; /* [3][4] */ - B66[28] = BB; /* [4][4] */ - - ATaddmm(B66, bdiff); -} - -static double B2perp(double bx, double by, double irho, - double x, double xpr, double y, double ypr) -/* Calculates sqr(|e x B|) , where e is a unit vector in the direction of velocity */ - -{ - double v_norm2 = 1.0/(SQR(1.0+x*irho)+ SQR(xpr) + SQR(ypr)); - - /* components of the velocity vector: - ex = xpr; - ey = ypr; - ez = (1+x*irho); - */ - - return (SQR(by*(1+x*irho)) + SQR(bx*(1+x*irho)) + SQR(bx*ypr - by*xpr))*v_norm2 ; -} - -static void diff_bnd_kick(double *r6, double *A, double *B, int max_order, - double L, double irho, double rad_const, double diff_const, double *bdiff) { - /* clang-format off */ -/***************************************************************************** -The design magnetic field Byo that provides this curvature By0 = irho * E0 /(c*e) -MUST NOT be included in the dipole term PolynomB(1)(MATLAB notation)(B[0] C notation) -of the By field expansion -HOWEVER!!! to calculate the effect of classical radiation the full field must be -used in the square of the |v x B|. -When calling B2perp(Bx, By, ...), use the By = ReSum + irho, where ReSum is the -normalized vertical field - sum of the polynomial terms in PolynomB. - -The kick is given by - - e L L delta L x -theta = - --- B + ------- - ----- , - x p y rho 2 - 0 rho - - e L -theta = --- B - y p x - 0 - - max_order - ---- - \ n - (B + iB )/ B rho = > (iA + B ) (x + iy) - y x / n n - ---- - n=0 - - ******************************************************************************/ - /* clang-format on */ - int i; - double ImSum = A[max_order]; - double ReSum = B[max_order]; - double x, xpr, y, ypr, p_norm, dp_0, B2P, factor; - double ReSumTemp; - - /* recursively calculate the local transverse magnetic field */ - for (i = max_order - 1; i >= 0; i--) { - ReSumTemp = ReSum * r6[0] - ImSum * r6[2] + B[i]; - ImSum = ImSum * r6[0] + ReSum * r6[2] + A[i]; - ReSum = ReSumTemp; - } - /* calculate angles from momenta */ - p_norm = 1.0 / (1.0+r6[4]); - x = r6[0]; - xpr = r6[1] * p_norm; - y = r6[2]; - ypr = r6[3] * p_norm; - - B2P = B2perp(ImSum, ReSum+irho, irho, x, xpr, y, ypr); - factor = (1.0 + x*irho + (SQR(xpr) + SQR(ypr)) / 2.0) / SQR(p_norm) * L; - - if (bdiff) { - thinkickM(r6, A, B, max_order, L, irho, bdiff); - thinkickB(r6, ReSum, ImSum, diff_const, B2P, factor, bdiff); - } - - dp_0 = r6[4]; /* save a copy of the initial value of dp/p */ - - r6[4] -= rad_const * B2P * factor; - - /* recalculate momenta from angles after losing energy */ - p_norm = 1.0 / (1.0 + r6[4]); - r6[1] = xpr / p_norm; - r6[3] = ypr / p_norm; - - r6[1] -= L * (ReSum - (dp_0 - r6[0] * irho) * irho); - r6[3] += L * ImSum; - r6[5] += L * irho * r6[0]; /* pathlength */ -} \ No newline at end of file diff --git a/atintegrators/diff_str_exactkick.c b/atintegrators/diff_str_exactkick.c deleted file mode 100644 index 2c877dae02..0000000000 --- a/atintegrators/diff_str_exactkick.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "diff_thinkick.c" - -static double B2perp(double bx, double by, - double x, double xpr, double y, double ypr) -/* Calculates sqr(|B x e|) , where e is a unit vector in the direction of velocity */ - -{ - /* components of the normalized velocity vector - double ex, ey, ez; - ex = xpr; - ey = ypr; - ez = sqrt(1 - xpr^2 - ypr^2); - - sqr(|B x e|) = sqr(|B|) * sqr(|e|) - sqr(B.e) - */ - - return SQR(bx) + SQR(by) - SQR(bx*xpr + by*ypr); -} - -static void diff_str_exactkick(double* r6, const double* A, const double* B, int max_order, - double L, double rad_const, double diff_const, double *bdiff) -/***************************************************************************** - -The kick is given by - - e L -theta = - --- B - x p y - 0 - - e L -theta = --- B - y p x - 0 - max_order - ---- - \ n - (B + iB )/ B rho = > (iA + B ) (x + iy) - y x / n n - ---- - n=0 - - ******************************************************************************/ -{ - double x ,xpr, y, ypr, p_norm, B2P, factor; - double ReSumTemp; - - /* recursively calculate the local transverse magnetic field */ - double ReSum = B[max_order]; - double ImSum = A[max_order]; - for (int i=max_order-1; i>=0; i--) { - ReSumTemp = ReSum*r6[0] - ImSum*r6[2] + B[i]; - ImSum = ImSum*r6[0] + ReSum*r6[2] + A[i]; - ReSum = ReSumTemp; - } - - /* calculate angles from momentums */ - p_norm = 1.0 / (1.0+r6[4]); - x = r6[0]; - xpr = r6[1] * p_norm; - y = r6[2]; - ypr = r6[3] * p_norm; - - B2P = B2perp(ImSum, ReSum, x, xpr, y ,ypr); - factor = L / SQR(p_norm) / sqrt(1.0 - SQR(xpr) - SQR(ypr)); - - if (bdiff) { - thinkickM(r6, A, B, max_order, L, bdiff); - thinkickB(r6, ReSum, ImSum, diff_const, B2P, factor, bdiff); - } - - /* Momentum loss */ - r6[4] -= rad_const * B2P * factor; - - /* recalculate momentums from angles after losing energy for radiation */ - p_norm = 1.0 / (1.0+r6[4]); - r6[1] = xpr / p_norm; - r6[3] = ypr / p_norm; - - /* multipole kick */ - r6[1] -= L * ReSum; - r6[3] += L * ImSum; -} diff --git a/atintegrators/diff_str_kick.c b/atintegrators/diff_str_kick.c deleted file mode 100644 index 1408e098ec..0000000000 --- a/atintegrators/diff_str_kick.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "diff_thinkick.c" - -static double B2perp(double bx, double by, - double x, double xpr, double y, double ypr) -/* Calculates sqr(|e x B|) , where e is a unit vector in the direction of velocity */ - -{ - double v_norm2 = 1.0/(1.0+ SQR(xpr) + SQR(ypr)); - - /* components of the velocity vector: - ex = xpr; - ey = ypr; - ez = 1 - */ - - return (SQR(by) + SQR(bx) + SQR(bx*ypr - by*xpr))*v_norm2 ; -} - -static void diff_str_kick(double *r6, double *A, double *B, int max_order, - double L, double rad_const, double diff_const, double *bdiff) -{ - /* clang-format off */ -/***************************************************************************** - -The kick is given by - - e L -theta = - --- B - x p y - 0 - - e L -theta = --- B - y p x - 0 - max_order - ---- - \ n - (B + iB )/ B rho = > (iA + B ) (x + iy) - y x / n n - ---- - n=0 - - ******************************************************************************/ - /* clang-format on */ - double x, xpr, y, ypr, p_norm, B2P, factor; - double ReSumTemp; - - /* recursively calculate the local transverse magnetic field */ - double ImSum = A[max_order]; - double ReSum = B[max_order]; - for (int i = max_order - 1; i >= 0; i--) { - ReSumTemp = ReSum * r6[0] - ImSum * r6[2] + B[i]; - ImSum = ImSum * r6[0] + ReSum * r6[2] + A[i]; - ReSum = ReSumTemp; - } - /* calculate angles from momenta */ - p_norm = 1.0 / (1.0+r6[4]); - x = r6[0]; - xpr = r6[1] * p_norm; - y = r6[2]; - ypr = r6[3] * p_norm; - - B2P = B2perp(ImSum, ReSum, x, xpr, y, ypr); - factor = (1.0 + (SQR(xpr) + SQR(ypr)) / 2.0) / SQR(p_norm) * L; - - if (bdiff) { - thinkickM(r6, A, B, max_order, L, bdiff); - thinkickB(r6, ReSum, ImSum, diff_const, B2P, factor, bdiff); - } - - /* Momentum loss */ - r6[4] -= rad_const * B2P * factor; - - /* recalculate momenta from angles after losing energy */ - p_norm = 1.0 / (1.0 + r6[4]); - r6[1] = xpr / p_norm; - r6[3] = ypr / p_norm; - - /* multipole kick */ - r6[1] -= L * ReSum; - r6[3] += L * ImSum; -} \ No newline at end of file diff --git a/atintegrators/diff_thinkick.c b/atintegrators/diff_thinkick.c index acb7ee64b4..db9a0562b1 100644 --- a/atintegrators/diff_thinkick.c +++ b/atintegrators/diff_thinkick.c @@ -1,7 +1,10 @@ static void thinkickM(const double *r6, const double *A, const double *B, int max_order, - double L, double *bdiff) + double L, double irho, double *bdiff) /* Calculate the symplectic (no radiation) transfer matrix of a thin multipole kick near the entrance point r6 + For elements with straight coordinate system irho = 0 + For curved elements the B polynomial (PolynomB in MATLAB) + MUST NOT include the guide field By0 = irho * E0 /(c*e) */ { double M66[36]; @@ -30,6 +33,9 @@ static void thinkickM(const double *r6, const double *A, const double *B, int ma M66[13] = L * ImSumN; /* [1, 2] */ M66[3] = L * ImSumN; /* [3, 0] */ M66[15] = L * ReSumN; /* [3, 2] */ + M66[25] = L * irho; /* [1, 4] */ + M66[1] -= L * irho * irho; /* [1, 0] */ + M66[5] = L * irho; /* [5, 0] */ ATsandwichmmt(M66, bdiff); } diff --git a/atintegrators/diff_yrot.c b/atintegrators/diff_yrot.c deleted file mode 100644 index 9711c42a2c..0000000000 --- a/atintegrators/diff_yrot.c +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef PXYZ -#define PXYZ -static double pxyz(double dp1, double px, double py) -{ - return sqrt(dp1*dp1 - px*px - py*py); -} -#endif /*PXYZ*/ - -static yrot_propagate(double *r6, double c, double s, double pz, double p, double *bdiff) -{ - double dp1 = 1.0 + r6[delta_]; - double px = r6[px_]; - double py = r6[py_]; - double x_s_pz_p2 = r6[x_]*s/pz/p/p; - double yrotmat[36]; - - for (int m = 0; m < 36; m++) - yrotmat[m] = 0.0; - /* Set diagonal elements to 1 */ - for (int m = 0; m < 6; m++) - yrotmat[m * 7] = 1.0; - - yrotmat[0] = pz / p; /* [0,0] */ - yrotmat[6] = x_s_pz_p2 * (SQR(px) + SQR(pz)); /* [0, 1] */ - yrotmat[18] = x_s_pz_p2 * px * py; /* [0, 3] */ - yrotmat[24] = -x_s_pz_p2 * px * dp1; /* [0, 4] */ - yrotmat[7] = c - s*px/pz; /* [1, 1] */ - yrotmat[19] = -s*py/pz; /* [1, 3] */ - yrotmat[25] = s*dp1/pz; /* [1, 4] */ - yrotmat[2] = s*py/p; /* [2, 0] */ - yrotmat[8] = x_s_pz_p2 * py * (c*px + s*pz); /* [2, 1] */ - yrotmat[20] = x_s_pz_p2 * (c*(SQR(pz)+SQR(py)) - s*px*pz); /* [2, 3] */ - yrotmat[26] = -x_s_pz_p2 * c*py*dp1; /* [2, 4] */ - yrotmat[5] = s*dp1/p; /* 5, 0] */ - yrotmat[11] = x_s_pz_p2 * dp1*(c*px + s*pz); /* [5, 1] */ - yrotmat[23] = x_s_pz_p2 * c*dp1*py; /* [5, 3] */ - yrotmat[29] = -x_s_pz_p2 * (c*(SQR(px)+SQR(py)) + s*px*pz); /* 5, 4] */ - - ATsandwichmmt(yrotmat, bdiff); -} - -static void Yrot(double *r6, double phi, double *bdiff) -{ - /* Forest 10.26, rotation in free space */ - - if (phi != 0.0) { - double dp1 = 1.0 + r6[delta_]; - double c = cos(phi); - double s = sin(phi); - double pz = pxyz(dp1, r6[px_], r6[py_]); - double p = c*pz - s*r6[px_]; - double px = s*pz + c*r6[px_]; - double x = r6[x_]*pz/p; - double dy = r6[x_]*r6[py_]*s/p; - double dct = dp1*r6[x_]*s/p; - - if (bdiff) { - yrot_propagate(r6, c, s, pz, p, bdiff); - } - r6[x_] = x; - r6[px_] = px; - r6[y_] += dy; - r6[ct_] += dct; - } -} \ No newline at end of file diff --git a/atintegrators/drift_E2.h b/atintegrators/drift_E2.h new file mode 100644 index 0000000000..af86bb9f28 --- /dev/null +++ b/atintegrators/drift_E2.h @@ -0,0 +1,19 @@ +#ifdef DIFFUSION +#error "drift_E2 does not compute the diffusion matrix" +#endif + +/* the pseudo-drift element described by Hamiltonian H1 = (1+hx) (px^2+py^2)/2(1+delta), */ +static void drift(double* r6, double L, double h, double *bdiff) +{ + double p_norm = 1.0 / (1.0+r6[4]); + double px = r6[1]; + double py = r6[3]; + double hs = h*L; + double x=r6[0]; + + r6[0] += (1.0+h*x)*L*p_norm*px + 1.0/4.0*hs*L*(px*px-py*py)*p_norm*p_norm; + r6[1] -= hs*(px*px+py*py)*p_norm/2.0; + + r6[2] += (1.0+h*x)*L*p_norm*py*(1.0+px*hs/2.0); + r6[5] += (1.0+h*x)*L*p_norm*p_norm/2.0*(px*px+py*py); +} diff --git a/atintegrators/diff_exactdrift.c b/atintegrators/drift_exact.h similarity index 93% rename from atintegrators/diff_exactdrift.c rename to atintegrators/drift_exact.h index 6ce53042e5..023b34d116 100644 --- a/atintegrators/diff_exactdrift.c +++ b/atintegrators/drift_exact.h @@ -1,4 +1,6 @@ #include +#include "atlalib.c" +#define ABSOLUTE_PATH_LENGTH #define SQR(X) ((X)*(X)) static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff) @@ -34,7 +36,7 @@ static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff /* Forest 10.23, exact drift L: length [m] */ -static void diff_exactdrift(double *r6, double L, double *bdiff) +static void drift(double *r6, double L, double irho, double *bdiff) { double p_norm = 1.0 / (1.0+r6[4]); double xpr = r6[1] * p_norm; diff --git a/atintegrators/exactbend.c b/atintegrators/drift_exactbend.h similarity index 54% rename from atintegrators/exactbend.c rename to atintegrators/drift_exactbend.h index 3113b91b14..a7016b218d 100644 --- a/atintegrators/exactbend.c +++ b/atintegrators/drift_exactbend.h @@ -1,4 +1,10 @@ +#ifdef DIFFUSION +#error "drift_exactbend does not compute the diffusion matrix" +#endif + #include +#include "atlalib.c" +#define ABSOLUTE_PATH_LENGTH #ifndef PXYZ #define PXYZ @@ -8,7 +14,7 @@ static double pxyz(double dp1, double px, double py) } #endif /*PXYZ*/ -static void exact_bend(double *r6, double irho, double L) +static void drift(double *r6, double L, double irho, double *bdiff) { /* Forest 12.18, bend-kick split, map W(L,irho) */ @@ -37,30 +43,3 @@ static void exact_bend(double *r6, double irho, double L) r6[ct_] += dct; } } - -static void exact_straight_bend(double *r6, double irho, double L) -{ - /* Forest 12.39, bend-kick split, map V(L,irho) */ - - double dp1 = 1.0 + r6[delta_]; - double pz = pxyz(dp1, r6[px_], r6[py_]); - if (fabs(irho) < 1.e-6) { - double NormL = L / pz; - r6[x_] += r6[px_] * NormL; - r6[y_] += r6[py_] * NormL; - r6[ct_] += NormL * dp1; /* Absolute path length */ - } - else { - double px = r6[px_] - irho*L; - double d2 = pxyz(dp1, 0.0, r6[py_]); - double dasin = (asin(r6[px_]/d2) - asin(px/d2))/irho; - double dx = (pxyz(dp1, px, r6[py_]) - pz)/irho; - double dy = r6[py_]*dasin; - double dct = dp1*dasin; /* Absolute path length */ - - r6[x_] += dx; - r6[px_] = px; - r6[y_] += dy; - r6[ct_] += dct; - } -} diff --git a/atintegrators/drift_exactstrbend.h b/atintegrators/drift_exactstrbend.h new file mode 100644 index 0000000000..38f6fd7cbc --- /dev/null +++ b/atintegrators/drift_exactstrbend.h @@ -0,0 +1,42 @@ +#ifdef DIFFUSION +#error "drift_exactstrbend does not compute the diffusion matrix" +#endif + +#include +#include "atlalib.c" +#define ABSOLUTE_PATH_LENGTH + +#ifndef PXYZ +#define PXYZ +static double pxyz(double dp1, double px, double py) +{ + return sqrt(dp1*dp1 - px*px - py*py); +} +#endif /*PXYZ*/ + +static void drift(double *r6, double L, double irho, double *bdiff) +{ + /* Forest 12.39, bend-kick split, map V(L,irho) */ + + double dp1 = 1.0 + r6[delta_]; + double pz = pxyz(dp1, r6[px_], r6[py_]); + if (fabs(irho) < 1.e-6) { + double NormL = L / pz; + r6[x_] += r6[px_] * NormL; + r6[y_] += r6[py_] * NormL; + r6[ct_] += NormL * dp1; /* Absolute path length */ + } + else { + double px = r6[px_] - irho*L; + double d2 = pxyz(dp1, 0.0, r6[py_]); + double dasin = (asin(r6[px_]/d2) - asin(px/d2))/irho; + double dx = (pxyz(dp1, px, r6[py_]) - pz)/irho; + double dy = r6[py_]*dasin; + double dct = dp1*dasin; /* Absolute path length */ + + r6[x_] += dx; + r6[px_] = px; + r6[y_] += dy; + r6[ct_] += dct; + } +} diff --git a/atintegrators/diff_drift.c b/atintegrators/drift_expanded.h similarity index 77% rename from atintegrators/diff_drift.c rename to atintegrators/drift_expanded.h index 90edff5147..bb1b048242 100644 --- a/atintegrators/diff_drift.c +++ b/atintegrators/drift_expanded.h @@ -1,3 +1,5 @@ +#include "atlalib.c" +#define SQR(X) ((X)*(X)) static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff) { /* Propagate cumulative Ohmi's diffusion matrix B through a drift. @@ -27,17 +29,17 @@ static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff ATsandwichmmt(M66, bdiff); } -static void diff_drift(double *r6, double L, double *bdiff) +static void drift(double *r6, double L, double irho, double *bdiff) { double p_norm = 1.0 / (1.0+r6[4]); - double xpr = r6[1] * p_norm; - double ypr = r6[3] * p_norm; + double px = r6[1]; + double py = r6[3]; double NormL = L * p_norm; if (bdiff) { - drift_propagateB(NormL, xpr, ypr, bdiff); + drift_propagateB(NormL, px * p_norm, py * p_norm, bdiff); } - r6[0] += NormL * r6[1]; - r6[2] += NormL * r6[3]; - r6[5] += NormL * p_norm * (r6[1]*r6[1] + r6[3]*r6[3]) / 2.0; + r6[0] += NormL * px; + r6[2] += NormL * py; + r6[5] += NormL * p_norm * (px*px + py*py) / 2.0; } diff --git a/atintegrators/drift_fast.h b/atintegrators/drift_fast.h new file mode 100644 index 0000000000..b2ac6e7131 --- /dev/null +++ b/atintegrators/drift_fast.h @@ -0,0 +1,21 @@ +#ifdef RADIATION +#error "drift_fast cannot be used with radiation" +#endif +#ifdef DIFFUSION +#error "drift_fast does not compute the diffusion matrix" +#endif + +#define FAST_DRIFT + +static void drift(double* r, double NormL, double irho, double *bdiff) + +/* NormL=(Physical Length)/(1+delta) is computed externally to speed up calculations + in the loop if momentum deviation (delta) does not change + such as in 4-th order symplectic integrator w/o radiation + */ + +{ + r[0] += NormL*r[1]; + r[2] += NormL*r[3]; + r[5] += NormL*(r[1]*r[1] + r[3]*r[3])/(2.0 * (1.0 + r[4])); +} diff --git a/atintegrators/driftkick.c b/atintegrators/driftkick.c deleted file mode 100644 index f3a32ff474..0000000000 --- a/atintegrators/driftkick.c +++ /dev/null @@ -1,115 +0,0 @@ -/*********************************************************************** - Note: in the US convention the transverse multipole field is written as: - - max_order+1 - ---- - \ n-1 - (B + iB )/ B rho = > (ia + b ) (x + iy) - y x / n n - ---- - n=1 - is a polynomial in (x,y) with the highest order = MaxOrder - - - Using different index notation - - max_order - ---- - \ n - (B + iB )/ B rho = > (iA + B ) (x + iy) - y x / n n - ---- - n=0 - - A,B: i=0 ... max_order - [0] - dipole, [1] - quadrupole, [2] - sextupole ... - units for A,B[i] = 1/[m]^(i+1) - Coeficients are stroed in the PolynomA, PolynomB field of the element - structure in MATLAB - - A[i] (C++,C) = PolynomA(i+1) (MATLAB) - B[i] (C++,C) = PolynomB(i+1) (MATLAB) - i = 0 .. MaxOrder - - ************************************************************************/ - - -static void fastdrift(double* r, double NormL) - -/* NormL=(Physical Length)/(1+delta) is computed externally to speed up calculations - in the loop if momentum deviation (delta) does not change - such as in 4-th order symplectic integrator w/o radiation - */ - -{ - r[0] += NormL*r[1]; - r[2] += NormL*r[3]; - r[5] += NormL*(r[1]*r[1]+r[3]*r[3])/(2*(1+r[4])); -} - - -static void bndthinkick(double* r, double* A, double* B, double L, double irho, int max_order) -/***************************************************************************** -Calculate multipole kick in a curved elemrnt (bending magnet) -The reference coordinate system has the curvature given by the inverse -(design) radius irho. -IMPORTANT !!! -The magnetic field Bo that provides this curvature MUST NOT be included in the dipole term -PolynomB[1](MATLAB notation)(C: B[0] in this function) of the By field expansion - -The kick is given by - - e L L delta L x -theta = - --- B + ------- - ----- , - x p y rho 2 - 0 rho - - e L -theta = --- B - y p x - 0 - -*************************************************************************/ -{ - int i; - double ReSum = B[max_order]; - double ImSum = A[max_order]; - double ReSumTemp; - /* recursively calculate the local transverse magnetic field - * Bx = ReSum, By = ImSum - */ - for (i=max_order-1; i>=0; i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] + A[i]; - ReSum = ReSumTemp; - } - r[1] -= L*(ReSum-(r[4]-r[0]*irho)*irho); - r[3] += L*ImSum; - r[5] += L*irho*r[0]; /* pathlength */ -} - - -static void strthinkick(double* r, const double* A, const double* B, double L, int max_order) -/***************************************************************************** - Calculate and apply a multipole kick to a 6-dimentional - phase space vector in a straight element (quadrupole) - - IMPORTANT !!! - The reference coordinate system is straight but the field expansion may still - contain dipole terms: PolynomA(1), PolynomB(1) - in MATLAB notation, - A[0], B[0] - C,C++ notation - - ******************************************************************************/ -{ - int i; - double ReSum = B[max_order]; - double ImSum = A[max_order]; - double ReSumTemp; - for (i=max_order-1; i>=0; i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] + A[i]; - ReSum = ReSumTemp; - } - r[1] -= L*ReSum; - r[3] += L*ImSum; -} diff --git a/atintegrators/driftkickrad.c b/atintegrators/driftkickrad.c deleted file mode 100644 index b2c57062f7..0000000000 --- a/atintegrators/driftkickrad.c +++ /dev/null @@ -1,198 +0,0 @@ -/*********************************************************************** - Note: in the US convention the transverse multipole field is written as: - - max_order+1 - --- - \ n-1 - (B + iB )/ B rho = > (ia + b ) (x + iy) - y x / n n - ---- - n=1 - is a polynomial in (x,y) with the highest order = MaxOrder - - - Using different index notation - - max_order - ---- - \ n - (B + iB )/ B rho = > (iA + B ) (x + iy) - y x / n n - ---- - n=0 - - A,B: i=0 ... max_order - [0] - dipole, [1] - quadrupole, [2] - sextupole ... - units for A,B[i] = 1/[m]^(i+1) - Coefficients are stored in the PolynomA, PolynomB field of the element - structure in MATLAB - - A[i] (C++,C) = PolynomA(i+1) (MATLAB) - B[i] (C++,C) = PolynomB(i+1) (MATLAB) - i = 0 .. MaxOrder - -*************************************************************************/ - -static void drift6(double* r, double L) -/* Input parameter L is the physical length - 1/(1+delta) normalization is done internally -*/ -{ double p_norm = 1/(1+r[4]); - double NormL = L*p_norm; - r[0]+= NormL*r[1]; - r[2]+= NormL*r[3]; - r[5]+= NormL*p_norm*(r[1]*r[1]+r[3]*r[3])/2; -} - -#define SQR(X) ((X)*(X)) - -double StrB2perp(double bx, double by, - double x, double xpr, double y, double ypr) -/* Calculates sqr(|B x e|) , where e is a unit vector in the direction of velocity */ - -{ double v_norm2; - v_norm2 = 1/(1 + SQR(xpr) + SQR(ypr)); - - /* components of the normalized velocity vector - double ex, ey, ez; - ex = xpr; - ey = ypr; - ez = 1; - */ - - return((SQR(by) + SQR(bx) + SQR(bx*ypr - by*xpr) )*v_norm2) ; - -} - - -static double B2perp(double bx, double by, double irho, - double x, double xpr, double y, double ypr) - /* Calculates sqr(|e x B|) , where e is a unit vector in the direction of velocity */ - -{ - double v_norm2 = 1/(SQR(1+x*irho)+ SQR(xpr) + SQR(ypr)); - - /* components of the velocity vector - * double ex, ey, ez; - * ex = xpr; - * ey = ypr; - * ez = (1+x*irho); - */ - - return((SQR(by*(1+x*irho)) + SQR(bx*(1+x*irho)) + SQR(bx*ypr - by*xpr) )*v_norm2) ; -} - -static void bndthinkickrad(double* r, double* A, double* B, double L, double irho, double E0, int max_order) - -/***************************************************************************** -Calculate multipole kick in a curved elemrnt (bending magnet) -The reference coordinate system has the curvature given by the inverse -(design) radius irho. -IMPORTANT !!! -The magnetic field Bo that provides this curvature MUST NOT be included in the dipole term -PolynomB[1](MATLAB notation)(C: B[0] in this function) of the By field expansion -HOWEVER!!! to calculate the effect of classical radiation the full field must be -used in the square of the |v x B|. -When calling B2perp(Bx, By, ...), use the By = RESum + irho, where ImSum is the sum of -the polynomial terms in PolynomB. - - The kick is given by - - e L L delta L x - theta = - --- B + ------- - ----- , - x p y rho 2 - 0 rho - - e L - theta = --- B - y p x - 0 - - ******************************************************************************/ -{ - int i; - double ImSum = A[max_order]; - double ReSum = B[max_order]; - double ReSumTemp; - double x ,xpr, y, ypr, p_norm,dp_0, B2P; - double CRAD = CGAMMA*E0*E0*E0/(TWOPI*1e27); /* [m]/[GeV^3] M.Sands (4.1) */ - - /* recursively calculate the local transvrese magnetic field - * Bx = ReSum, By = ImSum - */ - for (i=max_order-1; i>=0; i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] + A[i]; - ReSum = ReSumTemp; - } - - /* calculate angles from momentums */ - p_norm = 1/(1+r[4]); - x = r[0]; - xpr = r[1]*p_norm; - y = r[2]; - ypr = r[3]*p_norm; - - B2P = B2perp(ImSum, ReSum +irho, irho, x , xpr, y ,ypr); - - dp_0 = r[4]; - r[4] = r[4] - CRAD*SQR(1+r[4])*B2P*(1 + x*irho + (SQR(xpr)+SQR(ypr))/2 )*L; - - /* recalculate momentums from angles after losing energy for radiation */ - p_norm = 1/(1+r[4]); - r[1] = xpr/p_norm; - r[3] = ypr/p_norm; - - r[1] -= L*(ReSum-(dp_0-r[0]*irho)*irho); - r[3] += L*ImSum; - r[5] += L*irho*r[0]; /* pathlength */ -} - -static void strthinkickrad(double* r, const double* A, const double* B, double L, double E0,int max_order) -/***************************************************************************** - Calculate and apply a multipole kick to a 6-dimentional - phase space vector in a straight element ( quadrupole) - - IMPORTANT !!! - he reference coordinate system is straight but the field expansion may still - ontain dipole terms: PolynomA(1), PolynomB(1) - in MATLAB notation, - [0], B[0] - C,C++ notation - - ******************************************************************************/ -{ - int i; - double ReSum = B[max_order]; - double ImSum = A[max_order]; - double ReSumTemp; - double irho=0;/*straight elements no curvature.*/ - double x ,xpr, y, ypr, p_norm,dp_0, B2P; - double CRAD = CGAMMA*E0*E0*E0/(TWOPI*1e27); /* [m]/[GeV^3] M.Sands (4.1) */ - - for (i=max_order-1; i>=0; i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] + A[i]; - ReSum = ReSumTemp; - } - - /* calculate angles from momentums */ - p_norm = 1/(1+r[4]); - x = r[0]; - xpr = r[1]*p_norm; - y = r[2]; - ypr = r[3]*p_norm; - - /*B2P = B2perp(ImSum, ReSum +irho, irho, x , xpr, y ,ypr);*/ - B2P = StrB2perp(ImSum, ReSum , x , xpr, y ,ypr); - - dp_0 = r[4]; - r[4] = r[4] - CRAD*SQR(1+r[4])*B2P*(1 + x*irho + (SQR(xpr)+SQR(ypr))/2 )*L; - - /* recalculate momentums from angles after losing energy for radiation */ - p_norm = 1/(1+r[4]); - r[1] = xpr/p_norm; - r[3] = ypr/p_norm; - - r[1] -= L*(ReSum-(dp_0-r[0]*irho)*irho); - r[3] += L*ImSum; - r[5] += L*irho*r[0]; /* pathlength */ -} diff --git a/atintegrators/exactbendfringe.c b/atintegrators/exactbendfringe.c deleted file mode 100644 index 3c8e8ac522..0000000000 --- a/atintegrators/exactbendfringe.c +++ /dev/null @@ -1,162 +0,0 @@ - -static double Sec(double x) -{ - return 1.0 / cos(x); -} - -#ifndef PXYZ -#define PXYZ -static double pxyz(double dp1, double px, double py) -{ - return sqrt(dp1*dp1 - px*px - py*py); -} -#endif /*PXYZ*/ - -static void Yrot(double *r6, double phi) -{ - /* Forest 10.26, rotation in free space */ - - if (phi != 0.0) { - double dp1 = 1.0 + r6[delta_]; - double c = cos(phi); - double s = sin(phi); - double pz = pxyz(dp1, r6[px_], r6[py_]); - double p = c*pz - s*r6[px_]; - double px = s*pz + c*r6[px_]; - double x = r6[x_]*pz/p; - double dy = r6[x_]*r6[py_]*s/p; - double dct = dp1*r6[x_]*s/p; - r6[x_] = x; - r6[px_] = px; - r6[y_] += dy; - r6[ct_] += dct; - } -} - -static void bend_fringe(double *r6, double irho, double gK) -{ - /* Forest 13.13, bend fringe in the hard-edge limit */ - - double b0 = irho; - - double pz = pxyz(1.0+r6[delta_], r6[px_], r6[py_]); - double px = r6[px_]; - double py = r6[py_]; - double d = r6[delta_]; - double xp = px / pz; - double yp = py / pz; - - double phi = -b0 * tan( b0 * gK * (1 + xp*xp*(2 + yp*yp))*pz - atan(xp / (1 + yp*yp))); - - /* these are the partial derivatives of phi with respect to px, py and delta - total horror from Mathematica. This could benefit from some mini-TPSA */ - - double px2 = px*px; - double px4 = px2*px2; - double py2 = py*py; - double py4 = py2*py2; - double py6 = py4*py2; - double pz2 = pz*pz; - double pz3 = pz2*pz; - double pz4 = pz2*pz2; - double pz5 = pz4*pz; - double pz6 = pz4*pz2; - double py2z2 = (py2 + pz2) * (py2 + pz2); - double powsec = pow(Sec((b0*gK*(pz4 + px2*(py2 + 2*pz2)))/pz3 - atan((px*pz)/(py2 + pz2))),2); - double denom = (pz5*(py4 + px2*pz2 + 2*py2*pz2 + pz4)); - - double dpx = -(b0*(px2*pz4*(py2 - pz2) - pz6*(py2 + pz2) + - b0*gK*px*(pz2*py2z2*(2*py2 + 3*pz2) + px4*(3*py2*pz2 + 2*pz4) + - px2*(3*py6 + 8*py4*pz2 + 9*py2*pz4 + 5*pz6)))*powsec) - /denom; - - double dpy = -(b0*py*(px*pz4*(py2 + pz2) + - b0*gK*(-(pz4*py2z2) + px4*(3*py2*pz2 + 4*pz4) + - px2*(3*py6 + 10*py4*pz2 + 11*py2*pz4 + 3*pz6)))*powsec) - /denom; - - double dd = (b0*(1 + d)*(px*pz4*(py2 - pz2) + b0*gK* - (-(pz4*py2z2) + px4*(3*py2*pz2 + 2*pz4) + - px2*(3*py6 + 8*py4*pz2 + 7*py2*pz4 + pz6)))*powsec) - /denom; - - /* solve quadratic equation in yf (Forest fringe_part_I.pdf) */ - - double yf = (2 * r6[y_]) / (1 + sqrt(1 - 2 * dpy * r6[y_])); - double dxf = 0.5 * dpx * yf * yf; - double dct = 0.5 * dd * yf * yf; - double dpyf = phi * yf; - - r6[y_] = yf; - r6[x_] += dxf; - r6[py_] -= dpyf; - r6[ct_] -= dct; -} - -static void bend_edge(double *r6, double rhoinv, double theta) -{ - /* Forest 12.41, ideal wedge, map U(theta, rhoinv) */ - - if (fabs(rhoinv) >= 1.e-6) { - double dp1 = 1.0 + r6[4]; - double c = cos(theta); - double s = sin(theta); - double pz = pxyz(dp1, r6[px_], r6[py_]); - double d2 = pxyz(dp1, 0.0, r6[py_]); - double px = r6[px_]*c + (pz - rhoinv*r6[x_])*s; - double dasin = asin(r6[px_]/d2) - asin(px/d2); - double num = r6[x_]*(r6[px_]*sin(2.0*theta) + s*s*(2.0*pz - rhoinv*r6[x_])); - double den = pxyz(dp1, px, r6[py_]) + pxyz(dp1, r6[px_], r6[py_])*c - r6[px_]*s; - double x = r6[x_]*c + num/den; - double dy = r6[py_]*theta/rhoinv + r6[py_]/rhoinv*dasin; - double dct = dp1/rhoinv*(theta + dasin); - - r6[x_] = x; - r6[px_] = px; - r6[y_] += dy; - r6[ct_] += dct; - } -} - -static void bend_fringe_test(double *r6, double irho, double gK) -{ - /* Forest 13.13, bend fringe in the hard-edge limit */ - - double b0 = irho; - - double pz = pxyz(1.0+r6[delta_], r6[px_], r6[py_]); - double px = r6[px_]; - double py = r6[py_]; - double d = r6[delta_]; - double xp = px / pz; - double yp = py / pz; - - double psi = b0*xp/(1+yp*yp); - - /* these are the partial derivatives of psi with respect to px, py and delta - total horror from Mathematica. This could benefit from some mini-TPSA */ - - double px2 = px*px; - double py2 = py*py; - double pz2 = pz*pz; - double pz4 = pz2*pz2; - double denom = (pz2 + py2); - - double dpx = b0*(pz4 + pz2*denom - px2*py2)/pz/denom/denom; - double dpy = -b0*yp*px/denom; - double dd = b0*xp*(1.0+d)*(py2-pz2)/denom/denom; - - /* solve quadratic equation in yf (Forest fringe_part_I.pdf) */ - - double yf = (2 * r6[y_]) / (1 + sqrt(1 - 2 * dpy * r6[y_])); - double dxf = 0.5 * dpx * yf * yf; - double dct = 0.5 * dd * yf * yf; - double dpyf = psi * yf; - // atPrintf("Fringe dx, dpy, dct: %g, %g, %g\n", dxf, dpyf, dct); - - - r6[x_] += dxf; - r6[y_] = yf; - r6[py_] -= dpyf; - r6[ct_] -= dct; -} diff --git a/atintegrators/exactdrift.c b/atintegrators/exactdrift.c deleted file mode 100644 index 0437854cc2..0000000000 --- a/atintegrators/exactdrift.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#define SQR(X) ((X)*(X)) - -static double get_pz(double *r6) { - return sqrt(SQR(1 + r6[4]) - SQR(r6[1]) - SQR(r6[3])); -} - -/* Forest 10.23, exact drift - L: length [m] -*/ -static void exact_drift(double *r6, double L) { - double NormL = L / get_pz(r6); - r6[0] += r6[1] * NormL; - r6[2] += r6[3] * NormL; - r6[5] += NormL * (1.0 + r6[4]); /* Absolute path length */ -} diff --git a/atintegrators/exactkickrad.c b/atintegrators/exactkickrad.c deleted file mode 100644 index 726032bb76..0000000000 --- a/atintegrators/exactkickrad.c +++ /dev/null @@ -1,186 +0,0 @@ -/*********************************************************************** - Note: in the US convention the transverse multipole field is written as: - - max_order+1 - --- - \ n-1 - (B + iB )/ B rho = > (ia + b ) (x + iy) - y x / n n - ---- - n=1 - is a polynomial in (x,y) with the highest order = MaxOrder - - - Using different index notation - - max_order - ---- - \ n - (B + iB )/ B rho = > (iA + B ) (x + iy) - y x / n n - ---- - n=0 - - A,B: i=0 ... max_order - [0] - dipole, [1] - quadrupole, [2] - sextupole ... - units for A,B[i] = 1/[m]^(i+1) - Coefficients are stored in the PolynomA, PolynomB field of the element - structure in MATLAB - - A[i] (C++,C) = PolynomA(i+1) (MATLAB) - B[i] (C++,C) = PolynomB(i+1) (MATLAB) - i = 0 .. MaxOrder - -*************************************************************************/ - -#define SQR(X) ((X)*(X)) - -static double StrB2perp(double bx, double by, - double x, double xpr, double y, double ypr) -/* Calculates sqr(|B x e|) , where e is a unit vector in the direction of velocity */ - -{ - /* components of the normalized velocity vector - double ex, ey, ez; - ex = xpr; - ey = ypr; - ez = sqrt(1 - xpr^2 - ypr^2); - - sqr(|B x e|) = sqr(|B|) * sqr(|e|) - sqr(B.e) - */ - - return SQR(bx) + SQR(by) - SQR(bx*xpr + by*ypr); -} - - -static double B2perp(double bx, double by, double irho, - double x, double xpr, double y, double ypr) - /* Calculates sqr(|e x B|) , where e is a unit vector in the direction of velocity */ - -{ - double nrm = SQR(1.0+x*irho); -// double v_norm2 = nrm + SQR(xpr) + SQR(ypr); - double v_norm2 = nrm + SQR(xpr)*(1.0-nrm) + SQR(ypr)*(1.0-nrm); - - /* components of the velocity vector - * double ex, ey, ez; - * ex = xpr; - * ey = ypr; - * ez = (1+x*irho) * sqrt(1 - xpr^2 - ypr^2); - */ - - return SQR(bx) + SQR(by) - SQR(bx*xpr + by*ypr)/v_norm2; -// return (SQR(by*(1+x*irho)) + SQR(bx*(1+x*irho)) + SQR(bx*ypr - by*xpr))/v_norm2 ; -} - -//static void ex_bndthinkickrad(double* r, double* A, double* B, double L, double irho, double E0, int max_order) -static void ex_bndthinkickrad(double* r, double* A, double* B, int max_order, - double L, double irho, double rad_const, double diff_const, double *bdiff) - -/***************************************************************************** -Calculate multipole kick in a curved element (bending magnet) -The reference coordinate system has the curvature given by the inverse -(design) radius irho. -IMPORTANT !!! -The magnetic field Bo that provides this curvature MUST NOT be included in the dipole term -PolynomB[1](MATLAB notation)(C: B[0] in this function) of the By field expansion -HOWEVER!!! to calculate the effect of classical radiation the full field must be -used in the square of the |v x B|. -When calling B2perp(Bx, By, ...), use the By = RESum + irho, where ImSum is the sum of -the polynomial terms in PolynomB. - - The kick is given by - - e L L delta L x - theta = - --- B + ------- - ----- , - x p y rho 2 - 0 rho - - e L - theta = --- B - y p x - 0 - - ******************************************************************************/ -{ - int i; - double ImSum = A[max_order]; - double ReSum = B[max_order]; - double ReSumTemp; - double x ,xpr, y, ypr, p_norm, B2P; - - for (i=max_order-1; i>=0; i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] + A[i]; - ReSum = ReSumTemp; - } - - /* calculate angles from momentums */ - p_norm = 1/(1+r[4]); - x = r[0]; - xpr = r[1]*p_norm; - y = r[2]; - ypr = r[3]*p_norm; - - B2P = B2perp(ImSum, ReSum+irho, irho, x , xpr, y ,ypr); - - /* Momentum loss */ - r[4] -= rad_const * SQR(1+r[4]) * B2P * (1.0+x*irho) * L / sqrt(1.0 - xpr*xpr - ypr*ypr); -// r[4] = r[4] - CRAD*SQR(1+r[4])*B2P*(1 + x*irho + (SQR(xpr)+SQR(ypr))/2 )*L; - - /* recalculate momentums from angles after losing energy for radiation */ - p_norm = 1/(1+r[4]); - r[1] = xpr/p_norm; - r[3] = ypr/p_norm; - - /* Multipole kick */ - r[1] -= L*ReSum; - r[3] += L*ImSum; -} - -//static void ex_strthinkickrad(double* r, const double* A, const double* B, double B0, double L, double E0, int max_order) -static void ex_strthinkickrad(double* r, const double* A, const double* B, int max_order, - double B0, double L, double rad_const, double diff_const, double *bdiff) -/***************************************************************************** - Calculate and apply a multipole kick to a 6-dimentional - phase space vector in a straight element ( quadrupole) - - IMPORTANT !!! - he reference coordinate system is straight but the field expansion may still - ontain dipole terms: PolynomA(1), PolynomB(1) - in MATLAB notation, - [0], B[0] - C,C++ notation - - ******************************************************************************/ -{ - double ReSum = B[max_order]; - double ImSum = A[max_order]; - double ReSumTemp; - double x ,xpr, y, ypr, p_norm, B2P; - - for (int i=max_order-1; i>=0; i--) { - ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i]; - ImSum = ImSum*r[0] + ReSum*r[2] + A[i]; - ReSum = ReSumTemp; - } - - /* calculate angles from momentums */ - p_norm = 1/(1+r[4]); - x = r[0]; - xpr = r[1]*p_norm; - y = r[2]; - ypr = r[3]*p_norm; - - B2P = StrB2perp(ImSum, ReSum+B0 , x , xpr, y ,ypr); - - /* Momentum loss */ - r[4] -= rad_const * SQR(1+r[4]) * B2P * L / sqrt(1.0 - xpr*xpr - ypr*ypr); - - /* recalculate momentums from angles after losing energy for radiation */ - p_norm = 1/(1+r[4]); - r[1] = xpr/p_norm; - r[3] = ypr/p_norm; - - /* multipole kick */ - r[1] -= L*ReSum; - r[3] += L*ImSum; -} diff --git a/atintegrators/exactmultipolefringe.c b/atintegrators/exactmultipolefringe.c deleted file mode 100644 index 1f5343fb8f..0000000000 --- a/atintegrators/exactmultipolefringe.c +++ /dev/null @@ -1,95 +0,0 @@ - -static void multipole_fringe(double *r6, double L, - double *polya, double *polyb, int max_order, - double edge, int skip_b0) -{ - // PTC multipole_fringer - // Forest 13.29 - // not re-derived and checked - // note this is the sum over n of Forest 13.29 - // one for each multipole component - - double U, V, DU, DV, DUX, DVX, DUY, DVY, FX, FY, FX_X, FX_Y, FY_X, FY_Y, - RX, IX, DRX, DIX; - - FX = 0; - FY = 0; - FX_X = 0; - FX_Y = 0; - FY_X = 0; - FY_Y = 0; - - RX = 1.0; - IX = 0.0; - - // invariant is (j is the index, i is the complex unit) - // RX+IXi = (x + iy)^j - for (int n = 0; n <= max_order; n++) { - - double B = polyb[n]; - double A = polya[n]; - - int j = n + 1; - - DRX = RX; - DIX = IX; - - // complex muls - - RX = DRX * r6[x_] - DIX * r6[y_]; - IX = DRX * r6[y_] + DIX * r6[x_]; - - if (n == 0 && skip_b0) { - U = - A * IX; - V = + A * RX; - DU = - A * DIX; - DV = + A * DRX; - } - else { - U = B * RX - A * IX; - V = B * IX + A * RX; - DU = B * DRX - A * DIX; - DV = B * DIX + A * DRX; - } - double f1 = -edge / 4.0 / (j + 1); - - U = U * f1; - V = V * f1; - DU = DU * f1; - DV = DV * f1; - - DUX = j * DU; - DVX = j * DV; - DUY = -j * DV; - DVY = j * DU; - - double nf = 1.0 * (j + 2) / j; - - FX += U * r6[x_] + nf * V * r6[y_]; - FY += U * r6[y_] - nf * V * r6[x_]; - - FX_X += DUX * r6[x_] + U + nf * r6[y_] * DVX; - FX_Y += DUY * r6[x_] + nf * V + nf * r6[y_] * DVY; - - FY_X += DUX * r6[y_] - nf * V - nf * r6[x_] * DVX; - FY_Y += DUY * r6[y_] + U - nf * r6[x_] * DVY; - } - - double DEL = 1.0 / (1 + r6[delta_]); - - // solve 2x2 matrix equation - - double A = 1 - FX_X * DEL; - double B = -FY_X * DEL; - double D = 1 - FY_Y * DEL; - double C = -FX_Y * DEL; - - r6[x_] = r6[x_] - FX * DEL; - r6[y_] = r6[y_] - FY * DEL; - - double pxf = (D * r6[px_] - B * r6[py_]) / (A * D - B * C); - double pyf = (A * r6[py_] - C * r6[px_]) / (A * D - B * C); - r6[py_] = pyf; - r6[px_] = pxf; - r6[ct_] = r6[ct_] - (r6[px_] * FX + r6[py_] * FY) * DEL * DEL; -} diff --git a/atintegrators/integrators.h b/atintegrators/integrators.h new file mode 100644 index 0000000000..63a606bb9d --- /dev/null +++ b/atintegrators/integrators.h @@ -0,0 +1,85 @@ +#ifdef QUANTUM +#include "quantum_diffusion.h" +#endif /*QUANTUM*/ + +#define YD1 3.922568052387799819591407413100e-01 +#define YD2 5.100434119184584780271052295575e-01 +#define YD3 -4.710533854097565531482416645304e-01 +#define YD4 6.875316825251809316199569366290e-02 + +#define YK1 7.845136104775599639182814826199e-01 +#define YK2 2.355732133593569921359289764951e-01 +#define YK3 -1.177679984178870098432412305556e+00 +#define YK4 1.315186320683906284756403692882e+00 + +#ifndef DRIFT +#define DRIFT drift +#endif + +#ifndef KICK +#define KICK kick +#endif + +#ifdef RADIATION +#define KICK_(r6, A0, B0, A, B, max_order, length, irho, rad_const, diff_const, bdiff) \ + KICK(r6, A0, B0, A, B, max_order, length, irho, rad_const, diff_const, bdiff) +#else +#define KICK_(r6, A0, B0, A, B, max_order, length, irho, rad_const, diff_const, bdiff) \ + KICK(r6, A0, B0, A, B, max_order, length, irho) +#endif + +#ifndef INTEGRATOR_PREFIX +#define INTEGRATOR_PREFIX +#endif + +#ifndef INTEGRATOR_SUFFIX +#define INTEGRATOR_SUFFIX +#endif + +#ifndef INTEGRATOR +#define INTEGRATOR integrator +#endif + +#ifdef ABSOLUTE_PATH_LENGTH +#define FIX_LENGTH r6[5] -= (le+refdz); +#else +#define FIX_LENGTH +#endif + +#if defined(INTEGRATOR_4) +#define integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + for (int m = 0; m < num_int_steps; m++) { /* Loop over slices */ \ + INTEGRATOR_PREFIX \ + DRIFT(r6, DRIFT1 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, KICK1 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, DRIFT2 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, KICK2 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, DRIFT2 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, KICK1 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, DRIFT1 * slength, irho, bdiff); \ + INTEGRATOR_SUFFIX \ + } \ + FIX_LENGTH +#elif defined(INTEGRATOR_6) +#define integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + for (int m = 0; m < num_int_steps; m++) { /* Loop over slices */ \ + INTEGRATOR_PREFIX \ + DRIFT(r6, YD1 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, YK1 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, YD2 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, YK2 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, YD3 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, YK3 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, YD4 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, YK4 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, YD4 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, YK3 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, YD3 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, YK2 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, YD2 * slength, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, YK1 * klength, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, YD1 * slength, irho, bdiff); \ + INTEGRATOR_SUFFIX \ + } \ + FIX_LENGTH +#endif /*INTEGRATOR_4*/ diff --git a/atintegrators/kick_E2.h b/atintegrators/kick_E2.h new file mode 100644 index 0000000000..7e8067d5f1 --- /dev/null +++ b/atintegrators/kick_E2.h @@ -0,0 +1,102 @@ +/*********************************************************************** +Expansion of the magnetic field in AT: + + max_order + ---- + \ n + (B + iB )/ B rho = > (iA + B ) (x + iy) + y x / n n + ---- + n=0 + + A,B: i=0 ... max_order + [0] - dipole, [1] - quadrupole, [2] - sextupole ... + units for A,B[i] = 1/[m]^(i+1) +*************************************************************************/ + +#ifdef DIFFUSION +#error "kick_E2 does not compute the diffusion matrix" +#endif + +#ifdef RADIATION +#define SQR(X) ((X)*(X)) + +static double B2perp(double bx, double by, double irho, double x, double xpr, double y, double ypr) +/* Calculates sqr(|B x e|), where e is a unit vector in the direction of velocity */ +{ + double xh1 = SQR(1.0 + x*irho); + double v_norm2 = (xh1 + SQR(xpr) + SQR(ypr)); + + /* components of the velocity vector: + ex = xpr; + ey = ypr; + ez = (1+x*irho); + + sqr(|B x e|) = sqr(|B|) * sqr(|e|) - sqr(B.e) + */ + + return((xh1*SQR(by) + xh1*SQR(bx) + SQR(bx*ypr - by*xpr)) / v_norm2) ; +} + +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho, double rad_const, double diff_const, double *bdiff) +#else +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho) +#endif /* RADIATION */ +{ +/* clang-format off */ +/***************************************************************************** +(1) PolynomA is neglected. +(2) The vector potential is expanded up to 4th order of x and y. +(3) Coefficients in PolynomB higher than 4th order is treated as if they are on straight geometry. +(4) The Hamiltonian is H2 = - h x delta - (1+h x)As/Brho-B0 x/Brho +*/ +/* clang-format on */ + double ReSum = B[max_order]; + double ImSum = A[max_order]; + double ReSumTemp; + double x = r6[0]; + double y = r6[2]; + double dp_0 = r6[4]; /* save a copy of the initial value of dp/p */ + + double K1 = (max_order >= 1) ? B[1] : 0.0; + double K2 = (max_order >= 2) ? B[2] : 0.0; + + /* recursively calculate the local transverse magnetic field */ + for (int i = max_order - 1; i >= 0; i--) { + ReSumTemp = ReSum*x - ImSum*y + B[i]; + ImSum = ImSum*x + ReSum*y + A[i]; + ReSum = ReSumTemp; + } + ReSum += B0; + ImSum += A0; + + #ifdef RADIATION + double p_norm = 1.0 / (1.0+r6[4]); + + /* calculate angles from momenta */ + double xpr = r6[1] * p_norm; + double ypr = r6[3] * p_norm; + + /* see Iselin Part. Accel. 1985 */ + ImSum += irho*(K1*irho-K2)*y*y*y/6.0; + ReSum += -K1*irho*y*y/2.0 + irho*(K1*irho-K2)*x*y*y/2.0; + + double B2P = B2perp(ImSum, ReSum+irho, irho, x , xpr, y ,ypr); + double factor = L * (1.0 + x*irho + (SQR(xpr) + SQR(ypr)) / 2.0) / SQR(p_norm); + + /* Momentum loss */ + r6[4] -= rad_const * B2P * factor; + + /* Recalculate momenta from angles after losing energy */ + p_norm = 1.0 / (1.0 + r6[4]); + r6[1] = xpr / p_norm; + r6[3] = ypr / p_norm; + #endif /* RADIATION */ + + /* Multipole kick */ + r6[1] -= L * (ReSum - irho*dp_0 + irho*(irho*x + K1*(x*x-0.5*y*y) + K2*(x*x*x-4.0/3.0*x*y*y))); + r6[3] += L * (ImSum + irho*(K1*x*y + 4.0/3.0*K2*x*x*y + (irho/6.0*K1-K2/3.0)*y*y*y)) ; + r6[5] += L * irho*x; /* pathlength */ +} diff --git a/atintegrators/kick_exactkn.h b/atintegrators/kick_exactkn.h new file mode 100644 index 0000000000..c3b0fef23b --- /dev/null +++ b/atintegrators/kick_exactkn.h @@ -0,0 +1,109 @@ +/*********************************************************************** +Expansion of the magnetic field in AT: + + max_order + ---- + \ n + (B + iB )/ B rho = > (iA + B ) (x + iy) + y x / n n + ---- + n=0 + + A,B: i=0 ... max_order + [0] - dipole, [1] - quadrupole, [2] - sextupole ... + units for A,B[i] = 1/[m]^(i+1) +*************************************************************************/ + +#ifdef RADIATION +#include "diff_thinkick.c" + +static double B2perp(double bx, double by, double x, double xpr, double y, double ypr) +/* Calculates sqr(|B x e|), where e is a unit vector in the direction of velocity */ +{ + /* components of the normalized velocity vector: + ex = xpr; + ey = ypr; + ez = sqrt(1 - xpr^2 - ypr^2); + + sqr(|B x e|) = sqr(|B|) * sqr(|e|) - sqr(B.e) + */ + + return SQR(bx) + SQR(by) - SQR(bx*xpr + by*ypr); +} + +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho, double rad_const, double diff_const, double *bdiff) +#else +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho) +#endif /* RADIATION */ +{ +/* clang-format off */ +/***************************************************************************** +Calculate multipole kick in a straight element + IMPORTANT !!! + The reference coordinate system is straight but the field expansion may still + contain dipole terms: A[0], B[0] + +The kick is given by + + e L +theta = - --- B + x p y + 0 + + e L +theta = --- B + y p x + 0 + +******************************************************************************/ +/* clang-format on */ + double ReSum = B[max_order]; + double ImSum = A[max_order]; + double ReSumTemp; + double x = r6[0]; + double y = r6[2]; + + /* recursively calculate the local transverse magnetic field */ + for (int i = max_order - 1; i >= 0; i--) { + ReSumTemp = ReSum*x - ImSum*y + B[i]; + ImSum = ImSum*x + ReSum*y + A[i]; + ReSum = ReSumTemp; + } + ReSum += B0; + ImSum += A0; + + #ifdef RADIATION + double p_norm = 1.0 / (1.0+r6[4]); + + /* calculate angles from momenta */ + double xpr = r6[1] * p_norm; + double ypr = r6[3] * p_norm; + + #ifdef CURVATURE_IN_B0 + double B2P = B2perp(ImSum, ReSum, x, xpr, y ,ypr); + #else + double B2P = B2perp(ImSum, ReSum + irho, x, xpr, y ,ypr); + #endif + double factor = L / sqrt(1.0 - SQR(xpr) - SQR(ypr)) / SQR(p_norm); + + /* Propagation of the diffusion matrix */ + if (bdiff) { + thinkickM(r6, A, B, max_order, L, 0.0, bdiff); + thinkickB(r6, ReSum, ImSum, diff_const, B2P, factor, bdiff); + } + + /* Momentum loss */ + r6[4] -= rad_const * B2P * factor; + + /* Recalculate momenta from angles after losing energy */ + p_norm = 1.0 / (1.0 + r6[4]); + r6[1] = xpr / p_norm; + r6[3] = ypr / p_norm; + #endif /* RADIATION */ + + /* Multipole kick */ + r6[1] -= L * ReSum; + r6[3] += L * ImSum; +} diff --git a/atintegrators/kick_h_k0h_k1h_kn.h b/atintegrators/kick_h_k0h_k1h_kn.h new file mode 100644 index 0000000000..ee160ee5f1 --- /dev/null +++ b/atintegrators/kick_h_k0h_k1h_kn.h @@ -0,0 +1,115 @@ +/*********************************************************************** +Expansion of the magnetic field in AT: + + max_order + ---- + \ n + (B + iB )/ B rho = > (iA + B ) (x + iy) + y x / n n + ---- + n=0 + + A,B: i=0 ... max_order + [0] - dipole, [1] - quadrupole, [2] - sextupole ... + units for A,B[i] = 1/[m]^(i+1) +*************************************************************************/ + +#ifdef RADIATION +#include "diff_thinkick.c" + +static double B2perp(double bx, double by, double irho, double x, double xpr, double y, double ypr) +/* Calculates sqr(|B x e|), where e is a unit vector in the direction of velocity */ +{ + double xh1 = SQR(1.0 + x*irho); + double v_norm2 = (xh1 + SQR(xpr) + SQR(ypr)); + + /* components of the velocity vector: + ex = xpr; + ey = ypr; + ez = (1+x*irho); + + sqr(|B x e|) = sqr(|B|) * sqr(|e|) - sqr(B.e) + */ + + return((xh1*SQR(by) + xh1*SQR(bx) + SQR(bx*ypr - by*xpr)) / v_norm2) ; +} + +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho, double rad_const, double diff_const, double *bdiff) +#else +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho) +#endif /* RADIATION */ +{ +/* clang-format off */ +/***************************************************************************** +Calculate multipole kick in a curved element (bending magnet) +The reference coordinate system has the curvature given by the inverse (design) radius irho. +IMPORTANT !!! +The magnetic field Bo that provides this curvature MUST NOT be included in the dipole term + +The kick is given by + 2 2 + e L L delta L x L K1 (x - y /2) +theta = - --- B + ------- - ----- - -----------------, + x p y rho 2 rho + 0 rho + + e L L K1 x y +theta = --- B + ---------- + y p x rho + 0 + +******************************************************************************/ +/* clang-format on */ + double ReSum = B[max_order]; + double ImSum = A[max_order]; + double ReSumTemp; + double x = r6[0]; + double y = r6[2]; + double dp_0 = r6[4]; /* save a copy of the initial value of dp/p */ + double B1 = (max_order >= 1) ? B[1] : 0.0; + + /* recursively calculate the local transverse magnetic field */ + for (int i = max_order - 1; i >= 0; i--) { + ReSumTemp = ReSum*x - ImSum*y + B[i]; + ImSum = ImSum*x + ReSum*y + A[i]; + ReSum = ReSumTemp; + } + ReSum += B0; + ImSum += A0; + + #ifdef RADIATION + double p_norm = 1.0 / (1.0+r6[4]); + + /* calculate angles from momenta */ + double xpr = r6[1] * p_norm; + double ypr = r6[3] * p_norm; + + #ifdef CURVATURE_IN_B0 + double B2P = B2perp(ImSum, ReSum, irho, x, xpr, y ,ypr); + #else + double B2P = B2perp(ImSum, ReSum + irho, irho, x, xpr, y ,ypr); + #endif + double factor = L * (1.0 + x*irho + (SQR(xpr) + SQR(ypr)) / 2.0) / SQR(p_norm); + + /* Propagation of the diffusion matrix */ + if (bdiff) { + thinkickM(r6, A, B, max_order, L, irho, bdiff); + thinkickB(r6, ReSum, ImSum, diff_const, B2P, factor, bdiff); + } + + /* Momentum loss */ + r6[4] -= rad_const * B2P * factor; + + /* Recalculate momenta from angles after losing energy */ + p_norm = 1.0 / (1.0 + r6[4]); + r6[1] = xpr / p_norm; + r6[3] = ypr / p_norm; + #endif /* RADIATION */ + + /* Multipole kick */ + r6[1] -= L * (ReSum + irho*(x*irho - dp_0 + B1*(x*x-0.5*y*y))); + r6[3] += L * (ImSum + irho*B1*x*y); + r6[5] += L * irho*x; /* pathlength */ +} diff --git a/atintegrators/kick_k1h_kn.h b/atintegrators/kick_k1h_kn.h new file mode 100644 index 0000000000..ea9312887e --- /dev/null +++ b/atintegrators/kick_k1h_kn.h @@ -0,0 +1,111 @@ +/*********************************************************************** +Expansion of the magnetic field in AT: + + max_order + ---- + \ n + (B + iB )/ B rho = > (iA + B ) (x + iy) + y x / n n + ---- + n=0 + + A,B: i=0 ... max_order + [0] - dipole, [1] - quadrupole, [2] - sextupole ... + units for A,B[i] = 1/[m]^(i+1) +*************************************************************************/ + +#ifdef DIFFUSION +#error "kick_k1h_kn does not compute the diffusion matrix" +#endif + +#ifdef RADIATION + +static double B2perp(double bx, double by, double irho, double x, double xpr, double y, double ypr) +/* Calculates sqr(|B x e|), where e is a unit vector in the direction of velocity */ +{ + /* components of the velocity vector + ex = xpr; + ey = ypr; + ez = (1 + x*irho) * sqrt(1 - xpr^2 - ypr^2); + + sqr(|B x e|) = sqr(|B|) * sqr(|e|) - sqr(B.e) + */ + double nrm = SQR(1.0 + x*irho); + double v_norm2 = nrm + SQR(xpr)*(1.0-nrm) + SQR(ypr)*(1.0-nrm); + + return SQR(bx) + SQR(by) - SQR(bx*xpr + by*ypr) / v_norm2; +} + +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho, double rad_const, double diff_const, double *bdiff) +#else +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho) +#endif /* RADIATION */ +{ +/* clang-format off */ +/***************************************************************************** +Calculate multipole kick in a curved element (bending magnet) +The reference coordinate system has the curvature given by the inverse +(design) radius irho. +IMPORTANT !!! +The magnetic field Bo that provides this curvature MUST NOT be included in the dipole term +PolynomB[1](MATLAB notation)(C: B[0] in this function) of the By field expansion + +The kick is given by + 2 2 + e L L K1 (x - y /2) +theta = - --- B + -----------------, + x p y rho + 0 + + e L L K1 x y +theta = --- B + ---------- + y p x rho + 0 + +******************************************************************************/ +/* clang-format on */ + double ReSum = B[max_order]; + double ImSum = A[max_order]; + double ReSumTemp; + double x = r6[0]; + double y = r6[2]; + double B1 = (max_order >= 1) ? B[1] : 0.0; + + /* recursively calculate the local transverse magnetic field */ + for (int i = max_order - 1; i >= 0; i--) { + ReSumTemp = ReSum*x - ImSum*y + B[i]; + ImSum = ImSum*x + ReSum*y + A[i]; + ReSum = ReSumTemp; + } + ReSum += B0; + ImSum += A0; + + #ifdef RADIATION + double p_norm = 1.0 / (1.0+r6[4]); + + /* calculate angles from momenta */ + double xpr = r6[1] * p_norm; + double ypr = r6[3] * p_norm; + + #ifdef CURVATURE_IN_B0 + double B2P = B2perp(ImSum, ReSum, irho, x, xpr, y ,ypr); + #else + double B2P = B2perp(ImSum, ReSum + irho, irho, x, xpr, y ,ypr); + #endif + double factor = L * (1.0 + x*irho) / sqrt(1.0 - xpr*xpr - ypr*ypr) / SQR(p_norm); + + /* Momentum loss */ + r6[4] -= rad_const * B2P * factor; + + /* Recalculate momenta from angles after losing energy */ + p_norm = 1.0 / (1.0 + r6[4]); + r6[1] = xpr / p_norm; + r6[3] = ypr / p_norm; + #endif /* RADIATION */ + + /* Multipole kick */ + r6[1] -= L * (ReSum + irho*B1*(x*x-0.5*y*y)); + r6[3] += L * (ImSum + irho*B1*x*y); +} diff --git a/atintegrators/kick_kn.h b/atintegrators/kick_kn.h new file mode 100644 index 0000000000..ab2ccdbb4b --- /dev/null +++ b/atintegrators/kick_kn.h @@ -0,0 +1,110 @@ +/*********************************************************************** +Expansion of the magnetic field in AT: + + max_order + ---- + \ n + (B + iB )/ B rho = > (iA + B ) (x + iy) + y x / n n + ---- + n=0 + + A,B: i=0 ... max_order + [0] - dipole, [1] - quadrupole, [2] - sextupole ... + units for A,B[i] = 1/[m]^(i+1) +*************************************************************************/ + +#ifdef RADIATION +#include "diff_thinkick.c" + +static double B2perp(double bx, double by, double x, double xpr, double y, double ypr) +/* Calculates sqr(|B x e|), where e is a unit vector in the direction of velocity */ +{ + /* components of the velocity vector: + ex = xpr; + ey = ypr; + ez = 1 + + sqr(|B x e|) = sqr(|B|) * sqr(|e|) - sqr(B.e) + */ + double v_norm2 = (1.0+ SQR(xpr) + SQR(ypr)); + + return (SQR(by) + SQR(bx) + SQR(bx*ypr - by*xpr)) / v_norm2 ; +} + +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho, double rad_const, double diff_const, double *bdiff) +#else +static void kick(double *r6, double A0, double B0, const double *A, const double *B, int max_order, + double L, double irho) +#endif /* RADIATION */ +{ +/* clang-format off */ +/***************************************************************************** +Calculate multipole kick in a straight element + IMPORTANT !!! + The reference coordinate system is straight but the field expansion may still + contain dipole terms: A[0], B[0] + +The kick is given by + + e L +theta = - --- B + x p y + 0 + + e L +theta = --- B + y p x + 0 + +******************************************************************************/ +/* clang-format on */ + double ReSum = B[max_order]; + double ImSum = A[max_order]; + double ReSumTemp; + double x = r6[0]; + double y = r6[2]; + + /* recursively calculate the local transverse magnetic field */ + for (int i = max_order - 1; i >= 0; i--) { + ReSumTemp = ReSum*x - ImSum*y + B[i]; + ImSum = ImSum*x + ReSum*y + A[i]; + ReSum = ReSumTemp; + } + ReSum += B0; + ImSum += A0; + + #ifdef RADIATION + double p_norm = 1.0 / (1.0+r6[4]); + + /* calculate angles from momenta */ + double xpr = r6[1] * p_norm; + double ypr = r6[3] * p_norm; + + #ifdef CURVATURE_IN_B0 + double B2P = B2perp(ImSum, ReSum, x, xpr, y ,ypr); + #else + double B2P = B2perp(ImSum, ReSum + irho, x, xpr, y ,ypr); + #endif + double factor = L * (1.0 + (SQR(xpr) + SQR(ypr)) / 2.0) / SQR(p_norm); + + /* Propagation of the diffusion matrix */ + if (bdiff) { + thinkickM(r6, A, B, max_order, L, 0.0, bdiff); + thinkickB(r6, ReSum, ImSum, diff_const, B2P, factor, bdiff); + } + + /* Momentum loss */ + r6[4] -= rad_const * B2P * factor; + + /* Recalculate momenta from angles after losing energy */ + p_norm = 1.0 / (1.0 + r6[4]); + r6[1] = xpr / p_norm; + r6[3] = ypr / p_norm; + #endif /* RADIATION */ + + /* Multipole kick */ + r6[1] -= L * ReSum; + r6[3] += L * ImSum; +} diff --git a/atintegrators/quadfringe.c b/atintegrators/linearquadfringe.h similarity index 54% rename from atintegrators/quadfringe.c rename to atintegrators/linearquadfringe.h index 77d6618477..577cf6b3da 100644 --- a/atintegrators/quadfringe.c +++ b/atintegrators/linearquadfringe.h @@ -2,7 +2,7 @@ static void QuadFringePassP(double* r, const double b2) { -/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] +/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] Lee-Whiting's thin lens limit formula as given in p. 390 of "Beam Dynamics..."by E. Forest */ register double u = b2/(12.0*(1.0+r[4])); register double x2 = r[0]*r[0]; @@ -15,19 +15,19 @@ static void QuadFringePassP(double* r, const double b2) r[0]+=gx; r1tmp=3*u*(2*xz*r[3]-(x2+z2)*r[1]); - + r[2]-=gz; - + r3tmp=3*u*(2*xz*r[1]-(x2+z2)*r[3]); r[5]-=(gz*r[3] - gx*r[1])/(1+r[4]); - + r[1]+=r1tmp; r[3]-=r3tmp; } static void QuadFringePassN(double* r, const double b2) { -/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] +/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] Lee-Whiting's thin lens limit formula as given in p. 390 of "Beam Dynamics..."by E. Forest */ register double u = b2/(12.0*(1.0+r[4])); register double x2 = r[0]*r[0]; @@ -40,12 +40,12 @@ static void QuadFringePassN(double* r, const double b2) r[0]-=gx; r1tmp=3*u*(2*xz*r[3]-(x2+z2)*r[1]); - + r[2]+=gz; - + r3tmp=3*u*(2*xz*r[1]-(x2+z2)*r[3]); r[5]+=(gz*r[3] - gx*r[1])/(1+r[4]); - + r[1]-=r1tmp; r[3]+=r3tmp; } @@ -57,38 +57,38 @@ static void quadPartialFringeMatrix(double R[6][6], double K1, double inFringe, double K1sqr, expJ1x, expJ1y; R[4][4] = R[5][5] = 1; - + K1sqr = K1*K1; if (part==1) { - J1x = inFringe*(K1*fringeInt[1] - 2*K1sqr*fringeInt[3]/3. - K1sqr * fringeInt[0] * fringeInt[2] / 2); - J2x = inFringe*K1*fringeInt[2]; - J3x = inFringe*K1sqr*(fringeInt[2] + fringeInt[4] + fringeInt[0] * fringeInt[1]); + J1x = inFringe*(K1*fringeInt[1] - 2*K1sqr*fringeInt[3]/3.); + J2x = inFringe*(K1*fringeInt[2]); + J3x = inFringe*(K1sqr*(fringeInt[2] + fringeInt[4])); - //K1 = -K1; - J1y = inFringe * (-K1 * fringeInt[1] - 2 * K1sqr * fringeInt[3] / 3. - K1sqr * fringeInt[0] * fringeInt[2] / 2); + K1 = -K1; + J1y = inFringe*(K1*fringeInt[1] - 2*K1sqr*fringeInt[3]/3.); J2y = -J2x; J3y = J3x; } else { - J1x = inFringe * (K1 * fringeInt[1] + K1sqr * fringeInt[0] * fringeInt[2] / 2); - J2x = inFringe * K1 * fringeInt[2]; - J3x = inFringe * K1sqr * (fringeInt[4] - fringeInt[0] * fringeInt[1]); + J1x = inFringe*(K1*fringeInt[1] + K1sqr*fringeInt[0]*fringeInt[2]/2); + J2x = inFringe*(K1*fringeInt[2]); + J3x = inFringe*(K1sqr*(fringeInt[4]-fringeInt[0]*fringeInt[1])); - //K1 = -K1; - J1y = inFringe * (-K1 * fringeInt[1] + K1sqr * fringeInt[0] * fringeInt[2] / 2); + K1 = -K1; + J1y = inFringe*(K1*fringeInt[1] + K1sqr*fringeInt[0]*fringeInt[2]); J2y = -J2x; J3y = J3x; } expJ1x = R[0][0] = exp(J1x); - R[0][1] = J2x / expJ1x; - R[1][0] = expJ1x * J3x; - R[1][1] = (1 + J2x * J3x) / expJ1x; - + R[0][1] = J2x/expJ1x; + R[1][0] = expJ1x*J3x; + R[1][1] = (1 + J2x*J3x)/expJ1x; + expJ1y = R[2][2] = exp(J1y); - R[2][3] = J2y / expJ1y; - R[3][2] = expJ1y * J3y; - R[3][3] = (1 + J2y * J3y) / expJ1y; + R[2][3] = J2y/expJ1y; + R[3][2] = expJ1y*J3y; + R[3][3] = (1 + J2y*J3y)/expJ1y; return; } @@ -98,36 +98,27 @@ static void linearQuadFringeElegantEntrance(double* r6, double b2, double *fring double R[6][6]; double *fringeIntM, *fringeIntP; double delta, inFringe; - double x, px, y, py, swap_temp; /* quadrupole linear fringe field, from elegant code */ - inFringe=1.0; - fringeIntM = fringeIntM0; - fringeIntP = fringeIntP0; + inFringe=-1.0; + fringeIntM = fringeIntP0; + fringeIntP = fringeIntM0; delta = r6[4]; /* determine first linear matrix for this delta */ - quadPartialFringeMatrix(R, b2, inFringe, fringeIntP, 2); - swap_temp = R[0][0]; R[0][0] = R[1][1]; R[1][1] = swap_temp; - swap_temp = R[2][2]; R[2][2] = R[3][3]; R[3][3] = swap_temp; - - x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; - r6[0] = R[0][0]*x + R[0][1]*px; - r6[1] = R[1][0]*x + R[1][1]*px; - r6[2] = R[2][2]*y + R[2][3]*py; - r6[3] = R[3][2]*y + R[3][3]*py; + quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntM, 1); + r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; + r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; + r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; + r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; /* nonlinear fringe field */ QuadFringePassP(r6,b2); /*This is original AT code*/ /*Linear fringe fields from elegant*/ - inFringe=1.0; + inFringe=-1.0; /* determine and apply second linear matrix, from elegant code */ - quadPartialFringeMatrix(R, b2, inFringe, fringeIntM, 1); - swap_temp = R[0][0]; R[0][0] = R[1][1]; R[1][1] = swap_temp; - swap_temp = R[2][2]; R[2][2] = R[3][3]; R[3][3] = swap_temp; - - x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; - r6[0] = R[0][0]*x + R[0][1]*px; - r6[1] = R[1][0]*x + R[1][1]*px; - r6[2] = R[2][2]*y + R[2][3]*py; - r6[3] = R[3][2]*y + R[3][3]*py; + quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntP, 2); + r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; + r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; + r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; + r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; } @@ -136,28 +127,27 @@ static void linearQuadFringeElegantExit(double* r6, double b2, double *fringeInt double R[6][6]; double *fringeIntM, *fringeIntP; double delta, inFringe; - double x, px, y, py; /* quadrupole linear fringe field, from elegant code */ inFringe=1.0; fringeIntM = fringeIntM0; fringeIntP = fringeIntP0; delta = r6[4]; /* determine first linear matrix for this delta */ - quadPartialFringeMatrix(R, b2, inFringe, fringeIntM, 1); - x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; - r6[0] = R[0][0]*x + R[0][1]*px; - r6[1] = R[1][0]*x + R[1][1]*px; - r6[2] = R[2][2]*y + R[2][3]*py; - r6[3] = R[3][2]*y + R[3][3]*py; + quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntP, 2); + r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; + r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; + r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; + r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; /* nonlinear fringe field */ QuadFringePassN(r6,b2); /*This is original AT code*/ /*Linear fringe fields from elegant*/ inFringe=1.0; /* determine and apply second linear matrix, from elegant code */ - quadPartialFringeMatrix(R, b2, inFringe, fringeIntP, 2); - x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; - r6[0] = R[0][0]*x + R[0][1]*px; - r6[1] = R[1][0]*x + R[1][1]*px; - r6[2] = R[2][2]*y + R[2][3]*py; - r6[3] = R[3][2]*y + R[3][3]*py; -} \ No newline at end of file + quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntM, 1); + r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; + r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; + r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; + r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; +} + + diff --git a/atintegrators/magnet_template.h b/atintegrators/magnet_template.h new file mode 100644 index 0000000000..1f8d95487f --- /dev/null +++ b/atintegrators/magnet_template.h @@ -0,0 +1,357 @@ +#include "atconstants.h" +#include "atelem.c" +#include "atlalib.c" +#include "integrators.h" + +#ifndef CHECK_NSTEPS +#define CHECK_NSTEPS \ + if (NumIntSteps <= 0) { \ + atError("NumIntSteps must be positive"); check_error(); \ + } +#endif + +struct elem +{ + double Length; + double *PolynomA; + double *PolynomB; + int MaxOrder; + int NumIntSteps; + double BendingAngle; + double EntranceAngle; + double ExitAngle; + /* Optional fields */ + double Energy; + double Scaling; + int FringeBendEntrance; + int FringeBendExit; + double gK_entrance; + double gK_exit; + int FringeQuadEntrance; + int FringeQuadExit; + double *fringeIntM0; + double *fringeIntP0; + double *R1; + double *R2; + double *T1; + double *T2; + double *RApertures; + double *EApertures; + double *KickAngle; +#ifdef STRAIGHT_DIPOLE + double X0ref; + double RefDZ; +#endif /*STRAIGHT_DIPOLE*/ +#ifdef E2_DIPOLE + double H1; + double H2; +#endif /*E2_DIPOLE*/ +}; + +static void magnet(double *r, double le, double bending_angle, + double *A, double *B, + int max_order, int num_int_steps, + double entrance_angle, double exit_angle, + int FringeBendEntrance, int FringeBendExit, + double gK_entrance, double gK_exit, + int FringeQuadEntrance, int FringeQuadExit, + double *fringeIntM0, /* I0m/K1, I1m/K1, I2m/K1, I3m/K1, Lambda2m/K1 */ + double *fringeIntP0, /* I0p/K1, I1p/K1, I2p/K1, I3p/K1, Lambda2p/K1 */ + double *T1, double *T2, + double *R1, double *R2, + double *RApertures, double *EApertures, + double *KickAngle, double scaling, +#if defined(STRAIGHT_DIPOLE) + double x0ref, + double refdz, +#endif +#if defined(E2_DIPOLE) + double h1, + double h2, +#endif +#if defined(RADIATION) + double gamma0, + double *bdiff, +#endif +#if defined(QUANTUM) + double gamma0, + pcg32_random_t *rng, +#endif + int num_particles +) +{ + double irho = bending_angle / le; + #ifdef RADIATION + double rad_const = RAD_CONST*pow(gamma0, 3); + double diff_const = DIF_CONST*pow(gamma0, 5); + #else + double *bdiff = NULL; + #endif + #ifdef STRAIGHT_DIPOLE + double phi2 = 0.5 * bending_angle; + double phi_entrance = phi2-entrance_angle; + double phi_exit = phi2-exit_angle; + double LR = fabs(phi2) < 1.e-10 ? le : le *sin(phi2) / phi2; + double SL = (num_int_steps > 0) ? LR/num_int_steps : LR; + #else + double refdz = 0.0; + double SL = (num_int_steps > 0) ? le/num_int_steps : le; + #endif /*STRAIGHT_DIPOLE*/ + double B1 = (max_order >= 1) ? B[1] : 0.0; + double A0 = 0.0; + #ifdef CURVATURE_IN_B0 + double B0 = irho; + #else + double B0 = 0.0; + #endif + + if (KickAngle) { /* Convert corrector component to polynomial coefficients */ + B0 -= sin(KickAngle[0]) / le; + A0 += sin(KickAngle[1]) / le; + } + + #ifndef NO_OMP + #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(shared) + #endif + for (int c = 0; cenergy, atGetOptionalDouble(ElemData,"Energy", Param->energy)); check_error(); + #else + double Energy=0.0; + #endif + double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); + int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); \ + int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); + double *fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); + double *fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); + double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); + double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); + double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); + double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); + double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); + double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); + double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); + CHECK_NSTEPS + + Elem = (struct elem*)atMalloc(sizeof(struct elem)); + Elem->Length=Length; + Elem->PolynomA=PolynomA; + Elem->PolynomB=PolynomB; + Elem->MaxOrder=MaxOrder; + Elem->NumIntSteps=NumIntSteps; + MAGNET_ITEMS + /*optional fields*/ + Elem->Energy=Energy; + Elem->Scaling=Scaling; + Elem->FringeQuadEntrance=FringeQuadEntrance; \ + Elem->FringeQuadExit=FringeQuadExit; \ + Elem->fringeIntM0=fringeIntM0; \ + Elem->fringeIntP0=fringeIntP0; \ + Elem->R1=R1; + Elem->R2=R2; + Elem->T1=T1; + Elem->T2=T2; + Elem->EApertures=EApertures; + Elem->RApertures=RApertures; + Elem->KickAngle=KickAngle; + } + #if defined(RADIATION) || defined(QUANTUM) + double gamma0 = atGamma(Param->energy, Elem->Energy, Param->rest_energy); check_error(); + #ifdef DIFFUSION + bdiff = Param->bdiff; + #endif + #endif + magnet(r_in, Elem->Length, Elem->BendingAngle, + Elem->PolynomA, Elem->PolynomB, + Elem->MaxOrder, Elem->NumIntSteps, Elem->EntranceAngle, Elem->ExitAngle, + Elem->FringeBendEntrance,Elem->FringeBendExit, + Elem->gK_entrance, Elem->gK_exit, + Elem->FringeQuadEntrance, Elem->FringeQuadExit, + Elem->fringeIntM0, Elem->fringeIntP0, + Elem->T1, Elem->T2, Elem->R1, Elem->R2, + Elem->RApertures, Elem->EApertures, + Elem->KickAngle, Elem->Scaling, + #if defined(STRAIGHT_DIPOLE) + Elem->X0ref, + Elem->RefDZ, + #endif + #if defined(E2_DIPOLE) + Elem->H1, + Elem->H2, + #endif + #if defined(RADIATION) + gamma0, + bdiff, + #endif + #if defined(QUANTUM) + gamma0, + Param->thread_rng, + #endif + num_particles); + return Elem; +} + +MODULE_DEF(MAGNET_PASS) /* Dummy module initialisation */ + +#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ + +#if defined(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]); + if (mxGetM(prhs[1]) != 6) mexErrMsgTxt("Second argument must be a 6 x N matrix"); + + double Length=atGetDouble(ElemData,"Length"); check_error(); + double *PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); + double *PolynomB=atGetDoubleArray(ElemData,"PolynomB"); check_error(); + int MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); + int NumIntSteps=atGetLong(ElemData,"NumIntSteps"); check_error(); + MAGNET_ARGUMENTS + /*optional fields*/ + double Scaling=atGetOptionalDouble(ElemData,"FieldScaling",1.0); check_error(); + int FringeQuadEntrance=atGetOptionalLong(ElemData,"FringeQuadEntrance",0); check_error(); \ + int FringeQuadExit=atGetOptionalLong(ElemData,"FringeQuadExit",0); check_error(); + double *fringeIntM0=atGetOptionalDoubleArray(ElemData,"fringeIntM0"); check_error(); + double *fringeIntP0=atGetOptionalDoubleArray(ElemData,"fringeIntP0"); check_error(); + double *R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); + double *R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); + double *T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); + double *T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); + double *EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); + double *RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); + double *KickAngle=atGetOptionalDoubleArray(ElemData,"KickAngle"); check_error(); + CHECK_NSTEPS + MAGNET_MEX_ITEMS + + /* ALLOCATE memory for the output array of the same size as the input */ + plhs[0] = mxDuplicateArray(prhs[1]); + r_in = mxGetDoubles(plhs[0]); + + #if defined(RADIATION) || defined(QUANTUM) + double Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); + double rest_energy = 0.0;; + double charge = -1.0; + if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); + double gamma0 = atGamma(Energy, Energy, rest_energy); + #endif + + magnet(r_in, Length, BendingAngle, PolynomA, PolynomB, + MaxOrder, NumIntSteps, EntranceAngle, ExitAngle, + FringeBendEntrance, FringeBendExit, + gK_entrance, gK_exit, + FringeQuadEntrance, FringeQuadExit, + fringeIntM0, fringeIntP0, + T1, T2, R1, R2, RApertures, EApertures, + KickAngle, Scaling, + #if defined(STRAIGHT_DIPOLE) + X0ref, + RefDZ, + #endif + #if defined(E2_DIPOLE) + H1, + H2, + #endif + #if defined(RADIATION) + gamma0, + NULL, + #endif + #if defined(QUANTUM) + gamma0, + &pcg32_global, + #endif + num_particles); + } else if (nrhs == 0) { + /* list of required fields */ + int i0 = 0; + plhs[0] = mxCreateCellMatrix(5+N_REQUIRED, 1); + mxSetCell(plhs[0], i0++, mxCreateString("Length")); + mxSetCell(plhs[0], i0++, mxCreateString("PolynomA")); + mxSetCell(plhs[0], i0++, mxCreateString("PolynomB")); + mxSetCell(plhs[0], i0++, mxCreateString("MaxOrder")); + mxSetCell(plhs[0], i0++, mxCreateString("NumIntSteps")); + for (int i=0; i1) { /* list of optional fields */ + int i1 = 0; + plhs[1] = mxCreateCellMatrix(12+N_OPTIONAL, 1); + for (int i=0; i 0) { // Skip field order 0 + U = f1 * (B * RX - A * IX); + V = f1 * (B * IX + A * RX); + DU = f1 * (B * DRX - A * DIX); + DV = f1 * (B * DIX + A * DRX); + } + + const double DUX = j * DU; + const double DVX = j * DV; + const double DUY = -j * DV; + const double DVY = j * DU; + + + FX += U * x + nf * V * y; + FY += U * y - nf * V * x; + + FX_X += DUX * x + U + nf * y * DVX; + FX_Y += DUY * x + nf * (V + y * DVY); + FY_X += DUX * y - nf * (V + x * DVX); + FY_Y += DUY * y + U - nf * x * DVY; + } + + + // solve 2x2 matrix equation + + double A = 1.0 - FX_X * p_norm; + double B = -FY_X * p_norm; + double C = -FX_Y * p_norm; + double D = 1.0 - FY_Y * p_norm; + double det = A*D - B*C; + + double pxf = (D * r6[px_] - B * r6[py_]) / det; + double pyf = (A * r6[py_] - C * r6[px_]) / det; + + r6[x_] -= FX * p_norm; + r6[y_] -= FY * p_norm; + r6[px_] = pxf; + r6[py_] = pyf; + r6[ct_] = r6[ct_] - (pxf * FX + pyf * FY) * p_norm * p_norm; +} + +static void multipole_fringe(double *r6, int method, double B1, + const double *polya, const double *polyb, int max_order, + double *fringeIntM0, double *fringeIntP0, + double edge) +{ + switch (method) { + case 1: quad_fringe(r6, B1, edge); + break; + case 2: if (fringeIntM0 && fringeIntP0) { + if (edge > 0) + linearQuadFringeElegantEntrance(r6, B1, fringeIntM0, fringeIntP0); + else + linearQuadFringeElegantExit(r6, B1, fringeIntM0, fringeIntP0); + } + else + quad_fringe(r6, B1, edge); + break; + case 3: all_mult_fringe(r6, polya, polyb, max_order, edge); + break; + } +} \ No newline at end of file diff --git a/atintegrators/atquantlib.c b/atintegrators/quantum_diffusion.h similarity index 93% rename from atintegrators/atquantlib.c rename to atintegrators/quantum_diffusion.h index 0826cdb319..6250293049 100644 --- a/atintegrators/atquantlib.c +++ b/atintegrators/quantum_diffusion.h @@ -454,3 +454,44 @@ static double getEnergy(pcg32_random_t *rng, double ec) return re * ec; } + +const double alpha0 = 7.2973525643e-3; // fine-structure constant [] - from CODATA 2022 +const double emass = 510998.95069; // electron mass [eV] - from CODATA 2022 +const double CST1 = 1.0e9 * 3.0/ 2.0 * __HBAR_C / emass; // [m] +const double CST2 = 5.0 * ROOT_3 / 6.0 * alpha0; // [] + +#define INTEGRATOR_PREFIX \ + double dp1 = 1.0 + r6[4]; \ + double gamma = dp1 * gamma0; \ + double cstec = CST1 * gamma * gamma; \ + double cstng = CST2 * gamma; \ + double p_norm = 1.0 / dp1; \ + double xp0 = r6[1] * p_norm; \ + double yp0 = r6[3] * p_norm; \ + double s0 = r6[5]; + +#ifdef ABSOLUTE_PATH_LENGTH +#define SLDS ds +#else +#define SLDS (SL + ds) +#endif + +#define INTEGRATOR_SUFFIX \ + double dxp = r6[1] * p_norm - xp0 - irho * SL; \ + double dyp = r6[3] * p_norm - yp0; \ + double ds = r6[5] - s0; \ + \ + double rho = SLDS / sqrt(dxp * dxp + dyp * dyp); \ + \ + double ng = cstng / rho * SLDS; \ + double ec = cstec / rho; \ + \ + int nph = atrandp_r(rng, ng); \ + \ + double dee = 0.0; \ + for (int i = 0; i < nph; i++) { \ + dee = dee + getEnergy(rng, ec); \ + }; \ + r6[4] = r6[4] - dee; \ + r6[1] = r6[1] * p_norm * (1 + r6[4]); \ + r6[3] = r6[3] * p_norm * (1 + r6[4]); diff --git a/atintegrators/straight_dipole.h b/atintegrators/straight_dipole.h new file mode 100644 index 0000000000..73564d5a5d --- /dev/null +++ b/atintegrators/straight_dipole.h @@ -0,0 +1,74 @@ +#ifndef STRAIGHT_DIPOLE +#define STRAIGHT_DIPOLE +#include "bendfringe.h" +#include "multipolefringe.h" + +#ifndef MAGNET_ENTRY +#define MAGNET_ENTRY \ + /* Change to the magnet referential */ \ + Yrot(r6, entrance_angle, bdiff); \ + \ + /* Entry face */ \ + r6[0] += x0ref; \ + if (FringeBendEntrance) \ + bend_fringe(r6, irho, gK_entrance); \ + multipole_fringe(r6, FringeQuadEntrance, B1, A, B, max_order, fringeIntM0, fringeIntP0, 1.0); \ + if (phi_entrance != 0.0) { \ + if (B1 != 0.0 && FringeBendEntrance) quad_wedge(r6, -B1 * phi_entrance); \ + bend_wedge(r6, irho, phi_entrance, bdiff); \ + } +#endif /*MAGNET_ENTRY*/ + +#ifndef MAGNET_EXIT +#define MAGNET_EXIT \ + /* Exit face */ \ + if (phi_exit != 0.0) { \ + bend_wedge(r6, irho, phi_exit, bdiff); \ + if (B1 != 0.0 && FringeQuadExit) quad_wedge(r6, -B1 * phi_exit); \ + } \ + multipole_fringe(r6, FringeQuadExit, B1, A, B, max_order, fringeIntM0, fringeIntP0, -1.0); \ + if (FringeBendExit) \ + bend_fringe(r6, -irho, gK_exit); \ + r6[0] -= x0ref; \ + \ + /* Change back to the lattice referential */ \ + Yrot(r6, exit_angle, bdiff); +#endif /*MAGNET_EXIT*/ + +#define MAGNET_ARGUMENTS \ + double BendingAngle=atGetOptionalDouble(ElemData,"BendingAngle", 0.0); check_error(); \ + double EntranceAngle=atGetDouble(ElemData,"EntranceAngle"); check_error(); \ + double ExitAngle=atGetDouble(ElemData,"ExitAngle"); check_error(); \ + int FringeBendEntrance=atGetOptionalLong(ElemData,"FringeBendEntrance",4); check_error(); \ + int FringeBendExit=atGetOptionalLong(ElemData,"FringeBendExit",4); check_error(); \ + double FullGap=atGetOptionalDouble(ElemData,"FullGap",0.0); check_error(); \ + double FringeInt1=atGetOptionalDouble(ElemData,"FringeInt1",0.0); check_error(); \ + double FringeInt2=atGetOptionalDouble(ElemData,"FringeInt2",0.0); check_error(); \ + double X0ref=atGetOptionalDouble(ElemData,"X0ref", 0.0); check_error(); \ + double RefDZ=atGetOptionalDouble(ElemData,"RefDZ", 0.0); check_error(); + +#define MAGNET_ITEMS \ + Elem->BendingAngle=BendingAngle; \ + Elem->EntranceAngle=EntranceAngle; \ + Elem->ExitAngle=ExitAngle; \ + Elem->FringeBendEntrance=FringeBendEntrance; \ + Elem->FringeBendExit=FringeBendExit; \ + Elem->gK_entrance=FullGap*FringeInt1; \ + Elem->gK_exit=FullGap*FringeInt2; \ + Elem->X0ref=X0ref; \ + Elem->RefDZ=RefDZ; + +#ifdef MATLAB_MEX_FILE +#define MAGNET_MEX_ITEMS \ + double gK_entrance=FullGap*FringeInt1; \ + double gK_exit=FullGap*FringeInt2; + +const char *required[] = {"BendingAngle", "EntranceAngle", "ExitAngle"}; +const char *optional[] = {"FringeBendEntrance", "FringeBendExit", "FullGap", "FringeInt1", "FringeInt2", "X0ref", "RefDZ"}; +#define N_REQUIRED 3 +#define N_OPTIONAL 7 +#endif /*MATLAB_MEX_FILE*/ +#endif /*STRAIGHT_DIPOLE*/ + + + diff --git a/atintegrators/straight_multipole.h b/atintegrators/straight_multipole.h new file mode 100644 index 0000000000..ae8730f12f --- /dev/null +++ b/atintegrators/straight_multipole.h @@ -0,0 +1,46 @@ +#ifndef STRAIGHT_MULTIPOLE +#define STRAIGHT_MULTIPOLE +#include "multipolefringe.h" + +#ifndef MAGNET_ENTRY +#define MAGNET_ENTRY \ + /* Entry face */ \ + multipole_fringe(r6, FringeQuadEntrance, B1, A, B, max_order, fringeIntM0, fringeIntP0, 1.0); +#endif /*MAGNET_ENTRY*/ + +#ifndef MAGNET_EXIT +#define MAGNET_EXIT \ + /* Exit face */ \ + multipole_fringe(r6, FringeQuadExit, B1, A, B, max_order, fringeIntM0, fringeIntP0, -1.0); +#endif /*MAGNET_EXIT*/ + +#define MAGNET_ARGUMENTS + +#define MAGNET_ITEMS \ + Elem->BendingAngle=0.0; \ + Elem->EntranceAngle=0.0; \ + Elem->ExitAngle=0.0; \ + Elem->FringeBendEntrance=0; \ + Elem->FringeBendExit=0; \ + Elem->gK_entrance=0.0; \ + Elem->gK_exit=0.0; + +#if defined(MATLAB_MEX_FILE) +#define MAGNET_MEX_ITEMS \ + double BendingAngle=0.0; \ + double EntranceAngle=0.0; \ + double ExitAngle=0.0; \ + int FringeBendEntrance=0; \ + int FringeBendExit=0; \ + double gK_entrance=0.0; \ + double gK_exit=0.0; + +const char *required[] = {}; +const char *optional[] = {}; +#define N_REQUIRED 0 +#define N_OPTIONAL 0 +#endif /*MATLAB_MEX_FILE*/ +#endif /*STRAIGHT_MULTIPOLE*/ + + + diff --git a/atintegrators/track.cc b/atintegrators/track.cc deleted file mode 100644 index efe353e48a..0000000000 --- a/atintegrators/track.cc +++ /dev/null @@ -1,528 +0,0 @@ -/* - track.cc - tracking routines for exact Hamiltonian from Forest / PTC / Tracy-3 - James Rowland 2010 -*/ - -#include -#include -#include -#include "track.h" - -#define TPSA_MODE - -#ifdef AT_MODE -#undef TPSA_MODE -#endif - -#ifdef TPSA_MODE -#include -#endif - -#undef DEBUG_MODE - -#ifdef DEBUG_MODE -#define Log(x) printf x -#else -#define Log(x) -#endif - -/* Forest-Ruth 4th order coefficients - could also use 6th order Yoshida */ - -#define INT_ORDER 4 - -/* - -Generated by: - -#!/usr/bin/env python -c1 = c4 = 1.0/(2.0*(2.0-2.0**(1.0/3.0))) -c2 = c3 = (1-2**(1.0/3.0))/(2.0*(2.0-2.0**(1.0/3.0))) -d1 = d3 = 1.0/(2.0-2.0**(1.0/3.0)) -d2 = -(2**(1.0/3.0)/(2.0-2.0**(1.0/3.0))) -d4 = 0 -print "double c[] = {% .17f, % .17f, % .17f, % .17f};" % (c1, c2, c3, c4) -print "double d[] = {% .17f, % .17f, % .17f, % .17f};" % (d1, d2, d3, d4) - -*/ - -double c[] = { 0.67560359597982889, -0.17560359597982883, -0.17560359597982883, 0.67560359597982889}; -double d[] = { 1.35120719195965777, -1.70241438391931532, 1.35120719195965777, 0.00000000000000000}; - -/* phase space indices */ - -enum -{ - x_ = 0, - px_, - y_, - py_, - delta_, - ct_ -}; - -template void multipole_fringe(element * e, - T * x, double L, double * F, int nF, int edge) -{ - // PTC multipole_fringer - // Forest 13.29 - // not re-derived and checked - // note this is the sum over n of Forest 13.29 - // one for each multipole component - - T I, U, V, DU, DV, DUX, DVX, DUY, DVY, - FX, FY, FX_X, FX_Y, FY_X, FY_Y, - RX, IX, DRX, DIX; - - if(edge == 0) - { - I = 1; - } - else - { - I = -1; - } - - FX = 0; - FY = 0; - FX_X = 0; - FX_Y = 0; - FY_X = 0; - FY_Y = 0; - - RX = 1.0; - IX = 0.0; - - // invariant is (j is the index, i is the complex unit) - // RX+IXi = (x + iy)^j - for(int n = 0; n < nF; n++) - { - - double B = F[2 * n]; - double A = F[2 * n + 1]; - - int j = n + 1; - - DRX = RX; - DIX = IX; - - // complex muls - - RX = DRX * x[x_] - DIX * x[y_]; - IX = DRX * x[y_] + DIX * x[x_]; - - if(j == 1 && e->type == dipole) - { - U = - A * IX; - V = + A * RX; - DU = - A * DIX; - DV = + A * DRX; - } - else - { - U = B * RX - A * IX; - V = B * IX + A * RX; - DU = B * DRX - A * DIX; - DV = B * DIX + A * DRX; - } - - T f1 = -I / 4.0 / (j + 1); - - U = U * f1; - V = V * f1; - DU = DU * f1; - DV = DV * f1; - - DUX = j * DU; - DVX = j * DV; - DUY = -j * DV; - DVY = j * DU; - - double nf = 1.0 * (j + 2) / j; - - FX += U * x[x_] + nf * V * x[y_]; - FY += U * x[y_] - nf * V * x[x_]; - - FX_X += DUX * x[x_] + U + nf * x[y_] * DVX; - FX_Y += DUY * x[x_] + nf * V + nf * x[y_] * DVY; - - FY_X += DUX * x[y_] - nf * V - nf * x[x_] * DVX; - FY_Y += DUY * x[y_] + U - nf * x[x_] * DVY; - - } - - T DEL = 1.0 / (1 + x[delta_]); - - // solve 2x2 matrix equation - - T A = 1 -FX_X * DEL; - T B = -FY_X * DEL; - T D = 1 -FY_Y * DEL; - T C = -FX_Y * DEL; - - x[x_] = x[x_] - FX * DEL; - x[y_] = x[y_] - FY * DEL; - - T pxf = (D * x[px_] - B * x[py_]) / (A * D - B * C); - T pyf = (A * x[py_] - C * x[px_]) / (A * D - B * C); - x[py_] = pyf; - x[px_] = pxf; - x[ct_] = x[ct_] - (x[px_] * FX + x[py_] * FY) * DEL * DEL; -} - -template T pow2(T x) -{ - return x * x; -} - -/* this is the z momentum */ -template T get_pz(T * x) -{ - return sqrt(pow2(1 + x[delta_]) - pow2(x[px_]) - pow2(x[py_])); -} - -/* Forest 10.26, layout rotation - phi: angle [rad] -*/ -template void Yrot(double phi, T * x) -{ - T c, s; - c = cos(phi); - s = sin(phi); - T x1[6] = {x[0], x[1], x[2], x[3], x[4], x[5]}; - T ps = get_pz(x); - T p = c*ps - s*x1[px_]; - x[x_] = x1[x_]*ps/p; - x[px_] = s*ps + c*x1[px_]; - x[y_] += x1[x_]*x1[py_]*s/p; - x[ct_] += (1.0+x1[delta_])*x1[x_]*s/p; -} - -/* Forest 10.23, exact drift - L: length [m] -*/ -template void exact_drift(T * x, double L) -{ - T u = L / get_pz(x); - x[x_] += x[px_] * u; - x[y_] += x[py_] * u; - x[ct_] += u * (1.0 + x[delta_]); -} - -/* Forest-Ruth 4th order integrator - x : phase space (inout) - L : length - F : multipole coefficients - nf : length of F - slices : number of integration steps -*/ - -template void fr4(T * x, double L, double * F, int nF, int slices) -{ - double ds = L / slices; - T psi = (1 + x[delta_]); - int max_order = nF - 1; - int s, n, i; - - for(s = 0; s < slices; s++) - { - for(n = 0; n < INT_ORDER; n++) - { - exact_drift(x, c[n] * ds); - - /* multipole summation with horner's rule - - scaled field = sum_n (b_n+ia_n) (x+iy)^n - - */ - - /* - C99 complex numbers don't work in C++ - forget the C++ complex class - complex double f = F[max_order]; - complex double z = x[x_] + x[y_] * I; - */ - - T fr = F[2 * max_order]; - T fi = F[2 * max_order + 1]; - - for(i = max_order - 1; i >= 0; i--) - { - /* - complex multiplication - f = f * z + F[i]; - */ - T temp1 = fr * x[x_] - fi * x[y_]; - T temp2 = fr * x[y_] + fi * x[x_]; - fr = temp1 + F[2 * i]; - fi = temp2 + F[2 * i + 1]; - } - - x[px_] -= d[n] * ds * fr; - x[py_] -= d[n] * ds * -fi; - - } - } - -} - -/* bend fringe */ - -/* add these definitions to match Mathematica output */ - -#define ArcTan atan -#define Power pow - -template T Sec(T x) -{ - return 1.0 / cos(x); -} - -template void bend_fringe(T * x, double irho, double gK) -{ - - T dpx, dpy, dd, b0, px, py, pz, g, K, d, phi, xp, yp, yf, xf, lf, pyf; - - b0 = irho; - - /* gK always multiplied together so put everything in g and set K to one */ - - K = 1.0; - g = gK; - - pz = get_pz(x); - px = x[px_]; - py = x[py_]; - d = x[delta_]; - xp = px / pz; - yp = py / pz; - - phi = -b0 * tan( b0 * g * K * (1 + pow2(xp)*(2 + pow2(yp)))*pz - atan(xp / (1 + pow2(yp)))); - - /* these are the partial derivatives of phi with respect to px, py and delta - total horror from Mathematica. This could benefit from some mini-TPSA */ - - dpx = -((b0*(Power(px,2)*Power(pz,4)*(Power(py,2) - Power(pz,2)) - Power(pz,6)*(Power(py,2) + Power(pz,2)) + - b0*g*K*px*(Power(pz,2)*Power(Power(py,2) + Power(pz,2),2)*(2*Power(py,2) + 3*Power(pz,2)) + Power(px,4)*(3*Power(py,2)*Power(pz,2) + 2*Power(pz,4)) + - Power(px,2)*(3*Power(py,6) + 8*Power(py,4)*Power(pz,2) + 9*Power(py,2)*Power(pz,4) + 5*Power(pz,6))))* - Power(Sec((b0*g*K*(Power(pz,4) + Power(px,2)*(Power(py,2) + 2*Power(pz,2))))/Power(pz,3) - ArcTan((px*pz)/(Power(py,2) + Power(pz,2)))),2))/ - (Power(pz,5)*(Power(py,4) + Power(px,2)*Power(pz,2) + 2*Power(py,2)*Power(pz,2) + Power(pz,4)))); - - - dpy = -((b0*py*(px*Power(pz,4)*(Power(py,2) + Power(pz,2)) + b0*g*K*(-(Power(pz,4)*Power(Power(py,2) + Power(pz,2),2)) + - Power(px,4)*(3*Power(py,2)*Power(pz,2) + 4*Power(pz,4)) + - Power(px,2)*(3*Power(py,6) + 10*Power(py,4)*Power(pz,2) + 11*Power(py,2)*Power(pz,4) + 3*Power(pz,6))))* - Power(Sec((b0*g*K*(Power(pz,4) + Power(px,2)*(Power(py,2) + 2*Power(pz,2))))/Power(pz,3) - ArcTan((px*pz)/(Power(py,2) + Power(pz,2)))),2))/ - (Power(pz,5)*(Power(py,4) + Power(px,2)*Power(pz,2) + 2*Power(py,2)*Power(pz,2) + Power(pz,4)))); - - dd = (b0*(1 + d)*(px*Power(pz,4)*(Power(py,2) - Power(pz,2)) + b0*g*K* - (-(Power(pz,4)*Power(Power(py,2) + Power(pz,2),2)) + Power(px,4)*(3*Power(py,2)*Power(pz,2) + 2*Power(pz,4)) + - Power(px,2)*(3*Power(py,6) + 8*Power(py,4)*Power(pz,2) + 7*Power(py,2)*Power(pz,4) + Power(pz,6))))* - Power(Sec((b0*g*K*(Power(pz,4) + Power(px,2)*(Power(py,2) + 2*Power(pz,2))))/Power(pz,3) - ArcTan((px*pz)/(Power(py,2) + Power(pz,2)))),2))/ - (Power(pz,5)*(Power(py,4) + Power(px,2)*Power(pz,2) + 2*Power(py,2)*Power(pz,2) + Power(pz,4))); - - /* solve quadratic equation in yf (Forest fringe_part_I.pdf) */ - - yf = (2 * x[y_]) / (1 + sqrt(1 - 2 * dpy * x[y_])); - xf = x[x_] + 0.5 * dpx * pow2(yf); - lf = x[ct_] - 0.5 * dd * pow2(yf); - pyf = py - phi * yf; - - x[y_] = yf; - x[x_] = xf; - x[py_] = pyf; - x[ct_] = lf; - -} - -template void bend(element * e, T * x, double L, double phi, double gK, - double * F, int nF, int slices) -{ - double irho = phi / L; - /* convert arc length to rectangular length */ - double LR = 2 / irho * sin(phi / 2.0); - Yrot(phi / 2, x); - bend_fringe(x, F[0], gK); - if(e->do_multipole_fringe) - { - multipole_fringe(e, x, LR, e->F, e->nF, 0); - } - fr4(x, LR, F, nF, slices); - if(e->do_multipole_fringe) - { - multipole_fringe(e, x, LR, e->F, e->nF, 1); - } - bend_fringe(x, -F[0], gK); - Yrot(phi / 2, x); -} - -template void track_element(T * x, element * e) -{ - Log(("track element\n")); - switch(e->type) - { - case drift: - Log(("drift %f\n", e->L)); - exact_drift(x, e->L); - x[ct_] -= e->L; - break; - case dipole: - Log(("bend %f %f %f\n", e->L, e->phi, creal(e->F[0]))); - bend(e, x, e->L, e->phi, e->gK, e->F, e->nF, e->slices); - x[ct_] -= e->L; - break; - case multipole: - Log(("multipole %f %f\n", e->L, creal(e->F[1]))); - if(e->do_multipole_fringe) - { - multipole_fringe(e, x, e->L, e->F, e->nF, 0); - } - fr4(x, e->L, e->F, e->nF, e->slices); - if(e->do_multipole_fringe) - { - multipole_fringe(e, x, e->L, e->F, e->nF, 1); - } - x[ct_] -= e->L; - break; - case marker: - Log(("marker\n")); - break; - default: - Log(("unknown element\n")); - exit(1); - } -} - -template void track_lattice_polymorphic(T * x, lattice * lat) -{ - Log(("track_lattice_polymorpic %d\n", lat->N)); - int n; - for(n = 0; n < lat->N; n++) - { - track_element(x, lat->next + n); - Log(("%e %e %e %e %e %e\n", x[0], x[1], x[2], x[3], x[4], x[5])); - } -} - -extern "C" long binomi2(int n, int k) { - long double accum = 1; - unsigned int i; - - if (k > n) - return 0; - - if (k > n/2) - k = n-k; - - for (i = 1; i <= k; i++) - accum = accum * (n-k+i) / i; - - /* was missing the outer cast in the original - possible bug? */ - return (long)((long) accum + 0.5); -} - -extern "C" int address2( int d, int* im ) { - int i, - add = 0; - - for (i=0; i>= x[i]; } - - /* finish the tracing tape */ - trace_off(tag); - - /* allocate outputs */ - - double *S[n]; - double *tensor[m]; - - double tensor_storage[m][sz]; - double S_storage[n][p]; - - int j = 0; - for(int i = 0; i < m; i++) - { - tensor[i] = map1 + j; - j += sz; - } - - for(int i = 0; i < n; i++) - { - S[i] = S_storage[i]; - } - - /* select full tensor of partial derivatives */ - for(int i = 0; i < n; ++i) - { - for(int j = 0; j < p; ++j) - S[i][j] = 0.0; - S[i][i] = 1.0; - } - - /* run tape to build derivative tensor */ - tensor_eval(tag, m, n, d, p, x0, tensor, S); - -} - -#else - -extern "C" void track_map(double * x, lattice * lat, double * map1) -{ - fprintf(stderr, "track_map is not available, rebuild with #define TPSA_MODE\n"); - exit(1); -} - -#endif - -extern "C" void track_lattice(double * x, lattice * lat, int turns) -{ - for(int n = 0; n < turns; n++) - { - track_lattice_polymorphic(x, lat); - } -} diff --git a/atintegrators/track.h b/atintegrators/track.h deleted file mode 100644 index 4df7330f58..0000000000 --- a/atintegrators/track.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __TRACK_H__ -#define __TRACK_H__ - -/* element interface */ - -enum { FMAX = 32 }; - -enum element_type -{ - drift = 0, - dipole, - multipole, - marker -}; - -struct element -{ - double L; - double phi; - double gK; - double F[FMAX]; - int nF; - int slices; - int type; - int do_multipole_fringe; -}; - -struct lattice -{ - element * next; - int N; -}; - -template void track_element(T * x, element * e); - -#endif - diff --git a/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c b/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c index 56412a0ea1..1aa7fe568e 100644 --- a/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c +++ b/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c @@ -13,6 +13,7 @@ #include "atelem.c" #include "atlalib.c" #include "atconstants.h" +#include "drift_expanded.h" #define SQR(X) ((X)*(X)) @@ -232,8 +233,6 @@ static void thinkickM(double* orbit_in, double* A, double* B, double L, } - - static void thinkickB(double* orbit_in, double* A, double* B, double L, double irho, int max_order, double E0, double *B66) @@ -299,41 +298,6 @@ static void thinkickB(double* orbit_in, double* A, double* B, double L, B66[28] = BB; } - - - - -static void drift_propagateB(double *orb_in, double L, double *B) -{ /* Propagate cumulative Ohmi's diffusion matrix B through a drift - B is a (*double) pointer to 1-dimentional array - containing 36 elements of matrix elements arranged column-by-column - as in MATLAB representation - - The relationship between indexes when a 6-by-6 matrix is - represented in MATLAB as one-dimentional array containing - 36 elements arranged column-by-column is - [i][j] <---> [i+6*j] - */ - - int m; - - double DRIFTMAT[36]; - for (m=0;m<36;m++) DRIFTMAT[m] = 0.0; - /* Set diagonal elements to 1 */ - for (m=0;m<6;m++) DRIFTMAT[m*7] = 1.0; - - DRIFTMAT[6] = L/(1+orb_in[4]); - DRIFTMAT[20] = DRIFTMAT[6]; - DRIFTMAT[24] = -L*orb_in[1]/SQR(1+orb_in[4]); - DRIFTMAT[26] = -L*orb_in[3]/SQR(1+orb_in[4]); - DRIFTMAT[11] = L*orb_in[1]/SQR(1+orb_in[4]); - DRIFTMAT[23] = L*orb_in[3]/SQR(1+orb_in[4]); - DRIFTMAT[29] = -L*(SQR(orb_in[1])+SQR(orb_in[3]))/((1+orb_in[4])*SQR(1+orb_in[4])); - - ATsandwichmmt(DRIFTMAT,B); -} - - static void FindElemB(double *orbit_in, double le, double irho, double *A, double *B, double *T1, double* T2,double *R1, double *R2, double entrance_angle, double exit_angle, @@ -378,8 +342,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl /* Propagate orbit_in and BDIFF through a 4-th orderintegrator */ for(m=0; m < num_int_steps; m++) /* Loop over slices */ - { drift_propagateB(orbit_in,L1, BDIFF); - ATdrift6(orbit_in,L1); + { drift(orbit_in, L1, irho, BDIFF); thinkickM(orbit_in, A,B, K1, irho, max_order, MKICK); thinkickB(orbit_in, A,B, K1, irho, max_order, E0, BKICK); @@ -387,8 +350,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl ATaddmm(BKICK,BDIFF); thinkickrad(orbit_in, A, B, K1, irho, E0, max_order); - drift_propagateB(orbit_in,L2, BDIFF); - ATdrift6(orbit_in,L2); + drift(orbit_in, L2, irho, BDIFF); thinkickM(orbit_in, A,B, K2, irho, max_order, MKICK); thinkickB(orbit_in, A,B, K2, irho, max_order, E0, BKICK); @@ -396,8 +358,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl ATaddmm(BKICK,BDIFF); thinkickrad(orbit_in, A, B, K2, irho, E0, max_order); - drift_propagateB(orbit_in,L2, BDIFF); - ATdrift6(orbit_in,L2); + drift(orbit_in, L2, irho, BDIFF); thinkickM(orbit_in, A,B, K1, irho, max_order, MKICK); thinkickB(orbit_in, A,B, K1, irho, max_order, E0, BKICK); @@ -405,8 +366,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl ATaddmm(BKICK,BDIFF); thinkickrad(orbit_in, A, B, K1, irho, E0, max_order); - drift_propagateB(orbit_in,L1, BDIFF); - ATdrift6(orbit_in,L1); + drift(orbit_in, L1, irho, BDIFF); } edgefringeB(orbit_in, BDIFF, irho, exit_angle, fringe_int2, full_gap); diff --git a/atmat/attests/pytests.m b/atmat/attests/pytests.m index aea1295a50..94792024ae 100644 --- a/atmat/attests/pytests.m +++ b/atmat/attests/pytests.m @@ -105,7 +105,7 @@ function orbit6(testCase,lat2,dp) porbit6=double(porbit6)'; % Matlab [~,morbit6]=findorbit6(lattice.m,dp=dp); - testCase.verifyEqual(morbit6,porbit6,AbsTol=2.E-12); + testCase.verifyEqual(morbit6,porbit6,AbsTol=3.E-12); end function m44(testCase,lat2,dp) diff --git a/pyat/at/lattice/elements/rectangular_bend.py b/pyat/at/lattice/elements/rectangular_bend.py index 62545f3f61..1615e6d3b0 100644 --- a/pyat/at/lattice/elements/rectangular_bend.py +++ b/pyat/at/lattice/elements/rectangular_bend.py @@ -43,14 +43,12 @@ def checkmul(el): return True return False - passmethod = self.PassMethod.replace("RadPass", "Pass") - if passmethod in { + elem = self.set_longt_motion(False, new_pass="auto", copy=True) + if elem.PassMethod in { "BndStrMPoleSymplectic4Pass", "ExactRectangularBendPass", "ExactRectBendPass", }: - elem = self.copy() - elem.PassMethod = passmethod theta = elem.BendingAngle # Analytical estimate @@ -60,8 +58,8 @@ def checkmul(el): if checkmul(self): x0ref = float(fsolve(cross, x0ref)) + rout = elem.track(np.zeros(6)) self.X0ref = x0ref - rout = self.track(np.zeros(6)) self.RefDZ = rout[5] diff --git a/pyat/at/load/xsuite.py b/pyat/at/load/xsuite.py index 8e3373ef1a..6fad1bb942 100644 --- a/pyat/at/load/xsuite.py +++ b/pyat/at/load/xsuite.py @@ -115,11 +115,11 @@ |Straight magnet +------------------------+----------------+---------------------------+ | |*default* |"adaptive" |"drift-kick-drift-expanded"| +-----------------+------------------------+----------------+---------------------------+ - | |ExactSectorBendPass |"bend-kick-bend"| | + | |ExactSectorBendPass |"bend-kick-bend" | | +------------------------+----------------+---------------------------+ |Dipole |ExactRectangularBendPass|"drift-kick-drift-exact" | | +------------------------+----------------+---------------------------+ - | |*default* |"adaptive" |"rot-kick-rot" | + | |*default* |"adaptive" |"drift-kick-drift-expanded"| +-----------------+------------------------+----------------+---------------------------+ Longitudinal motion @@ -157,10 +157,11 @@ import json import warnings +from abc import abstractmethod from math import sqrt from pathlib import Path from collections.abc import Callable -from typing import Any, ClassVar +from typing import Any, ClassVar, Protocol import contextlib import numpy as np @@ -225,7 +226,15 @@ def default(self, obj): return super().default(obj) -class XsElement(dict): +class _XsFactory(Protocol): + """Base class for Xsuite element factories.""" + + @classmethod + @abstractmethod + def from_at(cls, **atparams) -> XsElement: ... + + +class XsElement(dict, _XsFactory): """Base class for Xsuite elements.""" # Class attributes @@ -329,8 +338,6 @@ def from_at(cls, match_model: bool = False, **atparams) -> XsElement: xs_model = cls._at2xsuite_model.get(None, None) if (integrator := cls._at_integrator) is not None: xsparams["integrator"] = integrator - else: - xsparams.pop("num_multipole_kicks", None) if xs_model is not None: xsparams["model"] = xs_model # Set the Xsuite class @@ -407,7 +414,6 @@ class Multipole(XsElement): _at_integrator = "yoshida4" _xsuite2at_attr = XsElement._xsuite2at_attr | { "order": "MaxOrder", - "num_multipole_kicks": "NumIntSteps", } def _set_at_transforms(self) -> dict: @@ -468,8 +474,8 @@ def xspoly(kmain: list[str], kerr: str) -> tuple[int, np.ndarray]: return porder, np.fromiter(poly_from_mad(poly), dtype=float, count=lpoly) length = self.get("length", 0.0) - xsorder = self.get("order", 0) - atorder = getattr(self._atClass, "DefaultOrder", xsorder) + xsorder: int = self.get("order", 0) + atorder: int = getattr(self._atClass, "DefaultOrder", xsorder) aorder, polya = xspoly(["k0s", "k1s", "k2s", "k3s"], "ksl") border, polyb = xspoly(["k0", "k1", "k2", "k3"], "knl") maxorder = max(aorder, border) @@ -478,13 +484,20 @@ def xspoly(kmain: list[str], kerr: str) -> tuple[int, np.ndarray]: "PolynomB": polyb[: maxorder + 1], "PolynomA": polya[: maxorder + 1], } + if (nk := self.get("num_multipole_kicks", 0)) != 0: + atparams["NumIntSteps"] = (nk - 1) // 3 + 1 if (taper := self.get("delta_taper")) is not None: atparams["FieldScaling"] = 1.0 + taper return atparams def _set_at_fringe(self) -> dict[str, Any]: """generate the AT fringe field description.""" - return {} + atparams = {} + if self.get("edge_entry_active", False): + atparams["FringeQuadEntrance"] = 1 + if self.get("edge_exit_active", False): + atparams["FringeQuadExit"] = 1 + return atparams def _set_xs_transforms(self, atparams: dict) -> None: """Generate Xsuite element displacements.""" @@ -516,31 +529,45 @@ def _set_xs_transforms(self, atparams: dict) -> None: self.update(misalign) - def _set_xs_poly(self, atparams: dict) -> None: + def _set_xs_poly(self, atparams: dict, match_model: bool = False) -> None: """Generate the AT field expansion.""" + + def extract(poly, ord): + try: + v = poly[ord] + except IndexError: + v = 0.0 + else: + poly[ord] = 0.0 + return v + pata = atparams.get("PolynomA", np.zeros(4)) pola = np.fromiter(poly_to_mad(pata), dtype=float, count=pata.size) patb = atparams.get("PolynomB", np.zeros(4)) polb = np.fromiter(poly_to_mad(patb), dtype=float, count=patb.size) - length = atparams.get("Length") + length: float = atparams.get("Length") korder = getattr(self, "_mag_order", None) - if korder is not None: - self["k" + str(korder)] = polb[korder] - self["k" + str(korder) + "s"] = pola[korder] - pola[korder] = 0.0 - polb[korder] = 0.0 + if korder == 0: # dipole + self["k1"] = extract(polb, 1) + self["k2"] = extract(polb, 2) + elif korder is not None: # quadrupole, sextupole, octupole + self["k" + str(korder)] = extract(polb, korder) + self["k" + str(korder) + "s"] = extract(pola, korder) if length > 0.0: polb *= length pola *= length if np.any(pola) or np.any(polb): self["knl"] = list(polb) self["ksl"] = list(pola) + if match_model and (numintsteps := atparams.get("NumIntSteps")) is not None: + self["num_multipole_kicks"] = 3 * numintsteps if (scaling := atparams.get("FieldScaling")) is not None: self["delta_taper"] = scaling - 1.0 self["_isthick"] = length != 0.0 def _set_xs_fringe(self, atparams: dict) -> None: - """generate the Xsuite fringe field description.""" + self["edge_entry_active"] = bool(atparams.get("FringeQuadEntrance", 0)) + self["edge_exit_active"] = bool(atparams.get("FringeQuadExit", 0)) def _class_to_at(self, atparams: dict[str, Any]) -> type[elt.Element]: if atparams.get("Length", 0.0) == 0.0: @@ -556,9 +583,9 @@ def _params_to_at(self, **atparams) -> dict[str, Any]: return atparams @classmethod - def from_at(cls, **atparams): - elem = super().from_at(**atparams) - elem._set_xs_poly(atparams) + def from_at(cls, match_model: bool = False, **atparams): + elem = super().from_at(match_model=match_model, **atparams) + elem._set_xs_poly(atparams, match_model=match_model) elem._set_xs_fringe(atparams) elem._set_xs_transforms(atparams) return elem @@ -571,19 +598,6 @@ class Quadrupole(Multipole): _atClass = elt.Quadrupole _mag_order: ClassVar[int] = 1 - def _set_at_fringe(self): - """generate the AT fringe field description.""" - atparams = {} - if self.get("edge_entry_active", 0): - atparams["FringeQuadEntrance"] = 1 - if self.get("edge_exit_active", 0): - atparams["FringeQuadExit"] = 1 - return atparams - - def _set_xs_fringe(self, atparams: dict): - self["edge_entry_active"] = atparams.get("FringeQuadEntrance", 0) - self["edge_exit_active"] = atparams.get("FringeQuadExit", 0) - class Sextupole(Multipole): """Xsuite Sextupole element.""" @@ -619,13 +633,33 @@ class Bend(Multipole): "edge_entry_angle": "EntranceAngle", "edge_exit_angle": "ExitAngle", } - _mag_order = 1 - _edge_to_xs: ClassVar[dict[bool, dict[bool, str]]] = { - True: {True: "full", False: "dipole-only"}, - False: {True: "linear", False: "linear"}, + _mag_order = 0 + _default_bend_fringe: ClassVar[dict[bool, int]] = { + True: 4, + False: 1, + } + _at2xsuite_edge: ClassVar[dict[int, str]] = { + 0: "suppressed", + 1: "linear", + 2: "linear", + 3: "linear", + 4: "dipole-only", + } + _xsuite2at_edge: ClassVar[dict[str, tuple]] = { + "suppressed": (0, None), + "linear": (1, None), + "dipole-only": (None, None), + "full": (None, 1), } def _set_at_fringe(self) -> dict[str, Any]: + def edge_model(xskey, bendkey, quadkey): + [bend, quad] = self._xsuite2at_edge[self.get(xskey, "linear")] + if bend is not None: + atparams[bendkey] = bend + if quad is not None: + atparams[quadkey] = quad + atparams = {} entry_hgap = self.get("edge_entry_hgap") exit_hgap = self.get("edge_exit_hgap") @@ -633,31 +667,37 @@ def _set_at_fringe(self) -> dict[str, Any]: msg = "Entry and Exit gaps for dipole are different, use entry" warnings.warn(AtWarning(msg), stacklevel=2) if entry_hgap is not None: - atparams["FullGap"] = entry_hgap + atparams["FullGap"] = 2.0 * entry_hgap - if self.get("edge_entry_model", "linear") in ["linear", "full"]: - atparams["FringeQuadEntrance"] = 1 - if self.get("edge_exit_model", "linear") in ["linear", "full"]: - atparams["FringeQuadExit"] = 1 + edge_model("edge_entry_model", "FringeBendEntrance", "FringeQuadEntrance") + edge_model("edge_exit_model", "FringeBendExit", "FringeQuadExit") return atparams def _set_xs_fringe(self, atparams: dict): + def edge_model(bendkey, quadkey): + at_quad_fringe = atparams.get(quadkey, 0) + if at_quad_fringe > 0: + return "full" + else: + return self._at2xsuite_edge[atparams.get(bendkey, default_bend_fringe)] + if (gap := atparams.get("FullGap")) is not None: - self["edge_entry_gap"] = gap - self["edge_exit_gap"] = gap + self["edge_entry_hgap"] = 0.5 * gap + self["edge_exit_hgap"] = 0.5 * gap exact = atparams.get("PassMethod", "").startswith("Exact") - qentry = atparams.get("FringeQuadEntrance", 0) - qexit = atparams.get("FringeQuadExit", 0) - self["edge_entry_model"] = self._edge_to_xs[exact][qentry > 0] - self["edge_exit_model"] = self._edge_to_xs[exact][qexit > 0] + default_bend_fringe = self._default_bend_fringe[exact] + self["edge_entry_model"] = edge_model( + "FringeBendEntrance", "FringeQuadEntrance" + ) + self["edge_exit_model"] = edge_model("FringeBendExit", "FringeQuadExit") def _params_to_at(self, **atparams) -> dict[str, Any]: atparams = super()._params_to_at(EntranceAngle=0.0, ExitAngle=0.0, **atparams) return atparams @classmethod - def from_at(cls, **atparams): - elem = super().from_at(**atparams) + def from_at(cls, match_model: bool = False, **atparams): + elem = super().from_at(match_model=match_model, **atparams) elem["k0_from_h"] = True return elem @@ -705,8 +745,8 @@ def _params_to_at(self, **atparams) -> dict[str, Any]: return atparams @classmethod - def from_at(cls, **atparams): - elem = super().from_at(**atparams) + def from_at(cls, match_model: bool = False, **atparams): + elem = super().from_at(match_model=match_model, **atparams) elem["rbend_model"] = "straight-body" hangle = 0.5 * elem["angle"] elem["edge_entry_angle"] -= hangle @@ -746,13 +786,13 @@ def _params_to_at(self, **atparams) -> dict[str, Any]: return atparams @classmethod - def from_at(cls, **atparams): - elem = super().from_at(**atparams) + def from_at(cls, match_model: bool = False, **atparams): + elem = super().from_at(match_model=match_model, **atparams) elem._set_xs_lag(atparams) return elem -class NotInAT: +class NotInAT(_XsFactory): """Class for Xsuite elements without AT equivalent.""" @classmethod @@ -771,7 +811,7 @@ def from_dict( return xsclass.from_dict(xsparams, name=name, warn=warn) -class NotInXsuite: +class NotInXsuite(_XsFactory): """Class for AT elements without Xsuite equivalent.""" @classmethod @@ -783,7 +823,7 @@ def from_at(cls, **atparams) -> XsElement: return xsclass.from_at(**atparams) -class Dipole: +class Dipole(_XsFactory): """Class for handling AT dipoles.""" @classmethod @@ -797,6 +837,24 @@ def from_at(cls, **atparams) -> XsElement: return Bend.from_at(**atparams) +class Corrector(_XsFactory): + """Class for handling AT correctors.""" + + # noinspection PyPep8Naming + @classmethod + def from_at(cls, KickAngle=(0.0, 0.0), **atparams) -> XsElement: + pola = np.array([KickAngle[1]]) + polb = np.array([-KickAngle[0]]) + if (length := atparams["Length"]) != 0.0: + pola /= length + polb /= length + # Prevent from duplicate attributes + atparams.pop("PolynomA", None) + atparams.pop("PolynomB", None) + atparams.pop("MaxOrder", None) + return Multipole.from_at(PolynomA=pola, PolynomB=polb, MaxOrder=0, **atparams) + + _xsclass: dict[str, type[XsElement]] = { "Marker": Marker, "Drift": Drift, @@ -810,7 +868,7 @@ def from_at(cls, **atparams) -> XsElement: } -_at2xsclass: dict[type[elt.Element], type[XsElement]] = { +_at2xsclass: dict[type[elt.Element], type[_XsFactory]] = { elt.Marker: Marker, elt.Monitor: Marker, elt.Drift: Drift, @@ -821,6 +879,7 @@ def from_at(cls, **atparams) -> XsElement: elt.Multipole: Multipole, elt.ThinMultipole: Multipole, elt.Dipole: Dipole, + elt.Corrector: Corrector, } @@ -1046,9 +1105,7 @@ def from_at(cls, ring: Lattice, match_model: bool = False, **kwargs) -> XsLine: def refpart(rng): prt = rng.particle if prt.name == "relativistic": - with warnings.catch_warnings(): - warnings.simplefilter("ignore", category=UserWarning) - prt = Particle("electron") + prt = Particle("electron") gamma0 = rng.energy / prt.rest_energy beta0 = sqrt(1.0 - 1.0 / gamma0 / gamma0) return { diff --git a/pyat/test/test_physics.py b/pyat/test/test_physics.py index a2504ff6c2..8d9c0b1c04 100644 --- a/pyat/test/test_physics.py +++ b/pyat/test/test_physics.py @@ -326,10 +326,10 @@ def test_get_tune_chrom(hmba_lattice): qharm = hmba_lattice.get_tune(method="interp_fft") qpharm = hmba_lattice.get_chrom(method="interp_fft") print(qlin, qharm) - assert_close(qlin, [0.2099983, 0.34001317], atol=1e-8) - assert_close(qharm, [0.20999833, 0.34001324], atol=1e-8) - assert_close(qplin, [5.734099, 3.917612], atol=1e-8) - assert_close(qpharm, [5.734123, 3.917639], atol=1e-8) + assert_close(qlin, [0.209998303584, 0.340013166682], atol=1e-8) + assert_close(qharm, [0.209998327527, 0.340013235807], atol=1e-8) + assert_close(qplin, [5.729114185134, 3.931703139652], atol=1e-8) + assert_close(qpharm, [5.729138523591, 3.931730165145], atol=1e-8) def test_nl_detuning_chromaticity(hmba_lattice): @@ -342,8 +342,8 @@ def test_nl_detuning_chromaticity(hmba_lattice): nlqplin, np.array( [ - [0.2101570, 5.730634, 151.87972, -18977.6808], - [0.3399707, 3.916998, 258.2324, -3529.81728], + [2.10157015e-01, 5.72564645e00, 1.51815354e02, -1.89809140e04], + [3.39970733e-01, 3.93108893e00, 2.58206212e02, -3.53120138e03], ] ), atol=1e-12, @@ -353,8 +353,8 @@ def test_nl_detuning_chromaticity(hmba_lattice): nlqpharm, np.array( [ - [0.2101570, 5.730630, 151.87968, -18977.7132], - [0.3399708, 3.916997, 258.23236, -3529.8072], + [2.10156985e-01, 5.72564318e00, 1.51815337e02, -1.89809436e04], + [3.39970750e-01, 3.93108797e00, 2.58206152e02, -3.53119072e03], ] ), atol=1e-12, @@ -362,13 +362,14 @@ def test_nl_detuning_chromaticity(hmba_lattice): ) assert_close( q0, - np.array([[0.210004, 0.340017], [0.210004, 0.340017]]), + np.array([[0.21000425, 0.34001688], [0.21000425, 0.34001688]]), atol=1e-12, rtol=1e-5, ) assert_close( q1, - np.array([[96183.925683, -104218.18371], [-104263.908197, 51684.400417]]), + np.array( + [[96172.00066329, -103658.3658934], [-103704.24788915, 51570.58307421]]), atol=1e-12, rtol=1e-5, ) From fbc0f32bfb70d03c04709f037316750bf0239f4e Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Mon, 1 Jun 2026 14:51:22 +0200 Subject: [PATCH 02/10] Refactoring of magnet integrators --- atintegrators/magnet_template.h | 9 +++------ atintegrators/quantum_diffusion.h | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/atintegrators/magnet_template.h b/atintegrators/magnet_template.h index 1f8d95487f..6c0cd7da51 100644 --- a/atintegrators/magnet_template.h +++ b/atintegrators/magnet_template.h @@ -132,16 +132,13 @@ static void magnet(double *r, double le, double bending_angle, if (RApertures) checkiflostRectangularAp(r6,RApertures); if (EApertures) checkiflostEllipticalAp(r6,EApertures); + /* Entry face */ MAGNET_ENTRY /* Integrator */ INTEGRATOR(r6, num_int_steps, DL, SL, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); -// -// /* Convert absolute path length to path lengthening */ -// #ifdef ABSOLUTE_PATH_LENGTH -// r6[5] -= (le+refdz); -// #endif + /* Exit face*/ MAGNET_EXIT /* Check physical apertures at the exit of the magnet */ @@ -289,7 +286,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) #if defined(RADIATION) || defined(QUANTUM) double Energy=atGetOptionalDouble(ElemData,"Energy",0.0); check_error(); - double rest_energy = 0.0;; + double rest_energy = 0.0; double charge = -1.0; if (nrhs > 2) atProperties(prhs[2], &Energy, &rest_energy, &charge); double gamma0 = atGamma(Energy, Energy, rest_energy); diff --git a/atintegrators/quantum_diffusion.h b/atintegrators/quantum_diffusion.h index 6250293049..40f31a660b 100644 --- a/atintegrators/quantum_diffusion.h +++ b/atintegrators/quantum_diffusion.h @@ -1,4 +1,5 @@ #include +#include "atconstants.h" #include "atrandom.c" /*this is quite ugly....but avoids reading form file*/ From bb660aa13e6ff5d7a8098706f4e1f590ab65a50f Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Mon, 1 Jun 2026 14:59:11 +0200 Subject: [PATCH 03/10] for Windows compiler --- atintegrators/quantum_diffusion.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/atintegrators/quantum_diffusion.h b/atintegrators/quantum_diffusion.h index 40f31a660b..be48759600 100644 --- a/atintegrators/quantum_diffusion.h +++ b/atintegrators/quantum_diffusion.h @@ -1,6 +1,12 @@ #include #include "atconstants.h" #include "atrandom.c" + +const double alpha0 = 7.2973525643e-3; // fine-structure constant [] - from CODATA 2022 +const double emass = 510998.95069; // electron mass [eV] - from CODATA 2022 +static double CST1 = 1.0e9 * 3.0/ 2.0 * __HBAR_C / emass; // [m] +static double CST2 = 5.0 * ROOT_3 / 6.0 * alpha0; // [] + /*this is quite ugly....but avoids reading form file*/ static int nt = 347; @@ -456,11 +462,6 @@ static double getEnergy(pcg32_random_t *rng, double ec) return re * ec; } -const double alpha0 = 7.2973525643e-3; // fine-structure constant [] - from CODATA 2022 -const double emass = 510998.95069; // electron mass [eV] - from CODATA 2022 -const double CST1 = 1.0e9 * 3.0/ 2.0 * __HBAR_C / emass; // [m] -const double CST2 = 5.0 * ROOT_3 / 6.0 * alpha0; // [] - #define INTEGRATOR_PREFIX \ double dp1 = 1.0 + r6[4]; \ double gamma = dp1 * gamma0; \ From 9fa59e40fb65f71a97a33d8cdd3e7ea72b2c4cfa Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Mon, 1 Jun 2026 15:25:52 +0200 Subject: [PATCH 04/10] for Windows compiler --- atintegrators/quantum_diffusion.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/atintegrators/quantum_diffusion.h b/atintegrators/quantum_diffusion.h index be48759600..f20daa6147 100644 --- a/atintegrators/quantum_diffusion.h +++ b/atintegrators/quantum_diffusion.h @@ -4,8 +4,13 @@ const double alpha0 = 7.2973525643e-3; // fine-structure constant [] - from CODATA 2022 const double emass = 510998.95069; // electron mass [eV] - from CODATA 2022 -static double CST1 = 1.0e9 * 3.0/ 2.0 * __HBAR_C / emass; // [m] -static double CST2 = 5.0 * ROOT_3 / 6.0 * alpha0; // [] +#ifdef _WIN32 +const double CST1 = 5.792389009807655298e-13; // [m] +const double CST2 = 1.053282116842552650e-02; // [] +#else +const double CST1 = 1.0e9 * 3.0/ 2.0 * __HBAR_C / emass; // [m] +const double CST2 = 5.0 * ROOT_3 / 6.0 * alpha0; // [] +#endif /*this is quite ugly....but avoids reading form file*/ From 0765a0815f79b9ef67456272d1b4e33f99a44015 Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Mon, 1 Jun 2026 15:37:33 +0200 Subject: [PATCH 05/10] Remove ExactHamiltonianPass --- pyat/test/test_integrators.py | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/pyat/test/test_integrators.py b/pyat/test/test_integrators.py index c754c2189c..14799af90c 100644 --- a/pyat/test/test_integrators.py +++ b/pyat/test/test_integrators.py @@ -10,32 +10,6 @@ from at import element_pass, internal_epass -@pytest.mark.parametrize("func", (element_track, element_pass, internal_epass)) -def test_exact_hamiltonian_pass(rin, func): - drift = elements.Multipole("m1", 1, [0, 0, 0, 0], [0, 0, 0, 0]) - drift.Type = 0 - drift.PassMethod = "ExactHamiltonianPass" - drift.BendingAngle = 0 - func(drift, rin) - - -@pytest.mark.parametrize("func", (element_track, element_pass, internal_epass)) -def test_exact_hamiltonian_pass_with_dls_dipole(rin, func): - bend = elements.Multipole("rb", 0.15, [0, 0, 0, 0], [-0.0116333, 3.786786, 0, 0]) - bend.Type = 1 - bend.PassMethod = "ExactHamiltonianPass" - bend.BendingAngle = -0.001745 - bend.Energy = 3.5e9 - bend.MaxOrder = 3 - if func == element_track: - func(bend, rin, in_place=True) - else: - func(bend, rin) - # Results from Matlab - expected = numpy.array([9.23965e-9, 1.22319e-5, 0, 0, 0, -4.8100e-10]).reshape(6, 1) - numpy.testing.assert_allclose(rin, expected, rtol=1e-5, atol=1e-6) - - @pytest.mark.parametrize("func", (element_track, element_pass, internal_epass)) @pytest.mark.parametrize("passmethod", ("GWigSymplecticPass", "GWigSymplecticRadPass")) def test_gwig_symplectic_pass(rin, passmethod, func): From 1b6cd61de3e4ba3400ec782c0ecf1c6b6092f4c2 Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Thu, 4 Jun 2026 13:12:45 +0200 Subject: [PATCH 06/10] drift template --- atintegrators/BendLinearPass.c | 10 +- atintegrators/BndMPoleSymplectic4Pass.c | 2 +- atintegrators/BndMPoleSymplectic4QuantPass.c | 2 +- atintegrators/ChangePRefPass.c | 6 +- atintegrators/CrabCavityPass.c | 4 +- atintegrators/DriftPass.c | 135 +----------------- atintegrators/ExactDriftPass.c | 126 +--------------- atintegrators/ExactRectBendPass.c | 14 +- atintegrators/ExactSectorBendPass.c | 13 +- atintegrators/GWigSymplecticPass.c | 6 +- atintegrators/IdTablePass.c | 12 +- atintegrators/LongtAperturePass.c | 9 +- atintegrators/Matrix66Pass.c | 6 +- atintegrators/Matrix66RadPass.c | 6 +- atintegrators/MatrixTijkPass.c | 4 +- atintegrators/QuadLinearFPass.c | 12 +- atintegrators/QuadLinearPass.c | 11 +- atintegrators/SimpleQuantDiffPass.c | 11 +- atintegrators/SimpleRadiationRadPass.c | 13 +- atintegrators/SliceMomentsPass.c | 4 +- atintegrators/SolenoidLinearPass.c | 12 +- atintegrators/StrMPoleSymplectic4Pass.c | 2 +- atintegrators/StrMPoleSymplectic4QuantPass.c | 4 +- atintegrators/VariableThinMPolePass.c | 7 +- atintegrators/WakeFieldPass.c | 3 +- atintegrators/WiggLinearPass.c | 6 +- atintegrators/atelem.c | 29 ---- atintegrators/attrackfunc.c | 10 +- atintegrators/drift_E2.h | 4 +- atintegrators/drift_exact.h | 16 ++- atintegrators/drift_exactbend.h | 15 +- atintegrators/drift_exactstrbend.h | 15 +- atintegrators/drift_expanded.h | 4 +- atintegrators/drift_fast.h | 21 --- atintegrators/drift_template.h | 128 +++++++++++++++++ atintegrators/integrators.h | 78 ++++++---- atintegrators/magnet_template.h | 11 +- atintegrators/multipolefringe.h | 1 + .../Radiation/findmpoleraddiffmatrix.c | 8 +- 39 files changed, 323 insertions(+), 457 deletions(-) delete mode 100644 atintegrators/drift_fast.h create mode 100644 atintegrators/drift_template.h diff --git a/atintegrators/BendLinearPass.c b/atintegrators/BendLinearPass.c index 59b373bd43..2bc53f839e 100644 --- a/atintegrators/BendLinearPass.c +++ b/atintegrators/BendLinearPass.c @@ -141,13 +141,11 @@ void BendLinearPass(double *r, double le, double grd ,double ba, double bye, * Set fint OR gap are 0 to ignore fringe effects * Set bye to 0 to ignore ByError*/ { - double *r6; double irho = ba/le; - int c; - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(shared) shared(r,num_particles) private(c,r6) - for (c = 0;c OMP_PARTICLE_THRESHOLD) default(shared) shared(r,num_particles) + for (int c = 0;c OMP_PARTICLE_THRESHOLD*10) \ - default(none) shared(r_in, num_particles, scaling ) private(c) - for (c = 0; c OMP_PARTICLE_THRESHOLD*10) default(shared) shared(r_in,num_particles) private(c,r6) - for (c = 0; cLength=Length; - Elem->R1=R1; - Elem->R2=R2; - Elem->T1=T1; - Elem->T2=T2; - Elem->EApertures=EApertures; - Elem->RApertures=RApertures; - } - DriftPass(r_in, Elem->Length, Elem->T1, Elem->T2, Elem->R1, Elem->R2, Elem->RApertures, Elem->EApertures, num_particles); -/* } - else { - atFree(Elem->T1); - atFree(Elem->T2); - atFree(Elem->R1); - atFree(Elem->R2); - atFree(Elem->EApertures); - atFree(Elem->RApertures); - }*/ - return Elem; -} - -MODULE_DEF(DriftPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - double Length; - double *R1, *R2, *T1, *T2, *EApertures, *RApertures; - Length=atGetDouble(ElemData,"Length"); check_error(); - R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); - R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); - T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); - T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); - EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); - RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); - if (mxGetM(prhs[1]) != 6) mexErrMsgIdAndTxt("AT:WrongArg","Second argument must be a 6 x N matrix"); - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - DriftPass(r_in, Length, T1, T2, R1, R2, RApertures, EApertures, num_particles); - } - else if (nrhs == 0) { - /* list of required fields */ - plhs[0] = mxCreateCellMatrix(1,1); - mxSetCell(plhs[0],0,mxCreateString("Length")); - if (nlhs>1) { - /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(6,1); - mxSetCell(plhs[1],0,mxCreateString("T1")); - mxSetCell(plhs[1],1,mxCreateString("T2")); - mxSetCell(plhs[1],2,mxCreateString("R1")); - mxSetCell(plhs[1],3,mxCreateString("R2")); - mxSetCell(plhs[1],4,mxCreateString("RApertures")); - mxSetCell(plhs[1],5,mxCreateString("EApertures")); - } - } - else { - mexErrMsgIdAndTxt("AT:WrongArg","Needs 0 or 2 arguments"); - } -} -#endif /*defined(MATLAB_MEX_FILE)*/ +#include "drift_template.h" \ No newline at end of file diff --git a/atintegrators/ExactDriftPass.c b/atintegrators/ExactDriftPass.c index 3887fc49fb..32d52da537 100644 --- a/atintegrators/ExactDriftPass.c +++ b/atintegrators/ExactDriftPass.c @@ -1,126 +1,4 @@ -#include "atelem.c" -#include "atlalib.c" +#define DRIFT_PASS ExactDriftPass #include "drift_exact.h" -struct elem { - double Length; - double *R1; - double *R2; - double *T1; - double *T2; - double *EApertures; - double *RApertures; -}; - -static void drift_pass(double *r_in, double le, const double *T1, const double *T2, - const double *R1, const double *R2, double *RApertures, - double *EApertures, int num_particles) -{ - double *r6; - int c; - - #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD * 10) \ - default(shared) \ - shared(r_in, num_particles) \ - private(c, r6) - for (c = 0; c < num_particles; c++) { /*Loop over particles */ - r6 = r_in + c * 6; - if (!atIsNaN(r6[0])) { - - /* misalignment at entrance */ - if (T1) ATaddvv(r6, T1); - if (R1) ATmultmv(r6, R1); - - /* Check physical apertures at the entrance of the magnet */ - if (RApertures) checkiflostRectangularAp(r6, RApertures); - if (EApertures) checkiflostEllipticalAp(r6, EApertures); - - drift(r6, le, 0.0, NULL); - - /* Convert absolute path length to path lengthening */ - r6[5] -= le; - - /* Check physical apertures at the exit of the magnet */ - if (RApertures) checkiflostRectangularAp(r6, RApertures); - if (EApertures) checkiflostEllipticalAp(r6, EApertures); - - /* Misalignment at exit */ - if (R2) ATmultmv(r6, R2); - if (T2) ATaddvv(r6, T2); - } - } -} - -#if defined(MATLAB_MEX_FILE) || defined(PYAT) -ExportMode struct elem *trackFunction(const atElem *ElemData, struct elem *Elem, - double *r_in, int num_particles, - struct parameters *Param) { - if (!Elem) { - double Length = atGetDouble(ElemData, "Length"); check_error(); - double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); - double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); - double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); - double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); - double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); - double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); - Elem = (struct elem *)atMalloc(sizeof(struct elem)); - Elem->Length = Length; - Elem->R1 = R1; - Elem->R2 = R2; - Elem->T1 = T1; - Elem->T2 = T2; - Elem->EApertures = EApertures; - Elem->RApertures = RApertures; - } - drift_pass(r_in, Elem->Length, Elem->T1, Elem->T2, Elem->R1, Elem->R2, - Elem->RApertures, Elem->EApertures, num_particles); - return Elem; -} - -MODULE_DEF(ExactDriftPass) /* Dummy module initialisation */ - -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ - -#if defined(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]); - - double Length = atGetDouble(ElemData, "Length"); check_error(); - double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); - double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); - double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); - double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); - double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); - double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); - if (mxGetM(prhs[1]) != 6) - mexErrMsgIdAndTxt("AT:WrongArg", - "Second argument must be a 6 x N matrix"); - /* ALLOCATE memory for the output array of the same size as the input */ - plhs[0] = mxDuplicateArray(prhs[1]); - r_in = mxGetDoubles(plhs[0]); - drift_pass(r_in, Length, T1, T2, R1, R2, RApertures, EApertures, - num_particles); - } else if (nrhs == 0) { - /* list of required fields */ - int i0 = 0; - plhs[0] = mxCreateCellMatrix(1, 1); - mxSetCell(plhs[0], i0++, mxCreateString("Length")); - if (nlhs > 1) { - /* list of optional fields */ - int i1 = 0; - plhs[1] = mxCreateCellMatrix(6, 1); - mxSetCell(plhs[1], i1++, mxCreateString("T1")); - mxSetCell(plhs[1], i1++, mxCreateString("T2")); - mxSetCell(plhs[1], i1++, mxCreateString("R1")); - mxSetCell(plhs[1], i1++, mxCreateString("R2")); - mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); - mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); - } - } else { - mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); - } -} -#endif /*defined(MATLAB_MEX_FILE)*/ +#include "drift_template.h" \ No newline at end of file diff --git a/atintegrators/ExactRectBendPass.c b/atintegrators/ExactRectBendPass.c index a0681e9ad4..1e3a94c12b 100644 --- a/atintegrators/ExactRectBendPass.c +++ b/atintegrators/ExactRectBendPass.c @@ -5,11 +5,15 @@ #include "kick_exactkn.h" #include "straight_dipole.h" -#define INTEGRATOR(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ - if (num_int_steps == 0) \ - drift(r6, slength, irho, bdiff); \ - else \ - integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); + +#define INTEGRATOR(r6, num_int_steps, slength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + if (num_int_steps == 0) { \ + DRIFT(r6, slength, irho, bdiff); \ + FIX_LENGTH(slength); \ + } \ + else { \ + integrator(r6, num_int_steps, slength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); \ + } #define CHECK_NSTEPS \ int ForceSplit = atGetOptionalLong(ElemData,"ForceSplit",0); check_error(); \ diff --git a/atintegrators/ExactSectorBendPass.c b/atintegrators/ExactSectorBendPass.c index 41ddc20de5..6304e4fd84 100644 --- a/atintegrators/ExactSectorBendPass.c +++ b/atintegrators/ExactSectorBendPass.c @@ -5,11 +5,14 @@ #include "kick_k1h_kn.h" #include "curved_dipole.h" -#define INTEGRATOR(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ - if (num_int_steps == 0) \ - drift(r6, slength, irho, bdiff); \ - else \ - integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); +#define INTEGRATOR(r6, num_int_steps, slength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + if (num_int_steps == 0) { \ + DRIFT(r6, slength, irho, bdiff); \ + FIX_LENGTH(slength); \ + } \ + else { \ + integrator(r6, num_int_steps, slength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); \ + } #define CHECK_NSTEPS \ int ForceSplit = atGetOptionalLong(ElemData,"ForceSplit",0); check_error(); \ diff --git a/atintegrators/GWigSymplecticPass.c b/atintegrators/GWigSymplecticPass.c index d8501bdb4d..29031d628d 100644 --- a/atintegrators/GWigSymplecticPass.c +++ b/atintegrators/GWigSymplecticPass.c @@ -79,14 +79,12 @@ void GWigSymplecticPass(double *r, double gamma, double Ltot, double Lw, double *By, double *Bx, double *T1, double *T2, double *R1, double *R2, int num_particles) { - int c; - double *r6; struct gwig pWig; /* Energy is defined in the lattice in eV but GeV is used by the gwig code. */ GWigInit2(&pWig, gamma,Ltot, Lw, Bmax, Nstep, Nmeth, NHharm, NVharm,0, 0, By,Bx,T1,T2,R1,R2); - for (c = 0;c OMP_PARTICLE_THRESHOLD) default(shared) shared(r,num_particles) private(c,r6) - for (c = 0;c OMP_PARTICLE_THRESHOLD) default(shared) shared(r,num_particles) + for (int c = 0;c OMP_PARTICLE_THRESHOLD) default(shared) shared(r,num_particles) private(c,r6) - for (c = 0;c OMP_PARTICLE_THRESHOLD) default(shared) shared(r,num_particles) + for (int c = 0;c OMP_PARTICLE_THRESHOLD*10) default(shared) shared(r_in,num_particles) private(c,r6) - for (c = 0; c OMP_PARTICLE_THRESHOLD*10) default(shared) shared(r_in,num_particles) + for (int c = 0; c OMP_PARTICLE_THRESHOLD*10) default(shared) shared(r_in,num_particles) private(c,r6) - for (c = 0; c OMP_PARTICLE_THRESHOLD*10) default(shared) shared(r_in,num_particles) + for (int c = 0; c= smin[ib]) && (rtmp[5] <= smax[ib])) { diff --git a/atintegrators/SolenoidLinearPass.c b/atintegrators/SolenoidLinearPass.c index 95fc10547d..5acaac6071 100644 --- a/atintegrators/SolenoidLinearPass.c +++ b/atintegrators/SolenoidLinearPass.c @@ -24,12 +24,12 @@ void SolenoidLinearPass(double *r_in, double le, double ks, double *T1, double * r_in - 6-by-N matrix of initial conditions reshaped into 1-d array of 6*N elements */ -{ int c; - double *r6, p_norm, H, S, C, x, xpr, y, ypr, NormL; +{ + double p_norm, H, S, C, x, xpr, y, ypr, NormL; if (ks!=0) - for (c = 0;cMaxOrder; @@ -107,8 +106,8 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in }; }; - for (c = 0; c < num_particles; c++) { - r6 = r + c * 6; + for (int c = 0; c < num_particles; c++) { + double *r6 = r + c * 6; if (!atIsNaN(r6[0])) { if (mode == 0) { double tpart = t + r6[5] / C0; diff --git a/atintegrators/WakeFieldPass.c b/atintegrators/WakeFieldPass.c index 08f4769077..cd4819f1b4 100755 --- a/atintegrators/WakeFieldPass.c +++ b/atintegrators/WakeFieldPass.c @@ -48,7 +48,6 @@ void WakeFieldPass(double *r_in,int num_particles,double circumference,int nbunc double *z_cuts = Elem->z_cuts; size_t sz = 7*nslice*nbunch*sizeof(double) + num_particles*sizeof(int); - int c; int *pslice; double *kx; @@ -87,7 +86,7 @@ void WakeFieldPass(double *r_in,int num_particles,double circumference,int nbunc #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD) default(none) \ shared(r_in,num_particles,pslice,kx,kx2,ky,ky2,kz) private(c) */ - for (c=0; c #include "atlalib.c" +/* +To speed up the integration loop, the path length is computed in absolute on +each step, and the reference total length is subtracted at the end of the loop. +For other uses, the relative path length is computed. +*/ +#ifdef MAGNET_PASS #define ABSOLUTE_PATH_LENGTH +#define FIX_LENGTH(length) r6[5] -= (length) +#endif + #define SQR(X) ((X)*(X)) +#define DRIFT(r6, length, irho, bdiff) drift(r6, length, bdiff) + static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff) { /* Propagate cumulative Ohmi's diffusion matrix B through an exact drift. B is a (*double) pointer to 1-dimensional array containing 36 elements of @@ -36,7 +47,7 @@ static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff /* Forest 10.23, exact drift L: length [m] */ -static void drift(double *r6, double L, double irho, double *bdiff) +static void drift(double *r6, double L, double *bdiff) { double p_norm = 1.0 / (1.0+r6[4]); double xpr = r6[1] * p_norm; @@ -50,4 +61,7 @@ static void drift(double *r6, double L, double irho, double *bdiff) r6[0] += NormL * r6[1]; r6[2] += NormL * r6[3]; r6[5] += NormL * (1.0 + r6[4]); /* Absolute path length */ + #ifndef ABSOLUTE_PATH_LENGTH + r6[5] -= L; + #endif } diff --git a/atintegrators/drift_exactbend.h b/atintegrators/drift_exactbend.h index a7016b218d..cb5aca5148 100644 --- a/atintegrators/drift_exactbend.h +++ b/atintegrators/drift_exactbend.h @@ -4,7 +4,15 @@ #include #include "atlalib.c" +/* +To speed up the integration loop, the path length is computed in absolute on +each step, and the reference total length is subtracted at the end of the loop. +For other uses, the relative path length is computed. +*/ +#ifdef MAGNET_PASS #define ABSOLUTE_PATH_LENGTH +#define FIX_LENGTH(length) r6[5] -= (length) +#endif #ifndef PXYZ #define PXYZ @@ -14,7 +22,9 @@ static double pxyz(double dp1, double px, double py) } #endif /*PXYZ*/ -static void drift(double *r6, double L, double irho, double *bdiff) +#define DRIFT(r6,length,irho,bdiff) drift(r6,length,irho) + +static void drift(double *r6, double L, double irho) { /* Forest 12.18, bend-kick split, map W(L,irho) */ @@ -42,4 +52,7 @@ static void drift(double *r6, double L, double irho, double *bdiff) r6[y_] += dy; r6[ct_] += dct; } + #ifndef ABSOLUTE_PATH_LENGTH + r6[ct_] -= L; + #endif } diff --git a/atintegrators/drift_exactstrbend.h b/atintegrators/drift_exactstrbend.h index 38f6fd7cbc..74b1a98ba7 100644 --- a/atintegrators/drift_exactstrbend.h +++ b/atintegrators/drift_exactstrbend.h @@ -4,7 +4,15 @@ #include #include "atlalib.c" +/* +To speed up the integration loop, the path length is computed in absolute on +each step, and the reference total length is subtracted at the end of the loop. +For other uses, the relative path length is computed. +*/ +#ifdef MAGNET_PASS #define ABSOLUTE_PATH_LENGTH +#define FIX_LENGTH(length) r6[5] -= (length) +#endif #ifndef PXYZ #define PXYZ @@ -14,7 +22,9 @@ static double pxyz(double dp1, double px, double py) } #endif /*PXYZ*/ -static void drift(double *r6, double L, double irho, double *bdiff) +#define DRIFT(r6,length,irho,bdiff) drift(r6,length,irho) + +static void drift(double *r6, double L, double irho) { /* Forest 12.39, bend-kick split, map V(L,irho) */ @@ -39,4 +49,7 @@ static void drift(double *r6, double L, double irho, double *bdiff) r6[y_] += dy; r6[ct_] += dct; } + #ifndef ABSOLUTE_PATH_LENGTH + r6[ct_] -= L; + #endif } diff --git a/atintegrators/drift_expanded.h b/atintegrators/drift_expanded.h index bb1b048242..258566af03 100644 --- a/atintegrators/drift_expanded.h +++ b/atintegrators/drift_expanded.h @@ -1,6 +1,8 @@ #include "atlalib.c" #define SQR(X) ((X)*(X)) +#define DRIFT(r6, length, irho, bdiff) drift(r6, length, bdiff) + static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff) { /* Propagate cumulative Ohmi's diffusion matrix B through a drift. B is a (*double) pointer to 1-dimensional array containing 36 elements of @@ -29,7 +31,7 @@ static void drift_propagateB(double NormL, double xpr, double ypr, double *bdiff ATsandwichmmt(M66, bdiff); } -static void drift(double *r6, double L, double irho, double *bdiff) +static void drift(double *r6, double L, double *bdiff) { double p_norm = 1.0 / (1.0+r6[4]); double px = r6[1]; diff --git a/atintegrators/drift_fast.h b/atintegrators/drift_fast.h deleted file mode 100644 index b2ac6e7131..0000000000 --- a/atintegrators/drift_fast.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifdef RADIATION -#error "drift_fast cannot be used with radiation" -#endif -#ifdef DIFFUSION -#error "drift_fast does not compute the diffusion matrix" -#endif - -#define FAST_DRIFT - -static void drift(double* r, double NormL, double irho, double *bdiff) - -/* NormL=(Physical Length)/(1+delta) is computed externally to speed up calculations - in the loop if momentum deviation (delta) does not change - such as in 4-th order symplectic integrator w/o radiation - */ - -{ - r[0] += NormL*r[1]; - r[2] += NormL*r[3]; - r[5] += NormL*(r[1]*r[1] + r[3]*r[3])/(2.0 * (1.0 + r[4])); -} diff --git a/atintegrators/drift_template.h b/atintegrators/drift_template.h new file mode 100644 index 0000000000..4e0e75dd39 --- /dev/null +++ b/atintegrators/drift_template.h @@ -0,0 +1,128 @@ +#include "atelem.c" +#include "atlalib.c" + +struct elem { + double Length; + double *R1; + double *R2; + double *T1; + double *T2; + double *EApertures; + double *RApertures; +}; + +void drift_pass(double *r_in, double le, + const double *T1, const double *T2, + const double *R1, const double *R2, + double *RApertures, double *EApertures, + int num_particles +) +/* le - physical length + r_in - 6-by-N matrix of initial conditions reshaped into + 1-d array of 6*N elements +*/ +{ + #pragma omp parallel for if (num_particles > OMP_PARTICLE_THRESHOLD * 10) default(none) \ + shared(r_in, le, num_particles, RApertures, EApertures, T1, T2, R1, R2) + for (int c = 0; c < num_particles; c++) { /*Loop over particles */ + double *r6 = r_in + c * 6; + if (!atIsNaN(r6[0])) { + + /* misalignment at entrance */ + if (T1) ATaddvv(r6, T1); + if (R1) ATmultmv(r6, R1); + + /* Check physical apertures at the entrance of the magnet */ + if (RApertures) checkiflostRectangularAp(r6, RApertures); + if (EApertures) checkiflostEllipticalAp(r6, EApertures); + + DRIFT(r6, le, 0.0, NULL); + + /* Check physical apertures at the exit of the magnet */ + if (RApertures) checkiflostRectangularAp(r6, RApertures); + if (EApertures) checkiflostEllipticalAp(r6, EApertures); + + /* Misalignment at exit */ + if (R2) ATmultmv(r6, R2); + if (T2) ATaddvv(r6, T2); + } + } +} + +#if defined(MATLAB_MEX_FILE) || defined(PYAT) +ExportMode struct elem *trackFunction(const atElem *ElemData, struct elem *Elem, + double *r_in, int num_particles, + struct parameters *Param +) +{ + if (!Elem) { + double Length = atGetDouble(ElemData, "Length"); check_error(); + double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); + double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); + double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); + double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); + double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); + double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); + Elem = (struct elem *)atMalloc(sizeof(struct elem)); + Elem->Length = Length; + Elem->R1 = R1; + Elem->R2 = R2; + Elem->T1 = T1; + Elem->T2 = T2; + Elem->EApertures = EApertures; + Elem->RApertures = RApertures; + } + drift_pass(r_in, Elem->Length, Elem->T1, Elem->T2, Elem->R1, Elem->R2, + Elem->RApertures, Elem->EApertures, num_particles); + return Elem; +} + +MODULE_DEF(DRIFT_PASS) /* Dummy module initialisation */ + +#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ + +#if defined(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]); + + double Length = atGetDouble(ElemData, "Length"); check_error(); + double *R1 = atGetOptionalDoubleArray(ElemData, "R1"); check_error(); + double *R2 = atGetOptionalDoubleArray(ElemData, "R2"); check_error(); + double *T1 = atGetOptionalDoubleArray(ElemData, "T1"); check_error(); + double *T2 = atGetOptionalDoubleArray(ElemData, "T2"); check_error(); + double *EApertures = atGetOptionalDoubleArray(ElemData, "EApertures"); check_error(); + double *RApertures = atGetOptionalDoubleArray(ElemData, "RApertures"); check_error(); + if (mxGetM(prhs[1]) != 6) + mexErrMsgIdAndTxt("AT:WrongArg", "Second argument must be a 6 x N matrix"); + /* ALLOCATE memory for the output array of the same size as the input */ + plhs[0] = mxDuplicateArray(prhs[1]); + r_in = mxGetDoubles(plhs[0]); + drift_pass(r_in, Length, T1, T2, R1, R2, RApertures, EApertures, + num_particles); + } + else if (nrhs == 0) { + /* list of required fields */ + int i0 = 0; + plhs[0] = mxCreateCellMatrix(1, 1); + mxSetCell(plhs[0], i0++, mxCreateString("Length")); + if (nlhs > 1) { + /* list of optional fields */ + int i1 = 0; + plhs[1] = mxCreateCellMatrix(6, 1); + mxSetCell(plhs[1], i1++, mxCreateString("T1")); + mxSetCell(plhs[1], i1++, mxCreateString("T2")); + mxSetCell(plhs[1], i1++, mxCreateString("R1")); + mxSetCell(plhs[1], i1++, mxCreateString("R2")); + mxSetCell(plhs[1], i1++, mxCreateString("RApertures")); + mxSetCell(plhs[1], i1++, mxCreateString("EApertures")); + } + } + else { + mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); + } +} +#endif /*defined(MATLAB_MEX_FILE)*/ diff --git a/atintegrators/integrators.h b/atintegrators/integrators.h index 63a606bb9d..0d03905e0e 100644 --- a/atintegrators/integrators.h +++ b/atintegrators/integrators.h @@ -40,46 +40,64 @@ #define INTEGRATOR integrator #endif -#ifdef ABSOLUTE_PATH_LENGTH -#define FIX_LENGTH r6[5] -= (le+refdz); -#else -#define FIX_LENGTH +#ifndef FIX_LENGTH +#define FIX_LENGTH(length) #endif #if defined(INTEGRATOR_4) -#define integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + +#define INTEGRATOR_STEPS(sl) \ + double ID1 = DRIFT1 * sl; \ + double ID2 = DRIFT2 * sl; \ + double IK1 = KICK1 * sl; \ + double IK2 = KICK2 * sl; + +#define integrator(r6, num_int_steps, slength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ for (int m = 0; m < num_int_steps; m++) { /* Loop over slices */ \ INTEGRATOR_PREFIX \ - DRIFT(r6, DRIFT1 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, KICK1 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, DRIFT2 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, KICK2 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, DRIFT2 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, KICK1 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, DRIFT1 * slength, irho, bdiff); \ + DRIFT(r6, ID1, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK1, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID2, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK2, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID2, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK1, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID1, irho, bdiff); \ INTEGRATOR_SUFFIX \ } \ - FIX_LENGTH + FIX_LENGTH(le+refdz); + #elif defined(INTEGRATOR_6) -#define integrator(r6, num_int_steps, slength, klength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ + +#define INTEGRATOR_STEPS(sl) \ + double ID1 = YD1 * sl; \ + double ID2 = YD2 * sl; \ + double ID3 = YD3 * sl; \ + double ID4 = YD4 * sl; \ + double IK1 = YK1 * sl; \ + double IK2 = YK2 * sl; \ + double IK3 = YK3 * sl; \ + double IK4 = YK4 * sl; + +#define integrator(r6, num_int_steps, slength, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) \ for (int m = 0; m < num_int_steps; m++) { /* Loop over slices */ \ INTEGRATOR_PREFIX \ - DRIFT(r6, YD1 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, YK1 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, YD2 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, YK2 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, YD3 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, YK3 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, YD4 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, YK4 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, YD4 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, YK3 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, YD3 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, YK2 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, YD2 * slength, irho, bdiff); \ - KICK_(r6, A0, B0, A, B, max_order, YK1 * klength, irho, rad_const, diff_const, bdiff); \ - DRIFT(r6, YD1 * slength, irho, bdiff); \ + DRIFT(r6, ID1, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK1, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID2, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK2, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID3, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK3, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID4, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK4, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID4, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK3, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID3, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK2, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID2, irho, bdiff); \ + KICK_(r6, A0, B0, A, B, max_order, IK1, irho, rad_const, diff_const, bdiff); \ + DRIFT(r6, ID1, irho, bdiff); \ INTEGRATOR_SUFFIX \ } \ - FIX_LENGTH + FIX_LENGTH(le+refdz); + #endif /*INTEGRATOR_4*/ diff --git a/atintegrators/magnet_template.h b/atintegrators/magnet_template.h index 6c0cd7da51..571ddfe136 100644 --- a/atintegrators/magnet_template.h +++ b/atintegrators/magnet_template.h @@ -81,12 +81,14 @@ static void magnet(double *r, double le, double bending_angle, ) { double irho = bending_angle / le; + #ifdef RADIATION double rad_const = RAD_CONST*pow(gamma0, 3); double diff_const = DIF_CONST*pow(gamma0, 5); #else double *bdiff = NULL; #endif + #ifdef STRAIGHT_DIPOLE double phi2 = 0.5 * bending_angle; double phi_entrance = phi2-entrance_angle; @@ -97,6 +99,8 @@ static void magnet(double *r, double le, double bending_angle, double refdz = 0.0; double SL = (num_int_steps > 0) ? le/num_int_steps : le; #endif /*STRAIGHT_DIPOLE*/ + + INTEGRATOR_STEPS(SL) double B1 = (max_order >= 1) ? B[1] : 0.0; double A0 = 0.0; #ifdef CURVATURE_IN_B0 @@ -118,11 +122,6 @@ static void magnet(double *r, double le, double bending_angle, if (!atIsNaN(r6[0])) { /* Check for change of reference momentum */ if (scaling != 1.0) ATChangePRef(r6, scaling); - #ifdef FAST_DRIFT - double DL = SL / (1.0 + r6[4]); - #else - #define DL SL - #endif /* misalignment at entrance */ if (T1) ATaddvv(r6,T1); @@ -136,7 +135,7 @@ static void magnet(double *r, double le, double bending_angle, MAGNET_ENTRY /* Integrator */ - INTEGRATOR(r6, num_int_steps, DL, SL, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff); + INTEGRATOR(r6, num_int_steps, SL, irho, A0, B0, A, B, max_order, rad_const, diff_const, bdiff) /* Exit face*/ MAGNET_EXIT diff --git a/atintegrators/multipolefringe.h b/atintegrators/multipolefringe.h index 608e8f2413..f4f86c9f46 100644 --- a/atintegrators/multipolefringe.h +++ b/atintegrators/multipolefringe.h @@ -137,6 +137,7 @@ static void multipole_fringe(double *r6, int method, double B1, double edge) { switch (method) { + case 0: break; case 1: quad_fringe(r6, B1, edge); break; case 2: if (fringeIntM0 && fringeIntP0) { diff --git a/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c b/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c index 1aa7fe568e..6627efd106 100644 --- a/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c +++ b/atmat/atphysics/Radiation/findmpoleraddiffmatrix.c @@ -342,7 +342,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl /* Propagate orbit_in and BDIFF through a 4-th orderintegrator */ for(m=0; m < num_int_steps; m++) /* Loop over slices */ - { drift(orbit_in, L1, irho, BDIFF); + { DRIFT(orbit_in, L1, irho, BDIFF); thinkickM(orbit_in, A,B, K1, irho, max_order, MKICK); thinkickB(orbit_in, A,B, K1, irho, max_order, E0, BKICK); @@ -350,7 +350,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl ATaddmm(BKICK,BDIFF); thinkickrad(orbit_in, A, B, K1, irho, E0, max_order); - drift(orbit_in, L2, irho, BDIFF); + DRIFT(orbit_in, L2, irho, BDIFF); thinkickM(orbit_in, A,B, K2, irho, max_order, MKICK); thinkickB(orbit_in, A,B, K2, irho, max_order, E0, BKICK); @@ -358,7 +358,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl ATaddmm(BKICK,BDIFF); thinkickrad(orbit_in, A, B, K2, irho, E0, max_order); - drift(orbit_in, L2, irho, BDIFF); + DRIFT(orbit_in, L2, irho, BDIFF); thinkickM(orbit_in, A,B, K1, irho, max_order, MKICK); thinkickB(orbit_in, A,B, K1, irho, max_order, E0, BKICK); @@ -366,7 +366,7 @@ static void FindElemB(double *orbit_in, double le, double irho, double *A, doubl ATaddmm(BKICK,BDIFF); thinkickrad(orbit_in, A, B, K1, irho, E0, max_order); - drift(orbit_in, L1, irho, BDIFF); + DRIFT(orbit_in, L1, irho, BDIFF); } edgefringeB(orbit_in, BDIFF, irho, exit_angle, fringe_int2, full_gap); From e0625c76a20e74caa414c9cd238481e8aba979d9 Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Wed, 29 Jul 2026 14:25:52 +0200 Subject: [PATCH 07/10] Updated linearquadfringe.c from @wei0852 --- atintegrators/linearquadfringe.h | 116 +++++++++++++++++-------------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/atintegrators/linearquadfringe.h b/atintegrators/linearquadfringe.h index 577cf6b3da..77d6618477 100644 --- a/atintegrators/linearquadfringe.h +++ b/atintegrators/linearquadfringe.h @@ -2,7 +2,7 @@ static void QuadFringePassP(double* r, const double b2) { -/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] +/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] Lee-Whiting's thin lens limit formula as given in p. 390 of "Beam Dynamics..."by E. Forest */ register double u = b2/(12.0*(1.0+r[4])); register double x2 = r[0]*r[0]; @@ -15,19 +15,19 @@ static void QuadFringePassP(double* r, const double b2) r[0]+=gx; r1tmp=3*u*(2*xz*r[3]-(x2+z2)*r[1]); - + r[2]-=gz; - + r3tmp=3*u*(2*xz*r[1]-(x2+z2)*r[3]); r[5]-=(gz*r[3] - gx*r[1])/(1+r[4]); - + r[1]+=r1tmp; r[3]-=r3tmp; } static void QuadFringePassN(double* r, const double b2) { -/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] +/* x=r[0],px=r[1],y=r[2],py=r[3],delta=r[4],ct=r[5] Lee-Whiting's thin lens limit formula as given in p. 390 of "Beam Dynamics..."by E. Forest */ register double u = b2/(12.0*(1.0+r[4])); register double x2 = r[0]*r[0]; @@ -40,12 +40,12 @@ static void QuadFringePassN(double* r, const double b2) r[0]-=gx; r1tmp=3*u*(2*xz*r[3]-(x2+z2)*r[1]); - + r[2]+=gz; - + r3tmp=3*u*(2*xz*r[1]-(x2+z2)*r[3]); r[5]+=(gz*r[3] - gx*r[1])/(1+r[4]); - + r[1]-=r1tmp; r[3]+=r3tmp; } @@ -57,38 +57,38 @@ static void quadPartialFringeMatrix(double R[6][6], double K1, double inFringe, double K1sqr, expJ1x, expJ1y; R[4][4] = R[5][5] = 1; - + K1sqr = K1*K1; if (part==1) { - J1x = inFringe*(K1*fringeInt[1] - 2*K1sqr*fringeInt[3]/3.); - J2x = inFringe*(K1*fringeInt[2]); - J3x = inFringe*(K1sqr*(fringeInt[2] + fringeInt[4])); + J1x = inFringe*(K1*fringeInt[1] - 2*K1sqr*fringeInt[3]/3. - K1sqr * fringeInt[0] * fringeInt[2] / 2); + J2x = inFringe*K1*fringeInt[2]; + J3x = inFringe*K1sqr*(fringeInt[2] + fringeInt[4] + fringeInt[0] * fringeInt[1]); - K1 = -K1; - J1y = inFringe*(K1*fringeInt[1] - 2*K1sqr*fringeInt[3]/3.); + //K1 = -K1; + J1y = inFringe * (-K1 * fringeInt[1] - 2 * K1sqr * fringeInt[3] / 3. - K1sqr * fringeInt[0] * fringeInt[2] / 2); J2y = -J2x; J3y = J3x; } else { - J1x = inFringe*(K1*fringeInt[1] + K1sqr*fringeInt[0]*fringeInt[2]/2); - J2x = inFringe*(K1*fringeInt[2]); - J3x = inFringe*(K1sqr*(fringeInt[4]-fringeInt[0]*fringeInt[1])); + J1x = inFringe * (K1 * fringeInt[1] + K1sqr * fringeInt[0] * fringeInt[2] / 2); + J2x = inFringe * K1 * fringeInt[2]; + J3x = inFringe * K1sqr * (fringeInt[4] - fringeInt[0] * fringeInt[1]); - K1 = -K1; - J1y = inFringe*(K1*fringeInt[1] + K1sqr*fringeInt[0]*fringeInt[2]); + //K1 = -K1; + J1y = inFringe * (-K1 * fringeInt[1] + K1sqr * fringeInt[0] * fringeInt[2] / 2); J2y = -J2x; J3y = J3x; } expJ1x = R[0][0] = exp(J1x); - R[0][1] = J2x/expJ1x; - R[1][0] = expJ1x*J3x; - R[1][1] = (1 + J2x*J3x)/expJ1x; - + R[0][1] = J2x / expJ1x; + R[1][0] = expJ1x * J3x; + R[1][1] = (1 + J2x * J3x) / expJ1x; + expJ1y = R[2][2] = exp(J1y); - R[2][3] = J2y/expJ1y; - R[3][2] = expJ1y*J3y; - R[3][3] = (1 + J2y*J3y)/expJ1y; + R[2][3] = J2y / expJ1y; + R[3][2] = expJ1y * J3y; + R[3][3] = (1 + J2y * J3y) / expJ1y; return; } @@ -98,27 +98,36 @@ static void linearQuadFringeElegantEntrance(double* r6, double b2, double *fring double R[6][6]; double *fringeIntM, *fringeIntP; double delta, inFringe; + double x, px, y, py, swap_temp; /* quadrupole linear fringe field, from elegant code */ - inFringe=-1.0; - fringeIntM = fringeIntP0; - fringeIntP = fringeIntM0; + inFringe=1.0; + fringeIntM = fringeIntM0; + fringeIntP = fringeIntP0; delta = r6[4]; /* determine first linear matrix for this delta */ - quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntM, 1); - r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; - r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; - r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; - r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; + quadPartialFringeMatrix(R, b2, inFringe, fringeIntP, 2); + swap_temp = R[0][0]; R[0][0] = R[1][1]; R[1][1] = swap_temp; + swap_temp = R[2][2]; R[2][2] = R[3][3]; R[3][3] = swap_temp; + + x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; + r6[0] = R[0][0]*x + R[0][1]*px; + r6[1] = R[1][0]*x + R[1][1]*px; + r6[2] = R[2][2]*y + R[2][3]*py; + r6[3] = R[3][2]*y + R[3][3]*py; /* nonlinear fringe field */ QuadFringePassP(r6,b2); /*This is original AT code*/ /*Linear fringe fields from elegant*/ - inFringe=-1.0; + inFringe=1.0; /* determine and apply second linear matrix, from elegant code */ - quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntP, 2); - r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; - r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; - r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; - r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; + quadPartialFringeMatrix(R, b2, inFringe, fringeIntM, 1); + swap_temp = R[0][0]; R[0][0] = R[1][1]; R[1][1] = swap_temp; + swap_temp = R[2][2]; R[2][2] = R[3][3]; R[3][3] = swap_temp; + + x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; + r6[0] = R[0][0]*x + R[0][1]*px; + r6[1] = R[1][0]*x + R[1][1]*px; + r6[2] = R[2][2]*y + R[2][3]*py; + r6[3] = R[3][2]*y + R[3][3]*py; } @@ -127,27 +136,28 @@ static void linearQuadFringeElegantExit(double* r6, double b2, double *fringeInt double R[6][6]; double *fringeIntM, *fringeIntP; double delta, inFringe; + double x, px, y, py; /* quadrupole linear fringe field, from elegant code */ inFringe=1.0; fringeIntM = fringeIntM0; fringeIntP = fringeIntP0; delta = r6[4]; /* determine first linear matrix for this delta */ - quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntP, 2); - r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; - r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; - r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; - r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; + quadPartialFringeMatrix(R, b2, inFringe, fringeIntM, 1); + x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; + r6[0] = R[0][0]*x + R[0][1]*px; + r6[1] = R[1][0]*x + R[1][1]*px; + r6[2] = R[2][2]*y + R[2][3]*py; + r6[3] = R[3][2]*y + R[3][3]*py; /* nonlinear fringe field */ QuadFringePassN(r6,b2); /*This is original AT code*/ /*Linear fringe fields from elegant*/ inFringe=1.0; /* determine and apply second linear matrix, from elegant code */ - quadPartialFringeMatrix(R, b2/(1+delta), inFringe, fringeIntM, 1); - r6[0] = R[0][0]*r6[0] + R[0][1]*r6[1]; - r6[1] = R[1][0]*r6[0] + R[1][1]*r6[1]; - r6[2] = R[2][2]*r6[2] + R[2][3]*r6[3]; - r6[3] = R[3][2]*r6[2] + R[3][3]*r6[3]; -} - - + quadPartialFringeMatrix(R, b2, inFringe, fringeIntP, 2); + x = r6[0]; px = r6[1]; y = r6[2]; py = r6[3]; + r6[0] = R[0][0]*x + R[0][1]*px; + r6[1] = R[1][0]*x + R[1][1]*px; + r6[2] = R[2][2]*y + R[2][3]*py; + r6[3] = R[3][2]*y + R[3][3]*py; +} \ No newline at end of file From 8d82a8c8ad6ad03b12ed4c693bb41a01a11f33ef Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Fri, 31 Jul 2026 10:08:06 +0200 Subject: [PATCH 08/10] relax test in legacy matching --- pyat/test/test_legacy_matching.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/test/test_legacy_matching.py b/pyat/test/test_legacy_matching.py index b880643bed..9f8abfb477 100644 --- a/pyat/test/test_legacy_matching.py +++ b/pyat/test/test_legacy_matching.py @@ -94,7 +94,7 @@ def test_envelope_matching(mring: Lattice): # check the residuals residual = lopcst.evaluate(newring.radiation_on(copy=True)) - assert_close(residual, 0, rtol=0.0, atol=2.e-8) + assert_close(residual, 0, rtol=0.0, atol=3.e-8) # Define the constraints lincst = LinoptConstraints(ring) From cbd39a28db9065b375a2551c0caa5a59ea1847e0 Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Fri, 31 Jul 2026 10:21:03 +0200 Subject: [PATCH 09/10] relax test in legacy matching --- pyat/test/test_legacy_matching.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyat/test/test_legacy_matching.py b/pyat/test/test_legacy_matching.py index 9f8abfb477..453d89098f 100644 --- a/pyat/test/test_legacy_matching.py +++ b/pyat/test/test_legacy_matching.py @@ -108,5 +108,5 @@ def test_envelope_matching(mring: Lattice): # check the residuals linresidual = lincst.evaluate(newring) lopresidual = lopcst.evaluate(newring.radiation_on(copy=True)) - assert_close(linresidual, 0, rtol=0.0, atol=2.e-8) - assert_close(lopresidual, 0, rtol=0.0, atol=3e-8) + assert_close(linresidual, 0, rtol=0.0, atol=3.e-8) + assert_close(lopresidual, 0, rtol=0.0, atol=3.e-8) From 10998e41b3d8520d900852af463a8f4bea580df2 Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Wed, 5 Aug 2026 11:07:27 +0200 Subject: [PATCH 10/10] relax Matlab tests for MacOS --- atmat/attests/pytests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atmat/attests/pytests.m b/atmat/attests/pytests.m index 94792024ae..18d77f487f 100644 --- a/atmat/attests/pytests.m +++ b/atmat/attests/pytests.m @@ -223,7 +223,7 @@ function avlin1(testCase, lat, dp) % Matlab [~,mbeta,mmu,mdisp,~,~]=atavedata(lattice.m,dp,mrefs); % check - testCase.verifyEqual(mbeta,pbeta,AbsTol=1.E-8,RelTol=1.e-8); + testCase.verifyEqual(mbeta,pbeta,AbsTol=1.E-8,RelTol=2.e-8); testCase.verifyEqual(mmu,pmu,AbsTol=1.E-8,RelTol=0); testCase.verifyEqual(mdisp,pdisp,AbsTol=1.E-8,RelTol=0); end