@@ -89,15 +89,15 @@ def loco_correction_lm(initial_guess0, orm_model, orm_measured, Jn, lengths, inc
8989 return result .x
9090
9191
92- def loco_correction_ng (initial_guess0 , orm_model , orm_measured , J , lengths , including_fit_parameters , s_cut , weights = 1 ):
92+ def loco_correction_ng (initial_guess0 , orm_model , orm_measured , J , lengths , including_fit_parameters , s_cut , weights = 1 , LM_lambda = 0 ):
9393 initial_guess = initial_guess0 .copy ()
9494 mask = _get_parameters_mask (including_fit_parameters , lengths )
9595 residuals = objective (initial_guess [mask ], orm_measured - orm_model , J [mask , :, :], weights )
9696 r = residuals .reshape (np .transpose (orm_model ).shape )
9797 t2 = np .zeros ([len (initial_guess [mask ]), 1 ])
9898 for i in range (len (initial_guess [mask ])):
9999 t2 [i ] = np .sum (np .dot (np .dot (J [i ].T , weights ), r .T ))
100- return get_inverse (J [mask , :, :], t2 , s_cut , weights )
100+ return get_inverse (J [mask , :, :], t2 , s_cut , weights , LM_lambda = LM_lambda )
101101
102102
103103def objective (masked_params , orm_residuals , masked_jacobian , weights ):
@@ -157,10 +157,29 @@ def select_equally_spaced_elements(total_elements, num_elements):
157157 return total_elements [::step ]
158158
159159
160- def get_inverse (jacobian , B , s_cut , weights , plot = False ):
160+ def get_inverse (jacobian , B , s_cut , weights , LM_lambda = 0 , plot = False ):
161+ """
162+ Calculates $(J^t J + \lambda diag(J^t J))^{-1} J^t r_0$ using a modified
163+ version of the Levenberg-Marquardt method. More information at p.114 of
164+ https://inis.iaea.org/collection/NCLCollectionStore/_Public/54/003/54003559.pdf
165+
166+ Args:
167+ jacobian: jacobian matrix obtained from calculate_jacobian()
168+ bpm_ords: array of element indices of registered BPMs for which to calculate readings
169+ (for convenience, otherwise `SC.ORD.BPM` is used)
170+ s_cut: number of kept singular values when inverting the matrix
171+ weights: weights applied to the elements of the jacobian
172+ LM_lambda: Levenberg-Marquardt lambda parameter. If LM_lambda=0, the
173+ function is equivalent to the Gauss-Newton method
174+ plot: boolean flag to plot the resulting inverse matrix
175+
176+ Returns:
177+ Array of correction values of the same size as B.
178+ """
161179 n_resp_mats = len (jacobian )
162- sum_corr = np .sum (jacobian , axis = 2 ) # Sum over i and j for all planes
163- matrix = np .dot (np .dot (sum_corr , weights ), sum_corr .T )
180+ Jt = np .sum (jacobian , axis = 2 ) # Sum over i and j for all planes
181+ Jt_dot_J = np .dot (np .dot (Jt , weights ), Jt .T )
182+ matrix = Jt_dot_J + LM_lambda * np .diag (np .diag (Jt_dot_J ))
164183 inv_matrix = sc_tools .pinv (matrix , num_removed = n_resp_mats - min (n_resp_mats , s_cut ), plot = plot )
165184 results = np .ravel (np .dot (inv_matrix , B ))
166185 # e = np.ravel(np.dot(matrix, results)) - np.ravel(B)
0 commit comments