Skip to content

Commit e7c89e2

Browse files
committed
new changes wiht custom_tango
1 parent 3d27c8c commit e7c89e2

23 files changed

+2451
-194
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ wheels/
4444
*.pyc
4545
*.pyo
4646
__pycache__/
47-
47+
**/.DS_Store
4848
venv*/

src/dt4acc/custom_tango/README.md

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
# DT4ACC Tango Implementation
2+
3+
## Overview
4+
This module implements the Tango-based control system for the DT4ACC (Digital Twin for Accelerator Control) project. It provides device servers and clients for managing accelerator components through the Tango control system.
5+
6+
## Architecture
7+
8+
### System Components
9+
```
10+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
11+
│ Tango DB │ │ Tango Server │ │ Tango Client │
12+
│ (Device Info) │◄────┤ (Devices) │◄────┤ (ResultView) │
13+
└─────────────────┘ └─────────────────┘ └─────────────────┘
14+
```
15+
16+
### Component Structure
17+
```
18+
Tango System
19+
├── Server Side
20+
│ ├── Device Classes
21+
│ │ ├── TwissOrbitDevice
22+
│ │ │ ├── Attributes
23+
│ │ │ │ ├── orbit_x, orbit_y
24+
│ │ │ │ ├── twiss_alpha_x, twiss_beta_x
25+
│ │ │ │ └── magnet_strengths
26+
│ │ │ └── Commands
27+
│ │ │ ├── update_orbit
28+
│ │ │ └── update_twiss
29+
│ │ ├── BPMDevice
30+
│ │ │ ├── Attributes
31+
│ │ │ │ └── bpm_data
32+
│ │ │ └── Commands
33+
│ │ │ └── update_bpm
34+
│ │ ├── MagnetDevice
35+
│ │ │ ├── Attributes
36+
│ │ │ │ ├── main_strength
37+
│ │ │ │ ├── x_kick
38+
│ │ │ │ ├── y_kick
39+
│ │ │ │ ├── powersupply_current
40+
│ │ │ │ └── device_state
41+
│ │ │ └── Commands
42+
│ │ │ ├── set_strength
43+
│ │ │ ├── set_kick
44+
│ │ │ └── reset
45+
│ │ └── PowerConverterDevice
46+
│ │ ├── Attributes
47+
│ │ │ ├── set_current
48+
│ │ │ ├── readback_current
49+
│ │ │ └── device_state
50+
│ │ └── Commands
51+
│ │ ├── set_current
52+
│ │ └── reset
53+
│ └── Device Registration
54+
│ ├── Database Setup
55+
│ └── Device Info
56+
└── Client Side
57+
├── ResultView
58+
│ ├── Device Proxies
59+
│ ├── Update Methods
60+
│ └── Error Handling
61+
├── BPM Data Handling
62+
└── Heartbeat Monitoring
63+
```
64+
65+
## Installation
66+
67+
### Prerequisites
68+
- Python 3.8+
69+
- Tango Control System
70+
- pytango
71+
- PyTango
72+
- NumPy
73+
74+
### Setup
75+
1. running Tango Control System
76+
```bash
77+
# For Ubuntu/Debian
78+
sudo DataBaseds 2 -ORBendPoint giop:tcp::10000
79+
```
80+
81+
## Usage
82+
83+
### Starting the Server
84+
```bash
85+
# Start Tango server
86+
python -m dt4acc.custom_tango.tango_server test
87+
```
88+
89+
### Using the Client
90+
```python
91+
from dt4acc.custom_tango.views.calculation_result_view import ResultView
92+
93+
# Initialize ResultView
94+
view = ResultView(prefix="tango_server/test")
95+
96+
# Update orbit data
97+
await view.push_orbit(orbit_data)
98+
99+
# Update Twiss parameters
100+
await view.push_twiss(twiss_data)
101+
102+
# Update BPM data
103+
await view.push_bpms(bpm_data)
104+
105+
# Update magnet strength
106+
await view.push_value(ElementUpdate(
107+
element_id="magnet_name",
108+
property_name="K",
109+
value=new_strength
110+
))
111+
```
112+
113+
## Device Details
114+
115+
### MagnetDevice
116+
The MagnetDevice class manages individual magnets in the accelerator:
117+
118+
```python
119+
class MagnetDevice(Device):
120+
def __init__(self):
121+
# Attributes
122+
self.main_strength = 0.0 # Main magnetic field strength
123+
self.x_kick = 0.0 # Horizontal kick
124+
self.y_kick = 0.0 # Vertical kick
125+
self.powersupply_current = 0.0 # Current power supply value
126+
self.device_state = DevState.ON # Device state
127+
128+
def set_strength(self, value):
129+
"""Set the main magnetic field strength"""
130+
self.main_strength = value
131+
self._update_power_supply()
132+
133+
def set_kick(self, x_kick=None, y_kick=None):
134+
"""Set horizontal and/or vertical kicks"""
135+
if x_kick is not None:
136+
self.x_kick = x_kick
137+
if y_kick is not None:
138+
self.y_kick = y_kick
139+
self._update_power_supply()
140+
141+
def _update_power_supply(self):
142+
"""Update power supply based on strength and kicks"""
143+
# Implementation of power supply update logic
144+
pass
145+
```
146+
147+
### PowerConverterDevice
148+
Manages the power supply for magnets:
149+
150+
```python
151+
class PowerConverterDevice(Device):
152+
def __init__(self):
153+
# Attributes
154+
self.set_current = 0.0
155+
self.readback_current = 0.0
156+
self.device_state = DevState.ON
157+
158+
def set_current(self, value):
159+
"""Set the current value"""
160+
self.set_current = value
161+
self._update_readback()
162+
163+
def _update_readback(self):
164+
"""Update readback value"""
165+
pass
166+
```
167+
168+
## Data Flow
169+
170+
### Magnet Update Flow
171+
```
172+
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
173+
│ Client │ │ResultView│ │ Magnet │ │ Power │
174+
│ │ │ │ │ Device │ │ Converter│
175+
└────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
176+
│ │ │ │
177+
│ push_value() │ │ │
178+
│───────────────►│ │ │
179+
│ │ set_strength() │ │
180+
│ │────────────────►│ │
181+
│ │ │ _update_ps() │
182+
│ │ │───────────────►│
183+
│ │ │ │
184+
│ │ │ OK │
185+
│ │ │◄───────────────│
186+
│ │ OK │ │
187+
│ │◄────────────────│ │
188+
│ OK │ │ │
189+
│◄───────────────│ │ │
190+
```
191+
192+
### Orbit Update Flow
193+
```
194+
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
195+
│ Client │ │ResultView│ │ Device │ │ Server │
196+
│ │ │ │ │ Proxy │ │ │
197+
└────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
198+
│ │ │ │
199+
│ push_orbit() │ │ │
200+
│───────────────►│ │ │
201+
│ │ _get_device() │ │
202+
│ │────────────────►│ │
203+
│ │ │ write_attribute│
204+
│ │ │───────────────►│
205+
│ │ │ │
206+
│ │ │ OK │
207+
│ │ │◄───────────────│
208+
│ │ │ │
209+
│ │ OK │ │
210+
│ │◄────────────────│ │
211+
│ OK │ │ │
212+
│◄───────────────│ │ │
213+
```
214+
215+
### Heartbeat Flow
216+
```
217+
┌──────────┐ ┌──────────┐ ┌──────────┐
218+
│Heartbeat │ │ResultView│ │ Device │
219+
│ Loop │ │ │ │ Proxy │
220+
└────┬─────┘ └────┬─────┘ └────┬─────┘
221+
│ │ │
222+
│ heart_beat() │ │
223+
│───────────────►│ │
224+
│ │ ping() │
225+
│ │────────────────►│
226+
│ │ │
227+
│ │ OK │
228+
│ │◄────────────────│
229+
│ OK │ │
230+
│◄───────────────│ │
231+
```
232+
233+
## Error Handling
234+
235+
### Connection Errors
236+
The system implements automatic reconnection with exponential backoff:
237+
```python
238+
async def _get_device(self):
239+
try:
240+
return DeviceProxy(self.device_name)
241+
except DevFailed as e:
242+
if self._reconnect_attempts < self._max_reconnect_attempts:
243+
self._reconnect_attempts += 1
244+
await asyncio.sleep(self._reconnect_delay)
245+
return await self._get_device()
246+
else:
247+
logger.error(f"Max reconnection attempts reached: {e}")
248+
raise
249+
```
250+
251+
### Data Validation
252+
All data is validated before being sent to devices:
253+
```python
254+
def convert_to_list(data: Union[Sequence, np.ndarray]) -> List:
255+
if isinstance(data, np.ndarray):
256+
data = np.nan_to_num(data, nan=0.0, posinf=0.0, neginf=0.0)
257+
return data.tolist()
258+
return list(data)
259+
```
260+
261+
## Key Features
262+
263+
1. **Device Management**
264+
- Automatic device registration
265+
- Device state monitoring
266+
- Reconnection handling
267+
268+
2. **Data Handling**
269+
- Type conversion
270+
- Data validation
271+
- Error checking
272+
273+
3. **Communication**
274+
- Asynchronous updates
275+
- Heartbeat monitoring
276+
- Error recovery
277+
278+
4. **Security**
279+
- Device access control
280+
- Data validation
281+
- Error logging
282+
283+
## Testing
284+
285+
Run the test suite:
286+
```bash
287+
python -m pytest tests/
288+
```
289+
290+
291+
292+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import os
2+
from tango import Database, DeviceProxy
3+
from dt4acc.custom_tango.server_config import SERVER_NAME, SERVER_INSTANCE
4+
5+
os.environ["TANGO_HOST"] = "localhost:10000"
6+
7+
def check_server_status():
8+
try:
9+
admin = DeviceProxy('dserver/tango_server/test')
10+
print("\nServer Status:")
11+
print("-" * 50)
12+
print(f"Server: {SERVER_NAME}")
13+
print(f"Server name: {admin.name()}")
14+
print(f"Server state: {admin.state()}")
15+
print(f"Server status: {admin.status()}")
16+
print("-" * 50)
17+
18+
# List all devices
19+
print("\nRegistered Devices:")
20+
print("-" * 50)
21+
db = Database()
22+
devices = db.get_device_name('tango_server/test', '*')
23+
for device in devices:
24+
print(f"Device: {device}")
25+
print("-" * 50)
26+
27+
except Exception as e:
28+
print(f"Error checking server status: {e}")
29+
30+
if __name__ == "__main__":
31+
check_server_status()

src/dt4acc/custom_tango/config.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
SERVER_NAME = "tango_server"
3+
SERVER_CLASS = "TangoServer"
4+
SERVER_INSTANCE = "test"
5+
6+
DEVICE_NAME_FORMAT = "{device_type}_{name}"
7+
FULL_DEVICE_NAME_FORMAT = f"{SERVER_NAME}/{SERVER_INSTANCE}/{{device_name}}"
8+
9+
DEVICE_CLASSES = {
10+
"MagnetDevice": "MagnetDevice",
11+
"PowerConverterDevice": "PowerConverterDevice",
12+
"TwissOrbitDevice": "TwissOrbitDevice",
13+
"BPMDevice": "BPMDevice"
14+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
SERVER_NAME = "tango_server/test"
2+
DEVICE_NAME = "PowerConverterDevice_VS3P2T2R"
3+
4+
POWER_CONVERTER_DEVICE = f"{SERVER_NAME}/{DEVICE_NAME}"
5+
6+
print(f"Using device path: {POWER_CONVERTER_DEVICE}")

0 commit comments

Comments
 (0)