Closed prjemian closed 3 months ago
While the documentation of numpy.allclose()
that says the shapes can be different should be fixed, there is still the problem that EPICS returns the full array. Ophyd needs to trim that EPICS array down to the size of the target array.
Both fixes can be applied by inserting code just before this line: https://github.com/bluesky/ophyd/blob/9c77d86cd7c3b1c6e34d88b9b3eed27063c9b616/ophyd/utils/epics_pvs.py#L338
I propose inserting these lines:
array_like = (list, np.ndarray, tuple)
if isinstance(a, array_like) and isinstance(b, array_like):
# 2024-07-30, prj:
# np.allclose(a, b) fails when both a & b are different shaped arrays
# If only one is a numpy array, then np.allclose does not fail.
# np.allclose() calls np.isclose() which has a comment that states
# the two arrays "must be the same shape."
a = np.array(a) # target
b = np.array(b) # reported by EPICS
if len(a.shape) == 1 and len(b.shape) == 1 and len(a) < len(b):
# Some EPICS arrays always return full size, even if only less is written.
# EPICS CA arrays are always 1-D.
b = b[:len(a)] # cut 1-D EPICS array down to requested size
if a.shape != b.shape:
return False
A fix here is critical to our fly scans at the APS.
With my fix added locally, the EpicsSignal.set()
method does not raise the FailedStatus exception for arrays with different lengths.
If you put
across CA to an array with less than the full array is the expected semantics:
?
When we "put" to an array should we be resetting the size as well or is the issue that the monitor is providing up to max size rather than the current size?
When we "put" to an array should we be resetting the size as well or is the issue that the monitor is providing up to max size rather than the current size?
Neither, actually. The current .put()
works properly. The .get()
always returns the full array (the max size). But the comparison should always truncate the array from .get()
to the length of the provided array (the one sent to .put()
) for the comparison of Did we get there yet?
We want to write to some array PVs (such as positioner arrays in the sscan record, array fields in the array calcs). We know we can do this with the
EpicsSignal.put()
method. It works. What fails is the QA process associated with the.set()
method that assures the EPICS PV has reached the values we wrote.When writing an array (list, np.ndarray, tuple) to an EpicsSignal connected to such a PV, the ophyd code stops with an FailedStatus exception that points to this chain:
ophyd.utils._wait_for_value()
line 295ophyd.utils._compare_maybe_enum()
line 341np.core.numeric.allclose()
line 2241np.core.numeric.isclose()
line 2332, which fails due toabs(x-y)
One failure is that the two arrays passed must have the same shape (or this operation in numpy fails).
Another part of the failure is that EPICS Channel Access (used by EpicsSignal) always returns (since we have not told it to return less) the full array, not just the limited part we wanted to write.
Demonstrate the problem
Such an EPICS PV:
pjgp:userArrayCalc1.AA
ophyd 1.9.0, numpy 1.26.4
Show the problem using
EpicsSignal.set()
:numpy demo