Skip to content

[MSD-302][feat] milling patterns takes spot size input#3495

Draft
K4rishma wants to merge 1 commit into
delmic:masterfrom
K4rishma:spot-size-millling-patterns
Draft

[MSD-302][feat] milling patterns takes spot size input#3495
K4rishma wants to merge 1 commit into
delmic:masterfrom
K4rishma:spot-size-millling-patterns

Conversation

@K4rishma

Copy link
Copy Markdown
Contributor

The “hole size” parameter of the Essence preset (in XML) currently contains the diameter of the orifice that will be milled out by FIB. The milling boxes displayed in Odemis should circumscribe the beam path to account for so-called beam tails.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an explicit FIB beam spot_size (diameter) milling parameter and uses it to expand the displayed milling rectangle overlays so the on-screen boxes circumscribe the beam path (accounting for beam tails).

Changes:

  • Add spot_size to MillingSettings (serialization + YAML defaults) and expose it in the milling task UI.
  • Expand GUI milling rectangle overlays by spot_size in both width/height when drawing patterns.
  • Fix panel config handling to avoid KeyError when removing the label key.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/odemis/gui/cont/milling.py Pass spot_size into overlay generation and expand rectangle dimensions accordingly; wire UI updates to include the new parameter.
src/odemis/gui/comp/milling.py Add UI configuration for spot_size and make label removal safe via pop().
src/odemis/acq/milling/tasks.py Add spot_size VA to MillingSettings and include it in (de)serialization.
src/odemis/acq/milling/milling_tasks.yaml Add default spot_size values to the built-in task presets and update comments.

Comment thread src/odemis/gui/cont/milling.py Outdated
Comment on lines +100 to +105
@@ -101,12 +101,19 @@
ref_img: model.DataArray,
pattern: RectanglePatternParameters,
colour: str = "#FFFF00",
name: str = None) -> EditableShape:
"""Convert a rectangle pattern to a shape"""
rect = RectangleOverlay(cnvs=canvas, colour = colour, show_selection_points = False)
name: str = None,
spot_size: float = 0.0) -> EditableShape:
Updates milling time and availability of the mill button when there's an update on the patterns
"""

logging.warning(f"Pattern updated: {dat}")
Comment thread src/odemis/acq/milling/milling_tasks.yaml Outdated
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds spot_size as a milling parameter across the configuration, data model, UI, and overlay rendering paths. MillingSettings now stores and serializes spot_size with backward-compatible deserialization, and the default milling task YAML adds spot_size to each preset. The milling panel configuration adds a spot_size control and updates label handling. Overlay rendering now expands rectangle geometry using spot_size, subscribes pattern updates for the new control, and saves the project before redrawing on pattern changes.

Sequence Diagram(s)

sequenceDiagram
  participant MillingTaskPanel
  participant MillingController
  participant rectangle_pattern_to_shape
  participant ProjectState

  MillingTaskPanel->>MillingController: update spot_size control values
  MillingController->>rectangle_pattern_to_shape: render with spot_size=task.milling.spot_size.value
  rectangle_pattern_to_shape->>rectangle_pattern_to_shape: expand width and height by spot_size
  MillingController->>ProjectState: save_project(main)
  MillingController->>MillingController: redraw milling overlays
Loading

Possibly related PRs

  • delmic/odemis#3383: Touches src/odemis/gui/cont/milling.py’s rectangle_pattern_to_shape flow and coordinate handling, which overlaps with this PR’s overlay geometry changes.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: milling patterns now take spot size into account.
Description check ✅ Passed The description is clearly related to the PR and describes the spot-size/beam-tail adjustment.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.23.0)
src/odemis/gui/cont/milling.py

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.21][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist

src/odemis/gui/comp/milling.py

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.14][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist

src/odemis/acq/milling/tasks.py

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.25][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/odemis/gui/cont/milling.py (1)

523-523: ⚡ Quick win

Consider using logging.debug instead of logging.warning.

The _on_patterns handler is called on every parameter change (width, height, depth, spacing, current, align, mode, spot_size) due to VA subscriptions. Using logging.warning here could spam the logs with routine updates. Consider using logging.debug unless pattern updates indicate an actual warning condition.

♻️ Proposed change
-        logging.warning(f"Pattern updated: {dat}")
+        logging.debug(f"Pattern updated: {dat}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/odemis/gui/cont/milling.py` at line 523, Change the logging level in the
_on_patterns handler from logging.warning to logging.debug for the "Pattern
updated" message. This log statement is called frequently due to VA
subscriptions monitoring routine parameter changes (width, height, depth,
spacing, current, align, mode, spot_size), and using warning level causes
unnecessary log spam. Since these are routine updates and not actual warning
conditions, using debug level is more appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/odemis/acq/milling/tasks.py`:
- Around line 36-47: The __init__ method of the MillingSettings class is missing
a docstring. Add a reStructuredText style docstring to the __init__ method that
documents all parameters including current, voltage, field_of_view, mode,
channel, align, and spot_size. Each parameter should be documented with its
type, unit (where applicable), range/choices, and a brief description of what it
represents. Use the :param type name: description format for consistency with
project guidelines.

In `@src/odemis/gui/cont/milling.py`:
- Around line 104-105: The `name` parameter in the method signature has an
incorrect type hint. The parameter is declared as `str` but it has a default
value of `None` and can be `None` based on usage at line 117 and line 420.
Update the type hint for the `name` parameter to accept both string and None
values by changing it to `str | None` or using `Optional[str]` (if using older
Python typing style).
- Around line 107-109: Update the docstring for the function that converts a
rectangle pattern to a shape to follow reStructuredText format. Expand the
current single-line summary to include proper parameter documentation using
:param: directives for all parameters (such as canvas and colour), and add a
:return: directive describing what the function returns. Ensure the docstring
maintains the summary line about rectangle pattern conversion and beam spot
expansion while adding the required reStructuredText sections for complete
parameter and return value documentation.

---

Nitpick comments:
In `@src/odemis/gui/cont/milling.py`:
- Line 523: Change the logging level in the _on_patterns handler from
logging.warning to logging.debug for the "Pattern updated" message. This log
statement is called frequently due to VA subscriptions monitoring routine
parameter changes (width, height, depth, spacing, current, align, mode,
spot_size), and using warning level causes unnecessary log spam. Since these are
routine updates and not actual warning conditions, using debug level is more
appropriate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 240e9dcb-a6e1-43f7-bf87-554dcc3c53fd

📥 Commits

Reviewing files that changed from the base of the PR and between 1534638 and da12606.

📒 Files selected for processing (4)
  • src/odemis/acq/milling/milling_tasks.yaml
  • src/odemis/acq/milling/tasks.py
  • src/odemis/gui/comp/milling.py
  • src/odemis/gui/cont/milling.py

Comment on lines 36 to +47
class MillingSettings:
"""Represents milling settings for a single milling task"""

def __init__(self, current: float, voltage: float, field_of_view: float, mode: str = "Serial", channel: str = "ion", align: bool = True):
def __init__(self, current: float, voltage: float, field_of_view: float, mode: str = "Serial",
channel: str = "ion", align: bool = True, spot_size: float = 50.0e-09):
self.current = model.FloatContinuous(current, unit="A", range=(20e-12, 120e-9))
self.voltage = model.FloatContinuous(voltage, unit="V", range=(0, 30e3))
self.field_of_view = model.FloatContinuous(field_of_view, unit="m", range=(50e-06, 960e-06))
self.mode = model.StringEnumerated(mode, choices={"Serial", "Parallel"})
self.channel = model.StringEnumerated(channel, choices={"ion"})
self.align = model.BooleanVA(align) # align at the milling current
self.align = model.BooleanVA(align) # align at the milling current
self.spot_size = model.FloatContinuous(spot_size, unit="m", range=(5.0e-09, 1.0e-06)) # FIB beam spot size (diameter)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add docstring for MillingSettings class and __init__ method.

The MillingSettings class and its __init__ method lack docstrings. As per coding guidelines, all classes and functions should have docstrings following the reStructuredText style.

📝 Proposed docstring
 class MillingSettings:
-    """Represents milling settings for a single milling task"""
+    """
+    Represents milling settings for a single milling task.
+    
+    Encapsulates all parameters required for FIB milling operations,
+    including beam current, voltage, field of view, and spot size.
+    """

-    def __init__(self, current: float, voltage: float, field_of_view: float, mode: str = "Serial",
-                 channel: str = "ion", align: bool = True, spot_size: float = 50.0e-09):
+    def __init__(
+        self,
+        current: float,
+        voltage: float,
+        field_of_view: float,
+        mode: str = "Serial",
+        channel: str = "ion",
+        align: bool = True,
+        spot_size: float = 50.0e-09
+    ) -> None:
+        """
+        Initialize milling settings.
+        
+        :param current: Beam current in amperes
+        :param voltage: Beam voltage in volts
+        :param field_of_view: Field of view in meters
+        :param mode: Milling mode, either Serial or Parallel
+        :param channel: Channel to use for milling
+        :param align: Whether to align at the milling current
+        :param spot_size: FIB beam spot size diameter in meters
+        """
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/odemis/acq/milling/tasks.py` around lines 36 - 47, The __init__ method of
the MillingSettings class is missing a docstring. Add a reStructuredText style
docstring to the __init__ method that documents all parameters including
current, voltage, field_of_view, mode, channel, align, and spot_size. Each
parameter should be documented with its type, unit (where applicable),
range/choices, and a brief description of what it represents. Use the :param
type name: description format for consistency with project guidelines.

Source: Coding guidelines

Comment thread src/odemis/gui/cont/milling.py Outdated
Comment on lines +104 to +105
name: str = None,
spot_size: float = 0.0) -> EditableShape:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix type hint for name parameter.

The name parameter can be None (as checked on line 117 and passed as None on line 420), but the type hint is str. It should be str | None or Optional[str].

🔧 Proposed fix
 def rectangle_pattern_to_shape(canvas,
                         ref_img: model.DataArray,
                         pattern: RectanglePatternParameters,
                         colour: str = "`#FFFF00`",
-                        name: str = None,
+                        name: str | None = None,
                         spot_size: float = 0.0) -> EditableShape:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
name: str = None,
spot_size: float = 0.0) -> EditableShape:
def rectangle_pattern_to_shape(canvas,
ref_img: model.DataArray,
pattern: RectanglePatternParameters,
colour: str = "`#FFFF00`",
name: str | None = None,
spot_size: float = 0.0) -> EditableShape:
🧰 Tools
🪛 Ruff (0.15.17)

[warning] 104-104: PEP 484 prohibits implicit Optional

Convert to T | None

(RUF013)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/odemis/gui/cont/milling.py` around lines 104 - 105, The `name` parameter
in the method signature has an incorrect type hint. The parameter is declared as
`str` but it has a default value of `None` and can be `None` based on usage at
line 117 and line 420. Update the type hint for the `name` parameter to accept
both string and None values by changing it to `str | None` or using
`Optional[str]` (if using older Python typing style).

Source: Linters/SAST tools

Comment thread src/odemis/gui/cont/milling.py Outdated
Comment thread src/odemis/gui/cont/milling.py Outdated
Comment thread src/odemis/acq/milling/tasks.py Outdated
Comment thread src/odemis/acq/milling/tasks.py Outdated
Comment thread src/odemis/gui/comp/milling.py Outdated
Comment thread src/odemis/gui/cont/milling.py Outdated
Comment thread src/odemis/gui/cont/milling.py Outdated
@K4rishma K4rishma force-pushed the spot-size-millling-patterns branch from da12606 to 27bd2fb Compare June 25, 2026 14:10
@K4rishma K4rishma requested review from pieleric and tepals June 25, 2026 14:13
Comment thread src/odemis/gui/cont/milling.py
Comment thread src/odemis/gui/cont/milling.py
Comment thread src/odemis/gui/cont/milling.py Outdated
# milling params: current, voltage, field of view, mode
milling_parameters = ["current", "align", "mode"]
pattern_parameters = ["width", "height", "depth", "spacing"]
# milling params: current, voltage, field of view, mode, spot_size

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this comment here and how does it relate to the code? Does "voltage" correspond to "align" and "field of view" to "mode"?

@K4rishma K4rishma Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added the spot size to preciously mentioned parameters. I do not know if voltage affects alignment, fov the mode. But according to the comment, it might be the case.

I can see that the comment is confusing nonetheless, I have decided to remove it as it does not bring any insights.

@K4rishma K4rishma force-pushed the spot-size-millling-patterns branch from 27bd2fb to ce5decb Compare June 29, 2026 12:50

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
src/odemis/acq/milling/tasks.py (2)

49-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the serialization helpers.

to_dict() and from_dict() are part of the config contract, but both changed methods are still undocumented. As per coding guidelines, all functions should have docstrings. Based on learnings, keep them plain text only.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/odemis/acq/milling/tasks.py` around lines 49 - 66, Document the
serialization helpers in MillingSettings by adding plain-text docstrings to
to_dict() and from_dict(); these methods define the config contract, so briefly
describe that to_dict() serializes the current settings to a dictionary and
from_dict() reconstructs a MillingSettings instance from a dictionary, including
the default fallback values used for optional fields.

Sources: Coding guidelines, Learnings


39-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the missing return annotation on __init__.

This changed signature still violates the Python typing rule because __init__ has no explicit -> None.

Suggested fix
-    def __init__(self, current: float, voltage: float, field_of_view: float, mode: str = "Serial",
-                 channel: str = "ion", align: bool = True, spot_size: float = 5.0e-09):
+    def __init__(self, current: float, voltage: float, field_of_view: float, mode: str = "Serial",
+                 channel: str = "ion", align: bool = True, spot_size: float = 5.0e-09) -> None:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/odemis/acq/milling/tasks.py` around lines 39 - 40, The __init__ method in
the task class is missing an explicit return annotation and should be updated to
declare that it returns None. Add the missing `-> None` to the constructor
signature for the `__init__` method so the typing is correct and consistent with
Python conventions.

Source: Coding guidelines

src/odemis/gui/cont/milling.py (1)

106-115: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep this docstring in plain text.

This file already has a repo-specific preference against :param: / :return: markup in docstrings, so this should be rewritten as plain text while keeping the spot-size explanation. Based on learnings, docstrings in this file should use plain text only, not RST directives.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/odemis/gui/cont/milling.py` around lines 106 - 115, The docstring in the
rectangle-to-shape conversion routine should be rewritten from RST-style
parameter markup to plain text only. Update the docstring on the shape
conversion helper in milling.py so it keeps the spot-size explanation and the
description of the canvas, reference image, pattern, colour, and name, but
removes all :param: directives and any similar markup.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/odemis/acq/milling/tasks.py`:
- Around line 49-66: Document the serialization helpers in MillingSettings by
adding plain-text docstrings to to_dict() and from_dict(); these methods define
the config contract, so briefly describe that to_dict() serializes the current
settings to a dictionary and from_dict() reconstructs a MillingSettings instance
from a dictionary, including the default fallback values used for optional
fields.
- Around line 39-40: The __init__ method in the task class is missing an
explicit return annotation and should be updated to declare that it returns
None. Add the missing `-> None` to the constructor signature for the `__init__`
method so the typing is correct and consistent with Python conventions.

In `@src/odemis/gui/cont/milling.py`:
- Around line 106-115: The docstring in the rectangle-to-shape conversion
routine should be rewritten from RST-style parameter markup to plain text only.
Update the docstring on the shape conversion helper in milling.py so it keeps
the spot-size explanation and the description of the canvas, reference image,
pattern, colour, and name, but removes all :param: directives and any similar
markup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8c8dd351-0dc9-4725-ae6d-5a6af5176965

📥 Commits

Reviewing files that changed from the base of the PR and between da12606 and ce5decb.

📒 Files selected for processing (4)
  • src/odemis/acq/milling/milling_tasks.yaml
  • src/odemis/acq/milling/tasks.py
  • src/odemis/gui/comp/milling.py
  • src/odemis/gui/cont/milling.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/odemis/gui/comp/milling.py

@K4rishma K4rishma marked this pull request as draft July 1, 2026 11:44
@K4rishma

K4rishma commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Reason for converting to draft -
During the testing, it was determined that the spot size is current dependent. If the spot size is known per current, it should be written to a config which will then be used during milling.

  • spot size should not be shown in the GUI. Most users do not know the spot size. If the spot size is written in the config, milling will take spot size into account
  • Introducing the spot size should not change the displayed width of the milling patterns, the spot size is accounted such that the milling of specified dimensions is performed.
  • Implement a way to get the values of spot size per current
  • find a way to get the spot size per OEM

@pieleric

pieleric commented Jul 6, 2026

Copy link
Copy Markdown
Member

@K4rishma I agree with you that it should go back to the specification level. I've replied in the Jira task.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants