diff --git a/atintegrators/IdTablePass.c b/atintegrators/IdTablePass.c index 1739e85c9..fae1cfb98 100644 --- a/atintegrators/IdTablePass.c +++ b/atintegrators/IdTablePass.c @@ -3,11 +3,15 @@ * Created: 13/11/08 * Zeus Marti * + * * Based in the matlab routine: * WigTablePass.m - The tracking table is described in * P. Elleaume, "A new approach to the electron beam dynamics in undulators * and wigglers", EPAC92. * + * History: + * 2023nov13 change in variable names according to Pull Request + * https://github.com/atcollab/at/pull/683 */ #include "atelem.c" @@ -16,8 +20,8 @@ struct elem { double Length; - double *xkick; - double *ykick; + double *xkick2; + double *ykick2; double *x_map; double *y_map; int nx_map; @@ -38,17 +42,18 @@ int GLOBAL_nx_map,GLOBAL_ny_map; static double get_kick(double *r6, double *ktable) { double f; + /*2023nov13 blanco-garcia. Warning: Variables not updated*/ /*cubic interpolation*/ /*splin2(GLOBAL_y_map,GLOBAL_x_map,GLOBAL_xkick,GLOBAL_xkick2,GLOBAL_n,GLOBAL_nx,y,x,&f);*/ - /*biliniar interpolation*/ + /*bilinear interpolation*/ /* Transpose coordinates because the kick-table is FORTRAN-ordered */ linint(GLOBAL_y_map, GLOBAL_x_map, ktable, GLOBAL_ny_map, GLOBAL_nx_map, r6[2], r6[0], &f); return f; } void IdKickMapModelPass(double *r, double le, double *xkick1, double *ykick1, - double *xkick, double *ykick, double *x_map, double *y_map,int nx_map,int ny_map, int Nslice, + double *xkick2, double *ykick2, double *x_map, double *y_map,int nx_map,int ny_map, int Nslice, double *T1, double *T2, double *R1, double *R2, int num_particles) { double *r6, deltaxp, deltayp, limitsptr[4]; @@ -80,8 +85,8 @@ void IdKickMapModelPass(double *r, double le, double *xkick1, double *ykick1, ATdrift6(r6,L1); if (!atIsNaN(r6[0])&&!atIsNaN(r6[2])) { /*The kick from IDs varies quadratically, not linearly, with energy. */ - deltaxp = get_kick(r6, xkick)/(1.0+r6[4]); - deltayp = get_kick(r6, ykick)/(1.0+r6[4]); + deltaxp = get_kick(r6, xkick2)/(1.0+r6[4]); + deltayp = get_kick(r6, ykick2)/(1.0+r6[4]); if (xkick1) deltaxp += get_kick(r6, xkick1); if (ykick1) deltayp += get_kick(r6, ykick1); r6[1] = r6[1] + deltaxp / Nslice; @@ -96,22 +101,23 @@ void IdKickMapModelPass(double *r, double le, double *xkick1, double *ykick1, } } -#if defined(MATLAB_MEX_FILE) || defined(PYAT) +#if defined(PYAT) ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, double *r_in, int num_particles, struct parameters *Param) { if (!Elem) { int Nslice, ny_map,nx_map; - double Length, *xkick, *ykick, *x_map, *y_map; + double Length, *xkick2, *ykick2, *x_map, *y_map; double *xkick1, *ykick1; double *R1, *R2, *T1, *T2; Length=atGetDouble(ElemData,"Length"); check_error(); - xkick=atGetDoubleArraySz(ElemData,"xkick", &ny_map, &nx_map); check_error(); - /* the third input of atGetDoubleArraySz is a pointer for the + /* read kick tables. + * The third input of atGetDoubleArraySz is a pointer for the * number of rows in the 2-D array, the fourth input is a pointer * for the number of columns */ - ykick=atGetDoubleArray(ElemData,"ykick"); check_error(); + xkick2=atGetDoubleArraySz(ElemData,"xkick2", &ny_map, &nx_map); check_error(); + ykick2=atGetDoubleArray(ElemData,"ykick2"); check_error(); x_map=atGetDoubleArray(ElemData,"xtable"); check_error(); y_map=atGetDoubleArray(ElemData,"ytable"); check_error(); Nslice=atGetLong(ElemData,"Nslice"); check_error(); @@ -124,8 +130,8 @@ ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); Elem->Length=Length; - Elem->xkick=xkick; - Elem->ykick=ykick; + Elem->xkick2=xkick2; + Elem->ykick2=ykick2; Elem->x_map=x_map; Elem->y_map=y_map; Elem->nx_map=nx_map; @@ -139,15 +145,91 @@ ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, Elem->T2=T2; } IdKickMapModelPass(r_in, Elem->Length, Elem->xkick1, Elem->ykick1, - Elem->xkick, Elem->ykick, Elem->x_map, Elem->y_map, Elem->nx_map, Elem->ny_map,Elem->Nslice, + Elem->xkick2, Elem->ykick2, Elem->x_map, Elem->y_map, Elem->nx_map, Elem->ny_map,Elem->Nslice, Elem->T1, Elem->T2, Elem->R1, Elem->R2, num_particles); return Elem; } MODULE_DEF(IdTablePass) /* Dummy module initialisation */ -#endif /*defined(MATLAB_MEX_FILE) || defined(PYAT)*/ +#endif /*defined(PYAT)*/ #ifdef MATLAB_MEX_FILE +ExportMode struct elem *trackFunction(const atElem *ElemData,struct elem *Elem, + double *r_in, int num_particles, struct parameters *Param) +{ + if (!Elem) { + int Nslice, ny_map,nx_map; + double Length, *xkick2, *ykick2, *x_map, *y_map; + double *xkick1, *ykick1; + double *R1, *R2, *T1, *T2; + mxArray *fieldtest; + Length=atGetDouble(ElemData,"Length"); check_error(); + + /* read kick tables. + * The third input of atGetDoubleArraySz is a pointer for the + * number of rows in the 2-D array, the fourth input is a pointer + * for the number of columns + */ + //xkick2=atGetDoubleArraySz(ElemData,"xkick2", &ny_map, &nx_map); check_error(); + //ykick2=atGetDoubleArray(ElemData,"ykick2"); check_error(); + + /* Backwards compatibility check. Renaming xkick to xkick2 and ykick to ykick2 + * https://github.com/atcollab/at/issues/682 + */ + fieldtest = get_field(ElemData,"xkick2"); + if (!fieldtest){ + fieldtest = get_field(ElemData,"xkick"); + if(!fieldtest) mexErrMsgIdAndTxt("AT:PassError","horizontal kick map not found.\n"); + else{ + mexWarnMsgIdAndTxt("AT:PassWarning", "xkick in Insertion Device is deprecated;" + " please, save .mat file again.\n"); + xkick2=atGetDoubleArraySz(ElemData,"xkick", &ny_map, &nx_map); check_error(); + } + }else xkick2=atGetDoubleArraySz(ElemData,"xkick2", &ny_map, &nx_map); check_error(); + fieldtest = get_field(ElemData,"ykick2"); + if (!fieldtest){ + fieldtest = get_field(ElemData,"ykick"); + if(!fieldtest) mexErrMsgIdAndTxt("AT:PassError","vertical kick map not found.\n"); + else{ + mexWarnMsgIdAndTxt("AT:PassWarning", "ykick in Insertion Device is deprecated;" + " please, save .mat file again.\n"); + ykick2=atGetDoubleArraySz(ElemData,"ykick", &ny_map, &nx_map); check_error(); + } + }else ykick2=atGetDoubleArraySz(ElemData,"ykick2", &ny_map, &nx_map); check_error(); + x_map=atGetDoubleArray(ElemData,"xtable"); check_error(); + y_map=atGetDoubleArray(ElemData,"ytable"); check_error(); + Nslice=atGetLong(ElemData,"Nslice"); check_error(); + /*optional fields*/ + xkick1=atGetOptionalDoubleArray(ElemData,"xkick1"); check_error(); + ykick1=atGetOptionalDoubleArray(ElemData,"ykick1"); 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(); + Elem = (struct elem*)atMalloc(sizeof(struct elem)); + Elem->Length=Length; + Elem->xkick2=xkick2; + Elem->ykick2=ykick2; + Elem->x_map=x_map; + Elem->y_map=y_map; + Elem->nx_map=nx_map; + Elem->ny_map=ny_map; + Elem->Nslice=Nslice; + Elem->xkick1=xkick1; + Elem->ykick1=ykick1; + Elem->R1=R1; + Elem->R2=R2; + Elem->T1=T1; + Elem->T2=T2; + } + IdKickMapModelPass(r_in, Elem->Length, Elem->xkick1, Elem->ykick1, + Elem->xkick2, Elem->ykick2, Elem->x_map, Elem->y_map, Elem->nx_map, Elem->ny_map,Elem->Nslice, + Elem->T1, Elem->T2, Elem->R1, Elem->R2, num_particles); + return Elem; +} + +MODULE_DEF(IdTablePass) /* Dummy module initialisation */ + void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { if (nrhs == 2) { @@ -155,16 +237,16 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) const mxArray *ElemData = prhs[0]; int num_particles = mxGetN(prhs[1]); int Nslice, ny_map, nx_map; - double Length, *xkick, *ykick, *x_map, *y_map; + double Length, *xkick2, *ykick2, *x_map, *y_map; double *xkick1, *ykick1; double *R1, *R2, *T1, *T2; Length=atGetDouble(ElemData,"Length"); check_error(); - xkick=atGetDoubleArraySz(ElemData,"xkick", &ny_map, &nx_map); check_error(); - /* the third input of atGetDoubleArraySz is a pointer for the - * number of rows in the 2-D array, the fourth input is a pointer + /* the third input of atGetDoubleArraySz is a pointer for the + * number of rows in the 2-D array, the fourth input is a pointer * for the number of columns */ - ykick=atGetDoubleArray(ElemData,"ykick"); check_error(); + xkick2=atGetDoubleArraySz(ElemData,"xkick2", &ny_map, &nx_map); check_error(); + ykick2=atGetDoubleArray(ElemData,"ykick2"); check_error(); x_map=atGetDoubleArray(ElemData,"xtable"); check_error(); y_map=atGetDoubleArray(ElemData,"ytable"); check_error(); Nslice=atGetLong(ElemData,"Nslice"); check_error(); @@ -178,15 +260,15 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) /* ALLOCATE memory for the output array of the same size as the input */ plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); - IdKickMapModelPass(r_in, Length, xkick1, ykick1, xkick, ykick, x_map, y_map, + IdKickMapModelPass(r_in, Length, xkick1, ykick1, xkick2, ykick2, x_map, y_map, nx_map, ny_map, Nslice, T1, T2, R1, R2, num_particles); } else if (nrhs == 0) { /* return list of required fields */ plhs[0] = mxCreateCellMatrix(6,1); mxSetCell(plhs[0],0,mxCreateString("Length")); - mxSetCell(plhs[0],1,mxCreateString("xkick")); - mxSetCell(plhs[0],2,mxCreateString("ykick")); + mxSetCell(plhs[0],1,mxCreateString("xkick2")); + mxSetCell(plhs[0],2,mxCreateString("ykick2")); mxSetCell(plhs[0],3,mxCreateString("xtable")); mxSetCell(plhs[0],4,mxCreateString("ytable")); mxSetCell(plhs[0],5,mxCreateString("Nslice")); diff --git a/atmat/atdemos/IDModeling/U35.mat b/atmat/atdemos/IDModeling/U35.mat old mode 100755 new mode 100644 index 9c50e256f..807852410 Binary files a/atmat/atdemos/IDModeling/U35.mat and b/atmat/atdemos/IDModeling/U35.mat differ diff --git a/atmat/atdemos/IDModeling/trackWithU35KickMap.m b/atmat/atdemos/IDModeling/trackWithU35KickMap.m index b1663233a..8a469a810 100644 --- a/atmat/atdemos/IDModeling/trackWithU35KickMap.m +++ b/atmat/atdemos/IDModeling/trackWithU35KickMap.m @@ -2,14 +2,14 @@ r=atradoff(esrf); %create element from kick map and plot kick map -U35elem=atidtable('U35',1,'U35.mat',6.04,'IdTablePass'); +U35elem=atidtable_dat('U35',1,'U35.mat',6.04,'IdTablePass'); xtable=U35elem.xtable; ytable=U35elem.ytable; -xkick=U35elem.xkick; -ykick=U35elem.ykick; -surf(xtable,ytable,xkick) +xkick2=U35elem.xkick2; +ykick2=U35elem.ykick2; +surf(xtable,ytable,xkick2) figure -surf(xtable,ytable,ykick) +surf(xtable,ytable,ykick2) %add kick map to lattice esrf_U35 = add_ID(r,U35elem); diff --git a/atmat/lattice/at2str.m b/atmat/lattice/at2str.m index 631ca57ab..91ff986e7 100644 --- a/atmat/lattice/at2str.m +++ b/atmat/lattice/at2str.m @@ -109,8 +109,8 @@ 'Normalization_energy', ... 'Nslice', ... 'Length', ... - 'xkick', ... - 'ykick', ... + 'xkick2', ... + 'ykick2', ... 'xkick1', ... 'ykick1', ... 'xtable', ... diff --git a/atmat/lattice/element_creation/atinsertiondevicekickmap.m b/atmat/lattice/element_creation/atinsertiondevicekickmap.m index 9449893cf..1de97baf6 100644 --- a/atmat/lattice/element_creation/atinsertiondevicekickmap.m +++ b/atmat/lattice/element_creation/atinsertiondevicekickmap.m @@ -4,8 +4,8 @@ Normalization_energy, ... Nslice, ... length, ... - xkick, ... - ykick, ... + xkick2, ... + ykick2, ... xkick1, ... ykick1, ... xtable, ... @@ -51,7 +51,9 @@ %------------------ % Modification Log: % ----------------- -% 24-05-2023: orblancog, added for compatibility with pyat +% 24-05-2023: blanco-garcia, added for compatibility with pyat +% 13-11-2023: blanco-garcia, change of variable names as in Pull Request +% https://github.com/atcollab/at/pull/683 %--------------------------------------------------------------------------- Elem.FamName = fname; @@ -62,8 +64,8 @@ Elem.Length= length; Elem.xtable = xtable; Elem.ytable = ytable; -Elem.xkick = xkick; -Elem.ykick = ykick; +Elem.xkick2 = xkick2; +Elem.ykick2 = ykick2; Elem.xkick1 = xkick1; Elem.ykick1 = ykick1; Elem.Class = 'InsertionDeviceKickMap'; diff --git a/atmat/pubtools/create_elems/atidtable_dat.m b/atmat/pubtools/create_elems/atidtable_dat.m index f248d8e3d..de99e3164 100644 --- a/atmat/pubtools/create_elems/atidtable_dat.m +++ b/atmat/pubtools/create_elems/atidtable_dat.m @@ -1,21 +1,26 @@ function Elem = atidtable_dat(FamName, Nslice, filename, Energy, method) -% atidtable(FamName, Nslice, filename, Energy, method) +% atidtable_dat Read - RADIA kick maps of 1st and 2nd order in energy +% +% Elem = atidtable_dat(FamName, Nslice, filename, Energy, method) % % FamName family name -% Nslice number of slices (1 means the Insertion Device is represented by a -% single kick in the center of the device). +% Nslice number of slices (1 means the Insertion Device is represented +% by a single kick in the center of the device). % filename name of file with the ID tracking tables. % Energy Normalization energy in GeV, needed for scaling % method name of the function to use for tracking. Use 'IdTablePass' % or 'WigTablePass' % +% returns atinsertiondevicekickmap +% +% +% This function creates an AT element read from an integrated kickmap file. +% % The tracking table method is described in % P. Elleaume, "A new approach to the electron beam dynamics in undulators % and wigglers", EPAC92. -% -% returns atinsertiondevicekickmap -%--------------------------------------------------------------------------- +%-------------------------------------------------------------------------- % Modification Log: % ----------------- % 13-09-2007: Created by M. Munoz, based in J. Safranek code. @@ -24,109 +29,138 @@ % PolynomA, PolynomB,NumX,NumY % (they are not used in IdTablePass) % Adds InsertionDeviceKickMap class -%--------------------------------------------------------------------------- - -%Elem.FamName = fname; % add check for identical family names -%Elem.Filename_in = filename; -%Elem.Normalization_energy = Energy; -%Elem.Class = "KickMap"; -%Elem.Nslice = Nslice; -%Elem.MaxOrder = 3; -%Elem.NumIntSteps = 10; -%Elem.R1 = diag(ones(6,1)); -%Elem.R2 = diag(ones(6,1)); -%Elem.T1 = zeros(1,6); -%Elem.T2 = zeros(1,6); -%Elem.PassMethod = method; +% 13-11-2023: blanco-garcia. Renaming variables due to Pull Request +% https://github.com/atcollab/at/pull/683 +%-------------------------------------------------------------------------- +% constants +lightspeed = PhysConstant.speed_of_light_in_vacuum.value; +emassGeV = PhysConstant.electron_mass_energy_equivalent_in_MeV.value/1e3; -factor=1/((Energy/0.299792458)^2); -factor1=-1/((Energy/0.299792458)); +% energy scaling for 1st order kick-map +factor1 = 1 / (1e9*sqrt(Energy ^2 - emassGeV^2 )/ lightspeed); +% energy scaling for 2st order kick-map +factor2 = (factor1) ^ 2; % Read the file -D=importdata(filename); -if isfield(D,'Kick1x') - x=(D.x)'; - y=(D.y)'; - xkick1=factor1*D.Kick1x; - ykick1=factor1*D.Kick1y; - xkick=factor*D.Kick2x; - ykick=factor*D.Kick2y; - L=D.Len; - nn=size(xkick1); - Ny=nn(1); - Nx=nn(2); -% ElemData.MultiKick= 1; -% ElemData.nkicks= nn(3); +D = importdata(filename); + +% mat file ? +if isfield(D, 'Kick1x') % old matlab format + isIDfileformat = 1; + fprintf('Old format type. Variables will be renamed.\n'); +elseif isfield(D, 'xkick1') % ID new variable names + isIDfileformat = 2; else - [header_mat, data_mat]=mhdrload_bis(filename); - L=data_mat(:,:,1); - Nx=data_mat(:,:,2); - Ny=data_mat(:,:,3); - A = importdata(filename,' ',10); - x=A.data; - x=x(1,1:Nx); - A = importdata(filename,' ',11); - txkick=A.data; - y=txkick(1:Ny,1); - txkick=txkick(:,2:end); - A=importdata(filename,' ',11+Ny+3); - tykick=A.data; - tykick=tykick(:,2:end); - A=importdata(filename,' ',11+2*Ny+2*3); - if isstruct(A) - txkick1=A.data; - txkick1=txkick1(:,2:end); - else - txkick1=0*txkick; - end - A=importdata(filename,' ',11+3*Ny+3*3); - if isstruct(A) - tykick1=A.data; - tykick1=tykick1(:,2:end); - else - tykick1=0*tykick; - end + isIDfileformat = 3; % text file with only TABs or only SPACES +end - xkick=factor*txkick; - ykick=factor*tykick; +% readout variables according to fileformat +switch isIDfileformat + case {1} % mat file + x = (D.x)'; + y = (D.y)'; + xkick1 = factor1 * D.Kick1x; + ykick1 = factor1 * D.Kick1y; + xkick2 = factor2 * D.Kick2x; + ykick2 = factor2 * D.Kick2y; + L = D.Len; - xkick1=factor1*txkick1; - ykick1=factor1*tykick1; + case {2} % new variable names + x = D.xtable; + y = D.ytable; + xkick1 = factor1 * D.xkick1; + ykick1 = factor1 * D.ykick1; + xkick2 = factor2 * D.xkick2; + ykick2 = factor2 * D.ykick2; + L = D.Length; - % Sort arrays in ascending order (needed for "IdTablePass.c") - [y indy]=sort(y); - [x indx]=sort(x); - x=x'; - xkick=xkick(indy,indx); - ykick=ykick(indy,indx); + case {3}% data from text file + % check the data separator, either all tabs or all spaces + fid = fopen(filename); + line_ex = fgetl(fid); + while ischar(line_ex) + line_ex = fgetl(fid); + if line_ex(1) == '#' + continue + end + flagistab = (line_ex==9); + istab = (sum(flagistab)); + if istab + break + end + end + fclose(fid); + % define data separator + if istab + datasep = '\t'; + else + datasep = ' '; + end -end + % read data + A = importdata(filename, datasep, 3); + L = A.data; + A = importdata(filename, datasep, 5); + Nx = A.data; + A = importdata(filename, datasep, 7); + Ny = A.data; + % kick tables + A = importdata(filename, datasep, 10); + x = A.data; + x = x(1, 1:Nx); + A = importdata(filename, datasep, 11); + txkick2 = A.data; + y = txkick2(1:Ny, 1); + txkick2 = txkick2(:, 2:end); + A = importdata(filename, datasep, 11 + Ny + 3); + tykick2 = A.data; + tykick2 = tykick2(:, 2:end); -%Deprecated -%Elem.Length= L; -%Elem.NumX = Ny; -%Elem.NumY = Nx; -%Elem.xtable = x; -%Elem.ytable = y; -%Elem.xkick = xkick; -%Elem.ykick = ykick; -%Elem.xkick1 = xkick1; -%Elem.ykick1 = ykick1; -%Elem.PolynomA= [0 0 0 0]; -%Elem.PolynomB= [0 0 0 0]; + % check if first orders kicks are defined, otherwise set them to zero + A = importdata(filename, datasep, 11 + 2 * Ny + 2 * 3); + if isstruct(A) + txkick1 = A.data; + txkick1 = txkick1(:, 2:end); + else + txkick1 = 0 * txkick2; + end + A = importdata(filename, datasep, 11 + 3 * Ny + 3 * 3); + if isstruct(A) + tykick1 = A.data; + tykick1 = tykick1(:, 2:end); + else + tykick1 = 0 * tykick2; + end -Elem = atinsertiondevicekickmap( FamName, ... - method, ... - filename, ... - Energy, ... - Nslice, ... - L, ... - xkick, ... - ykick, ... - xkick1, ... - ykick1, ... - x, ... - y ... - ); + % scale kick tables + xkick2 = factor2 * txkick2; + ykick2 = factor2 * tykick2; + xkick1 = factor1 * txkick1; + ykick1 = factor1 * tykick1; + % Sort arrays in ascending order (needed for "IdTablePass.c") + [y, indy] = sort(y); + [x, indx] = sort(x); + x = x'; + xkick2 = xkick2(indy, indx); + ykick2 = ykick2(indy, indx); + otherwise + fprintf('Unsupported fileformat.\n') +end + +Elem = atinsertiondevicekickmap( ... + FamName, ... + method, ... + filename, ... + Energy, ... + Nslice, ... + L, ... + xkick2, ... + ykick2, ... + xkick1, ... + ykick1, ... + x, ... + y ... +); +end diff --git a/pyat/at/lattice/idtable_element.py b/pyat/at/lattice/idtable_element.py index cba09117d..c9ffd97e8 100644 --- a/pyat/at/lattice/idtable_element.py +++ b/pyat/at/lattice/idtable_element.py @@ -1,7 +1,7 @@ from .elements import Element import numpy import io -from ..constants import clight +from ..constants import clight, e_mass from warnings import warn @@ -24,8 +24,8 @@ class InsertionDeviceKickMap(Element): 'Normalization_energy', 'Nslice', 'Length', - 'xkick', - 'ykick', + 'xkick2', + 'ykick2', 'xkick1', 'ykick1', 'xtable', @@ -33,8 +33,8 @@ class InsertionDeviceKickMap(Element): _conversions = dict(Element._conversions, Nslice=int, - xkick=_anyarray, - ykick=_anyarray, + xkick2=_anyarray, + ykick2=_anyarray, xkick1=_anyarray, ykick1=_anyarray ) @@ -109,6 +109,9 @@ def readRadiaFieldMap(file_in_name): data_lines = 0 # line not starting with '#' header_lines = 0 # line starting with '#' block_counter = 0 # START of the h.map, START of the v.map + kick_block_list = [] + kick_haxes_list = [] + kick_vaxes_list = [] for line in f: sline = line.split() if sline[0] == '#': # line is comment @@ -122,7 +125,7 @@ def readRadiaFieldMap(file_in_name): elif data_lines == 3: # get the number of ver. points v_points = int(sline[0]) # initialize element kicks and table_axes - kick_map = numpy.zeros((v_points, h_points)) + kick_block = numpy.zeros((v_points, h_points)) haxis = numpy.zeros(h_points) vaxis = numpy.zeros(v_points) else: @@ -137,28 +140,35 @@ def readRadiaFieldMap(file_in_name): # and minus another one due # to the column labels in first line vaxis[block_lines - 2] = float(sline[0]) - kick_map[block_lines - 2][:] = sline[1:] + kick_block[block_lines - 2][:] = sline[1:] if block_lines > v_points: block_lines = 0 - if block_counter == 1: - hkickmap = numpy.copy(kick_map) - table_cols1 = haxis - table_rows1 = vaxis - if block_counter == 2: - vkickmap = numpy.copy(kick_map) - table_cols2 = haxis - table_rows2 = vaxis - if block_counter > 2: - print('atWarning: only two tables read') + kick_block_list.append(kick_block) + kick_haxes_list.append(haxis) + kick_vaxes_list.append(vaxis) block_lines += 1 - # dummy variables not implemented in the reading function - # but required - hkickmap1 = 0.0 * numpy.copy(hkickmap) - vkickmap1 = 0.0 * numpy.copy(vkickmap) + # checking how many kick blocks were added + lenkick_block_list = len(kick_block_list) + if lenkick_block_list < 2 or lenkick_block_list == 3: + _minimumBlocknumberErrormsg = ('Input file contains only ' + f'{len(kick_block_list)} block') + raise ValueError(_minimumBlocknumberErrormsg) + if lenkick_block_list == 2: + # first order kick not in file + kick_block_list.append(0.0 * numpy.copy(kick_block)) + kick_block_list.append(0.0 * numpy.copy(kick_block)) + elif lenkick_block_list > 4: + # file contains more blocks that required + _warn4kickblocks = ('Input file contains more than 4 blocks. ' + 'Additional blocks ignored') + warn(_warn4kickblocks) - return el_length, hkickmap, vkickmap, table_cols1, table_rows1, \ - table_cols2, table_rows2, h_points, v_points, \ - hkickmap1, vkickmap1 + return el_length, \ + kick_block_list[0], kick_block_list[1], \ + kick_haxes_list[0], kick_vaxes_list[0], \ + kick_haxes_list[1], kick_vaxes_list[1], \ + kick_block_list[2], kick_block_list[3], \ + h_points, v_points def sorted_table(table_in, sorted_index, order_axis): # numpy.asfortranarray makes a copy of contiguous memory positions @@ -172,33 +182,34 @@ def sorted_table(table_in, sorted_index, order_axis): return table_out2 # read the input data - el_length, hkickmap, vkickmap, \ - table_cols1, table_rows1, \ - table_cols2, table_rows2, \ - NumX, NumY, \ - hkickmap1, vkickmap1 \ + el_length, \ + hkickmap2, vkickmap2, \ + table_colshkick, table_rowshkick, \ + table_colsvkick, table_rowsvkick, \ + hkickmap1, vkickmap1, \ + NumX, NumY \ = readRadiaFieldMap(Filename_in) # set to float - table_cols1array = numpy.array(table_cols1, dtype='float64') - table_rows1array = numpy.array(table_rows1, dtype='float64') - table_cols2array = numpy.array(table_cols2, dtype='float64') - table_rows2array = numpy.array(table_rows2, dtype='float64') + table_colshkickarray = numpy.array(table_colshkick, dtype='float64') + table_rowshkickarray = numpy.array(table_rowshkick, dtype='float64') + table_colsvkickarray = numpy.array(table_colsvkick, dtype='float64') + table_rowsvkickarray = numpy.array(table_rowsvkick, dtype='float64') # Reorder table_axes - cols1sorted_index = numpy.argsort(table_cols1array) - table_cols1array.sort() - rows1sorted_index = numpy.argsort(table_rows1array) - table_rows1array.sort() - cols2sorted_index = numpy.argsort(table_cols2array) - table_cols2array.sort() - rows2sorted_index = numpy.argsort(table_rows2array) - table_rows2array.sort() - # Reorder kickmap - hkickmap_a = sorted_table(hkickmap, cols1sorted_index, 'col') - hkickmap = sorted_table(hkickmap_a, rows1sorted_index, 'row') - vkickmap_a = sorted_table(vkickmap, cols2sorted_index, 'col') - vkickmap = sorted_table(vkickmap_a, rows2sorted_index, 'row') + cols1sorted_index = numpy.argsort(table_colshkickarray) + table_colshkickarray.sort() + rows1sorted_index = numpy.argsort(table_rowshkickarray) + table_rowshkickarray.sort() + cols2sorted_index = numpy.argsort(table_colsvkickarray) + table_colsvkickarray.sort() + rows2sorted_index = numpy.argsort(table_rowsvkickarray) + table_rowsvkickarray.sort() + # Reorder kickmap2 + hkickmap2_a = sorted_table(hkickmap2, cols1sorted_index, 'col') + hkickmap2 = sorted_table(hkickmap2_a, rows1sorted_index, 'row') + vkickmap2_a = sorted_table(vkickmap2, cols2sorted_index, 'col') + vkickmap2 = sorted_table(vkickmap2_a, rows2sorted_index, 'row') # Reorder kickmap1 hkickmap1_a = sorted_table(hkickmap1, cols1sorted_index, 'col') hkickmap1 = sorted_table(hkickmap1_a, rows1sorted_index, 'row') @@ -206,24 +217,27 @@ def sorted_table(table_in, sorted_index, order_axis): vkickmap1 = sorted_table(vkickmap1_a, rows2sorted_index, 'row') # Field to kick factors - Brho = 1e9 * Energy/clight - factor = 1.0/(Brho**2) - xkick = factor * hkickmap - ykick = factor * vkickmap - # kick1 vars set to zero, not yet implemented - factor1 = -1.0/(Brho) + e_massGeV = e_mass * 1e-9 + Brho = 1e9 * numpy.sqrt(Energy**2 - e_massGeV**2)/clight + # kick2 vars + factor2 = 1.0/(Brho**2) + xkick2 = factor2 * hkickmap2 + ykick2 = factor2 * vkickmap2 + # kick1 vars + factor1 = 1.0/(Brho) xkick1 = factor1 * hkickmap1 ykick1 = factor1 * vkickmap1 - xtable = table_cols1array.T - ytable = table_rows1array.T + # axes + xtable = table_colshkickarray.T + ytable = table_rowshkickarray.T args_dict = {'PassMethod': 'IdTablePass', 'Filename_in': Filename_in, 'Normalization_energy': Energy, 'Nslice': numpy.uint8(Nslice), 'Length': el_length, - 'xkick': xkick, - 'ykick': ykick, + 'xkick2': xkick2, + 'ykick2': ykick2, 'xkick1': xkick1, 'ykick1': ykick1, 'xtable': xtable, @@ -237,12 +251,26 @@ def __init__(self, family_name: str, *args, **kwargs): 'Normalization_energy', 'Nslice', 'Length', - 'xkick', - 'ykick', + 'xkick2', + 'ykick2', 'xkick1', 'ykick1', 'xtable', 'ytable'] + # change of variable names since Pull Request + # https://github.com/atcollab/at/pull/683#issuecomment-1805667215 + _args_change = {'xkick': 'xkick2', 'ykick': 'ykick2'} + for _old_name in _args_change: + if _old_name in kwargs: + # insert in args while keeping order before zipping + _inda = _argnames.index(_args_change[_old_name]) + _argslist = list(args) + _argslist.insert(_inda, kwargs.pop(_old_name)) + args = tuple(_argslist) + _deprecat_msg = (f' argument {_old_name} is deprecated; ' + f'it is changed to {_args_change[_old_name]}' + ) + warn(_deprecat_msg) if len(args) < 11: # get data from text file elemargs = self.from_text_file(*args)