chore: start migrating dbpm3curr

This commit is contained in:
Benjamin Labrecque
2026-07-14 11:00:37 +02:00
parent 5d4d1124f1
commit 8a6b36820d
@@ -1,49 +1,173 @@
import time
import numpy as np
import typer
from agebd.enums import LogLevel
from agebd.pv import LocalPVLink
from agebd.pv import PVLink
from agebd.runner import CallbackRunner
from agebd.service.base import BaseService
from agebd.service.pvs import BasePVs
from agebd.utils import get_pv_class, init_logging, printgetversion
from epics import dbr
__version__ = printgetversion(__file__)
PV = get_pv_class()
PV_PROD_READONLY = PVLink
class PVs(BasePVs):
# Option 1:
## Service specific PVs from dedicated IOC
my_pv1 = PV("AGEBD-DBPM3CURR:AO") # TODO: is this a good PV to use?
recalibrate = PV("AGEBD-DBPM3CURR:CONTROL-RECALIBRATE")
recalibrate_apply = PV("AGEBD-DBPM3CURR:CONTROL-RECALIBRATE-APPLY")
Npts = PV("AGEBD-DBPM3CURR:CONTROL-RECALIBRATE-NPTS")
## Service specific PVs from other IOCs
# ...
# Output PVs
charge = PV("AGEBD-DBPM3CURR:CHARGE-AVG")
calibration = PV("AGEBD-DBPM3CURR:CALIBRATION-DBPM3-2-PCT")
calibration_new = PV("AGEBD-DBPM3CURR:CALIBRATION-DBPM3-2-PCT-NEW")
# Input PVs
dump_valve = PV_PROD_READONLY("ARS01-VVPG-0210:PLC_STATUS.VAL")
pctmast = PV_PROD_READONLY("ARS07-DPCT-0000:CURR.VAL")
# pct0100 = PV_PROD_READONLY("ARS07-DPCT-0100:CURR.VAL")
# pct0200 = PV_PROD_READONLY("ARS07-DPCT-0200:CURR.VAL")
# BPMs
bpms = [
PV_PROD_READONLY("ARS01-DBPM-0390:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-0760:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS01-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS02-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-0810:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS03-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-0090:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-0900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS04-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-0410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS05-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS06-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-0810:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-0840:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS07-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS08-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-0570:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS09-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS10-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-0850:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS11-DBPM-5880:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-1080:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-1460:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-1900:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-2410:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-2910:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-4220:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-4720:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-5250:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-5530:POS-STG2-I.VAL"),
PV_PROD_READONLY("ARS12-DBPM-5880:POS-STG2-I.VAL"),
]
def __init__(self, service_name: str, pv_factory):
super().__init__(service_name, pv_factory)
PV = pv_factory
# TODO: can we do this cleaner? Maybe mechanism for
# settings initial values in dev mode (e.g. ini file)
if isinstance(self.onoff, LocalPVLink):
self.onoff.value = True
# Option 2:
## Service specific PVs from dedicated IOC
self.my_pv2 = PV(
"AGEBD-DBPM3CURR:BO"
) # TODO: is this a good PV to use?
## Service specific PVs from other IOCs
# ...
# TODO: class attribute names usually lowercase
# usually it is advisable to trigger the mainloop of a service on changes of certain PVs:
self.CallbackPV = PV(
"AGEBD-DBPM3CURR:CALLBACK", auto_monitor=dbr.DBE_VALUE
) # TODO: ok?
class Service(BaseService[PVs]):
@@ -56,41 +180,71 @@ class Service(BaseService[PVs]):
):
super().__init__(name, pvs, version, sleep_interval)
# TODO: What is this for?
self.path = "sls/bd/bin"
# initialize array for DBPM3 data
self.ChargeArrayBPMs = np.empty(len(pvs.bpms))
self.iter = 0
def update(self):
# when callback is fired, this code will be executed
if self.CallbackFired:
#######################################################################################
#######################################################################################
# here goes all the code that your service
# is supposed to be running when the callback is fired
time.sleep(1)
#######################################################################################
#######################################################################################
# set current to zero without beam
if not self.pvs.dump_valve.get() == 1:
charge = 0.0
else:
# get the charge reading from each BPM
# ChargeArrayBPMs[:] = [pv.get() for pv in self.pvs.bpms]
# callback done
self.CallbackFired = 0
cal = self.pvs.calibration.get()
lolo = -0.5 / cal
hihi = 500 / cal
#######################################################################################
#######################################################################################
# here goes all the code that your service
# is supposed to be running in any case, e.g.,
for i, pv in enumerate(self.pvs.bpms):
if not pv.connected:
print("{:} is not connected".format(pv.pvname))
val = np.nan
# update some pvs/vals
my_pv1_random_val = str(time.clock_gettime_ns(0))[-1]
self.pvs.my_pv1.put(my_pv1_random_val)
# self.pvs.my_pv2.put("MY_PV2 value")
else:
tmp = pv.get()
# get some pvs/vals
self.val1 = self.pvs.my_pv1.get()
self.val2 = self.pvs.my_pv2.get()
if lolo <= tmp <= hihi:
val = tmp
else:
val = np.nan
print("BPM charge out of range for {:}".format(pv.pvname))
# maybe sleep to limit the update loop execution rate
time.sleep(1)
#######################################################################################
#######################################################################################
self.ChargeArrayBPMs[i] = val
# calculate mean and write to PVs
charge = np.nanmean(self.ChargeArrayBPMs)
self.pvs.charge.put(charge)
if self.pvs.recalibrate.get() and charge > 0:
self.pvs.recalibrate.put(0)
Npts = int(self.pvs.Npts.get())
calibration = np.zeros(Npts + 1)
self.iter = 0
calibration[self.iter] = self.pvs.pctmast.get() / charge
self.iter += 1
if self.iter > 0:
if self.iter < Npts:
calibration[self.iter] = self.pvs.pctmast.get() / charge
self.iter += 1
elif self.iter == Npts:
calibration[self.iter] = self.pvs.pctmast.get() / charge
self.pvs.calibration_new.put(np.mean(calibration))
self.iter = 0
elif self.pvs.recalibrate_apply.get():
self.pvs.calibration.put(self.pvs.calibration_new.get())
def on_pause(self):
"""
Called when the service is transitioned to pause
Set current to zero when service is paused
"""
self.pvs.charge.put(0.0)
def main(