Skip to content

13 adding a field for catalog name for the control system and a catalog registration method new impl#16

Open
gupichon wants to merge 26 commits into
mainfrom
13-adding-a-field-for-catalog-name-for-the-control-system-and-a-catalog-registration-method-new-impl
Open

13 adding a field for catalog name for the control system and a catalog registration method new impl#16
gupichon wants to merge 26 commits into
mainfrom
13-adding-a-field-for-catalog-name-for-the-control-system-and-a-catalog-registration-method-new-impl

Conversation

@gupichon
Copy link
Copy Markdown
Contributor

@gupichon gupichon commented Apr 27, 2026

Summary

This PR adapts pyaml-cs-oa to the new PyAML API and adds catalog support to resolve EPICS and Tango devices from PyAML keys.

Main Changes

  • add a catalog field to the OphydAsyncControlSystem configuration
  • add static and dynamic catalogs for EPICS, plus a dynamic catalog for Tango
  • add support for indexed access to vector signals through index, read_index, and write_index
  • update signal wrappers to support reading a single array element and targeted read-modify-write updates
  • tighten Pydantic models and apply related cleanup

Closes #13

Impact

This branch makes pyaml-cs-oa easier to integrate with PyAML's new resolution mechanisms while covering both scalar and vector signals, including partial access to array values.

Dependency

The related PyAML developments are available in branch 187-adding-catalogs-section-in-the-pyaml-configuration-file-new-implementation (PR #234).

…SetpointIndexed into OAReadback/OASetpoint with optional index, add read_index/write_index to EpicsConfigRW, and replace string-based static catalog entries with typed EpicsStaticCatalogEntry objects.

Add EpicsCatalog dynamic catalog (key = PV spec string) and EpicsStaticCatalog with structured per-entry signal configs; remove _epics_pv_builder module by inlining its logic into EpicsCatalog.
@JeanLucPons
Copy link
Copy Markdown
Contributor

There are 17 files modified + 36 files modified in pyaml !
Would it be possible to try to cut in several smaller updates with well defined tasks ?

However i did a small check on BESSY2 example reading an orbit:

sr = Accelerator.load("BESSY2Orbit.yaml")
SR = sr.live
orbit = SR.get_bpms("BPM").positions
print(orbit.get())

Here is what i get ?

[[3285.8356434 3285.8356434]
 [3285.8356434 3285.8356434]
 [3285.8356434 3285.8356434]
 [3285.8356434 3285.8356434]
 [3285.8356434 3285.8356434]
 [3285.8356434 3285.8356434]
...

Here is what i expect:

[[ 3.28583564e+03  0.00000000e+00]
 [ 2.19512518e+03  0.00000000e+00]
 [ 1.12020909e+04  0.00000000e+00]
 [ 1.75602034e+04  0.00000000e+00]
 [ 9.97247501e+03  0.00000000e+00]
 [-1.08780425e+03  0.00000000e+00]
 [-6.43913112e+02  0.00000000e+00]
...

@gupichon
Copy link
Copy Markdown
Contributor Author

How do you simulate the live?
I would like to reproduce it locally.

@gupichon
Copy link
Copy Markdown
Contributor Author

There are 17 files modified + 36 files modified in pyaml !
Would it be possible to try to cut in several smaller updates with well defined tasks ?

I realize it's a substantial PR, but since it’s a major architectural change, it’s difficult to break it down into smaller updates, they wouldn't make much sense in isolation as the pyaml branch (187-adding-catalogs-section-in-the-pyaml-configuration-file-new-implementation) requires the full implementation to be functional.

The main parts of this update are:

  • Catalog integration for the ControlSystem class.
  • Support for indexes in DeviceAccess implementations (this is the most significant change).
  • Static and dynamic catalogs (mostly consisting of new files).

@JeanLucPons
Copy link
Copy Markdown
Contributor

It is important to try to cut in smaller task otherwise it is too difficult even impossible to review.
For instance:

  • New Device Access interface.
  • Static catalog.
  • Dynamic catalog.
  • Indexed attribute.
    etc...

For examples, you have them in pyam/examples (including the soleil ones) with README that explain how to run them.

@JeanLucPons
Copy link
Copy Markdown
Contributor

I made the BESSY2 example working.
However, the factoring of signals is not done and the reading of the same PV is done once for each BPM when reading using aggregator. There is now a significant job in scalar_aggretor to factor reading (and writing) of indexed value.
The indexed_signal.py is not needed.

Comment thread pyaml_cs_oa/container.py
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handle error here when the get_value() return a float and and index is present.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's done

@gupichon
Copy link
Copy Markdown
Contributor Author

I made the BESSY2 example working. However, the factoring of signals is not done and the reading of the same PV is done once for each BPM when reading using aggregator. There is now a significant job in scalar_aggretor to factor reading (and writing) of indexed value. The indexed_signal.py is not needed.

Thank you very much for this contribution. I agree with you, but I would like to postpone these optimizations until we have fully functional catalogs, at least for the BPMs.

Comment thread pyaml_cs_oa/container.py
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is hasattr() needed ?
hasattr is a slow call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it was completely unnecessary, except for the specific error message. I've removed it.

@JeanLucPons
Copy link
Copy Markdown
Contributor

print in epcis.py: get_SP_RB() method.

ORBITCC:rdPos:<ophyd_async.core._signal.SignalR object at 0x7f6f440f1550>
ORBITCC:rdPos:<ophyd_async.core._signal.SignalR object at 0x7f6f440f1760>
pons:ORBITCC:rdPos:<ophyd_async.core._signal.SignalR object at 0x7f6f440f19a0>
pons:ORBITCC:rdPos:<ophyd_async.core._signal.SignalR object at 0x7f6f440f1bb0>

It seems that unattached signal are created ?!!!

@JeanLucPons
Copy link
Copy Markdown
Contributor

I patched epics.py to avoid duplication of signal (epics only) for aggregators implementation.
Tango will need ophyd async 0.17 which should be published soon

@JeanLucPons
Copy link
Copy Markdown
Contributor

I committed a first implementation of aggregator (it supports only read or readback for the moment) but it should be however compatible with the rest.

@JeanLucPons
Copy link
Copy Markdown
Contributor

For me it is stilll unclear how Catalog works and why unattached signal are constructed as shown above ?

JeanLucPons and others added 6 commits April 30, 2026 07:44
…ontrol-system-and-a-catalog-registration-method-new-impl
Update live tune integration configs for current PyAML tune API
Add EPICS catalog tests for dynamic and static resolution
Removing useless imports
Add coverage for catalog config, EPICS/Tango lookups, indexed devices, and get_device error paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adding a field for catalog name for the control system and a catalog registration method

3 participants