Skip to content

Commit aab4f28

Browse files
committed
[TASK] added orbit object
1 parent bd80771 commit aab4f28

File tree

4 files changed

+59
-16
lines changed

4 files changed

+59
-16
lines changed

src/dt4acc/custom_epics/ioc/pv_setup.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,14 @@ def initialize_magnet_pvs(builder, magnet):
4646
on_update=lambda val: handle_device_update(magnet_name, "K", val),
4747
)
4848
rdbk = builder.aIn(f"{magnet_name}:Cm:rdbk", initial_value=val)
49+
4950
async def handle_magnet_update(device_id: str, property_id: str, value: float):
50-
r = await handle_device_update(device_id=device_id, property_id=property_id, value=value)
51+
r = await handle_device_update(
52+
device_id=device_id, property_id=property_id, value=value
53+
)
5154
logger.info("%s:%s setting setpoint val=%s", device_id, property_id, value)
5255
rdbk.set(value)
53-
logger.info("%s:%s set readback val=%s", device_id, property_id,value)
56+
logger.info("%s:%s set readback val=%s", device_id, property_id, value)
5457
return r
5558

5659
builder.aOut(
@@ -111,9 +114,12 @@ def add_pc_pvs(builder, pc_name, prefix):
111114
)
112115
start_val = np.asarray(vals).mean()
113116
rdbk = builder.aOut(f"{pc_name}:rdbk", initial_value=start_val)
117+
114118
async def handle_pc_update(device_id: str, property_id: str, value: float):
115119
logger.debug("%s:%s updating setpoint val=%s", device_id, property_id, value)
116-
r = await handle_device_update(device_id=device_id, property_id=property_id, value=value)
120+
r = await handle_device_update(
121+
device_id=device_id, property_id=property_id, value=value
122+
)
117123
logger.debug("%s:%s updating rdbk val=%s", device_id, property_id, value)
118124
rdbk.set(value)
119125
return r
@@ -218,6 +224,18 @@ def initialize_bpm_pvs(builder):
218224
builder.longOut(f"{special_pvs['bpm_pv']}:count", initial_value=0)
219225

220226

227+
def initialize_orbit_object_pvs(builder):
228+
n_bpms = 128
229+
tmp = np.ravel(np.empty([n_bpms, 2], float))
230+
tmp.fill(np.nan)
231+
builder.WaveformOut("ORBITCC:rdPos", initial_value=tmp, length=len(tmp))
232+
tmp = np.ravel(np.empty([n_bpms, 4], float))
233+
tmp.fill(np.nan)
234+
builder.WaveformOut("ORBITCC:rdButtons", initial_value=tmp, length=len(tmp))
235+
builder.WaveformOut("ORBITCC:rdBpmNames", initial_value=[""], length=n_bpms)
236+
builder.longOut("ORBITCC:count", initial_value=0)
237+
238+
221239
def initialize_cavity_pvs(builder):
222240
"""
223241
Initializes PVs for RF cavities.

src/dt4acc/custom_epics/ioc/server.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
initialize_master_clock_pvs,
1111
initialize_orbit_pvs,
1212
initialize_bpm_pvs,
13+
initialize_orbit_object_pvs,
1314
initialize_twiss_pvs,
1415
initialize_other_pvs,
1516
)
@@ -35,6 +36,7 @@ def startup():
3536
initialize_power_converter_pvs(builder, prefix) # Initialize power converters and linked magnets
3637
initialize_orbit_pvs(builder) # Initialize orbit-related PVs
3738
initialize_bpm_pvs(builder) # Initialize Beam Position Monitor PVs
39+
initialize_orbit_object_pvs(builder) # Initialize PV's of the new orbit object ... collection of bpms
3840
initialize_twiss_pvs(builder) # Initialize Twiss parameter PVs
3941

4042
# Load the database of PVs defined above into the SoftIOC server

src/dt4acc/custom_epics/utils/bpm_mimicry.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,8 @@ def extract_bpm_data(self, orbit_result: Orbit):
6666
for name in self.bpm_names
6767
])
6868

69-
def extract_bpm_legacy_data(self, orbit_result: Orbit):
70-
"""
71-
Publish BPM data to EPICS.
69+
def extract_bpm_legacy_data_to_df(self, orbit_result: Orbit) -> pd.DataFrame:
70+
"""Publish BPM data to EPICS.
7271
7372
Args:
7473
orbit_result (OrbitResult): Result of the orbit calculation.
@@ -89,7 +88,7 @@ def extract_bpm_legacy_data(self, orbit_result: Orbit):
8988
bpm_names_as_index = pd.Series([f"empty_{cnt:03d}" for cnt in np.arange(128)])
9089
bpm_names_as_index.iloc[bpm_config["idx"]] = bpm_config["name"]
9190
df_bpm = pd.DataFrame(columns=["x", "y", "intensity_z", "intensity_s", "status", "x_rms", "y_rms"],
92-
index=bpm_names_as_index)
91+
index=bpm_names_as_index, dtype=float)
9392

9493
# Waring: order is lost!!!
9594
known_bpm_names = list(set(bpm_config["name"]).intersection(orbit_result.names))
@@ -98,7 +97,7 @@ def extract_bpm_legacy_data(self, orbit_result: Orbit):
9897
assert df_bpm.shape[0] == 128
9998

10099
# default values
101-
fill_value = 2 ** 15 - 1
100+
fill_value = np.nan
102101
df_bpm.loc[:, "x"] = fill_value
103102
df_bpm.loc[:, "y"] = fill_value
104103
df_bpm.loc[:, "y_rms"] = 0
@@ -118,8 +117,10 @@ def extract_bpm_legacy_data(self, orbit_result: Orbit):
118117
# needs to be at least a bit in 16 ...
119118
df_bpm.loc[known_bpm_names, "x_rms"] = 1
120119
df_bpm.loc[known_bpm_names, "y_rms"] = 1
120+
return df_bpm
121121

122-
tmp = np.empty([len(df_bpm), 8], dtype=np.int16)
122+
def bpm_legacy_data_df_to_array(self, bpm_data: pd.DataFrame) -> np.ndarray[np.int16]:
123+
tmp = np.empty([len(bpm_data), 8], dtype=np.int16)
123124
tmp.fill(0)
124125
mm2cnts = 2 ** 15 / 10
125126

@@ -128,19 +129,24 @@ def convert(vec):
128129
"""
129130
Todo: add test for maximum acceptable range
130131
"""
131-
r = np.clip(-2 ** 15 + 1, 2 ** 15 - 1, vec * mm2cnts)
132+
# mark invalid data
133+
tmp = vec.copy()
134+
tmp[np.isnan(vec)] = 2 ** 15 - 1
135+
r = np.clip(-2 ** 15 + 1, 2 ** 15 - 1, tmp * mm2cnts)
132136
return r.astype(np.int16)
133137

134-
tmp[:, 0] = convert(df_bpm.x)
135-
tmp[:, 1] = convert(df_bpm.y)
136-
tmp[:, 4] = df_bpm.status
137-
tmp[:, 6] = convert(df_bpm.x_rms)
138-
tmp[:, 7] = convert(df_bpm.y_rms)
138+
tmp[:, 0] = convert(bpm_data.x.values)
139+
tmp[:, 1] = convert(bpm_data.y.values)
140+
tmp[:, 4] = bpm_data.status
141+
tmp[:, 6] = convert(bpm_data.x_rms.values)
142+
tmp[:, 7] = convert(bpm_data.y_rms.values)
139143
bpm_legacy_data_vector = np.zeros([2048], np.int16)
140144
bpm_legacy_data_vector[:1024] = tmp.transpose().ravel()
141145

142146
return bpm_legacy_data_vector
143147

148+
def extract_bpm_legacy_data(self, orbit_result: Orbit):
149+
raise NotImplementedError("why still needed?")
144150

145151
@functools.lru_cache(maxsize=1)
146152
def create_bpm_config():

src/dt4acc/custom_epics/views/calculation_result_view.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Sequence
33

44
import numpy as np
5+
import pandas as pd
56
from p4p.client.asyncio import Context
67

78
from ...core.model.element_upate import ElementUpdate
@@ -100,12 +101,28 @@ async def push_bpms(self, orbit_data):
100101
raise ValueError("BPM Mimicry not set in ResultView")
101102
try:
102103
logger.warning(f"pushing legacy bpm data")
103-
bpm_legacy_data = self.bpm_mimicry.extract_bpm_legacy_data(orbit_data)
104+
df_bpm = self.bpm_mimicry.extract_bpm_legacy_data_to_df(orbit_data)
105+
bpm_legacy_data = self.bpm_mimicry.bpm_legacy_data_df_to_array(df_bpm)
104106
self.default_bpm_legacy_data = bpm_legacy_data
105107
await self.push_legacy_bpm_data(bpm_legacy_data)
108+
df_for_orbit = df_bpm.copy()
109+
mm2nm = 1e6
110+
df_for_orbit.x = df_bpm.x * mm2nm
111+
df_for_orbit.y = df_bpm.y * mm2nm
112+
await self.push_orbit_object(df_for_orbit)
106113
except Exception as e:
107114
logger.error(f"Error processing orbit data: {e}")
108115

116+
async def push_orbit_object(self, bpm_data: pd.DataFrame):
117+
try:
118+
prefix = f"{self.prefix}:ORBITCC"
119+
# Todo: check that the dimensions are properly made
120+
pos = np.array(bpm_data.loc[:, ["x", "y"]]).ravel()
121+
await ctx.put(f"{prefix}:rdPos", pos)
122+
await ctx.put(f"{prefix}:rdBpmNames", [str(val) for val in bpm_data.index])
123+
except Exception as e:
124+
logger.error(f"Error processing orbit object data: {e}")
125+
109126
async def push_legacy_bpm_data(self, bpm_legacy_data: Sequence[np.int16] = None):
110127
"""
111128
Push BPM data to EPICS. If no data is provided, push the default data.

0 commit comments

Comments
 (0)