From 73bc767368d93bed81218ba54fedd72d0eb38bfe Mon Sep 17 00:00:00 2001 From: Ana Clara Oliveira Date: Wed, 7 Jun 2023 17:46:46 -0300 Subject: [PATCH] wip --- siriuspy/siriuspy/currinfo/csdev.py | 29 +- .../currinfo/lifetime/check_fiterr.py | 159 +++++++++++ siriuspy/siriuspy/currinfo/lifetime/main.py | 133 ++++----- siriuspy/siriuspy/cycle/fc_cycle_data.py | 18 ++ siriuspy/siriuspy/devices/device.py | 20 +- siriuspy/siriuspy/diagsys/psdiag/main.py | 4 +- siriuspy/siriuspy/diagsys/psdiag/pvs.py | 21 +- siriuspy/siriuspy/epics/__init__.py | 2 +- siriuspy/siriuspy/fofb/main.py | 24 +- siriuspy/siriuspy/fofb/test_svd.py | 117 ++++++++ siriuspy/siriuspy/injctrl/main.py | 254 +++++++++--------- .../siriuspy/machshift/savedata_macreport.py | 69 +++++ siriuspy/siriuspy/machshift/test_macreport.py | 89 +++--- siriuspy/siriuspy/pwrsupply/csdev.py | 2 +- siriuspy/siriuspy/ramp/conn.py | 27 +- siriuspy/siriuspy/search/get_iocs_ref.py | 30 +++ siriuspy/siriuspy/timesys/static_table.py | 4 +- 17 files changed, 743 insertions(+), 259 deletions(-) create mode 100644 siriuspy/siriuspy/currinfo/lifetime/check_fiterr.py create mode 100644 siriuspy/siriuspy/fofb/test_svd.py create mode 100644 siriuspy/siriuspy/machshift/savedata_macreport.py create mode 100644 siriuspy/siriuspy/search/get_iocs_ref.py diff --git a/siriuspy/siriuspy/currinfo/csdev.py b/siriuspy/siriuspy/currinfo/csdev.py index 47c34ab5a7..7d0579ec27 100644 --- a/siriuspy/siriuspy/currinfo/csdev.py +++ b/siriuspy/siriuspy/currinfo/csdev.py @@ -14,6 +14,7 @@ class ETypes(_csdev.ETypes): DCCTSELECTIONTYP = ('DCCT13C4', 'DCCT14C4') BUFFAUTORSTTYP = ('Off', 'DCurrCheck') FITTYP = ('Exponential', 'Linear') + LTCALCSTS = ('CalcOk', 'ErrAboveThres') _et = ETypes # syntactic sugar @@ -28,6 +29,7 @@ class Const(_csdev.Const): DCCTFltCheck = _csdev.Const.register('DCCTFltCheck', _et.OFF_ON) BuffAutoRst = _csdev.Const.register('BuffAutoRst', _et.BUFFAUTORSTTYP) Fit = _csdev.Const.register('Fit', _et.FITTYP) + LtCalcSts = _csdev.Const.register('LtCalcSts', _et.LTCALCSTS) _c = Const # syntactic sugar @@ -189,6 +191,15 @@ def get_lifetime_database(): 'type': 'float', 'value': 0.0, 'prec': 3, 'unit': 'mA', 'lolim': -10.0, 'low': -10.0, 'lolo': -10.0, 'hilim': 10.0, 'high': 10.0, 'hihi': 10.0}, + 'LtRelErrThres-SP': { + 'type': 'float', 'value': 30.0, 'prec': 1, 'unit': '%', + 'lolim': 0.0, 'hilim': 100.0}, + 'LtRelErrThres-RB': { + 'type': 'float', 'value': 30.0, 'prec': 1, 'unit': '%', + 'lolim': 0.0, 'hilim': 100.0}, + 'LtCalcStatus-Mon': { + 'type': 'enum', 'enums': _et.LTCALCSTS, + 'value': _c.LtCalcSts.CalcOk}, 'BuffRst-Cmd': {'type': 'int', 'value': 0}, 'BuffAutoRst-Sel': { @@ -198,11 +209,11 @@ def get_lifetime_database(): 'type': 'enum', 'enums': _et.BUFFAUTORSTTYP, 'value': _c.BuffAutoRst.DCurrCheck}, 'BuffAutoRstDCurr-SP': { - 'type': 'float', 'value': 0.01, 'prec': 2, 'unit': 'mA', + 'type': 'float', 'value': 0.005, 'prec': 3, 'unit': 'mA', 'lolim': -300.0, 'low': -300.0, 'lolo': -300.0, 'hilim': 300.0, 'high': 300.0, 'hihi': 300.0}, 'BuffAutoRstDCurr-RB': { - 'type': 'float', 'value': 0.01, 'prec': 2, 'unit': 'mA', + 'type': 'float', 'value': 0.005, 'prec': 3, 'unit': 'mA', 'lolim': -300.0, 'low': -300.0, 'lolo': -300.0, 'hilim': 300.0, 'high': 300.0, 'hihi': 300.0}, @@ -226,8 +237,11 @@ def get_lifetime_database(): 'lolim': -1.0, 'hilim': 2e10}, 'Lifetime-Mon': { - 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's', - 'scan': 0.5}, + 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's'}, + 'LifetimeRaw-Mon': { + 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's'}, + 'LifetimeErr-Mon': { + 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's'}, 'BuffSize-Mon': {'type': 'int', 'value': 0}, 'BuffSizeTot-Mon': {'type': 'int', 'value': 0}, 'BufferValue-Mon': { @@ -238,8 +252,11 @@ def get_lifetime_database(): 'value': [0.0, ] * 100000}, 'LifetimeBPM-Mon': { - 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's', - 'scan': 0.5}, + 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's'}, + 'LifetimeRawBPM-Mon': { + 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's'}, + 'LifetimeErrBPM-Mon': { + 'type': 'float', 'value': 0.0, 'prec': 2, 'unit': 's'}, 'BuffSizeBPM-Mon': {'type': 'int', 'value': 0}, 'BuffSizeTotBPM-Mon': {'type': 'int', 'value': 0}, 'BufferValueBPM-Mon': { diff --git a/siriuspy/siriuspy/currinfo/lifetime/check_fiterr.py b/siriuspy/siriuspy/currinfo/lifetime/check_fiterr.py new file mode 100644 index 0000000000..e9295e1c26 --- /dev/null +++ b/siriuspy/siriuspy/currinfo/lifetime/check_fiterr.py @@ -0,0 +1,159 @@ +import numpy as np +import matplotlib.pyplot as mplt +from siriuspy.clientarch import PVDataSet, Time + + +def fit_pol(x, y, deg=1, polyfit=False): + # handle big timestamps + x = x - x[-1] + # considering y = b + ax + if polyfit: + (a, b), cov = np.polyfit(x, y, deg=deg, cov=True) + db_sqr, da_sqr = np.diag(cov) + else: + (b, a), details = np.polynomial.polynomial.polyfit(x, y, deg=deg, full=True) + + residues = details[0] + + lhs = np.polynomial.polynomial.polyvander(x, order-1) + scale = np.sqrt((lhs*lhs).sum(axis=0)) + + lhs /= scale + lhs_inv = np.linalg.inv(np.dot(lhs.T, lhs)) + lhs_inv /= np.outer(scale, scale) + + cov = lhs_inv * (residues/(lhs.shape[0] - order)) + + da_sqr, db_sqr = np.diag(cov) + + lt = - b / a + dlt_sqr_rel = da_sqr/a/a + db_sqr/b/b + dlt = np.sqrt(dlt_sqr_rel)*np.abs(lt) + + return a, np.sqrt(da_sqr), b, np.sqrt(db_sqr), lt, dlt + + +# datasets +dataset = { + 0: { + 'title': '2023-01-23, 6-8h, N~4000', + 't_start': Time(2023, 1, 23, 6, 0, 0), + 't_stop': Time(2023, 1, 23, 8, 0, 0), + 'nrpts_fit': 4000, + 'lt_ylim': [0, 100], + 'err_ylim': [0, 1.0], + }, + 1: { + 'title': '2023-01-23, 10-11h', + 't_start': Time(2023, 1, 23, 10, 0, 0), + 't_stop': Time(2023, 1, 23, 11, 0, 0), + 'nrpts_fit': 200, + 'lt_ylim': [0, 100], + 'err_ylim': [0, 1.0], + }, + 2: { + 'title': '2023-01-23, 12h30-12h35', + 't_start': Time(2023, 1, 23, 12, 30, 0), + 't_stop': Time(2023, 1, 23, 12, 35, 0), + 'nrpts_fit': 200, + 'lt_ylim': [0, 200], + 'err_ylim': [-100.0, 100.0], + }, + 3: { + 'title': '2023-01-23, 18h35-19h25', + 't_start': Time(2023, 1, 23, 18, 35, 0), + 't_stop': Time(2023, 1, 23, 19, 25, 0), + 'nrpts_fit': 4000, + 'lt_ylim': [0, 100], + 'err_ylim': [0, 1.0], + }, + 4: { + 'title': '2023-02-08 8h15-20h', + 't_start': Time(2023, 2, 8, 8, 15, 0), + 't_stop': Time(2023, 2, 8, 20, 0, 0), + 'nrpts_fit': 500, + 'lt_ylim': [0, 100], + 'err_ylim': [0, 1.0], + }, + 5: { + 'title': '2023-02-14 16h-16h30', + 't_start': Time(2023, 2, 14, 16, 0, 0), + 't_stop': Time(2023, 2, 14, 16, 30, 0), + 'nrpts_fit': 1000, + 'lt_ylim': [0, 100], + 'err_ylim': [0, 1.0], + }, +} + + +pvnames = [ + 'SI-Glob:AP-CurrInfo:Lifetime-Mon', + 'SI-Glob:AP-CurrInfo:Current-Mon' +] +pvds = PVDataSet(pvnames) +pvds.timeout = 30 + +# for setid in dataset: +setid = 0 + +# get archiver data +pvds.time_start = dataset[setid]['t_start'] +pvds.time_stop = dataset[setid]['t_stop'] +pvds.update() + +ycurr = np.asarray(pvds['SI-Glob:AP-CurrInfo:Current-Mon'].value) +dcurr = np.hstack([0, np.diff(ycurr)]) +xcurr = np.asarray(pvds['SI-Glob:AP-CurrInfo:Current-Mon'].timestamp) +xcudt = [Time(t) for t in xcurr] +yltim = np.asarray(pvds['SI-Glob:AP-CurrInfo:Lifetime-Mon'].value) +xltim = np.asarray(pvds['SI-Glob:AP-CurrInfo:Lifetime-Mon'].timestamp) +xltdt = [Time(t) for t in xltim] +thres = 0.01 + +# fit lifetime and errors +lenb = dataset[setid]['nrpts_fit'] # [#] +order = 2 +ltfit, lterr = [], [] +for i in range(lenb, len(ycurr)): + slc = slice(i-lenb, i) + idx = np.where(dcurr[slc] > thres)[0] + if idx.size: + slc = slice(idx[-1], i) + data = fit_pol(xcurr[slc], ycurr[slc], deg=order-1, polyfit=True) + ltfit.append(data[4]) + lterr.append(data[5]/data[4]) +ltfit, lterr = np.asarray(ltfit), np.asarray(lterr) + +# plot +fig, ax = mplt.subplots() +fig.subplots_adjust(right=0.75) +tkw = dict(size=4, width=1.5) + +ax.set_title(dataset[setid]['title'] + ', N~' + str(lenb)) +ax.set_xlabel('Time [s]') +ax.tick_params(axis='x', **tkw) +ax.xaxis.axis_date() + +ax.set_ylabel('Current [mA]') +p, = ax.plot(xcudt, ycurr, 'b', label='Current') +ax.tick_params(axis='y', colors=p.get_color(), **tkw) +ax.yaxis.label.set_color(p.get_color()) + +axlt = ax.twinx() +axlt.set_ylabel('Lifetime [h]') +po, = axlt.plot(xltdt, yltim/60/60, 'g', label='Lifetime Orig') +pf, = axlt.plot(xcudt[lenb:], ltfit/60/60, 'r', label='Lifetime Fit') +axlt.yaxis.label.set_color(po.get_color()) +axlt.tick_params(axis='y', colors=po.get_color(), **tkw) +axlt.set_ylim(dataset[setid]['lt_ylim']) + +axerr = ax.twinx() +axerr.set_ylabel('Lifetime Fit Rel. Error') +axerr.spines['right'].set_position(("axes", 1.2)) +p, = axerr.plot(xcudt[lenb:], lterr, 'k', label='Lifetime Fit Error') +axerr.yaxis.label.set_color(p.get_color()) +axerr.tick_params(axis='y', colors=p.get_color(), **tkw) +axerr.set_ylim(dataset[setid]['err_ylim']) + +fig.legend() +fig.show() diff --git a/siriuspy/siriuspy/currinfo/lifetime/main.py b/siriuspy/siriuspy/currinfo/lifetime/main.py index 9821d459f9..52ee827f84 100644 --- a/siriuspy/siriuspy/currinfo/lifetime/main.py +++ b/siriuspy/siriuspy/currinfo/lifetime/main.py @@ -4,6 +4,7 @@ import time as _time import numpy as _np from epics import PV as _PV +from epics.ca import CAThread as _Thread from ...callbacks import Callback as _Callback from ...epics import SiriusPVTimeSerie as _SiriusPVTimeSerie @@ -15,7 +16,7 @@ class SILifetimeApp(_Callback): - """Main Class of the IOC Logic.""" + """SI Lifetime App.""" def __init__(self): """Class constructor.""" @@ -65,6 +66,9 @@ def __init__(self): self._bpmsum_pv.add_callback(self._callback_calclifetime) self._storedebeam_pv.add_callback(self._callback_get_storedebeam) + self._thread = _Thread(target=self._update_lifetime, daemon=True) + self._thread.start() + @property def pvs_database(self): """Return pvs database.""" @@ -86,52 +90,6 @@ def process(self, interval): def read(self, reason): """Read from IOC database.""" value = None - if reason in ['Lifetime-Mon', 'LifetimeBPM-Mon']: - is_bpm = 'BPM' in reason - lt_type = 'BPM' if is_bpm else '' - lt_name = '_lifetime'+('_bpm' if is_bpm else '') - buffer_dt = self._bpmsum_buffer if is_bpm else self._current_buffer - - # get first and last sample - now = _time.time() - self._update_times(now) - first_name = '_frst_smpl_ts'+('_bpm' if is_bpm else '_dcct') - first_smpl = getattr(self, first_name) - last_name = '_last_smpl_ts'+('_bpm' if is_bpm else '_dcct') - last_smpl = getattr(self, last_name) - last_smpl = now if last_smpl == -1 else min(last_smpl, now) - intvl_name = '_smpl_intvl_mon'+('_bpm' if is_bpm else '_dcct') - intvl_smpl = getattr(self, intvl_name) - - # calculate lifetime - ts_abs_dqorg, val_dqorg = buffer_dt.get_serie(time_absolute=True) - ts_dqorg = ts_abs_dqorg - now - ts_dq, val_dq, ts_abs_dq = self._filter_buffer( - ts_dqorg, val_dqorg, ts_abs_dqorg, first_smpl, last_smpl) - - if ts_dq.size != 0: - if first_smpl != ts_abs_dq[0]: - setattr(self, first_name, ts_abs_dq[0]) - self.run_callbacks( - 'FrstSplTime'+lt_type+'-RB', getattr(self, first_name)) - intvl_smpl = last_smpl - first_smpl - setattr(self, intvl_name, intvl_smpl) - self.run_callbacks( - 'SplIntvl'+lt_type+'-Mon', getattr(self, intvl_name)) - - val_dq -= self._current_offset - - # check min number of points in buffer - if len(val_dq) > 100: - fit = 'lin' if self._mode == _Const.Fit.Linear else 'exp' - value = self._least_squares_fit(ts_dq, val_dq, fit=fit) - setattr(self, lt_name, value) - - # update pvs - self.run_callbacks('BufferValue'+lt_type+'-Mon', val_dq) - self.run_callbacks('BufferTimestamp'+lt_type+'-Mon', ts_dq) - self.run_callbacks('BuffSize'+lt_type+'-Mon', len(val_dq)) - self.run_callbacks('BuffSizeTot'+lt_type+'-Mon', len(val_dqorg)) return value def write(self, reason, value): @@ -193,10 +151,14 @@ def write(self, reason, value): def _callback_get_storedebeam(self, value, **kws): self._is_stored = value - def _callback_calclifetime(self, pvname, timestamp, **kws): - # check DCCT StoredEBeam PV + def _callback_calclifetime(self, pvname, **kws): + # if there is no beam stored, set lifetime to zero if not self._is_stored: - self._buffautorst_check() + if self._lifetime != 0: + self._lifetime, self._lifetime_bpm = 0, 0 + self.run_callbacks('Lifetime-Mon', self._lifetime) + self.run_callbacks('LifetimeBPM-Mon', self._lifetime_bpm) + self._reset_buff() return is_bpm = 'BPM' in pvname @@ -287,23 +249,18 @@ def _least_squares_fit(timestamp, value, fit='exp'): value = _np.log(value) except Warning: return 0.0 - _ns = len(timestamp) - _x1 = _np.sum(timestamp) - _y1 = _np.sum(value) - if timestamp.size > 10000: - _x2 = _np.sum(timestamp*timestamp) - _xy = _np.sum(timestamp*value) - else: - _x2 = _np.dot(timestamp, timestamp) - _xy = _np.dot(timestamp, value) - fit_a = (_x2*_y1 - _xy*_x1)/(_ns*_x2 - _x1*_x1) - fit_b = (_ns*_xy - _x1*_y1)/(_ns*_x2 - _x1*_x1) + # y = a + bx + (fit_b, fit_a), cov = _np.polyfit(timestamp, value, deg=1, cov=True) + da_sqr, db_sqr = _np.diag(cov) if fit == 'exp': lifetime = - 1/fit_b else: lifetime = - fit_a/fit_b - return lifetime + + dlt_sqr_rel = db_sqr/fit_b/fit_b + da_sqr/fit_a/fit_a + dlifetime = _np.sqrt(dlt_sqr_rel)*_np.abs(lifetime) + return lifetime, dlifetime/lifetime def _update_times(self, now, force_min_first=False): if self._last_ts_set == 'first': @@ -325,3 +282,55 @@ def _update_times(self, now, force_min_first=False): self.run_callbacks('FrstSplTimeBPM-RB', self._frst_smpl_ts_bpm) self.run_callbacks('LastSplTime-RB', self._last_smpl_ts_dcct) self.run_callbacks('LastSplTimeBPM-RB', self._last_smpl_ts_bpm) + + def _update_lifetime(self): + for reason in ['Lifetime-Mon', 'LifetimeBPM-Mon']: + is_bpm = 'BPM' in reason + lt_type = 'BPM' if is_bpm else '' + lt_name = '_lifetime'+('_bpm' if is_bpm else '') + buffer_dt = self._bpmsum_buffer if is_bpm else self._current_buffer + + # get first and last sample + now = _time.time() + self._update_times(now) + first_name = '_frst_smpl_ts'+('_bpm' if is_bpm else '_dcct') + first_smpl = getattr(self, first_name) + last_name = '_last_smpl_ts'+('_bpm' if is_bpm else '_dcct') + last_smpl = getattr(self, last_name) + last_smpl = now if last_smpl == -1 else min(last_smpl, now) + intvl_name = '_smpl_intvl_mon'+('_bpm' if is_bpm else '_dcct') + intvl_smpl = getattr(self, intvl_name) + + # calculate lifetime + ts_abs_dqorg, val_dqorg = buffer_dt.get_serie(time_absolute=True) + ts_dqorg = ts_abs_dqorg - now + ts_dq, val_dq, ts_abs_dq = self._filter_buffer( + ts_dqorg, val_dqorg, ts_abs_dqorg, first_smpl, last_smpl) + + if ts_dq.size != 0: + if first_smpl != ts_abs_dq[0]: + setattr(self, first_name, ts_abs_dq[0]) + self.run_callbacks( + 'FrstSplTime'+lt_type+'-RB', getattr(self, first_name)) + intvl_smpl = last_smpl - first_smpl + setattr(self, intvl_name, intvl_smpl) + self.run_callbacks( + 'SplIntvl'+lt_type+'-Mon', getattr(self, intvl_name)) + + val_dq -= self._current_offset + + # check min number of points in buffer + if len(val_dq) > 100: + fit = 'lin' if self._mode == _Const.Fit.Linear else 'exp' + value, fit_err = self._least_squares_fit( + ts_dq, val_dq, fit=fit) + if fit_err < _Const.ERR_THRES_LIFETIME: + setattr(self, lt_name, value) + else: + value = getattr(self, lt_name) + + # update pvs + self.run_callbacks('BufferValue'+lt_type+'-Mon', val_dq) + self.run_callbacks('BufferTimestamp'+lt_type+'-Mon', ts_dq) + self.run_callbacks('BuffSize'+lt_type+'-Mon', len(val_dq)) + self.run_callbacks('BuffSizeTot'+lt_type+'-Mon', len(val_dqorg)) diff --git a/siriuspy/siriuspy/cycle/fc_cycle_data.py b/siriuspy/siriuspy/cycle/fc_cycle_data.py index 28a5d469fc..ffbe357812 100644 --- a/siriuspy/siriuspy/cycle/fc_cycle_data.py +++ b/siriuspy/siriuspy/cycle/fc_cycle_data.py @@ -165,6 +165,24 @@ 'SI-20C2:PS-FCV': [0.5, 0.95, 24, 8, 48, False], 'SI-20C3:PS-FCH': [0.5, 0.95, 24, 8, 48, False], 'SI-20C3:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + + 'SI-22M1:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-22M1:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + 'SI-22M2:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-22M2:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + 'SI-22C2:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-22C2:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + 'SI-22C3:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-22C3:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + + 'SI-99M1:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-99M1:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + 'SI-99M2:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-99M2:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + 'SI-99C2:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-99C2:PS-FCV': [0.5, 0.95, 24, 8, 48, False], + 'SI-99C3:PS-FCH': [0.5, 0.95, 24, 8, 48, False], + 'SI-99C3:PS-FCV': [0.5, 0.95, 24, 8, 48, False], } diff --git a/siriuspy/siriuspy/devices/device.py b/siriuspy/siriuspy/devices/device.py index 450a577a38..05287971d3 100644 --- a/siriuspy/siriuspy/devices/device.py +++ b/siriuspy/siriuspy/devices/device.py @@ -18,6 +18,7 @@ _DEF_TIMEOUT = 10 # s _TINY_INTERVAL = 0.050 # s +_VACA_PREFIX = '' class Device: @@ -83,7 +84,14 @@ def set_auto_monitor(self, pvname, value): """Set auto_monitor state of individual PVs.""" if pvname not in self._pvs: return False - self._pvs[pvname].auto_monitor = int(value) + pvobj = self._pvs[pvname] + try: + pvobj.auto_monitor = int(value) + except (_ChannelAccessGetFailure, _CASeverityException): + # exceptions raised in a Virtual Circuit Disconnect (192) + # event. If the PV IOC goes down, for example. + print('Could not set auto_monitor of {}'.format(pvobj.pvname)) + return False return True def update(self): @@ -140,7 +148,15 @@ def __getitem__(self, propty): def __setitem__(self, propty, value): """Set value of property.""" pvobj = self._pvs[propty] - pvobj.value = value + # pvobj.value = value + pvname = pvobj.pvname + if 'FCH' in pvname or 'FCV' in pvname: + if '01C2' not in pvname: + return + if isinstance(value, _np.ndarray): + print(pvname, value.shape, [value[0], value[-1]]) + else: + print(pvname, value) # --- private methods --- diff --git a/siriuspy/siriuspy/diagsys/psdiag/main.py b/siriuspy/siriuspy/diagsys/psdiag/main.py index 4ef87abdf6..ce2a54e062 100644 --- a/siriuspy/siriuspy/diagsys/psdiag/main.py +++ b/siriuspy/siriuspy/diagsys/psdiag/main.py @@ -42,7 +42,7 @@ def _create_computed_pvs(self, psnames): alarm_list.extend( [aux+':'+alm for alm in intlks if 'Alarm' in alm]) - nbpvs = 4 if psname.dev in ['FCH', 'FCV'] else 5 + nbpvs = 5 pvs = [None]*(nbpvs+len(intlk_list)+len(alarm_list)) pvs[_PSStatusPV.PWRSTE_STS] = devname + ':PwrState-Sts' pvs[_PSStatusPV.CURRT_DIFF] = devname + ':DiagCurrentDiff-Mon' @@ -50,6 +50,8 @@ def _create_computed_pvs(self, psnames): pvs[_PSStatusPV.OPMODE_STS] = devname + ':OpMode-Sts' if psname.dev not in ['FCH', 'FCV']: pvs[_PSStatusPV.WAVFRM_MON] = devname + ':Wfm-Mon' + else: + pvs[_PSStatusPV.TRIGEN_STS] = devname + ':TrigEn-Sts' computer.INTLK_PVS = list() for idx, intlk in enumerate(intlk_list): diff --git a/siriuspy/siriuspy/diagsys/psdiag/pvs.py b/siriuspy/siriuspy/diagsys/psdiag/pvs.py index 3eecf17353..8ebd1c1781 100644 --- a/siriuspy/siriuspy/diagsys/psdiag/pvs.py +++ b/siriuspy/siriuspy/diagsys/psdiag/pvs.py @@ -32,13 +32,14 @@ def compute_update(self, computed_pv, updated_pv_name, value): class PSStatusPV: """Power Supply Status PV.""" - BIT_PSCONNECT = 0b0000001 - BIT_PWRSTATON = 0b0000010 - BIT_CURRTDIFF = 0b0000100 - BIT_INTERLOCK = 0b0001000 - BIT_ALARMSSET = 0b0010000 - BIT_OPMODEDIF = 0b0100000 - BIT_BOWFMDIFF = 0b1000000 + BIT_PSCONNECT = 0b00000001 + BIT_PWRSTATON = 0b00000010 + BIT_CURRTDIFF = 0b00000100 + BIT_INTERLOCK = 0b00001000 + BIT_ALARMSSET = 0b00010000 + BIT_OPMODEDIF = 0b00100000 + BIT_BOWFMDIFF = 0b01000000 + BIT_TRIGMDENB = 0b10000000 PWRSTE_STS = 0 CURRT_DIFF = 1 @@ -48,6 +49,7 @@ class PSStatusPV: OPMODE_SEL = 2 OPMODE_STS = 3 WAVFRM_MON = 4 + TRIGEN_STS = 5 DTOLWFM_DICT = dict() @@ -99,6 +101,7 @@ def compute_update(self, computed_pv, updated_pv_name, value): value |= PSStatusPV.BIT_ALARMSSET value |= PSStatusPV.BIT_OPMODEDIF value |= PSStatusPV.BIT_BOWFMDIFF + value |= PSStatusPV.BIT_TRIGMDENB return {'value': value} # pwrstate? @@ -114,7 +117,9 @@ def compute_update(self, computed_pv, updated_pv_name, value): if psname.dev in ['FCH', 'FCV']: opmode_sel = _ETypes.FOFB_OPMODES_SEL[sel] opmode_sts = _ETypes.FOFB_OPMODES_STS[sts] - checkdiff = sts == _PSConst.OpModeFOFBSts.manual + checkdiff = sts in [ + _PSConst.OpModeFOFBSts.manual, + _PSConst.OpModeFOFBSts.fofb] else: opmode_sel = _ETypes.OPMODES[sel] opmode_sts = _ETypes.STATES[sts] diff --git a/siriuspy/siriuspy/epics/__init__.py b/siriuspy/siriuspy/epics/__init__.py index a409cd495d..6cf5c794b1 100644 --- a/siriuspy/siriuspy/epics/__init__.py +++ b/siriuspy/siriuspy/epics/__init__.py @@ -2,7 +2,7 @@ # the following parameter is used to establish connections with IOC PVs. CONNECTION_TIMEOUT = 0.050 # [s] -GET_TIMEOUT = 5.0 # [s] +GET_TIMEOUT = 0.1 # [s] from .pv import PV from .pv_time_serie import * diff --git a/siriuspy/siriuspy/fofb/main.py b/siriuspy/siriuspy/fofb/main.py index f647228c2f..f2e2bf383c 100644 --- a/siriuspy/siriuspy/fofb/main.py +++ b/siriuspy/siriuspy/fofb/main.py @@ -107,7 +107,8 @@ def __init__(self, tests=False): pvo = pso.pv_object(propty) pvo.auto_monitor = _epics.dbr.DBE_VALUE pvo.add_callback( - _part(self._update_kick_array, ps_index=idx)) + _part(self._update_kick_array, ps_index=idx), + with_ctrlvars=False) self._rf_dev = _RFGen() @@ -189,12 +190,12 @@ def __init__(self, tests=False): # configuration scanning self.quit = False self.scanning = False - self.thread_check_corrs_configs = _epics.ca.CAThread( - target=self._check_corrs_configs, daemon=True) - self.thread_check_corrs_configs.start() - self.thread_check_ctrls_configs = _epics.ca.CAThread( - target=self._check_ctrls_configs, daemon=True) - self.thread_check_ctrls_configs.start() + # self.thread_check_corrs_configs = _epics.ca.CAThread( + # target=self._check_corrs_configs, daemon=True) + # self.thread_check_corrs_configs.start() + # self.thread_check_ctrls_configs = _epics.ca.CAThread( + # target=self._check_ctrls_configs, daemon=True) + # self.thread_check_ctrls_configs.start() def init_database(self): """Set initial PV values.""" @@ -1153,7 +1154,8 @@ def set_enbllist(self, device, value): def _handle_devices_enblconfig(self, device): if device in ['ch', 'cv']: if self._check_corr_connection(): - self._check_set_corrs_opmode() + pass + # self._check_set_corrs_opmode() elif device in ['bpmx', 'bpmy']: self._update_fofbctrl_sync_enbllist() if self._check_fofbctrl_connection(): @@ -1305,7 +1307,8 @@ def _calc_matrices(self): # convert matrix to hardware units str2curr = _np.r_[self._corrs_dev.strength_2_current_factor, 1.0] - currgain = _np.r_[self._corrs_dev.curr_gain, 1.0] + # currgain = _np.r_[self._corrs_dev.curr_gain, 1.0] + currgain = _np.r_[6.25e-5*_np.ones(160), 1.0] if _np.any(str2curr == 0) or _np.any(currgain == 0): self._update_log('ERR:Could not calculate hardware unit') self._update_log('ERR:matrix, CurrGain or "urad to A" ') @@ -1360,7 +1363,8 @@ def _calc_matrices(self): # send new matrix to low level FOFB self._calc_corrs_coeffs() if self._init: - self._set_corrs_coeffs() + # self._set_corrs_coeffs() + pass self._update_log('Ok!') return True diff --git a/siriuspy/siriuspy/fofb/test_svd.py b/siriuspy/siriuspy/fofb/test_svd.py new file mode 100644 index 0000000000..8b1b7b0b6b --- /dev/null +++ b/siriuspy/siriuspy/fofb/test_svd.py @@ -0,0 +1,117 @@ + +import numpy as np + +from siriuspy.clientconfigdb import ConfigDBClient +from siriuspy.devices import FamFastCorrs +from siriuspy.fofb.csdev import HLFOFBConst + +# create FOFB contants +fofbconst = HLFOFBConst() + +# get matrix from configdb +client = ConfigDBClient() +ref = client.get_config_value(name='ref_orb', config_type='si_orbit') +respm = client.get_config_value( + name='ref_respmat', config_type='si_fastorbcorr_respm') +respm = np.asarray(respm) + +# connect to correctors and get convertion constants +corrs_dev = FamFastCorrs() + +# determine enable lists +# select all +bpmxenbl = np.ones(fofbconst.nr_bpms, dtype=bool) +bpmyenbl = np.ones(fofbconst.nr_bpms, dtype=bool) +chenbl = np.ones(fofbconst.nr_ch, dtype=bool) +cvenbl = np.ones(fofbconst.nr_cv, dtype=bool) +rfenbl = np.ones(1, dtype=bool) +# select one straight section +bpmenbl = np.array( + ['C1' not in b and 'C3-2' not in b and 'C4' not in b + for b in fofbconst.bpm_nicknames]) +bpmxenbl = bpmenbl +bpmyenbl = bpmenbl +chenbl = np.array(['01M' not in c for c in fofbconst.ch_names]) +cvenbl = np.array(['01M' not in c for c in fofbconst.cv_names]) +rfenbl = np.zeros(1, dtype=bool) + +selbpm = np.hstack([bpmxenbl, bpmyenbl]) +selcorr = np.hstack([chenbl, cvenbl, rfenbl]) +selmat = selbpm[:, None] * selcorr[None, :] +if selmat.size != respm.size: + raise ValueError( + f'Incompatiple selection ({selmat.size}) and matrix size {respm.size}') +mat = respm.copy() +mat = mat[selmat] +mat = np.reshape(mat, [sum(selbpm), sum(selcorr)]) + +# calculate SVD +try: + _uo, _so, _vo = np.linalg.svd(mat, full_matrices=False) +except np.linalg.LinAlgError(): + raise ValueError('Could not calculate SVD') + +# handle singular values +# select singular values greater than minimum +idcs = _so > fofbconst.MIN_SING_VAL +_sr = _so[idcs] +nrs = np.sum(idcs) +if not nrs: + raise ValueError('All Singular Values below minimum.') +# apply Tikhonov regularization +regc = fofbconst.TIKHONOV_REG_CONST +regc *= regc +inv_s = np.zeros(_so.size, dtype=float) +inv_s[idcs] = _sr/(_sr*_sr + regc) +# calculate processed singular values +_sp = np.zeros(_so.size, dtype=float) +_sp[idcs] = 1/inv_s[idcs] + +# check if inverse matrix is valid +invmat = np.dot(_vo.T*inv_s, _uo.T) +if np.any(np.isnan(invmat)) or np.any(np.isinf(invmat)): + raise ValueError('Inverse contains nan or inf.') + +# reconstruct filtered and regularized matrix in physical units +matr = np.dot(_uo*_sp, _vo) + +# convert matrix to hardware units +str2curr = np.r_[corrs_dev.strength_2_current_factor, 1.0] +currgain = np.r_[corrs_dev.curr_gain, 1.0] +# unit convertion: um/urad (1)-> nm/urad (2)-> nm/A (3)-> nm/counts +matc = matr * fofbconst.CONV_UM_2_NM +matc = matc / str2curr[selcorr] +matc = matc * currgain[selcorr] + +# obtain pseudoinverse +# calculate SVD for converted matrix +_uc, _sc, _vc = np.linalg.svd(matc, full_matrices=False) +# handle singular value selection +idcsc = _sc/_sc.max() >= 1e-14 +inv_sc = np.zeros(_so.size, dtype=float) +inv_sc[idcsc] = 1/_sc[idcsc] +# calculate pseudoinverse of converted matrix from SVD +invmatc = np.dot(_vc.T*inv_sc, _uc.T) + +# get final matrices and singular values +sing_vals_raw = np.zeros(fofbconst.nr_svals, dtype=float) +sing_vals_raw[:_so.size] = _so + +sing_vals_phy = np.zeros(fofbconst.nr_svals, dtype=float) +sing_vals_phy[:_sp.size] = _sp +nr_sing_vals = nrs + +invrespmat = np.zeros(respm.shape, dtype=float).T +invrespmat[selmat.T] = invmat.ravel() + +respmat_proc = np.zeros(respm.shape, dtype=float) +respmat_proc[selmat] = matr.ravel() + +sing_vals_hw = np.zeros(fofbconst.nr_svals, dtype=float) +sing_vals_hw[:_sc.size] = _sc + +invrespmatconv = np.zeros(respm.shape, dtype=float).T +invrespmatconv[selmat.T] = invmatc.ravel() + +respmatconv_proc = np.zeros(respm.shape, dtype=float) +respmatconv_proc[selmat] = matc.ravel() diff --git a/siriuspy/siriuspy/injctrl/main.py b/siriuspy/siriuspy/injctrl/main.py index 179c00da91..5566572eb6 100644 --- a/siriuspy/siriuspy/injctrl/main.py +++ b/siriuspy/siriuspy/injctrl/main.py @@ -104,46 +104,46 @@ def __init__(self): # auxiliary diagnosis pvs self._pvs_diag = dict() - for sec in secs: - self._pvs_diag[sec] = dict() - self._pvs_diag[sec]['TI'] = { - n: _PV(n+':Status-Mon', connection_timeout=0.05) - for n in _HLTimeSearch.get_hl_triggers(filters={'sec': sec})} - - if sec == 'AS': - continue - - self._pvs_diag[sec]['PS'] = { - n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) - for n in _PSSearch.get_psnames( - {'sec': sec, 'dis': 'PS', 'dev': '(B|Q.*|S.*|CH|CV)'})} - - if sec != 'LI': - punames = _PSSearch.get_psnames({ - 'sec': sec, 'dis': 'PU', 'dev': '.*(Kckr|Sept)', - 'propty_name': '(?!:CCoil).*'}) - if sec == 'SI': - punames.remove('SI-01SA:PU-InjDpKckr') - self._pvs_diag[sec]['PU'] = { - n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) - for n in punames} - else: - self._pvs_diag[sec]['PU'] = { - n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) - for n in ['LI-01:PU-Modltr-1', 'LI-01:PU-Modltr-2']} - - self._pvs_diag[sec]['RF'] = { - n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) - for n in _LIDiagConst.DEV_2_LINAME if 'RF' in n} - - self._pvs_diag[sec]['Egun'] = { - n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) - for n in _LIDiagConst.DEV_2_LINAME if 'EG' in n} - - if sec in ['BO', 'SI']: - self._pvs_diag[sec]['RF'] = { - n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) - for n in _RFDiagConst.ALL_DEVICES if n.startswith(sec)} + # for sec in secs: + # self._pvs_diag[sec] = dict() + # self._pvs_diag[sec]['TI'] = { + # n: _PV(n+':Status-Mon', connection_timeout=0.05) + # for n in _HLTimeSearch.get_hl_triggers(filters={'sec': sec})} + + # if sec == 'AS': + # continue + + # self._pvs_diag[sec]['PS'] = { + # n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) + # for n in _PSSearch.get_psnames( + # {'sec': sec, 'dis': 'PS', 'dev': '(B|Q.*|S.*|CH|CV)'})} + + # if sec != 'LI': + # punames = _PSSearch.get_psnames({ + # 'sec': sec, 'dis': 'PU', 'dev': '.*(Kckr|Sept)', + # 'propty_name': '(?!:CCoil).*'}) + # if sec == 'SI': + # punames.remove('SI-01SA:PU-InjDpKckr') + # self._pvs_diag[sec]['PU'] = { + # n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) + # for n in punames} + # else: + # self._pvs_diag[sec]['PU'] = { + # n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) + # for n in ['LI-01:PU-Modltr-1', 'LI-01:PU-Modltr-2']} + + # self._pvs_diag[sec]['RF'] = { + # n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) + # for n in _LIDiagConst.DEV_2_LINAME if 'RF' in n} + + # self._pvs_diag[sec]['Egun'] = { + # n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) + # for n in _LIDiagConst.DEV_2_LINAME if 'EG' in n} + + # if sec in ['BO', 'SI']: + # self._pvs_diag[sec]['RF'] = { + # n: _PV(n+':DiagStatus-Mon', connection_timeout=0.05) + # for n in _RFDiagConst.ALL_DEVICES if n.startswith(sec)} # auxiliary injsys PVs self._pvs_injsys = dict() @@ -163,56 +163,58 @@ def __init__(self): self.egun_dev = EGun( print_log=False, callback=self._update_dev_status) self._init_egun = False - self.egun_dev.trigps.pv_object('enable').add_callback( - self._callback_watch_eguntrig) + # self.egun_dev.trigps.pv_object('enable').add_callback( + # self._callback_watch_eguntrig) - self._pumode_dev = InjSysPUModeHandler( - print_log=False, callback=self._update_dev_status) + # self._pumode_dev = InjSysPUModeHandler( + # print_log=False, callback=self._update_dev_status) self._evg_dev = EVG() self._init_injevt = False - self._evg_dev.pv_object('InjectionEvt-Sel').add_callback( - self._callback_watch_injectionevt) - self._evg_dev.pv_object('RepeatBucketList-RB').add_callback( - self._callback_watch_repeatbucketlist) - self._evg_dev.set_auto_monitor('TotalInjCount-Mon', True) - self._evg_dev.pv_object('TotalInjCount-Mon').add_callback( - self._callback_is_injecting) - - self._injsys_dev = InjSysStandbyHandler() + # self._evg_dev.pv_object('InjectionEvt-Sel').add_callback( + # self._callback_watch_injectionevt) + # self._evg_dev.pv_object('RepeatBucketList-RB').add_callback( + # self._callback_watch_repeatbucketlist) + # self._evg_dev.set_auto_monitor('TotalInjCount-Mon', True) + # self._evg_dev.pv_object('TotalInjCount-Mon').add_callback( + # self._callback_is_injecting) + pv = _PV('test-AS-RaMO:TI-EVG:TotalInjCount-Mon', connection_timeout=0.05) + pv.add_callback(self._callback_is_injecting) + + # self._injsys_dev = InjSysStandbyHandler() self.currinfo_dev = CurrInfoSI() - self.currinfo_dev.set_auto_monitor('Current-Mon', True) - curr_pvo = self.currinfo_dev.pv_object('Current-Mon') - curr_pvo.add_callback(self._callback_autostop) - curr_pvo.connection_callbacks.append(self._callback_conn_autostop) - - self._pu_names = _PSSearch.get_psnames({ - 'dis': 'PU', 'dev': '.*(InjKckr|EjeKckr|InjNLKckr|Sept)', - 'propty_name': '(?!:CCoil).*'}) - self._pu_devs = [PowerSupplyPU(pun) for pun in self._pu_names] - self._pu_refvolt = list() - self._topup_puref_ignore = False - for dev in self._pu_devs: - pvo = dev.pv_object('Voltage-SP') - self._pu_refvolt.append(pvo.value) - pvo.add_callback(self._callback_update_pu_refvolt) - - self._rfkillbeam = RFKillBeam() - - self._li_trig_names = _HLTimeSearch.get_hl_triggers( - {'sec': 'LI', 'dev': '(Mod|LLRF|SSAmp|Osc)'}) - self._li_trig_devs = [Trigger(tin) for tin in self._li_trig_names] - - self._bops_trig_names = _HLTimeSearch.get_hl_triggers( - {'sec': 'BO', 'dev': 'Mags'}) - self._bops_trig_devs = [Trigger(tin) for tin in self._bops_trig_names] - - self._borf_trig_names = _HLTimeSearch.get_hl_triggers( - {'sec': 'BO', 'dev': 'LLRF', 'idx': 'Rmp'}) - self._borf_trig_devs = [Trigger(tin) for tin in self._borf_trig_names] - - self._hlti_dev = HLTiming() + # self.currinfo_dev.set_auto_monitor('Current-Mon', True) + # curr_pvo = self.currinfo_dev.pv_object('Current-Mon') + # curr_pvo.add_callback(self._callback_autostop) + # curr_pvo.connection_callbacks.append(self._callback_conn_autostop) + + # self._pu_names = _PSSearch.get_psnames({ + # 'dis': 'PU', 'dev': '.*(InjKckr|EjeKckr|InjNLKckr|Sept)', + # 'propty_name': '(?!:CCoil).*'}) + # self._pu_devs = [PowerSupplyPU(pun) for pun in self._pu_names] + # self._pu_refvolt = list() + # self._topup_puref_ignore = False + # for dev in self._pu_devs: + # pvo = dev.pv_object('Voltage-SP') + # self._pu_refvolt.append(pvo.value) + # pvo.add_callback(self._callback_update_pu_refvolt) + + # self._rfkillbeam = RFKillBeam() + + # self._li_trig_names = _HLTimeSearch.get_hl_triggers( + # {'sec': 'LI', 'dev': '(Mod|LLRF|SSAmp|Osc)'}) + # self._li_trig_devs = [Trigger(tin) for tin in self._li_trig_names] + + # self._bops_trig_names = _HLTimeSearch.get_hl_triggers( + # {'sec': 'BO', 'dev': 'Mags'}) + # self._bops_trig_devs = [Trigger(tin) for tin in self._bops_trig_names] + + # self._borf_trig_names = _HLTimeSearch.get_hl_triggers( + # {'sec': 'BO', 'dev': 'LLRF', 'idx': 'Rmp'}) + # self._borf_trig_devs = [Trigger(tin) for tin in self._borf_trig_names] + + # self._hlti_dev = HLTiming() # pvname to write method map self.map_pv2write = { @@ -254,12 +256,12 @@ def __init__(self): # status scanning self.quit = False self.scanning = False - self.thread_check_diagstatus = _epics.ca.CAThread( - target=self._update_diagstatus, daemon=True) - self.thread_check_diagstatus.start() - self.thread_check_injstatus = _epics.ca.CAThread( - target=self._update_injstatus, daemon=True) - self.thread_check_injstatus.start() + # self.thread_check_diagstatus = _epics.ca.CAThread( + # target=self._update_diagstatus, daemon=True) + # self.thread_check_diagstatus.start() + # self.thread_check_injstatus = _epics.ca.CAThread( + # target=self._update_injstatus, daemon=True) + # self.thread_check_injstatus.start() # initialize default operation values with implemented values self.egun_dev.wait_for_connection() @@ -309,12 +311,12 @@ def init_database(self): 'HVOpVolt-SP': self._hvopvolt, 'HVOpVolt-RB': self._hvopvolt, 'HVOpVoltCmdSts-Mon': self._p2w['HVOpVolt']['status'], - 'PUModeDeltaPosAng-SP': self._pumode_dev.delta_posang, - 'PUModeDeltaPosAng-RB': self._pumode_dev.delta_posang, - 'PUModeDpKckrDlyRef-SP': self._pumode_dev.dpkckr_dlyref, - 'PUModeDpKckrDlyRef-RB': self._pumode_dev.dpkckr_dlyref, - 'PUModeDpKckrKick-SP': self._pumode_dev.dpkckr_kick, - 'PUModeDpKckrKick-RB': self._pumode_dev.dpkckr_kick, + # 'PUModeDeltaPosAng-SP': self._pumode_dev.delta_posang, + # 'PUModeDeltaPosAng-RB': self._pumode_dev.delta_posang, + # 'PUModeDpKckrDlyRef-SP': self._pumode_dev.dpkckr_dlyref, + # 'PUModeDpKckrDlyRef-RB': self._pumode_dev.dpkckr_dlyref, + # 'PUModeDpKckrKick-SP': self._pumode_dev.dpkckr_kick, + # 'PUModeDpKckrKick-RB': self._pumode_dev.dpkckr_kick, 'PUModeCmdSts-Mon': self._p2w['PUMode']['status'], 'TargetCurrent-SP': self._target_current, 'TargetCurrent-RB': self._target_current, @@ -354,7 +356,7 @@ def init_database(self): 'TopUpNextInj-Mon': self._topup_next, 'TopUpNrPulses-SP': self._topup_nrpulses, 'TopUpNrPulses-RB': self._topup_nrpulses, - 'InjSysCmdDone-Mon': ','.join(self._injsys_dev.done), + # 'InjSysCmdDone-Mon': ','.join(self._injsys_dev.done), 'InjSysCmdSts-Mon': _Const.InjSysCmdSts.Idle, 'RFKillBeam-Mon': _Const.RFKillBeamMon.Idle, 'DiagStatusLI-Mon': self._status['LI'], @@ -369,35 +371,35 @@ def init_database(self): self.run_callbacks(pvn, val) self._callback_update_type(init=True) - self.egun_dev.pulse.pv_object('multiselstatus').add_callback( - self._callback_update_type) - self.egun_dev.pulse.pv_object('multiswstatus').add_callback( - self._callback_update_type) - self.egun_dev.pulse.pv_object('singleselstatus').add_callback( - self._callback_update_type) - self.egun_dev.pulse.pv_object('singleswstatus').add_callback( - self._callback_update_type) - self.egun_dev.trigmultipre.pv_object('State-Sts').add_callback( - self._callback_update_type) - self.egun_dev.trigmulti.pv_object('State-Sts').add_callback( - self._callback_update_type) - self.egun_dev.trigsingle.pv_object('State-Sts').add_callback( - self._callback_update_type) - self._callback_update_pumode(init=True) - self._pumode_dev.trigdpk.pv_object('Src-Sts').add_callback( - self._callback_update_pumode) - self._pumode_dev.trigdpk.pv_object('DelayRaw-RB').add_callback( - self._callback_update_pumode) - self._pumode_dev.pudpk.pv_object('Kick-RB').add_callback( - self._callback_update_pumode) - self._pumode_dev.pudpk.pv_object('PwrState-Sts').add_callback( - self._callback_update_pumode) - self._pumode_dev.pudpk.pv_object('Pulse-Sts').add_callback( - self._callback_update_pumode) - self._pumode_dev.punlk.pv_object('PwrState-Sts').add_callback( - self._callback_update_pumode) - self._pumode_dev.punlk.pv_object('Pulse-Sts').add_callback( - self._callback_update_pumode) + # self.egun_dev.pulse.pv_object('multiselstatus').add_callback( + # self._callback_update_type) + # self.egun_dev.pulse.pv_object('multiswstatus').add_callback( + # self._callback_update_type) + # self.egun_dev.pulse.pv_object('singleselstatus').add_callback( + # self._callback_update_type) + # self.egun_dev.pulse.pv_object('singleswstatus').add_callback( + # self._callback_update_type) + # self.egun_dev.trigmultipre.pv_object('State-Sts').add_callback( + # self._callback_update_type) + # self.egun_dev.trigmulti.pv_object('State-Sts').add_callback( + # self._callback_update_type) + # self.egun_dev.trigsingle.pv_object('State-Sts').add_callback( + # self._callback_update_type) + # self._callback_update_pumode(init=True) + # self._pumode_dev.trigdpk.pv_object('Src-Sts').add_callback( + # self._callback_update_pumode) + # self._pumode_dev.trigdpk.pv_object('DelayRaw-RB').add_callback( + # self._callback_update_pumode) + # self._pumode_dev.pudpk.pv_object('Kick-RB').add_callback( + # self._callback_update_pumode) + # self._pumode_dev.pudpk.pv_object('PwrState-Sts').add_callback( + # self._callback_update_pumode) + # self._pumode_dev.pudpk.pv_object('Pulse-Sts').add_callback( + # self._callback_update_pumode) + # self._pumode_dev.punlk.pv_object('PwrState-Sts').add_callback( + # self._callback_update_pumode) + # self._pumode_dev.punlk.pv_object('Pulse-Sts').add_callback( + # self._callback_update_pumode) self._bias_feedback.init_database() self.run_callbacks('Log-Mon', 'Started.') diff --git a/siriuspy/siriuspy/machshift/savedata_macreport.py b/siriuspy/siriuspy/machshift/savedata_macreport.py new file mode 100644 index 0000000000..3325f23a4b --- /dev/null +++ b/siriuspy/siriuspy/machshift/savedata_macreport.py @@ -0,0 +1,69 @@ + +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd +from siriuspy.clientarch.time import Time +from siriuspy.machshift.macreport import MacReport + +# determine interval +time_start = Time(2022, 1, 1, 0, 0) +time_stop = Time(2022, 12, 31, 23, 59, 59) + +# get data from interval +macr = MacReport() +macr.connector.timeout = 300 +macr.time_start = time_start +macr.time_stop = time_stop +macr.update() + +# print small report +str_ = '{:<10s}' + '{:>16s}'*9 + '{:>20s}' +print(str_.format( + 'Y-M', 'MTBF', 'MTTR', + 'Reliability', 'Progrmd hours', 'Delivd hours', 'Total hours', + '% stable hours', 'Stable hours', 'Unstable hours', 'Current (Avg±Std)')) +str_ = '{:<10s}' + ' {:>12.3f}'*9 + ' {:4.3f} ± {:4.3f}' +print( + str_.format( + str(macr.time_start.year)+'-'+str(macr.time_start.month) + ' a ' + + str(macr.time_stop.year)+'-'+str(macr.time_stop.month), + macr.usershift_time_between_failures_average, + macr.usershift_time_to_recover_average, + macr.usershift_beam_reliability, + macr.usershift_progmd_time, + macr.usershift_delivd_time, + macr.usershift_total_time, + macr.usershift_relative_stable_beam_time, + macr.usershift_total_stable_beam_time, + macr.usershift_total_unstable_beam_time, + macr.usershift_current_average, + macr.usershift_current_stddev, + )) + +# get data of interest +raw_data = macr.raw_data.copy() +raw_data.pop('Shift') +raw_data.pop('EgunModes') +raw_data.pop('Distortions') +raw_data.pop('UserShiftTotal') +raw_data.pop('UserShiftStable') +failures = raw_data.pop('Failures') +raw_data['Failures - SubsystemsNOk'] = np.asarray(failures['SubsystemsNOk'], dtype=int) +raw_data['Failures - NoEBeam'] = np.asarray(failures['NoEBeam'], dtype=int) +raw_data['Failures - WrongShift'] = np.asarray(failures['WrongShift'], dtype=int) +raw_data['TimeDate'] = [Time(t).get_iso8601() for t in raw_data['Timestamp']] + +# stored data in specific order +order = [ + 'Timestamp', 'TimeDate', 'Current', + 'Failures - SubsystemsNOk', 'Failures - NoEBeam', 'Failures - WrongShift', + 'UserShiftProgmd', 'UserShiftInitCurr', 'UserShiftDelivd'] +data = {k: raw_data[k] for k in order} + +# save data to csv +df = pd.DataFrame.from_dict(data) +df.to_csv('raw_data_machine_report_2022.csv', index=False, header=True) + +# check hour numbers: each point is equivalent to 5s, converting to hours +delivered = sum(data['UserShiftDelivd'])*5/60/60 +programmed = sum(data['UserShiftProgmd'])*5/60/60 diff --git a/siriuspy/siriuspy/machshift/test_macreport.py b/siriuspy/siriuspy/machshift/test_macreport.py index 644b8a5293..e287e2d0df 100644 --- a/siriuspy/siriuspy/machshift/test_macreport.py +++ b/siriuspy/siriuspy/machshift/test_macreport.py @@ -7,21 +7,33 @@ # failure statistics per month intervals = [ - [Time(2021, 1, 1, 0, 0), Time(2021, 1, 31, 23, 59)], - [Time(2021, 2, 1, 0, 0), Time(2021, 2, 28, 23, 59)], - [Time(2021, 3, 1, 0, 0), Time(2021, 3, 31, 23, 59)], - [Time(2021, 4, 1, 0, 0), Time(2021, 4, 30, 23, 59)], - [Time(2021, 5, 1, 0, 0), Time(2021, 5, 31, 23, 59)], - [Time(2021, 6, 1, 0, 0), Time(2021, 6, 30, 23, 59)], - [Time(2021, 7, 1, 0, 0), Time(2021, 7, 31, 23, 59)], - [Time(2021, 8, 1, 0, 0), Time(2021, 8, 31, 23, 59)], - [Time(2021, 9, 1, 0, 0), Time(2021, 9, 30, 23, 59)], - [Time(2021, 10, 1, 0, 0), Time(2021, 10, 31, 23, 59)], - [Time(2021, 11, 1, 0, 0), Time(2021, 11, 30, 23, 59)], - [Time(2021, 12, 1, 0, 0), Time(2021, 12, 31, 23, 59)], - [Time(2022, 1, 1, 0, 0), Time(2022, 1, 31, 23, 59)], - [Time(2022, 2, 1, 0, 0), Time(2022, 2, 28, 23, 59)], - [Time(2022, 3, 1, 0, 0), Time(2022, 3, 31, 23, 59)], + # [Time(2021, 1, 1, 0, 0), Time(2021, 1, 31, 23, 59, 59)], + # [Time(2021, 2, 1, 0, 0), Time(2021, 2, 28, 23, 59, 59)], + # [Time(2021, 3, 1, 0, 0), Time(2021, 3, 31, 23, 59, 59)], + # [Time(2021, 4, 1, 0, 0), Time(2021, 4, 30, 23, 59, 59)], + # [Time(2021, 5, 1, 0, 0), Time(2021, 5, 31, 23, 59, 59)], + # [Time(2021, 6, 1, 0, 0), Time(2021, 6, 30, 23, 59, 59)], + # [Time(2021, 7, 1, 0, 0), Time(2021, 7, 31, 23, 59, 59)], + # [Time(2021, 8, 1, 0, 0), Time(2021, 8, 31, 23, 59, 59)], + # [Time(2021, 9, 1, 0, 0), Time(2021, 9, 30, 23, 59, 59)], + # [Time(2021, 10, 1, 0, 0), Time(2021, 10, 31, 23, 59, 59)], + # [Time(2021, 11, 1, 0, 0), Time(2021, 11, 30, 23, 59, 59)], + # [Time(2021, 12, 1, 0, 0), Time(2021, 12, 31, 23, 59, 59)], + # [Time(2022, 1, 1, 0, 0), Time(2022, 1, 31, 23, 59, 59)], + # [Time(2022, 2, 1, 0, 0), Time(2022, 2, 28, 23, 59, 59)], + # [Time(2022, 3, 1, 0, 0), Time(2022, 3, 31, 23, 59, 59)], + [Time(2022, 4, 1, 0, 0), Time(2022, 4, 30, 23, 59, 59)], + [Time(2022, 5, 1, 0, 0), Time(2022, 5, 31, 23, 59, 59)], + [Time(2022, 6, 1, 0, 0), Time(2022, 6, 30, 23, 59, 59)], + [Time(2022, 7, 1, 0, 0), Time(2022, 7, 31, 23, 59, 59)], + [Time(2022, 8, 1, 0, 0), Time(2022, 8, 31, 23, 59, 59)], + [Time(2022, 9, 1, 0, 0), Time(2022, 9, 30, 23, 59, 59)], + [Time(2022, 10, 1, 0, 0), Time(2022, 10, 31, 23, 59, 59)], + [Time(2022, 11, 1, 0, 0), Time(2022, 11, 30, 23, 59, 59)], + [Time(2022, 12, 1, 0, 0), Time(2022, 12, 31, 23, 59, 59)], + [Time(2023, 1, 1, 0, 0), Time(2023, 1, 31, 23, 59, 59)], + [Time(2023, 2, 1, 0, 0), Time(2023, 2, 28, 23, 59, 59)], + [Time(2023, 3, 1, 0, 0), Time(2023, 3, 31, 23, 59, 59)], ] macreports = dict() @@ -34,6 +46,7 @@ mtbfs, mttrs, reliabs = dict(), dict(), dict() progrmd, delivd, usertot = dict(), dict(), dict() +currmean, currstd = dict(), dict() stable, unstable, relstable = dict(), dict(), dict() for date, macr in macreports.items(): mtbfs[date] = macr.usershift_time_between_failures_average @@ -42,16 +55,18 @@ progrmd[date] = macr.usershift_progmd_time delivd[date] = macr.usershift_delivd_time usertot[date] = macr.usershift_total_time + currmean[date] = macr.usershift_current_average + currstd[date] = macr.usershift_current_stddev stable[date] = macr.usershift_total_stable_beam_time unstable[date] = macr.usershift_total_unstable_beam_time relstable[date] = macr.usershift_relative_stable_beam_time -str_ = '{:<10s}' + '{:>16s}'*9 +str_ = '{:<10s}' + '{:>16s}'*9 + '{:>20s}' print(str_.format( 'Y-M', 'MTBF', 'MTTR', 'Reliability', 'Progrmd hours', 'Delivd hours', 'Total hours', - '% stable hours', 'Stable hours', 'Unstable hours')) -str_ = '{:<10s}' + ' {:>12.3f}'*9 + '% stable hours', 'Stable hours', 'Unstable hours', 'Current (Avg±Std)')) +str_ = '{:<10s}' + ' {:>12.3f}'*9 + ' {:4.3f} ± {:4.3f}' for date in macreports: print(str_.format( str(date.year)+'-'+str(date.month), @@ -64,6 +79,7 @@ relstable[date], stable[date], unstable[date], + currmean[date], currstd[date], )) fig, axs = plt.subplots(3, 1, sharex=True) @@ -88,20 +104,33 @@ # programmed vs. delivered hours macr = MacReport() -macr.connector.timeout = 120 -macr.time_start = Time(2021, 3, 1, 0, 0) -macr.time_stop = Time(2022, 3, 31, 23, 59) +macr.connector.timeout = 300 +macr.time_start = Time(2022, 4, 1, 0, 0) +macr.time_stop = Time(2023, 3, 31, 23, 59, 59) macr.update() -print('MTBF', macr.usershift_time_between_failures_average) -print('MTTR', macr.usershift_time_to_recover_average) -print('Reliability', macr.usershift_beam_reliability) -print('Progrmd hours', macr.usershift_progmd_time) -print('Delivd hours', macr.usershift_delivd_time) -print('Total hours', macr.usershift_total_time) -print('% stable hours', macr.usershift_relative_stable_beam_time) -print('Stable hours', macr.usershift_total_stable_beam_time) -print('Unstable hours', macr.usershift_total_unstable_beam_time) +str_ = '{:<10s}' + '{:>16s}'*9 + '{:>20s}' +print(str_.format( + 'Y-M', 'MTBF', 'MTTR', + 'Reliability', 'Progrmd hours', 'Delivd hours', 'Total hours', + '% stable hours', 'Stable hours', 'Unstable hours', 'Current (Avg±Std)')) +str_ = '{:<10s}' + ' {:>12.3f}'*9 + ' {:4.3f} ± {:4.3f}' +print( + str_.format( + str(macr.time_start.year)+'-'+str(macr.time_start.month) + ' a ' + + str(macr.time_stop.year)+'-'+str(macr.time_stop.month), + macr.usershift_time_between_failures_average, + macr.usershift_time_to_recover_average, + macr.usershift_beam_reliability, + macr.usershift_progmd_time, + macr.usershift_delivd_time, + macr.usershift_total_time, + macr.usershift_relative_stable_beam_time, + macr.usershift_total_stable_beam_time, + macr.usershift_total_unstable_beam_time, + macr.usershift_current_average, + macr.usershift_current_stddev, + )) rd = macr.raw_data dtimes = np.diff(rd['Timestamp']) diff --git a/siriuspy/siriuspy/pwrsupply/csdev.py b/siriuspy/siriuspy/pwrsupply/csdev.py index 2f83aca3f4..3e8eee15e7 100644 --- a/siriuspy/siriuspy/pwrsupply/csdev.py +++ b/siriuspy/siriuspy/pwrsupply/csdev.py @@ -881,7 +881,7 @@ def get_ps_propty_database(psmodel=None, pstype=None, psname=None): psmodel = _PSSearch.conv_psname_2_psmodel(psname) pstype = _PSSearch.conv_psname_2_pstype(psname) - # get dbase for a psecific psmodel + # get dbase for a specific psmodel dbase = _get_model_db(psmodel) # insert corresponding strengths diff --git a/siriuspy/siriuspy/ramp/conn.py b/siriuspy/siriuspy/ramp/conn.py index 92654c292a..3263a23109 100644 --- a/siriuspy/siriuspy/ramp/conn.py +++ b/siriuspy/siriuspy/ramp/conn.py @@ -84,7 +84,9 @@ class Const(_csdev.Const): 'TrgEGunSglBun': 'LI-01:TI-EGun-SglBun', 'TrgEGunMultBun': 'LI-01:TI-EGun-MultBun', 'TrgEjeKckr': 'BO-48D:TI-EjeKckr', - 'TrgInjKckr': 'SI-01SA:TI-InjDpKckr'} + 'TrgInjDpKckr': 'SI-01SA:TI-InjDpKckr', + 'TrgInjNLKckr': 'SI-01SA:TI-InjNLKckr', + } trg_propties = ('State-Sel', 'Polarity-Sel', 'Src-Sel', 'NrPulses-SP', 'Duration-SP', 'Delay-SP', 'Status-Mon') @@ -137,7 +139,8 @@ def cmd_config_ramp(self, events_inj, events_eje, timeout=_TIMEOUT_DFLT): sp_dic[c.EvtLinac_Delay] = delays['Linac'] sp_dic[c.EvtInjBO_Delay] = delays['InjBO'] sp_dic[c.EvtInjSI_Delay] = delays['InjSI'] - sp_dic[c.TrgInjKckr_Delay] = delays[c.TrgInjKckr_Delay] + sp_dic[c.TrgInjDpKckr_Delay] = delays[c.TrgInjDpKckr_Delay] + sp_dic[c.TrgInjNLKckr_Delay] = delays[c.TrgInjNLKckr_Delay] for event in events_inj: attr = getattr(c, 'Evt'+event+'_Delay') sp_dic[attr] = delays[event] @@ -258,8 +261,11 @@ def calc_evts_delay(self, events_inj=list(), events_eje=list()): curr = self.get_readback(attr) delays[event] = curr + dlt_eje_dly - injkckr_dly = self.get_readback(c.TrgInjKckr_Delay) - delays[c.TrgInjKckr_Delay] = injkckr_dly + dlt_eje_dly + injdpkckr_dly = self.get_readback(c.TrgInjDpKckr_Delay) + delays[c.TrgInjDpKckr_Delay] = injdpkckr_dly + dlt_eje_dly + + injnlkckr_dly = self.get_readback(c.TrgInjNLKckr_Delay) + delays[c.TrgInjNLKckr_Delay] = injnlkckr_dly + dlt_eje_dly return delays def update_ramp_configsetup(self, events_inj, events_eje, delays): @@ -330,12 +336,13 @@ def _define_properties(self, prefix, connection_callback, callback): self.ramp_configsetup = { # Event delays - c.EvtLinac_Delay: None, # [us] - c.EvtInjBO_Delay: None, # [us] - c.EvtRmpBO_Delay: None, # [us] - c.EvtInjSI_Delay: None, # [us] - c.EvtStudy_Delay: None, # [us] - c.TrgInjKckr_Delay: None, # [us] + c.EvtLinac_Delay: None, # [us] + c.EvtInjBO_Delay: None, # [us] + c.EvtRmpBO_Delay: None, # [us] + c.EvtInjSI_Delay: None, # [us] + c.EvtStudy_Delay: None, # [us] + c.TrgInjDpKckr_Delay: None, # [us] + c.TrgInjNLKckr_Delay: None, # [us] # Mags trigger c.TrgMags_Delay: 0.0, # [us] # Corrs trigger diff --git a/siriuspy/siriuspy/search/get_iocs_ref.py b/siriuspy/siriuspy/search/get_iocs_ref.py new file mode 100644 index 0000000000..35ca589ceb --- /dev/null +++ b/siriuspy/siriuspy/search/get_iocs_ref.py @@ -0,0 +1,30 @@ + +from siriuspy.epics import PV +from siriuspy.search import IOCSearch + +pvs = dict() +for ioc in IOCSearch.get_iocs(): + prefs = IOCSearch.conv_ioc_2_prefixes(ioc) + if '-ap-' in ioc: + parts = ioc.split('-') + for pref in prefs: + if parts[2] in pref.lower() and parts[0] == pref[:2].lower(): + prefix = pref + break + else: + prefix = prefs[0] + + if prefix.endswith('Kick') or prefix.endswith('KL') or \ + prefix.endswith('Kx'): + prefix += '-SP' + elif ':TI-' in prefix: + prefix += ':Status-Mon' + else: + if not prefix.endswith(':Diag'): + prefix += ':' + prefix += 'Version-Cte' + pvs[ioc] = PV(prefix) + +for pv in pvs.values(): + if not pv.connected: + print(pv.pvname) diff --git a/siriuspy/siriuspy/timesys/static_table.py b/siriuspy/siriuspy/timesys/static_table.py index b602795f60..2b6673541c 100644 --- a/siriuspy/siriuspy/timesys/static_table.py +++ b/siriuspy/siriuspy/timesys/static_table.py @@ -65,11 +65,11 @@ def read_data_from_google(): # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. - store = file.Storage('/home/fernando/token.json') + store = file.Storage('/home/ana/token.json') creds = store.get() if not creds or creds.invalid: flow = client.flow_from_clientsecrets( - '/home/fernando/credentials.json', + '/home/ana/credentials.json', 'https://www.googleapis.com/auth/spreadsheets.readonly') creds = tools.run_flow(flow, store) service = build('sheets', 'v4', http=creds.authorize(Http()))