|
| 1 | +import numpy as np |
| 2 | +import at |
| 3 | + |
| 4 | +def phase_advance_correction(ring, bpm_indices, elements_indices, dkick, cut, Px=None, Py=None, Etax=None): |
| 5 | + """ |
| 6 | + Perform phase advance and horizontal dispersion correction on the given ring. |
| 7 | + |
| 8 | + Parameters: |
| 9 | + dkick: Change in quadrupole strength for response matrix calculation. |
| 10 | + cut: number of kept singular values |
| 11 | + Px, Py, Etax: response matrices for horizontal and vertical phase advances and dispersion. |
| 12 | + If not provided, they will be calculated. |
| 13 | + |
| 14 | + Returns: |
| 15 | + corrected ring |
| 16 | + """ |
| 17 | + # Initial Twiss parameters |
| 18 | + _, _, twiss_err0 = at.get_optics(ring, bpm_indices) |
| 19 | + elemdata0, beamdata, elemdata = at.get_optics(ring, bpm_indices) |
| 20 | + mux0 = elemdata.mu[:, 0] / (2 * np.pi) |
| 21 | + muy0 = elemdata.mu[:, 1] / (2 * np.pi) |
| 22 | + Eta_x0 = elemdata.dispersion[:, 0] |
| 23 | + |
| 24 | + # Calculate Response Matrix if not provided |
| 25 | + if Px is None or Py is None or Etax is None: |
| 26 | + Px, Py, Etax = calculate_rm(dkick, ring, elements_indices, bpm_indices, mux0, muy0, Eta_x0) |
| 27 | + |
| 28 | + response_matrix = np.hstack((Px, Py, Etax)) |
| 29 | + |
| 30 | + elemdata0, beamdata, elemdata = at.get_optics(ring, bpm_indices) |
| 31 | + mux = elemdata.mu[:, 0] / (2 * np.pi) |
| 32 | + muy = elemdata.mu[:, 1] / (2 * np.pi) |
| 33 | + Eta_xx = elemdata.dispersion[:, 0] |
| 34 | + |
| 35 | + measurement = np.concatenate((mux - mux0, muy - muy0, Eta_xx - Eta_x0), axis=0) |
| 36 | + |
| 37 | + s = np.linalg.svd(response_matrix.T, compute_uv=False) |
| 38 | + system_solution = np.linalg.pinv(response_matrix.T, rcond=s[cut - 1] / s[0]) @ -measurement |
| 39 | + ring = apply_correction(ring, system_solution, elements_indices) |
| 40 | + |
| 41 | + return ring |
| 42 | + |
| 43 | + |
| 44 | +def calculate_rm(dkick, ring, elements_indices, bpm_indices, mux0, muy0, Eta_x0): |
| 45 | + """ |
| 46 | + Returns: |
| 47 | + Px, Py, Etax: Response matrices for horizontal and vertical phase advances and dispersion. |
| 48 | + """ |
| 49 | + px =[] |
| 50 | + py =[] |
| 51 | + etax = [] |
| 52 | + |
| 53 | + for index in elements_indices: |
| 54 | + original_setting = ring[index].PolynomB[1] |
| 55 | + |
| 56 | + ring[index].PolynomB[1] += dkick |
| 57 | + _, _, elemdata = at.get_optics(ring, bpm_indices) |
| 58 | + |
| 59 | + mux = elemdata.mu[:, 0] / (2 * np.pi) |
| 60 | + muy = elemdata.mu[:, 1] / (2 * np.pi) |
| 61 | + Eta_x = elemdata.dispersion[:, 0] |
| 62 | + |
| 63 | + px.append((mux - mux0) / dkick) |
| 64 | + py.append((muy - muy0) / dkick) |
| 65 | + etax.append((Eta_x - Eta_x0) / dkick) |
| 66 | + |
| 67 | + ring[index].PolynomB[1] = original_setting |
| 68 | + |
| 69 | + Px = np.squeeze(np.array(px)) |
| 70 | + Py = np.squeeze(np.array(py)) |
| 71 | + Etax = np.squeeze(np.array(etax)) |
| 72 | + |
| 73 | + return Px, Py, Etax |
| 74 | + |
| 75 | + |
| 76 | +def apply_correction(ring, corrections, elements_indices): |
| 77 | + for i, index in enumerate(elements_indices): |
| 78 | + ring[index].PolynomB[1] += corrections[i] |
| 79 | + return ring |
0 commit comments