Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[refactor] [METEOR-1186] CryoFeature Refactor #3012

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
e321c84
[feat] add new milling structs/functions
patrickcleeve2 Jan 22, 2025
b280e36
[refactor] migrate old mimas code to separate files
patrickcleeve2 Jan 22, 2025
0c8b6cf
[feat] minor gui/model changes for fibsem tab
patrickcleeve2 Jan 22, 2025
8b456cb
[fix] add new milling manager
patrickcleeve2 Jan 22, 2025
e7a7c20
[feat] add tfs3 posture manager for multi-posture imaging
patrickcleeve2 Jan 23, 2025
b7989a2
[fix] fix linter
patrickcleeve2 Jan 23, 2025
80e7b2b
[refactor] feature structures
patrickcleeve2 Jan 24, 2025
1e6e372
Merge branch 'meteor-960-multi-posture-imaging' into meteor-960-featu…
patrickcleeve2 Jan 24, 2025
be44574
Merge branch 'meteor-960-fibsem-gui-prep' into meteor-960-feature-ref…
patrickcleeve2 Jan 24, 2025
ef38aa4
Merge branch 'meteor-960-milling-struct' into meteor-960-feature-refa…
patrickcleeve2 Jan 24, 2025
67a383f
Merge branch 'meteor-960-licence-refactor' into meteor-960-feature-re…
patrickcleeve2 Jan 24, 2025
646d9ac
[fix] typos and broken imports
patrickcleeve2 Jan 24, 2025
3159f6a
Merge remote-tracking branch 'kk-origin/feature_icons_change' into me…
patrickcleeve2 Jan 24, 2025
03fe264
[fix] add ready to mill icon
patrickcleeve2 Jan 24, 2025
e642280
[fix] add gui fixes, fix tfs1
patrickcleeve2 Jan 24, 2025
ac8789e
[fix] fix lint
patrickcleeve2 Jan 24, 2025
50bf76e
[fix] test
patrickcleeve2 Jan 24, 2025
d1d1030
[fix] client fixes from hw testing
patrickcleeve2 Jan 29, 2025
885dac8
[feat] add new milling structures and functions
patrickcleeve2 Feb 3, 2025
55bae58
[refactor] add new milling manger
patrickcleeve2 Feb 3, 2025
3c672f4
Merge branch 'meteor-960-milling-struct' into meteor-960-feature-refa…
patrickcleeve2 Feb 4, 2025
9f85ecf
[fix] review comments
patrickcleeve2 Feb 4, 2025
26046c5
[fix] linter
patrickcleeve2 Feb 4, 2025
6430e78
Merge remote-tracking branch 'upstream/master' into meteor-960-featur…
patrickcleeve2 Feb 5, 2025
2913af9
rm
patrickcleeve2 Feb 5, 2025
95287aa
Merge branch 'meteor-960-fibsem-client-updates' into meteor-960-featu…
patrickcleeve2 Feb 9, 2025
47c1065
fix config
patrickcleeve2 Feb 9, 2025
39f312f
[fix] client fixes from hw testing
patrickcleeve2 Feb 14, 2025
deeb427
[feat] add tfs3 posture manager for multi-posture imaging
patrickcleeve2 Feb 14, 2025
4fdfd25
Merge branch 'meteor-960-fibsem-client-updates' into meteor-960-featu…
patrickcleeve2 Feb 14, 2025
e76da10
[feat] add new milling structures and functions
patrickcleeve2 Feb 18, 2025
526324f
[refactor] add new milling manger
patrickcleeve2 Feb 18, 2025
56c6f45
Merge remote-tracking branch 'upstream/master' into meteor-960-featur…
patrickcleeve2 Feb 18, 2025
de21004
1
patrickcleeve2 Feb 20, 2025
82a0b8a
Merge branch 'meteor-960-multi-posture-imaging' into meteor-960-featu…
patrickcleeve2 Feb 20, 2025
f844134
[feat] add tfs3 posture manager for multi-posture imaging
patrickcleeve2 Feb 20, 2025
e5fc288
[feat] minor gui/model changes for fibsem tab
patrickcleeve2 Feb 20, 2025
0b859aa
Merge branch 'meteor-960-fibsem-gui-prep' into meteor-960-feature-ref…
patrickcleeve2 Feb 21, 2025
0f2b539
Merge branch 'meteor-960-multi-posture-imaging' into meteor-960-featu…
patrickcleeve2 Feb 21, 2025
feffa7e
Merge branch 'meteor-960-milling-struct' into meteor-960-feature-refa…
patrickcleeve2 Feb 21, 2025
2e05e4f
fix test
patrickcleeve2 Feb 21, 2025
455cc5c
fix test
patrickcleeve2 Feb 21, 2025
903ee1c
fix
patrickcleeve2 Feb 21, 2025
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
7 changes: 7 additions & 0 deletions .github/workflows/unit_tests_cloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ jobs:
export PYTHONPATH="$PWD/src:$PYTHONPATH"
python3 -m unittest src/odemis/acq/test/feature_test.py --verbose

- name: Run tests from odemis.acq.milling
if: ${{ !cancelled() }}
run: |
export PYTHONPATH="$PWD/src:$PYTHONPATH"
python3 -m unittest src/odemis/acq/milling/test/patterns_test.py --verbose
python3 -m unittest src/odemis/acq/milling/test/tasks_test.py --verbose

- name: Run tests from odemis.acq.leech
if: ${{ !cancelled() }}
run: |
Expand Down
5 changes: 3 additions & 2 deletions install/linux/usr/share/odemis/sim/meteor-fibsem-sim.odm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ METEOR-FIBSEM-Sim: {
SAMPLE_CENTERS: {"GRID 1": {'x': 0, 'y': 0, 'z': 32.e-3}, "GRID 2": {'x': 5.0e-3, 'y': 0, 'z': 32.e-3}},
# Mirroring values between SEM - METEOR
POS_COR: [0.0253126, 0.0024916],
CALIB: {"version": "tfs_2",
"Sample pre-tilt": 0.6108652381980153}, # 35°
CALIB: {"version": "tfs_3",
"Sample pre-tilt": 0.6108652381980153, # 35°
"SEM-Eucentric-Focus": 7.0e-3}, # aqulios=7.0e-3, hydra=4.0e-3
FAV_FM_POS_ACTIVE: {"rx": 0.12213888553625313 , "rz": 3.141592653589793}, # 7° - 270°
FAV_SEM_POS_ACTIVE: {"rx": 0.6108652381980153, "rz": 0}, # pre-tilt 35°
FAV_MILL_POS_ACTIVE: {"rx": 0.314159, "rz": 0}, # Note that milling angle (rx) can be changed per session
Expand Down
7 changes: 3 additions & 4 deletions install/linux/usr/share/odemis/sim/meteor-tfs2-sim.odm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,11 @@
# Adjusted so that at init (0,0,0), it's at the Grid 1.
SAMPLE_CENTERS: {"GRID 1": {'x': 0, 'y': 0, 'z': 32.e-3}, "GRID 2": {'x': 2.98e-3, 'y': 2.46e-3, 'z': 32.e-3}},
# dx and dy are mirroring values between SEM - METEOR, pre-tilt is 35°
CALIB: {"dx": 0.0506252, "dy": 0.0049832, "version": "tfs_2", "pre-tilt": 0.6108652381980153},
CALIB: {"dx": 0.0506252, "dy": 0.0049832, "version": "tfs_2", "Sample pre-tilt": 0.6108652381980153},
# Active tilting (rx) & rotation(rz) angles positions when switching between SEM & FM.
# Note: these values are calibrated at installation time.
FAV_FM_POS_ACTIVE: {"rx": 0.12213888553625313 , "rz": 1.91986}, # 7° - 270°
# Typically rz = 110°, but we make it 0 so that at init it looks like in SEM position
FAV_SEM_POS_ACTIVE: {"rx": 0.314159, "rz": 5.06145}, # Note that milling angle (rx) can be changed per session
FAV_FM_POS_ACTIVE: {"rx": 0.12213888553625313 , "rz": 3.14159265358979}, # 7° - 180°
FAV_SEM_POS_ACTIVE: {"rx": 0.314159, "rz": 0.0}, # Note that milling angle (rx) can be changed per session
},
}

Expand Down
201 changes: 201 additions & 0 deletions install/linux/usr/share/odemis/sim/meteor-tfs3-sim.odm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# For now, this is esssentially just a FM microscope, as the FIB part is handled
# separately by the SEM

"METEOR TFSv3": {
class: Microscope,
role: meteor,
}

"SEM": {
class: simsem.SimSEM,
role: null,
init: {
image: "simsem-fake-output.h5", # any large 16 bit image is fine
},
children: {
scanner: "EBeam",
detector0: "SE Detector",
focus: "EBeam Focus",
}
}

"EBeam": {
# Internal child of SimSEM, so no class
role: e-beam, # Not required for the meteor
init: {},
affects: ["SE Detector"],
}

"EBeam Focus": {
# role: ebeam-focus,
role: null,
init: {},
affects: ["EBeam"]
}

"SE Detector": {
# Internal child of SimSEM, so no class
# role: se-detector,
role: null,
init: {},
}


# Normally provided by the SEM
"Stage": {
class: tmcm.TMCLController,
role: stage-bare,
init: {
port: "/dev/fake6",
address: null,
axes: ["x", "y", "z", "rx", "rz"],
ustepsize: [1.e-6, 1.e-6, 1.e-6, 1.2e-5, 1.2e-5], # unit/µstep
rng: [[-0.1, 0.1], [-0.05, 0.05], [-0.05, 0.1], [-2, 2], [0, 6.28]],
unit: ["m", "m", "m", "rad", "rad"],
refproc: "Standard",
},
metadata: {
# Loading position:
FAV_POS_DEACTIVE: { 'rx': 0, 'rz': 1.9076449, 'x': -0.01529, 'y': 0.0506, 'z': 29.e-3 },
# XYZ ranges for SEM & METEOR
SEM_IMAGING_RANGE: {"x": [-10.e-3, 10.e-3], "y": [-30.e-3, 25.e-3], "z": [15.e-3, 37.e-3]},
FM_IMAGING_RANGE: {"x": [0.040, 0.054], "y": [-30.e-3, 25.e-3], "z": [15.e-3, 37.e-3]},
# Grid centers in SEM range
# Adjusted so that at init (0,0,0), it's at the Grid 1.
SAMPLE_CENTERS: {"GRID 1": {'x': 0, 'y': 0, 'z': 32.e-3}, "GRID 2": {'x': 2.98e-3, 'y': 2.46e-3, 'z': 32.e-3}},
# dx and dy are mirroring values between SEM - METEOR, pre-tilt is 35°
CALIB: {
"version": "tfs_3",
"dx": 0.0506252, "dy": 0.0049832,
"Sample pre-tilt": 0.6108652381980153,
},
# Active tilting (rx) & rotation(rz) angles positions when switching between SEM & FM.
FAV_FM_POS_ACTIVE: {"rx": 0.29670597283903605 , "rz": 3.141592653589793}, # 17° - 180°
FAV_SEM_POS_ACTIVE: {"rx": 0.6108652381980153, "rz": 0}, # pre-tilt 35°, 0° rotation
FAV_MILL_POS_ACTIVE: {"rx": 0.314159, "rz": 0}, # Note that milling angle (rx) can be changed per session
},
}

"Light Source": {
class: omicronxx.HubxX,
role: light,
init: {
port: "/dev/fakehub", # Simulator
#port: "/dev/ttyFTDI*",
},
affects: ["Camera"],
}

"Optical Objective": {
class: static.OpticalLens,
role: lens,
init: {
mag: 84.0, # ratio, (actually of the complete light path)
na: 0.85, # ratio, numerical aperture
ri: 1.0, # ratio, refractive index
},
affects: ["Camera"]
}

# Normally a IDS uEye or Zyla
# Axes: X is horizontal on screen (going left->right), physical: far->close when looking at the door
# Y is vertical on screen (going bottom->top), physical: left->right when looking at the door
"Camera": {
class: simcam.Camera,
role: ccd,
dependencies: {focus: "Optical Focus"},
init: {
image: "andorcam2-fake-clara.tiff",
transp: [-1, 2], # To swap/invert axes
},
metadata: {
# To change what the "good" focus position is on the simulator
# It's needed for not using the initial value, which is at deactive position.
FAV_POS_ACTIVE: {'z': 1.7e-3}, # good focus position
ROTATION: -0.099484, # [rad] (=-5.7°)
},
}

# Controller for the filter-wheel
# DIP must be configured with address 7 (= 1110000)
"Optical Actuators": {
class: tmcm.TMCLController,
role: null,
init: {
port: "/dev/fake6", # Simulator
address: null, # Simulator
axes: ["fw"],
ustepsize: [1.227184e-3], # [rad/µstep] fake value for simulator
rng: [[-14, 7]], # rad, more than 0->2 Pi, in order to allow one extra rotation in both direction, when quickly switching
unit: ["rad"],
refproc: "Standard",
refswitch: {"fw": 0}, #digital output used to switch on/off sensor
inverted: ["fw"], # for the filter wheel, the direction doesn't matter, as long as the positions are correct
},
}

"AntiBacklash for Filter Wheel": {
class: actuator.AntiBacklashActuator,
role: null,
init: {
backlash: {
# Force every move to always finish in the same direction
"fw": 50.e-3, # rad
},
},
dependencies: {"slave": "Optical Actuators"},
}

"Filter Wheel": {
class: actuator.FixedPositionsActuator,
role: filter,
dependencies: {"band": "AntiBacklash for Filter Wheel"},
init: {
axis_name: "fw",
# This filter-wheel is made so that the light goes through two "holes":
# the filter, and the opposite hole (left empty). So although it has 8
# holes, it only supports 4 filters (from 0° to 135°), and there is no
# "fast-path" between the last filter and the first one.
positions: {
# pos (rad) -> m,m
0.08: [414.e-9, 450.e-9], # FF01-432/36
0.865398: [500.e-9, 530.e-9], # FF01-515/30
1.650796: [579.5e-9, 610.5e-9], # FF01-595/31
2.4361944: [663.e-9, 733.e-9], # FF02-698/70
},
cycle: 6.283185, # position of ref switch (0) after a full turn
},
# TODO: a way to indicate the best filter to use during alignement and brightfield? via some metadata?
affects: ["Camera"],
}

# CLS3252dsc-1
"Optical Focus": {
class: smaract.MCS2,
role: focus,
init: {
locator: "fake",
ref_on_init: True,
# TODO: check speed/accel
speed: 0.003, # m/s
accel: 0.003, # m/s²
#hold_time: 5 # s, default = infinite
# TODO: check the ranges, and the channel
axes: {
'z': {
# -11.5mm is safely parked (FAV_POS_DEACTIVE)
# 1.7mm is typically in focus (FAV_POS_ACTIVE)
range: [-15.e-3, 5.e-3],
unit: 'm',
channel: 0,
},
},
},
metadata: {
# Loading position to retract lens
FAV_POS_DEACTIVE: {'z': -11.5e-3},
# Initial active position (close from the sample, but not too close, for safety)
FAV_POS_ACTIVE: {'z': 1.69e-3}
},
affects: ["Camera"],
}
26 changes: 26 additions & 0 deletions src/odemis/acq/drift/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import numpy
import cv2

from odemis import model
from odemis.acq.align.shift import MeasureShift

MIN_RESOLUTION = (20, 20) # sometimes 8x8 works, but it's not reliable enough
Expand Down Expand Up @@ -347,3 +348,28 @@ def GuessAnchorRegion(whole_img, sample_region):
(occurrences[0, 1] + (dc_shape[1] / 2)) / whole_img.shape[1])

return anchor_roi

def align_reference_image(
ref_image: model.DataArray,
new_image: model.DataArray,
scanner: model.Emitter
) -> None:
"""Align the new image to the reference image using beam shift.
Only supports 2D images with the same resolution.
:param ref_image: The reference image to align with.
:param new_image: The new image to align to the reference.
:param scanner: The scanner to align with.
:return: None
"""
if (ref_image.ndim != 2 or new_image.ndim != 2 or ref_image.shape != new_image.shape):
raise ValueError(f"Only equally sized 2D images are supported for alignment. {ref_image.shape}, {new_image.shape}")

shift_px = MeasureShift(ref_image, new_image, 10)

pixelsize = ref_image.metadata[model.MD_PIXEL_SIZE]
shift_m = (shift_px[0] * pixelsize[0], shift_px[1] * pixelsize[1])

previous_shift = scanner.shift.value
shift = (shift_m[0] + previous_shift[0], shift_m[1] + previous_shift[1]) # m
scanner.shift.value = shift
logging.debug(f"reference image alignment: previous: {previous_shift}, calculated shift: {shift_m}, beam shift: {scanner.shift.value}")
Loading
Loading