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)
示例#2
0
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)
示例#4
0
    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)
示例#5
0
    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
示例#13
0
    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)
示例#14
0
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.")
示例#18
0
    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')
示例#19
0
 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