Commit 1625a9bc authored by Simone Liuzzo's avatar Simone Liuzzo

TL1 optics initial commit

parent e1962176
function ring = checklattice(ring,varargin)
%NEWRING = EBS.CHECKLATTICE(RING) Check the validity of an EBS lattice
%
%CHECKLATTICE will
%- set the QUADRUPOLE, BEND and MULTIPOLE pass methods
%- Add if necessary markers at pinhole camera locations
%- Rename the BPMs with their device name
%
%CHECKLATTICE(...,'energy',energy)
% Set the ring energy
%
%CHECKLATTICE(...,'reduce',true,'keep',pattern)
% Remove elements with PassMethod='IdentityPass' and merge adjacent
% similar elements, but keeps elements with FamName matching "pattern"
% Pattern may be a logical mask.
% (Default: 'BPM.*|ID.*' for SR, '^BPM_..|^ID.*|JL1[AE].*|CA[02][57]').
%
%CHECKLATTICE(...,'remove',famnames)
% remove elements identified by the family names (cell array)
%
%CHECKLATTICE(...,'reduce',true)
% group similar elements together by calling atreduce
%
%CHECKLATTICE(...,'MaxOrder',n)
% Limit the order of polynomial field expansion to n at maximum
%
%CHECKLATTICE(...,'NumIntSteps',m)
% Set the NumIntSteps integration parameter to at least m
%
%CHECKLATTICE(...,'QuadFields',quadfields)
% Set quadrupoles fields to the specified ones.
% Default: {}
%
%CHECKLATTICE(...,'BendFields',bendfields)
% Set bending magnet fields to the specified ones.
% Default: {}
%
%CHECKLATTICE(...,'DeviceNames',true)
% add device names in AT structure.
[check,options]=getoption(varargin,'CheckLattice',true);
if check
[energy,periods]=atenergy(ring);
[energy,options]=getoption(options,'Energy',energy);
[periods,options]=getoption(options,'Periods',periods);
reduce=getoption(options,'reduce',false);
[keep,options]=getoption(options,'keep',false(size(ring)));
if ~islogical(keep), keep=atgetcells(ring,'FamName',keep); end
[devnam,options]=getoption(options,'DeviceNames',true);
cellnb=circshift(1:32,[0 -3]);
precious=atgetcells(ring,'FamName','ID.*$|^JL1[AE].*') |...
atgetcells(ring,'FamName','BM\w*') |...
atgetcells(ring,'Class','Monitor');
ring=atclean(ring,options{:},'keep',keep|precious);
ring=rename_bpms(ring);
if ~reduce
ring=addpinholes(ring);
end
if devnam
ring=adddevicenames(ring);
end
rp=atgetcells(ring,'Class','RingParam');
if any(rp)
params=ring(rp);
params{1}.Energy=energy;
params{1}.Periodicity=periods;
else
params={atringparam('TL1',energy,periods)};
end
ring=[params(1);ring(~rp)];
end
function mach=rename_bpms(mach)
bpmid=atgetcells(mach,'FamName','BPM_..');
if sum(bpmid) == 20 % Full machine
fprintf('Rename BPMs...\n');
bpmname=arrayfun(@(i) sprintf('BPM_%02d',i),1:sum(bpmid),'UniformOutput',false);
mach(bpmid)=atsetfieldvalues(mach(bpmid),'FamName',bpmname);
end
end
function mach=adddevicenames(mach)
warning('not yet implemented. no device name added. must define bpmname, qpname, ...');
return
fprintf('Add device names...\n');
ind = find(atgetcells(mach,'Class','Quadrupole') | atgetcells(mach,'FamName','Q[FDIJ]\w*'))';
mach(ind)=atsetfieldvalues(mach(ind),'Device',''); % initialize Device field to empty
firstsliceQF8D=diff(ind)~=1;% some QF8D are splitted, name first slice only!
indi=[ind(firstsliceQF8D) ind(end)]; % real number of Quads (removing overcount for splitted elements)
mach(indi)=atsetfieldvalues(mach(indi),'Device',ebs.qpname(1:length(indi)));
mach(ind(end:-1:1)) = nameunamedaslastnamed(mach(ind(end:-1:1)));
function r=nameunamedaslastnamed(r)
% name devices without a name with the name of the last device
% with a name
lastname = '';
for ii=1:length(r)
if ~isempty(r{ii}.Device)
lastname = r{ii}.Device;
else
r{ii}.Device = lastname;
end
end
end
ind=find(atgetcells(mach,'FamName','DQ\w*'))';
firstslicedq=diff(ind)~=2;% some DQ are splitted, name first slice
indi=[ind(firstslicedq) ind(end)]; % real number of DQ (removing overcount for splitted elements)
mach(indi)=atsetfieldvalues(mach(indi),'Device',ebs.dqname(1:length(indi)));
secondslicedq=ind(diff(ind)==2);
firstofsecondslicedq=secondslicedq+2; % index of first slice for DQ with second slice
dqsecondslicename=atgetfieldvalues(mach(firstofsecondslicedq),'Device'); % read device name fro first slice
mach(secondslicedq)=atsetfieldvalues(mach(secondslicedq),'Device',dqsecondslicename); % assign to second slice
ind=atgetcells(mach,'Class','Sextupole');
mach(ind)=atsetfieldvalues(mach(ind),'Device',ebs.sxname(1:sum(ind)));
ind=atgetcells(mach,'FamName','O[FIJ]\w*');
mach(ind)=atsetfieldvalues(mach(ind),'Device',ebs.ocname(1:sum(ind)));
ind=atgetcells(mach,'Class','Monitor');
mach(ind)=atsetfieldvalues(mach(ind),'Device',ebs.bpmname(1:sum(ind)));
ind=atgetcells(mach,'FamName','PINHOLE_.*');
mach(ind)=atsetfieldvalues(mach(ind),'Device',ebs.pinholename(1:sum(ind)));
end
function mach=addpinholes(mach)
warning('not yet implemented. no pinhole added.');
return
pinid=~any(atgetcells(mach,'FamName','PINHOLE_ID(\d\d)?'));
pind=~any(atgetcells(mach,'FamName','PINHOLE_D(\d\d)?'));
if pinid && ~isempty(ebs.model.pinhole_id)
fprintf('Add ID pinholes...\n');
dl1a5 = atgetcells(mach, 'FamName', 'DL1A_5');
nbdl = sum(dl1a5);
if nbdl == 1 % standard cell or injection cell
msk=true;
pinlist=atmarker('PINHOLE_ID');
else % 31 or 32: full machine
msk=pinmask(ebs.model.pinhole_id);
if nbdl == 31
msk=msk(2:end); % No DL1A_% in cell 4
end
pinlist=arrayfun(@(c) atmarker(sprintf('PINHOLE_ID%02d',c)),ebs.model.pinhole_id,'UniformOutput',false);
end
dl1a5(dl1a5)=msk(1:nbdl);
loc=1.5e-3./cellfun(@(el) el.BendingAngle, mach(dl1a5));
mach=atinsertelems(mach,dl1a5,loc,pinlist);
end
if pind && ~isempty(ebs.model.pinhole_bm)
fprintf('Add D pinholes...\n');
dq1d=atgetcells(mach,'FamName','DQ1D');
ffdq1d=find(atgetcells(mach,'FamName','mlDQ1D'),1);
nbdl = sum(dq1d);
if (nbdl == 1) || (nbdl == 2) % injection cell or standard cell
msk=true(2,1);
pinlist=atmarker('PINHOLE_D');
else % 32: full machine
msk=pinmask(ebs.model.pinhole_bm);
pinlist=arrayfun(@(c) atmarker(sprintf('PINHOLE_D%02d',c)),ebs.model.pinhole_bm,'UniformOutput',false);
end
dq1d(dq1d)=msk(1:nbdl);
if isempty(ffdq1d)
ffangle=0;
else
ffangle=mach{ffdq1d}.BendingAngle;
end
loc=(1.5e-3-ffangle)./cellfun(@(el) el.BendingAngle, mach(dq1d));
mach=atinsertelems(mach,dq1d,loc,pinlist);
end
function msk=pinmask(pin)
msk=false(1,32);
pin=mod(pin-4,32)+1;
msk(pin)=true;
end
end
end
classdef model < atmodel
%Class providing access to SY optical values
%
%Available locations:
%
%bpm: All BPMs
%hbpm: Horizontal BPMs
%h_bpms:Logical mask (1x75) of horizontal BPMs
%vbpm: Vertical BPMs
%v_bpms:Logical mask (1x75) of vertical BPMs
%qp: All quadrupoles
%sx: All sextpoles
%steerh: Horizontal steerers
%steerv: Vertical steerers
%
%Available parameters:
%
%0: index in the AT structure
%1: Integrated strength
%2: theta/2pi
%3: betax
%4: alphax
%5: phix/2pi/nux
%6: etax
%7: eta'x
%8: betaz
%9: alphaz
%10: phiz/2pi/nux
%11: etaz
%12: eta'z
%
%Default parameters:
%
%[ 2 3 5 6 8 10 ]
%[theta/2Pi, betax, Phix/2PiNux, etax, betaz, Phiz/2PiNux]
properties
directory
end
methods (Static)
function ring=checklattice(ring,varargin)
%NEWRING = EBS.CHECKLATTICE(RING) Check the validity of an EBS lattice
%
%CHECKLATTICE will
%- set the QUADRUPOLE, BEND and MULTIPOLE pass methods
%- Add if necessary markers at ID locations (centre of straight sections)
%- Add if necessary markers at pinhole camera locations
%- Rename the BPMs with their device name
%
%CHECKLATTICE(...,'energy',energy)
% Set the ring energy
%
%CHECKLATTICE(...,'reduce',true,'keep',pattern)
% Remove elements with PassMethod='IdentityPass' and merge adjacent
% similar elements, but keeps elements with FamName matching "pattern"
% Pattern may be a logical mask.
% (Default: 'BPM.*|ID.*' for SR, '^BPM_..|^ID.*|JL1[AE].*|CA[02][57]').
%
%CHECKLATTICE(...,'remove',famnames)
% remove elements identified by the family names (cell array)
%
%CHECKLATTICE(...,'reduce',true)
% group similar elements together by calling atreduce
%
%CHECKLATTICE(...,'MaxOrder',n)
% Limit the order of polynomial field expansion to n at maximum
%
%CHECKLATTICE(...,'NumIntSteps',m)
% Set the NumIntSteps integration parameter to at least m
%
%CHECKLATTICE(...,'QuadFields',quadfields)
% Set quadrupoles fields to the specified ones.
% Default: {}
%
%CHECKLATTICE(...,'BendFields',bendfields)
% Set bending magnet fields to the specified ones.
% Default: {}
%CHECKLATTICE(...,'DeviceNames',true)
% add device names in AT structure.
[check,options]=getoption(varargin,'CheckLattice',true);
if check
[energy,periods]=atenergy(ring);
[energy,options]=getoption(options,'energy',energy);
[periods,options]=getoption(options,'Periods',periods);
[keep,options]=getoption(options,'keep',false(size(ring)));
if ~islogical(keep), keep=atgetcells(ring,'FamName',keep); end
precious=atgetcells(ring,'Class','Monitor');
ring=atclean(ring,options{:},'keep',keep|precious);
rp=atgetcells(ring,'Class','RingParam');
if any(rp)
params=ring(rp);
params{1}.Energy=energy;
params{1}.Periodicity=periods;
else
params={atringparam('TL1',energy,1)};
end
ring=[params(1);ring(~rp)];
end
end
function pth=getdirectory(varargin)
nm=getargs(varargin,{'theory'});
directory=fullfile(getenv('APPHOME'),'optics','tl1');
pth=fullfile(directory,nm);
end
end
methods
function this=model(varargin)
%Builds the linear model of the ring
%
%M=SY.MODEL() takes the lattice from
% $APPHOME/sy/optics/settings/theory/betamodel.mat
%M=SY.MODEL('opticsname') takes the lattice from
% $APPHOME/sy/optics/settings/opticsname/betamodel.mat
%M=SY.MODEL(path) takes the lattice from
% path or path/betamodel.mat
%M=SY.MODEL(AT) Uses the given AT structure
this@atmodel(tl1.getat(varargin{:}));
this.directory = this.getdirectory;
end
end
methods (Access=protected)
function idx=elselect(this,code)
%Return indices of selected elements
switch lower(code)
case 'bpm'
idx=atgetcells(this.ring,'Class','Monitor') ;
case 'steerh'
idx=atgetcells(this.ring,'FamName','.*ch[0-9]+');
case 'steerv'
idx=atgetcells(this.ring,'FamName','.*cv[0-9]+');
case 'sx'
idx=atgetcells(this.ring,'Class','ThinMultipole') | ...
atgetcells(this.ring,'Class','Sextupole');
case 'qp'
idx=atgetcells(this.ring,'Class','Quadrupole');
otherwise
idx=atgetcells(this.ring,'FamName',upper(code));
end
end
end
end
function CreateOpticsFiles(r,opticsname,varargin)
% CREATEOPTICSFUILES(r,opticsname,'property',value,...),
% given an AT lattice R creates the relevant files for operation
%
% operation folder 2018 is APPHOME/ebs/optics/settings/(OPTICSNAME)
% operation folder 2019 could become APPHOME/<commissioingtoolsrepository>/optics/ebssr/(OPTICSNAME)
%
% optional input ('NAME',val,'Name2',val2,...)
% 'OperationFolder' : commissioningtools folder where optics/ebssr/theory
% link is present.
% 'MeasuredResponse' : folder containing ouput of full RM measurement
% 'errtab' : table of errors
% 'cortab' : table of corrections
%
% WARNING lattice contains QF8D modeled as dipoles.
% Those are merged to a single quadrupole without bending angle for all
% computations. This makes any function using dispersion (matching for ex.)
% incorrect.
%
% example:
% load /machfs/liuzzo/esrfupgradelatticefiles-code/S28D/MagneticLengths/AT/errors/WP_021_034__S28D_Z0p67_newErrFunct_1_seed1_.mat
% CreateOpticsFiles(ring_err,'Seed1MeasResp','MeasuredResponse','/machfs/liuzzo/EBS/Simulator/responsematrix/resp2')
%
%see also: LoadOpticsConfiguration
p=inputParser;
addRequired(p,'r',@iscell);
addRequired(p,'opticsname',@ischar);
addOptional(p,'OperationFolder',getenv('APPHOME'));
addOptional(p,'MeasuredResponse',[]);
addOptional(p,'errtab',[],@istable);
addOptional(p,'cortab',[],@istable);
parse(p,r,opticsname,varargin{:});
r = p.Results.r;
opticsname = p.Results.opticsname;
OpeFolder = p.Results.OperationFolder;
rm = p.Results.MeasuredResponse;
errtab = p.Results.ErrTab;
cortab = p.Results.CorTab;
if isempty(errtab)
errtab = atcreateerrortable(r);
end
if isempty(cortab)
cortab = atgetcorrectiontable(r,r); % zeros
end
% global APPHOME
% ah=getenv('APPHOME');
% %if ah~=APPHOME
% warning(['Setting APPHOME=' ah]);
% APPHOME=ah;
% %end
fulfold=fullfile(OpeFolder,'optics','tl1',opticsname);
curdir=pwd;
mkdir(fulfold);
cd(fulfold);
% AT lattice
betamodel=r;
save('betamodel.mat','betamodel');
% AT lattice for simulator with errors and corrections
disp('errors and correction lattice for simulator (provide errtab and cortab or zeros will be set)')
errmodel=atseterrortable(r,errtab);
errmodel=atsetcorrectiontable(errmodel,cortab);
save('errmodel.mat','errmodel','cortab','errtab');
% save image of lattice optics
f=figure;
atplot(r);
saveas(gca,[opticsname '.jpg']);
close(f);
rfull=tl2.model(r);
% compute fast model once for all
% merge DQ
indDQmark=atgetcells(r,'FamName','PINHOLE_D\w*','CellCenter');
r(indDQmark)=[]; % checklattice should merge all splitted elements.
% merge 2PW and transform back to quadrupole
indQF8dip = find(atgetcells(r,'FamName','QF8\w*') & atgetcells(r,'Class','Bend'))';
r=atsetfieldvalues(r,indQF8dip,'BendingAngle',0);
r=atsetfieldvalues(r,indQF8dip,'Class','Quadrupole');
r=atsetfieldvalues(r,indQF8dip,'PassMethod','StrMPoleSymplectic4Pass');
% get fast model (QF8D merged, not ok for optics computations)
rmod=tl2.model(r,'reduce',true,'keep','BPM.*|ID.*');
% % store family magnet strengths to file (or in the format for magnet application, to be loaded)
% orbit response, theory always,
%
% tl2.autocor_model(rfull);
%
% % measured if required
% if ~isempty(rm)
% tl2.autocor_model(rfull,'exp',rm);
% end
cd(curdir);
end
File added
function atstruct = getat(varargin)
%GETAT % Return an AT structure
%
%ATSTRUCT=GETAT(VARARGIN) scans the input arguments looking for:
%
%- 'opticsname'
% optics name (defaults to 'theory')
%- '/machfs/appdata/sy/optics/settings/opticsname':
% full path of optics directory
%- atstruct:
% AT structure
%- sy.model:
% sy.model object
%
%
%ATSTRUCT: Resulting AT structure
%
%GETAT(...,'energy',energy)
% Set the ring energy
%
%GETAT(...,'reduce',true,'keep',pattern)
% Remove elements with PassMethod='IdentityPass' and merge adjacent
% similar elements, but keeps elements with FamName matching "pattern"
% Pattern may be a logical mask. (Default: 'BPM.*|ID.*').
%
%GETAT(...,'remove',famnames)
% remove elements identified by the family names (cell array)
%
%GETAT(...,'MaxOrder',n)
% Limit the order of polynomial field expansion to n at maximum.
% Default 999
%
%GETAT(...,'NumIntSteps',m)
% Set the NumIntSteps integration parameter to at least m.
% Default 20
%
%GETAT(...,'QuadFields',quadfields)
% When reading a BETA file, set quadrupoles fields to the specified ones.
% Default: {}
%
%GETAT(...,'BendFields',bendfields)
% When reading a BETA file, set bending magnet fields to the specified ones.
% Default: {}
%
%GETAT(...,'DeviceNames',true)
% add device names in AT structure.
[machid,location,args]=atmodel.getpath('tl1',varargin{:});
atstruct=atmodel.getatstruct(machid,location,args{:});
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment