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..2bc53f839e 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; } @@ -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=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..52f753bb8e 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_expanded.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..6a20062010 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_expanded.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 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/E2_dipole.h b/atintegrators/E2_dipole.h new file mode 100644 index 0000000000..34a1dcc095 --- /dev/null +++ b/atintegrators/E2_dipole.h @@ -0,0 +1,135 @@ +#ifndef E2_DIPOLE +#define E2_DIPOLE +#include +#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..32d52da537 100644 --- a/atintegrators/ExactDriftPass.c +++ b/atintegrators/ExactDriftPass.c @@ -1,126 +1,4 @@ -#include "atelem.c" -#include "atlalib.c" -#include "exactdrift.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); - - exact_drift(r6, le); - - /* 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/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..1e3a94c12b 100644 --- a/atintegrators/ExactRectBendPass.c +++ b/atintegrators/ExactRectBendPass.c @@ -1,309 +1,32 @@ -#include "atconstants.h" -#include "atelem.c" -#include "atlalib.c" -#include "driftkick.c" /* strthinkick.c */ -#include "exactbend.c" -#include "exactbendfringe.c" -#include "exactmultipolefringe.c" +#define MAGNET_PASS ExactRectBendPass +#define INTEGRATOR_6 -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_exactstrbend.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; +#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); \ } - #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 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..6304e4fd84 100644 --- a/atintegrators/ExactSectorBendPass.c +++ b/atintegrators/ExactSectorBendPass.c @@ -1,290 +1,31 @@ -#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; +#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, 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); \ } - #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 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/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;c 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..0386eaaee2 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_expanded.h" +#include "kick_kn.h" +#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; 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; @@ -117,7 +116,7 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic); }; }; - strthinkick(r6, pola, polb, 1.0, maxorder); + kick(r6, 0.0, 0.0, pola, polb, maxorder, 1.0, 0.0); } } } 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= 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..306330a1cb 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) @@ -10,15 +10,13 @@ void trackRFCavity(double *r_in, double le, double nv, double freq, double h, do 1-d array of 6*N elements */ { - int c; - /* If nv is 0 and length is 0, then skip this whole loop (good for passive rf cavities anyway if there is a cavity length, we have to loop through the particles */ if (le == 0) { if (nv != 0) { - for (c = 0; c +#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..8ec2bbf873 --- /dev/null +++ b/atintegrators/drift_E2.h @@ -0,0 +1,21 @@ +#ifdef DIFFUSION +#error "drift_E2 does not compute the diffusion matrix" +#endif + +#define DRIFT(r6, length, irho, bdiff) drift(r6, length, irho) + +/* 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 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 77% rename from atintegrators/diff_exactdrift.c rename to atintegrators/drift_exact.h index 6ce53042e5..d9280bb4e1 100644 --- a/atintegrators/diff_exactdrift.c +++ b/atintegrators/drift_exact.h @@ -1,6 +1,19 @@ #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 + #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 @@ -34,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 diff_exactdrift(double *r6, double L, 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; @@ -48,4 +61,7 @@ static void diff_exactdrift(double *r6, double L, 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/exactbend.c b/atintegrators/drift_exactbend.h similarity index 54% rename from atintegrators/exactbend.c rename to atintegrators/drift_exactbend.h index 3113b91b14..cb5aca5148 100644 --- a/atintegrators/exactbend.c +++ b/atintegrators/drift_exactbend.h @@ -1,4 +1,18 @@ +#ifdef DIFFUSION +#error "drift_exactbend does not compute the diffusion matrix" +#endif + #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 @@ -8,7 +22,9 @@ static double pxyz(double dp1, double px, double py) } #endif /*PXYZ*/ -static void exact_bend(double *r6, double irho, double L) +#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) */ @@ -36,31 +52,7 @@ static void exact_bend(double *r6, double irho, double L) r6[y_] += dy; 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; - } + #ifndef ABSOLUTE_PATH_LENGTH + r6[ct_] -= L; + #endif } diff --git a/atintegrators/drift_exactstrbend.h b/atintegrators/drift_exactstrbend.h new file mode 100644 index 0000000000..74b1a98ba7 --- /dev/null +++ b/atintegrators/drift_exactstrbend.h @@ -0,0 +1,55 @@ +#ifdef DIFFUSION +#error "drift_exactstrbend does not compute the diffusion matrix" +#endif + +#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 +static double pxyz(double dp1, double px, double py) +{ + return sqrt(dp1*dp1 - px*px - py*py); +} +#endif /*PXYZ*/ + +#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) */ + + 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; + } + #ifndef ABSOLUTE_PATH_LENGTH + r6[ct_] -= L; + #endif +} diff --git a/atintegrators/diff_drift.c b/atintegrators/drift_expanded.h similarity index 74% rename from atintegrators/diff_drift.c rename to atintegrators/drift_expanded.h index 90edff5147..258566af03 100644 --- a/atintegrators/diff_drift.c +++ b/atintegrators/drift_expanded.h @@ -1,3 +1,7 @@ +#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. @@ -27,17 +31,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 *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_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/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..0d03905e0e --- /dev/null +++ b/atintegrators/integrators.h @@ -0,0 +1,103 @@ +#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 + +#ifndef FIX_LENGTH +#define FIX_LENGTH(length) +#endif + +#if defined(INTEGRATOR_4) + +#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, 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(le+refdz); + +#elif defined(INTEGRATOR_6) + +#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, 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(le+refdz); + +#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 100% rename from atintegrators/quadfringe.c rename to atintegrators/linearquadfringe.h diff --git a/atintegrators/magnet_template.h b/atintegrators/magnet_template.h new file mode 100644 index 0000000000..571ddfe136 --- /dev/null +++ b/atintegrators/magnet_template.h @@ -0,0 +1,353 @@ +#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*/ + + INTEGRATOR_STEPS(SL) + 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 0: break; + 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 92% rename from atintegrators/atquantlib.c rename to atintegrators/quantum_diffusion.h index 0826cdb319..f20daa6147 100644 --- a/atintegrators/atquantlib.c +++ b/atintegrators/quantum_diffusion.h @@ -1,5 +1,17 @@ #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 +#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*/ static int nt = 347; @@ -454,3 +466,39 @@ static double getEnergy(pcg32_random_t *rng, double ec) return re * ec; } + +#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..6627efd106 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..18d77f487f 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) @@ -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 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_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): diff --git a/pyat/test/test_legacy_matching.py b/pyat/test/test_legacy_matching.py index b880643bed..453d89098f 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) @@ -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) 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, )