From a409dd675bfa2075304049503c2c99da0726b3fb Mon Sep 17 00:00:00 2001 From: joanarenillas <153927722+joanarenillas@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:17:22 +0200 Subject: [PATCH] Bug Fix: Wiggler diffusion matrix (#759) * Adding wiggler matrix diffusion code and modifying wiggler integrators to initialize z position for every particle * Silencing warnings for .mexw64 and .pyd extensions * Defining energy in mex file from Param instead of ElemData * Wiggler difussion matrices added to ohmienvelope * Matlab/Python mex function update * update matlab & python runners * Merged gwigrad2 to gwigR * GwigInit function update * Adding rotation and translation to integrators * Spelling typos * Wiggler index deletion enhanced * File modification log update * Updated radiation kicks computation and documentation * Minor changes to documentation * Updating rotation and translation diffusion * Minor changes to integrator file * Translation diffusion deleted * radiation kicks back to original formula --------- Co-authored-by: ZeusMarti Co-authored-by: oscarxblanco <108396048+oscarxblanco@users.noreply.github.com> --- .gitignore | 2 + atintegrators/GWigSymplecticPass.c | 16 +- atintegrators/GWigSymplecticRadPass.c | 17 +- atintegrators/gwigR.c | 534 +++++++++++++++++++---- atmat/atphysics/Radiation/FDW.c | 458 +++++++++++++++++++ atmat/atphysics/Radiation/FDW.m | 16 + atmat/atphysics/Radiation/ohmienvelope.m | 9 +- docs/common/sa_passmethods.md | 41 ++ 8 files changed, 995 insertions(+), 98 deletions(-) create mode 100644 atmat/atphysics/Radiation/FDW.c create mode 100644 atmat/atphysics/Radiation/FDW.m diff --git a/.gitignore b/.gitignore index d0bba65fe..5eaae37e9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,11 @@ *.mex *.mexa64 *.mexmaci64 +*.mexw64 # Compiled python *.pyc +*.pyd # pytest cache .cache diff --git a/atintegrators/GWigSymplecticPass.c b/atintegrators/GWigSymplecticPass.c index a943be136..26b5e945c 100644 --- a/atintegrators/GWigSymplecticPass.c +++ b/atintegrators/GWigSymplecticPass.c @@ -6,6 +6,11 @@ *--------------------------------------------------------------------------- * Modification Log: * ----------------- + * .03 2024-05-06 J. Arenillas, ALBA, jarenillas@axt.email + * Adding rotations and translations to wiggler. + * Bug fix in wiggler initialisation. + * Energy parameter bug fix. + * * .02 2003-06-18 J. Li * Cleanup the code * @@ -123,11 +128,13 @@ void GWigSymplecticPass(double *r, double Energy, double Ltot, double Lw, /* Energy is defined in the lattice in eV but GeV is used by the gwig code. */ Energy = Energy / 1e9; - GWigInit(&Wig, Energy, Ltot, Lw, Bmax, Nstep, Nmeth, NHharm, NVharm, By, Bx, T1, T2, R1, R2); - for (c = 0;cenergy); check_error(); Ltot = atGetDouble(ElemData, "Length"); check_error(); Lw = atGetDouble(ElemData, "Lw"); check_error(); Bmax = atGetDouble(ElemData, "Bmax"); check_error(); diff --git a/atintegrators/GWigSymplecticRadPass.c b/atintegrators/GWigSymplecticRadPass.c index bc4dfdb9d..802aab584 100644 --- a/atintegrators/GWigSymplecticRadPass.c +++ b/atintegrators/GWigSymplecticRadPass.c @@ -6,6 +6,10 @@ *--------------------------------------------------------------------------- * Modification Log: * ----------------- + * .03 2024-05-06 J. Arenillas, ALBA, jarenillas@axt.email + * Adding rotations and translations to wiggler. + * Bug fix in wiggler initialisation. + * Energy parameter bug fix. * .02 2003-06-18 J. Li * Cleanup the code * @@ -123,7 +127,7 @@ void GWigInit(struct gwigR *Wig,double design_energy, double Ltot, double Lw, #define second 2 #define fourth 4 -void GWigSymplecticRadPass(double *r,double Energy, double Ltot, double Lw, +void GWigSymplecticRadPass(double *r, double Energy, double Ltot, double Lw, double Bmax, int Nstep, int Nmeth, int NHharm, int NVharm, double *By, double *Bx, double *T1, double *T2, double *R1, double *R2, int num_particles) @@ -141,11 +145,13 @@ void GWigSymplecticRadPass(double *r,double Energy, double Ltot, double Lw, zEndPointV[0] = 0; zEndPointV[1] = Ltot; - GWigInit(&Wig, Energy, Ltot, Lw, Bmax, Nstep, Nmeth, NHharm, NVharm,0, 0, zEndPointH, zEndPointV, By, Bx, T1, T2, R1, R2); - for(c = 0;cenergy); check_error(); Ltot = atGetDouble(ElemData, "Length"); check_error(); Lw = atGetDouble(ElemData, "Lw"); check_error(); Bmax = atGetDouble(ElemData, "Bmax"); check_error(); diff --git a/atintegrators/gwigR.c b/atintegrators/gwigR.c index fd1995222..0096cfa62 100644 --- a/atintegrators/gwigR.c +++ b/atintegrators/gwigR.c @@ -2,25 +2,36 @@ *---------------------------------------------------------------------------- * Modification Log: * ----------------- - * .04 2003-04-29 YK Wu, Duke University - * using scientific notation for constants. + * .07 2024-05-09 J. Arenillas, ALBA, jarenillas@axt.email + * New expression for the comptation of radiation kicks. + * Adding new functions for the computation of wiggler diffusion matrix. + * Extending GwigB to compute the z-coordinate of the magnetic field. + * + * .06 2018-06-01 A.Mash'al, ILSF, a-mashal@ipm.ir + * Implementing Hessian of the Hamiltonian for computing wiggler transfer matrix + * + * .05 2018-02-13 O.Jimenez, ALBA Synchrotron, oscar.jimenez.1996@gmail.com + * Implementing radiation loss. + * + * .04 2003-04-29 YK Wu, Duke University + * Using scientific notation for constants. * Checked with TRACY pascal code. * Computing differential pathlength only. * - * .03 2003-04-28 YK Wu, Duke University - * Convert to C code and cross-checked with the pascal version; + * .03 2003-04-28 YK Wu, Duke University + * Convert to C code and cross-checked with the pascal version; * * .02 2001-12-xx Y. K. Wu, Duke University * Implementing DA version of the wiggler integrator for Pascal. * Gauge is disabled !!! (Dec. 4, 2001) - * + * * .01 2001-02-12 Y. K. Wu, LBNL * Implementing a generic wiggler integrator * for paraxial-ray Hamiltonian approximation. * - * + * *---------------------------------------------------------------------------- - * Accelerator Physics Group, Duke FEL Lab, www.fel.duke.edu + * Accelerator Physics Group, Duke FEL Lab, www.fel.duke.edu */ #ifndef GWIG @@ -30,23 +41,33 @@ #include #endif -void GWigGauge(struct gwigR *pWig, double *X, int flag); -void GWigPass_2nd(struct gwigR *pWig, double *X); -void GWigPass_4th(struct gwigR *pWig, double *X); -void GWigMap_2nd(struct gwigR *pWig, double *X, double dl); -void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy); -void GWigAy(struct gwigR *pWig, double *Xvec, double *pay, double *paypx); -void GWigRadiationKicks(struct gwigR *pWig, double *X, double *Bxyz, double dl); -void GWigB(struct gwigR *pWig, double *Xvec, double *B); -double sinc(double x ); - -/* This function appears to be unused. */ -void GWigGauge(struct gwigR *pWig, double *X, int flag) +#define SQR(X) ((X)*(X)) + +static void GWigGauge(struct gwigR *pWig, double *X, int flag); +static void GWigPass_2nd(struct gwigR *pWig, double *X); +static void GWigPass_4th(struct gwigR *pWig, double *X); +static void GWigMap_2nd(struct gwigR *pWig, double *X, double dl); +static void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy); +static void GWigAy(struct gwigR *pWig, double *Xvec, double *pay, double *paypx); +static void GWigRadiationKicks(struct gwigR *pWig, double *X, double *Bxyz, double dl); +static void GWigB(struct gwigR *pWig, double *Xvec, double *B); +static void AxHessian(struct gwigR *pWig, double *Xvec, double *pax); +static void AyHessian(struct gwigR *pWig, double *Xvec, double *pay); +static void Hessian(struct gwigR *pWig, double *Xvec, double *H2); +static void GWigInit2(struct gwigR *pWig, double design_energy, double Ltot, double Lw, double Bmax, + int Nstep, int Nmeth, int NHharm, int NVharm, + int HSplitPole, int VSplitPole, double *zEndPointH, double *zEndPointV, + double *By, double *Bx, double *T1, double *T2, + double *R1, double *R2); +static double sinc(double x); + + +static void GWigGauge(struct gwigR *pWig, double *X, int flag) { double ax, ay, axpy, aypx; GWigAx(pWig, X, &ax, &axpy); GWigAy(pWig, X, &ay, &aypx); - + if (flag == Elem_Entrance) { /* At the entrance of the wiggler */ X[1] = X[1] + ax; @@ -61,24 +82,25 @@ void GWigGauge(struct gwigR *pWig, double *X, int flag) } -void GWigPass_2nd(struct gwigR *pWig, double *X) +static void GWigPass_2nd(struct gwigR *pWig, double *X) { int i, Nstep; double dl; - double B[2]; + double B[3]; double ax, ay, axpy, aypx; - + Nstep = pWig->PN*(pWig->Nw); dl = pWig->Lw/(pWig->PN); - - GWigAx(pWig, X, &ax, &axpy); - GWigAy(pWig, X, &ay, &aypx); - GWigB(pWig, X, B); - X[1] -= ax; - X[3] -= ay; - GWigRadiationKicks(pWig, X, B, dl); - X[1] += ax; - X[3] += ay; + + GWigAx(pWig, X, &ax, &axpy); + GWigAy(pWig, X, &ay, &aypx); + GWigB(pWig, X, B); + X[1] -= ax; + X[3] -= ay; + GWigRadiationKicks(pWig, X, B, dl); + X[1] += ax; + X[3] += ay; + for (i = 1; i <= Nstep; i++) { GWigMap_2nd(pWig, X, dl); GWigAx(pWig, X, &ax, &axpy); @@ -86,38 +108,40 @@ void GWigPass_2nd(struct gwigR *pWig, double *X) GWigB(pWig, X, B); X[1] -= ax; X[3] -= ay; - GWigRadiationKicks(pWig, X, B, dl); - X[1] += ax; + GWigRadiationKicks(pWig, X, B, dl); + X[1] += ax; X[3] += ay; } } -void GWigPass_4th(struct gwigR *pWig, double *X) +static void GWigPass_4th(struct gwigR *pWig, double *X) { - const double x1 = 1.3512071919596576340476878089715e0; const double x0 =-1.7024143839193152680953756179429e0; int i, Nstep; double dl, dl1, dl0; - double B[2]; - double ax, ay, axpy, aypx; - Nstep = pWig->PN*(pWig->Nw); - dl = pWig->Lw/(pWig->PN); + double B[3]; + double ax, ay, axpy, aypx; + double factorvect; - dl1 = x1*dl; - dl0 = x0*dl; + Nstep = pWig->PN*(pWig->Nw); + dl = pWig->Lw/(pWig->PN); - GWigAx(pWig, X, &ax, &axpy); - GWigAy(pWig, X, &ay, &aypx); - GWigB(pWig, X, B); - X[1] -= ax; - X[3] -= ay; - GWigRadiationKicks(pWig, X, B, dl); - X[1] += ax; - X[3] += ay; - for (i = 1; i <= Nstep; i++ ) { + dl1 = x1*dl; + dl0 = x0*dl; + + GWigAx(pWig, X, &ax, &axpy); + GWigAy(pWig, X, &ay, &aypx); + GWigB(pWig, X, B); + X[1] -= ax; + X[3] -= ay; + GWigRadiationKicks(pWig, X, B, dl); + X[1] += ax; + X[3] += ay; + + for (i = 1; i <= Nstep; i++) { GWigMap_2nd(pWig, X, dl1); GWigMap_2nd(pWig, X, dl0); GWigMap_2nd(pWig, X, dl1); @@ -128,17 +152,16 @@ void GWigPass_4th(struct gwigR *pWig, double *X) X[3] -= ay; GWigRadiationKicks(pWig, X, B, dl); X[1] += ax; - X[3] += ay; + X[3] += ay; } } -void GWigMap_2nd(struct gwigR *pWig, double *X, double dl) +static void GWigMap_2nd(struct gwigR *pWig, double *X, double dl) { - double dld, dl2, dl2d; double ax, ay, axpy, aypx; - + dld = dl/(1.0e0 + X[4]); dl2 = 0.5e0 * dl; dl2d = dl2/(1.0e0 + X[4]); @@ -153,7 +176,7 @@ void GWigMap_2nd(struct gwigR *pWig, double *X, double dl) X[2] = X[2] + dl2d*X[3]; X[5] = X[5] + 0.5e0*dl2d*(X[3]*X[3])/(1.0e0+X[4]); - + GWigAy(pWig, X, &ay, &aypx); X[1] = X[1] + aypx; X[3] = X[3] + ay; @@ -169,7 +192,7 @@ void GWigMap_2nd(struct gwigR *pWig, double *X, double dl) */ /* Differential path length only */ X[5] = X[5] + 0.5e0*dld*(X[1]*X[1])/(1.0e0+X[4]); - + GWigAx(pWig, X, &ax, &axpy); X[1] = X[1] + ax; X[3] = X[3] + axpy; @@ -181,7 +204,7 @@ void GWigMap_2nd(struct gwigR *pWig, double *X, double dl) X[2] = X[2] + dl2d*X[3]; X[5] = X[5] + 0.5e0*dl2d*(X[3]*X[3])/(1.0e0+X[4]); - + GWigAy(pWig, X, &ay, &aypx); X[1] = X[1] + aypx; X[3] = X[3] + ay; @@ -191,9 +214,8 @@ void GWigMap_2nd(struct gwigR *pWig, double *X, double dl) } -void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy) +static void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy) { - int i; double x, y, z; double kx, ky, kz, tz, kw; @@ -205,7 +227,7 @@ void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy) x = Xvec[0]; y = Xvec[2]; z = pWig->Zw; - + kw = 2e0*PI/(pWig->Lw); ax = 0e0; axpy = 0e0; @@ -239,7 +261,7 @@ void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy) /* Vertical Wiggler: note that one potentially could have: ky=0 */ - for (i = 0; i < pWig->NVharm; i++ ) { + for (i = 0; i < pWig->NVharm; i++) { pWig->VCw[i] = pWig->VCw_raw[i]*(pWig->Aw)/(gamma0*beta0); kx = pWig->Vkx[i]; ky = pWig->Vky[i]; @@ -253,7 +275,7 @@ void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy) chx = cosh(kx * x); cy = cos(ky * y); - axpy = axpy + pWig->VCw[i]*(kw/kz)* pow(ky/kx,2) *chx*cy*sz; + axpy = axpy + pWig->VCw[i]*(kw/kz)* pow(ky/kx,2) *chx*cy*sz; } *pax = ax; @@ -261,7 +283,7 @@ void GWigAx(struct gwigR *pWig, double *Xvec, double *pax, double *paxpy) } -void GWigAy(struct gwigR *pWig, double *Xvec, double *pay, double *paypx) +static void GWigAy(struct gwigR *pWig, double *Xvec, double *pay, double *paypx) { int i; double x, y, z; @@ -274,7 +296,7 @@ void GWigAy(struct gwigR *pWig, double *Xvec, double *pay, double *paypx) x = Xvec[0]; y = Xvec[2]; z = pWig->Zw; - + kw = 2e0*PI/(pWig->Lw); ay = 0e0; aypx = 0e0; @@ -282,29 +304,29 @@ void GWigAy(struct gwigR *pWig, double *Xvec, double *pay, double *paypx) gamma0 = pWig->E0/XMC2; beta0 = sqrt(1e0 - 1e0/(gamma0*gamma0)); pWig->Aw = (q_e/m_e/clight)/(2e0*PI) * (pWig->Lw) * (pWig->PB0); - + /* Horizontal Wiggler: note that one potentially could have: kx=0 */ - for ( i = 0; i < pWig->NHharm; i++ ){ + for (i = 0; i < pWig->NHharm; i++){ pWig->HCw[i] = (pWig->HCw_raw[i])*(pWig->Aw)/(gamma0*beta0); kx = pWig->Hkx[i]; ky = pWig->Hky[i]; kz = pWig->Hkz[i]; tz = pWig->Htz[i]; - + sx = sin(kx * x); shy = sinh(ky * y); sz = sin(kz * z + tz); ay = ay + (pWig->HCw[i])*(kw/kz)*(kx/ky)*sx*shy*sz; - + cx = cos(kx * x); chy = cosh(ky * y); - + aypx = aypx + (pWig->HCw[i])*(kw/kz)*pow(kx/ky,2) * cx*chy*sz; } /* Vertical Wiggler: note that one potentially could have: ky=0 */ for (i = 0; i < pWig->NVharm; i++) { - pWig->VCw[i] = (pWig->VCw_raw[i])*(pWig->Aw)/(gamma0*beta0); + pWig->VCw[i] = (pWig->VCw_raw[i])*(pWig->Aw)/(gamma0*beta0); kx = pWig->Vkx[i]; ky = pWig->Vky[i]; kz = pWig->Vkz[i]; @@ -323,24 +345,105 @@ void GWigAy(struct gwigR *pWig, double *Xvec, double *pay, double *paypx) } aypx = aypx + (pWig->VCw[i])*(kw/kz)* kx*shx*syky*sz; } - + *pay = ay; *paypx = aypx; } -double sinc(double x) +static double sinc(double x) { double x2, result; /* Expand sinc(x) = sin(x)/x to x^8 */ x2 = x*x; - result = 1e0 - x2/6e0*(1e0 - x2/20e0 *(1e0 - x2/42e0*(1e0-x2/72e0) ) ); + result = 1e0 - x2/6e0*(1e0 - x2/20e0 *(1e0 - x2/42e0*(1e0-x2/72e0))); return result; } +static void GWigInit2(struct gwigR *Wig,double design_energy, double Ltot, double Lw, + double Bmax, int Nstep, int Nmeth, int NHharm, int NVharm, + int HSplitPole, int VSplitPole, double *zEndPointH, + double *zEndPointV, double *By, double *Bx, double *T1, + double *T2, double *R1, double *R2) +{ + double *tmppr; + int i; + double kw; + + Wig->E0 = design_energy; + Wig->Po = Wig->E0/XMC2; + Wig->Pmethod = Nmeth; + Wig->PN = Nstep; + Wig->Nw = (int)(Ltot / Lw); + Wig->NHharm = NHharm; + Wig->NVharm = NVharm; + Wig->PB0 = Bmax; + Wig->Lw = Lw; + + /*------------------ radiation including -------------------*/ + Wig->srCoef = (q_e*q_e)*((Wig->Po)*(Wig->Po)*(Wig->Po))/(6*PI*epsilon_o*m_e*(clight*clight)); + Wig->HSplitPole = HSplitPole; + Wig->VSplitPole = VSplitPole; + Wig->zStartH = zEndPointH[0]; + Wig->zEndH = zEndPointH[1]; + Wig->zStartV = zEndPointV[0]; + Wig->zEndV = zEndPointV[1]; + /*----------------------------------------------------------*/ + + kw = 2.0e0*PI/(Wig->Lw); + Wig->Zw = 0.0; + Wig->Aw = 0.0; + tmppr = By; + for (i = 0; i < NHharm; i++) { + tmppr++; + Wig->HCw[i] = 0.0; + Wig->HCw_raw[i] = *tmppr; + tmppr++; + Wig->Hkx[i] = (*tmppr) * kw; + tmppr++; + Wig->Hky[i] = (*tmppr) * kw; + tmppr++; + Wig->Hkz[i] = (*tmppr) * kw; + tmppr++; + Wig->Htz[i] = *tmppr; + tmppr++; + } + tmppr = Bx; + for (i = 0; i < NVharm; i++) { + tmppr++; + Wig->VCw[i] = 0.0; + Wig->VCw_raw[i] = *tmppr; + tmppr++; + Wig->Vkx[i] = (*tmppr) * kw; + tmppr++; + Wig->Vky[i] = (*tmppr) * kw; + tmppr++; + Wig->Vkz[i] = (*tmppr) * kw; + tmppr++; + Wig->Vtz[i] = *tmppr; + tmppr++; + } + for (i = NHharm; i< WHmax; i++) { + Wig->HCw[i] = 0.0; + Wig->HCw_raw[i] = 0.0; + Wig->Hkx[i] = 0.0; + Wig->Hky[i] = 0.0; + Wig->Hkz[i] = 0.0; + Wig->Htz[i] = 0.0; + } + for (i = NVharm; i< WHmax; i++) { + Wig->VCw[i] = 0.0; + Wig->VCw_raw[i] = 0.0; + Wig->Vkx[i] = 0.0; + Wig->Vky[i] = 0.0; + Wig->Vkz[i] = 0.0; + Wig->Vtz[i] = 0.0; + } +} + -void GWigB(struct gwigR *pWig, double *Xvec, double *B) +static void GWigB(struct gwigR *pWig, double *Xvec, double *B) /* Compute magnetic field at particle location. * Added by M. Borland, August 2007. */ @@ -350,18 +453,19 @@ void GWigB(struct gwigR *pWig, double *Xvec, double *B) double kx, ky, kz, tz, kw; double cx, sx, chx, shx; double cy, sy, chy, shy; - double cz; + double cz, sz; /* B0 is a reserved symbol on MacOS, defined in termios.h */ double _B0; - + x = Xvec[0]; y = Xvec[2]; z = pWig->Zw; - + kw = 2e0*PI/(pWig->Lw); B[0] = 0; B[1] = 0; + B[2] = 0; if (pWig->NHharm && z>=pWig->zStartH && z<=pWig->zEndH) { _B0 = pWig->PB0; @@ -378,10 +482,12 @@ void GWigB(struct gwigR *pWig, double *Xvec, double *B) chy = cosh(ky * y); shy = sinh(ky * y); cz = cos(kz*z+tz); - - /* Accumulate field values in user-supplied array (Bx, By) */ + sz = sin(kz*z+tz); + + /* Accumulate field values in user-supplied array (Bx, By, Bz) */ B[0] += _B0*pWig->HCw_raw[i]*kx/ky*sx*shy*cz; B[1] -= _B0*pWig->HCw_raw[i]*cx*chy*cz; + B[2] += _B0*pWig->HCw_raw[i]*kz/ky*cx*shy*sz; } } else { /* Split-pole Horizontal Wiggler: note that one potentially could have: ky=0 (caught in main routine) */ @@ -396,18 +502,23 @@ void GWigB(struct gwigR *pWig, double *Xvec, double *B) cy = cos(ky * y); sy = sin(ky * y); cz = cos(kz*z+tz); - + cx = cos(kx*x); + chy = cosh(ky * y); + sz = sin(kz*z+tz); + + /* Accumulate field values in user-supplied array (Bx, By, Bz) */ B[0] -= _B0*pWig->HCw_raw[i]*kx/ky*shx*sy*cz; B[1] -= _B0*pWig->HCw_raw[i]*chx*cy*cz; + B[2] -= _B0*pWig->HCw_raw[i]*kz/ky*cx*chy*sz; } } } - + if (pWig->NVharm && z>=pWig->zStartV && z<=pWig->zEndV) { _B0 = pWig->PB0; if (!pWig->VSplitPole) { /* Normal Vertical Wiggler: note that one potentially could have: ky=0 */ - for (i = 0; i < pWig->NVharm; i++ ) { + for (i = 0; i < pWig->NVharm; i++) { kx = pWig->Vkx[i]; ky = pWig->Vky[i]; kz = pWig->Vkz[i]; @@ -418,14 +529,16 @@ void GWigB(struct gwigR *pWig, double *Xvec, double *B) sy = sin(ky * y); cy = cos(ky * y); cz = cos(kz*z + tz); + sz = sin(kz*z+tz); - /* Accumulate field values in user-supplied array (Bx, By) */ + /* Accumulate field values in user-supplied array (Bx, By, Bz) */ B[0] += _B0*pWig->VCw_raw[i]*chx*cy*cz; B[1] -= _B0*pWig->VCw_raw[i]*ky/kx*shx*sy*cz; + B[2] -= _B0*pWig->VCw_raw[i]*kz/kx*cy*shx*sz; } } else { /* Split-pole Vertical Wiggler: note that one potentially could have: kx=0 (caught in main routine) */ - for (i = 0; i < pWig->NVharm; i++ ) { + for (i = 0; i < pWig->NVharm; i++) { kx = pWig->Vkx[i]; ky = pWig->Vky[i]; kz = pWig->Vkz[i]; @@ -437,16 +550,17 @@ void GWigB(struct gwigR *pWig, double *Xvec, double *B) chy = cosh(ky * y); cz = cos(kz*z + tz); - /* Accumulate field values in user-supplied array (Bx, By) */ + /* Accumulate field values in user-supplied array (Bx, By, Bz) */ B[0] += _B0*pWig->VCw_raw[i]*cx*chy*cz; B[1] += _B0*pWig->VCw_raw[i]*ky/kx*sx*shy*cz; + B[2] += _B0*pWig->VCw_raw[i]*kz/kx*cx*shy*sz; } } } } -void GWigRadiationKicks(struct gwigR *pWig, double *X, double *Bxy, double dl) +static void GWigRadiationKicks(struct gwigR *pWig, double *X, double *Bxy, double dl) /* Apply kicks for synchrotron radiation. * Added by M. Borland, August 2007. */ @@ -459,7 +573,7 @@ void GWigRadiationKicks(struct gwigR *pWig, double *X, double *Bxy, double dl) B2 = (Bxy[0]*Bxy[0]) + (Bxy[1]*Bxy[1]); if (B2==0) return; - + /* Beam rigidity in T*m */ H = (pWig->Po)/586.679074042074490; @@ -468,12 +582,252 @@ void GWigRadiationKicks(struct gwigR *pWig, double *X, double *Bxy, double dl) /* (1+delta)^2 */ dFactor = ((1+X[4])*(1+X[4])); - + /* Classical radiation loss */ dDelta = -(pWig->srCoef)*dFactor*irho2*dl; X[4] += dDelta; X[1] *= (1+dDelta); X[3] *= (1+dDelta); - + +} + + +/* Hessian functions */ +static void Hessian(struct gwigR *pWig, double *Xvec, double *H2) +{ + int i,j,k; + double x,px,y,py,D; + double ax,axx,axxx,axy,axyy,axxy; + double ay, ayx, ayxx, ayy, ayyy, ayxy; + double Pax[6]; + double Pay[6]; + double H[6][6]; + + AxHessian(pWig, Xvec, Pax); + AyHessian(pWig, Xvec, Pay); + + ax =Pax[0]; + axx =Pax[1]; + axxx=Pax[2]; + axy =Pax[3]; + axyy=Pax[4]; + axxy=Pax[5]; + + ay =Pay[0]; + ayx =Pay[1]; + ayxx=Pay[2]; + ayy =Pay[3]; + ayyy=Pay[4]; + ayxy=Pay[5]; + + x =Xvec[0]; + px=Xvec[1]; + y =Xvec[2]; + py=Xvec[3]; + D =Xvec[4]; + + for(i=0;i<6;i++){ + for(j=0;j<6;j++){ + H[i][j]=0; + } + } + + H[0][0]= 0.5*(1/(1+D))*(((ax-px)*axxx)+ ((ay-py)*ayxx)+ (axx*axx)+ (ayx*ayx)); + H[0][1]=-0.5*(axx/(1+D)); + H[0][2]= 0.5*(1/(1+D))*(((ax-px)*axxy)+ ((ay-py)*ayxy)+ (axx*axy)+ (ayx*ayy)); + H[0][3]= -0.5*(ayx/(1+D)); + H[0][4]= -0.5*(1/((1+D)*(1+D)))*( ((ax-px)*axx)+ ((ay-py)*ayx)); + H[0][5]= 0.00; + + H[1][0]=-0.5*(axx/(1+D)); + H[1][1]= 0; + H[1][2]=-0.5*(axy/(1+D)); + H[1][3]= 0; + H[1][4]= 0.5*ax/((1+D)*(1+D)); + H[1][5]= 0.00; + + H[2][0]= 0.5*(1/(1+D))*(((ax-px)*axxy)+ ((ay-py)*ayxy)+ (axx*axy)+ (ayx*ayy)); + H[2][1]=-0.5*(axy/(1+D)); + H[2][2]= 0.5*(1/(1+D))*(((ax-px)*axxy)+ ((ay-py)*ayxy)+ (axy*axy)+ (ayy*ayy)); + H[2][3]= -0.5*(ayy/(1+D)); + H[2][4]= -0.5*(1/((1+D)*(1+D)))*( ((ax-px)*axy)+ ((ay-py)*ayy)); + H[2][5]=0; + + H[3][0]=-0.5*(ayx/(1+D)); + H[3][1]= 0; + H[3][2]=-0.5*(ayy/(1+D)); + H[3][3]= 0; + H[3][4]=0.5 *ay/((1+D)*(1+D)); + H[3][5]=0; + + H[4][0]= -0.5*(1/((1+D)*(1+D)))*( ((ax-px)*axx)+ ((ay-py)*ayx)); + H[4][1]= 0.5 *ax/((1+D)*(1+D)); + H[4][2]= -0.5*(1/((1+D)*(1+D)))*( ((ax-px)*axy)+ ((ay-py)*ayy)); + H[4][3]= 0.5 *ay/((1+D)*(1+D)); + H[4][4]=0.5 *(1/((1+D)*(1+D) *(1+D)))*(((ax*ax)+(ay*ay))-2*((ax*px)+(ay*py))); + H[4][5]=0; + + for (i=0;i<6;i++){ + for(j=0;j<6;j++){ + k=j+i*6; + H2[k]=H[i][j]; + } + } +} + + +static void AxHessian(struct gwigR *pWig, double *Xvec, double *pax) +{ + int i; + double x, y, z; + double kx, ky, kz, tz, kw; + double cx, chx, shx; + double sx; + double cy, sy, chy, shy, sz; + double gamma0, beta0; + double ax,axx,axxx,axy,axyy,axxy; + + x = Xvec[0]; + y = Xvec[2]; + z = pWig->Zw; + + kw = 2e0*PI/(pWig->Lw); + ax = 0e0; + axx = 0e0; + axxx = 0e0; + axy = 0e0; + axyy = 0e0; + axxy = 0e0; + gamma0 = pWig->Po; + beta0 = sqrt(1e0 - 1e0/(gamma0*gamma0)); + pWig->Aw = (q_e/m_e/clight)/(2e0*PI) * (pWig->Lw) * (pWig->PB0); + + /* Horizontal Wiggler: note that one potentially could have: kx=0 */ + for (i = 0; i < pWig->NHharm; i++) { + pWig->HCw[i] = pWig->HCw_raw[i]*(pWig->Aw)/(gamma0*beta0); + kx = pWig->Hkx[i]; + ky = pWig->Hky[i]; + kz = pWig->Hkz[i]; + tz = pWig->Htz[i]; + + cx = cos(kx*x); + sx = sin(kx*x); + chy = cosh(ky * y); + shy = sinh(ky * y); + sz = sin(kz * z + tz); + ax = ax + (pWig->HCw[i])*(kw/kz)*cx*chy*sz; + axx = axx- (pWig->HCw[i])*(kx)*(kw/kz)*sx*chy*sz; + axxx=axxx- (pWig->HCw[i])*(kx*kx)*(kw/kz)*cx*chy*sz; + axy = axy+ (pWig->HCw[i])*(ky)*(kw/kz)*cx*shy*sz; + axyy=axyy+ (pWig->HCw[i])*(ky*ky)*(kw/kz)*cx*chy*sz; + axxy=axxy- (pWig->HCw[i])*(kx*ky)*(kw/kz)*sx*shy*sz; + } + + /* Vertical Wiggler: note that one potentially could have: ky=0 */ + for (i = 0; i < pWig->NVharm; i++) { + pWig->VCw[i] = pWig->VCw_raw[i]*(pWig->Aw)/(gamma0*beta0); + kx = pWig->Vkx[i]; + ky = pWig->Vky[i]; + kz = pWig->Vkz[i]; + tz = pWig->Vtz[i]; + + shx = sinh(kx * x); + sy = sin(ky * y); + chx = cosh(kx * x); + cy = cos(ky * y); + sz = sin(kz * z + tz); + ax = ax + pWig->VCw[i]*(kw/kz)*(ky/kx)*shx*sy*sz; + axx = axx+ pWig->VCw[i]*(kw/kz)*(ky)*chx*sy*sz; + axxx=axxx+ pWig->VCw[i]*(kw/kz)*(ky*kx)*chx*sy*sz; + axy = axy+ pWig->VCw[i]*(kw/kz)*(ky)*(ky/kx)*shx*cy*sz; + axyy=axyy- pWig->VCw[i]*(kw/kz)*(ky*ky)*(ky/kx)*shx*sy*sz; + axxy=axxy+ pWig->VCw[i]*(kw/kz)*(ky*ky)*chx*cy*sz; + } + + pax[0] = ax; + pax[1] = axx; + pax[2] = axxx; + pax[3] = axy; + pax[4] = axyy; + pax[5] = axxy; } + +static void AyHessian(struct gwigR *pWig, double *Xvec, double *pay) +{ + int i; + double x, y, z; + double kx, ky, kz, tz, kw; + double cx, sx, chx, shx, sy; + double cy, chy, shy, sz; + double gamma0, beta0; + double ay, ayx, ayxx, ayy, ayyy, ayxy; + + x = Xvec[0]; + y = Xvec[2]; + z = pWig->Zw; + + kw = 2e0*PI/(pWig->Lw); + ay = 0e0; + ayx = 0e0; + ayxx = 0e0; + ayy = 0e0; + ayyy = 0e0; + ayxy = 0e0; + + gamma0 = pWig->Po; + beta0 = sqrt(1e0 - 1e0/(gamma0*gamma0)); + pWig->Aw = (q_e/m_e/clight)/(2e0*PI) * (pWig->Lw) * (pWig->PB0); + + /* Horizontal Wiggler: note that one potentially could have: kx=0 */ + for (i = 0; i < pWig->NHharm; i++){ + pWig->HCw[i] = (pWig->HCw_raw[i])*(pWig->Aw)/(gamma0*beta0); + kx = pWig->Hkx[i]; + ky = pWig->Hky[i]; + kz = pWig->Hkz[i]; + tz = pWig->Htz[i]; + + sx = sin(kx * x); + shy = sinh(ky * y); + sz = sin(kz * z + tz); + cx = cos(kx * x); + chy = cosh(ky * y); + + + ay = ay + (pWig->HCw[i])*(kw/kz)*(kx/ky)*sx*shy*sz; + ayx = ayx+ (pWig->HCw[i])*(kx)*(kw/kz)*(kx/ky)*cx*shy*sz; + ayxx=ayxx- (pWig->HCw[i])*(kw/kz)*(kx*kx)*(kx/ky)*sx*shy*sz; + ayy = ayy+ (pWig->HCw[i])*(kw/kz)*(kx)*sx*chy*sz; + ayyy=ayyy+ (pWig->HCw[i])*(kw/kz)*(ky*kx)*sx*shy*sz; + ayxy=ayxy+ (pWig->HCw[i])*(kw/kz)*(kx*kx)*cx*chy*sz; + } + + /* Vertical Wiggler: note that one potentially could have: ky=0 */ + for (i = 0; i < pWig->NVharm; i++) { + pWig->VCw[i] = (pWig->VCw_raw[i])*(pWig->Aw)/(gamma0*beta0); + kx = pWig->Vkx[i]; + ky = pWig->Vky[i]; + kz = pWig->Vkz[i]; + tz = pWig->Vtz[i]; + + chx = cosh(kx * x); + cy = cos(ky * y); + sy = sin(ky * y); + sz = sin(kz * z + tz); + shx = sinh(kx * x); + + ay = ay + (pWig->VCw[i])*(kw/kz)*chx*cy*sz; + ayx = ayx+ (pWig->VCw[i])*(kx)*(kw/kz)*shx*cy*sz; + ayxx=ayxx+ (pWig->VCw[i])*(kx*kx)*(kw/kz)*chx*cy*sz; + ayy = ayy- (pWig->VCw[i])*(ky)*(kw/kz)*chx*sy*sz; + ayyy=ayyy- (pWig->VCw[i])*(ky*ky)*(kw/kz)*chx*cy*sz; + ayxy=ayxy- (pWig->VCw[i])*(kx*ky)*(kw/kz)*shx*sy*sz; + } + + pay[0] = ay; + pay[1] = ayx; + pay[2] = ayxx; + pay[3] = ayy; + pay[4] = ayyy; + pay[5] = ayxy; +} diff --git a/atmat/atphysics/Radiation/FDW.c b/atmat/atphysics/Radiation/FDW.c new file mode 100644 index 000000000..891bcd6b4 --- /dev/null +++ b/atmat/atphysics/Radiation/FDW.c @@ -0,0 +1,458 @@ +/*FDW.c for Accelerator Toolbox + *---------------------------------------------------------------------------- + * Modification Log: + * ----------------- + * .02 2024-05-09 J. Arenillas, ALBA, jarenillas@axt.email + * Rewriting mex function. + * Cleaning up code, using constants in gwig.h. + * New factors for diffusion matrix computation. + * Updated version of radiation kicks in diffusion matrix propagation. + * + * .01 2018-06-01 A. Mash'al, ILSF, a-mashal@ipm.ir + * Implementing the diffusion matrix for a wiggler + *---------------------------------------------------------------------------- + * mex-function to calculate integrated radiation diffusion matrix B defined in [2] + * for wiggler elements in MATLAB Accelerator Toolbox and based on [3]. + * + * References + * [1] M.Sands 'The Physics of Electron Storage Rings' + * [2] Ohmi, Kirata, Oide 'From the beam-envelope matrix to synchrotron + * radiation integrals', Phys.Rev.E Vol.49 p.751 (1994) + * [3] A. Mashal, F. D. Kashani, J. Rahighi, E. Ahmadi, Z. Marti, and O. J. Arranz. + * Study the effect of insertion devices on electron beam properties by envelope method. + * Journal of Instrumentation, May 2021. + */ + +#include "atlalib.c" +#include "atelem.c" +#include "gwigR.c" +#include +#include "mex.h" +#include "matrix.h" +#include "gwig.h" + +/* Fourth order-symplectic integrator constants */ + +#define KICK1 1.351207191959657328 +#define KICK2 -1.702414383919314656 + +/* Physical constants used in the calculations */ + +#define LAMBDABAR 3.8615926796e-13 /* Compton wavelength/2pi [m] */ +#define CU 1.323094366892892 /* 55/(24*sqrt(3)) factor */ + +#define SQR(X) ((X)*(X)) + + +static void wigglerM(struct gwigR *pWig, double* orbit_in, double L, double *M66) +{ + /* Computes the transfer matrix for a wiggler. */ + int i,j,k; + double H2[36]; + double H[6][6]; + Hessian(pWig, orbit_in ,H2); + + for (i=0;i<6;i++){ + for(j=0;j<6;j++){ + k=j+i*6; + H[i][j]=H2[k]; + } + } + + /* Initialize M66 to a 1-by-36 zero vector. */ + for(i=0;i<36;i++){ + M66[i]= 0; + } + + M66[0] =1+H[1][0]; + M66[1] =-H[0][0]; + M66[2] = H[3][0]; + M66[3] =-H[2][0]; + M66[4] = H[5][0]; + M66[5] =-H[4][0]; + + M66[6] = L*H[1][0]+H[1][1]; + M66[7] =1-L*H[0][0]-H[0][1]; + M66[8] = L*H[3][0]+H[3][1]; + M66[9] =-L*H[2][0]-H[2][1]; + M66[10] = L*H[5][0]+H[5][1]; + M66[11] =-L*H[4][0]-H[4][1]; + + M66[12] = H[1][2]; + M66[13] =-H[0][2]; + M66[14] =1+H[3][2]; + M66[15] =-H[2][2]; + M66[16] = H[5][2]; + M66[17] =-H[4][2]; + + M66[18] = L*H[1][2]+H[1][3]; + M66[19] =-L*H[0][2]-H[0][3]; + M66[20] = L*H[3][2]+H[3][3]; + M66[21] =1-L*H[2][2]-H[2][3]; + M66[22] = L*H[5][2]+H[5][3]; + M66[23] =-L*H[4][2]-H[4][3]; + + M66[24] = H[1][4]; + M66[25] =-H[0][4]; + M66[26] = H[3][4]; + M66[27] =-H[2][4]; + M66[28] =1+H[5][4]; + M66[29] =-H[4][4]; + + M66[30] = H[1][5]; + M66[31] =-H[0][5]; + M66[32] = H[3][5]; + M66[33] =-H[2][5]; + M66[34] = H[5][5]; + M66[35] =1-H[4][5]; +} + + +static void wigglerB(struct gwigR *pWig, double* orbit_in, double L, double *B66) +{ /* Calculate Ohmi's diffusion matrix of a wiggler. + Since wigglers have a straight coordinate system: irho=0 + The result is stored in a preallocated 1-dimentional array B66 + (of 36 elements) of matrix B arranged column-by-column +*/ + + double ax,ay,kx,ky,axpy,aypx; + double BB, E; + double Brho,irho3,B2; + double Bxyz[3]; + double p_norm = 1/(1+orbit_in[4]); + double p_norm2 = SQR(p_norm); + double x,px,y,py,D; + double DLDS; + int i; + + x = orbit_in[0]; + px= orbit_in[1]; + y = orbit_in[2]; + py= orbit_in[3]; + D = orbit_in[4]; + GWigAx(pWig, orbit_in, &ax, &axpy); + GWigAy(pWig, orbit_in, &ay, &aypx); + kx=px-ax; + ky=py-ay; + + /* Calculate the local magnetic field in T^2 */ + GWigB(pWig, orbit_in, Bxyz); + B2 = (Bxyz[0]*Bxyz[0]) + (Bxyz[1]*Bxyz[1]) + (Bxyz[2]*Bxyz[2]); + + /* Beam rigidity in T*m */ + E = (pWig->E0)*(1+orbit_in[4]); + Brho = E*1E9/clight; + + /* 1/rho^3 */ + irho3 = B2/(Brho*Brho)*sqrt(B2)/Brho; + + DLDS = (1+D)/(sqrt((1+D)*(1+D)-(px-ax)*(px-ax)-(py-ay)*(py-ay))); + BB = CU*r_e*LAMBDABAR*pow(pWig->Po,5)*irho3*DLDS*L; + + /* 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(i=0;i<36;i++) + B66[i] = 0; + + /* Populate B66 */ + B66[7] = BB*SQR(kx)*p_norm2; + B66[19] = BB*kx*ky*p_norm2; + B66[9] = B66[19]; + B66[21] = BB*SQR(ky)*p_norm2; + B66[10] = BB*kx*p_norm; + B66[25] = B66[10]; + B66[22] = BB*ky*p_norm; + B66[27] = B66[22]; + B66[28] = BB; +} + + +static void FindElemB(double *orbit_in, double le, double Lw, double Bmax, + int Nstep, int Nmeth, int NHharm, int NVharm, + double *By, double *Bx, double E0, double *T1, + double *T2, double *R1, double *R2, double *BDIFF) +{ /* Find Ohmi's diffusion matrix BDIFF of a wiggler + BDIFF - cumulative Ohmi's diffusion is initialized to 0 + BDIFF is preallocated 1 dimensional array to store 6-by-6 matrix + columnwise. + */ + + int m; + double MKICK[36], BKICK[36]; + + /* 4-th order symplectic integrator constants */ + int Niter = Nstep*(le/Lw); + double SL = Lw/Nstep; + double dl1 = SL*KICK1; + double dl0 = SL*KICK2; + + /* Allocate memory for thin kick matrix MKICK + and a diffusion matrix BKICK + */ + for(m=0; m < 6; m++) + { MKICK[m] = 0; + BKICK[m] = 0; + } + + double zEndPointH[2]; + double zEndPointV[2]; + double ax,ay,axpy,aypx; + double B[3]; + double E0G; + double factorvect; + struct gwigR pWig; + int flag; + + /* Transform orbit to a local coordinate system of an element + BDIFF stays zero */ + if(T1) ATaddvv(orbit_in,T1); + if(R1) ATmultmv(orbit_in,R1); + + /*Generate the wiggler*/ + zEndPointH[0] = 0; + zEndPointH[1] = le; + zEndPointV[0] = 0; + zEndPointV[1] = le; + + /* Energy is defined in the lattice in eV but GeV is used by the gwig code. */ + E0G = E0 / 1e9; + GWigInit2(&pWig,E0G,le,Lw,Bmax,Nstep,Nmeth,NHharm,NVharm,0,0,zEndPointH,zEndPointV,By,Bx,T1,T2,R1,R2); + + /* Propagate orbit_in and BDIFF through a 4-th order integrator */ + flag=1; + GWigGauge(&pWig, orbit_in, flag); + + GWigAx(&pWig, orbit_in, &ax, &axpy); + GWigAy(&pWig, orbit_in, &ay, &aypx); + GWigB(&pWig, orbit_in, B); + orbit_in[1] -= ax; + orbit_in[3] -= ay; + GWigRadiationKicks(&pWig, orbit_in, B, SL); + orbit_in[1] += ax; + orbit_in[3] += ay; + + for (m = 1; m <= Niter; m++ ) /* Loop over slices */ + { + wigglerM(&pWig, orbit_in, dl1, MKICK); + wigglerB(&pWig, orbit_in, dl1, BKICK); + ATsandwichmmt(MKICK,BKICK); + ATaddmm(BKICK,BDIFF); + GWigMap_2nd(&pWig, orbit_in, dl1); + + wigglerM(&pWig, orbit_in, dl0, MKICK); + wigglerB(&pWig, orbit_in, dl0, BKICK); + ATsandwichmmt(MKICK,BKICK); + ATaddmm(BKICK,BDIFF); + GWigMap_2nd(&pWig, orbit_in, dl0); + + wigglerM(&pWig, orbit_in, dl1, MKICK); + wigglerB(&pWig, orbit_in, dl1, BKICK); + ATsandwichmmt(MKICK,BKICK); + ATaddmm(BKICK,BDIFF); + GWigMap_2nd(&pWig, orbit_in, dl1); + + GWigAx(&pWig, orbit_in, &ax, &axpy); + GWigAy(&pWig, orbit_in, &ay, &aypx); + GWigB(&pWig, orbit_in, B); + orbit_in[1] -= ax; + orbit_in[3] -= ay; + GWigRadiationKicks(&pWig, orbit_in, B, SL); + orbit_in[1] += ax; + orbit_in[3] += ay; + } + + flag=-1; + GWigGauge(&pWig, orbit_in, flag); + + if(R2) { + ATmultmv(orbit_in,R2); + ATsandwichmmt(R2,BDIFF); + } + if(T2) ATaddvv(orbit_in,T2); +} + + +static double *wiggdiffmatrix(const atElem *ElemData, double *orb, double energy, double *bdiff) +{ + double Ltot, Lw, Bmax; + int Nstep, Nmeth; + int NHharm, NVharm; + double *R1, *R2, *T1, *T2; + double *By, *Bx; + + /* Required fields */ + Ltot = atGetOptionalDouble(ElemData, "Length",0.0); + /* If ELEMENT has a zero length, return zeros matrix end exit */ + if (Ltot == 0.0) return bdiff; + + Nstep = atGetLong(ElemData, "Nstep"); check_error(); + + if (atIsNaN(energy)) { + energy=atGetDouble(ElemData,"Energy"); check_error(); + } + Lw = atGetDouble(ElemData, "Lw"); check_error(); + Bmax = atGetDouble(ElemData, "Bmax"); check_error(); + Nmeth = atGetLong(ElemData, "Nmeth"); check_error(); + NHharm = atGetLong(ElemData, "NHharm"); check_error(); + NVharm = atGetLong(ElemData, "NVharm"); check_error(); + By = atGetDoubleArray(ElemData, "By"); check_error(); + Bx = atGetDoubleArray(ElemData, "Bx"); check_error(); + + /* Optional fields */ + R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); + R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); + T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); + T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); + + FindElemB(orb, Ltot, Lw, Bmax, Nstep, Nmeth, NHharm, NVharm, By, Bx, energy, T1, T2, R1, R2, bdiff); + return bdiff; +} + + +#if defined(MATLAB_MEX_FILE) +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ /* The calling syntax of this mex-function from MATLAB is + FindWiggRadDiffMatrix(ELEMENT, ORBIT) + ELEMENT is the element structure with field names consistent with + a multipole transverse field model. + ORBIT is a 6-by-1 vector of the closed orbit at the entrance (calculated elsewhere) +*/ + + mxDouble *orb0; + const mxArray *mxElem, *mxOrbit; + double *bdiff; + double orb[6]; + double energy; + int i, m, n; + + if (nrhs < 2) + mexErrMsgIdAndTxt("AT:WrongArg", """FDW"" needs at least 2 arguments"); + mxElem = prhs[0]; + mxOrbit = prhs[1]; + + m = mxGetM(mxOrbit); + n = mxGetN(mxOrbit); + if (!(mxIsDouble(mxOrbit) && (m==6 && n==1))) + mexErrMsgIdAndTxt("AT:WrongArg", "Orbit must be a double 6x1 vector"); + + orb0 = mxGetDoubles(mxOrbit); + /* make local copy of the input closed orbit vector */ + for (i=0;i<6;i++) orb[i] = orb0[i]; + + if (nrhs >= 3) { + const mxArray *mxEnergy = prhs[2]; + if (!(mxIsDouble(mxEnergy) && mxIsScalar(mxEnergy))) + mexErrMsgIdAndTxt("AT:WrongArg", "Energy must be a double scalar"); + energy=mxGetScalar(mxEnergy); + } + + else { + energy=mxGetNaN(); + } + /* ALLOCATE memory for the output array */ + plhs[0] = mxCreateDoubleMatrix(6,6,mxREAL); + bdiff = mxGetDoubles(plhs[0]); + for (i=0; i<36; i++) bdiff[i]=0.0; + + wiggdiffmatrix(mxElem, orb, energy, bdiff); +} +#endif + + +#if defined(PYAT) + +#define MODULE_NAME wiggdiffmatrix +#define MODULE_DESCR "Computation of the radiation diffusion matrix for a wiggler" + +static PyObject *compute_wiggdiffmatrix(PyObject *self, PyObject *args) { + PyObject *pyElem, *pyMatrix; + PyArrayObject *pyOrbit; + double *orb0, *bdiff, *retval; + double orb[6]; + double energy; + npy_intp outdims[2] = {6, 6}; + int i; + + if (!PyArg_ParseTuple(args, "OO!d", &pyElem, &PyArray_Type, &pyOrbit, &energy)) { + return NULL; + } + if (PyArray_DIM(pyOrbit,0) != 6) { + PyErr_SetString(PyExc_ValueError, "Orbit is not a (6,) array"); + return NULL; + } + if (PyArray_TYPE(pyOrbit) != NPY_DOUBLE) { + PyErr_SetString(PyExc_ValueError, "Orbit is not a double array"); + return NULL; + } + if ((PyArray_FLAGS(pyOrbit) & NPY_ARRAY_FARRAY_RO) != NPY_ARRAY_FARRAY_RO) { + PyErr_SetString(PyExc_ValueError, "Orbit is not Fortran-aligned"); + return NULL; + } + + orb0 = PyArray_DATA(pyOrbit); + /* make local copy of the input closed orbit vector */ + for (i=0;i<6;i++) orb[i] = orb0[i]; + + /* ALLOCATE memory for the output array */ + pyMatrix = PyArray_ZEROS(2, outdims, NPY_DOUBLE, 1); + bdiff = PyArray_DATA((PyArrayObject *)pyMatrix); + + retval = wiggdiffmatrix(pyElem, orb, energy, bdiff); + if (retval == NULL) { + Py_DECREF(pyMatrix); + return NULL; + } + return pyMatrix; +} + +static PyMethodDef AtMethods[] = { + {"FDW", + (PyCFunction)compute_wiggdiffmatrix, METH_VARARGS, + PyDoc_STR( + "FDW(element, orbit, energy)\n\n" + "Computes the radiation diffusion matrix B defined in [2]_\n" + "for wiggler elements\n\n" + "Args:\n" + " element: Lattice element\n" + " orbit: (6,) closed orbit at the entrance of ``element``\n" + " energy: particle energy\n\n" + "Returns:\n" + " diffmatrix: The radiation diffusion matrix of the wiggler\n\n" + "References:\n" + " **[1]** M.Sands, *The Physics of Electron Storage Rings*\n\n" + " .. [2] Ohmi, Kirata, Oide, *From the beam-envelope matrix to synchrotron\n" + " radiation integrals*, Phys.Rev.E Vol.49 p.751 (1994)\n" + )}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC MOD_INIT(MODULE_NAME) +{ + +#if PY_MAJOR_VERSION >= 3 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + STR(MODULE_NAME), /* m_name */ + PyDoc_STR(MODULE_DESCR), /* m_doc */ + -1, /* m_size */ + AtMethods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ + }; + PyObject *m = PyModule_Create(&moduledef); +#else + PyObject *m = Py_InitModule3(STR(MODULE_NAME), AtMethods, + MODULE_DESCR); +#endif + if (m == NULL) return MOD_ERROR_VAL; + import_array(); + return MOD_SUCCESS_VAL(m); +} +#endif /*PYAT*/ diff --git a/atmat/atphysics/Radiation/FDW.m b/atmat/atphysics/Radiation/FDW.m new file mode 100644 index 000000000..523b551e0 --- /dev/null +++ b/atmat/atphysics/Radiation/FDW.m @@ -0,0 +1,16 @@ +function varargout=FDW(varargin) %#ok +%FDW calculate radiation diffusion matrix of a wiggler element. +%DIFF=FDW(ELEM,ORBIT_IN,ENERGY) +% +%ELEM: AT wiggler element +%ORBIT_IN: input closed orbit +%ENERGY: ring energy [GeV] +% +%DIFF=FDW(ELEM,ORBIT_IN) +% takes energy from the 'Energy' field of the element +% +% for use in Ohmi's beam envelope formalism [1] +% See also OHMIENVELOPE +% [1] K.Ohmi et al. Phys.Rev.E. Vol.49. (1994) +error('at:missingMex','missing MEX file.'); +end \ No newline at end of file diff --git a/atmat/atphysics/Radiation/ohmienvelope.m b/atmat/atphysics/Radiation/ohmienvelope.m index dc54bcc29..916a29bad 100644 --- a/atmat/atphysics/Radiation/ohmienvelope.m +++ b/atmat/atphysics/Radiation/ohmienvelope.m @@ -24,6 +24,11 @@ NumElements = length(ring); if nargin<3, refpts=1; end +% Erase wigglers from the radiative element list. +% Diffusion matrix to be computed with separate FDW function. +Wig=atgetcells(ring,'Bmax'); +radindex = radindex & ~Wig; + [mring, ms, orbit] = findm66(ring,1:NumElements+1); mt=squeeze(num2cell(ms,[1 2])); orb=num2cell(orbit,1)'; @@ -34,6 +39,8 @@ % calculate Radiation-Diffusion matrix B for elements with radiation B(radindex)=cellfun(@findmpoleraddiffmatrix,... ring(radindex),orb(radindex),'UniformOutput',false); +B(Wig)=cellfun(@FDW,... + ring(Wig),orb(Wig),'UniformOutput',false); % Calculate cumulative Radiation-Diffusion matrix for the ring BCUM = zeros(6,6); @@ -59,7 +66,7 @@ R = sylvester(AA,BB,CC); % Envelope matrix at the ring entrance rmsdp = sqrt(R(5,5)); % R.M.S. energy spread -rmsbl = sqrt(R(6,6)); % R.M.S. bunch lenght +rmsbl = sqrt(R(6,6)); % R.M.S. bunch length [rr,tt,ss]=cellfun(@propag,mt(refpts),Batbeg(refpts),'UniformOutput',false); envelope=struct('R',rr,'Sigma',ss,'Tilt',tt); diff --git a/docs/common/sa_passmethods.md b/docs/common/sa_passmethods.md index d29d7886f..b1561f293 100644 --- a/docs/common/sa_passmethods.md +++ b/docs/common/sa_passmethods.md @@ -130,3 +130,44 @@ ExitAngle : Angle of the exit pole face {math}`\varepsilon_2` with respect to the plane perpendicular to the output trajectory. Use 0 for a sector magnet, {math}`\theta/2` for a rectangular magnet. + +(GWigSymplecticPass)= +## `GWigSymplecticPass` +2 {sup}`nd` and 4{sup}`th` order Forest-Wu-Robin integrator for wigglers without radiation. + +Length +: Length {math}`L` of the element. + +MaxOrder, NumIntSteps +: see [StrMPoleSymplectic4Pass](#StrMPoleSymplectic4Pass). + +Period +: Wiggler period {math}`L_w`. + +Peak magnetic field, B_0 +: Maximum magnetic field {math}`B_0` of the wiggler. + +Nmeth +: Indicates the integration method: 2nd or 4th order integrator. + +NHharm +: Number of horizontal harmonics of the wiggler. + +NVharm +: Number of vertical harmonics of the wiggler. + +By +: 6 x NHharm array containing the following quantities. row 1: Horizontal +harmonic counter; row 2: relative amplitudes of wiggler harmonics; row 3: {math}`k_x*L_w/2\pi`; +row 4: {math}`k_y*L_w/2\pi`; row 5: {math}`k_z*L_w/2\pi`; row 6: {math}`\theta_n`, the relative +phase of the n{sup}`th` wiggler harmonic. {math}`k_x`, {math}`k_y` and {math}`k_z` are defined in [^Wu]. + +Bx +: 6 x NVharm array containing the following quantities. row 1: Vertical +harmonic counter; row 2: relative amplitudes of wiggler harmonics; row 3: {math}`k_x*L_w/2\pi`; +row 4: {math}`k_y*L_w/2\pi`; row 5: {math}`k_z*L_w/2\pi`; row 6: {math}`\theta_n`, the relative +phase of the n{sup}`th` wiggler harmonic. {math}`k_x`, {math}`k_y` and {math}`k_z` are defined in [^Wu]. + + +[^Wu]: Y. K. Wu, E. Forest, and D. S. Robin, _Explicit symplectic integrator for s-dependent static magnetic +field_, Phys. Rev. E, 68:046502, Oct 2003. \ No newline at end of file