mxcubecore 1.440.0__py3-none-any.whl → 1.449.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.
- mxcubecore/Command/BlueskyHttpServer.py +84 -0
- mxcubecore/CommandContainer.py +14 -0
- mxcubecore/HardwareObjects/Gphl/GphlQueueEntry.py +2 -2
- mxcubecore/HardwareObjects/ICATLIMS.py +16 -2
- mxcubecore/HardwareObjects/LNLS/BlueskyHttpServer.py +23 -0
- mxcubecore/HardwareObjects/LNLS/EPICS/EPICSMotor.py +40 -0
- mxcubecore/HardwareObjects/LNLS/LNLSDiffractometer.py +44 -297
- mxcubecore/HardwareObjects/MicrodiffInOut.py +12 -5
- mxcubecore/HardwareObjects/QtGraphicsManager.py +28 -21
- mxcubecore/HardwareObjects/abstract/AbstractMultiCollect.py +57 -83
- mxcubecore/HardwareObjects/abstract/AbstractNState.py +3 -1
- mxcubecore/HardwareObjects/abstract/AbstractVideoDevice.py +9 -4
- mxcubecore/HardwareObjects/abstract/ISPyBAbstractLims.py +8 -4
- mxcubecore/HardwareObjects/autoprocessing.py +2 -2
- mxcubecore/HardwareObjects/mockup/CollectMockup.py +11 -8
- mxcubecore/HardwareObjects/mockup/ISPyBRestClientMockup.py +10 -6
- mxcubecore/HardwareRepository.py +1 -1
- mxcubecore/protocols_config.py +7 -0
- mxcubecore/queue_entry/base_queue_entry.py +6 -5
- mxcubecore/utils/qt_import.py +0 -10
- {mxcubecore-1.440.0.dist-info → mxcubecore-1.449.0.dist-info}/METADATA +1 -1
- {mxcubecore-1.440.0.dist-info → mxcubecore-1.449.0.dist-info}/RECORD +25 -23
- {mxcubecore-1.440.0.dist-info → mxcubecore-1.449.0.dist-info}/WHEEL +0 -0
- {mxcubecore-1.440.0.dist-info → mxcubecore-1.449.0.dist-info}/licenses/COPYING +0 -0
- {mxcubecore-1.440.0.dist-info → mxcubecore-1.449.0.dist-info}/licenses/COPYING.LESSER +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Project name: MXCuBE
|
|
4
|
+
# https://github.com/mxcube
|
|
5
|
+
#
|
|
6
|
+
# This file is part of MXCuBE software.
|
|
7
|
+
#
|
|
8
|
+
# MXCuBE is free software: you can redistribute it and/or modify
|
|
9
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
|
10
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# MXCuBE is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU Lesser General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
19
|
+
# along with MXCuBE. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import time
|
|
24
|
+
|
|
25
|
+
import gevent
|
|
26
|
+
import requests
|
|
27
|
+
|
|
28
|
+
from mxcubecore.CommandContainer import CommandObject
|
|
29
|
+
|
|
30
|
+
__copyright__ = """ Copyright © 2010 - 2020 by MXCuBE Collaboration """
|
|
31
|
+
__license__ = "LGPLv3+"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BlueskyHttpServerCommand(CommandObject):
|
|
35
|
+
"""Interface for communicating with the Bluesky Http Server API."""
|
|
36
|
+
|
|
37
|
+
_default_timeout = 5
|
|
38
|
+
_status_path = "api/status"
|
|
39
|
+
_execute_path = "api/queue/item/execute"
|
|
40
|
+
|
|
41
|
+
def __init__(self, name, url, timeout=5, **kwargs):
|
|
42
|
+
CommandObject.__init__(self, name, **kwargs)
|
|
43
|
+
self.username = ""
|
|
44
|
+
self._default_timeout = timeout
|
|
45
|
+
self._url = f"{url}/" if url[-1] != "/" else url
|
|
46
|
+
self._headers = {"Authorization": f"ApiKey {os.environ['AUTH_KEY']}"}
|
|
47
|
+
|
|
48
|
+
def format_response(self, response):
|
|
49
|
+
if response:
|
|
50
|
+
response.raise_for_status()
|
|
51
|
+
return json.loads(response.text)
|
|
52
|
+
return response
|
|
53
|
+
|
|
54
|
+
def status(self):
|
|
55
|
+
response = requests.get(
|
|
56
|
+
self._url + self._status_path,
|
|
57
|
+
headers=self._headers,
|
|
58
|
+
timeout=self._default_timeout,
|
|
59
|
+
)
|
|
60
|
+
return self.format_response(response)
|
|
61
|
+
|
|
62
|
+
def monitor_manager_state(self, stop_state, timeout=86400):
|
|
63
|
+
with gevent.Timeout(timeout, exception=TimeoutError):
|
|
64
|
+
while self.status()["manager_state"] != stop_state:
|
|
65
|
+
time.sleep(0.1)
|
|
66
|
+
|
|
67
|
+
def execute_plan(self, plan_name, kwargs=None):
|
|
68
|
+
if not kwargs:
|
|
69
|
+
kwargs = {}
|
|
70
|
+
return requests.post(
|
|
71
|
+
self._url + self._execute_path,
|
|
72
|
+
headers=self._headers,
|
|
73
|
+
json={
|
|
74
|
+
"user": self.username,
|
|
75
|
+
"item": {"name": plan_name, "item_type": "plan", "kwargs": kwargs},
|
|
76
|
+
},
|
|
77
|
+
timeout=self._default_timeout,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def is_connected(self):
|
|
81
|
+
http_server_status = self.status()
|
|
82
|
+
re_environment_open = http_server_status["worker_environment_exists"]
|
|
83
|
+
re_running = http_server_status["re_state"] is not None
|
|
84
|
+
return re_environment_open and re_running
|
mxcubecore/CommandContainer.py
CHANGED
|
@@ -760,6 +760,20 @@ class CommandContainer:
|
|
|
760
760
|
cmd_name,
|
|
761
761
|
)
|
|
762
762
|
|
|
763
|
+
elif cmd_type.lower() == "bluesky_http_server":
|
|
764
|
+
try:
|
|
765
|
+
from mxcubecore.Command.BlueskyHttpServer import (
|
|
766
|
+
BlueskyHttpServerCommand,
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
new_command = BlueskyHttpServerCommand(cmd_name, cmd, **attributes_dict)
|
|
770
|
+
except Exception as exc:
|
|
771
|
+
logging.getLogger().exception(
|
|
772
|
+
"%s: cannot establish a connection with the Bluesky Http Server %s",
|
|
773
|
+
self.id,
|
|
774
|
+
cmd_name,
|
|
775
|
+
)
|
|
776
|
+
|
|
763
777
|
elif cmd_type.lower() == "sardana":
|
|
764
778
|
doorname = None
|
|
765
779
|
taurusname = None
|
|
@@ -49,7 +49,7 @@ class GphlWorkflowQueueEntry(BaseQueueEntry):
|
|
|
49
49
|
)
|
|
50
50
|
HWR.beamline.gphl_workflow.post_execute()
|
|
51
51
|
HWR.beamline.gphl_workflow.pre_execute(self)
|
|
52
|
-
|
|
52
|
+
logging.getLogger("HWR").debug("Done GphlWorkflowQueueEntry.pre_execute")
|
|
53
53
|
|
|
54
54
|
def post_execute(self):
|
|
55
55
|
BaseQueueEntry.post_execute(self)
|
|
@@ -60,5 +60,5 @@ class GphlWorkflowQueueEntry(BaseQueueEntry):
|
|
|
60
60
|
def stop(self):
|
|
61
61
|
HWR.beamline.gphl_workflow.workflow_aborted("Dummy", "Dummy")
|
|
62
62
|
BaseQueueEntry.stop(self)
|
|
63
|
-
|
|
63
|
+
logging.getLogger("user_level_log").info("MXCuBE aborting current GΦL workflow")
|
|
64
64
|
self.get_view().setText(1, "Stopped")
|
|
@@ -898,12 +898,22 @@ class ICATLIMS(AbstractLims):
|
|
|
898
898
|
if session is not None:
|
|
899
899
|
investigation_name = session.proposal_name
|
|
900
900
|
|
|
901
|
-
|
|
901
|
+
actual_instrument = None
|
|
902
|
+
try:
|
|
903
|
+
if (
|
|
904
|
+
self.active_session is None
|
|
905
|
+
or not self.active_session.is_scheduled_beamline
|
|
906
|
+
):
|
|
907
|
+
actual_instrument = HWR.beamline.session.beamline_name
|
|
908
|
+
except RuntimeError as e:
|
|
909
|
+
logger.warning("Failed to set __actualInstrument. %s", e)
|
|
910
|
+
|
|
911
|
+
result = {
|
|
902
912
|
"sampleId": sample_id,
|
|
903
913
|
"Sample_name": sample_name,
|
|
904
914
|
"startDate": start_time,
|
|
905
915
|
"endDate": end_time,
|
|
906
|
-
"
|
|
916
|
+
"investigationId": investigation_id,
|
|
907
917
|
"beamline_name": beamline_name,
|
|
908
918
|
"proposal": investigation_name,
|
|
909
919
|
"scheduled_beamline_name": scheduled_beamline_name,
|
|
@@ -920,6 +930,10 @@ class ICATLIMS(AbstractLims):
|
|
|
920
930
|
"InstrumentSource_current": machine_info.get("current"),
|
|
921
931
|
"InstrumentSource_mode": machine_info.get("fill_mode"),
|
|
922
932
|
}
|
|
933
|
+
if actual_instrument is not None:
|
|
934
|
+
result["__actualInstrument"] = actual_instrument
|
|
935
|
+
|
|
936
|
+
return result
|
|
923
937
|
|
|
924
938
|
def store_energy_scan(self, energyscan_dict: dict):
|
|
925
939
|
try:
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from mxcubecore.BaseHardwareObjects import HardwareObject
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BlueskyHttpServer(HardwareObject):
|
|
5
|
+
def __init__(self, name):
|
|
6
|
+
HardwareObject.__init__(self, name)
|
|
7
|
+
|
|
8
|
+
def init(self):
|
|
9
|
+
super().init()
|
|
10
|
+
self.api = self.get_command_object("bluesky_http_server")
|
|
11
|
+
self.api.username = "mnc-data"
|
|
12
|
+
|
|
13
|
+
def execute_plan(self, plan_name, kwargs=None):
|
|
14
|
+
response = self.api.execute_plan(plan_name=plan_name, kwargs=kwargs)
|
|
15
|
+
response_content = response.json()
|
|
16
|
+
if response_content["success"]:
|
|
17
|
+
try:
|
|
18
|
+
self.api.monitor_manager_state("running")
|
|
19
|
+
self.api.monitor_manager_state("idle")
|
|
20
|
+
except TimeoutError:
|
|
21
|
+
self.log.exception("The Bluesky plan has timed out!")
|
|
22
|
+
else:
|
|
23
|
+
self.log.exception(response_content["msg"])
|
|
@@ -97,3 +97,43 @@ class EPICSMotor(EPICSActuator, AbstractMotor):
|
|
|
97
97
|
def done_movement(self):
|
|
98
98
|
dmov = self.get_channel_value(self.MOTOR_DMOV)
|
|
99
99
|
return bool(dmov)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class EPICSMotorDetachable(EPICSMotor):
|
|
103
|
+
"""
|
|
104
|
+
Class that implements an interface of motor record IOC and accepts
|
|
105
|
+
a presence PV, that indicated if the motor is or is not present on the
|
|
106
|
+
facility. If it is present, it actuates as an EpicsMotor, if it is not,
|
|
107
|
+
then the widget receives the state OFF and remains disabled.
|
|
108
|
+
|
|
109
|
+
YAML Example
|
|
110
|
+
------------
|
|
111
|
+
|
|
112
|
+
%YAML 1.2
|
|
113
|
+
---
|
|
114
|
+
class: LNLS.EPICS.EPICSMotor.EPICSMotorDetachable
|
|
115
|
+
epics:
|
|
116
|
+
"MOTOR_PV":
|
|
117
|
+
channels:
|
|
118
|
+
'':
|
|
119
|
+
'PRESENCE_PREFIX':
|
|
120
|
+
channels:
|
|
121
|
+
'presence':
|
|
122
|
+
suffix: "PRESENCE_SUFFIX"
|
|
123
|
+
configuration:
|
|
124
|
+
is_absent_value: 0
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
MOTOR_PRESENCE_RBV = "presence"
|
|
129
|
+
|
|
130
|
+
def init(self):
|
|
131
|
+
super().init()
|
|
132
|
+
self.get_value()
|
|
133
|
+
|
|
134
|
+
def get_value(self):
|
|
135
|
+
value = self.get_property("is_absent_value")
|
|
136
|
+
current_value = int(self.get_channel_value(self.MOTOR_PRESENCE_RBV))
|
|
137
|
+
if current_value == value:
|
|
138
|
+
self.update_state(self.STATES.OFF)
|
|
139
|
+
return super().get_value()
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Project name: MXCuBE
|
|
3
|
-
# https://github.com/mxcube
|
|
4
|
-
#
|
|
5
|
-
# This file is part of MXCuBE software.
|
|
6
|
-
#
|
|
7
|
-
# MXCuBE is free software: you can redistribute it and/or modify
|
|
8
|
-
# it under the terms of the GNU Lesser General Public License as published by
|
|
9
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
10
|
-
# (at your option) any later version.
|
|
11
|
-
#
|
|
12
|
-
# MXCuBE is distributed in the hope that it will be useful,
|
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
-
# GNU Lesser General Public License for more details.
|
|
16
|
-
#
|
|
17
|
-
# You should have received a copy of the GNU Lesser General Public License
|
|
18
|
-
# along with MXCuBE. If not, see <http://www.gnu.org/licenses/>.
|
|
19
|
-
|
|
20
|
-
import logging
|
|
21
|
-
import random
|
|
22
1
|
import time
|
|
23
2
|
|
|
24
3
|
from gevent.event import AsyncResult
|
|
@@ -28,71 +7,33 @@ from mxcubecore.HardwareObjects.GenericDiffractometer import GenericDiffractomet
|
|
|
28
7
|
|
|
29
8
|
|
|
30
9
|
class LNLSDiffractometer(GenericDiffractometer):
|
|
31
|
-
"""
|
|
32
|
-
Descript. :
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
10
|
def __init__(self, name):
|
|
36
|
-
"""
|
|
37
|
-
Descript. :
|
|
38
|
-
"""
|
|
39
11
|
GenericDiffractometer.__init__(self, name)
|
|
40
12
|
|
|
41
|
-
# child object slots
|
|
42
|
-
self.backlight = None
|
|
43
|
-
self.backlightswitch = None
|
|
44
|
-
self.beamstop_distance = None
|
|
45
|
-
self.focus = None
|
|
46
|
-
self.frontlight = None
|
|
47
|
-
self.frontlightswitch = None
|
|
48
|
-
self.phi = None
|
|
49
|
-
self.phiy = None
|
|
50
|
-
self.phiz = None
|
|
51
|
-
self.sampx = None
|
|
52
|
-
self.sampy = None
|
|
53
|
-
|
|
54
13
|
def init(self):
|
|
55
|
-
"""
|
|
56
|
-
Descript. :
|
|
57
|
-
"""
|
|
58
|
-
# self.image_width = 100
|
|
59
|
-
# self.image_height = 100
|
|
60
|
-
|
|
61
14
|
GenericDiffractometer.init(self)
|
|
62
|
-
|
|
63
|
-
self.
|
|
64
|
-
self.
|
|
65
|
-
self.
|
|
66
|
-
|
|
67
|
-
self.pixels_per_mm_x = 1.0 / self.x_calib
|
|
68
|
-
self.pixels_per_mm_y = 1.0 / self.y_calib
|
|
69
|
-
self.beam_position = self.get_property("beam_position", "")
|
|
70
|
-
|
|
71
|
-
self.current_phase = GenericDiffractometer.PHASE_CENTRING
|
|
72
|
-
|
|
73
|
-
self.cancel_centring_methods = {}
|
|
15
|
+
self._bluesky_api = HWR.beamline.get_object_by_role("bluesky")
|
|
16
|
+
self.pixels_per_mm_x = 10**-4
|
|
17
|
+
self.pixels_per_mm_y = 10**-4
|
|
18
|
+
self.beam_position = [318, 238]
|
|
19
|
+
self.last_centred_position = self.beam_position
|
|
74
20
|
self.current_motor_positions = {
|
|
75
|
-
"phiy":
|
|
76
|
-
"sampx":
|
|
77
|
-
"sampy":
|
|
78
|
-
"zoom":
|
|
79
|
-
"focus":
|
|
80
|
-
"phiz":
|
|
81
|
-
"phi":
|
|
82
|
-
"kappa":
|
|
83
|
-
"kappa_phi":
|
|
21
|
+
"phiy": 0,
|
|
22
|
+
"sampx": 0,
|
|
23
|
+
"sampy": 0,
|
|
24
|
+
"zoom": 0,
|
|
25
|
+
"focus": 0,
|
|
26
|
+
"phiz": 0,
|
|
27
|
+
"phi": 0,
|
|
28
|
+
"kappa": 0,
|
|
29
|
+
"kappa_phi": 0,
|
|
84
30
|
}
|
|
85
31
|
|
|
86
|
-
self.
|
|
87
|
-
self.centring_status = {"valid": False}
|
|
88
|
-
self.centring_time = self.get_property("centring_time", "")
|
|
89
|
-
|
|
32
|
+
self.centring_time = 0
|
|
90
33
|
self.mount_mode = self.get_property("sample_mount_mode")
|
|
91
34
|
if self.mount_mode is None:
|
|
92
35
|
self.mount_mode = "manual"
|
|
93
36
|
|
|
94
|
-
self.equipment_ready()
|
|
95
|
-
|
|
96
37
|
self.connect(self.motor_hwobj_dict["phi"], "valueChanged", self.phi_motor_moved)
|
|
97
38
|
self.connect(
|
|
98
39
|
self.motor_hwobj_dict["phiy"], "valueChanged", self.phiy_motor_moved
|
|
@@ -115,108 +56,10 @@ class LNLSDiffractometer(GenericDiffractometer):
|
|
|
115
56
|
self.motor_hwobj_dict["sampy"], "valueChanged", self.sampy_motor_moved
|
|
116
57
|
)
|
|
117
58
|
|
|
118
|
-
def manual_centring(self):
|
|
119
|
-
"""
|
|
120
|
-
Descript. :
|
|
121
|
-
"""
|
|
122
|
-
self.print_log(level="debug", msg="Iniciando centragem manual...")
|
|
123
|
-
for click in range(3):
|
|
124
|
-
self.print_log(
|
|
125
|
-
level="debug", msg=f"Aguardando clique do usuário ({click + 1}/3)..."
|
|
126
|
-
)
|
|
127
|
-
self.user_clicked_event = AsyncResult()
|
|
128
|
-
x, y = self.user_clicked_event.get()
|
|
129
|
-
self.print_log(
|
|
130
|
-
level="debug", msg=f"Usuário clicou nas coordenadas: x={x}, y={y}"
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
# go to beam
|
|
134
|
-
self.print_log(
|
|
135
|
-
level="debug", msg="Movendo para o feixe com as coordenadas clicadas."
|
|
136
|
-
)
|
|
137
|
-
res = self.move_to_beam(x, y) # wait before continue
|
|
138
|
-
self.print_log(
|
|
139
|
-
level="debug", msg=f"Resultado do movimento para o feixe: {res}"
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
if click < 2:
|
|
143
|
-
self.print_log(
|
|
144
|
-
level="debug",
|
|
145
|
-
msg=f"Executando rotação relativa do motor phi em 90 graus (click={click})...",
|
|
146
|
-
)
|
|
147
|
-
self.motor_hwobj_dict["phi"].set_value_relative(90)
|
|
148
|
-
|
|
149
|
-
self.print_log(
|
|
150
|
-
level="debug", msg=f"Salvando última posição centrada: x={x}, y={y}"
|
|
151
|
-
)
|
|
152
|
-
self.last_centred_position[0] = x
|
|
153
|
-
self.last_centred_position[1] = y
|
|
154
|
-
|
|
155
|
-
self.print_log(level="debug", msg="Centragem manual finalizada.")
|
|
156
|
-
return {}
|
|
157
|
-
|
|
158
|
-
def automatic_centring(self):
|
|
159
|
-
"""Automatic centring procedure"""
|
|
160
|
-
self.print_log(level="debug", msg="Iniciando centragem automática...")
|
|
161
|
-
|
|
162
|
-
centred_pos_dir = self._get_random_centring_position()
|
|
163
|
-
self.print_log(
|
|
164
|
-
level="debug",
|
|
165
|
-
msg=f"Posição centrada gerada automaticamente: {centred_pos_dir}",
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
self.emit("newAutomaticCentringPoint", centred_pos_dir)
|
|
169
|
-
self.print_log(level="debug", msg="Sinal 'newAutomaticCentringPoint' emitido.")
|
|
170
|
-
|
|
171
|
-
return centred_pos_dir
|
|
172
|
-
|
|
173
|
-
def _get_random_centring_position(self):
|
|
174
|
-
"""Get random centring result for current positions"""
|
|
175
|
-
|
|
176
|
-
# Names of motors to vary during centring
|
|
177
|
-
vary_actuator_names = ("sampx", "sampy", "phiy")
|
|
178
|
-
|
|
179
|
-
# Range of random variation
|
|
180
|
-
var_range = 0.08
|
|
181
|
-
|
|
182
|
-
# absolute value limit for varied motors
|
|
183
|
-
var_limit = 2.0
|
|
184
|
-
|
|
185
|
-
result = self.current_motor_positions.copy()
|
|
186
|
-
for tag in vary_actuator_names:
|
|
187
|
-
val = result.get(tag)
|
|
188
|
-
if val is not None:
|
|
189
|
-
random_num = random.random()
|
|
190
|
-
var = (random_num - 0.5) * var_range
|
|
191
|
-
val += var
|
|
192
|
-
if abs(val) > var_limit:
|
|
193
|
-
val *= 1 - var_range / var_limit
|
|
194
|
-
result[tag] = val
|
|
195
|
-
return result
|
|
196
|
-
|
|
197
59
|
def is_ready(self) -> bool:
|
|
198
|
-
"""
|
|
199
|
-
Descript. :
|
|
200
|
-
"""
|
|
201
60
|
return True
|
|
202
61
|
|
|
203
|
-
def get_centred_point_from_coord(self, x, y, return_by_names=None):
|
|
204
|
-
"""
|
|
205
|
-
Descript. :
|
|
206
|
-
"""
|
|
207
|
-
centred_pos_dir = self._get_random_centring_position()
|
|
208
|
-
return centred_pos_dir
|
|
209
|
-
|
|
210
|
-
def motor_positions_to_screen(self, centred_positions_dict):
|
|
211
|
-
"""
|
|
212
|
-
Descript. :
|
|
213
|
-
"""
|
|
214
|
-
return self.last_centred_position[0], self.last_centred_position[1]
|
|
215
|
-
|
|
216
62
|
def phi_motor_moved(self, pos):
|
|
217
|
-
"""
|
|
218
|
-
Descript. :
|
|
219
|
-
"""
|
|
220
63
|
self.current_motor_positions["phi"] = pos
|
|
221
64
|
self.emit("phiMotorMoved", pos)
|
|
222
65
|
|
|
@@ -233,9 +76,6 @@ class LNLSDiffractometer(GenericDiffractometer):
|
|
|
233
76
|
self.current_motor_positions["sampy"] = pos
|
|
234
77
|
|
|
235
78
|
def kappa_motor_moved(self, pos):
|
|
236
|
-
"""
|
|
237
|
-
Descript. :
|
|
238
|
-
"""
|
|
239
79
|
self.current_motor_positions["kappa"] = pos
|
|
240
80
|
if time.time() - self.centring_time > 1.0:
|
|
241
81
|
self.invalidate_centring()
|
|
@@ -243,136 +83,43 @@ class LNLSDiffractometer(GenericDiffractometer):
|
|
|
243
83
|
self.emit("kappaMotorMoved", pos)
|
|
244
84
|
|
|
245
85
|
def kappa_phi_motor_moved(self, pos):
|
|
246
|
-
"""
|
|
247
|
-
Descript. :
|
|
248
|
-
"""
|
|
249
86
|
self.current_motor_positions["kappa_phi"] = pos
|
|
250
87
|
if time.time() - self.centring_time > 1.0:
|
|
251
88
|
self.invalidate_centring()
|
|
252
89
|
self.emit_diffractometer_moved()
|
|
253
90
|
self.emit("kappaPhiMotorMoved", pos)
|
|
254
91
|
|
|
255
|
-
def
|
|
256
|
-
""
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
# Armazena clique do usuário
|
|
270
|
-
self.last_centred_position[0] = x
|
|
271
|
-
self.last_centred_position[1] = y
|
|
272
|
-
self.print_log(
|
|
273
|
-
level="debug", msg=f"Última posição clicada pelo usuário: x={x}, y={y}"
|
|
274
|
-
)
|
|
275
|
-
|
|
276
|
-
# Obtém posições atuais dos motores
|
|
277
|
-
omega_pos = self.motor_hwobj_dict["phi"].get_value()
|
|
278
|
-
goniox_pos = self.motor_hwobj_dict["phiz"].get_value()
|
|
279
|
-
sampx_pos = self.motor_hwobj_dict["sampx"].get_value()
|
|
280
|
-
sampy_pos = self.motor_hwobj_dict["sampy"].get_value()
|
|
281
|
-
self.print_log(
|
|
282
|
-
level="debug",
|
|
283
|
-
msg=f"Posições atuais dos motores: omega={omega_pos}, phiz={goniox_pos}, sampx={sampx_pos}, sampy={sampy_pos}",
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
# Cálculo da movimentação de goniox
|
|
287
|
-
import math
|
|
288
|
-
|
|
289
|
-
drx_goniox = abs(-x - y + 1152) / math.sqrt(2)
|
|
290
|
-
dir_goniox = 1 if y <= (-x + 1152) else -1
|
|
291
|
-
move_goniox = dir_goniox * drx_goniox / self.pixels_per_mm_x + goniox_pos
|
|
292
|
-
self.print_log(
|
|
293
|
-
level="debug",
|
|
294
|
-
msg=f"Movimento calculado para phiz (goniox): {move_goniox:.4f}",
|
|
295
|
-
)
|
|
296
|
-
|
|
297
|
-
# Cálculo da movimentação em Y
|
|
298
|
-
dry_samp = abs(x - y - 128) / math.sqrt(2)
|
|
299
|
-
dir_samp = 1 if y >= x - 128 else -1
|
|
300
|
-
move_samp = dir_samp * dry_samp
|
|
301
|
-
self.print_log(
|
|
302
|
-
level="debug",
|
|
303
|
-
msg=f"Movimento intermediário para centragem vertical (samp): {move_samp:.4f}",
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
move_sampy = move_samp / self.pixels_per_mm_y
|
|
307
|
-
self.print_log(
|
|
308
|
-
level="debug", msg=f"Conversão para mm em Y: move_sampy = {move_sampy:.4f}"
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
move_sampy += sampy_pos
|
|
312
|
-
self.print_log(
|
|
313
|
-
level="debug", msg=f"Posição absoluta destino para sampy: {move_sampy:.4f}"
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
# Criação do dicionário de destino
|
|
317
|
-
centred_pos_dir = {"phiz": move_goniox, "sampy": move_sampy}
|
|
318
|
-
self.print_log(
|
|
319
|
-
level="debug",
|
|
320
|
-
msg=f"Posições alvo calculadas para centragem: {centred_pos_dir}",
|
|
321
|
-
)
|
|
92
|
+
def manual_centring(self):
|
|
93
|
+
self.log.info("Initializing manual sample alignment...")
|
|
94
|
+
for step in range(3):
|
|
95
|
+
self.log.info(f"Step {step + 1} of 3...")
|
|
96
|
+
self.user_clicked_event = AsyncResult()
|
|
97
|
+
self.waiting_for_click = True
|
|
98
|
+
x, y = self.user_clicked_event.get()
|
|
99
|
+
self.log.info(f"{x}, {y}")
|
|
100
|
+
self._bluesky_api.execute_plan(
|
|
101
|
+
plan_name="manual_alignment",
|
|
102
|
+
kwargs={"x_px": x, "y_px": y, "step": step},
|
|
103
|
+
)
|
|
104
|
+
self.log.info("Manual sample alignment has finished...")
|
|
105
|
+
return {}
|
|
322
106
|
|
|
323
|
-
|
|
107
|
+
def automatic_centring(self):
|
|
108
|
+
self.log.info("Initializing automatic sample alignment...")
|
|
109
|
+
self._bluesky_api.execute_plan(plan_name="automatic_alignment")
|
|
110
|
+
self.log.info("Automatic sample alignment has finished...")
|
|
324
111
|
|
|
325
112
|
def move_to_beam(self, x, y, omega=None):
|
|
326
|
-
""
|
|
327
|
-
Descript. : function to create a centring point based on all motors
|
|
328
|
-
positions.
|
|
329
|
-
"""
|
|
330
|
-
logging.getLogger("HWR").info("Moving to beam...")
|
|
331
|
-
self.print_log(
|
|
332
|
-
level="debug",
|
|
333
|
-
msg=f"Initializing beam centering with beam at x={x}, y={y}...",
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
centred_pos_dir = self.calculate_move_to_beam_pos(x, y)
|
|
337
|
-
|
|
338
|
-
self.print_log(level="debug", msg="Moving to beam...")
|
|
339
|
-
self.move_to_motors_positions(centred_pos_dir, wait=True)
|
|
340
|
-
|
|
341
|
-
logging.getLogger("HWR").info("Move to beam has finished...")
|
|
342
|
-
return centred_pos_dir
|
|
113
|
+
self.log.info("Moving to beam...")
|
|
343
114
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
self.centring_status = {
|
|
353
|
-
"valid": True,
|
|
354
|
-
"startTime": curr_time,
|
|
355
|
-
"endTime": curr_time,
|
|
356
|
-
}
|
|
357
|
-
motors = self.get_positions()
|
|
358
|
-
self.last_centred_position[0] = coord_x
|
|
359
|
-
self.last_centred_position[1] = coord_y
|
|
360
|
-
self.centring_status["motors"] = motors
|
|
361
|
-
self.centring_status["valid"] = True
|
|
362
|
-
self.centring_status["angleLimit"] = False
|
|
363
|
-
self.emit_progress_message("")
|
|
364
|
-
self.accept_centring()
|
|
365
|
-
self.current_centring_method = None
|
|
366
|
-
self.current_centring_procedure = None
|
|
367
|
-
|
|
368
|
-
def re_emit_values(self):
|
|
369
|
-
self.emit("zoomMotorPredefinedPositionChanged", None, None)
|
|
370
|
-
omega_ref = [0, 238]
|
|
371
|
-
self.emit("omegaReferenceChanged", omega_ref)
|
|
372
|
-
|
|
373
|
-
def move_omega_relative(self, relative_angle):
|
|
374
|
-
self.motor_hwobj_dict["phi"].set_value_relative(relative_angle, 5)
|
|
115
|
+
self._bluesky_api.execute_plan(
|
|
116
|
+
plan_name="move_to_beam",
|
|
117
|
+
kwargs={
|
|
118
|
+
"x_px": x - self.beam_position[0],
|
|
119
|
+
"y_px": y - self.beam_position[1],
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
self.log.info("Move to beam has finished...")
|
|
375
123
|
|
|
376
|
-
def
|
|
377
|
-
self.
|
|
378
|
-
self.emit("minidiffPhaseChanged", (self.current_phase,))
|
|
124
|
+
def motor_positions_to_screen(self, motor_positions):
|
|
125
|
+
return self.beam_position
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import time
|
|
3
|
+
import warnings
|
|
3
4
|
|
|
4
5
|
from mxcubecore.BaseHardwareObjects import HardwareObject
|
|
5
6
|
|
|
@@ -53,11 +54,17 @@ class MicrodiffInOut(HardwareObject):
|
|
|
53
54
|
import ast
|
|
54
55
|
|
|
55
56
|
self.states = ast.literal_eval(states)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
tt = self.get_property("timeout")
|
|
58
|
+
if tt is None:
|
|
59
|
+
warnings.warn(
|
|
60
|
+
"%s: %s is not configured" % (self.__class__.__name__, "timeout")
|
|
61
|
+
)
|
|
62
|
+
else:
|
|
63
|
+
try:
|
|
64
|
+
tt = float(tt)
|
|
65
|
+
except TypeError:
|
|
66
|
+
self.log.exception("")
|
|
67
|
+
self.timeout = tt
|
|
61
68
|
|
|
62
69
|
if self.get_property("use_hwstate"):
|
|
63
70
|
self.hwstate_attr = self.add_channel(
|