sfrs-element-loader 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.1
2
+ Name: sfrs_element_loader
3
+ Version: 0.1.0
4
+ Summary: A tool to load and inspect SFRS elements from a database using SQLAlchemy
5
+ Author: Achim Andres
6
+ Author-email: Achim Andres <a.andres@gsi.de>
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: SQLAlchemy>=1.4
11
+ Requires-Dist: python-dotenv
12
+ Requires-Dist: tabulate
File without changes
@@ -0,0 +1,17 @@
1
+ [project]
2
+ name = "sfrs_element_loader"
3
+ version = "0.1.0"
4
+ description = "A tool to load and inspect SFRS elements from a database using SQLAlchemy"
5
+ authors = [{ name = "Achim Andres", email = "a.andres@gsi.de" }]
6
+ readme = "README.md"
7
+ license = { file = "LICENSE" }
8
+ requires-python = ">=3.8"
9
+ dependencies = [
10
+ "SQLAlchemy>=1.4",
11
+ "python-dotenv",
12
+ "tabulate"
13
+ ]
14
+
15
+ [build-system]
16
+ requires = ["setuptools", "wheel"]
17
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+ # setup.py
2
+ from setuptools import setup, find_packages
3
+
4
+ setup(
5
+ name='sfrs-element-loader', # PyPI package name (dashes are fine here)
6
+ version='0.2.0',
7
+ description='A tool to load and inspect SFRS elements from a database using SQLAlchemy. First working development.',
8
+ author='Achim Andres',
9
+ author_email='a.andres@gsi.de',
10
+ packages=find_packages(), # Automatically includes all packages with __init__.py
11
+ install_requires=[
12
+ 'SQLAlchemy',
13
+ 'tabulate',
14
+ 'python-dotenv'
15
+ ],
16
+ classifiers=[
17
+ 'Programming Language :: Python :: 3',
18
+ 'Operating System :: OS Independent',
19
+ ],
20
+ )
@@ -0,0 +1,152 @@
1
+ import os
2
+ from dotenv import load_dotenv
3
+ from tabulate import tabulate
4
+ import inspect
5
+
6
+ from sqlalchemy import create_engine
7
+ from sqlalchemy.orm import sessionmaker
8
+
9
+ from .model import (
10
+ Element, Dipole, Quadrupole, Sextupole, Octupole, Steerer, Drift,
11
+ ExperimentalChamber, EmptyDetector, BeamStopper, ProfileGrid,
12
+ HorizontalSlit, PlasticScintillator, RotaryWedgeDegrader,
13
+ SlidableWedgeDegrader, LadderSystemDegrader
14
+ )
15
+
16
+ class ElementLoader:
17
+ def __init__(self, env_path: str = '.env'):
18
+ self._load_env(env_path)
19
+ self._setup_database()
20
+
21
+ def _load_env(self, env_path: str):
22
+ load_dotenv(env_path)
23
+ self.database_uri = os.getenv('SQLALCHEMY_DATABASE_URI')
24
+ if not self.database_uri:
25
+ raise ValueError("Database URI not found in environment variables")
26
+
27
+ def _setup_database(self):
28
+ engine = create_engine(self.database_uri)
29
+ Session = sessionmaker(bind=engine)
30
+ self.session = Session()
31
+
32
+ def load_element_data(self, element_name: str) -> dict:
33
+ element = self.session.query(Element).filter(Element.element_name == element_name).first()
34
+ if not element:
35
+ raise ValueError(f"Element '{element_name}' not found in the database")
36
+
37
+ # Dynamically collect fields for the specific subclass of the element
38
+ model_class = type(element)
39
+ columns = model_class.__mapper__.column_attrs
40
+ data = {col.key: getattr(element, col.key) for col in columns}
41
+
42
+ # Optional: Add related objects dynamically (like experimental_chamber)
43
+ # You can inspect relationships using `__mapper__.relationships`
44
+ for rel in model_class.__mapper__.relationships:
45
+ related_obj = getattr(element, rel.key)
46
+ if related_obj:
47
+ data[rel.key] = {
48
+ col.key: getattr(related_obj, col.key)
49
+ for col in type(related_obj).__mapper__.column_attrs
50
+ }
51
+
52
+ return data
53
+
54
+ def list_all_optical_elements(self):
55
+ elements = self.session.query(Element).all()
56
+ return [element.element_name for element in elements]
57
+
58
+
59
+ def list_all_drifts(self, pprint = False):
60
+ """
61
+ Retrieve all Drift elements from the database and optionally print them in a table.
62
+ Args: pprint (bool, optional): If True, prints the drift data in a fancy grid table. Defaults to False.
63
+ Returns: List[str]: A list of all drift element names.\n
64
+ """
65
+ drifts = self.session.query(Drift).all()
66
+ drift_data = []
67
+
68
+ for drift in drifts:
69
+ drift_data.append({
70
+ 'element_name': drift.element_name,
71
+ 'location': drift.loc,
72
+ 'high_energy_branch': drift.high_energy_branch,
73
+ 'low_energy_branch': drift.low_energy_branch,
74
+ 'ring_branch': drift.ring_branch,
75
+ })
76
+
77
+ headers = ["Element Name", "High Energy Branch", "Low Energy Branch", "Ring Branch"]
78
+ table = [
79
+ [
80
+ d['element_name'],
81
+ d['high_energy_branch'],
82
+ d['low_energy_branch'],
83
+ d['ring_branch']
84
+ ]
85
+ for d in drift_data
86
+ ]
87
+ if pprint: print(tabulate(table, headers=headers, tablefmt="fancy_grid"))
88
+ return [d['element_name'] for d in drift_data]
89
+
90
+ def list_all_dipoles(self, pprint = False):
91
+ """
92
+ Retrieve all Dipoles elements from the database and optionally print them in a table.
93
+ Args: pprint (bool, optional): If True, prints the drift data in a fancy grid table. Defaults to False.
94
+ Returns: List[str]: A list of all dipole element names.\n
95
+ """
96
+ dipoles = self.session.query(Dipole).all()
97
+ dipole_data = []
98
+
99
+ for dipole in dipoles:
100
+ dipole_data.append({
101
+ 'element_name': dipole.element_name,
102
+ 'location': dipole.loc,
103
+ 'high_energy_branch': dipole.high_energy_branch,
104
+ 'low_energy_branch': dipole.low_energy_branch,
105
+ 'ring_branch': dipole.ring_branch,
106
+ })
107
+
108
+ headers = ["Element Name", "High Energy Branch", "Low Energy Branch", "Ring Branch"]
109
+ table = [
110
+ [
111
+ d['element_name'],
112
+ d['high_energy_branch'],
113
+ d['low_energy_branch'],
114
+ d['ring_branch']
115
+ ]
116
+ for d in dipole_data
117
+ ]
118
+ if pprint: print(tabulate(table, headers=headers, tablefmt="fancy_grid"))
119
+ return [d['element_name'] for d in dipole_data]
120
+
121
+ def list_all_quadrupoles(self, pprint = False):
122
+ pass
123
+
124
+ def list_all_sextupoles(self, pprint = False):
125
+ pass
126
+
127
+ def list_all_octupoles(self, pprint = False):
128
+ pass
129
+
130
+ def list_all_multipletts(self, pprint = False):
131
+ """"""
132
+ pass
133
+
134
+ def help(self):
135
+ print("Available methods:\n")
136
+ for name, method in inspect.getmembers(self, predicate=inspect.ismethod):
137
+ if not name.startswith('_') and name != "help":
138
+ doc = inspect.getdoc(method) or "No description"
139
+ print(f"{name}:\n{doc}\n")
140
+
141
+
142
+ # Example usage
143
+ if __name__ == "__main__":
144
+ loader = ElementLoader(env_path = '../../.env')
145
+ element_name = 'FTF1QT21' # adjust as needed
146
+ data = loader.load_element_data(element_name)
147
+ data = loader.list_all_drifts(pprint = False)
148
+ data = loader.list_all_dipoles(pprint = False)
149
+ data = loader.list_all_optical_elements()
150
+ print(data)
151
+ #loader.help()
152
+
@@ -0,0 +1,301 @@
1
+ from flask_sqlalchemy import SQLAlchemy
2
+
3
+ db = SQLAlchemy()
4
+
5
+ # Base class for all elements
6
+ class Element(db.Model):
7
+ __tablename__ = 'elements'
8
+ __table_args__ = {'schema': 'sfrs_component_database'}
9
+ id = db.Column(db.Integer, primary_key=True)
10
+ element_name = db.Column(db.String(100), nullable=False)
11
+ is_detector = db.Column(db.Boolean, default=False)
12
+ high_energy_branch = db.Column(db.Boolean, nullable=False, default=False)
13
+ low_energy_branch = db.Column(db.Boolean, nullable=False, default=False)
14
+ ring_branch = db.Column(db.Boolean, nullable=False, default=False)
15
+ loc = db.Column(db.JSON, nullable=True)
16
+ length = db.Column(db.Float, nullable=True)
17
+ type = db.Column(db.String(25), nullable=False) # Discriminator column
18
+ __mapper_args__ = {
19
+ 'polymorphic_identity': 'element',
20
+ 'polymorphic_on': type
21
+ }
22
+
23
+ class ExperimentalChamber(Element):
24
+ __tablename__ = 'experimental_chambers'
25
+ __table_args__ = {'schema': 'sfrs_component_database'}
26
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
27
+ number_of_detectors = db.Column(db.Integer, nullable=False)
28
+ focal_plane = db.Column(db.String(4), nullable = False)
29
+ __mapper_args__ = {
30
+ 'polymorphic_identity': 'experimental_chamber'
31
+ }
32
+
33
+ class EmptyDetector(Element):
34
+ __tablename__ = 'empty_detectors'
35
+ __table_args__ = {'schema': 'sfrs_component_database'}
36
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
37
+ slot_number = db.Column(db.Integer, nullable=True)
38
+
39
+ # Foreign key to the experimental chamber
40
+ experimental_chamber_id = db.Column(
41
+ db.Integer,
42
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
43
+ nullable=True
44
+ )
45
+
46
+ # Disambiguated relationship
47
+ experimental_chamber = db.relationship(
48
+ 'ExperimentalChamber',
49
+ backref='empty_detectors',
50
+ foreign_keys=[experimental_chamber_id] # this is the fix
51
+ )
52
+
53
+ __mapper_args__ = {
54
+ 'polymorphic_identity': 'empty_detector'
55
+ }
56
+
57
+ class BeamStopper(Element):
58
+ __tablename__ = 'beam_stoppers'
59
+ __table_args__ = {'schema': 'sfrs_component_database'}
60
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
61
+ slot_number = db.Column(db.Integer, nullable=True)
62
+ pneumatic_actuator_name = db.Column(db.String(15), nullable=False)
63
+
64
+ # Foreign key to the experimental chamber
65
+ experimental_chamber_id = db.Column(
66
+ db.Integer,
67
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
68
+ nullable=True
69
+ )
70
+
71
+ # Disambiguated relationship
72
+ experimental_chamber = db.relationship(
73
+ 'ExperimentalChamber',
74
+ backref='beam_stoppers',
75
+ foreign_keys=[experimental_chamber_id] # this is the fix
76
+ )
77
+
78
+ __mapper_args__ = {
79
+ 'polymorphic_identity': 'beam_stopper'
80
+ }
81
+
82
+ class ProfileGrid(Element):
83
+ __tablename__ = 'profile_grids'
84
+ __table_args__ = {'schema': 'sfrs_component_database'}
85
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
86
+ slot_number = db.Column(db.Integer, nullable=True)
87
+ grid_name = db.Column(db.String(15), nullable=False)
88
+ stepper_motor_name = db.Column(db.String(15), nullable=False)
89
+ # Foreign key to the experimental chamber
90
+ experimental_chamber_id = db.Column(
91
+ db.Integer,
92
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
93
+ nullable=True
94
+ )
95
+
96
+ # Disambiguated relationship
97
+ experimental_chamber = db.relationship(
98
+ 'ExperimentalChamber',
99
+ backref='profile_grids',
100
+ foreign_keys=[experimental_chamber_id] # this is the fix
101
+ )
102
+ __mapper_args__ = {
103
+ 'polymorphic_identity': 'profile_grid'
104
+ }
105
+
106
+ class HorizontalSlit(Element):
107
+ __tablename__ = 'horizontal_slits'
108
+ __table_args__ = {'schema': 'sfrs_component_database'}
109
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
110
+ slot_number = db.Column(db.Integer, nullable=True)
111
+ left_slit_name = db.Column(db.String(15), nullable=False)
112
+ right_slit_name = db.Column(db.String(15), nullable=False)
113
+ # Foreign key to the experimental chamber
114
+ experimental_chamber_id = db.Column(
115
+ db.Integer,
116
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
117
+ nullable=True
118
+ )
119
+
120
+ # Disambiguated relationship
121
+ experimental_chamber = db.relationship(
122
+ 'ExperimentalChamber',
123
+ backref='horizontal_slits',
124
+ foreign_keys=[experimental_chamber_id] # this is the fix
125
+ )
126
+ __mapper_args__ = {
127
+ 'polymorphic_identity': 'horizontal_slit'
128
+ }
129
+
130
+ class PlasticScintillator(Element):
131
+ __tablename__ = 'plastic_scintillators'
132
+ __table_args__ = {'schema': 'sfrs_component_database'}
133
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
134
+ slot_number = db.Column(db.Integer, nullable=True)
135
+ pneumatic_actuator = db.Column(db.String(15), nullable=False)
136
+ # Foreign key to the experimental chamber
137
+ experimental_chamber_id = db.Column(
138
+ db.Integer,
139
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
140
+ nullable=True
141
+ )
142
+
143
+ # Disambiguated relationship
144
+ experimental_chamber = db.relationship(
145
+ 'ExperimentalChamber',
146
+ backref='plastic_scintillators',
147
+ foreign_keys=[experimental_chamber_id] # this is the fix
148
+ )
149
+ __mapper_args__ = {
150
+ 'polymorphic_identity': 'plastic_scintillator'
151
+ }
152
+
153
+ class RotaryWedgeDegrader(Element):
154
+ __tablename__ = 'rotary_wedge_degraders'
155
+ __table_args__ = {'schema': 'sfrs_component_database'}
156
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
157
+ slot_number = db.Column(db.Integer, nullable=True)
158
+ stepper_motor = db.Column(db.String(15), nullable=False)
159
+ pneumatic_actuator = db.Column(db.String(15), nullable=False)
160
+ # Foreign key to the experimental chamber
161
+ experimental_chamber_id = db.Column(
162
+ db.Integer,
163
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
164
+ nullable=True
165
+ )
166
+
167
+ # Disambiguated relationship
168
+ experimental_chamber = db.relationship(
169
+ 'ExperimentalChamber',
170
+ backref='rotary_wedge_degraders',
171
+ foreign_keys=[experimental_chamber_id] # this is the fix
172
+ )
173
+ __mapper_args__ = {
174
+ 'polymorphic_identity': 'rotary_wedge_degrader'
175
+ }
176
+
177
+ class SlidableWedgeDegrader(Element):
178
+ __tablename__ = 'slidable_wedge_degraders'
179
+ __table_args__ = {'schema': 'sfrs_component_database'}
180
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
181
+ slot_number = db.Column(db.Integer, nullable=True)
182
+ stepper_motor = db.Column(db.String(15), nullable=False)
183
+ # Foreign key to the experimental chamber
184
+ experimental_chamber_id = db.Column(
185
+ db.Integer,
186
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
187
+ nullable=True
188
+ )
189
+
190
+ # Disambiguated relationship
191
+ experimental_chamber = db.relationship(
192
+ 'ExperimentalChamber',
193
+ backref='slidable_wedge_degraders',
194
+ foreign_keys=[experimental_chamber_id] # this is the fix
195
+ )
196
+ __mapper_args__ = {
197
+ 'polymorphic_identity': 'slidable_wedge_degrader'
198
+ }
199
+
200
+ class LadderSystemDegrader(Element):
201
+ __tablename__ = 'ladder_system_degraders'
202
+ __table_args__ = {'schema': 'sfrs_component_database'}
203
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
204
+ slot_number = db.Column(db.Integer, nullable=True)
205
+ stepper_motor = db.Column(db.String(15), nullable=False)
206
+ # Foreign key to the experimental chamber
207
+ experimental_chamber_id = db.Column(
208
+ db.Integer,
209
+ db.ForeignKey('sfrs_component_database.experimental_chambers.id'),
210
+ nullable=True
211
+ )
212
+
213
+ # Disambiguated relationship
214
+ experimental_chamber = db.relationship(
215
+ 'ExperimentalChamber',
216
+ backref='ladder_system_degraders',
217
+ foreign_keys=[experimental_chamber_id] # this is the fix
218
+ )
219
+ __mapper_args__ = {
220
+ 'polymorphic_identity': 'ladder_system_degrader'
221
+ }
222
+
223
+ # Derived class for Dipole
224
+ class Dipole(Element):
225
+ __tablename__ = 'dipoles'
226
+ __table_args__ = {'schema': 'sfrs_component_database'}
227
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
228
+ is_superconducting = db.Column(db.Boolean, nullable = False)
229
+ __mapper_args__ = {
230
+ 'polymorphic_identity': 'dipole'
231
+ }
232
+
233
+ # Derived class for Quadrupole
234
+ class Quadrupole(Element):
235
+ __tablename__ = 'quadrupoles'
236
+ __table_args__ = {'schema': 'sfrs_component_database'}
237
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
238
+ multiplett_name = db.Column(db.String(10), nullable=True)
239
+ multiplett_company_name = db.Column(db.String(9), nullable=True)
240
+ multiplett_type = db.Column(db.String(10), nullable=True)
241
+ is_superconducting = db.Column(db.Boolean, nullable = False)
242
+ is_horizontal_focusing = db.Column(db.Boolean, nullable=False)
243
+ loadline_data = db.Column(db.PickleType, nullable=True)
244
+ position_in_multiplett = db.Column(db.Integer, nullable = True)
245
+ __mapper_args__ = {
246
+ 'polymorphic_identity': 'quadrupole'
247
+ }
248
+
249
+ # Derived class for Sextupoles
250
+ class Sextupole(Element):
251
+ __tablename__ = 'sextupoles'
252
+ __table_args__ = {'schema': 'sfrs_component_database'}
253
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
254
+ multiplett_name = db.Column(db.String(10), nullable=True)
255
+ multiplett_company_name = db.Column(db.String(9), nullable=True)
256
+ multiplett_type = db.Column(db.String(10), nullable=True)
257
+ is_superconducting = db.Column(db.Boolean, nullable = False)
258
+ position_in_multiplett = db.Column(db.Integer, nullable = True)
259
+ __mapper_args__ = {
260
+ 'polymorphic_identity': 'sextupole'
261
+ }
262
+
263
+ # Derived class for Octupole
264
+ class Octupole(Element):
265
+ __tablename__ = 'octupoles'
266
+ __table_args__ = {'schema': 'sfrs_component_database'}
267
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
268
+ multiplett_name = db.Column(db.String(10), nullable=True)
269
+ multiplett_company_name = db.Column(db.String(9), nullable=True)
270
+ multiplett_type = db.Column(db.String(10), nullable=True)
271
+ is_superconducting = db.Column(db.Boolean, nullable = False)
272
+ position_in_multiplett = db.Column(db.Integer, nullable = True)
273
+ __mapper_args__ = {
274
+ 'polymorphic_identity': 'octupole'
275
+ }
276
+
277
+ # Derived class for Steerer
278
+ class Steerer(Element):
279
+ __tablename__ = 'steerer'
280
+ __table_args__ = {'schema': 'sfrs_component_database'}
281
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
282
+ multiplett_name = db.Column(db.String(10), nullable=True)
283
+ multiplett_company_name = db.Column(db.String(9), nullable=True)
284
+ multiplett_type = db.Column(db.String(10), nullable=True)
285
+ is_superconducting = db.Column(db.Boolean, nullable = False)
286
+ is_vertical_bending = db.Column(db.Boolean, nullable=False)
287
+ position_in_multiplett = db.Column(db.Integer, nullable = True)
288
+ total_number_of_elements_in_multiplett = db.Column(db.Integer, nullable = True)
289
+ __mapper_args__ = {
290
+ 'polymorphic_identity': 'steerer'
291
+ }
292
+
293
+ # Derived class for Drifts
294
+ class Drift(Element):
295
+ __tablename__ = 'beamlines'
296
+ __table_args__ = {'schema': 'sfrs_component_database'}
297
+ id = db.Column(db.Integer, db.ForeignKey('sfrs_component_database.elements.id'), primary_key=True)
298
+ __mapper_args__ = {
299
+ 'polymorphic_identity': 'drift'
300
+ }
301
+
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.1
2
+ Name: sfrs_element_loader
3
+ Version: 0.1.0
4
+ Summary: A tool to load and inspect SFRS elements from a database using SQLAlchemy
5
+ Author: Achim Andres
6
+ Author-email: Achim Andres <a.andres@gsi.de>
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: SQLAlchemy>=1.4
11
+ Requires-Dist: python-dotenv
12
+ Requires-Dist: tabulate
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ sfrs_element_loader/__init__.py
6
+ sfrs_element_loader/access_database.py
7
+ sfrs_element_loader/model.py
8
+ sfrs_element_loader.egg-info/PKG-INFO
9
+ sfrs_element_loader.egg-info/SOURCES.txt
10
+ sfrs_element_loader.egg-info/dependency_links.txt
11
+ sfrs_element_loader.egg-info/requires.txt
12
+ sfrs_element_loader.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ SQLAlchemy>=1.4
2
+ python-dotenv
3
+ tabulate
@@ -0,0 +1 @@
1
+ sfrs_element_loader