1 | function ChiSquare = calclocochi2(LocoModel, LocoMeasData, BPMData, CMData, FitParameters, LocoFlags, RINGData) |
---|
2 | %CALCLOCOCHI2 - Calculate the contribution to chi^2 of each fit parameter in LOCO |
---|
3 | % ChiSquare = calclocochi2(LocoModel, LocoMeasData, BPMData, CMData, FitParameters, LocoFlags, RINGData) |
---|
4 | % ChiSquare = calclocochi2(LOCOFileName) |
---|
5 | |
---|
6 | |
---|
7 | % Input #1 can be a LOCO file |
---|
8 | if ischar(LocoModel) |
---|
9 | load(LocoModel); |
---|
10 | end |
---|
11 | |
---|
12 | |
---|
13 | % Get the flags |
---|
14 | LocoParams = FitParameters.Params; |
---|
15 | LocoValues = FitParameters.Values; |
---|
16 | LocoDeltas = FitParameters.Deltas; |
---|
17 | SVmethod = LocoFlags.SVmethod; |
---|
18 | AutoCorrectDeltaFlag = LocoFlags.AutoCorrectDelta; |
---|
19 | CouplingFlag = LocoFlags.Coupling; |
---|
20 | NormalizeFlag = LocoFlags.Normalize; |
---|
21 | OutlierFactor = LocoFlags.OutlierFactor; |
---|
22 | |
---|
23 | % UNITS CONVERSIONS (to be combatible with tracking code) |
---|
24 | % Convert corrector kicks used in the response matrix to radians |
---|
25 | CMData.HCMKicks = CMData.HCMKicks(:) / 1000; % milliradian to radians (column vector) |
---|
26 | CMData.VCMKicks = CMData.VCMKicks(:) / 1000; % milliradian to radians (column vector) |
---|
27 | |
---|
28 | % Convert the measured response matrix to meters |
---|
29 | LocoMeasData.M = LocoMeasData.M / 1000; |
---|
30 | |
---|
31 | % Convert the BPMSTD to meters and make the same size as a response matrix |
---|
32 | LocoMeasData.BPMSTD = LocoMeasData.BPMSTD / 1000; % mm to meters |
---|
33 | Mstd = LocoMeasData.BPMSTD * ones(1,size(LocoMeasData.M,2)); |
---|
34 | |
---|
35 | % Convert orbit for "dispersion" in meters in column vector format |
---|
36 | LocoMeasData.Eta = LocoMeasData.Eta(:) / 1000; % mm to meters |
---|
37 | % END UNITS CONVERTSION |
---|
38 | |
---|
39 | % Use the entire family of BPMs in the model response matrix, then index later (not much difference computationally) |
---|
40 | BPMIndexShortX = BPMData.HBPMIndex(BPMData.HBPMGoodDataIndex); |
---|
41 | BPMIndexShortY = length(BPMData.BPMIndex)+BPMData.VBPMIndex(BPMData.VBPMGoodDataIndex); |
---|
42 | BPMIndexShort = [BPMIndexShortX(:)' BPMIndexShortY(:)']; |
---|
43 | NHBPM = length(BPMData.HBPMGoodDataIndex); |
---|
44 | NVBPM = length(BPMData.VBPMGoodDataIndex); |
---|
45 | NBPM = NHBPM + NVBPM; |
---|
46 | NHCM = length(CMData.HCMGoodDataIndex); |
---|
47 | NVCM = length(CMData.VCMGoodDataIndex); |
---|
48 | |
---|
49 | |
---|
50 | % Remove unwanted data from the Mmeas and Mstd |
---|
51 | Mmeas = LocoMeasData.M([BPMData.HBPMGoodDataIndex length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex], [CMData.HCMGoodDataIndex length(CMData.HCMIndex)+CMData.VCMGoodDataIndex]); |
---|
52 | Mstd = Mstd([BPMData.HBPMGoodDataIndex length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex], [CMData.HCMGoodDataIndex length(CMData.HCMIndex)+CMData.VCMGoodDataIndex]); |
---|
53 | |
---|
54 | % If including dispersion then Mstd and Mmeas must include disperion term |
---|
55 | if strcmpi((LocoFlags.Dispersion),'yes') |
---|
56 | Xstd = LocoMeasData.BPMSTD(BPMData.HBPMGoodDataIndex); |
---|
57 | Ystd = LocoMeasData.BPMSTD(length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex); |
---|
58 | |
---|
59 | if isempty(LocoMeasData.Eta) |
---|
60 | error('Measured dispersion (LocoMeasData.Eta) can not be empty when including dispersion'); |
---|
61 | end |
---|
62 | EtaX = LocoMeasData.Eta(BPMData.HBPMGoodDataIndex); |
---|
63 | EtaY = LocoMeasData.Eta(length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex); |
---|
64 | |
---|
65 | LocoFlags.HorizontalDispersionWeight = abs(LocoFlags.HorizontalDispersionWeight); |
---|
66 | LocoFlags.VerticalDispersionWeight = abs(LocoFlags.VerticalDispersionWeight); |
---|
67 | |
---|
68 | % Should remove the dispersion if both weights are zero |
---|
69 | if LocoFlags.HorizontalDispersionWeight == 0 |
---|
70 | LocoFlags.HorizontalDispersionWeight = eps; |
---|
71 | end |
---|
72 | if LocoFlags.VerticalDispersionWeight == 0 |
---|
73 | LocoFlags.VerticalDispersionWeight = eps; |
---|
74 | end |
---|
75 | |
---|
76 | % Weight the dispersion |
---|
77 | Mstd = [Mstd [Xstd/LocoFlags.HorizontalDispersionWeight; Ystd/LocoFlags.VerticalDispersionWeight]]; |
---|
78 | Mmeas = [Mmeas [EtaX; EtaY]]; |
---|
79 | end |
---|
80 | |
---|
81 | |
---|
82 | % Convert to a column vector |
---|
83 | Mstd = Mstd(:); |
---|
84 | Mmeas = Mmeas(:); |
---|
85 | |
---|
86 | |
---|
87 | % Build the corrector magnet data structures to be used with locoresponsematrix |
---|
88 | CMDataRM.FamName = CMData.FamName; |
---|
89 | CMDataRM.HCMIndex = CMData.HCMIndex(CMData.HCMGoodDataIndex); |
---|
90 | CMDataRM.VCMIndex = CMData.VCMIndex(CMData.VCMGoodDataIndex); |
---|
91 | CMDataRM.HCMKicks = CMData.HCMKicks(CMData.HCMGoodDataIndex); |
---|
92 | CMDataRM.VCMKicks = CMData.VCMKicks(CMData.VCMGoodDataIndex); |
---|
93 | CMDataRM.HCMCoupling = CMData.HCMCoupling(CMData.HCMGoodDataIndex); |
---|
94 | CMDataRM.VCMCoupling = CMData.VCMCoupling(CMData.VCMGoodDataIndex); |
---|
95 | CMDataRM.HCMEnergyShift = CMData.HCMEnergyShift(CMData.HCMGoodDataIndex); |
---|
96 | CMDataRM.VCMEnergyShift = CMData.VCMEnergyShift(CMData.VCMGoodDataIndex); |
---|
97 | |
---|
98 | % Compute the new model response matrix with dispersion for saving |
---|
99 | %fprintf(' Computing final response matrix (after fit) (%s, %s) ... ', LocoFlags.ResponseMatrixCalculator, LocoFlags.ClosedOrbitType); tic |
---|
100 | CMDataRM.HCMKicks = CMData.HCMKicks(CMData.HCMGoodDataIndex); |
---|
101 | CMDataRM.VCMKicks = CMData.VCMKicks(CMData.VCMGoodDataIndex); |
---|
102 | CMDataRM.HCMCoupling = CMData.HCMCoupling(CMData.HCMGoodDataIndex); |
---|
103 | CMDataRM.VCMCoupling = CMData.VCMCoupling(CMData.VCMGoodDataIndex); |
---|
104 | warning off; |
---|
105 | lastwarn(''); |
---|
106 | |
---|
107 | %modify RINGData |
---|
108 | LocoValues = LocoValues(:); % Force a column vector |
---|
109 | for i = 1:length(LocoParams) |
---|
110 | % Compute the response matrix with the parameter change |
---|
111 | RINGData = locosetlatticeparam(RINGData, LocoParams{i}, LocoValues(i)); |
---|
112 | end |
---|
113 | |
---|
114 | if isempty(FitParameters.DeltaRF) |
---|
115 | Mmodel = locoresponsematrix(RINGData, BPMData, CMDataRM, LocoFlags); |
---|
116 | else |
---|
117 | Mmodel = locoresponsematrix(RINGData, BPMData, CMDataRM, LocoFlags, 'RF', FitParameters.DeltaRF); |
---|
118 | end |
---|
119 | warning on; |
---|
120 | %fprintf('%f seconds. \n',toc); |
---|
121 | % if ~isempty(lastwarn) |
---|
122 | % fprintf('\n Warning computing the final response matrix:\n %s\n', lastwarn); |
---|
123 | % fprintf( ' Check the final values of the fits to make sure they are in a reasonable range for\n'); |
---|
124 | % fprintf( ' this accelerator. Check the input data and/or reduce the number of singular values.\n\n'); |
---|
125 | % end |
---|
126 | |
---|
127 | % To remove the off-diagonal part of the A matrix find the index vector, iNoCoupling, of rows to keep |
---|
128 | if strcmpi((CouplingFlag),'no') |
---|
129 | CF = [ ones(NHBPM,NHCM) zeros(NHBPM,NVCM); |
---|
130 | zeros(NVBPM,NHCM) ones(NVBPM,NVCM)]; |
---|
131 | |
---|
132 | % Keep the dispersion |
---|
133 | if strcmpi((LocoFlags.Dispersion),'yes') |
---|
134 | % Keep the horizontal and vertical part of the "dispersion" orbit |
---|
135 | CF = [CF [2*ones(NHBPM,1); 3*ones(NVBPM,1)]]; % Make zeros to ignor dispersion |
---|
136 | end |
---|
137 | |
---|
138 | CF = CF(:); |
---|
139 | iNoCoupling = find(CF > 0); % Rows of A to keep when ignoring coupling |
---|
140 | %iHorizontalDispersion = find(CF == 2); % Rows of A corresponding to horizontal dispersion |
---|
141 | %iVerticalDispersion = find(CF == 3); % Rows of A corresponding to vertical dispersion |
---|
142 | clear CF |
---|
143 | else |
---|
144 | if strcmpi((LocoFlags.Dispersion),'yes') |
---|
145 | iNoCoupling = (1:(NVBPM+NHBPM)*(NHCM+NVCM+1))'; |
---|
146 | else |
---|
147 | iNoCoupling = (1:(NVBPM+NHBPM)*(NHCM+NVCM))'; |
---|
148 | end |
---|
149 | end |
---|
150 | |
---|
151 | % Rotate Mmodel and remove BPMs not in the measured response matrix |
---|
152 | C11 = ones(length(BPMData.BPMIndex),1); |
---|
153 | C11(BPMData.HBPMIndex(BPMData.HBPMGoodDataIndex)) = BPMData.HBPMGain(BPMData.HBPMGoodDataIndex); |
---|
154 | |
---|
155 | C12 = zeros(length(BPMData.BPMIndex),1); |
---|
156 | C12(BPMData.HBPMIndex(BPMData.HBPMGoodDataIndex)) = BPMData.HBPMCoupling(BPMData.HBPMGoodDataIndex); |
---|
157 | |
---|
158 | C21 = zeros(length(BPMData.BPMIndex),1); |
---|
159 | C21(BPMData.VBPMIndex(BPMData.VBPMGoodDataIndex)) = BPMData.VBPMCoupling(BPMData.VBPMGoodDataIndex); |
---|
160 | |
---|
161 | C22 = ones(length(BPMData.BPMIndex),1); |
---|
162 | C22(BPMData.VBPMIndex(BPMData.VBPMGoodDataIndex)) = BPMData.VBPMGain(BPMData.VBPMGoodDataIndex); |
---|
163 | |
---|
164 | C = [diag(C11) diag(C12) |
---|
165 | diag(C21) diag(C22)]; |
---|
166 | clear C11 C12 C21 C22 |
---|
167 | |
---|
168 | Mmodel = C * Mmodel; |
---|
169 | Mmodel = Mmodel(BPMIndexShort, :); |
---|
170 | |
---|
171 | |
---|
172 | % Compute chi-squared based on new model |
---|
173 | Mmeas = LocoMeasData.M; |
---|
174 | Mmeas = Mmeas([BPMData.HBPMGoodDataIndex length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex], [CMData.HCMGoodDataIndex length(CMData.HCMIndex)+CMData.VCMGoodDataIndex]); |
---|
175 | |
---|
176 | Mstd = LocoMeasData.BPMSTD * ones(1,size(LocoMeasData.M,2)); |
---|
177 | Mstd = Mstd ([BPMData.HBPMGoodDataIndex length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex], [CMData.HCMGoodDataIndex length(CMData.HCMIndex)+CMData.VCMGoodDataIndex]); |
---|
178 | |
---|
179 | Xstd = LocoMeasData.BPMSTD(BPMData.HBPMGoodDataIndex); |
---|
180 | Ystd = LocoMeasData.BPMSTD(length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex); |
---|
181 | |
---|
182 | |
---|
183 | % When using the fixed momentum response matrix calculator, the merit function becomes: |
---|
184 | % Merit = Mmeas_ij - Mmod_ij - Dp/p_j * eta_i |
---|
185 | % where eta_i is the measured eta (not the model eta) |
---|
186 | % This is done by changing Mmodel to (Mmodel_ij + Dp/p_j * eta_i) |
---|
187 | %if strcmpi((CMData.FitHCMEnergyShift),'yes') | strcmpi((CMData.FitVCMEnergyShift),'yes') |
---|
188 | if strcmpi((LocoFlags.ClosedOrbitType), 'fixedmomentum') |
---|
189 | HCMEnergyShift = CMData.HCMEnergyShift(CMData.HCMGoodDataIndex); |
---|
190 | VCMEnergyShift = CMData.VCMEnergyShift(CMData.VCMGoodDataIndex); |
---|
191 | |
---|
192 | if ~exist('AlphaMCF') |
---|
193 | AlphaMCF = locomcf(RINGData); |
---|
194 | EtaXmcf = -AlphaMCF * LocoMeasData.RF * LocoMeasData.Eta(BPMData.HBPMGoodDataIndex) / LocoMeasData.DeltaRF; |
---|
195 | EtaYmcf = -AlphaMCF * LocoMeasData.RF * LocoMeasData.Eta(length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex) / LocoMeasData.DeltaRF; |
---|
196 | end |
---|
197 | |
---|
198 | for i = 1:length(HCMEnergyShift) |
---|
199 | Mmodel(:,i) = Mmodel(:,i) + HCMEnergyShift(i) * [EtaXmcf; EtaYmcf]; |
---|
200 | end |
---|
201 | |
---|
202 | for i = 1:length(VCMEnergyShift) |
---|
203 | Mmodel(:,NHCM+i) = Mmodel(:,NHCM+i) + VCMEnergyShift(i) * [EtaXmcf; EtaYmcf]; |
---|
204 | end |
---|
205 | end |
---|
206 | |
---|
207 | Mstd = Mstd(:); |
---|
208 | Mmeas = Mmeas(:); |
---|
209 | if strcmpi((LocoFlags.Dispersion),'yes') |
---|
210 | EtaX = LocoMeasData.Eta(BPMData.HBPMGoodDataIndex); |
---|
211 | EtaY = LocoMeasData.Eta(length(BPMData.HBPMIndex)+BPMData.VBPMGoodDataIndex); |
---|
212 | |
---|
213 | Mstd = [Mstd; [Xstd; Ystd]]; |
---|
214 | Mmeas = [Mmeas; [EtaX; EtaY]]; |
---|
215 | else |
---|
216 | if ~isempty(FitParameters.DeltaRF) |
---|
217 | Mmodel = Mmodel(:,1:end-1); |
---|
218 | end |
---|
219 | end |
---|
220 | Mmodel = Mmodel(:); |
---|
221 | |
---|
222 | % Combine the Mmodel outliers and the Eta outliers |
---|
223 | if strcmpi((LocoFlags.Dispersion),'yes') |
---|
224 | iOutliers = [LocoModel.OutlierIndex, LocoModel.EtaOutlierIndex + ((NHBPM+NVBPM)*(NHCM+NVCM))]; |
---|
225 | else |
---|
226 | iOutliers = LocoModel.OutlierIndex; |
---|
227 | end |
---|
228 | |
---|
229 | % Outliers are referenced to the coupled model |
---|
230 | % Mark the outliers with NaN |
---|
231 | Mmeas(iOutliers) = NaN; |
---|
232 | Mmodel(iOutliers) = NaN; |
---|
233 | Mstd(iOutliers) = NaN; |
---|
234 | |
---|
235 | % Remove coupling rows |
---|
236 | if strcmpi((CouplingFlag),'no') |
---|
237 | Mmodel = Mmodel(iNoCoupling); |
---|
238 | Mmeas = Mmeas(iNoCoupling); |
---|
239 | Mstd = Mstd(iNoCoupling); |
---|
240 | end |
---|
241 | |
---|
242 | % Remove the outliers |
---|
243 | Mmeas(find(isnan(Mmeas))) = []; |
---|
244 | Mmodel(find(isnan(Mmodel))) = []; |
---|
245 | Mstd(find(isnan(Mstd))) = []; |
---|
246 | |
---|
247 | |
---|
248 | NumberOfFitParameters = 0; |
---|
249 | %count the number of fit paramters |
---|
250 | % Horizontal BPM gains |
---|
251 | if strcmpi((BPMData.FitGains),'yes') |
---|
252 | NumberOfFitParameters = NumberOfFitParameters + length(BPMData.HBPMGoodDataIndex); |
---|
253 | end |
---|
254 | |
---|
255 | % Horizontal BPM coupling |
---|
256 | if strcmpi((BPMData.FitCoupling),'yes') |
---|
257 | NumberOfFitParameters = NumberOfFitParameters + length(BPMData.HBPMGoodDataIndex); |
---|
258 | end |
---|
259 | |
---|
260 | % Vertical BPM coupling |
---|
261 | if strcmpi((BPMData.FitCoupling),'yes') |
---|
262 | NumberOfFitParameters = NumberOfFitParameters + length(BPMData.VBPMGoodDataIndex); |
---|
263 | end |
---|
264 | |
---|
265 | % Vertical BPM gains |
---|
266 | if strcmpi((BPMData.FitGains),'yes') |
---|
267 | NumberOfFitParameters = NumberOfFitParameters + length(BPMData.VBPMGoodDataIndex); |
---|
268 | end |
---|
269 | |
---|
270 | % Corrector magnet gains |
---|
271 | if strcmpi((CMData.FitKicks),'yes') |
---|
272 | NumberOfFitParameters = NumberOfFitParameters + length(CMData.HCMGoodDataIndex); |
---|
273 | end |
---|
274 | |
---|
275 | if strcmpi((CMData.FitKicks),'yes') |
---|
276 | NumberOfFitParameters = NumberOfFitParameters + length(CMData.VCMGoodDataIndex); |
---|
277 | end |
---|
278 | |
---|
279 | % Corrector magnet coupling |
---|
280 | if strcmpi((CMData.FitCoupling),'yes') |
---|
281 | NumberOfFitParameters = NumberOfFitParameters + length(CMData.HCMGoodDataIndex); |
---|
282 | end |
---|
283 | |
---|
284 | if strcmpi((CMData.FitCoupling),'yes') |
---|
285 | NumberOfFitParameters = NumberOfFitParameters + length(CMData.VCMGoodDataIndex); |
---|
286 | end |
---|
287 | |
---|
288 | % Corrector magnet energy shifts |
---|
289 | if strcmpi((CMData.FitHCMEnergyShift),'yes') |
---|
290 | NumberOfFitParameters = NumberOfFitParameters + length(CMData.HCMGoodDataIndex); |
---|
291 | end |
---|
292 | if strcmpi((CMData.FitVCMEnergyShift),'yes') |
---|
293 | NumberOfFitParameters = NumberOfFitParameters + length(CMData.VCMGoodDataIndex); |
---|
294 | end |
---|
295 | |
---|
296 | % RF Frequency parameter fit |
---|
297 | if strcmpi((FitParameters.FitRFFrequency),'yes') |
---|
298 | NumberOfFitParameters = NumberOfFitParameters + 1; |
---|
299 | end |
---|
300 | |
---|
301 | % The rest of the parameter fits |
---|
302 | NumberOfFitParameters = NumberOfFitParameters + length(FitParameters.Values); |
---|
303 | |
---|
304 | |
---|
305 | %ChiSquare = sum(((Mmeas - Mmodel) ./ Mstd) .^ 2) / length(Mstd); |
---|
306 | ChiSquare = sum(((Mmeas - Mmodel) ./ Mstd) .^ 2) / (length(Mstd)-NumberOfFitParameters); % mean e'*e = sigma*(n-k) |
---|
307 | % fprintf(' Chi-square/D.O.F. = %f (N=%d, K=%d) (computed from final response matrix)\n\n', ChiSquare, length(Mstd), NumberOfFitParameters); |
---|
308 | LocoModel.ChiSquare = ChiSquare; |
---|
309 | |
---|
310 | |
---|
311 | % Unit conversions (back to LOCO units) |
---|
312 | CMData.HCMKicks = 1000*CMData.HCMKicks; % radian to milliradians |
---|
313 | CMData.VCMKicks = 1000*CMData.VCMKicks; % radian to milliradians |
---|
314 | CMData.HCMKicksSTD = 1000*CMData.HCMKicksSTD; % radian to milliradians |
---|
315 | CMData.VCMKicksSTD = 1000*CMData.VCMKicksSTD; % radian to milliradians |
---|
316 | LocoModel.M = 1000*LocoModel.M; % meters to millimeters |
---|
317 | LocoModel.Eta = 1000*LocoModel.Eta; % meters to millimeters |
---|