Bluesky数据采集框架-4

编写自定义计划

如在以上简单自定义中提到,count()和scan()的"预装配"计划是从更小的"plan stubs"构建的。我们组合和匹配"stubs"和/或"预装配"计划来构建自定义计划。

有很多计划stubs,因此导入整个模块并且使用它是非常方便的。

import bluesky.plan_stubs as bps

并行移动

在编写一个协调多个设备移动的自定义计划前,考虑你的使用情况是否能用内建的多维扫描之一解决。

我们先前介绍了mv()计划,它移动一个或多个设备并且等待它们都到达。也有用于相对当前位置移动的mvr()。

from ophyd.sim import motor1, motor2
from bluesky import RunEngine
from bluesky.callbacks.best_effort import BestEffortCallbackbec = BestEffortCallback()
RE = RunEngine({})RE.subscribe(bec)# 相对于它们当前位置正方向移动motor1到1个单位和motor2到10个单位.
# 并且等待它们两个到达.
RE(bps.mvr(motor1, 1, motor2, 10))

某些场景需要在等待发生时更底层控制。对于这些,我们使用wait()和abs_set()("绝对设置")或rel_set()("相对设置")。

这是一个需要自定义方案的场景:我们想要一次设置若干电机,包括多个快速电机和一个慢速电机。我们想要等待快速电机到达,打印一条消息,接着等待慢速电机到达,并且打印第二天消息。

def staggered_wait(fast_motors, slow_motor):# 立即启动所有电机,快速和慢速# 放置所有快速电机在一个组...for motor in fast_motors:yield from bps.abs_set(motor, 5, group='A')# ...而在一个单独组中放置慢速电机yield from bps.abs_set(slow_motor, 5, group='B')# 等待所有快速电机print('Waiting on the fast motors.')yield from bps.wait('A')print('Fast motors are in place. Just waiting on the slow one now.')# 接着等待慢速电机yield from bps.wait('B')

睡眠(定时延迟)

注意:如果你需要等待电机结束移动,温度完成平衡,或者快门完成打开,插入延时到计划不是做这件事的最好方法。准确地报告它何时结束应该是设备的事情,包括为稳定或平衡的任何额外的填充。在某些设备上,注入EpicsMotor,这可以像motor.setting_time=3被设置。

对于定时延迟,bluesky有一个特殊计划,它允许RunEngine在睡眠过程中继续它的事情。

from ophyd.sim import  motordef sleepy_plan(motor, positions):# 在步与步之间1秒延时,步进一个电机通过一个位置列表i = 1for position in positions:print("step %d" % (i,))yield from bps.mv(motor, position)yield from bps.sleep(1)i = i + 1RE(sleepy_plan(motor, [1,2,3]))

你应该总是使用这个计划,不要Python的内建函数:func:'time.sleep'。为什么?RunEngine使用一个事件循环并发管理很多任务。它认为那些任务中没有任务阻塞非常长。(对应"非常长"代表性数值是0.2秒)。因而,你不应该在你的计划中包含长阻塞函数,诸如time.sleep(1)。

捕获数据

产生数据的任何计划必须包含把读取分组到事件的指令(即,在一个表格中的行)并且把那些事件分组到Runs(被赋予一个"扫描ID"的数据集)。通过示例最好地解释了这个。

import bluesky.plan_stubs as bps
from ophyd.sim import  det1, det2def one_run_one_event(detectors):# 声明一个新run地开始yield from bps.open_run()yield from bps.declare_stream(*detectors, name='primary')# 触发每个探测器并且等待触发结束.# 接着读取探测器并且把这些读取捆绑到一个事件# (即,在表格中一行)yield from bps.trigger_and_read(detectors)# 声明这个run的结束yield from bps.close_run()

 像这样执行这个计划:

RE(one_run_one_event([det1, det2]))

我们观察:

1、一个表格(一个Run)

2、一行(一个Event)

3、两列(每个探测器一列) 

再次,这是相同的计划,将trigger_and_read移动到一个for循环中。

import bluesky.plan_stubs as bps
from ophyd.sim import  det1, det2def one_run_multi_event(detectors, num):# 声明一个新run地开始yield from bps.open_run()yield from bps.declare_stream(*detectors, name='primary')for i in range(num):yield from bps.trigger_and_read(detectors)# 声明这个run的结束yield from bps.close_run()

像这样执行这个计划:

我们观察:

1、一个表格(一个Run)

2、三行(三个事件)

3、两列(每个探测器1列)

最后,我们添加另一个在其循环中重复使用one_run_multi_events的循环。

def multi_runs_multi_events(detectors, num, num_runs):for i in range(num_runs):yield from one_run_multi_event(detectors,num)

我们观察:

1、两个表格(两个Run)

2、三行(三个事件)

3、两列(每个探测器1列)

我们也注意到,从RunEngine输出的返回值是一个二个唯一IDs的元组,由此计划产生每个Run一个唯一ID。

为了关注Event和Run的作用域,我们省去了一个重要细节,在下面章节讲述,在真是设备上尝试这些计划前,它必需包含。

stage和unstage

复杂设备在它们可以用于数据采集前经常需要某些初始设置,使它们从一个空闲状态转变为它们为一个准备采集数据的状态。Bluesky通过允许每个Device实现一个可选的stage()方法和一个对应的unstage()方法,用一种通用的方法提供了此特性。计划应该stage每个设备它们准确到达一次并且在结束时unstage一次。如果一个设备没有stage()方法,RunEngine将只是跳过它。

修改我们最简单的示例one_run_one_event:

import bluesky.plan_stubs as bps
from ophyd.sim import  det1, det2def one_run_one_event(detectors):yield from bps.open_run()yield from bps.declare_stream(*detectors, name='primary')yield from bps.trigger_and_read(detectors)yield from bps.close_run()

我们像这样组合了staging:

import bluesky.plan_stubs as bps
from ophyd.sim import  det1, det2def one_run_one_event(detectors):# ‘Stage’每个设备for det in detectors:yield from bps.stage(det)yield from bps.open_run()yield from bps.declare_stream(*detectors, name='primary')yield from bps.trigger_and_read(detectors)yield from bps.close_run()# 'unstage'每个设备for det in detectors:yield from bps.unstage(det)

这是开始获取详细说明。到此,我们会想要接受某些额外复杂性以换取简洁,并且确保我们不忘记在匹配括号中使用这些计划。到此,这个计划相当于:

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
from ophyd.sim import  det1, det2def one_run_one_event(detectors):@bpp.stage_decorator(detectors)def inner():yield from bps.open_run()yield from bps.declare_stream(*detectors, name='primary')yield from bps.trigger_and_read(detectors)yield from bps.close_run()return (yield from inner())

stage_decorator()是一个计划预处理程序,一个消费另一个计划并且修改其指令的计划。在这种情况中,它插入了'stage'和'unstage'消息,取代了stage()和unstage()。我们通过使用run_decorator(),取代了open_run()和close_run(),可以还可以减少冗长内容。

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
from ophyd.sim import  det1, det2def one_run_one_event(detectors):@bpp.stage_decorator(detectors)@bpp.run_decorator()def inner():yield from bps.declare_stream(*detectors, name='primary')yield from bps.trigger_and_read(detectors)return (yield from inner())

在有关baseline读取的部分中,回忆我们已经在本教程中遇到过一个预处理器。supplementaldata是一个预处理程序。

添加元数据

为了使搜索由计划产生的数据变得容易,并且检查之后做了什么,我们应该包含某些元数据。我们创建了一个字典并且传递它给run_decorator()(或者,用更详细的公式,传给open_run)。RunEngine将组合元数据和由用户提供的任何信息,如在有关元数据更早章节中展示的。

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
from ophyd.sim import  det1, det2def one_run_one_event(detectors):md = {# 探测器Devices的人性化名称(对搜索有用)'detectors': [det.name for det in detectors],# python 'repr'的每个参数给这个计划'plan_args':{'detectors':list(map(repr, detectors))},# 这个计划的名称'plan_name': 'one_run_one_event',}@bpp.stage_decorator(detectors)@bpp.run_decorator()def inner():yield from bps.declare_stream(*detectors, name='primary')yield from bps.trigger_and_read(detectors)return (yield from inner())

警告:在元数据字段中的值必须仅是字符串,数值,lists/arrays,或者字典。元数据不能包含任意Python类型,因为下游消费者(如数据库)不知道对那些做什么并且将出错。

出于礼貌,我们应该允许用户重写这些元数据。为此目的,所有bluesky的"预组装"计划(count(), scan()等)提供了一个可选的md参数,像这样实现:

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bppdef one_run_one_event(detectors, md=None):md = {# 探测器Devices的人性化名称(对搜索有用)'detectors': [det.name for det in detectors],# python 'repr'的每个参数给这个计划'plan_args':{'detectors':list(map(repr, detectors))},# 这个计划的名称'plan_name': 'one_run_one_event',}# 如果在md中存在一个键,它用在_md中重写默认值_md.update(md or {})@bpp.stage_decorator(detectors)@bpp.run_decorator()def inner():yield from bps.declare_stream(*detectors, name='primary')yield from bps.trigger_and_read(detectors)return (yield from inner())

在元数据中添加"提示"

元数据字典可以可选地包含一个名为'hints'的键。这个键对BestEffortCallback和潜在地其它下游消费者尤其重要,它们使用它尝试推断表示数据地有用方式。当前,它解决两个特别问题。

1、缩小较大范围读数范围到放入表格中可管理数目的最重要读数

2、标识数据维度(1D扫描?2D网格?N-D网格)和应变和自变参数,用于可视化和峰拟合目的。

由每个设备来解决(1)。计划在那中没有作用。每个设备有一个可选的hints属性,如{'fields':[...]}的一个值来回答这个问题。“你产生的所有读数,最重要读数色名称是什么?”

我们需要计划在(2)帮助我们。只有计划能够分类哪些设备被用于"独立"轴而哪些被作为应变量被测量。单看设备是不明确的,因为任何可移动的设备取决于上下文可以用作一个轴或者一个"探测器"-count([motor])是一件要做的完美有效事情。

计划的提示元数据的方案是:

{'dimensions': [([<FIELD>, ...], <STREAM_NAME>),([<FIELD>, ...], <STREAM_NAME>),...]}

示例:

# 在X上1维扫描
{'dimensions': [(['x'], 'primary')]}# 在X和Y上2网格维扫描
{'dimensions': [(['x'], 'primary'),(['y'], 'primary')]}# 一个沿一条对角线一起移动X和Y的扫描
{'dimensions': [(['x', 'y'], 'primary')]}# 一条在温度上的1D扫描,用C和K为单位表示
{'dimensions': [(['C', 'K'], 'primary')]}# 在能量上的一维扫描,用能量和衍射仪未知测量
{'dimensions': [(['E', 'dcm'], 'primary')]}# 特殊情况:一个读取序列,在其中自变轴仅是时间
{'dimensions': [(['time'], 'primary')]}

在外层列表中的每个条目表示一个独立维度。一个维度可能由多个字段表示,要么来自用通过计划(['x', 'y'])协调方式移动的不同设备,表示为来自一个设备(['C', 'K'])完全冗余信息,或者来自两个子设备(['E', 'dcm'])的耦合信息。

在每个条目中第二个元素是这个流名称:在每个以上示例中'primary'。这应该对应在此计划中传递给trigger_and_read()或create()的name。默认名称是primary。

放置它们都在一起,这个计划为它们的重要字段请求设备被用作独立轴并且构建一个像这样的维度列表:

dimensions = [(motor.hints['fields'], 'primary')]

我们必须考虑hints是可选的实际。一个指定设备可能完全没有hints属性,并且即使它有,提示可能不包含我们感兴趣的'fields'字段。如果设备没有提供必要信息,这种模式悄悄地忽略维度提示:

def scan(..., md=None):_md = {...}_md.update(md or {})try:dimensions = [(motor.hints['fields'], 'primary')]except (AttributeError, KeyError):passelse:_md['hints'].setdefault('dimensions', dimensions)...

最后,通过使用setdefault,如果它们更了解传入scan(..., md={'hint':...}),我们运行用户重写这些hints。

在计划中自适应逻辑

在生成器和RunEngine之间,双向通信是可能的。例如,trigger_and_read()计划用其读数响应。我们可以使用它做有关是否继续或者停止的即时决策。

import bluesky.preprocessors as bpp
import bluesky.plan_stubs as bps
from ophyd.sim import det, motor
def conditional_break(threshold):"""在探测器读数强度小于阈值前,设置,触发,读取 """@bpp.stage_decorator([det, motor])@bpp.run_decorator()def inner():i = 0yield from bps.declare_stream(det, name='primary')while True:yield from bps.mv(motor, i)readings = yield from bps.trigger_and_read([det])if readings['det']['value'] < threshold:breaki += 1return (yield from inner())

演示:

在本例中重要行是:

readings = yield from bps.trigger_and_read([det])

此操作像这样运行:

1、此计划生成一个'read'消息给RunEngine

2、RunEngine读取这个探测器

3、RunEngine发回读数给这个计划,并且给这个变量reading分配那个响应。

响应reading被格式化如下:

{<name>: {'value': <value>, 'timestamp': <timestamp>}, ...}

需要此消息和它们响应的详细技术描述,见消息协议。

计划"清理"(异常处理)

如果产生了一个异常,RunEngine给计划捕获异常的机会,并且要么处理它或者在再次产生这个异常并且杀死计划执行前仅产生一些"清理"消息。(从一行暂停,继续,挂起回忆这个)。

这是一般想法:
 

# 本例是说明的,单它不是完全正确。
# 使用'finalize_wrapper'替代(或者读取它的源代码)
def plan_with_cleanup():def main_plan():# do stuff...def cleanup_plan():# do other stuff...try:yield from main_plan()finally:# 即使产生了一个异常,做这件事yield from cleanup_plan()

出现的异常可能源自这个计划自身或者来自RunEngine尝试执行一指定命令时的RunEngine。

finalize_wrapper()预处理程序提供了使用这种通用模式的简洁和完全正确的方式。

import bluesky.preprocessors as bppdef plan_with_cleanup():yield from bpp.finalize_wrapper(main_plan(), cleanup_plan())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2812452.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

低价对品牌渠道的危害

品牌价值的体现主要在价格&#xff0c;比如要与竞品体现差异&#xff0c;除了产品功能上有做出差异&#xff0c;价格上也需要设置不同的阶梯&#xff0c;但如果经销商不遵守这个体系&#xff0c;或者非授权店铺随意低价&#xff0c;对于品牌来说都是非常不好的事情&#xff0c;…

ubuntu20.04安装和使用 Maldet (Linux Malware Detect)

1、下载 Maldet sudo wget http://www.rfxn.com/downloads/maldetect-current.tar.gz 2、解压Maldet sudo tar -xvf maldetect-current.tar.gz 3、进入到Maldet目录&#xff0c;然后运行安装脚本 sudo ./install.sh 4、安装ClamAV sudo apt-get update sudo apt-get in…

【程序员英语】【美语从头学】初级篇(入门)(笔记)Lesson 16 At the Shoe Store 在鞋店

《美语从头学初级入门篇》 注意&#xff1a;被 删除线 划掉的不一定不正确&#xff0c;只是不是标准答案。 文章目录 Lesson 16 At the Shoe Store 在鞋店对话A对话B笔记会话A会话B替换 Lesson 16 At the Shoe Store 在鞋店 对话A A: Do you have these shoes in size 8? B:…

交叉编译qt到arm平台

使用pkg-config命令查看xxx包是否存在&#xff1a; pkg-config --print-errors xxx pkg-config的搜索路径可以通过环境变量PKG_CONFIG_PATH指定。需要在运行./configure 之前指定。 ./configure -release -qt-libjpeg -qt-libpng -qt-zlib -qt-pcre -xplatform linux-aarch64-…

【Git教程】(三)提交详解 —— add、commit、status、stach命令的说明,提交散列值与历史,多次提交及忽略 ~

Git教程 提交详解 1️⃣ 访问权限与时间戳2️⃣ add命令与 commit 命令3️⃣ 提交散列值4️⃣ 提交历史5️⃣ 一种特别的提交查看方法6️⃣ 同一项目的多部不同历史6.1 部分输出&#xff1a;-n6.2 格式化输出&#xff1a;--format、--oneline6.3 统计修改信息&#xff1a;--st…

yolov8学习笔记(三)添加注意力机制+源码简单了解

目录 一、前言 二、注意力机制添加 三、源码简单了解 1、YOLO类中的——私有Model类 2、在哪来初始化的网络模型 3、注释版下载 4、笔记下载 一、前言 因为我没有学过pytorch&#xff0c;所以看源码也是一头雾水&#xff0c;不过大概看懂的是yolo是对pytorch的再次封装&a…

聚集高速托盘类四向穿梭车ASRV|一车跑全仓可获得10000个货位的HEGERLS智能搬运机器人

随着国内外制造业加速转型升级&#xff0c;越来越多的企业需要进行物流智能化升级&#xff0c;但是往往受到仓库面积、高度、形状等现实条件的限制&#xff0c;以及市场不确定性因素的影响。因此&#xff0c;相对于投资传统的自动化立体库&#xff0c;企业更倾向于选择智能化、…

LeetCode刷题---平均售价

解题思路&#xff1a; 首先对Prices表和UnitsSold表进行Left join操作&#xff0c;之后按照购买日期位于定价开始和结束日期之间的条件进行过滤 按照product_id进行分组&#xff0c;对组内进行计算 将price和units的乘积进行累加&#xff0c;将units的值进行累加&#xff0c;之…

Django学习笔记-ModelForm使用(完全依赖)

1.创建模型 ,code,name,sex,entrydate 2.模型映射 python manage.py makemigrations myapp01,python manage.py migrate 3.创建模型表单,继承forms.ModelForm,Meta:元数据,models需引入,fields填写引用的模型变量 4.创建testModelForm.html,添加urls 5.views编写testmodelfo…

input输入框过滤非金额内容保留一个小数点和2位小数

这篇是输入框过滤非金额内容保留一个小数点和2位小数&#xff0c;金额的其他格式化可以看这篇文章常用的金额数字的格式化方法 js方法直接使用 该方式可以直接使用过滤内容&#xff0c;也可以到onInput或onblur等地方过滤&#xff0c;自行使用 /*** 非金额字符格式化处理* p…

精益思维引领AI创新浪潮:从理念到实践的蜕变!

在人工智能&#xff08;AI&#xff09;飞速发展的今天&#xff0c;精益思维作为一种追求卓越、持续改进的管理哲学&#xff0c;正逐渐成为推动AI创新的重要动力。本文&#xff0c;天行健咨询将探讨精益思维如何与AI创新相结合&#xff0c;以及这种结合如何推动科技进步和社会发…

springboot-基础-eclipse集成mybatis+使用方法+排错

备份笔记。所有代码都是2019年测试通过的&#xff0c;如有问题请自行搜索解决&#xff01; 目录 集成mybatis安装mybatis的jar包安装插件&#xff1a;mybatis-generator安装方法生成方法报错&#xff1a;java.lang.RuntimeException: Exception getting JDBC Driver mybatis注解…

一文讲清DTO、BO、PO、VO

DTO、BO、PO、VO是什么&#xff1f; 在后端开发中&#xff0c;比如传统的MVC架构和现在流行的DDD架构&#xff0c;经常会使用到下列几种对象的概念 DTO (Data Transfer Object) 数据传输对象&#xff1a; DTO设计模式用于将数据从服务端传输到客户端&#xff0c;或者在不同的…

使用 Koltin 集合时容易产生的 bug 注意事项

来看下面代码&#xff1a; class ChatManager {private val messages mutableListOf<Message>()/*** 当收到消息时回调*/fun onMessageReceived(message: Message) {messages.add(message)}/*** 当删除消息时回调*/fun onMessageDeleted(message: Message) {messages.r…

jenkins + gitlab + nginx 自动部署(webhook)

一、意义 当代码仓库被更新时&#xff0c;Jenkins会自动拉取代码进行构建。 适用于测试环境 二、jenkins gitlab nginx 自动部署(webhook) 1.准备服务器 ①安装Jenkins&#xff08;Java17&#xff0c;tomcat9&#xff09; ②安装gitlab &#xff08;16&#xff09; ③…

[JavaWeb玩耍日记]Mybatis快速入门与增删改查

目录 模块一&#xff1a;快速入门 1.创建数据库&#xff0c;插入数据 2.创建maven模块后&#xff0c;需要导入的依赖有哪些&#xff1f; 3.想要输出查询到的数据(包括日志打印)&#xff0c;需要创建哪些文件&#xff1f; 4.如何放置UserMapper接口与User类&#xff1f; 5.…

SpringCloud-Docker安装与详解

Docker 是一款强大的容器化平台&#xff0c;通过其轻量级的容器技术&#xff0c;使应用程序的开发、部署和管理变得更加便捷和高效。本文将深入探讨 Docker 的安装过程&#xff0c;并详细解析其基本概念、组件及常用命令&#xff0c;以帮助读者充分理解和熟练使用 Docker。企业…

C++:多重继承带来的问题及解决方法

在继承的过程中&#xff0c;如果一个派生类由多个基类派生&#xff0c;则称为多重继承&#xff08;实际开发中会引入困难&#xff0c;不建议使用&#xff09; 目录 多重继承的构造函数、析构函数调用顺序&#xff1a; 多重继承引发的二义性问题&#xff1a; 问题1&#xff…

【SVN】使用TortoiseGit删除Git分支

使用TortoiseGit删除Git分支 前言 平时我在进行开发的时候&#xff0c;比如需要开发一个新功能&#xff0c;这里以蘑菇博客开发服务网关-gateway功能为例 一般我都会在原来master分支的基础上&#xff0c;然后拉取一个新的分支【gateway】&#xff0c;然后在 gateway分支上进…

SQL Server添加用户登录

我们可以模拟一下让这个数据库可以给其它人使用 1、在计算机中添加一个新用户TeacherWang 2、在Sql Server中添加该计算机用户的登录权限 exec sp_grantlogin LAPTOP-61GDB2Q7\TeacherWang -- 之后这个计算机用户也可以登录数据库了 3、添加数据库的登录用户和密码&#xff0…