Skip to content

Commit 5c958e9

Browse files
committed
Initialization
0 parents  commit 5c958e9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2053
-0
lines changed

.gitignore

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# PyCharm
2+
.idea/
3+
4+
# Emacs auto save files
5+
*~
6+
7+
# build files
8+
*.o
9+
10+
# Library files
11+
*.so
12+
*.a
13+
14+
# Byte-compiled / optimized / DLL files
15+
__pycache__/
16+
*.py[cod]
17+
*$py.class
18+
19+
# C extensions
20+
*.so
21+
22+
# Directories created by the build process
23+
bin/
24+
lib/
25+
include/
26+
dbd/
27+
db/
28+
configure/O.linux-x86_64/
29+
vaccelApp/Db/O.linux-x86_64/
30+
vaccelApp/Db/O.Common/
31+
vaccelApp/src/O.Common/
32+
vaccelApp/src/O.linux-x86_64/
33+
34+
# Files created by magnet_info_from_db
35+
vaccelApp/src/*.inc
36+
*.inc
37+
38+
# envPaths: built during first make after make clean
39+
iocBoot/iocvaccel/envPaths
40+
41+
# python related stuff
42+
src/dist/
43+
*.pyc
44+
*.pyo
45+
__pycache__/

pyproject.toml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[build-system]
2+
requires = [ "poetry-core>=1.0.0",]
3+
build-backend = "poetry.core.masonry.api"
4+
5+
[tool.poetry]
6+
name = "lat2db"
7+
version = "0.0.1"
8+
description = "Storing accelerator lattices as json in mongo"
9+
authors = [ "Waheedullah Sulaiman Khail", "Pierre Schnizer", "Teresia Olsson"]
10+
license = "GPL-3.0"
11+
homepage = "https://github.com/hz-b/bact-bessyii-ophyd"
12+
documentation = "https://github.com/hz-b/bact-bessyii-ophyd"
13+
repository = "https://github.com/hz-b/bact-bessyii-ophyd.git"
14+
keywords = []
15+
16+
[tool.poetry.dependencies]
17+
python = ">=3.7"
18+
fastapi="*"
19+
pymongo="*"
20+
pydantic="*"
21+
jsons="*"
22+
uuid="*"
23+
pytest="*"
24+
attrs="*"
25+
numpy="*"
26+
uvicorn="*"
27+
httpx="*"
28+
lark="*"
29+
accelerator-toolbox="*"

requirements.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pymongo~=4.10.1
2+
setuptools~=71.1.0
3+
4+
pydantic~=2.10.5
5+
softioc~=4.5.0
6+
numpy~=2.2.1
7+
p4p~=4.2.0

setup.cfg

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# -*- coding: utf-8 -*-
2+
[metadata]
3+
name = lat2db
4+
fullname = lattice to database
5+
version = 0.1.0
6+
url = https://gitlab.helmholtz-berlin.de/acc-tools/lat2db
7+
author = Waheedullah Sulaiman Khail, Pierre Schnizer
8+
9+
description =
10+
long_description = file: README.md
11+
classifiers =
12+
Development Status :: 4 - Beta
13+
Intended Audience :: Science/Research
14+
License :: OSI Approved :: GNU General Public License (GPL)
15+
Programming Language :: Python :: 3
16+
Topic :: Scientific/Engineering :: Physics
17+
[build-system]
18+
requires = setup_tools
19+
20+
21+
[options]
22+
packages = find:
23+
include_package_data = True
24+
zip_safe = False

setup.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from setuptools import setup
2+
3+
setup()

src/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from src.config.db_config import mongodb_url as _mongodb_
2+
3+
mongodb_ = _mongodb_(__name__)
4+
5+
__all__ = ["mongodb_"]

src/config/config.cfg

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[default]
2+
mongodb = localhost
3+
4+
[localhost]
5+
server = localhost
6+
port = 27017
7+
database_name = bessyii
8+
9+
[BESSYII]
10+
server = mongodb.bessy.de
11+
port = 28018
12+
;username = notadmin
13+
;password = admin123
14+
database_name = bessyii

src/config/db_config.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from configparser import ConfigParser
2+
from importlib.resources import files
3+
from urllib.parse import quote_plus
4+
import os
5+
6+
from src.core.utils.logger import get_logger
7+
8+
logger = get_logger()
9+
10+
11+
def config(mod_name):
12+
parser = ConfigParser()
13+
config_path = files(mod_name).joinpath("config/config.cfg")
14+
read_files = parser.read(config_path)
15+
16+
if not read_files:
17+
raise FileNotFoundError(f"Configuration file not found: {config_path}")
18+
19+
return parser
20+
21+
def mongodb_url_from_config(mod_name):
22+
cfg = config(mod_name)
23+
mongodb = cfg["default"]["mongodb"]
24+
dbsec = cfg[mongodb]
25+
server = dbsec['server']
26+
port = dbsec['port']
27+
try:
28+
username = dbsec['username']
29+
except KeyError:
30+
username = None # Add username from config
31+
try:
32+
password = dbsec['password']
33+
except KeyError:
34+
password = None
35+
db_name = dbsec['database_name']
36+
if(username):
37+
# Encode username and password for inclusion in URL
38+
encoded_username = quote_plus(username)
39+
encoded_password = quote_plus(password)
40+
return f"mongodb://{encoded_username}:{encoded_password}@{server}:{port}/{db_name}"
41+
else: return f"mongodb://{server}:{port}/{db_name}"
42+
43+
def mongodb_url(mod_name):
44+
default_url = mongodb_url_from_config(mod_name)
45+
try:
46+
return os.environ["MONGODB_URL"]
47+
except KeyError:
48+
txt = f'Environment variable MONGODB_URL is not defined, using default: {default_url}'
49+
print(txt)
50+
logger.warning(txt)
51+
return default_url
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from typing import Union
2+
3+
from ..bl.delay_execution import DelayExecution
4+
from ..bl.event import Event
5+
from ..interfaces.accelerator_interface import AcceleratorInterface
6+
from ..interfaces.element_interface import ElementInterface
7+
8+
9+
class AcceleratorImpl(AcceleratorInterface):
10+
def __init__(self, acc, proxy_factory, twiss_calculator, orbit_calculator, *, delay=0.1):
11+
"""
12+
Initializes the accelerator implementation.
13+
This manages the accelerator state, interactions, and calculation flow.
14+
Registers event handlers and calculations.
15+
16+
Args:
17+
acc: Accelerator model.
18+
proxy_factory: Factory for creating element proxies.
19+
twiss_calculator: Calculator for twiss parameters.
20+
orbit_calculator: Calculator for orbit calculations.
21+
delay (float): Delay for calculation executions.
22+
"""
23+
super().__init__()
24+
self.acc = acc
25+
self.proxy_factory = proxy_factory
26+
self.twiss_calculator = twiss_calculator
27+
self.orbit_calculator = orbit_calculator
28+
29+
# Store calculation results
30+
self.twiss = twiss_calculator.calculate()
31+
self.orbit = orbit_calculator.calculate()
32+
33+
# Events for notification
34+
self.on_new_orbit = Event()
35+
self.on_new_twiss = Event()
36+
37+
async def cb_twiss():
38+
"""Internal method to calculate twiss parameters."""
39+
self.twiss = self.twiss_calculator.calculate()
40+
await self.on_new_twiss.trigger(self.twiss)
41+
42+
async def cb_orbit():
43+
"""Internal method to calculate orbit parameters."""
44+
self.orbit = self.orbit_calculator.calculate()
45+
await self.on_new_orbit.trigger(self.orbit)
46+
47+
self.twiss_calculation_delay = DelayExecution(callback=cb_twiss, delay=delay)
48+
self.orbit_calculation_delay = DelayExecution(callback=cb_orbit, delay=delay)
49+
50+
self.on_changed_value = Event()
51+
52+
self.on_orbit_calculation_request = self.orbit_calculation_delay.on_calculation_requested
53+
self.on_orbit_calculation = self.orbit_calculation_delay.on_calculation
54+
self.on_twiss_calculation_request = self.twiss_calculation_delay.on_calculation_requested
55+
self.on_twiss_calculation = self.twiss_calculation_delay.on_calculation
56+
57+
def set_delay(self, delay: Union[float, None]):
58+
"""How much to delay twiss and orbit calculation after last received command"""
59+
self.twiss_calculation_delay.set_delay(delay)
60+
self.orbit_calculation_delay.set_delay(delay)
61+
62+
async def get_element(self, element_id) -> ElementInterface:
63+
"""
64+
Retrieves an element and subscribes to its changes.
65+
66+
Args:
67+
element_id (str): The element identifier.
68+
69+
Returns:
70+
ElementInterface: Proxy object for the element.
71+
"""
72+
proxy = self.proxy_factory.get(element_id)
73+
proxy.on_changed_value.subscribe(self.on_changed_value.trigger)
74+
75+
async def cb(unused):
76+
await self.orbit_calculation_delay.request_execution()
77+
await self.twiss_calculation_delay.request_execution()
78+
79+
proxy.on_update_finished.subscribe(cb)
80+
return proxy
81+
82+
def calculate_twiss(self):
83+
return self.twiss_calculator.calculate()
84+
85+
def calculate_orbit(self):
86+
return self.orbit_calculator.calculate()
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from src.core.utils.logger import get_logger
2+
from src.custom_epics.utils.bpm_mimicry import BPMMimicry
3+
from .proxy_factory import PyATProxyFactory
4+
from ..accelerators.accelerator_impl import AcceleratorImpl
5+
from ..calculations.pyat_calculator import PyAtTwissCalculator, PyAtOrbitCalculator
6+
from ...custom_epics.views.shared_view import get_view_instance
7+
8+
logger = get_logger()
9+
10+
11+
class AcceleratorManager:
12+
"""
13+
Manages the initialization and event subscription of the accelerator.
14+
Orchestrates interactions, manages configurations,
15+
and serves as a bridge between core accelerator logic and higher-level application needs.
16+
17+
Attributes:
18+
prefix (str): The prefix for PVs (Process Variables).
19+
accelerator (AcceleratorImpl): Instance of the accelerator implementation.
20+
view (ResultView): Instance of the result view to handle user interface.
21+
bpm_mimicry (BPMMimicry): Object to manage BPM data mimicking.
22+
"""
23+
24+
def __init__(self, prefix):
25+
"""
26+
Initializes the AcceleratorManager with a given prefix.
27+
28+
Args:
29+
prefix (str): The prefix for the PVs in the EPICS system.
30+
todo: What about tango? do we have/need usage of prefix? we will findout
31+
"""
32+
self.prefix = prefix
33+
self.accelerator = None # Will be initialized in the `initialize` method
34+
self.view = get_view_instance() # Shared view instance for displaying results
35+
self.bpm_mimicry = None # Placeholder for BPM mimicry instance
36+
37+
def initialize(self):
38+
"""
39+
Initializes the accelerator and its required components.
40+
41+
This method sets up the accelerator, proxies, calculators, and BPMs.
42+
It also subscribes to relevant events.
43+
44+
Raises:
45+
Exception: If initialization fails.
46+
"""
47+
try:
48+
from lat2db.model.accelerator import Accelerator
49+
acc_model = Accelerator()
50+
51+
# Initialize the accelerator with required components
52+
self.accelerator = AcceleratorImpl(
53+
acc_model.ring,
54+
PyATProxyFactory(lattice_model=None, at_lattice=acc_model.ring),
55+
PyAtTwissCalculator(acc_model),
56+
PyAtOrbitCalculator(acc_model.ring)
57+
)
58+
59+
# Extract BPM elements from the accelerator and create BPM mimicry
60+
bpm_names = [elem.FamName for elem in self.accelerator.acc if elem.FamName.startswith("BPM")]
61+
self.bpm_mimicry = BPMMimicry(prefix=self.prefix, bpm_names=bpm_names)
62+
# Inject the BPM mimicry into the view instance
63+
self.view.set_bpm_mimicry(self.bpm_mimicry)
64+
self.setup_event_subscriptions()
65+
66+
logger.warning("AcceleratorManager initialized successfully.")
67+
except Exception as e:
68+
logger.error(f"Failed to initialize AcceleratorManager: {e}")
69+
raise
70+
71+
def setup_event_subscriptions(self):
72+
"""
73+
Subscribe to accelerator events and bind them to view update methods.
74+
75+
Ensures that the view receives updates whenever the accelerator produces new data.
76+
"""
77+
if not self.accelerator:
78+
logger.error("Accelerator must be initialized before subscribing to events.")
79+
80+
# Subscriptions
81+
self.accelerator.on_new_twiss.subscribe(self.view.push_twiss)
82+
self.accelerator.on_new_orbit.subscribe(self.view.push_orbit)
83+
84+
self.accelerator.on_new_orbit.subscribe(self.view.push_bpms)
85+
self.accelerator.on_changed_value.subscribe(self.view.push_value)

0 commit comments

Comments
 (0)