Skip to content

Commit

Permalink
Merge pull request #5 from hz-b/dev/feature/redirect-through-proxy
Browse files Browse the repository at this point in the history
Flag calculation in progress / inhibit bpm data update when calculation in progress
  • Loading branch information
Sulimankhail authored Mar 4, 2024
2 parents e04d47b + ad8bff0 commit cc42678
Show file tree
Hide file tree
Showing 15 changed files with 333 additions and 86 deletions.
11 changes: 9 additions & 2 deletions src/dt4acc/accelerators/accelerator_impl.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from collections import UserList
from typing import Union

from ..device_interface.event import Event
from ..device_interface.delay_execution import DelayExecution
from dt4acc.bl.event import Event
from dt4acc.bl.delay_execution import DelayExecution
from ..interfaces.accelerator_interface import AcceleratorInterface
from ..interfaces.element_interface import ElementInterface

Expand Down Expand Up @@ -37,6 +37,13 @@ def cb_orbit():

self.on_changed_value = Event()

# Shall one subscribe to the object below or should one just hand it through?
# this all seems to call for a message bus ...
self.on_orbit_calculation_request = self.orbit_calculation_delay.on_calculation_requested
self.on_orbit_calculation = self.orbit_calculation_delay.on_calculation
self.on_twiss_calculation_request = self.twiss_calculation_delay.on_calculation_requested
self.on_twiss_calculation = self.twiss_calculation_delay.on_calculation

def set_delay(self, delay: Union[float, None]):
"""How much to delay twiss and orbit calculation after last received comamnd
"""
Expand Down
2 changes: 1 addition & 1 deletion src/dt4acc/accelerators/element_proxies.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ..device_interface.event import Event
from dt4acc.bl.event import Event
from ..interfaces.element_interface import ElementInterface
from ..model.element_upate import ElementUpdate

Expand Down
12 changes: 9 additions & 3 deletions src/dt4acc/accelerators/pyat_accelerator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import logging

from ..accelerators.accelerator_impl import AcceleratorImpl
from ..accelerators.proxy_factory import PyATProxyFactory
from ..calculator.pyat_calculator import PyAtTwissCalculator, PyAtOrbitCalculator
Expand All @@ -16,15 +18,19 @@
view = ResultView(prefix=prefix +":beam")
#: todo into a controller to pass prefix as parameter at start ?
elem_par_view = ElementParameterView(prefix=prefix)
bpm_names_pyat = [elem.FamName for elem in accelerator.acc if "bpm" in elem.FamName]
bpm_names_pyat = [elem.FamName for elem in accelerator.acc if "BPM" == elem.FamName[:3]]
bpm_pyat = BPMMimikry(prefix=prefix, bpm_names=bpm_names_pyat)
accelerator.on_new_orbit.append(view.push_orbit)
accelerator.on_changed_value.append(elem_par_view.push_value)


logger = logging.getLogger("dt4acc")


def cb(orbit_data: Orbit):
reduced_data_pyat = bpm_pyat.extract_bpm_data_from_orbit(orbit_data)
view.push_bpms(reduced_data_pyat)
# Todo: push all orbit data to beam
bpm_data = bpm_pyat.extract_bpm_data(orbit_data)
view.push_bpms(bpm_data)


accelerator.on_new_orbit.append(cb)
Expand Down
2 changes: 1 addition & 1 deletion src/dt4acc/accelerators/thor_scsi_accelerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@


def cb(orbit_data: Orbit):
reduced_data = bpm.extract_bpm_data_from_orbit(orbit_data)
reduced_data = bpm.pyat_orbit_data_to_model(orbit_data)
view.push_bpms(reduced_data)


Expand Down
Empty file added src/dt4acc/bl/__init__.py
Empty file.
32 changes: 32 additions & 0 deletions src/dt4acc/bl/context_manager_with_trigger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import logging
from .event import StatusChange

logger = logging.getLogger("dt4acc")


class ReportOnExitContextManager:
def __enter__(self):
logger.debug("Report exit enter")
pass

def __exit__(self, exc_type, exc_val, exc_tb):
logger.debug("Report exit")
if exc_type is None:
return
logger.error(
f"execution of trigger failed {exc_type}({exc_val})"
)


class TriggerEnterExitContextManager:
def __init__(self, event: StatusChange):
assert callable(event.trigger)
self.event = event

def __enter__(self):
with ReportOnExitContextManager():
self.event.trigger(True)

def __exit__(self, exc_type, exc_val, exc_tb):
with ReportOnExitContextManager():
self.event.trigger(False)
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import logging
import queue
import threading
import time
import datetime
from typing import Union

from .event import Event
from queue import Queue
from .context_manager_with_trigger import TriggerEnterExitContextManager

logger = logging.getLogger("dt4acc")
from .event import StatusChange
from queue import Queue


class DelayExecution:
Expand All @@ -21,14 +20,30 @@ class DelayExecution:
"""

def __init__(self, *, callback, delay: Union[float, None]):
self.callback = callback
self._callback = callback
self.set_delay(delay)

self.pending_queue = Queue() # Queue for managing pending executions
self.worker_thread = threading.Thread(target=self.worker)
self.worker_thread.daemon = True # Daemonize the worker thread
self.worker_thread.start()
self.calculation_requested = False
self._calculation_requested = False
self.on_calculation = StatusChange()
self.on_calculation_requested = StatusChange()

@property
def calculation_requested(self):
return self._calculation_requested

@calculation_requested.setter
def calculation_requested(self, flag: bool):
flag = bool(flag)
self.on_calculation_requested.trigger(flag)
self._calculation_requested = flag

def callback(self):
with TriggerEnterExitContextManager(self.on_calculation):
return self._callback()

def set_delay(self, delay: Union[float, None]):
if delay is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ def trigger(self, obj):
for callback in self:
callback(obj)


class StatusChange(Event):
def trigger(self, flag: bool):
return super().trigger(flag)
34 changes: 28 additions & 6 deletions src/dt4acc/command.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import os

from .bl.context_manager_with_trigger import TriggerEnterExitContextManager
from .bl.event import Event
from .update_context_manager import UpdateContext
from .view.calculation_progress_view import StatusFlagView
import os

CALCULATION_ENGINE_default = os.environ["CALCULATION_ENGINE"]

Expand All @@ -16,6 +18,25 @@
def publish(*, what):
print(f"Need to implement publishing {what}?")


# Signals to EPICS:
# that an update is in progress
prefix = "Pierre:DT"
view = StatusFlagView(prefix=f"{prefix}:dt:im:updates")
on_update_event = Event()
on_update_event.append(view.on_update)

# signal if orbit or twiss calculations are requested
view = StatusFlagView(prefix=f"{prefix}:dt:im:calc:orbit:exc")
acc.on_orbit_calculation.append(view.on_update)
view = StatusFlagView(prefix=f"{prefix}:dt:im:calc:orbit:req")
acc.on_orbit_calculation_request.append(view.on_update)

view = StatusFlagView(prefix=f"{prefix}:dt:im:calc:twiss:exc")
acc.on_orbit_calculation.append(view.on_update)
view = StatusFlagView(prefix=f"{prefix}:dt:im:calc:twiss:req")
acc.on_orbit_calculation_request.append(view.on_update)

def update(*, element_id, property_name, value=None):
"""
What to do here:
Expand All @@ -26,8 +47,9 @@ def update(*, element_id, property_name, value=None):
Who takes care of the read back
Is value=None a value user wants to set?
If so get an other place holder..
If so get another placeholder..
"""
with UpdateContext(element_id=element_id, property_name=property_name, value=value, kwargs=dict()):
elem_proxy = acc.get_element(element_id)
elem_proxy.update(property_name, value)
with TriggerEnterExitContextManager(on_update_event):
with UpdateContext(element_id=element_id, property_name=property_name, value=value, kwargs=dict()):
elem_proxy = acc.get_element(element_id)
elem_proxy.update(property_name, value)
8 changes: 4 additions & 4 deletions src/dt4acc/device_interface/bpm_mimikry.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(self, *, prefix, bpm_names):
self.prefix = prefix
self.bpm_names = bpm_names

def extract_bpm_data_from_orbit(self, orbit_result: Orbit):
def extract_bpm_data(self, orbit_result: Orbit):
"""
Publish BPM data to EPICS.
Expand All @@ -49,6 +49,6 @@ def extract_bpm_data_from_orbit(self, orbit_result: Orbit):
return

# find indices where the names are ..
df = pd.DataFrame(index=["x", "y"], columns=orbit_result.names, data=[orbit_result.x, orbit_result.y]).T.loc[
self.bpm_names, :]
return Orbit(x=df.x.values, y=df.y.values, names=df.index.values, found=orbit_result.found, x0=orbit_result.x0)
df = pd.DataFrame(index=["x", "y"], columns=orbit_result.names, data=[orbit_result.x, orbit_result.y]).T
df_bpm = df.loc[self.bpm_names, :]
return Orbit(x=df_bpm.x.values, y=df_bpm.y.values, names=df_bpm.index.values, found=orbit_result.found, x0=orbit_result.x0)
14 changes: 14 additions & 0 deletions src/dt4acc/view/calculation_progress_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import logging
import pydev

logger = logging.getLogger("dt4acc")


class StatusFlagView:
def __init__(self, *, prefix):
self.prefix = prefix

def on_update(self, flag: bool):
val = int(flag)
pydev.iointr(self.prefix, val)
logger.debug("sent label %s, val %s", self.prefix, val)
28 changes: 24 additions & 4 deletions src/dt4acc/view/calculation_result_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pydev


from ..model.element_upate import ElementUpdate
from ..model.orbit import Orbit
from ..model.twiss import Twiss
Expand All @@ -26,7 +27,7 @@ def __init__(self, *, prefix):
def push_orbit(self, orbit_result: Orbit):
label = f"{self.prefix}:orbit:found"
logger.warning('label %s = %s type(%s)', label, orbit_result.found, type(orbit_result.found))
pydev.iointr(label, orbit_result.found)
pydev.iointr(label, bool(orbit_result.found))
pydev.iointr(f"{self.prefix}:orbit:x", orbit_result.x)
pydev.iointr(f"{self.prefix}:orbit:y", orbit_result.y)
label = f"{self.prefix}:names"
Expand All @@ -51,6 +52,25 @@ def push_twiss(self, twiss_result: Twiss):
# fmt:on

def push_bpms(self, bpm_result: Orbit):
pydev.iointr(f"{self.prefix}:bpm:x", list(bpm_result.x))
pydev.iointr(f"{self.prefix}:bpm:y", list(bpm_result.y))
pydev.iointr(f"{self.prefix}:bpm:names", list(bpm_result.names))
"""
Todo:
implement that data is pushed to bdata
or make it unnecssary ...
Warning:
Current implementation is broken
"""
import numpy as np

n_entries = 128
n_found = len(bpm_result.x)
bdata = np.zeros([8, n_entries], dtype=float)
bdata[0, :n_found] = bpm_result.x
bdata[1, :n_found] = bpm_result.y
pydev.iointr(f"{self.prefix}:bpm:bdata", list(bdata.ravel()))

pydev.iointr(f"{self.prefix}:bpm:dx", list(bpm_result.x))
pydev.iointr(f"{self.prefix}:bpm:dy", list(bpm_result.y))
pydev.iointr(f"{self.prefix}:bpm:names", [bytes(name.encode("utf8")) for name in bpm_result.names])


8 changes: 4 additions & 4 deletions vaccelApp/Db/beam.rec
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ record(ao, "$(PREFIX):beam:orbit:im:eps")
field(TPRO, 0)
}

record(bi, "$(PREFIX):beam:orbit:found")
record(longin, "$(PREFIX):beam:orbit:found")
{
field(DESC, "Closed orbit: fixed point found?")
field(ZNAM, "particle lost")
field(ONAM, "found")
# field(ZNAM, "particle lost")
# field(ONAM, "found")

field(DTYP, "pydev")
field(INP, "@pydev.iointr('$(PREFIX):beam:orbit:found')")
Expand Down Expand Up @@ -188,7 +188,7 @@ record(waveform, "$(PREFIX):beam:names")
field(SCAN, "I/O Intr")
field(NELM, 2048)
field(FTVL, "STRING")
field(TPRO, 1)
field(TPRO, 0)
}

record(longout, "$(PREFIX):beam:publish")
Expand Down
Loading

0 comments on commit cc42678

Please sign in to comment.