nbs-bl 0.2.0__py3-none-any.whl

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.
Files changed (64) hide show
  1. nbs_bl/__init__.py +15 -0
  2. nbs_bl/beamline.py +450 -0
  3. nbs_bl/configuration.py +838 -0
  4. nbs_bl/detectors.py +89 -0
  5. nbs_bl/devices/__init__.py +12 -0
  6. nbs_bl/devices/detectors.py +154 -0
  7. nbs_bl/devices/motors.py +242 -0
  8. nbs_bl/devices/sampleholders.py +360 -0
  9. nbs_bl/devices/shutters.py +120 -0
  10. nbs_bl/devices/slits.py +51 -0
  11. nbs_bl/gGrEqns.py +171 -0
  12. nbs_bl/geometry/__init__.py +0 -0
  13. nbs_bl/geometry/affine.py +197 -0
  14. nbs_bl/geometry/bars.py +189 -0
  15. nbs_bl/geometry/frames.py +534 -0
  16. nbs_bl/geometry/linalg.py +138 -0
  17. nbs_bl/geometry/polygons.py +56 -0
  18. nbs_bl/help.py +126 -0
  19. nbs_bl/hw.py +270 -0
  20. nbs_bl/load.py +113 -0
  21. nbs_bl/motors.py +19 -0
  22. nbs_bl/planStatus.py +5 -0
  23. nbs_bl/plans/__init__.py +8 -0
  24. nbs_bl/plans/batches.py +174 -0
  25. nbs_bl/plans/conditions.py +77 -0
  26. nbs_bl/plans/flyscan_base.py +180 -0
  27. nbs_bl/plans/groups.py +55 -0
  28. nbs_bl/plans/maximizers.py +423 -0
  29. nbs_bl/plans/metaplans.py +179 -0
  30. nbs_bl/plans/plan_stubs.py +246 -0
  31. nbs_bl/plans/preprocessors.py +160 -0
  32. nbs_bl/plans/scan_base.py +58 -0
  33. nbs_bl/plans/scan_decorators.py +524 -0
  34. nbs_bl/plans/scans.py +145 -0
  35. nbs_bl/plans/suspenders.py +87 -0
  36. nbs_bl/plans/time_estimation.py +168 -0
  37. nbs_bl/plans/xas.py +123 -0
  38. nbs_bl/printing.py +221 -0
  39. nbs_bl/qt/models/beamline.py +11 -0
  40. nbs_bl/qt/models/energy.py +53 -0
  41. nbs_bl/qt/widgets/energy.py +225 -0
  42. nbs_bl/queueserver.py +249 -0
  43. nbs_bl/redisDevice.py +96 -0
  44. nbs_bl/run_engine.py +63 -0
  45. nbs_bl/samples.py +130 -0
  46. nbs_bl/settings.py +68 -0
  47. nbs_bl/shutters.py +39 -0
  48. nbs_bl/sim/__init__.py +2 -0
  49. nbs_bl/sim/config/polphase.nc +0 -0
  50. nbs_bl/sim/energy.py +403 -0
  51. nbs_bl/sim/manipulator.py +14 -0
  52. nbs_bl/sim/utils.py +36 -0
  53. nbs_bl/startup.py +27 -0
  54. nbs_bl/status.py +114 -0
  55. nbs_bl/tests/__init__.py +0 -0
  56. nbs_bl/tests/modify_regions.py +160 -0
  57. nbs_bl/tests/test_frames.py +99 -0
  58. nbs_bl/tests/test_panels.py +69 -0
  59. nbs_bl/utils.py +235 -0
  60. nbs_bl-0.2.0.dist-info/METADATA +71 -0
  61. nbs_bl-0.2.0.dist-info/RECORD +64 -0
  62. nbs_bl-0.2.0.dist-info/WHEEL +4 -0
  63. nbs_bl-0.2.0.dist-info/entry_points.txt +2 -0
  64. nbs_bl-0.2.0.dist-info/licenses/LICENSE +13 -0
@@ -0,0 +1,56 @@
1
+ import numpy as np
2
+ from .linalg import vec_len
3
+
4
+ """
5
+ Module that computes areas, distances, and inclusion in polygons
6
+ """
7
+
8
+
9
+ def triarea(p1, p2, p3):
10
+ n1 = p1 - p2
11
+ n2 = p3 - p2
12
+ return 0.5*(n1[0]*n2[1] - n1[1]*n2[0])
13
+
14
+
15
+ def getPointAreas(p, *args):
16
+ areas = []
17
+ for n in range(len(args)):
18
+ areas.append(triarea(p, args[n-1], args[n]))
19
+ return areas
20
+
21
+
22
+ def distFromTri(p, a, b):
23
+ area = np.abs(triarea(p, a, b))
24
+ d = vec_len(a - b)
25
+ s1 = vec_len(a - p)
26
+ s2 = vec_len(b - p)
27
+ if np.isclose(d, 0):
28
+ return min(s1, s2)
29
+ elif s1**2 > d**2 + s2**2:
30
+ return s2
31
+ elif s2**2 > d**2 + s1**2:
32
+ return s1
33
+ else:
34
+ return 2.0*area/d
35
+
36
+
37
+ def getMinDist(p, *args):
38
+ distances = []
39
+ for n in range(len(args)):
40
+ distances.append(distFromTri(p, args[n-1], args[n]))
41
+ return np.min(distances)
42
+
43
+
44
+ def prunePoints(*args):
45
+ pruned = []
46
+ for n in range(len(args)):
47
+ if not np.all(np.isclose(args[n-1] - args[n], 0.0)):
48
+ pruned.append(args[n])
49
+ return pruned
50
+
51
+
52
+ def isInPoly(p, *args):
53
+ # Works for convex polygons only!
54
+ polyPoints = prunePoints(*args)
55
+ areas = np.array(getPointAreas(p, *polyPoints))
56
+ return (np.all(areas < 0) or np.all(areas > 0))
nbs_bl/help.py ADDED
@@ -0,0 +1,126 @@
1
+ from .status import StatusList
2
+ from .queueserver import GLOBAL_USER_STATUS
3
+ from .printing import boxed_text
4
+
5
+ GLOBAL_HELP_DICTIONARY = {
6
+ "functions": {},
7
+ "plans": {},
8
+ "scans": {},
9
+ "xas": {},
10
+ "conditions": {},
11
+ }
12
+ GLOBAL_IMPORT_DICTIONARY = {}
13
+
14
+ # Request status lists from the global manager
15
+ GLOBAL_PLAN_LIST = GLOBAL_USER_STATUS.request_status_list("PLAN_LIST", use_redis=True)
16
+ GLOBAL_SCAN_LIST = GLOBAL_USER_STATUS.request_status_list("SCAN_LIST", use_redis=True)
17
+ GLOBAL_CONDITION_LIST = GLOBAL_USER_STATUS.request_status_list(
18
+ "CONDITION_LIST", use_redis=True
19
+ )
20
+ GLOBAL_PLAN_TIME_DICT = GLOBAL_USER_STATUS.request_status_dict(
21
+ "PLAN_TIME_DICT", use_redis=True
22
+ )
23
+
24
+
25
+ def _add_to_import_list(f, help_section):
26
+ """
27
+ A function decorator that will add the function to the built-in list
28
+ """
29
+ key = f.__name__
30
+ doc = f.__doc__ if f.__doc__ is not None else "No Docstring yet!"
31
+ if help_section not in GLOBAL_HELP_DICTIONARY:
32
+ GLOBAL_HELP_DICTIONARY[help_section] = {}
33
+ GLOBAL_HELP_DICTIONARY[help_section][key] = doc.lstrip()
34
+ GLOBAL_IMPORT_DICTIONARY[key] = f
35
+ return key
36
+
37
+
38
+ def add_to_func_list(f):
39
+ """
40
+ A function decorator that will add the function to the built-in list
41
+ """
42
+ _add_to_import_list(f, "functions")
43
+ return f
44
+
45
+
46
+ def add_to_plan_list(f):
47
+ """
48
+ A function decorator that will add the plan to the built-in list
49
+ """
50
+ key = _add_to_import_list(f, "plans")
51
+ GLOBAL_PLAN_LIST.append(key)
52
+ return f
53
+
54
+
55
+ def add_to_scan_list(f):
56
+ """
57
+ A function decorator that will add the plan to the built-in list
58
+ """
59
+ key = _add_to_import_list(f, "scans")
60
+ GLOBAL_SCAN_LIST.append(key)
61
+ return f
62
+
63
+
64
+ def add_to_condition_list(f):
65
+ """
66
+ A function decorator that will add the condition to the built-in list
67
+ """
68
+ key = _add_to_import_list(f, "conditions")
69
+ GLOBAL_CONDITION_LIST.append(key)
70
+ return f
71
+
72
+
73
+ def add_to_plan_time_dict(
74
+ f,
75
+ estimator="generic_estimate",
76
+ fixed=0,
77
+ overhead=0.5,
78
+ dwell="dwell",
79
+ points=None,
80
+ reset=0,
81
+ **kwargs,
82
+ ):
83
+ key = f.__name__
84
+ if key not in GLOBAL_PLAN_TIME_DICT:
85
+ GLOBAL_PLAN_TIME_DICT[key] = {}
86
+ GLOBAL_PLAN_TIME_DICT[key]["estimator"] = estimator
87
+ GLOBAL_PLAN_TIME_DICT[key]["fixed"] = fixed
88
+ GLOBAL_PLAN_TIME_DICT[key]["overhead"] = overhead
89
+ GLOBAL_PLAN_TIME_DICT[key]["dwell"] = dwell
90
+ GLOBAL_PLAN_TIME_DICT[key]["points"] = points
91
+ GLOBAL_PLAN_TIME_DICT[key]["reset"] = reset
92
+ GLOBAL_PLAN_TIME_DICT[key].update(kwargs)
93
+ return f
94
+
95
+
96
+ @add_to_func_list
97
+ def print_builtins(sections=None):
98
+ """Prints a list of built-in functions for ucal"""
99
+
100
+ if sections is None:
101
+ sections = sorted(GLOBAL_HELP_DICTIONARY.keys())
102
+ if type(sections) is str:
103
+ sections = [sections]
104
+ for key in sections:
105
+ textList = []
106
+ section = f"{key.capitalize()}"
107
+ if key == "xas":
108
+ for f in sorted(GLOBAL_HELP_DICTIONARY[key].keys()):
109
+ doc = GLOBAL_IMPORT_DICTIONARY[f]._short_doc
110
+ textList.append(f"{f}: {doc}")
111
+
112
+ else:
113
+ for f in sorted(GLOBAL_HELP_DICTIONARY[key].keys()):
114
+ doc = GLOBAL_HELP_DICTIONARY[key][f].split("\n")[0]
115
+ textList.append(f"{f}: {doc}")
116
+ boxed_text(section, textList, "white", width=100)
117
+
118
+
119
+ @add_to_func_list
120
+ def sst_help():
121
+ print(
122
+ "Welcome to SST. For a list of loaded functions and plans, call print_builtins() \n"
123
+ 'To print the docstring for any of the built-in functions, use the built-in python "?"'
124
+ " command with the name of the desired function. \n I.e, typing activate_detector? will "
125
+ 'print the help text for the "activate_detector" function'
126
+ )
nbs_bl/hw.py ADDED
@@ -0,0 +1,270 @@
1
+ from .queueserver import GLOBAL_USER_STATUS
2
+ from .printing import boxed_text
3
+ from nbs_core.autoload import loadFromConfig as _loadFromConfig
4
+ from nbs_core.autoload import instantiateOphyd, _find_deferred_devices, getMaxLoadPass
5
+
6
+
7
+ def loadDevices(device_config, namespace=None, mode=None):
8
+ max_load_pass = getMaxLoadPass(device_config)
9
+
10
+ all_devices = {}
11
+ all_groups = {}
12
+ all_roles = {}
13
+ deferred_config = {}
14
+ deferred_devices = set()
15
+ for pass_num in range(1, max_load_pass + 1):
16
+ print(f" Load pass {pass_num}/{max_load_pass}")
17
+
18
+ _, _, _deferred_config = _find_deferred_devices(device_config, mode=mode)
19
+
20
+ devices, groups, roles = loadFromConfig(
21
+ device_config,
22
+ instantiateOphyd,
23
+ alias=True,
24
+ namespace=namespace,
25
+ load_pass=pass_num,
26
+ mode=mode,
27
+ )
28
+
29
+
30
+ deferred_config.update(_deferred_config)
31
+ deferred_devices.update(_deferred_config.keys())
32
+
33
+ for device_name in devices:
34
+ deferred_config.pop(device_name, None)
35
+ deferred_devices.discard(device_name)
36
+ for group, group_devices in groups.items():
37
+ if group in all_groups:
38
+ all_groups[group] = all_groups[group] + group_devices
39
+ else:
40
+ all_groups[group] = group_devices
41
+ all_devices.update(devices)
42
+ all_roles.update(roles)
43
+ device_dict = {key: {"device": device, "loaded": True, "groups": [], "roles": [], "config": device_config.get(key, {})} for key, device in all_devices.items()}
44
+ for group, group_devices in all_groups.items():
45
+ for device in group_devices:
46
+ if device in device_dict:
47
+ device_dict[device]["groups"].append(group)
48
+ else:
49
+ device_dict[device] = {"device": None, "groups": [group], "loaded": False, "roles": [], "config": device_config.get(device, {})}
50
+
51
+ for role, device in all_roles.items():
52
+ if device in device_dict:
53
+ device_dict[device]["roles"].append(role)
54
+ else:
55
+ device_dict[device] = {"device": None, "roles": [role], "loaded": False, "groups": [], "config": device_config.get(device, {})}
56
+ for device_name, dconf in deferred_config.items():
57
+ dinfo = {"loaded": False, "config": dconf}
58
+ device_dict[device_name] = dinfo
59
+
60
+ return device_dict
61
+
62
+ def loadFromConfig(
63
+ config,
64
+ instantiateDevice,
65
+ alias=True,
66
+ namespace=None,
67
+ load_pass="auto",
68
+ filter_deferred=True,
69
+ mode=None,
70
+ ):
71
+ devices, groups, roles = _loadFromConfig(
72
+ config, instantiateDevice, alias, namespace, load_pass, filter_deferred, mode=mode
73
+ )
74
+ for key, device in devices.items():
75
+ globals()[key] = device
76
+ return devices, groups, roles
77
+
78
+
79
+ class HardwareGroup:
80
+ def __init__(self, name="", use_redis=False):
81
+ self.groupname = name
82
+ self.devices = GLOBAL_USER_STATUS.request_status_dict(
83
+ f"{self.groupname.upper()}", use_redis=False
84
+ )
85
+ self.descriptions = GLOBAL_USER_STATUS.request_status_dict(
86
+ f"{self.groupname.upper()}_DESCRIPTIONS", use_redis=use_redis
87
+ )
88
+
89
+ def values(self):
90
+ return self.devices.values()
91
+
92
+ def items(self):
93
+ return self.devices.items()
94
+
95
+ def get_key(self, device_or_key):
96
+ if isinstance(device_or_key, str):
97
+ if device_or_key in self.devices:
98
+ return device_or_key
99
+ else:
100
+ raise KeyError(f"Device {device_or_key} not found")
101
+ else:
102
+ for k, v in self.devices.items():
103
+ if v == device_or_key:
104
+ return k
105
+ raise KeyError(f"Device {device_or_key} not found")
106
+
107
+ def get(self, device_or_key):
108
+ key = self.get_key(device_or_key)
109
+ return self.devices[key]
110
+
111
+ def add(self, key, device, description="", **kwargs):
112
+ self.devices[key] = device
113
+ has_subdevices = False
114
+ if hasattr(device, "real_positioners"):
115
+ try:
116
+ for k2 in device.real_positioners._fields:
117
+ self.descriptions[f"{key}.{k2}"] = getattr(
118
+ device.real_positioners, k2
119
+ ).name
120
+ has_subdevices = True
121
+ except Exception as e:
122
+ print(f"Error getting real positioners for {key}: {e}")
123
+ if hasattr(device, "pseudo_positioners"):
124
+ try:
125
+ for k2 in device.pseudo_positioners._fields:
126
+ self.descriptions[f"{key}.{k2}"] = getattr(
127
+ device.pseudo_positioners, k2
128
+ ).name
129
+ has_subdevices = True
130
+ except Exception as e:
131
+ print(f"Error getting pseudo positioners for {key}: {e}")
132
+ if hasattr(device, "position_axes"):
133
+ try:
134
+ for k2 in device.position_axes:
135
+ self.descriptions[f"{key}.{k2.attr_name}"] = k2.attr_name
136
+ has_subdevices = True
137
+ except Exception as e:
138
+ print(f"Error getting position axes for {key}: {e}")
139
+ if not has_subdevices:
140
+ self.descriptions[key] = description
141
+
142
+ def remove(self, device_or_key):
143
+ key = self.get_key(device_or_key)
144
+ self.devices.pop(key, None)
145
+ self.descriptions.pop(key, None)
146
+ for dkey in list(self.descriptions.keys()):
147
+ if dkey.split(".")[0] == key:
148
+ self.descriptions.pop(dkey, None)
149
+
150
+ def describe(self, verbose=True, textFunction=None):
151
+ title = self.groupname
152
+ text = []
153
+ for key, device in self.devices.items():
154
+ name = device.name
155
+ if textFunction is None:
156
+ text.append(f"Key: {key}; Name: {name}")
157
+ else:
158
+ text.append(textFunction(self, key, device))
159
+ if verbose:
160
+ text.append(f" {self.descriptions[key]}")
161
+ boxed_text(title, text, "white")
162
+
163
+
164
+ class DetectorGroup(HardwareGroup):
165
+ def __init__(self, name="detectors", use_redis=False):
166
+ super().__init__(name=name, use_redis=use_redis)
167
+ self.status = GLOBAL_USER_STATUS.request_status_dict(
168
+ f"{self.groupname.upper()}_STATUS", use_redis=use_redis
169
+ )
170
+ self.thresholds = GLOBAL_USER_STATUS.request_status_dict(
171
+ f"{self.groupname.upper()}_THRESHOLDS", use_redis=use_redis
172
+ )
173
+ self.active = GLOBAL_USER_STATUS.request_status_list(
174
+ f"{self.groupname.upper()}_ACTIVE", use_redis=False
175
+ )
176
+ self.detector_sets = GLOBAL_USER_STATUS.request_status_dict(
177
+ f"{self.groupname.upper()}_SETS", use_redis=use_redis
178
+ )
179
+ self.roles = {}
180
+
181
+ def add(
182
+ self,
183
+ key,
184
+ device,
185
+ description="",
186
+ activate=True,
187
+ sets=None,
188
+ threshold=None,
189
+ **kwargs,
190
+ ):
191
+ super().add(key, device, description)
192
+ self.status[key] = "inactive"
193
+ if activate:
194
+ self.activate(key)
195
+ if sets is not None:
196
+ for set_name in sets:
197
+ self.add_to_set(device, set_name)
198
+ if threshold is not None:
199
+ self.thresholds[key] = threshold
200
+
201
+ def remove(self, device_or_key):
202
+ self.deactivate(device_or_key)
203
+ key = self.get_key(device_or_key)
204
+ super().remove(device_or_key)
205
+ self.status.pop(key, None)
206
+ self.thresholds.pop(key, None)
207
+
208
+ def activate(self, device_or_key, role=None):
209
+ key = self.get_key(device_or_key)
210
+ detector = self.devices[key]
211
+ if self.status[key] == "disabled":
212
+ print(f"Detector {key} is disabled and will not be activated")
213
+ return
214
+ else:
215
+ self.status[key] = "active"
216
+ if detector not in self.active:
217
+ self.active.append(detector)
218
+ if role is not None:
219
+ self.add_role(key, role)
220
+
221
+ def deactivate(self, device_or_key):
222
+ key = self.get_key(device_or_key)
223
+ device = self.get(device_or_key)
224
+ if device in self.active:
225
+ idx = self.active.index(device)
226
+ self.active.pop(idx)
227
+ if self.status[key] != "disabled":
228
+ self.status[key] = "inactive"
229
+
230
+ def activate_set(self, set_name):
231
+ for key in self.detector_sets.get(set_name, []):
232
+ self.activate(key)
233
+
234
+ def deactivate_set(self, set_name):
235
+ for key in self.detector_sets.get(set_name, []):
236
+ self.deactivate(key)
237
+
238
+ def add_set(self, set_name, set_keys):
239
+ self.detector_sets[set_name] = set_keys
240
+
241
+ def set_role(self, key, role):
242
+ self.roles[key] = role
243
+
244
+ def save_active_as_set(self, set_name):
245
+ set_keys = [self.get_key(device) for device in self.active]
246
+ self.add_set(set_name, set_keys)
247
+
248
+ def enable(self, device_or_key, activate=True):
249
+ key = self.get_key(device_or_key)
250
+ self.status[key] = "inactive"
251
+ if activate:
252
+ self.activate(device_or_key)
253
+
254
+ def disable(self, device_or_key):
255
+ key = self.get_key(device_or_key)
256
+ self.deactivate(device_or_key)
257
+ self.status[key] = "disabled"
258
+
259
+ def get_plot_hints(self):
260
+ plot_hints = {}
261
+ for detector in self.active:
262
+ key = self.get_key(detector)
263
+ role = self.roles.get(key, "auxiliary")
264
+ if role not in plot_hints:
265
+ plot_hints[role] = []
266
+ if hasattr(detector, "get_plot_hints"):
267
+ plot_hints[role] += detector.get_plot_hints()
268
+ else:
269
+ plot_hints[role].append(detector.name)
270
+ return plot_hints
nbs_bl/load.py ADDED
@@ -0,0 +1,113 @@
1
+ from copy import deepcopy
2
+ from importlib import import_module
3
+
4
+ try:
5
+ import tomllib
6
+ except ModuleNotFoundError:
7
+ import tomli as tomllib
8
+
9
+
10
+ def loadConfigDB(filename):
11
+ """
12
+ Load configuration from a TOML file.
13
+
14
+ Parameters
15
+ ----------
16
+ filename : str
17
+ The path to the TOML file containing the configuration.
18
+
19
+ Returns
20
+ -------
21
+ dict
22
+ The configuration loaded from the TOML file.
23
+ """
24
+ with open(filename, "rb") as f:
25
+ db = tomllib.load(f)
26
+ return db
27
+
28
+
29
+ def simpleResolver(fullclassname):
30
+ """
31
+ Resolve a full class name to a class object.
32
+
33
+ Parameters
34
+ ----------
35
+ fullclassname : str
36
+ The full class name to resolve.
37
+
38
+ Returns
39
+ -------
40
+ type
41
+ The class object resolved from the full class name.
42
+ """
43
+ class_name = fullclassname.split(".")[-1]
44
+ module_name = ".".join(fullclassname.split(".")[:-1])
45
+ module = import_module(module_name)
46
+ cls = getattr(module, class_name)
47
+ return cls
48
+
49
+
50
+ def instantiateDevice(device_key, info, cls=None, namespace=None):
51
+ """
52
+ Instantiate a device with given information.
53
+
54
+ Parameters
55
+ ----------
56
+ device_key : str
57
+ The key identifying the device.
58
+ info : dict
59
+ The information dictionary for the device.
60
+ cls : type, optional
61
+ The class to instantiate the device with. If not provided, it will be resolved from the info dictionary.
62
+ namespace : dict, optional
63
+ The namespace to add the instantiated device to.
64
+
65
+ Returns
66
+ -------
67
+ object
68
+ The instantiated device.
69
+ """
70
+ device_info = deepcopy(info)
71
+ if cls is not None:
72
+ device_info.pop("_target", None)
73
+ elif device_info.get("_target", None) is not None:
74
+ cls = simpleResolver(device_info.pop("_target"))
75
+ else:
76
+ raise KeyError("Could not find '_target' in {}".format(device_info))
77
+
78
+ popkeys = [key for key in device_info if key.startswith("_")]
79
+ for key in popkeys:
80
+ device_info.pop(key)
81
+
82
+ name = device_info.pop("name", device_key)
83
+ prefix = device_info.pop("prefix", "")
84
+ add_to_namespace = device_info.pop("_add_to_ns", True)
85
+ device = cls(prefix, name=name, **device_info)
86
+
87
+ if add_to_namespace and namespace is not None:
88
+ namespace[device_key] = device
89
+ return device
90
+
91
+
92
+ def loadDeviceConfig(filename, namespace=None):
93
+ """
94
+ Load device configuration from a file and instantiate devices.
95
+
96
+ Parameters
97
+ ----------
98
+ filename : str
99
+ The path to the file containing the device configuration.
100
+ namespace : dict, optional
101
+ The namespace to add the instantiated devices to.
102
+
103
+ Returns
104
+ -------
105
+ dict
106
+ A dictionary of instantiated devices.
107
+ """
108
+ db = loadConfigDB(filename)
109
+ device_dict = {}
110
+ for key, info in db.items():
111
+ device = instantiateDevice(key, info, namespace=namespace)
112
+ device_dict[key] = device
113
+ return device_dict
nbs_bl/motors.py ADDED
@@ -0,0 +1,19 @@
1
+ from ophyd.utils.errors import DisconnectedError
2
+ from .beamline import GLOBAL_BEAMLINE
3
+ from .help import add_to_func_list
4
+
5
+
6
+ @add_to_func_list
7
+ def list_motors(verbose=False):
8
+ """List the most important motors and their current positions"""
9
+
10
+ def textFunction(motors, key, device):
11
+ name = device.name
12
+ try:
13
+ position = device.position
14
+ except DisconnectedError:
15
+ position = "disconnected"
16
+ text = f"{name}: {position}"
17
+ return text
18
+
19
+ GLOBAL_BEAMLINE.motors.describe(verbose, textFunction)
nbs_bl/planStatus.py ADDED
@@ -0,0 +1,5 @@
1
+ from .queueserver import GLOBAL_USER_STATUS
2
+
3
+ GLOBAL_PLAN_STATUS = GLOBAL_USER_STATUS.request_status_dict(
4
+ "PLAN_STATUS", use_redis=True
5
+ )
@@ -0,0 +1,8 @@
1
+ from . import scans
2
+ from . import xas
3
+ from .flyscan_base import fly_scan
4
+ from .plan_stubs import set_exposure
5
+ from .metaplans import (
6
+ repeat_plan_sequence_for_duration,
7
+ repeat_plan_sequence_while_condition,
8
+ )