source: MML/trunk/at/atphysics/findmpoleraddiffmatrix.c @ 5

Last change on this file since 5 was 4, checked in by zhangj, 11 years ago

Initial import--MML version from SOLEIL@2013

File size: 16.9 KB
Line 
1/* findmpoleraddifmatrix.c
2
3   mex-function to calculate radiation diffusion matrix B defined in [2]
4   for multipole elements in MATLAB Accelerator Toolbox
5   A.Terebilo 8/14/00
6
7   References
8   [1] M.Sands 'The Physics of Electron Storage Rings
9   [2] Ohmi, Kirata, Oide 'From the beam-envelope matrix to synchrotron
10   radiation integrals', Phys.Rev.E  Vol.49 p.751 (1994)
11*/
12
13#include "mex.h"
14#include "matrix.h"
15#include "atlalib.c"
16#include <math.h>
17
18
19/* Fourth order-symplectic integrator constants */
20
21#define DRIFT1    0.6756035959798286638
22#define DRIFT2   -0.1756035959798286639
23#define KICK1     1.351207191959657328
24#define KICK2    -1.702414383919314656
25
26/* Physical constants used in the calculations */
27
28#define TWOPI           6.28318530717959
29#define CGAMMA  8.846056192e-05                         /* [m]/[GeV^3] Ref[1] (4.1)      */
30#define M0C2      5.10999060e5                          /* Electron rest mass [eV]       */
31#define LAMBDABAR 3.86159323e-13                        /* Compton wavelength/2pi [m]    */
32#define CER             2.81794092e-15                  /* Classical electron radius [m] */
33#define CU        1.323094366892892                     /* 55/(24*sqrt(3)) factor        */
34
35
36
37#define SQR(X) ((X)*(X))
38
39
40
41
42void edgefringeB(double* r, double *B, double inv_rho, double edge_angle, double fint, double gap)
43{   double fx, fy, psi;
44    int m;
45   
46   
47    if(inv_rho<=0) return; /* Skip if not a bending element*/
48   
49    fx = inv_rho*tan(edge_angle);
50    psi = inv_rho*gap*fint*(1+pow(sin(edge_angle),2))/cos(edge_angle);
51    if(fint >0 && gap >0)
52        fy = inv_rho*tan(edge_angle-psi/(1+r[4]));
53    else
54        fy = fx;
55       
56/*  Propagate B */
57
58    for(m=0;m<6;m++)
59    {   B[1+6*m] += fx*B[6*m];
60                B[3+6*m] -= fy*B[2+6*m];
61    }
62    if(fint >0 && gap >0)
63        for(m=0;m<6;m++)   
64            B[3+6*m] -= B[4+6*m]*r[2]*
65                (inv_rho*inv_rho+fy*fy)*psi/pow((1+r[4]),2)/inv_rho;
66       
67
68    for(m=0;m<6;m++)
69        {       B[m+6*1] += fx*B[m+6*0];
70                B[m+6*3] -= fy*B[m+6*2];
71    }
72    if(fint >0 && gap >0)
73        for(m=0;m<6;m++)
74            B[m+6*3] -= B[m+6*4]*r[2]*
75                (inv_rho*inv_rho+fy*fy)*psi/pow((1+r[4]),2)/inv_rho;
76
77    /* Propagate particle */
78        r[1]+=r[0]*fx;
79        r[3]-=r[2]*fy;
80
81}
82
83
84double B2perp(double bx, double by, double irho, 
85                            double x, double xpr, double y, double ypr)
86/* Calculates sqr(|e x B|) , where e is a unit vector in the direction of velocity   */
87   
88{       double v_norm2;
89        v_norm2 = 1/(SQR(1+x*irho)+ SQR(xpr) + SQR(ypr));
90
91        /* components of the  velocity vector
92           double ex, ey, ez;
93           ex = xpr;
94           ey = ypr;
95           ez = (1+x*irho);
96        */
97       
98        return((SQR(by*(1+x*irho)) + SQR(bx*(1+x*irho)) + SQR(bx*ypr - by*xpr) )*v_norm2) ;
99
100
101
102} 
103 
104
105void thinkickrad(double* r, double* A, double* B, double L, double irho, double E0, int max_order)
106
107/*****************************************************************************
108Calculate and apply a multipole kick to a phase space vector *r in a multipole element.
109The reference coordinate system  may have the curvature given by the inverse
110(design) radius irho. irho = 0 for straight elements
111
112IMPORTANT !!!
113The design magnetic field Byo that provides this curvature By0 = irho * E0 /(c*e)
114MUST NOT be included in the dipole term PolynomB(1)(MATLAB notation)(B[0] C notation)
115of the By field expansion
116HOWEVER!!! to calculate the effect of classical radiation the full field must be
117used in the square of the |v x B|.
118When calling B2perp(Bx, By, ...), use the By = ReSum + irho, where ReSum is the
119normalized vertical field - sum of the polynomial terms in PolynomB.
120
121The kick is given by
122
123           e L      L delta      L x
124theta  = - --- B  + -------  -  -----  ,
125     x     p    y     rho           2
126            0                    rho
127
128         e L
129theta  = --- B
130     y    p   x
131           0
132
133Note: in the US convention the field is written as:
134
135                        max_order+1
136                          ----
137                          \                       n-1
138           (B + iB  ) = B rho  >   (ia  + b ) (x + iy)
139        y    x           /       n    n
140                              ----
141                          n=1
142
143Use different index notation
144
145                         max_order
146                           ----
147                           \                       n
148           (B + iB  )/ B rho  =  >   (iA  + B ) (x + iy)
149        y    x             /       n    n
150                                ----
151                           n=0
152
153A,B: i=0 ... i=max_order
154[0] - dipole, [1] - quadrupole, [2] - sextupole ...
155units for A,B[i] = 1/[m]^(i+1)
156Coeficients are stored in the PolynomA, PolynomB field of the element
157structure in MATLAB
158
159
160******************************************************************************/
161{  int i;
162        double ImSum = A[max_order];
163        double ReSum = B[max_order];   
164        double x ,xpr, y, ypr, p_norm,dp_0, B2P;
165        double ReSumTemp;
166        double CRAD = CGAMMA*E0*E0*E0/(TWOPI*1e27);
167       
168        /* recursively calculate the local transvrese magnetic field
169           Bx = ReSum, By = ImSum
170        */
171        for(i=max_order-1;i>=0;i--)
172                {       ReSumTemp = ReSum*r[0] - ImSum*r[2] + B[i];
173                        ImSum = ImSum*r[0] +  ReSum*r[2] + A[i];
174                        ReSum = ReSumTemp;
175                }
176       
177
178        /* calculate angles from momentas */   
179        p_norm = 1/(1+r[4]);
180        x   = r[0];
181        xpr = r[1]*p_norm;
182        y   = r[2];
183        ypr = r[3]*p_norm;
184
185
186        B2P = B2perp(ImSum, ReSum +irho, irho, x , xpr, y ,ypr);
187       
188        dp_0 = r[4]; /* save a copy of the initial value of dp/p */
189
190        r[4] = r[4] - CRAD*SQR(1+r[4])*B2P*(1 + x*irho + (SQR(xpr)+SQR(ypr))/2 )*L;
191
192        /* recalculate momentums from angles after losing energy to radiation   */
193        p_norm = 1/(1+r[4]);
194        r[1] = xpr/p_norm;
195        r[3] = ypr/p_norm;
196
197       
198        r[1] -=  L*(ReSum-(dp_0-r[0]*irho)*irho);
199        r[3] +=  L*ImSum;
200        r[5] +=  L*irho*r[0]; /* pathlength */
201
202
203}
204
205void thinkickM(double* orbit_in, double* A, double* B, double L, 
206                                                        double irho, int max_order, double *M66)
207/* Calculate the symplectic (no radiation) transfer matrix of a
208   thin multipole kick near the entrance point orbit_in
209   For elements with straight coordinate system irho = 0
210   For curved elements the B polynomial (PolynomB in MATLAB)
211   MUST NOT include the guide field  By0 = irho * E0 /(c*e)
212
213   M is a (*double) pointer to a preallocated 1-dimentional array
214   of 36 elements of matrix M arranged column-by-column
215*/
216{  int m,n;
217   
218        double ReSumNTemp;
219   double ImSumN = max_order*A[max_order];
220   double ReSumN = max_order*B[max_order];     
221
222   /* Recursively calculate the derivatives
223           ReSumN = (irho/B0)*Re(d(By + iBx)/dx)
224           ImSumN = (irho/B0)*Im(d(By + iBx)/dy)
225    */
226        for(n=max_order-1;n>0;n--)
227                {       ReSumNTemp = (ReSumN*orbit_in[0] - ImSumN*orbit_in[2]) + n*B[n];
228                        ImSumN = ImSumN*orbit_in[0] +  ReSumN*orbit_in[2] + n*A[n];
229                        ReSumN = ReSumNTemp;
230                }
231
232        /* Initialize M66 to a 6-by-6 identity matrix */
233        for(m=0;m<36;m++)
234                M66[m]= 0;
235        /* Set diagonal elements to 1 */
236        for(m=0;m<6;m++)
237                M66[m*7] = 1;
238       
239        /* The relationship between indexes when a 6-by-6 matrix is
240           represented in MATLAB as one-dimentional array containing
241           36 elements arranged column-by-column is
242           [i][j] <---> [i+6*j]
243        */
244
245        M66[1]   = -L*ReSumN;                           /* [1][0] */
246        M66[13]  =  L*ImSumN;                           /* [1][2] */
247        M66[3]   =  L*ImSumN;                           /* [3][0] */
248        M66[15]  =  L*ReSumN;                           /* [3][2] */
249        M66[25]  =  L*irho;                                     /* [1][4] */
250        M66[1]  += -L*irho*irho;                        /* [1][0] */
251        M66[5]   =  L*irho;                                     /* [5][0] */
252
253}
254
255
256
257void thinkickB(double* orbit_in, double* A, double* B, double L, 
258                                                        double irho, int max_order, double E0, double *B66)
259
260/* Calculate Ohmi's diffusion matrix of a thin multipole  element
261   For elements with straight coordinate system irho = 0
262   For curved elements the B polynomial (PolynomB in MATLAB)
263   MUST NOT include the guide field  By0 = irho * E0 /(c*e)
264   The result is stored in a preallocated 1-dimentional array B66
265   of 36 elements of matrix B arranged column-by-column
266
267  Ohmi's paper: Eqn.(48).
268*/
269
270{       double BB,B2P,B3P;
271        int i;
272        double p_norm = 1/(1+orbit_in[4]);
273        double p_norm2 = SQR(p_norm);
274        double ImSum = A[max_order];
275        double ReSum = B[max_order];   
276        double ReSumTemp;
277       
278        /* recursively calculate the local transvrese magnetic field
279           ReSum = irho*By/B0
280           ImSum = irho*Bx/B0
281        */
282
283        for(i=max_order-1;i>=0;i--)
284                {       ReSumTemp = ReSum*orbit_in[0] - ImSum*orbit_in[2] + B[i];
285                        ImSum = ImSum*orbit_in[0] +  ReSum*orbit_in[2] + A[i];
286                        ReSum = ReSumTemp;
287                }
288       
289       
290        /* calculate |B x n|^3 - the third power of the B field component
291           orthogonal to the normalized velocity vector n
292    */
293        B2P = B2perp(ImSum, ReSum +irho, irho, orbit_in[0] , orbit_in[1]*p_norm , 
294                                                                orbit_in[2] , orbit_in[3]*p_norm );
295        B3P = B2P*sqrt(B2P);
296
297        BB = CU * CER * LAMBDABAR *  pow(E0/M0C2,5) * L * B3P * SQR(SQR(1+orbit_in[4]))*
298                                (1+orbit_in[0]*irho + (SQR(orbit_in[1])+SQR(orbit_in[3]))*p_norm2/2);
299
300       
301        /* When a 6-by-6 matrix is represented in MATLAB as one-dimentional
302           array containing 36 elements arranged column-by-column,
303           the relationship between indexes  is
304           [i][j] <---> [i+6*j]
305
306        */
307       
308        /* initialize B66 to 0 */
309        for(i=0;i<36;i++)
310                B66[i] = 0;
311       
312        /* Populate B66 */
313        B66[7]      = BB*SQR(orbit_in[1])*p_norm2;
314        B66[19]     = BB*orbit_in[1]*orbit_in[3]*p_norm2;
315        B66[9]      = B66[19];
316        B66[21]     = BB*SQR(orbit_in[3])*p_norm2;
317        B66[10]     = BB*orbit_in[1]*p_norm;
318        B66[25]     = B66[10];
319        B66[22]     = BB*orbit_in[3]*p_norm;
320        B66[27]     = B66[22];
321        B66[28]     = BB;
322}
323
324
325
326
327
328void drift_propagateB(double *orb_in, double L,  double *B)
329{       /* Propagate cumulative Ohmi's diffusion matrix B through a drift
330           B is a (*double) pointer to 1-dimentional array
331           containing 36 elements of matrix elements arranged column-by-column
332           as in MATLAB representation
333
334           The relationship between indexes when a 6-by-6 matrix is
335           represented in MATLAB as one-dimentional array containing
336           36 elements arranged column-by-column is
337           [i][j] <---> [i+6*j]
338        */
339               
340        int m;
341               
342        double *DRIFTMAT = (double*)mxCalloc(36,sizeof(double));
343        for(m=0;m<36;m++)
344                DRIFTMAT[m] = 0;
345        /* Set diagonal elements to 1   */
346        for(m=0;m<6;m++)
347                DRIFTMAT[m*7] = 1;
348 
349        /*6*6 transfer matrix in a drift */
350        DRIFTMAT[6]  =  L/(1+orb_in[4]);  /* [0][1] */
351        DRIFTMAT[20] =  DRIFTMAT[6];  /*[2][3] */
352        DRIFTMAT[24] = -L*orb_in[1]/SQR(1+orb_in[4]); /*[0][4] */
353        DRIFTMAT[26] = -L*orb_in[3]/SQR(1+orb_in[4]); /* [2][4] */
354        DRIFTMAT[11] =  L*orb_in[1]/SQR(1+orb_in[4]); /* [5][1]*/
355        DRIFTMAT[23] =  L*orb_in[3]/SQR(1+orb_in[4]);/* [5][3]*/       
356        DRIFTMAT[29] = -L*(SQR(orb_in[1])+SQR(orb_in[3]))/((1+orb_in[4])*SQR(1+orb_in[4])); /* [5][4]*/
357
358        ATsandwichmmt(DRIFTMAT,B); 
359        mxFree(DRIFTMAT);
360       
361}
362
363
364
365
366
367void FindElemB(double *orbit_in, double le, double irho, double *A, double *B,
368                                        double *pt1, double* pt2,double *PR1, double *PR2,
369                                        double entrance_angle,  double exit_angle,
370                    double fringe_int1, double fringe_int2, double full_gap,
371                                        int max_order, int num_int_steps,
372                                        double E0, double *BDIFF)
373
374{       /* Find Ohmi's diffusion matrix BDIFF of a thick multipole
375           BDIFF - cumulative Ohmi's diffusion is initialized to 0
376           BDIFF is preallocated 1 dimensional array to store 6-by-6 matrix
377           columnwise
378       
379       Ref[2]  Eqn.(31) 
380        */
381       
382        int m; 
383        double  *MKICK, *BKICK;
384
385        /* 4-th order symplectic integrator constants */
386        double SL, L1, L2, K1, K2;
387        SL = le/num_int_steps;
388        L1 = SL*DRIFT1;
389        L2 = SL*DRIFT2;
390        K1 = SL*KICK1;
391        K2 = SL*KICK2;
392       
393       
394        /* Allocate memory for thin kick matrix MKICK
395           and a diffusion matrix BKICK
396        */
397        MKICK = (double*)mxCalloc(36,sizeof(double));
398        BKICK = (double*)mxCalloc(36,sizeof(double));
399        for(m=0; m < 6; m++)
400                {       MKICK[m] = 0;
401                        BKICK[m] = 0;
402                }
403       
404        /* Transform orbit to a local coordinate system of an element
405       BDIFF stays zero */
406    if(pt1)
407        ATaddvv(orbit_in,pt1); 
408    if(PR1)
409        ATmultmv(orbit_in,PR1); 
410
411
412   
413    /* Propagate orbit_in and BDIFF through the entrance edge */
414    if(entrance_angle!=0 && fringe_int1!=0 && full_gap!=0) 
415      edgefringeB(orbit_in, BDIFF, irho, entrance_angle, fringe_int1, full_gap);
416
417        /* Propagate orbit_in and BDIFF through a 4-th order integrator */
418
419        for(m=0; m < num_int_steps; m++) /* Loop over slices    */                     
420                {               drift_propagateB(orbit_in,L1, BDIFF);
421                                ATdrift6(orbit_in,L1);  /* transfer of orbit_in in drift*/
422                               
423                                thinkickM(orbit_in, A,B, K1, irho, max_order, MKICK);
424                                thinkickB(orbit_in, A,B, K1, irho, max_order, E0, BKICK);
425                                ATsandwichmmt(MKICK,BDIFF); /*BDIFF= MKICK*BDIFF*MKICK'*/
426                                ATaddmm(BKICK,BDIFF); /*BDIFF = BDIFF+BKICK; to get B bar, Ref[2] eqn.(31)*/
427                                thinkickrad(orbit_in, A, B, K1, irho, E0, max_order); /*transfer of orbit_in in kicker*/
428               
429                                drift_propagateB(orbit_in,L2, BDIFF);
430                                ATdrift6(orbit_in,L2);
431                               
432                                thinkickM(orbit_in, A,B, K2, irho, max_order, MKICK);
433                                thinkickB(orbit_in, A,B, K2, irho, max_order, E0, BKICK);
434                                ATsandwichmmt(MKICK,BDIFF);
435                                ATaddmm(BKICK,BDIFF);
436                                thinkickrad(orbit_in, A, B, K2, irho, E0, max_order);
437       
438                                drift_propagateB(orbit_in,L2, BDIFF);
439                                ATdrift6(orbit_in,L2);
440                               
441                                thinkickM(orbit_in, A,B, K1, irho, max_order, MKICK);
442                                thinkickB(orbit_in, A,B, K1, irho, max_order, E0, BKICK);
443                                ATsandwichmmt(MKICK,BDIFF);
444                                ATaddmm(BKICK,BDIFF);
445                                thinkickrad(orbit_in, A, B,  K1, irho, E0, max_order);
446
447                                drift_propagateB(orbit_in,L1, BDIFF);
448                                ATdrift6(orbit_in,L1);
449                } 
450        if(exit_angle!=0 && fringe_int1!=0 && full_gap!=0) 
451          edgefringeB(orbit_in, BDIFF, irho, exit_angle, fringe_int2, full_gap); 
452                               
453
454               
455        if(PR2)
456            ATmultmv(orbit_in,PR2);     
457        if(pt2)
458            ATaddvv(orbit_in,pt2);     
459       
460       
461                mxFree(MKICK);
462                mxFree(BKICK);
463}
464
465
466void mexFunction(       int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
467/* The calling syntax of this mex-function from MATLAB is
468   FindMPoleRadDiffMatrix(ELEMENT, ORBIT)
469   ELEMENT is the element structure with field names consistent with
470           a multipole transverse field model.
471   ORBIT is a 6-by-1 vector of the closed orbit at the entrance (calculated elsewhere)
472*/
473{       int m,n;
474        double le, ba, irho, fringe_int1,  fringe_int2, full_gap, *A, *B; 
475
476        double E0;              /* Design energy [eV] to be obtained from 'Energy' field of ELEMENT*/
477        int max_order, num_int_steps;
478        double entrance_angle, exit_angle ;
479        double *BDIFF;
480        mxArray  *mxtemp;
481
482        double *orb, *orb0;
483        double *pt1, *pt2, *PR1, *PR2;
484
485
486        m = mxGetM(prhs[1]);
487        n = mxGetN(prhs[1]);
488        if(!(m==6 && n==1))
489                mexErrMsgTxt("Second argument must be a 6-by-1 column vector");
490   
491        /* ALLOCATE memory for the output array */
492        plhs[0] = mxCreateDoubleMatrix(6,6,mxREAL);
493        BDIFF = mxGetPr(plhs[0]);
494
495
496        /* If the ELEMENT sructure does not have fields PolynomA and PolynomB
497           return zero matrix and  exit
498        */
499        if(mxGetField(prhs[0],0,"PolynomA") == NULL ||  mxGetField(prhs[0],0,"PolynomB") == NULL)
500                return;
501
502
503
504        orb0 = mxGetPr(prhs[1]);
505        /* make local copy of the input closed orbit vector */
506        orb = (double*)mxCalloc(6,sizeof(double));
507        for(m=0;m<6;m++)
508                orb[m] = orb0[m];
509   
510        /* Retrieve element information */
511       
512        le = mxGetScalar(mxGetField(prhs[0],0,"Length"));
513       
514        /* If ELEMENT has a zero length, return zeros matrix end exit */
515        if(le == 0)
516                return;
517       
518        A = mxGetPr(mxGetField(prhs[0],0,"PolynomA"));
519        B = mxGetPr(mxGetField(prhs[0],0,"PolynomB"));
520
521       
522    mxtemp = mxGetField(prhs[0],0,"Energy");
523    if(mxtemp != NULL)
524        E0 = mxGetScalar(mxtemp);
525    else
526                mexErrMsgTxt("Required field 'Energy'  not found in the ELEMENT structure");
527
528               
529        mxtemp = mxGetField(prhs[0],0,"NumIntSteps");
530   if(mxtemp != NULL)
531                num_int_steps = (int)mxGetScalar(mxtemp);
532        else
533                mexErrMsgTxt("Field 'NumIntSteps' not found in the ELEMENT structure");
534
535    mxtemp = mxGetField(prhs[0],0,"MaxOrder");
536   if(mxtemp != NULL)
537                max_order = (int)mxGetScalar(mxtemp);
538        else
539                mexErrMsgTxt("Field 'MaxOrder' not found in the ELEMENT structure");
540
541
542        mxtemp = mxGetField(prhs[0],0,"BendingAngle");
543   if(mxtemp != NULL)
544                {       ba = mxGetScalar(mxtemp);
545                        irho = ba/le;
546                }
547        else
548                {       ba = 0;
549                        irho = 0;
550                }
551               
552        mxtemp = mxGetField(prhs[0],0,"EntranceAngle");
553        if(mxtemp != NULL)
554                entrance_angle = mxGetScalar(mxtemp);
555        else
556                        entrance_angle =0;
557
558        mxtemp = mxGetField(prhs[0],0,"ExitAngle");
559        if(mxtemp != NULL)
560                exit_angle = mxGetScalar(mxtemp);
561        else
562                        exit_angle =0;
563
564        /* Optional felds */
565    mxtemp = mxGetField(prhs[0],0,"T1");
566    if(mxtemp)
567        pt1 = mxGetPr(mxtemp);
568    else
569        pt1 = NULL;
570   
571    mxtemp = mxGetField(prhs[0],0,"T2");
572    if(mxtemp)
573        pt2 = mxGetPr(mxtemp);
574    else
575        pt2 = NULL;
576   
577    mxtemp = mxGetField(prhs[0],0,"R1");
578    if(mxtemp)
579        PR1 = mxGetPr(mxtemp);
580    else
581        PR1 = NULL;
582   
583    mxtemp = mxGetField(prhs[0],0,"R2");
584    if(mxtemp)
585        PR2 = mxGetPr(mxtemp);
586    else
587        PR2 = NULL;
588   
589    mxtemp = mxGetField(prhs[0],0,"FringeInt1");
590    if(mxtemp)
591        fringe_int1 = mxGetScalar(mxtemp);
592    else
593        fringe_int1 = 0;
594   
595    mxtemp = mxGetField(prhs[0],0,"FringeInt2");
596    if(mxtemp)
597        fringe_int2 = mxGetScalar(mxtemp);
598    else
599        fringe_int2 = 0;
600       
601    mxtemp = mxGetField(prhs[0],0,"FullGap");
602    if(mxtemp)
603        full_gap = mxGetScalar(mxtemp);
604    else
605        full_gap = 0;
606   
607   
608   
609
610        FindElemB(orb, le, irho, A, B, 
611                                        pt1, pt2, PR1, PR2,
612                                        entrance_angle,         exit_angle,
613                    fringe_int1, fringe_int2, full_gap,
614                                        max_order, num_int_steps, E0, BDIFF);
615}
616
617
Note: See TracBrowser for help on using the repository browser.