apsbits 1.0.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.
- apsbits/__init__.py +18 -0
- apsbits/_version.py +21 -0
- apsbits/core/__init__.py +11 -0
- apsbits/core/best_effort_init.py +51 -0
- apsbits/core/catalog_init.py +36 -0
- apsbits/core/run_engine_init.py +118 -0
- apsbits/demo_instrument/README.md +1 -0
- apsbits/demo_instrument/__init__.py +22 -0
- apsbits/demo_instrument/callbacks/__init__.py +1 -0
- apsbits/demo_instrument/callbacks/nexus_data_file_writer.py +58 -0
- apsbits/demo_instrument/callbacks/spec_data_file_writer.py +97 -0
- apsbits/demo_instrument/configs/__init__.py +1 -0
- apsbits/demo_instrument/configs/devices.yml +52 -0
- apsbits/demo_instrument/configs/devices_aps_only.yml +6 -0
- apsbits/demo_instrument/configs/iconfig.yml +82 -0
- apsbits/demo_instrument/configs/logging.yml +41 -0
- apsbits/demo_instrument/devices/__init__.py +1 -0
- apsbits/demo_instrument/plans/__init__.py +8 -0
- apsbits/demo_instrument/plans/dm_plans.py +111 -0
- apsbits/demo_instrument/plans/sim_plans.py +69 -0
- apsbits/demo_instrument/startup.py +76 -0
- apsbits/demo_qserver/qs-config.yml +51 -0
- apsbits/demo_qserver/qs_host.sh +231 -0
- apsbits/demo_qserver/user_group_permissions.yaml +46 -0
- apsbits/tests/__init__.py +1 -0
- apsbits/tests/conftest.py +39 -0
- apsbits/tests/test_config.py +113 -0
- apsbits/tests/test_device_factories.py +44 -0
- apsbits/tests/test_general.py +98 -0
- apsbits/tests/test_stored_dict.py +139 -0
- apsbits/utils/__init__.py +1 -0
- apsbits/utils/aps_functions.py +67 -0
- apsbits/utils/config_loaders.py +169 -0
- apsbits/utils/controls_setup.py +107 -0
- apsbits/utils/create_new_instrument.py +129 -0
- apsbits/utils/helper_functions.py +123 -0
- apsbits/utils/logging_setup.py +211 -0
- apsbits/utils/make_devices.py +162 -0
- apsbits/utils/metadata.py +96 -0
- apsbits/utils/sim_creator.py +202 -0
- apsbits/utils/stored_dict.py +174 -0
- apsbits-1.0.0.dist-info/METADATA +195 -0
- apsbits-1.0.0.dist-info/RECORD +47 -0
- apsbits-1.0.0.dist-info/WHEEL +5 -0
- apsbits-1.0.0.dist-info/entry_points.txt +2 -0
- apsbits-1.0.0.dist-info/licenses/LICENSE +48 -0
- apsbits-1.0.0.dist-info/top_level.txt +1 -0
apsbits/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# -*- coding: iso-8859-1 -*-
|
|
2
|
+
|
|
3
|
+
"""Model Bluesky Data Acquisition Instrument."""
|
|
4
|
+
|
|
5
|
+
from apsbits.utils.logging_setup import configure_logging
|
|
6
|
+
|
|
7
|
+
configure_logging()
|
|
8
|
+
|
|
9
|
+
__package__ = "apsbits"
|
|
10
|
+
try:
|
|
11
|
+
from setuptools_scm import get_version
|
|
12
|
+
|
|
13
|
+
__version__ = get_version(root="..", relative_to=__file__)
|
|
14
|
+
del get_version
|
|
15
|
+
except (LookupError, ModuleNotFoundError):
|
|
16
|
+
from importlib.metadata import version
|
|
17
|
+
|
|
18
|
+
__version__ = version(__package__)
|
apsbits/_version.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
6
|
+
TYPE_CHECKING = False
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
11
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
12
|
+
else:
|
|
13
|
+
VERSION_TUPLE = object
|
|
14
|
+
|
|
15
|
+
version: str
|
|
16
|
+
__version__: str
|
|
17
|
+
__version_tuple__: VERSION_TUPLE
|
|
18
|
+
version_tuple: VERSION_TUPLE
|
|
19
|
+
|
|
20
|
+
__version__ = version = '1.0.0'
|
|
21
|
+
__version_tuple__ = version_tuple = (1, 0, 0)
|
apsbits/core/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility support to start bluesky sessions.
|
|
3
|
+
|
|
4
|
+
Also contains setup code that MUST run before other code in this directory.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from apsbits.utils.helper_functions import debug_python
|
|
8
|
+
from apsbits.utils.helper_functions import mpl_setup
|
|
9
|
+
|
|
10
|
+
debug_python()
|
|
11
|
+
mpl_setup()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BestEffortCallback: simple real-time visualizations, provides ``bec``.
|
|
3
|
+
======================================================================
|
|
4
|
+
|
|
5
|
+
.. autosummary::
|
|
6
|
+
~init_bec_peaks
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
from bluesky.callbacks.best_effort import BestEffortCallback
|
|
12
|
+
|
|
13
|
+
from apsbits.utils.helper_functions import running_in_queueserver
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
logger.bsdev(__file__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def init_bec_peaks(iconfig):
|
|
20
|
+
"""
|
|
21
|
+
Create and configure a BestEffortCallback object based on the provided iconfig.
|
|
22
|
+
|
|
23
|
+
Parameters:
|
|
24
|
+
iconfig (dict): Configuration dictionary.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
tuple: A tuple containing the configured BestEffortCallback object (bec)
|
|
28
|
+
and its peaks dictionary.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
bec = BestEffortCallback()
|
|
32
|
+
"""BestEffortCallback object, creates live tables and plots."""
|
|
33
|
+
|
|
34
|
+
bec_config = iconfig.get("BEC", {})
|
|
35
|
+
|
|
36
|
+
if not bec_config.get("BASELINE", True):
|
|
37
|
+
bec.disable_baseline()
|
|
38
|
+
|
|
39
|
+
if not bec_config.get("HEADING", True):
|
|
40
|
+
bec.disable_heading()
|
|
41
|
+
|
|
42
|
+
if not bec_config.get("PLOTS", True) or running_in_queueserver():
|
|
43
|
+
bec.disable_plots()
|
|
44
|
+
|
|
45
|
+
if not bec_config.get("TABLE", True):
|
|
46
|
+
bec.disable_table()
|
|
47
|
+
|
|
48
|
+
peaks = bec.peaks
|
|
49
|
+
"""Dictionary with statistical analysis of LivePlots."""
|
|
50
|
+
|
|
51
|
+
return bec, peaks
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Databroker catalog, provides ``cat``
|
|
3
|
+
====================================
|
|
4
|
+
|
|
5
|
+
.. autosummary::
|
|
6
|
+
~cat
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
import databroker
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
logger.bsdev(__file__)
|
|
15
|
+
|
|
16
|
+
TEMPORARY_CATALOG_NAME = "temporalcat"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def init_catalog(iconfig):
|
|
20
|
+
"""
|
|
21
|
+
Initialize the Databroker catalog using the provided iconfig.
|
|
22
|
+
|
|
23
|
+
Parameters:
|
|
24
|
+
iconfig: Configuration object to retrieve catalog name.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Databroker catalog object.
|
|
28
|
+
"""
|
|
29
|
+
catalog_name = iconfig.get("DATABROKER_CATALOG", TEMPORARY_CATALOG_NAME)
|
|
30
|
+
try:
|
|
31
|
+
_cat = databroker.catalog[catalog_name].v2
|
|
32
|
+
except KeyError:
|
|
33
|
+
_cat = databroker.temp().v2
|
|
34
|
+
|
|
35
|
+
logger.info("Databroker catalog name: %s", _cat.name)
|
|
36
|
+
return _cat
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Setup the Bluesky RunEngine, provides ``RE`` and ``sd``.
|
|
3
|
+
========================================================
|
|
4
|
+
|
|
5
|
+
.. autosummary::
|
|
6
|
+
~init_RE
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
import bluesky
|
|
12
|
+
from bluesky.utils import ProgressBarManager
|
|
13
|
+
|
|
14
|
+
from apsbits.utils.controls_setup import connect_scan_id_pv
|
|
15
|
+
from apsbits.utils.controls_setup import set_control_layer
|
|
16
|
+
from apsbits.utils.controls_setup import set_timeouts
|
|
17
|
+
from apsbits.utils.metadata import get_md_path
|
|
18
|
+
from apsbits.utils.metadata import re_metadata
|
|
19
|
+
from apsbits.utils.stored_dict import StoredDict
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
logger.bsdev(__file__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def init_RE(iconfig, bec_instance=None, cat_instance=None):
|
|
26
|
+
"""
|
|
27
|
+
Initialize and configure a bluesky RunEngine (RE) instance.
|
|
28
|
+
|
|
29
|
+
This function sets up the RunEngine with metadata storage, subscriptions,
|
|
30
|
+
preprocessors, and other configurations based on the provided input
|
|
31
|
+
parameters and configuration dictionary.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
iconfig (dict): Configuration dictionary containing settings for the
|
|
35
|
+
RunEngine. Expected keys include:
|
|
36
|
+
- "RUN_ENGINE": A dictionary with RunEngine-specific settings.
|
|
37
|
+
- "MD_STORAGE_HANDLER": (Optional) The handler for metadata storage
|
|
38
|
+
(default is "StoredDict").
|
|
39
|
+
- "DEFAULT_METADATA": (Optional) Default metadata to be added to
|
|
40
|
+
the RunEngine.
|
|
41
|
+
- "USE_PROGRESS_BAR": (Optional) Boolean to enable/disable the
|
|
42
|
+
progress bar (default is True).
|
|
43
|
+
bec_instance (object, optional): An instance of BestEffortCallback (BEC)
|
|
44
|
+
for subscribing to the RunEngine. Defaults to `bec`.
|
|
45
|
+
cat_instance (object, optional): An instance of a databroker catalog
|
|
46
|
+
for subscribing to the RunEngine. Defaults to `cat`.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
tuple: A tuple containing the configured RunEngine instance and the
|
|
50
|
+
SupplementalData instance.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
Exception: If there is an error creating the metadata storage handler.
|
|
54
|
+
|
|
55
|
+
Notes:
|
|
56
|
+
- The function ensures that the RE.md dictionary is saved/restored
|
|
57
|
+
using the specified metadata storage handler.
|
|
58
|
+
- Subscriptions to the catalog and BEC are added if the respective
|
|
59
|
+
instances are provided.
|
|
60
|
+
- Additional configurations such as control layer setup, timeouts,
|
|
61
|
+
and progress bar are applied.
|
|
62
|
+
"""
|
|
63
|
+
re_config = iconfig.get("RUN_ENGINE", {})
|
|
64
|
+
|
|
65
|
+
RE = bluesky.RunEngine()
|
|
66
|
+
"""The bluesky RunEngine object."""
|
|
67
|
+
|
|
68
|
+
MD_PATH = get_md_path(iconfig)
|
|
69
|
+
# Save/restore RE.md dictionary, in this precise order.
|
|
70
|
+
if MD_PATH is not None:
|
|
71
|
+
handler_name = re_config.get("MD_STORAGE_HANDLER", "StoredDict")
|
|
72
|
+
logger.debug(
|
|
73
|
+
"Select %r to store 'RE.md' dictionary in %s.",
|
|
74
|
+
handler_name,
|
|
75
|
+
MD_PATH,
|
|
76
|
+
)
|
|
77
|
+
try:
|
|
78
|
+
if handler_name == "PersistentDict":
|
|
79
|
+
RE.md = bluesky.utils.PersistentDict(MD_PATH)
|
|
80
|
+
else:
|
|
81
|
+
RE.md = StoredDict(MD_PATH)
|
|
82
|
+
except Exception as error:
|
|
83
|
+
print(
|
|
84
|
+
"\n"
|
|
85
|
+
f"Could not create {handler_name} for RE metadata. Continuing"
|
|
86
|
+
f" without saving metadata to disk. {error=}\n"
|
|
87
|
+
)
|
|
88
|
+
logger.warning("%s('%s') error:%s", handler_name, MD_PATH, error)
|
|
89
|
+
|
|
90
|
+
if cat_instance is not None:
|
|
91
|
+
RE.md.update(re_metadata(iconfig, cat_instance)) # programmatic metadata
|
|
92
|
+
RE.md.update(re_config.get("DEFAULT_METADATA", {}))
|
|
93
|
+
|
|
94
|
+
sd = bluesky.SupplementalData()
|
|
95
|
+
"""Baselines & monitors for ``RE``."""
|
|
96
|
+
|
|
97
|
+
if cat_instance is not None:
|
|
98
|
+
RE.subscribe(cat_instance.v1.insert)
|
|
99
|
+
if bec_instance is not None:
|
|
100
|
+
RE.subscribe(bec_instance)
|
|
101
|
+
RE.preprocessors.append(sd)
|
|
102
|
+
|
|
103
|
+
set_control_layer(
|
|
104
|
+
control_layer=iconfig.get("OPHYD", {}).get("CONTROL_LAYER", "PyEpics")
|
|
105
|
+
)
|
|
106
|
+
# MUST happen before ANY EpicsSignalBase (or subclass) is created.
|
|
107
|
+
set_timeouts(timeouts=iconfig.get("OPHYD", {}).get("TIMEOUTS", {}))
|
|
108
|
+
connect_scan_id_pv(
|
|
109
|
+
RE,
|
|
110
|
+
scan_id_pv=iconfig.get("RUN_ENGINE", {}).get("SCAN_ID_PV"),
|
|
111
|
+
) # need to add the variables I removed from iconfig here as args
|
|
112
|
+
|
|
113
|
+
if re_config.get("USE_PROGRESS_BAR", True):
|
|
114
|
+
# Add a progress bar.
|
|
115
|
+
pbar_manager = ProgressBarManager()
|
|
116
|
+
RE.waiting_hook = pbar_manager
|
|
117
|
+
|
|
118
|
+
return RE, sd
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
## Demo Instrument
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Demo instrument package.
|
|
3
|
+
|
|
4
|
+
This package provides a demo instrument implementation for testing and development.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from apsbits.utils.config_loaders import load_config
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
logger.bsdev(__file__)
|
|
14
|
+
|
|
15
|
+
# Get the path to the instrument package
|
|
16
|
+
instrument_path = Path(__file__).parent
|
|
17
|
+
|
|
18
|
+
# Load configuration
|
|
19
|
+
iconfig_path = instrument_path / "configs" / "iconfig.yml"
|
|
20
|
+
load_config(iconfig_path)
|
|
21
|
+
|
|
22
|
+
logger.info("Starting Instrument with iconfig: %s", iconfig_path)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""RunEngine callbacks, mostly."""
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Nexus data file writer callback.
|
|
3
|
+
|
|
4
|
+
This module provides callbacks for writing data to Nexus data files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
from apsbits.utils.aps_functions import host_on_aps_subnet
|
|
10
|
+
from apsbits.utils.config_loaders import get_config
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
logger.bsdev(__file__)
|
|
14
|
+
|
|
15
|
+
# Get the configuration
|
|
16
|
+
iconfig = get_config()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if host_on_aps_subnet():
|
|
20
|
+
from apstools.callbacks import NXWriterAPS as NXWriter
|
|
21
|
+
else:
|
|
22
|
+
from apstools.callbacks import NXWriter
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MyNXWriter(NXWriter):
|
|
26
|
+
"""Patch to get sample title from metadata, if available."""
|
|
27
|
+
|
|
28
|
+
def get_sample_title(self):
|
|
29
|
+
"""
|
|
30
|
+
Get the title from the metadata or modify the default.
|
|
31
|
+
|
|
32
|
+
default title: S{scan_id}-{plan_name}-{short_uid}
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
title = self.metadata["title"]
|
|
36
|
+
except KeyError:
|
|
37
|
+
# title = super().get_sample_title() # the default title
|
|
38
|
+
title = f"S{self.scan_id:05d}-{self.plan_name}-{self.uid[:7]}"
|
|
39
|
+
return title
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def nxwriter_init(RE):
|
|
43
|
+
"""Initialize the Nexus data file writer callback."""
|
|
44
|
+
nxwriter = MyNXWriter() # create the callback instance
|
|
45
|
+
"""The NeXus file writer object."""
|
|
46
|
+
|
|
47
|
+
if iconfig.get("NEXUS_DATA_FILES", {}).get("ENABLE", False):
|
|
48
|
+
RE.subscribe(nxwriter.receiver) # write data to NeXus files
|
|
49
|
+
|
|
50
|
+
nxwriter.file_extension = iconfig.get("NEXUS_DATA_FILES", {}).get(
|
|
51
|
+
"FILE_EXTENSION", "hdf"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
print(nxwriter.file_extension)
|
|
55
|
+
warn_missing = iconfig.get("NEXUS_DATA_FILES", {}).get("WARN_MISSING", False)
|
|
56
|
+
nxwriter.warn_on_missing_content = warn_missing
|
|
57
|
+
|
|
58
|
+
return nxwriter
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
custom callbacks
|
|
3
|
+
================
|
|
4
|
+
|
|
5
|
+
.. autosummary::
|
|
6
|
+
:nosignatures:
|
|
7
|
+
|
|
8
|
+
~newSpecFile
|
|
9
|
+
~spec_comment
|
|
10
|
+
~specwriter
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import datetime
|
|
14
|
+
import logging
|
|
15
|
+
import pathlib
|
|
16
|
+
|
|
17
|
+
import apstools.callbacks
|
|
18
|
+
import apstools.utils
|
|
19
|
+
|
|
20
|
+
from apsbits.utils.config_loaders import get_config
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
logger.bsdev(__file__)
|
|
24
|
+
|
|
25
|
+
iconfig = get_config()
|
|
26
|
+
file_extension = iconfig.get("SPEC_DATA_FILES", {}).get("FILE_EXTENSION", "dat")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def spec_comment(comment, doc=None):
|
|
30
|
+
"""Make it easy for user to add comments to the data file."""
|
|
31
|
+
apstools.callbacks.spec_comment(comment, doc, specwriter)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def newSpecFile(title, scan_id=None, RE=None):
|
|
35
|
+
"""
|
|
36
|
+
User choice of the SPEC file name.
|
|
37
|
+
|
|
38
|
+
Cleans up title, prepends month and day and appends file extension.
|
|
39
|
+
If ``RE`` is passed, then resets ``RE.md["scan_id"] = scan_id``.
|
|
40
|
+
|
|
41
|
+
If the SPEC file already exists, then ``scan_id`` is ignored and
|
|
42
|
+
``RE.md["scan_id"]`` is set to the last scan number in the file.
|
|
43
|
+
"""
|
|
44
|
+
kwargs = {}
|
|
45
|
+
if RE is not None:
|
|
46
|
+
kwargs["RE"] = RE
|
|
47
|
+
|
|
48
|
+
mmdd = str(datetime.datetime.now()).split()[0][5:].replace("-", "_")
|
|
49
|
+
clean = apstools.utils.cleanupText(title)
|
|
50
|
+
fname = pathlib.Path(f"{mmdd}_{clean}.{file_extension}")
|
|
51
|
+
if fname.exists():
|
|
52
|
+
logger.warning(f">>> file already exists: {fname} <<<")
|
|
53
|
+
handled = "appended"
|
|
54
|
+
else:
|
|
55
|
+
kwargs["scan_id"] = scan_id or 1
|
|
56
|
+
handled = "created"
|
|
57
|
+
|
|
58
|
+
specwriter.newfile(fname, **kwargs)
|
|
59
|
+
|
|
60
|
+
logger.info(f"SPEC file name : {specwriter.spec_filename}")
|
|
61
|
+
logger.info(f"File will be {handled} at end of next bluesky scan.")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# Add this function to specwriter.py
|
|
65
|
+
def init_specwriter_with_RE(RE):
|
|
66
|
+
"""Initialize specwriter with the run engine."""
|
|
67
|
+
|
|
68
|
+
# make the SPEC file in current working directory (assumes is writable)
|
|
69
|
+
specwriter.newfile(specwriter.spec_filename)
|
|
70
|
+
|
|
71
|
+
if iconfig.get("SPEC_DATA_FILES", {}).get("ENABLE", False):
|
|
72
|
+
RE.subscribe(specwriter.receiver) # write data to SPEC files
|
|
73
|
+
logger.info("SPEC data file: %s", specwriter.spec_filename.resolve())
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
# feature new in apstools 1.6.14
|
|
77
|
+
from apstools.plans import label_stream_wrapper
|
|
78
|
+
|
|
79
|
+
def motor_start_preprocessor(plan):
|
|
80
|
+
"""Record motor positions at start of each run."""
|
|
81
|
+
return label_stream_wrapper(plan, "motor", when="start")
|
|
82
|
+
|
|
83
|
+
RE.preprocessors.append(motor_start_preprocessor)
|
|
84
|
+
except Exception:
|
|
85
|
+
logger.warning("Could load support to log motors positions.")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# write scans to SPEC data file
|
|
89
|
+
try:
|
|
90
|
+
# apstools >=1.6.21
|
|
91
|
+
_specwriter = apstools.callbacks.SpecWriterCallback2()
|
|
92
|
+
except AttributeError:
|
|
93
|
+
# apstools <1.6.21
|
|
94
|
+
_specwriter = apstools.callbacks.SpecWriterCallback()
|
|
95
|
+
|
|
96
|
+
specwriter = _specwriter
|
|
97
|
+
"""The SPEC file writer object."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Configs required to set up user package"""
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Guarneri-style device YAML configuration
|
|
2
|
+
|
|
3
|
+
apsbits.utils.sim_creator.predefined_device:
|
|
4
|
+
- {creator: ophyd.sim.motor, name: sim_motor}
|
|
5
|
+
- {creator: ophyd.sim.noisy_det, name: sim_det}
|
|
6
|
+
|
|
7
|
+
apstools.devices.SimulatedApsPssShutterWithStatus:
|
|
8
|
+
- name: shutter
|
|
9
|
+
labels: ["shutters"]
|
|
10
|
+
|
|
11
|
+
# ophyd.Signal:
|
|
12
|
+
# - name: test
|
|
13
|
+
# value: 50.7
|
|
14
|
+
# - name: t2
|
|
15
|
+
# value: 2
|
|
16
|
+
|
|
17
|
+
# apstools.synApps.Optics2Slit2D_HV:
|
|
18
|
+
# - name: slit1
|
|
19
|
+
# prefix: ioc:Slit1
|
|
20
|
+
# labels: ["slits"]
|
|
21
|
+
|
|
22
|
+
# hkl.SimulatedE4CV:
|
|
23
|
+
# - name: sim4c
|
|
24
|
+
# prefix: ""
|
|
25
|
+
# labels: ["diffractometer"]
|
|
26
|
+
|
|
27
|
+
# ophyd.scaler.ScalerCH:
|
|
28
|
+
# - name: scaler1
|
|
29
|
+
# prefix: vme:scaler1
|
|
30
|
+
# labels: ["scalers", "detectors"]
|
|
31
|
+
|
|
32
|
+
# ophyd.EpicsMotor:
|
|
33
|
+
# - {name: m1, prefix: gp:m1, labels: ["motor"]}
|
|
34
|
+
# - {name: m2, prefix: gp:m2, labels: ["motor"]}
|
|
35
|
+
# - {name: m3, prefix: gp:m3, labels: ["motor"]}
|
|
36
|
+
# - {name: m4, prefix: gp:m4, labels: ["motor"]}
|
|
37
|
+
|
|
38
|
+
# apstools.devices.ad_creator:
|
|
39
|
+
# - name: adsimdet
|
|
40
|
+
# prefix: "ad:"
|
|
41
|
+
# labels: ["area_detector", "detectors"]
|
|
42
|
+
# plugins:
|
|
43
|
+
# - cam:
|
|
44
|
+
# class: apstools.devices.SimDetectorCam_V34
|
|
45
|
+
# - image
|
|
46
|
+
# - pva
|
|
47
|
+
# - hdf1:
|
|
48
|
+
# class: apstools.devices.AD_EpicsFileNameHDF5Plugin
|
|
49
|
+
# read_path_template: "/path/to/bluesky/tmp/"
|
|
50
|
+
# write_path_template: "/path/to/ioc/tmp/"
|
|
51
|
+
# - roi1
|
|
52
|
+
# - stats1
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Configuration for the Bluesky instrument package.
|
|
2
|
+
|
|
3
|
+
# identify the version of this iconfig.yml file
|
|
4
|
+
ICONFIG_VERSION: 2.0.0
|
|
5
|
+
|
|
6
|
+
# Add additional configuration for use with your instrument.
|
|
7
|
+
|
|
8
|
+
### The short name for the databroker catalog.
|
|
9
|
+
DATABROKER_CATALOG: &databroker_catalog temp
|
|
10
|
+
|
|
11
|
+
### RunEngine configuration
|
|
12
|
+
RUN_ENGINE:
|
|
13
|
+
DEFAULT_METADATA:
|
|
14
|
+
beamline_id: demo_instrument
|
|
15
|
+
instrument_name: Most Glorious Scientific Instrument
|
|
16
|
+
proposal_id: commissioning
|
|
17
|
+
databroker_catalog: *databroker_catalog
|
|
18
|
+
|
|
19
|
+
### EPICS PV to use for the `scan_id`.
|
|
20
|
+
### Default: `RE.md["scan_id"]` (not using an EPICS PV)
|
|
21
|
+
# SCAN_ID_PV: "IOC:bluesky_scan_id"
|
|
22
|
+
|
|
23
|
+
### Where to "autosave" the RE.md dictionary.
|
|
24
|
+
### Defaults:
|
|
25
|
+
MD_STORAGE_HANDLER: StoredDict
|
|
26
|
+
MD_PATH: .re_md_dict.yml
|
|
27
|
+
|
|
28
|
+
### The progress bar is nice to see,
|
|
29
|
+
### except when it clutters the output in Jupyter notebooks.
|
|
30
|
+
### Default: False
|
|
31
|
+
USE_PROGRESS_BAR: false
|
|
32
|
+
|
|
33
|
+
# Command-line tools, such as %wa, %ct, ...
|
|
34
|
+
USE_BLUESKY_MAGICS: true
|
|
35
|
+
|
|
36
|
+
### Best Effort Callback Configurations
|
|
37
|
+
### Defaults: all true
|
|
38
|
+
### except no plots in queueserver
|
|
39
|
+
BEC:
|
|
40
|
+
BASELINE: true
|
|
41
|
+
HEADING: true
|
|
42
|
+
PLOTS: false
|
|
43
|
+
TABLE: true
|
|
44
|
+
|
|
45
|
+
### Support for known output file formats.
|
|
46
|
+
### Uncomment to use. If undefined, will not write that type of file.
|
|
47
|
+
### Each callback should apply its configuration from here.
|
|
48
|
+
NEXUS_DATA_FILES:
|
|
49
|
+
ENABLE: false
|
|
50
|
+
FILE_EXTENSION: hdf
|
|
51
|
+
|
|
52
|
+
SPEC_DATA_FILES:
|
|
53
|
+
ENABLE: true
|
|
54
|
+
FILE_EXTENSION: dat
|
|
55
|
+
|
|
56
|
+
### APS Data Management
|
|
57
|
+
### Use bash shell, deactivate all conda environments, source this file:
|
|
58
|
+
DM_SETUP_FILE: "/home/dm/etc/dm.setup.sh"
|
|
59
|
+
|
|
60
|
+
### Local OPHYD Device Control Yaml
|
|
61
|
+
DEVICES_FILES:
|
|
62
|
+
- devices.yml
|
|
63
|
+
APS_DEVICES_FILES:
|
|
64
|
+
- devices_aps_only.yml
|
|
65
|
+
|
|
66
|
+
# ----------------------------------
|
|
67
|
+
|
|
68
|
+
OPHYD:
|
|
69
|
+
### Control layer for ophyd to communicate with EPICS.
|
|
70
|
+
### Default: PyEpics
|
|
71
|
+
### Choices: "PyEpics" or "caproto" # caproto is not yet supported
|
|
72
|
+
CONTROL_LAYER: PyEpics
|
|
73
|
+
|
|
74
|
+
### default timeouts (seconds)
|
|
75
|
+
TIMEOUTS:
|
|
76
|
+
PV_READ: &TIMEOUT 5
|
|
77
|
+
PV_WRITE: *TIMEOUT
|
|
78
|
+
PV_CONNECTION: *TIMEOUT
|
|
79
|
+
|
|
80
|
+
# Control detail of exception traces in IPython (console and notebook).
|
|
81
|
+
# Options are: Minimal, Plain, Verbose
|
|
82
|
+
XMODE_DEBUG_LEVEL: Plain
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Bluesky Session Logging Configuration
|
|
2
|
+
|
|
3
|
+
console_logs:
|
|
4
|
+
date_format: "%a-%H:%M:%S"
|
|
5
|
+
log_format: "%(levelname)-.1s %(asctime)s.%(msecs)03d: %(message)s"
|
|
6
|
+
level: info
|
|
7
|
+
root_level: bsdev
|
|
8
|
+
|
|
9
|
+
file_logs:
|
|
10
|
+
date_format: "%Y-%m-%d %H:%M:%S"
|
|
11
|
+
log_directory: .logs
|
|
12
|
+
log_filename_base: logging.log
|
|
13
|
+
log_format: "|\
|
|
14
|
+
%(asctime)s.%(msecs)03d|\
|
|
15
|
+
%(levelname)s|\
|
|
16
|
+
%(process)d|\
|
|
17
|
+
%(name)s|\
|
|
18
|
+
%(module)s|\
|
|
19
|
+
%(lineno)d|\
|
|
20
|
+
%(threadName)s| - \
|
|
21
|
+
%(message)s"
|
|
22
|
+
maxBytes: 1_000_000
|
|
23
|
+
backupCount: 9
|
|
24
|
+
level: info
|
|
25
|
+
rotate_on_startup: true
|
|
26
|
+
|
|
27
|
+
ipython_logs:
|
|
28
|
+
log_directory: .logs
|
|
29
|
+
log_filename_base: ipython_log.py
|
|
30
|
+
log_mode: rotate
|
|
31
|
+
options: -o -t
|
|
32
|
+
|
|
33
|
+
modules:
|
|
34
|
+
apstools: warning
|
|
35
|
+
bluesky-queueserver: warning
|
|
36
|
+
bluesky: warning
|
|
37
|
+
bluesky.RE: warning
|
|
38
|
+
caproto: warning
|
|
39
|
+
databroker: warning
|
|
40
|
+
instrument: bsdev
|
|
41
|
+
ophyd: warning
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Ophyd-style devices."""
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Bluesky plans."""
|
|
2
|
+
|
|
3
|
+
from .dm_plans import dm_kickoff_workflow # noqa: F401
|
|
4
|
+
from .dm_plans import dm_list_processing_jobs # noqa: F401
|
|
5
|
+
from .dm_plans import dm_submit_workflow_job # noqa: F401
|
|
6
|
+
from .sim_plans import sim_count_plan # noqa: F401
|
|
7
|
+
from .sim_plans import sim_print_plan # noqa: F401
|
|
8
|
+
from .sim_plans import sim_rel_scan_plan # noqa: F401
|