def calc_chromatic_beating(self): """ Calculate the Chromatic Beating Eq. 36 in [#FranchiAnalyticformulasrapid2017]_ """ tw = self.twiss_df res = self._results_df phs_adv = self.get_phase_adv() if 'CHROMX' not in res: self._calc_chromatic_term() LOG.debug("Calculating Chromatic Beating") with timeit(lambda t: LOG.debug(" Time needed: {:f}".format(t))): chromx = res['CHROMX'].dropna() chromy = res['CHROMY'].dropna() res['DBEATX'] = self._chromatic_beating( chromx, tau(phs_adv['X'].loc[chromx.index, :], tw.Q1), tw.Q1).transpose() - 1 res['DBEATY'] = -self._chromatic_beating( chromy, tau(phs_adv['Y'].loc[chromy.index, :], tw.Q2), tw.Q2).transpose() - 1 LOG.debug(" Pk2Pk chromatic beating DBEATX: {:g}".format( res['DBEATX'].max() - res['DBEATX'].min())) LOG.debug(" Pk2Pk chromatic beating DBEATY: {:g}".format( res['DBEATY'].max() - res['DBEATY'].min())) self._log_added('DBEATX', 'DBEATY')
def _calc_beta_response(self): """ Response Matrix for delta beta. Eq. A35 -> Eq. B45 in [#FranchiAnalyticformulasrapid2017]_ """ LOG.debug("Calculate Beta Response Matrix") with timeit(lambda t: LOG.debug(" Time needed: {:f}s".format(t))): tw = self._twiss adv = self._phase_advances el_out = self._elements_out k1_el = self._elements_in["K1L"] dbeta = dict.fromkeys(["X", "Y"]) for plane in ["X", "Y"]: col_beta = "BET" + plane q = tw.Q1 if plane == "X" else tw.Q2 coeff_sign = -1 if plane == "X" else 1 pi2tau = 2 * np.pi * tau(adv[plane].loc[k1_el, el_out], q) dbeta[plane] = tfs.TfsDataFrame( tw.loc[el_out, col_beta].values[None, :] * tw.loc[k1_el, col_beta].values[:, None] * np.cos(2 * pi2tau.values) * (coeff_sign / (2 * np.sin(2 * np.pi * q))), index=k1_el, columns=el_out).transpose() return dict_mul(self._direction, dbeta)
def _calc_dispersion_response(self): """ Response Matrix for delta normalized dispersion Eq. 25-27 in [#FranchiAnalyticformulasrapid2017]_ But w/o the assumtion :math:`\delta K_1 = 0` from Appendix B.1 """ LOG.debug("Calculate Dispersion Response Matrix") with timeit(lambda t: LOG.debug(" Time needed: {:f}".format(t))): tw = self._twiss adv = self._phase_advances el_out = self._elements_out els_in = self._elements_in sign_map = { "X": {"K0L": 1, "K1L": -1, "K1SL": 1, }, "Y": {"K0SL": -1, "K1L": 1, "K1SL": 1, }, } col_disp_map = { "X": {"K1L": "DX", "K1SL": "DY", }, "Y": {"K1L": "DY", "K1SL": "DX", }, } q_map = {"X": tw.Q1, "Y": tw.Q2} disp_resp = dict.fromkeys(["{p:s}_{t:s}".format(p=p, t=t) for p in sign_map for t in sign_map[p]]) for plane in sign_map: q = q_map[plane] col_beta = "BET{}".format(plane) el_types = sign_map[plane].keys() els_per_type = [els_in[el_type] for el_type in el_types] coeff = np.sqrt(tw.loc[el_out, col_beta].values) / (2 * np.sin(np.pi * q)) for el_in, el_type in zip(els_per_type, el_types): coeff_sign = sign_map[plane][el_type] out_str = "{p:s}_{t:s}".format(p=plane, t=el_type) if len(el_in): pi2tau = 2 * np.pi * tau(adv[plane].loc[el_in, el_out], q) bet_term = np.sqrt(tw.loc[el_in, col_beta]) try: col_disp = col_disp_map[plane][el_type] except KeyError: pass else: bet_term *= tw.loc[el_in, col_disp] disp_resp[out_str] = (coeff_sign * coeff[None, :] * bet_term[:, None] * np.cos(pi2tau) ).transpose() else: LOG.debug( " No '{:s}' variables found. ".format(el_type) + "Dispersion Response '{:s}' will be empty.".format(out_str)) disp_resp[out_str] = tfs.TfsDataFrame(None, index=el_out) return dict_mul(self._direction, disp_resp)
def _calc_phase_response(self): """ Response Matrix for delta DPhi. Eq. 28 in [#FranchiAnalyticformulasrapid2017]_ Reduced to only delta phase. --> w = 0: DPhi(z,j) = DPhi(x, 0->j) This calculation could also be achieved by applying np.cumsum to the DataFrames of _calc_phase_adv_response() (tested!), but _calc_phase_response() is about 4x faster. """ LOG.debug("Calculate Phase Response Matrix") with timeit(lambda t: LOG.debug(" Time needed: {:f}s".format(t))): tw = self._twiss adv = self._phase_advances k1_el = self._elements_in["K1L"] el_out = self._elements_out if len(k1_el) > 0: dmu = dict.fromkeys(["X", "Y"]) pi = tfs.TfsDataFrame( tw['S'][:, None] < tw['S'][None, :], # pi(i,j) = s(i) < s(j) index=tw.index, columns=tw.index, dtype=int) pi_term = pi.loc[k1_el, el_out].values for plane in ["X", "Y"]: col_beta = "BET" + plane q = tw.Q1 if plane == "X" else tw.Q2 coeff_sign = 1 if plane == "X" else -1 pi2tau = 2 * np.pi * tau( adv[plane].loc[k1_el, [DUMMY_ID] + el_out], q) brackets = (2 * pi_term + ( (np.sin(2 * pi2tau.loc[:, el_out].values) - np.sin(2 * pi2tau.loc[:, DUMMY_ID].values[:, None])) / np.sin(2 * np.pi * q))) dmu[plane] = tfs.TfsDataFrame( tw.loc[k1_el, col_beta].values[:, None] * brackets * (coeff_sign / (8 * np.pi)), index=k1_el, columns=el_out).transpose() else: LOG.debug( " No 'K1L' variables found. Phase Response will be empty." ) dmu = { "X": tfs.TfsDataFrame(None, index=el_out), "Y": tfs.TfsDataFrame(None, index=el_out) } return dict_mul(self._direction, dmu)
def _calc_phase_advance_response(self): """ Response Matrix for delta DPhi. Eq. 28 in [#FranchiAnalyticformulasrapid2017]_ Reduced to only phase advances between consecutive elements, as the 3D-Matrix of all elements exceeds memory space (~11000^3 = 1331 Giga Elements) --> w = j-1: DPhi(z,j) = DPhi(x, (j-1)->j) """ LOG.debug("Calculate Phase Advance Response Matrix") with timeit(lambda t: LOG.debug(" Time needed: {:f}s".format(t))): tw = self._twiss adv = self._phase_advances k1_el = self._elements_in["K1L"] el_out_all = [DUMMY_ID] + self._elements_out # Add MU[XY] = 0.0 to the start el_out = el_out_all[1:] # in these we are actually interested el_out_mm = el_out_all[0:-1] # elements-- if len(k1_el) > 0: dmu = dict.fromkeys(["X", "Y"]) pi = tfs.TfsDataFrame(tw['S'][:, None] < tw['S'][None, :], # pi(i,j) = s(i) < s(j) index=tw.index, columns=tw.index, dtype=int) pi_term = (pi.loc[k1_el, el_out].values - pi.loc[k1_el, el_out_mm].values + np.diag(pi.loc[el_out, el_out_mm].values)[None, :]) for plane in ["X", "Y"]: col_beta = "BET" + plane q = tw.Q1 if plane == "X" else tw.Q2 coeff_sign = 1 if plane == "X" else -1 pi2tau = 2 * np.pi * tau(adv[plane].loc[k1_el, el_out_all], q) brackets = (2 * pi_term + ((np.sin(2 * pi2tau.loc[:, el_out].values) - np.sin(2 * pi2tau.loc[:, el_out_mm].values)) / np.sin(2 * np.pi * q) )) dmu[plane] = tfs.TfsDataFrame( tw.loc[k1_el, col_beta].values[:, None] * brackets * (coeff_sign / (8 * np.pi)), index=k1_el, columns=el_out).transpose() else: LOG.debug(" No 'K1L' variables found. Phase Response will be empty.") dmu = {"X": tfs.TfsDataFrame(None, index=el_out), "Y": tfs.TfsDataFrame(None, index=el_out)} return dict_mul(self._direction, dmu)
def _calc_dispersion_response(self): """ Response Matrix for delta dispersion Eq. 25-27 in [#FranchiAnalyticformulasrapid2017]_ """ LOG.debug("Calculate Dispersion Response Matrix") with timeit(lambda t: LOG.debug(" Time needed: {:f}".format(t))): tw = self._twiss adv = self._phase_advances el_out = self._elements_out els_in = self._elements_in disp_resp = dict.fromkeys(["X_K0L", "X_K1SL", "Y_K0SL", "Y_K1SL"]) for plane in ["X", "Y"]: q = tw.Q1 if plane == "X" else tw.Q2 type_plane = ("K0L" if plane == "X" else "K0SL", "K1SL") el_in_plane = (els_in[type_plane[0]], els_in[type_plane[1]]) col_beta = "BET" + plane col_disp = "DY" if plane == "X" else "DX" if any((len(el_in_plane[0]), len(el_in_plane[1]))): coeff = np.sqrt(tw.loc[el_out, col_beta].values) / ( 2 * np.sin(np.pi * q)) for el_in, el_type in zip(el_in_plane, type_plane): coeff_sign = -1 if el_type == "K0SL" else 1 out_str = "{p:s}_{t:s}".format(p=plane, t=el_type) if len(el_in): pi2tau = 2 * np.pi * tau(adv[plane].loc[el_in, el_out], q) bet_term = np.sqrt(tw.loc[el_in, col_beta].values) if el_type == "K1SL": bet_term *= tw.loc[el_in, col_disp].values disp_resp[out_str] = tfs.TfsDataFrame( coeff_sign * coeff[None, :] * bet_term[:, None] * np.cos(pi2tau), index=el_in, columns=el_out).transpose() else: LOG.debug( " No '{:s}' variables found. ".format(el_type) + "Dispersion Response '{:s}' will be empty.".format( out_str)) disp_resp[out_str] = tfs.TfsDataFrame(None, index=el_out) return dict_mul(self._direction, disp_resp)
def calc_linear_dispersion(self, bpms_only=False): """ Calculate the Linear Disperion. Eq. 24 in [#FranchiAnalyticformulasrapid2017]_ """ tw = self.twiss_df phs_adv = self.get_phase_adv() res = self._results_df coeff_fun = self._linear_dispersion_coeff sum_fun = self._linear_dispersion_sum # Calculate LOG.debug("Calculate Linear Dispersion") with timeit(lambda t: LOG.debug(" Time needed: {:f}".format(t))): # sources k0_mask = tw['K0L'] != 0 k0s_mask = tw['K0SL'] != 0 k1s_mask = tw['K1SL'] != 0 mx_mask = k0_mask | k1s_mask # magnets contributing to Dx,j (-> Dy,m) my_mask = k0s_mask | k1s_mask # magnets contributing to Dy,j (-> Dx,m) if not any(mx_mask | my_mask): LOG.warning( " No linear dispersion contributions found. Values will be NaN." ) res['DX'] = np.nan res['DY'] = np.nan return # results if bpms_only: res_mask = self._elements["BPM"] else: res_mask = np.ones(res.shape[0], dtype=bool) # create temporary DataFrame for magnets with coefficients already in place df = tfs.TfsDataFrame(index=tw.index).join( coeff_fun(tw.loc[:, 'BETX'], tw.Q1)).join(coeff_fun(tw.loc[:, 'BETY'], tw.Q2)) df.columns = ['COEFFX', 'COEFFY'] LOG.debug(" Calculate uncoupled linear dispersion") df.loc[my_mask, 'DX'] = df.loc[my_mask, 'COEFFX'] * \ sum_fun(tw.loc[mx_mask, 'K0L'], 0, 0, tw.loc[mx_mask, 'BETX'], tau(phs_adv['X'].loc[mx_mask, my_mask], tw.Q1) ).transpose() df.loc[mx_mask, 'DY'] = df.loc[mx_mask, 'COEFFY'] * \ sum_fun(-tw.loc[my_mask, 'K0SL'], # MINUS! 0, 0, tw.loc[my_mask, 'BETY'], tau(phs_adv['Y'].loc[my_mask, mx_mask], tw.Q2) ).transpose() LOG.debug(" Calculate full linear dispersion values") res.loc[res_mask, 'DX'] = df.loc[res_mask, 'COEFFX'] * \ sum_fun(tw.loc[mx_mask, 'K0L'], tw.loc[mx_mask, 'K1SL'], df.loc[mx_mask, 'DY'], tw.loc[mx_mask, 'BETX'], tau(phs_adv['X'].loc[mx_mask, res_mask], tw.Q1) ).transpose() res.loc[res_mask, 'DY'] = df.loc[res_mask, 'COEFFY'] * \ sum_fun(-tw.loc[my_mask, 'K0SL'], # MINUS! tw.loc[my_mask, 'K1SL'], df.loc[my_mask, 'DX'], tw.loc[my_mask, 'BETY'], tau(phs_adv['Y'].loc[my_mask, res_mask], tw.Q2) ).transpose() LOG.debug(" Average linear dispersion Dx: {:g}".format( np.mean(res['DX']))) LOG.debug(" Average linear dispersion Dy: {:g}".format( np.mean(res['DY']))) self._log_added('DX', 'DY')