B. An overview of BMM’s profile#
Once upon a time, the advice from Bluesky’s developers was to populate
a profile_collection folder with python files containing the
beamline customizations. These files would start with a two digit
number from 00- to 99- – that is, files like
30-detectors.py or 17-motors.py. These files would be
imported into the main namespace of the IPython session in
numeric order.
As BMM’s profile grew in size and complexity, this system of ordered, numbered files all imported into the main namespace became increasingly unweilding, hard to maintain, and hard to extend.
At Dan Allan’s suggestion, we took a different approach.
B.1. The startup folder#
The startup folder is a symlink to a folder on Lustre where BMM’s profile is kept. If bsui does not start with BMM’s profile, make that symlink by doing the following:
cd ~/.ipython
ln -s /nsls2/data3/bmm/shared/config/bluesky/profile_collection
If a folder called profile_collection already exists at that
location – which would be the case if you have already used bsui
or ipython – go ahead and rename or delete that folder.
The top folder of the profile contains a single python file. It
follows the old convention in that it is named
00-populate-namespace.py and is read as soon as IPython starts.
There are three files in the startup folder:
00-populate-namespace.pyThis is the first file ipython loads as it starts bsui. See Section B.3.
BMM_configuration.iniThis windows-style INI file contains configuration information for the instrumentation and network services at the beamlines.
rois.jsonThis is a small database of ROI definitions used by the XSpress3 configuration.
user_group_permissions.yamlThis is a configuration file used by queueserver to grant access to plans according to authentication
Beneath the startup folder, there are several sub-folders:
BMM/the bulk of the code used for data acquisition.
consumer/the code used by the process that captures Kafka messages and generates plots for real-time and other data visualization (Section C)
BMM_common/code shared by data acquisition and the Kafka consumer
lookup_table/the spreadsheet with the look up table of motor positions used by the
change_edge()command (Section 7)standards/the spreadsheet for working with BMM’s collection of measurement standards
ML/the data used for the machine learning data evaluation model (Section 9.9)
telemetry/the data used for the time estimates of XAFS and other scans (Section 9.8)
dossier/files used to construct dossiers (Section 12.4)
tmpl/template files used for dossiers, INI files, and other templated materials
xlsx/empty spreadsheet examples for the various forms of automation (Section 11)
B.2. BMM_configuration.ini#
This files controls configuration details for measurement instrumentation and network services. The concept is that this file is edited prior to starting bsui to reflect the current state of the beamline and the needs of the current experiment.
Much of this file consists of flags for turning specific instruments on and off when starting bsui. For example, this section is used to enable or disable the use of the Pilatus 100K area detector and the Dante readout for the NSLS-II germanium detector in XAS experiments.
[detectors]
# use Pilatus 100K as an available detector
pilatus = False
# use the DANTE at xf06bm-edxd1
dante = False
Additionally, there are sections with flags for controlling
electrometer use for ion chambers and the electron yield detector
which silicon drift detectors are in use
which cameras (usb, analog, web) are in use
special instrumentation needs, e.g. Linkam stage, Lakeshore temperature controller, or radiological enclosure
Additional sections control configuration for
the network addresses of various services or disk locations containing files and folders needed for proper operation of bsui at BMM
for both the new NSLS-II Slack workspace and the older, deprecated BMM Slack workspace
B.3. The IPython namespace#
The 00-populate-namespace.py file contains a single line:
from BMM.user_ns import *
This tells python to read the BMM/user_ns/__init__.py file and
follow it’s instructions. That file, in turn, imports each of the
files in the BMM/user_ns/ and imports those symbols into the main
IPython namespace.
This is different from the old-fashioned approach in that the files in
BMM/user_ns/ contain a more carefully curated group of symbols to
be imported into the main namespace.
Most of the code for creating ophyd objects, defining plans,
establishing automation, and so on is contained in the files found in
the BMM folder. And most of that is not imported into the main
namespace.
A motif used in almost every file in the profile is this one:
from BMM import user_ns as user_ns_module
user_ns = vars(user_ns_module)
This allows functions and plans defined in the files in the BMM
folder to have access to symbols from the user namespace without
either importing the entire main namespace or exporting additional
symbols to the main namespace.
This, perhaps, makes the code in BMM a bit clunkier. For example,
a motor name like xafs_x which is defined in the main namespace
cannot be directly accessed by a module in BMM. Instead, it is
accessed as user_ns['xafs_x']. A bit of extra typing, but it
makes for code that is more robust and more readily maintainable and
extensible.
B.4. Managing bsui and queueserver#
A common motif found in many files, including
BMM/user_ns/__init__.py, looks like this:
try:
from bluesky_queueserver import is_re_worker_active
except ImportError:
def is_re_worker_active():
return False
This is used to allow a plan or some other bit of code to know whether it is being run under bsui or queueserver.
bsui is, by design, run on the same workstation with which the experimenter is interacting. queueserver is, by design, run on a remote server. Having a way to distinguish the two is essential. For example, there are many plans which, when run with bsui, stop to prompt for an interaction from the user. Such prompts need to be disabled when running under queueserver.
B.5. Profile start-up as a narrative#
Early in the loading of the profile, a function called
run_report() is defined. This function is defined in
BMM/functions.py and called near the top of
BMM/user_ns/bmm.py, which is the second file loaded by
BMM/user_ns/__init__.py. So, it is defined very early in the
process of loading the profile.
This is used to write a message to the screen explaining what chore is being done during start-up or what file is being loaded. As such it is very similar to the common python idiom of
print(__file__)
to identify the module or source code file being loaded. While similar in concept, it is a bit more suited to our purpose.
Fig. B.1 Screen messages during bsui start-up.#
For one thing, it applies consistent coloring to the text. In that way the user knows that that color is a progress report explaining what is happening at that moment. That is helpful for debugging problems in that it gives a hint where to look when the problem presents itself.
For another, it is a consistent way to write any progress message to the screen. For example,
run_report(__file__)
would behave very similarly to the idiom. However, the way it is used throughout the profile is in lines like this:
run_report('\tglancing angle stage')
This is the message that appears on screen as the ophyd objects and automation procedures related to the glancing angle stage (Section 5.7) are imported. As you can see in the screenshot, one such message is issued for every major component of the profile.
Taken together, this sequence of messages provides a start-up narrative that tells the user something about what capabilities are available and provides the code maintainer/developer some hints about where to look in the code base for various features.
B.6. Profile start-up as acceptance testing#
At NSLS-II, beamline staff are asked to develop ways to do acceptance testing to verify things like recovery from power failures, or upgrades of computer operating systems, upgrades of conda and python.
At BMM, we have chosen not to develop one-off or on-delivery acceptance testing practices. Instead, acceptance testing is built right into BMM’s profile.
Very early in profile start-up, several basic functions are checked for, including:
Verify that Channel Access Security is configured for read/write access
Verify that the LAN is up and that IOC servers can be pinged
Verify that various necessary folders on the local machine can be found
Verify that Lustre mounts can be found
Verify that authentication keys (e.g. for Slack) can be found
Verify that a redis server can be found
If any of these tests fail, the profile stops loading and issues a (hopefully) useful error message.
As the profile continues loading, it runs a variety of tests, such as:
Verify that beamline state and user configuration can be obtained from redis
Establish all necessary user configuration
Check each axis to verify that it is connected
Check each axis to verify that it is homed, or identify those that are used without homing
Verify that detectors are started correctly (e.g. the XSpress3 needs to save an HDF5 file to initialize file saving)
Initialize the hinted ROI from the XSpress3 using data from redis
In short, the concept is that the profile is instrumented to do acceptance testing every time it starts. If anything is found to be missing, it can be noticed and addressed immediately.
B.7. Core Bluesky functionality#
The file BMM/user_ns/base.py is used to define core features of
the bluesky ecosystem:
The plan stubs
mv,mvr, andsleepare imported into the main namespacenslsii.configure_base() is called appropriately for bsui or queueserver
Some configuration of best effort callbacks is done
A Tiled catalog is created
A ZeroMQ publisher is defined.
All of this happens before any BMM-specific code is run.
B.8. Everything in the BMM folder#
Here’s a brief summary of every module in the BMM profile.
file
purpose
actuators.pydefine shutters and valves
agent_plans.pyBMM-specific ML agents
areascan.pydefine an area scan plan
busy.pydefine a “wall clock” motor
camera_device.pyinteract with AD and non-AD cameras
db.pyutilities for working with DataBroker
dcm.pydefine monochromator ophyd objects
dcm_parameters.pymono calibration parameters
demeter.pyathena and hephaestus integration
derivedplot.pydeprecated plotting capabilities
desc_string.pyfix epics motor
DESCfields for CSS
detector_mount.pymostly deprecated tools for
xafs_detx
dossier.pymanage writing of dossier files
dwelltime.pycoordinate dwell time across detectors
edge.pychange edge
electrometer.pyophyd objects for QuadEM and related
energystep.pysimple plan for I0 vs. energy
fmbo.pyFMBO motor controller tools
frontend.pyophyd objects for front-end devices
functions.pymiscellaneous utilities
gdrive.pyinteract with Google drive (deprecated)
glancing_angle.pydefine glancing angle stage + automation
grid.pygeneric grid automation
handler.pyDataBroker handler for images
kafka.pyKafka producer for profile
killswitch.pyinteract with FMBO controller kill switches
lakeshore.pyLakeShore temp. controller
larch_interface.pyconnect to Larch XAFS functionality
linescans.pygeneric and specific motor scans
linkam.pyLinkam stage temp. controller
logging.pyvarious logging tools
macrobuilder.pybase class for automation
metadata.pymanage metadata
mirror_trigonometry.pyincomplete tools for mirrors and distances
ml.pydata evaluation tools
modes.pymanage lookup table and PDS modes
mono_calibration.pyenergy calibration tools
motor_status.pymotor status reporting tools
motors.pyophyd objects for motors
periodictable.pyperiodic table tools
pilatus.pyPilatus tools
plans.pysimple plans, power cycle recovery plans
prompt.pycustomize IPython prompts
purpose.pydeprecated
raster.pyareascan measurement + dossier
resting_state.pyput beamline in a defined resting state
rois.pydeprecated, struck tools
slits.pyophyd objects and tools for BL slits
struck.pydeprecated |nd| interact with Struck
suspenders.pydefine suspenders
telemetry.pytools for scan telemetry and time estimates
timescan.pytime sequence plan
usb_camera.pyinteract with USB cameras
user.pydefine and manage the BMMuser object
utilities.pyinetract with BL EPS and utilities
video.pyrecord videos from USB cameras
wafer.pytools for wafer samples
wdywtd.pydeprecated user help tools
webcam_device.pyinteract with Axis webcams
wheel.pytools for ex situ sample wheel
workspace.pyacceptance tests for working environment
xafs.pyXAFS plan definition + dossier
xafs_functions.pyXAFS-related tools
xdi.pyXDI formatting tools
xspress3.pyXSpress3 tools
xspress3_1element.pycustomizations for 1 element detector
xspress3_4element.pycustomizations for 4 element detector
xspress3_7element.pycustomizations for 7 element detector