def _calc_tune_response(self): """ Response vectors for Tune. Eq. 7 in [#TomasReviewlinearoptics2017]_ """ LOG.debug("Calculate Tune Response Matrix") with timeit(lambda t: LOG.debug(" Time needed: {:f}s".format(t))): tw = self._twiss k1_el = self._elements_in["K1L"] if len(k1_el) > 0: dtune = dict.fromkeys(["X", "Y"]) dtune["X"] = 1 / (4 * np.pi) * tw.loc[k1_el, ["BETX"]].transpose() dtune["X"].index = ["DQX"] dtune["Y"] = -1 / (4 * np.pi) * tw.loc[k1_el, ["BETY"]].transpose() dtune["Y"].index = ["DQY"] else: LOG.debug( " No 'K1L' variables found. Tune Response will be empty.") dtune = { "X": tfs.TfsDataFrame(None, index=["DQX"]), "Y": tfs.TfsDataFrame(None, index=["DQY"]) } return dict_mul(self._direction, dtune)
def _create_fullresponse_from_dict(var_to_twiss): """ Convert var-tfs dictionary to fullresponse dictionary """ var_to_twiss = _add_coupling(var_to_twiss) resp = pandas.Panel.from_dict(var_to_twiss) resp = resp.transpose(2, 1, 0) # After transpose e.g: resp[NDX, bpm12l1.b1, kqt3] # The magnet called "0" is no change (nominal model) resp['NDX'] = resp.xs('DX', axis=0).div(np.sqrt(resp.xs('BETX', axis=0)), axis="index") resp['NDY'] = resp.xs('DY', axis=0).div(np.sqrt(resp.xs('BETY', axis=0)), axis="index") resp['BBX'] = resp.xs('BETX', axis=0).div(resp.loc['BETX', :, '0'], axis="index") resp['BBY'] = resp.xs('BETY', axis=0).div(resp.loc['BETY', :, '0'], axis="index") resp = resp.subtract(resp.xs('0', axis=2), axis=2) # Remove difference of nominal model with itself (bunch of zeros) resp.drop('0', axis=2, inplace=True) resp = resp.div(resp.loc['incr', :, :]) with suppress_warnings( np.ComplexWarning): # raised as everything is complex-type now df = { 'MUX': resp.xs('MUX', axis=0).astype(np.float64), 'MUY': resp.xs('MUY', axis=0).astype(np.float64), 'BETX': resp.xs('BETX', axis=0).astype(np.float64), 'BETY': resp.xs('BETY', axis=0).astype(np.float64), 'BBX': resp.xs('BBX', axis=0).astype(np.float64), 'BBY': resp.xs('BBY', axis=0).astype(np.float64), 'DX': resp.xs('DX', axis=0).astype(np.float64), 'DY': resp.xs('DY', axis=0).astype(np.float64), 'NDX': resp.xs('NDX', axis=0).astype(np.float64), 'NDY': resp.xs('NDY', axis=0).astype(np.float64), "F1001R": tfs.TfsDataFrame( resp.xs('1001', axis=0).apply(np.real).astype(np.float64)), "F1001I": tfs.TfsDataFrame( resp.xs('1001', axis=0).apply(np.imag).astype(np.float64)), "F1010R": tfs.TfsDataFrame( resp.xs('1010', axis=0).apply(np.real).astype(np.float64)), "F1010I": tfs.TfsDataFrame( resp.xs('1010', axis=0).apply(np.imag).astype(np.float64)), 'Q': resp.loc[['Q1', 'Q2'], resp.major_axis[0], :].transpose().astype(np.float64), } return df
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 _get_filtered_betabeat(key, meas, model, erwg, weight, modelcut, errorcut): # Beta-beating and its error RELATIVE as shown in GUI common_bpms = meas.index.intersection(model.index) meas = meas.loc[common_bpms, :] col_val = "BET" + key[-1] col_std = "STDBET" + key[-1] col_err = 'ERRBET' + key[-1] col_mdl = "BET" + key[-1] + "MDL" # value new = tfs.TfsDataFrame(index=common_bpms) new.loc[:, 'VALUE'] = meas[col_val] # errors if col_std in new.columns.values: # Old files or k-mod new.loc[:, 'ERROR'] = np.sqrt(np.square(meas[col_err]) + np.square(meas[col_std])) else: new.loc[:, 'ERROR'] = meas[col_err] # weights new.loc[:, 'WEIGHT'] = weight if erwg: new.loc[:, 'WEIGHT'] = _get_errorbased_weights(key, new['WEIGHT'] * meas[col_mdl], new['ERROR']) # filter cuts model_filter = np.abs(new['VALUE'] - meas[col_mdl]) / meas[col_mdl] < modelcut error_filter = new['ERROR'] / meas[col_mdl] < errorcut good_bpms = model_filter & error_filter LOG.debug("Number of BPMs with {:s}: {:d}".format(key, np.sum(good_bpms))) return new.loc[good_bpms, :]
def couple_caller(func, plane): # apply() converts empty DataFrames to Series! Cast them back. # Also: take care of minus-sign convention! sign = -1 if plane[-1] == "R" else 1 part_func = np.real if plane[-1] == "R" else np.imag return sign * tfs.TfsDataFrame( func()[plane[:-1]].apply(part_func).astype(np.float64))
def map_fun(df, mapping): """ Actual mapping function """ df_map = tfs.TfsDataFrame(index=df.index, columns=mapping.keys()) for var, magnets in mapping.iteritems(): df_map[var] = df.loc[:, upper(magnets.index)].mul( magnets.values, axis="columns").sum(axis="columns") return df_map
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_coupling_response(self): """ Response Matrix for coupling. Eq. 10 in [#FranchiAnalyticformulasrapid2017]_ """ LOG.debug("Calculate Coupling 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 k1s_el = self._elements_in["K1SL"] dcoupl = dict.fromkeys(["1001", "1010"]) i2pi = 2j * np.pi phx = dphi(adv['X'].loc[k1s_el, el_out], tw.Q1).values phy = dphi(adv['Y'].loc[k1s_el, el_out], tw.Q2).values bet_term = np.sqrt(tw.loc[k1s_el, "BETX"].values * tw.loc[k1s_el, "BETY"].values) for plane in ["1001", "1010"]: phs_sign = -1 if plane == "1001" else 1 dcoupl[plane] = tfs.TfsDataFrame( bet_term[:, None] * np.exp(i2pi * (phx + phs_sign * phy)) / (4 * (1 - np.exp(i2pi * (tw.Q1 + phs_sign * tw.Q2)))), index=k1s_el, columns=el_out).transpose() return dict_mul(self._direction, dcoupl)
def _get_filtered_phases(key, meas, model, erwg, weight, modelcut, errorcut): common_bpms = meas.index.intersection(model.index) meas = meas.loc[common_bpms, :] col_val = "PHASE" + key[-1] col_err = "STDPH" + key[-1] col_mdl = "PH" + key[-1] + "MDL" # value new = tfs.TfsDataFrame(index=common_bpms) new.loc[:, "VALUE"] = meas[col_val] # errors new.loc[:, 'ERROR'] = meas[col_err] # weights new.loc[:, 'WEIGHT'] = weight if erwg: new.loc[:, 'WEIGHT'] = _get_errorbased_weights(key, new['WEIGHT'], new['ERROR']) # filter cuts error_filter = new['ERROR'] < errorcut model_filter = np.abs(new['VALUE'] - meas[col_mdl]) < modelcut new.loc[:, 'NAME2'] = meas['NAME2'] second_bpm_in = np.in1d(new['NAME2'].values, new.index.values) good_bpms = error_filter & model_filter & second_bpm_in good_bpms[-1] = False LOG.debug("Number of BPMs with {:s}: {:d}".format(key, np.sum(good_bpms))) return new.loc[good_bpms, :]
def get_delta(response, delta_k): """ Returns the deltas of :math:`response_matrix \cdot delta_k`. Args: response: Response dictionary delta_k: Pandas Series of variables and their delta-value Returns: TFS_DataFrame with elements as indices and the calculated deltas in the columns """ delta_df = tfs.TfsDataFrame(None, index=response.index) for col in response.keys(): # equivalent to .dot() but more efficient as delta_k is "sparse" if col == "Q": try: delta_q = (response[col].loc[:, delta_k.index] * delta_k).dropna(axis="columns").sum(axis="columns") except KeyError: # none of the delta_k are in DataFrame delta_q = pd.Series([0., 0.], index=["Q1", "Q2"]) delta_df.headers["QX"] = delta_q["Q1"] delta_df.headers["QY"] = delta_q["Q2"] else: try: delta_df.loc[:, col] = (response[col].loc[:, delta_k.index] * delta_k).dropna(axis="columns").sum( axis="columns") except KeyError: # none of the delta_k are in DataFrame delta_df.loc[:, col] = 0. return delta_df
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 lhc_fill_to_tfs(fill_number, keys=None, names=None): """ Extracts data for keys of fill from timber. Args: fill_number: fill number keys: list of data to extract names: dict to map keys to column names Returns: tfs pandas dataframe. """ db = pytimber.LoggingDB() t_start, t_end = get_fill_times(db, fill_number) if keys is None: keys = get_tune_and_coupling_variables(db) extract_dict = db.get(keys, t_start, t_end) out_df = tfs.TfsDataFrame() for key in keys: if extract_dict[key.upper()][1][0].size > 1: raise NotImplementedError( "Multidimensional variables are not implemented yet.") data = np.asarray(extract_dict[key.upper()]).transpose() col = names.get(key, key) key_df = tfs.TfsDataFrame(data, columns=[TIME_COL, col]).set_index(TIME_COL) out_df = out_df.merge(key_df, how="outer", left_index=True, right_index=True) out_df.headers[START_TIME] = t_start out_df.headers[END_TIME] = t_end return out_df
def _calculate_delta(resp_matrix, meas_dict, keys, vars_list, method, meth_opt): """ Get the deltas for the variables. Output is Dataframe with one column 'DELTA' and vars_list index. """ weight_vector = _join_columns('WEIGHT', meas_dict, keys) diff_vector = _join_columns('DIFF', meas_dict, keys) resp_weighted = resp_matrix.mul(weight_vector, axis="index") diff_weighted = diff_vector * weight_vector delta = _get_method_fun(method)(resp_weighted, diff_weighted, meth_opt) delta = tfs.TfsDataFrame(delta, index=vars_list, columns=["DELTA"]) update = np.dot(resp_weighted, delta["DELTA"]) _print_rms(meas_dict, diff_weighted, update) return delta
def _get_filtered_generic(key, meas, model, erwg, weight, modelcut, errorcut): common_bpms = meas.index.intersection(model.index) meas = meas.loc[common_bpms, :] # value new = tfs.TfsDataFrame(index=common_bpms) new.loc[:, "VALUE"] = meas[key] # errors if ("ERR" + key) in meas.columns.values: # usually beta if ('STD' + key) in meas.columns.values: # Old files or k-mod new['ERROR'] = np.sqrt( np.square(meas['ERR' + key].values) + np.square(meas['STD' + key].values)) else: new['ERROR'] = meas['ERR' + key] else: key2num = {'1001': '1', '1010': '2'} if key[1:-1] in key2num: # coupling new.loc[:, 'ERROR'] = meas['FWSTD' + key2num[key[1:-1]]] else: new.loc[:, 'ERROR'] = meas['STD' + key] # weights new.loc[:, 'WEIGHT'] = weight if erwg: new.loc[:, 'WEIGHT'] = _get_errorbased_weights(key, new['WEIGHT'], new['ERROR']) # filter cuts error_filter = new.loc[:, 'ERROR'].values < errorcut try: model_filter = np.abs(new.loc[:, 'VALUE'].values - meas[key + 'MDL'].values) < modelcut except KeyError: # Why is there no standard for where "MDL" is attached to the name??? model_filter = np.abs(new['VALUE'].values - meas['MDL' + key].values) < modelcut good_bpms = error_filter & model_filter LOG.debug("Number of BPMs with {:s}: {:d}".format(key, np.sum(good_bpms))) return new.loc[good_bpms, :]
def global_correction(opt, accel_opt): """ Do the global correction. Iteratively. Keyword Args: Required meas_dir: Path to the directory containing the measurement files. **Flags**: --meas_dir model_dir: Path to the dir containing the model (twiss.dat or twiss_elements.dat) to use. **Flags**: --model_dir Optional beta_file_name: Prefix of the beta file to use. E.g.: getkmodbeta **Flags**: --beta_file_name **Default**: ``getbeta`` debug: Print debug information. **Flags**: --debug **Action**: ``store_true`` eps (float): (Not implemented yet) Convergence criterion. If :math:`<|\Delta(PARAM \cdot WEIGHT)|> < \epsilon`, stop iteration. **Flags**: --eps **Default**: ``None`` errorcut (float): Reject BPMs whose error bar is higher than the corresponding input. Input in order of optics_params. **Flags**: --error_cut fullresponse_path: Path to the fullresponse binary file. If not given, calculates the response analytically. **Flags**: --fullresponse max_iter (int): Maximum number of correction re-iterations to perform. A value of `0` means the correction is calculated once (like in the old days). **Flags**: --max_iter **Default**: ``3`` method (str): Optimization method to use. (Not implemented yet) **Flags**: --method **Choices**: ['pinv'] **Default**: ``pinv`` modelcut (float): Reject BPMs whose deviation to the model is higher than the correspoding input. Input in order of optics_params. **Flags**: --model_cut optics_file: Path to the optics file to use, usually modifiers.madx. If not present will default to model_path/modifiers.madx **Flags**: --optics_file optics_params (str): List of parameters to correct upon (e.g. BBX BBY) **Flags**: --optics_params **Default**: ``['MUX', 'MUY', 'BBX', 'BBY', 'NDX', 'Q']`` output_path: Path to the directory where to write the output files, will default to the --meas input path. **Flags**: --output_dir **Default**: ``None`` svd_cut (float): Cutoff for small singular values of the pseudo inverse. (Method: 'pinv') Singular values smaller than :math:`rcond \cdot largest_singular_value` are set to zero **Flags**: --svd_cut **Default**: ``0.01`` use_errorbars: If True, it will take into account the measured errorbars in the correction. **Flags**: --use_errorbars **Action**: ``store_true`` variable_categories: List of names of the variables classes to use. **Flags**: --variables **Default**: ``['MQM', 'MQT', 'MQTL', 'MQY']`` virt_flag: If true, it will use virtual correctors. **Flags**: --virt_flag **Action**: ``store_true`` weights (float): Weights to apply to each measured quantity. Input in order of optics_params. **Flags**: --weights """ LOG.info("Starting Iterative Global Correction.") with logging_tools.DebugMode(active=opt.debug, log_file=os.path.join(opt.model_dir, "iterative_correction.log")): not_implemented_params = [k for k in opt.optics_params if k not in _get_measurement_filters()] if any(not_implemented_params): raise NotImplementedError("Correct iterative is not equipped for parameters:" "'{:s}'".format(not_implemented_params)) # ######### Preparations ######### # # check on opt opt = _check_opt(opt) meth_opt = _get_method_opt(opt) # get accelerator class accel_cls = manager.get_accel_class(accel_opt) accel_inst = accel_cls(model_dir=opt.model_dir) if opt.optics_file is not None: accel_inst.optics_file = opt.optics_file # convert numbers to dictionaries w_dict = dict(zip(opt.optics_params, opt.weights)) mcut_dict = dict(zip(opt.optics_params, opt.modelcut)) ecut_dict = dict(zip(opt.optics_params, opt.errorcut)) # read data from files vars_list = _get_varlist(accel_cls, opt.variable_categories, opt.virt_flag) optics_params, meas_dict = _get_measurment_data( opt.optics_params, opt.meas_dir, opt.beta_file_name, w_dict, ) mcut_dict = _automate_modelcut(mcut_dict, meas_dict, opt.variable_categories) if opt.fullresponse_path is not None: resp_dict = _load_fullresponse(opt.fullresponse_path, vars_list) else: resp_dict = response_twiss.create_response( accel_inst, opt.variable_categories, optics_params ) # the model in accel_inst is modified later, so save nominal model here to variables nominal_model = _maybe_add_coupling_to_model(accel_inst.get_model_tfs(), optics_params) # apply filters to data meas_dict = _filter_measurement( optics_params, meas_dict, nominal_model, opt.use_errorbars, w_dict, ecut_dict, mcut_dict ) meas_dict = _append_model_to_measurement(nominal_model, meas_dict, optics_params) resp_dict = _filter_response_index(resp_dict, meas_dict, optics_params) resp_matrix = _join_responses(resp_dict, optics_params, vars_list) # _dump(os.path.join(opt.output_path, "measurement_dict.bin"), meas_dict) delta = tfs.TfsDataFrame(0, index=vars_list, columns=["DELTA"]) # ######### Iteration Phase ######### # for iteration in range(opt.max_iter + 1): LOG.info("Correction Iteration {:d} of {:d}.".format(iteration, opt.max_iter)) # ######### Update Model and Response ######### # if iteration > 0: LOG.debug("Updating model via MADX.") corr_model_path = os.path.join(opt.output_path, "twiss_" + str(iteration) + ".dat") _create_corrected_model(corr_model_path, opt.change_params_path, accel_inst, opt.debug) corr_model_elements = tfs.read_tfs(corr_model_path, index="NAME") corr_model_elements = _maybe_add_coupling_to_model( corr_model_elements, optics_params ) corr_model = corr_model_elements.loc[tfs.get_bpms(corr_model_elements), :] meas_dict = _append_model_to_measurement(corr_model, meas_dict, optics_params) if opt.update_response: LOG.debug("Updating response.") # please look away for the next two lines. accel_inst._model = corr_model accel_inst._elements = corr_model_elements resp_dict = response_twiss.create_response( accel_inst, opt.variable_categories, optics_params ) resp_dict = _filter_response_index(resp_dict, meas_dict, optics_params) resp_matrix = _join_responses(resp_dict, optics_params, vars_list) # ######### Actual optimization ######### # delta += _calculate_delta( resp_matrix, meas_dict, optics_params, vars_list, opt.method, meth_opt) writeparams(opt.change_params_path, delta) writeparams(opt.change_params_correct_path, -delta) LOG.debug("Cumulative delta: {:.5e}".format( np.sum(np.abs(delta.loc[:, "DELTA"].values)))) write_knob(opt.knob_path, delta) LOG.info("Finished Iterative Global Correction.")
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')
def _make_results_dataframe(self): LOG.debug("Creating Results Dataframes.") results_df = tfs.TfsDataFrame(index=self.twiss_df.index) results_df["S"] = self.twiss_df["S"] return results_df
def _make_results_dataframe(self): """ Creating a dataframe used for storing results. """ LOG.debug("Creating Results Dataframes.") results_df = tfs.TfsDataFrame(index=self.twiss_df.index) results_df["S"] = self.twiss_df["S"] return results_df