Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d168690
Fixed typo
rhfogh Jan 29, 2026
5126184
Removed &SEGMENT_LIST from instrumentation.nml
rhfogh Jan 30, 2026
42f09ce
Commented out exotic strategies
rhfogh Jan 30, 2026
8e3a23f
Fixes for kappa-limits, use-for-indexing
rhfogh Jan 30, 2026
70e5ccb
Bug fix in latest commit
rhfogh Jan 31, 2026
55492be
Changed "GΦL" to "GPhL" in all strings
rhfogh Feb 9, 2026
76101ea
Fix and clean-up after introduction of new AbstractDiffractometer.
rhfogh Feb 18, 2026
850650b
Changed move_omega_relative to omega.set_value_relative, and improved…
rhfogh Feb 26, 2026
8e061ef
Cleaned up (get_)head_type
rhfogh Feb 26, 2026
cc3a56d
Fiddling to satisfy ruff
rhfogh Feb 27, 2026
b640f02
Fixed ruff nits, and globally disactivated ICN001 ruff rule.
rhfogh Feb 27, 2026
9e2e901
Addiotional linting - import order, typos and types
rhfogh Feb 27, 2026
f1c3a7e
More ruff linting for import order
rhfogh Feb 27, 2026
3787281
WIP Working on MXExperiment generation
rhfogh Nov 5, 2024
078bed5
Finished create_mxexperiment function
rhfogh Nov 6, 2024
0ae4f4f
Bug fixes and WIP improving MXLIMS handling
rhfogh Nov 11, 2024
4cfbb86
Model bug fixes -> 0.2.4. Should now support phasing experiments (?)
rhfogh Nov 11, 2024
6ee4125
Minor model change -> 0.2.5. Now support GPhL characterisation and in…
rhfogh Nov 12, 2024
9fde73e
Added line indent to final MXLIMS JSON output
rhfogh Nov 12, 2024
d50b800
Added updated mxlims record export
rhfogh Jan 30, 2025
69f1a5f
Updated model,generation. amd use. WIP
rhfogh Mar 27, 2025
d1cb081
Documentation fix
rhfogh Mar 27, 2025
f3e8848
Fixed pydantic/html generation
rhfogh Mar 27, 2025
61d80f7
Debugged export of MXLIMS json data. Now works
rhfogh Mar 28, 2025
10b7c23
WIP trying to get MXCuBE impl and Pydantic to work
rhfogh May 10, 2025
76932bf
Added and tested MXLIMS export
rhfogh May 12, 2025
c3bf96f
Added mxlims loading test code
rhfogh May 13, 2025
de37f34
Linting clean-up
rhfogh May 15, 2025
1fdf6a9
Adapted to MXLIMS model changes
rhfogh Jun 11, 2025
a8365fa
Made mxcubecore/configuration/mockup.yaml and adapted mockups to use it
rhfogh Jun 4, 2025
52d921a
Updated mxcubeweb config for gphl
rhfogh Jun 4, 2025
5fe651e
Fixed yaml linting problems
rhfogh Jun 4, 2025
8c64425
Fixed yaml linting problems 2
rhfogh Jun 4, 2025
abce7bb
Adapted to MXLIMS 0.6.4 and tested
rhfogh Jun 12, 2025
ae75456
Ruff reformatting
rhfogh Jun 12, 2025
0d90f45
Satisfied Ruff
rhfogh Jun 12, 2025
05457db
Fixed bug in QtGraphicsMAnager.init
rhfogh Jun 13, 2025
f4e3147
Bug fix - removed debug printout
rhfogh Jun 13, 2025
94b9e4a
Updated to use new MXLIMS output code
rhfogh Jun 18, 2025
ef01f42
removed now-obsolete imports
rhfogh Jun 18, 2025
ef60800
Removed no-longer-used configuration directory
rhfogh Aug 21, 2025
2824565
Made MXLIMS export function again; Updated poetry.lock
rhfogh Aug 21, 2025
bddb005
Fixed som ruff complaints
rhfogh Aug 21, 2025
19cd487
linter nitpicking
rhfogh Nov 13, 2025
bac27ca
Bug fix in MXLIMS export
rhfogh Dec 22, 2025
b699152
Some fixes for GPhL - MXLIMS integration
rhfogh Jan 9, 2026
bb6d411
Updated to MXLIMS 0.6.10
rhfogh Jan 13, 2026
be5e37f
CHanged MXLIMS timestamp to UTC
rhfogh Mar 1, 2026
4f47e14
Import and code cleanup - renamed utils/mxlims to utils/mxutils
rhfogh Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/source/dev/json-schema-generated-user-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

We have a system for code-generated interfaces that can be plugged in to both a Qt and a Web user interface. It is implemented for Qt5, and (as of 20240213) just about ready for testing with the web interface.

The system is used to generate parameter queries from mxcubecore (for now from the GΦL workflow). It includes a wide range of widgets; multiple nested layout fields; support for custom update functions triggered when values are edited, that can reset values of other fields, change widget colouring and pulldown enums; field value validation; and colouring and disabling of action for invalid values. There are several examples of pulldown menu contents being modified depending on the values of other fields. The system is started with a `PARAMETERS_NEEDED` on signals being sent from the mxcubecore side with the JSON schemas as parameters. The UI side responds by sending a `PARAMETER_RETURN_SIGNAL` with the complete dictionary of parameter values. There is also a control parameter, that determines whether the response matches a Continue or Cancel click (closing the UI popup), or whether it is a request for a UI update. In the latter case the update is sent from the mxcubecore side with a `PARAMETER_UPDATE_SIGNAL`.
The system is used to generate parameter queries from mxcubecore (for now from the GPhL workflow). It includes a wide range of widgets; multiple nested layout fields; support for custom update functions triggered when values are edited, that can reset values of other fields, change widget colouring and pulldown enums; field value validation; and colouring and disabling of action for invalid values. There are several examples of pulldown menu contents being modified depending on the values of other fields. The system is started with a `PARAMETERS_NEEDED` on signals being sent from the mxcubecore side with the JSON schemas as parameters. The UI side responds by sending a `PARAMETER_RETURN_SIGNAL` with the complete dictionary of parameter values. There is also a control parameter, that determines whether the response matches a Continue or Cancel click (closing the UI popup), or whether it is a request for a UI update. In the latter case the update is sent from the mxcubecore side with a `PARAMETER_UPDATE_SIGNAL`.

The form of the JSON schemas used has been agreed between Rasmus Fogh, Jean-Baptiste Florial, and Marcus Oscarsson. Hopefully it fits with standard practices.

Expand Down
3 changes: 2 additions & 1 deletion mxcubecore/HardwareObjects/ALBA/ALBAMiniDiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ def use_sample_changer(self):
return True

# TODO:Implement dynamically
@property
def in_plate_mode(self):
"""
Overrides GenericDiffracometer method.
Expand Down Expand Up @@ -349,7 +350,7 @@ def prepare_centring(self):
# {"X": (x - self.zoom_centre['x'])/ self.pixels_per_mm_x,
# "Y": (y - self.zoom_centre['y'])/ self.pixels_per_mm_y})

# if self.in_plate_mode():
# if self.in_plate_mode:
# dynamic_limits = self.phi_motor_hwobj.get_dynamic_limits()
# if click == 0:
# self.phi_motor_hwobj.set_value(dynamic_limits[0])
Expand Down
3 changes: 2 additions & 1 deletion mxcubecore/HardwareObjects/ALBA/XalocMiniDiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def getBeamInfo(self, update_beam_callback):

update_beam_callback(data)

@property
def in_plate_mode(self):
return False

Expand All @@ -146,7 +147,7 @@ def manual_centring(self):
}
)

if self.in_plate_mode():
if self.in_plate_mode:
dynamic_limits = self.phi_motor_hwobj.get_dynamic_limits()
if click == 0:
self.phi_motor_hwobj.set_value(dynamic_limits[0])
Expand Down
2 changes: 1 addition & 1 deletion mxcubecore/HardwareObjects/Beamline.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ def get_default_acquisition_parameters(self, acquisition_type="default"):
acq_parameters.detector_binning_mode = ""

try:
acq_parameters.detector_roi_mode = self.detector.get_roi_mode()
acq_parameters.detector_roi_mode = self.detector.get_roi_mode_name()
except Exception:
self.log.warning(
"get_default_acquisition_parameters: "
Expand Down
2 changes: 1 addition & 1 deletion mxcubecore/HardwareObjects/DESY/P11Collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,5 +1264,5 @@ def take_crystal_snapshots(self):
self._take_crystal_snapshot(snapshot_filename)
time.sleep(1) # needed, otherwise will get the same images
if number_of_snapshots > 1:
HWR.beamline.diffractometer.move_omega_relative(90)
HWR.beamline.diffractometer.omega.set_value_relative(90)
time.sleep(1) # needed, otherwise will get the same images
2 changes: 1 addition & 1 deletion mxcubecore/HardwareObjects/DESY/P11NanoDiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def centring_done(self, centring_procedure, motor_p=None):
# if 3 click centring move -180. well. dont, in principle the calculated
# centred positions include omega to initial position
pass
# if not self.in_plate_mode():
# if not self.in_plate_mode:
# self.log.debug("Centring finished. Moving omega back to initial position")
# self.motor_hwobj_dict['phi'].set_value_relative(-180, timeout=None)
# self.log.debug(" Moving omega done")
Expand Down
2 changes: 1 addition & 1 deletion mxcubecore/HardwareObjects/EMBL/EMBLDoorInterlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def unlock_door_interlock(self):
"""
if HWR.beamline.diffractometer is not None:
detector_distance = HWR.beamline.detector.distance
if HWR.beamline.diffractometer.in_plate_mode():
if HWR.beamline.diffractometer.in_plate_mode:
if detector_distance is not None:
if detector_distance.get_value() < 780:
detector_distance.set_value(800, timeout=None)
Expand Down
8 changes: 4 additions & 4 deletions mxcubecore/HardwareObjects/EMBL/EMBLMiniDiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def use_sample_changer(self):

:return: bool
"""
return not self.in_plate_mode()
return not self.in_plate_mode

def beam_position_changed(self, value):
self.beam_position = value
Expand Down Expand Up @@ -301,7 +301,7 @@ def set_phase(self, phase, timeout=80):
"Diffractometer: Setting %s phase. Please wait..." % phase
)

if self.in_plate_mode() and (
if self.in_plate_mode and (
phase
in (GenericDiffractometer.PHASE_TRANSFER, GenericDiffractometer.PHASE_BEAM)
or self.current_phase
Expand Down Expand Up @@ -391,7 +391,7 @@ def manual_centring(self):
"Y": (y - self.beam_position[1]) / self.pixels_per_mm_y,
}
)
if self.in_plate_mode():
if self.in_plate_mode:
dynamic_limits = self.get_osc_limits()
if click == 0:
self.motor_hwobj_dict["phi"].set_value(dynamic_limits[0] + 0.5)
Expand Down Expand Up @@ -601,7 +601,7 @@ def convert_from_obj_to_name(self, motor_pos):
return motors

def visual_align(self, point_1, point_2):
if self.in_plate_mode():
if self.in_plate_mode:
self.log.info("EMBLMiniDiff: Visual align not available in Plate mode")
else:
t1 = [point_1.sampx, point_1.sampy, point_1.phiy]
Expand Down
12 changes: 2 additions & 10 deletions mxcubecore/HardwareObjects/GenericDiffractometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,6 @@ def __init__(self, name):
self.fast_shutter_is_open = None
self.centring_status = {"valid": False}
self.centring_time = 0
self.user_confirms_centring = None
self.user_clicked_event = None
self.automatic_centring_try_count = 1
self.omega_reference_par = None
Expand All @@ -327,7 +326,6 @@ def init(self):
# Internal values -----------------------------------------------------
self.ready_event = gevent.event.Event()
self.user_clicked_event = gevent.event.AsyncResult()
self.user_confirms_centring = True

self.beamstop = self.get_object_by_role("beamstop")
self.aperture = self.get_object_by_role("aperture")
Expand Down Expand Up @@ -682,20 +680,14 @@ def execute_server_task(self, method, timeout=30, *args):
self.wait_device_ready(timeout)
self.ready_event.set()

@property
def in_plate_mode(self):
"""Returns True if diffractometer in plate mod

:returns: boolean
"""
return self.head_type == GenericDiffractometer.HEAD_TYPE_PLATE

def get_head_type(self):
"""Returns head type

:returns: string
"""
return self.head_type

def use_sample_changer(self):
"""Returns True if sample changer is in use

Expand Down Expand Up @@ -1000,7 +992,7 @@ def centring_done(self, centring_procedure):
# if 3 click centring move -180. well. dont, in principle the calculated
# centred positions include omega to initial position
pass
# if not self.in_plate_mode():
# if not self.in_plate_mode:
# self.log.debug("Centring finished. Moving omega back to initial position")
# self.motor_hwobj_dict['phi'].set_value_relative(-180, timeout=None)
# self.log.debug(" Moving omega done")
Expand Down
6 changes: 3 additions & 3 deletions mxcubecore/HardwareObjects/Gphl/CollectEmulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,10 @@ def data_collection_hook(self):
data_collect_parameters = self.current_dc_parameters

if not HWR.beamline.gphl_workflow:
raise ValueError("Emulator requires GΦL workflow installation")
raise ValueError("Emulator requires GPhL workflow installation")
gphl_connection = HWR.beamline.gphl_connection
if not gphl_connection:
raise ValueError("Emulator requires GΦL connection installation")
raise ValueError("Emulator requires GPhL connection installation")

# Get program locations
simcal_executive = gphl_connection.get_executable("simcal")
Expand Down Expand Up @@ -326,7 +326,7 @@ def set_ulimit():
# NBNB TODO put in time-out, somehow
return_code = running_process.wait()
except Exception:
self.log.error("Error in GΦL collection emulation")
self.log.error("Error in GPhL collection emulation")
raise
finally:
fp1.close()
Expand Down
48 changes: 44 additions & 4 deletions mxcubecore/HardwareObjects/Gphl/GphlQueueEntry.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

from mxcubecore import HardwareRepository as HWR
from mxcubecore.queue_entry.base_queue_entry import BaseQueueEntry
from mxcubecore.utils import mxutils

__credits__ = ["MXCuBE collaboration"]
__license__ = "LGPLv3+"
Expand All @@ -35,7 +36,7 @@ class GphlWorkflowQueueEntry(BaseQueueEntry):
def execute(self):
BaseQueueEntry.execute(self)

msg = "Starting GΦL workflow (%s), please wait." % (
msg = "Starting GPhL workflow (%s), please wait." % (
self.get_data_model().strategy_name
)
logging.getLogger("user_level_log").info(msg)
Expand All @@ -45,20 +46,59 @@ def pre_execute(self):
BaseQueueEntry.pre_execute(self)
if not HWR.beamline.gphl_workflow.is_ready():
logging.getLogger("user_level_log").warning(
"WARNING: GΦL workflow was not ready - cleaning up"
"WARNING: GPhL workflow was not ready - cleaning up"
)
HWR.beamline.gphl_workflow.post_execute()
HWR.beamline.gphl_workflow.pre_execute(self)
logging.getLogger("HWR").debug("Done GphlWorkflowQueueEntry.pre_execute")

def post_execute(self):
self.finalize_mxlims()
BaseQueueEntry.post_execute(self)
msg = "Finishing GΦL workflow (%s)" % (self.get_data_model().strategy_name)
msg = "Finishing GPhL workflow (%s)" % (self.get_data_model().strategy_name)
logging.getLogger("user_level_log").info(msg)
HWR.beamline.gphl_workflow.post_execute()

def stop(self):
HWR.beamline.gphl_workflow.workflow_aborted("Dummy", "Dummy")
BaseQueueEntry.stop(self)
logging.getLogger("user_level_log").info("MXCuBE aborting current GΦL workflow")
logging.getLogger("user_level_log").info(
"MXCuBE aborting current GPhL workflow"
)
self.get_view().setText(1, "Stopped")

def init_mxlims(self):
"""Initialise MXLIMS MxExperimentMessage if it is not already set"""

if self.get_mxlims_job() is None:
data_model = self.get_data_model()
self._mxlims_job, mxlims_sample = mxutils.make_mx_experiment(
sample=data_model.get_sample_node(),
tracking_data=data_model.tracking_data,
measured_flux=HWR.beamline.flux.get_value(),
)
def finalize_mxlims(self):
"""Finalize MXLIMS MxExperimentMessage setting information at end of execution
"""
mx_experiment = self.get_mxlims_job()
if not mx_experiment:
# Only happens if there was an error upstream anyway
return
data_model = self.get_data_model()
workflow_name = data_model.workflow_name
if not mx_experiment.experiment_strategy:
mx_experiment.experiment_strategy = workflow_name
mx_experiment.radiation_dose = data_model.total_radiation_dose
mx_experiment.selected_space_group_name = data_model.space_group
cell_parameters = data_model.cell_parameters
if cell_parameters:
unit_cell = mxutils.make_unit_cell(*cell_parameters)
if unit_cell:
mx_experiment.selected_unit_cell = unit_cell
extensions = mx_experiment.extensions
if not extensions:
extensions = mx_experiment.extensions = {}
gphl_extensions = extensions.setdefault(data_model.GPHL_WORKFLOW_EXTENSION, {})
gphl_extensions.update(data_model.strategy_options)
gphl_extensions["experiment_strategy"] = workflow_name

Loading
Loading