1 | function RM = locoresponsematrix(RINGData, BPMData, CMData, varargin) |
---|
2 | %LOCORESPONSEMATRIX - Calculate the BPM response matrix and dispersion function |
---|
3 | % M = LOCORESPONCEMATRIX(RINGData, BPMData, CMData) |
---|
4 | % |
---|
5 | % Accelerator Toolbox implementation of generic LOCO function |
---|
6 | % |
---|
7 | % RINGData - must have fields 'Lattice', 'CavityFrequency', 'CavityHarmNumber' |
---|
8 | % RINGData.Lattice - AT lattice cell arrary |
---|
9 | % RINGData.CavityFrequency [Hz] |
---|
10 | % RINGData.CavityHarmNumber [Hz] |
---|
11 | % |
---|
12 | % CMData - must have fields: 'HCMIndex', 'VCMIndex', 'HCMKicks', 'VCMKicks', 'HCMCoupling', 'VCMCoupling' |
---|
13 | % CMData.HCMIndex - indexes in the AT lattice of elements used as horizontal correctors |
---|
14 | % CMData.VCMIndex - indexes in the AT lattice of elements used as vertical correctors |
---|
15 | % Elements used as correctors in both planes should be included in both lists |
---|
16 | % CMData.HCMKicks - kick size [radians] of horizontal correctors in the horizontal plane |
---|
17 | % CMData.VCMKicks - kick size [radians] of vertical correctors in the vertical plane |
---|
18 | % CMData.HCMCoupling - corrector coupling coefficient into another plane: |
---|
19 | % 0.01 coupling means that for 1e-3 kick in the horizontal direction there |
---|
20 | % is a 1e-5 rad kick in the vertical direction |
---|
21 | % CMData.VCMCoupling - corrector coupling coefficient into another plane: |
---|
22 | % 0.01 coupling means that for 1e-3 kick in the vertical direction there |
---|
23 | % is a 1e-5 rad kick in the horizontal direction |
---|
24 | % |
---|
25 | % BPMData - must have field 'BPMIndex' |
---|
26 | % CMData.BPMIndex - indexes of all BPMs or observation points in the AT lattice |
---|
27 | % All BPS and observation points (single plane too) |
---|
28 | % are included in CMData.BPMIndex. |
---|
29 | % |
---|
30 | % Return value: a matrix with number of rows equal to 2*length(CMData.BPMIndex) and the number of columns |
---|
31 | % equal length(CMData.HCMIndex)+length(CMData.VCMIndex) |
---|
32 | % |
---|
33 | % Additional string flags (in any order) |
---|
34 | % |
---|
35 | % LOCORESPONSEMATRIX(...,ClosedOrbitType,...) |
---|
36 | % ClosedOrbitType is 'fixedmomentum', 'fixedpathlength' (default) |
---|
37 | % |
---|
38 | % LOCORESPONCEMATRIX(..., 'linear') calculates M using linear approximation !!! including the dispersion terms |
---|
39 | % |
---|
40 | % LOCORESPONCEMATRIX(..., 'RF', DeltaRF) - 'RF' switch must be followed by the value of DeltaRF [Hz] |
---|
41 | % |
---|
42 | % LOCORESPONCEMATRIX(..., 'ResponseMatrixMeasurement', 'oneway') - 'oneway' switch is used |
---|
43 | % when the response matrix was measured only kicking the i-th corrector |
---|
44 | % to +KicksCoupled(i) one way, default: ResponseMatrixMeasurement = 'bidirectional' |
---|
45 | % |
---|
46 | % LOCORESPONCEMATRIX(..., 'DispersionMeasurement', 'oneway') - 'oneway' switch is used |
---|
47 | % when the dispersion was measured only by varying the |
---|
48 | % RF frequency in one direction, default: DispersionMeasurement = 'bidirectional' |
---|
49 | % |
---|
50 | % Or a Flags structure can be an input argument: |
---|
51 | % LOCORESPONCEMATRIX(..., Flags) |
---|
52 | % Flags.ResponseMatrixMeasurement = 'oneway' or {'bi-directional'} |
---|
53 | % Flags.DispersionMeasurement = 'oneway' or {'bi-directional'} |
---|
54 | % Flags.ResponseMatrixCalculator = {'linear'} or 'full' |
---|
55 | % Flags.ClosedOrbitType = 'fixedmomentum' or {'fixedpathlength'} |
---|
56 | % |
---|
57 | % NOTE |
---|
58 | % 1. Flag names are not case sensitive |
---|
59 | % 2. JR - 12/7/05 added vectorized linear rm calculation (NewVectorizedMethod = 1) |
---|
60 | |
---|
61 | NewVectorizedMethod = 1; |
---|
62 | |
---|
63 | C = 2.99792458e8; |
---|
64 | |
---|
65 | % Defaults |
---|
66 | ResponseMatrixMeasurement = 'bidirectional'; |
---|
67 | DispersionMeasurement = 'bidirectional'; |
---|
68 | ResponseMatrixCalculator = 'linear'; |
---|
69 | ClosedOrbitType = 'fixedpathlength'; |
---|
70 | MachineType = 'StorageRing'; |
---|
71 | |
---|
72 | RFFLAG = 0; |
---|
73 | DeltaRF = []; |
---|
74 | |
---|
75 | N = nargin-3; |
---|
76 | i = 0; |
---|
77 | while i < N |
---|
78 | i = i + 1; |
---|
79 | if isstruct(varargin{i}) |
---|
80 | Flags = varargin{i}; |
---|
81 | if isfield(Flags,'ResponseMatrixCalculator') |
---|
82 | ResponseMatrixCalculator = Flags.ResponseMatrixCalculator; |
---|
83 | end |
---|
84 | if isfield(Flags,'ClosedOrbitType') |
---|
85 | ClosedOrbitType = Flags.ClosedOrbitType; |
---|
86 | end |
---|
87 | if isfield(Flags,'ResponseMatrixMeasurement') |
---|
88 | ResponseMatrixMeasurement = Flags.ResponseMatrixMeasurement; |
---|
89 | end |
---|
90 | if isfield(Flags,'DispersionMeasurement') |
---|
91 | DispersionMeasurement = Flags.DispersionMeasurement; |
---|
92 | end |
---|
93 | if isfield(Flags,'MachineType') |
---|
94 | MachineType = Flags.MachineType; |
---|
95 | end |
---|
96 | elseif ischar(varargin{i}) |
---|
97 | switch lower(varargin{i}) |
---|
98 | case 'linear' |
---|
99 | ResponseMatrixCalculator = 'linear'; |
---|
100 | case 'full' |
---|
101 | ResponseMatrixCalculator = 'full'; |
---|
102 | case 'fixedmomentum' |
---|
103 | ClosedOrbitType = 'fixedmomentum'; |
---|
104 | case 'fixedpathlength' |
---|
105 | ClosedOrbitType = 'fixedpathlength'; |
---|
106 | case 'rf' |
---|
107 | if (i+4<=nargin) && isnumeric(varargin{i+1}) |
---|
108 | RFFLAG = 1; |
---|
109 | DeltaRF = varargin{i+1}; |
---|
110 | i = i + 1; |
---|
111 | else |
---|
112 | error('''RF'' flag must be followed by a numeric value of delta RF [Hz]'); |
---|
113 | end |
---|
114 | case 'dispersionmeasurement' |
---|
115 | if (i+4<=nargin) && ischar(varargin{i+1}) |
---|
116 | DispersionMeasurement = varargin{i+1}; |
---|
117 | i = i + 1; |
---|
118 | else |
---|
119 | error('''DispersionMeasurement'' flag must be followed by ''oneway'' or ''bidirectional'''); |
---|
120 | end |
---|
121 | case 'responsematrixmeasurement' |
---|
122 | if (i+4<=nargin) && ischar(varargin{i+1}) |
---|
123 | ResponseMatrixMeasurement = varargin{i+1}; |
---|
124 | i = i + 1; |
---|
125 | else |
---|
126 | error('''ResponseMatrixMeasurement'' flag must be followed by ''oneway'' or ''bidirectional'''); |
---|
127 | end |
---|
128 | case {'storagering','booster','boosterring'} |
---|
129 | MachineType = 'StorageRing'; |
---|
130 | case {'transport','linac'} |
---|
131 | MachineType = 'Transport'; |
---|
132 | otherwise |
---|
133 | warning('Unknown switch ignored.'); |
---|
134 | end |
---|
135 | else |
---|
136 | warning('Unknown switch ignored.'); |
---|
137 | end |
---|
138 | end |
---|
139 | |
---|
140 | |
---|
141 | % Input checks |
---|
142 | if ~strcmpi(ResponseMatrixMeasurement, 'bidirectional') && ~strcmpi(ResponseMatrixMeasurement, 'oneway') |
---|
143 | error('Unknown ResponseMatrixMeasurement type'); |
---|
144 | end |
---|
145 | if ~strcmpi(DispersionMeasurement, 'bidirectional') && ~strcmpi(DispersionMeasurement, 'oneway') |
---|
146 | error('Unknown DispersionMeasurement type'); |
---|
147 | end |
---|
148 | if ~strcmpi(ResponseMatrixCalculator, 'linear') && ~strcmpi(ResponseMatrixCalculator, 'full') |
---|
149 | error('Unknown ResponseMatrixCalculator method'); |
---|
150 | end |
---|
151 | if ~strcmpi(ClosedOrbitType, 'fixedpathlength') && ~strcmpi(ClosedOrbitType, 'fixedmomentum') |
---|
152 | error('Unknown ClosedOrbitType method'); |
---|
153 | end |
---|
154 | if ~strcmpi(MachineType, 'StorageRing') && ~strcmpi(MachineType, 'Transport') |
---|
155 | error('Unknown MachineType'); |
---|
156 | end |
---|
157 | |
---|
158 | |
---|
159 | % Initialize |
---|
160 | ATRING = RINGData.Lattice; |
---|
161 | NHC = length(CMData.HCMIndex); |
---|
162 | NVC = length(CMData.VCMIndex); |
---|
163 | NBPM = length(BPMData.BPMIndex); |
---|
164 | |
---|
165 | |
---|
166 | if strcmpi(MachineType, 'StorageRing') |
---|
167 | |
---|
168 | if RFFLAG |
---|
169 | % Add an extra column for the orbit responce to the RF frequency change |
---|
170 | RM = zeros(2*NBPM,NHC+NVC+1); |
---|
171 | else |
---|
172 | RM = zeros(2*NBPM,NHC+NVC); |
---|
173 | end |
---|
174 | |
---|
175 | NE = length(ATRING); |
---|
176 | if strcmpi(ResponseMatrixCalculator, 'Linear') |
---|
177 | % Calculate linear optics and chromatic finctions for the model |
---|
178 | [M44,T,ClosedOrbit] = findm44(ATRING,0,1:NE+1); |
---|
179 | DP = 0.00001; |
---|
180 | ClosedOrbitDP = findorbit4(ATRING,DP,1:NE+1); |
---|
181 | Dispersion = (ClosedOrbitDP-ClosedOrbit)/DP; |
---|
182 | L0 = findspos(ATRING,NE+1); |
---|
183 | |
---|
184 | %%X1(6)/(DP*L0); % is not the same as mcf(ATRING)??? G. Portmann |
---|
185 | %X1 = ringpass(ATRING,[ClosedOrbitDP(:,1);DP;0]); |
---|
186 | %MCF = X1(6)/(DP*L0); |
---|
187 | MCF = mcf(ATRING); |
---|
188 | |
---|
189 | % Transfer matrixes through individual correctors |
---|
190 | M44HCOR = cell(1,NHC); |
---|
191 | M44VCOR = cell(1,NVC); |
---|
192 | for i=1:NHC |
---|
193 | M44HCOR{i}=findelemm44(ATRING{CMData.HCMIndex(i)},ATRING{CMData.HCMIndex(i)}.PassMethod,[ClosedOrbit(:,CMData.HCMIndex(i));0;0]); |
---|
194 | end |
---|
195 | for i=1:NVC |
---|
196 | match = find(CMData.VCMIndex(i)==CMData.HCMIndex); |
---|
197 | if match |
---|
198 | M44VCOR{i}=M44HCOR{match}; |
---|
199 | else |
---|
200 | M44VCOR{i}=findelemm44(ATRING{CMData.VCMIndex(i)},ATRING{CMData.VCMIndex(i)}.PassMethod,[ClosedOrbit(:,CMData.VCMIndex(i));0;0]); |
---|
201 | end |
---|
202 | end |
---|
203 | |
---|
204 | |
---|
205 | % Assemble arrays of corrector kicks including coupling |
---|
206 | HCORTheta = zeros(4,NHC); |
---|
207 | VCORTheta = zeros(4,NVC); |
---|
208 | |
---|
209 | HCORTheta(2,:) = CMData.HCMKicks(:)'; |
---|
210 | HCORTheta(4,:) = CMData.HCMCoupling(:)' .* CMData.HCMKicks(:)'; |
---|
211 | VCORTheta(2,:) = CMData.VCMCoupling(:)' .* CMData.VCMKicks(:)'; |
---|
212 | VCORTheta(4,:) = CMData.VCMKicks(:)'; |
---|
213 | |
---|
214 | |
---|
215 | % Calculate closed orbit at the exit of each corrector magnet WITH applied kick |
---|
216 | for i=1:NHC |
---|
217 | CI = CMData.HCMIndex(i); |
---|
218 | InverseT = inv(T(:,:,CI)); |
---|
219 | OrbitEntrance = (inv(eye(4)-T(:,:,CI)*M44*InverseT)*... |
---|
220 | T(:,:,CI)*M44*InverseT*(eye(4)+inv(M44HCOR{i}))*HCORTheta(:,i)/2); |
---|
221 | |
---|
222 | OrbitExit = HCORTheta(:,i)/2+M44HCOR{i}*(OrbitEntrance+HCORTheta(:,i)/2); |
---|
223 | |
---|
224 | |
---|
225 | R0 = inv(T(:,:,CI+1))*OrbitExit; |
---|
226 | |
---|
227 | if NewVectorizedMethod |
---|
228 | |
---|
229 | % very slow loop - use vector operations instead |
---|
230 | vectind = BPMData.BPMIndex(1:NBPM); |
---|
231 | |
---|
232 | % convert multidimensional loop to single matrix product |
---|
233 | T3 = T([1, 3],:,vectind); |
---|
234 | T2 = reshape(permute(T3, [1 3 2]), NBPM*2, 4); |
---|
235 | |
---|
236 | % vector comparison |
---|
237 | bgtc = find(vectind > CMData.HCMIndex(i)); |
---|
238 | bltc = find(vectind <= CMData.HCMIndex(i)); |
---|
239 | bgtc = [(bgtc - 1) .* 2 + 1 (bgtc - 1) .* 2 + 2]; |
---|
240 | bltc = [(bltc - 1) .* 2 + 1 (bltc - 1) .* 2 + 2]; |
---|
241 | |
---|
242 | % conditionally multiply |
---|
243 | Tout1 = T2 * R0; |
---|
244 | Tout2 = T2 * M44 * R0; |
---|
245 | Tout = zeros(size(Tout1)); |
---|
246 | Tout(bgtc,:) = Tout1(bgtc,:); |
---|
247 | Tout(bltc,:) = Tout2(bltc,:); |
---|
248 | |
---|
249 | % interleave the writes |
---|
250 | jjj = zeros(2, NBPM); |
---|
251 | jjj(1,:) = 1:NBPM; |
---|
252 | jjj(2,:) = NBPM+1:NBPM*2; |
---|
253 | |
---|
254 | RM(jjj(:), i) = Tout; |
---|
255 | |
---|
256 | else |
---|
257 | |
---|
258 | for j=1:NBPM |
---|
259 | if BPMData.BPMIndex(j)>CMData.HCMIndex(i) |
---|
260 | RM([j, j+NBPM],i) = T([1, 3],:,BPMData.BPMIndex(j))*R0; |
---|
261 | else |
---|
262 | RM([j, j+NBPM],i) = T([1, 3],:,BPMData.BPMIndex(j))*M44*R0; |
---|
263 | end |
---|
264 | end |
---|
265 | |
---|
266 | end |
---|
267 | |
---|
268 | if strcmpi(ClosedOrbitType, 'FixedPathLength') |
---|
269 | % Use the average value of the dispersion at entrance and exit |
---|
270 | D = HCORTheta(2,i) * ... |
---|
271 | (Dispersion(1,CMData.HCMIndex(i))+Dispersion(1,CMData.HCMIndex(i)+1)) * ... |
---|
272 | Dispersion([1 3],BPMData.BPMIndex) /L0/MCF/2; |
---|
273 | |
---|
274 | RM(1:NBPM,i) = RM(1:NBPM,i) - D(1,:)'; |
---|
275 | RM(NBPM+1:end,i) = RM(NBPM+1:end,i) - D(2,:)'; |
---|
276 | end |
---|
277 | |
---|
278 | end |
---|
279 | |
---|
280 | for i=1:NVC |
---|
281 | CI = CMData.VCMIndex(i); |
---|
282 | |
---|
283 | InverseT = inv(T(:,:,CI)); |
---|
284 | OrbitEntrance = (inv(eye(4)-T(:,:,CI)*M44*InverseT) * T(:,:,CI) * M44 * ... |
---|
285 | InverseT * (eye(4)+inv(M44VCOR{i}))*VCORTheta(:,i)/2); |
---|
286 | OrbitExit = VCORTheta(:,i)/2+M44VCOR{i}*(OrbitEntrance+VCORTheta(:,i)/2); |
---|
287 | |
---|
288 | R0 = inv(T(:,:,CI+1))*OrbitExit; |
---|
289 | |
---|
290 | if NewVectorizedMethod |
---|
291 | |
---|
292 | % very slow loop - use vector operations instead |
---|
293 | vectind = BPMData.BPMIndex(1:NBPM); |
---|
294 | |
---|
295 | % convert multidimensional loop to single matrix product |
---|
296 | T3 = T([1, 3],:,vectind); |
---|
297 | T2 = reshape(permute(T3, [1 3 2]), NBPM*2, 4); |
---|
298 | |
---|
299 | % vector comparison |
---|
300 | bgtc = find(vectind > CMData.VCMIndex(i)); |
---|
301 | bltc = find(vectind <= CMData.VCMIndex(i)); |
---|
302 | bgtc = [(bgtc - 1) .* 2 + 1 (bgtc - 1) .* 2 + 2]; |
---|
303 | bltc = [(bltc - 1) .* 2 + 1 (bltc - 1) .* 2 + 2]; |
---|
304 | |
---|
305 | % conditionally multiply |
---|
306 | Tout1 = T2 * R0; |
---|
307 | Tout2 = T2 * M44 * R0; |
---|
308 | Tout = zeros(size(Tout1)); |
---|
309 | Tout(bgtc,:) = Tout1(bgtc,:); |
---|
310 | Tout(bltc,:) = Tout2(bltc,:); |
---|
311 | |
---|
312 | % interleave the writes |
---|
313 | jjj = zeros(2, NBPM); |
---|
314 | jjj(1,:) = 1:NBPM; |
---|
315 | jjj(2,:) = NBPM+1:NBPM*2; |
---|
316 | |
---|
317 | RM(jjj(:), i+NHC) = Tout; |
---|
318 | |
---|
319 | else |
---|
320 | |
---|
321 | for j=1:NBPM |
---|
322 | if BPMData.BPMIndex(j)>CMData.VCMIndex(i) |
---|
323 | RM([j, j+NBPM],i+NHC) = T([1, 3],:,BPMData.BPMIndex(j))*R0; |
---|
324 | else |
---|
325 | RM([j, j+NBPM],i+NHC) = T([1, 3],:,BPMData.BPMIndex(j))*M44*R0; |
---|
326 | end |
---|
327 | end |
---|
328 | |
---|
329 | end |
---|
330 | |
---|
331 | % Vertical correctors with coupling to X and non-zero horizontal dispersion |
---|
332 | if strcmpi(ClosedOrbitType, 'FixedPathLength') |
---|
333 | % Use the average value of the dispersion at entrance and exit |
---|
334 | D = VCORTheta(2,i)*(Dispersion(1,CMData.VCMIndex(i))+Dispersion(1,CMData.VCMIndex(i)+1))*... |
---|
335 | Dispersion([1 3],BPMData.BPMIndex)/L0/MCF/2; |
---|
336 | RM(1:NBPM,NHC+i) = RM(1:NBPM,NHC+i) - D(1,:)'; |
---|
337 | RM(NBPM+1:end,NHC+i) = RM(NBPM+1:end,NHC+i) - D(2,:)'; |
---|
338 | end |
---|
339 | end |
---|
340 | |
---|
341 | if RFFLAG |
---|
342 | if strcmpi(DispersionMeasurement, 'Bidirectional') |
---|
343 | ORBITPLUS = findsyncorbit(RINGData.Lattice, (-C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2)/2, 1:length(RINGData.Lattice)+1); |
---|
344 | ORBIT0 = findsyncorbit(RINGData.Lattice, ( C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2)/2, 1:length(RINGData.Lattice)+1); |
---|
345 | else |
---|
346 | ORBITPLUS = findsyncorbit(RINGData.Lattice, -C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2, 1:length(RINGData.Lattice)+1); |
---|
347 | ORBIT0 = findsyncorbit(RINGData.Lattice, 0, 1:length(RINGData.Lattice)+1); |
---|
348 | end |
---|
349 | D = ORBITPLUS([1 3],BPMData.BPMIndex) - ORBIT0([1 3],BPMData.BPMIndex); |
---|
350 | RM(:,end) = [D(1,:)'; D(2,:)']; |
---|
351 | end |
---|
352 | |
---|
353 | |
---|
354 | elseif strcmpi(ClosedOrbitType, 'FixedPathLength') |
---|
355 | % Exact calculation using FINDSYNCORBIT |
---|
356 | |
---|
357 | for i = 1:NHC |
---|
358 | switch ATRING{CMData.HCMIndex(i)}.PassMethod |
---|
359 | case 'CorrectorPass' |
---|
360 | |
---|
361 | KickAngle0 = ATRING{CMData.HCMIndex(i)}.KickAngle; |
---|
362 | |
---|
363 | if strcmpi(ResponseMatrixMeasurement, 'bidirectional') |
---|
364 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.HCMKicks(i)/2; |
---|
365 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.HCMKicks(i)*CMData.HCMCoupling(i)/2; |
---|
366 | ORBITPLUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
367 | |
---|
368 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) - CMData.HCMKicks(i)/2; |
---|
369 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) - CMData.HCMKicks(i)*CMData.HCMCoupling(i)/2; |
---|
370 | ORBITMINUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
371 | else |
---|
372 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.HCMKicks(i); |
---|
373 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.HCMKicks(i)*CMData.HCMCoupling(i); |
---|
374 | ORBITPLUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
375 | |
---|
376 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1); |
---|
377 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2); |
---|
378 | ORBITMINUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
379 | end |
---|
380 | |
---|
381 | ATRING{CMData.HCMIndex(i)}.KickAngle = KickAngle0; |
---|
382 | |
---|
383 | RM(:,i) = [ORBITPLUS(1,:)-ORBITMINUS(1,:),ORBITPLUS(3,:)-ORBITMINUS(3,:)]'; |
---|
384 | |
---|
385 | case {'StrMPoleSymplectic4Pass','BndMPoleSymplectic4Pass'} |
---|
386 | error('Not implemented yet'); |
---|
387 | otherwise |
---|
388 | error('Unknown pass method for corrector'); |
---|
389 | end |
---|
390 | end |
---|
391 | |
---|
392 | for i = 1:NVC |
---|
393 | switch ATRING{CMData.VCMIndex(i)}.PassMethod |
---|
394 | case 'CorrectorPass' |
---|
395 | KickAngle0 = ATRING{CMData.VCMIndex(i)}.KickAngle; |
---|
396 | |
---|
397 | if strcmpi(ResponseMatrixMeasurement, 'Bidirectional') |
---|
398 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.VCMKicks(i)/2; |
---|
399 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.VCMKicks(i)*CMData.VCMCoupling(i)/2; |
---|
400 | ORBITPLUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
401 | |
---|
402 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) - CMData.VCMKicks(i)/2; |
---|
403 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) - CMData.VCMKicks(i)*CMData.VCMCoupling(i)/2; |
---|
404 | ORBITMINUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
405 | else |
---|
406 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.VCMKicks(i); |
---|
407 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.VCMKicks(i)*CMData.VCMCoupling(i); |
---|
408 | ORBITPLUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
409 | |
---|
410 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2); |
---|
411 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1); |
---|
412 | ORBITMINUS = findsyncorbit(ATRING,0,BPMData.BPMIndex); |
---|
413 | end |
---|
414 | |
---|
415 | ATRING{CMData.VCMIndex(i)}.KickAngle = KickAngle0; |
---|
416 | |
---|
417 | RM(:,NHC+i) = [ORBITPLUS(1,:)-ORBITMINUS(1,:),ORBITPLUS(3,:)-ORBITMINUS(3,:)]'; |
---|
418 | |
---|
419 | case {'StrMPoleSymplectic4Pass','BndMPoleSymplectic4Pass'} |
---|
420 | error('Not implemented yet'); |
---|
421 | otherwise |
---|
422 | error('Unknown pass method for corrector') |
---|
423 | end |
---|
424 | end |
---|
425 | |
---|
426 | if RFFLAG |
---|
427 | if strcmpi(DispersionMeasurement, 'bidirectional') |
---|
428 | ORBITPLUS = findsyncorbit(RINGData.Lattice, (-C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2)/2, 1:length(RINGData.Lattice)+1); |
---|
429 | ORBIT0 = findsyncorbit(RINGData.Lattice, ( C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2)/2, 1:length(RINGData.Lattice)+1); |
---|
430 | else |
---|
431 | ORBITPLUS = findsyncorbit(RINGData.Lattice, -C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2, 1:length(RINGData.Lattice)+1); |
---|
432 | ORBIT0 = findsyncorbit(RINGData.Lattice, 0, 1:length(RINGData.Lattice)+1); |
---|
433 | end |
---|
434 | |
---|
435 | D = ORBITPLUS([1 3],BPMData.BPMIndex) - ORBIT0([1 3],BPMData.BPMIndex); |
---|
436 | RM(:,end) = [D(1,:)';D(2,:)']; |
---|
437 | end |
---|
438 | |
---|
439 | elseif strcmpi(ClosedOrbitType, 'FixedMomentum') |
---|
440 | % ClosedOrbitType = 'fixedmomentum' - Exact calculation using FINDORBIT4 |
---|
441 | for i = 1:NHC |
---|
442 | switch ATRING{CMData.HCMIndex(i)}.PassMethod |
---|
443 | case 'CorrectorPass' |
---|
444 | KickAngle0 = ATRING{CMData.HCMIndex(i)}.KickAngle; |
---|
445 | |
---|
446 | if strcmpi(ResponseMatrixMeasurement, 'Bidirectional') |
---|
447 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.HCMKicks(i)/2; |
---|
448 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.HCMKicks(i)*CMData.HCMCoupling(i)/2; |
---|
449 | ORBITPLUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
450 | |
---|
451 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) - CMData.HCMKicks(i)/2; |
---|
452 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) - CMData.HCMKicks(i)*CMData.HCMCoupling(i)/2; |
---|
453 | ORBITMINUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
454 | else |
---|
455 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.HCMKicks(i); |
---|
456 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.HCMKicks(i)*CMData.HCMCoupling(i); |
---|
457 | ORBITPLUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
458 | |
---|
459 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1); |
---|
460 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2); |
---|
461 | ORBITMINUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
462 | end |
---|
463 | |
---|
464 | ATRING{CMData.HCMIndex(i)}.KickAngle = KickAngle0; |
---|
465 | |
---|
466 | RM(:,i) = [ORBITPLUS(1,:)-ORBITMINUS(1,:),ORBITPLUS(3,:)-ORBITMINUS(3,:)]'; |
---|
467 | |
---|
468 | case {'StrMPoleSymplectic4Pass','BndMPoleSymplectic4Pass'} |
---|
469 | error('Not implemented yet'); |
---|
470 | otherwise |
---|
471 | error('Unknown pass method for corrector'); |
---|
472 | end |
---|
473 | end |
---|
474 | |
---|
475 | for i = 1:NVC |
---|
476 | switch ATRING{CMData.HCMIndex(i)}.PassMethod |
---|
477 | case 'CorrectorPass' |
---|
478 | |
---|
479 | KickAngle0 = ATRING{CMData.HCMIndex(i)}.KickAngle; |
---|
480 | |
---|
481 | if strcmpi(ResponseMatrixMeasurement, 'Bidirectional') |
---|
482 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.VCMKicks(i)/2; |
---|
483 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.VCMKicks(i)*CMData.VCMCoupling(i)/2; |
---|
484 | ORBITPLUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
485 | |
---|
486 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) - CMData.VCMKicks(i)/2; |
---|
487 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) - CMData.VCMKicks(i)*CMData.VCMCoupling(i)/2; |
---|
488 | ORBITMINUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
489 | else |
---|
490 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.VCMKicks(i); |
---|
491 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.VCMKicks(i)*CMData.VCMCoupling(i); |
---|
492 | ORBITPLUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
493 | |
---|
494 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2); |
---|
495 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1); |
---|
496 | ORBITMINUS = findorbit4(ATRING,0,BPMData.BPMIndex); |
---|
497 | end |
---|
498 | |
---|
499 | ATRING{CMData.VCMIndex(i)}.KickAngle = KickAngle0; |
---|
500 | |
---|
501 | RM(:,NHC+i) = [ORBITPLUS(1,:)-ORBITMINUS(1,:),ORBITPLUS(3,:)-ORBITMINUS(3,:)]'; |
---|
502 | |
---|
503 | case {'StrMPoleSymplectic4Pass','BndMPoleSymplectic4Pass'} |
---|
504 | error('Not implemented yet'); |
---|
505 | otherwise |
---|
506 | error('Unknown pass method for corrector') |
---|
507 | end |
---|
508 | end |
---|
509 | |
---|
510 | if RFFLAG |
---|
511 | if strcmpi(DispersionMeasurement, 'Bidirectional') |
---|
512 | ORBITPLUS = findsyncorbit(RINGData.Lattice, (-C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2)/2, 1:length(RINGData.Lattice)+1); |
---|
513 | ORBIT0 = findsyncorbit(RINGData.Lattice, ( C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2)/2, 1:length(RINGData.Lattice)+1); |
---|
514 | else |
---|
515 | ORBITPLUS = findsyncorbit(RINGData.Lattice, -C*DeltaRF*RINGData.CavityHarmNumber/RINGData.CavityFrequency^2, 1:length(RINGData.Lattice)+1); |
---|
516 | ORBIT0 = findsyncorbit(RINGData.Lattice, 0, 1:length(RINGData.Lattice)+1); |
---|
517 | end |
---|
518 | |
---|
519 | D = ORBITPLUS([1 3],BPMData.BPMIndex) - ORBIT0([1 3],BPMData.BPMIndex); |
---|
520 | RM(:,end) = [D(1,:)'; D(2,:)']; |
---|
521 | end |
---|
522 | |
---|
523 | else |
---|
524 | error('ClosedOrbitType method unknown'); |
---|
525 | end |
---|
526 | |
---|
527 | % End of storage ring |
---|
528 | |
---|
529 | |
---|
530 | else |
---|
531 | |
---|
532 | |
---|
533 | % Transport line |
---|
534 | if RFFLAG |
---|
535 | RFFLAG = 0; |
---|
536 | fprintf(' RF flag ignored for transport lines.\n'); |
---|
537 | end |
---|
538 | |
---|
539 | %if strcmpi(ResponseMatrixCalculator, 'Linear') |
---|
540 | % ResponseMatrixCalculator = 'Full'; |
---|
541 | % fprintf(' ResponseMatrixCalculator set to ''Full'' for transport lines (linear is actualy slower for small transport lines).\n'); |
---|
542 | %end |
---|
543 | |
---|
544 | RM = zeros(2*NBPM,NHC+NVC); |
---|
545 | |
---|
546 | NE = length(ATRING); |
---|
547 | |
---|
548 | % Find the response matrix about an initial orbit |
---|
549 | if isfield(ATRING{1}, 'TwissData') |
---|
550 | TwissData = ATRING{1}.TwissData; |
---|
551 | R0 = [TwissData.ClosedOrbit; TwissData.dP; TwissData.dL]; |
---|
552 | else |
---|
553 | % Try the middlelayer |
---|
554 | try |
---|
555 | TwissData = getfamilydata('TwissData'); |
---|
556 | R0 = [TwissData.ClosedOrbit; TwissData.dP; TwissData.dL]; |
---|
557 | if isempty(TwissData) |
---|
558 | R0 = [0 0 0 0 0 0]'; |
---|
559 | end |
---|
560 | catch |
---|
561 | R0 = [0 0 0 0 0 0]'; |
---|
562 | end |
---|
563 | end |
---|
564 | |
---|
565 | if strcmpi(ResponseMatrixCalculator, 'Linear') |
---|
566 | |
---|
567 | % Calculate linear optics and chromatic finctions for the model |
---|
568 | [M44, T, ClosedOrbit1] = findm44(ATRING, 0, 1:NE+1); |
---|
569 | |
---|
570 | % Don't use the closed orbit that findm44 use. Use linepass. |
---|
571 | ClosedOrbit = linepass(ATRING, R0, 1:length(ATRING)+1); |
---|
572 | |
---|
573 | % Transfer matrixes through individual correctors |
---|
574 | M44HCOR = cell(1,NHC); |
---|
575 | M44VCOR = cell(1,NVC); |
---|
576 | |
---|
577 | for i=1:NHC |
---|
578 | M44HCOR{i} = findelemm44(ATRING{CMData.HCMIndex(i)}, ATRING{CMData.HCMIndex(i)}.PassMethod, ClosedOrbit(:,CMData.HCMIndex(i))); |
---|
579 | end |
---|
580 | for i=1:NVC |
---|
581 | match = find(CMData.VCMIndex(i)==CMData.HCMIndex); |
---|
582 | if match |
---|
583 | M44VCOR{i} = M44HCOR{match}; |
---|
584 | else |
---|
585 | M44VCOR{i} = findelemm44(ATRING{CMData.VCMIndex(i)}, ATRING{CMData.VCMIndex(i)}.PassMethod, ClosedOrbit(:,CMData.VCMIndex(i))); |
---|
586 | end |
---|
587 | end |
---|
588 | |
---|
589 | |
---|
590 | % Assemble arrays of corrector kicks including coupling |
---|
591 | HCORTheta = zeros(4,NHC); |
---|
592 | VCORTheta = zeros(4,NVC); |
---|
593 | |
---|
594 | HCORTheta(2,:) = CMData.HCMKicks(:)'; |
---|
595 | HCORTheta(4,:) = CMData.HCMCoupling(:)' .* CMData.HCMKicks(:)'; |
---|
596 | VCORTheta(2,:) = CMData.VCMCoupling(:)' .* CMData.VCMKicks(:)'; |
---|
597 | VCORTheta(4,:) = CMData.VCMKicks(:)'; |
---|
598 | |
---|
599 | |
---|
600 | % Calculate closed orbit at the exit of each corrector magnet WITH applied kick |
---|
601 | for i = 1:NHC |
---|
602 | CI = CMData.HCMIndex(i); |
---|
603 | InverseT = inv(T(:,:,CI)); |
---|
604 | |
---|
605 | % Split the kick on either side of the corrector |
---|
606 | OrbitExit = M44HCOR{i} * HCORTheta(:,i)/2 + HCORTheta(:,i)/2; |
---|
607 | OrbitEntrance = inv(M44HCOR{i}) * OrbitExit; |
---|
608 | R0 = InverseT * OrbitEntrance(1:4); |
---|
609 | |
---|
610 | for j = 1:NBPM |
---|
611 | if BPMData.BPMIndex(j) > CMData.HCMIndex(i) |
---|
612 | RM([j, j+NBPM],i) = T([1 3],:,BPMData.BPMIndex(j)) * R0; |
---|
613 | end |
---|
614 | end |
---|
615 | end |
---|
616 | |
---|
617 | for i=1:NVC |
---|
618 | CI = CMData.VCMIndex(i); |
---|
619 | InverseT = inv(T(:,:,CI)); |
---|
620 | |
---|
621 | % Split the kick on either side of the corrector |
---|
622 | OrbitExit = M44VCOR{i} * VCORTheta(:,i)/2 + VCORTheta(:,i)/2; |
---|
623 | OrbitEntrance = inv(M44HCOR{i}) * OrbitExit; |
---|
624 | R0 = InverseT * OrbitEntrance(1:4); |
---|
625 | |
---|
626 | for j=1:NBPM |
---|
627 | if BPMData.BPMIndex(j)>CMData.VCMIndex(i) |
---|
628 | RM([j, j+NBPM],i+NHC) = T([1 3],:,BPMData.BPMIndex(j)) * R0; |
---|
629 | end |
---|
630 | end |
---|
631 | end |
---|
632 | |
---|
633 | elseif strcmpi(ResponseMatrixCalculator, 'Full') |
---|
634 | |
---|
635 | % Exact calculation using linepass |
---|
636 | for i = 1:NHC |
---|
637 | switch ATRING{CMData.HCMIndex(i)}.PassMethod |
---|
638 | case 'CorrectorPass' |
---|
639 | |
---|
640 | KickAngle0 = ATRING{CMData.HCMIndex(i)}.KickAngle; |
---|
641 | |
---|
642 | if strcmpi(ResponseMatrixMeasurement, 'bidirectional') |
---|
643 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.HCMKicks(i)/2; |
---|
644 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.HCMKicks(i)*CMData.HCMCoupling(i)/2; |
---|
645 | ORBITPLUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
646 | |
---|
647 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) - CMData.HCMKicks(i)/2; |
---|
648 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) - CMData.HCMKicks(i)*CMData.HCMCoupling(i)/2; |
---|
649 | ORBITMINUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
650 | else |
---|
651 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.HCMKicks(i); |
---|
652 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.HCMKicks(i)*CMData.HCMCoupling(i); |
---|
653 | ORBITPLUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
654 | |
---|
655 | ATRING{CMData.HCMIndex(i)}.KickAngle(1) = KickAngle0(1); |
---|
656 | ATRING{CMData.HCMIndex(i)}.KickAngle(2) = KickAngle0(2); |
---|
657 | ORBITMINUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
658 | end |
---|
659 | |
---|
660 | ATRING{CMData.HCMIndex(i)}.KickAngle = KickAngle0; |
---|
661 | |
---|
662 | RM(:,i) = [ORBITPLUS(1,:)-ORBITMINUS(1,:),ORBITPLUS(3,:)-ORBITMINUS(3,:)]'; |
---|
663 | |
---|
664 | case {'StrMPoleSymplectic4Pass','BndMPoleSymplectic4Pass'} |
---|
665 | error('Not implemented yet'); |
---|
666 | otherwise |
---|
667 | error('Unknown pass method for corrector'); |
---|
668 | end |
---|
669 | end |
---|
670 | |
---|
671 | for i = 1:NVC |
---|
672 | switch ATRING{CMData.VCMIndex(i)}.PassMethod |
---|
673 | case 'CorrectorPass' |
---|
674 | KickAngle0 = ATRING{CMData.VCMIndex(i)}.KickAngle; |
---|
675 | |
---|
676 | if strcmpi(ResponseMatrixMeasurement, 'Bidirectional') |
---|
677 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.VCMKicks(i)/2; |
---|
678 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.VCMKicks(i)*CMData.VCMCoupling(i)/2; |
---|
679 | ORBITPLUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
680 | |
---|
681 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) - CMData.VCMKicks(i)/2; |
---|
682 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) - CMData.VCMKicks(i)*CMData.VCMCoupling(i)/2; |
---|
683 | ORBITMINUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
684 | else |
---|
685 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2) + CMData.VCMKicks(i); |
---|
686 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1) + CMData.VCMKicks(i)*CMData.VCMCoupling(i); |
---|
687 | ORBITPLUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
688 | |
---|
689 | ATRING{CMData.VCMIndex(i)}.KickAngle(2) = KickAngle0(2); |
---|
690 | ATRING{CMData.VCMIndex(i)}.KickAngle(1) = KickAngle0(1); |
---|
691 | ORBITMINUS = linepass(ATRING,R0,BPMData.BPMIndex); |
---|
692 | end |
---|
693 | |
---|
694 | ATRING{CMData.VCMIndex(i)}.KickAngle = KickAngle0; |
---|
695 | |
---|
696 | RM(:,NHC+i) = [ORBITPLUS(1,:)-ORBITMINUS(1,:),ORBITPLUS(3,:)-ORBITMINUS(3,:)]'; |
---|
697 | |
---|
698 | case {'StrMPoleSymplectic4Pass','BndMPoleSymplectic4Pass'} |
---|
699 | error('Not implemented yet'); |
---|
700 | otherwise |
---|
701 | error('Unknown pass method for corrector') |
---|
702 | end |
---|
703 | end |
---|
704 | else |
---|
705 | error('Unknown method for transfer lines.'); |
---|
706 | end |
---|
707 | end |
---|