Python SDK
Models & Configuration
The SDK uses Python dataclasses for configuration and result objects. All configuration classes
provide a to_dict() method, and result classes provide a
from_dict(data) class method.
AcquisitionConfig
Configuration for an imaging.acquire call.
All fields are optional; device clients may ignore unsupported fields. Only non-None fields are sent in the request.
from semphony.models import AcquisitionConfig
config = AcquisitionConfig(
fov_um=100, # field of view in µm
resolution=(1024, 1024), # width, height in pixels
mode="SE", # detector mode (e.g. "SE", "BSE")
dwell_time_us=1.0, # dwell time per pixel in µs
working_distance_mm=10.5,
scan_speed_index=3,
detector_channel=0,
)
| Field | Type | Description |
|---|---|---|
| fov_um | float | None | Requested field of view in micrometres. Sets the SEM view field before scanning. |
| resolution | tuple[int, int] | None | Image resolution as (width, height) in pixels. On ZEISS Gemini this must exactly match a SmartSEM DP_IMAGE_STORE entry (e.g. 1024×768, 2048×1536, ...); otherwise acquisition is rejected. |
| mode | str | None | Detector mode, e.g. "SE" (secondary electron) or "BSE" (backscatter). |
| dwell_time_us | float | None | Pixel dwell time in microseconds. |
| working_distance_mm | float | None | Working distance in millimetres. Set before acquisition if provided. |
| scan_speed_index | int | None | Scan speed index (ScSetSpeed). Device-specific mapping. |
| grab_immediately | bool | ZEISS Gemini: when False (default), the device client freezes the live image, waits for a full-frame scan, then grabs. When True, grabs without that wait. Ignored on other SEMs. |
| freeze_wait_timeout_s | float | None | ZEISS Gemini only: maximum seconds to wait for the frozen state when grab_immediately is false (client default is 60). |
| detector_channel | int | None | Detector channel index. |
| detector_mode | str | None | Detector mode string (SE, BSE, etc.). |
| roi_name | str | None | ROI name stored in acquisition metadata (used by save_roi). |
| roi_level | str | None | ROI level ("roi", "l2", "l1", "l0") stored in acquisition metadata. |
AcquisitionResult
Returned by imaging.acquire(). Contains the correlation ID, artifact references,
and optional local path if the image was downloaded.
| Field | Type | Description |
|---|---|---|
| correlation_id | str | Unique ID for this acquisition in the control server. |
| image_id | str | None | Artifact ID for downloading the image via the API. |
| remote_path | str | None | Path to the image on the control server. |
| local_path | str | None | Local file path if downloaded with target_path. |
| mime | str | None | MIME type of the image (e.g. "image/tiff"). |
| size | tuple[int, int] | None | Image dimensions as (width, height) in pixels. |
| metadata | dict | Any additional fields from the server response. |
RoiSpec
Defines the finest ROI field of view, how many coarse pyramid levels to capture (n_levels → L0…Ln−1), and the widest FOV at L0.
Intermediate FOVs are spaced geometrically between roi_fov_um and the resolved L0 FOV. Pass l0_fov_um="max" (ZEISS) to use the SEM maximum view field from imaging.get_view_field_limits() at save_roi time.
from semphony.models import RoiSpec
spec = RoiSpec(
name="my_roi",
roi_fov_um=50,
n_levels=3, # coarse levels: L0, L1, L2 (+ ROI)
l0_fov_um=1500, # micrometres, or "max" on supported SEMs
)
| Field | Type | Description |
|---|---|---|
| name | str | Name identifier for the ROI. |
| roi_fov_um | float | Field of view for the finest ROI level (micrometres). |
| n_levels | int | Number of coarse pyramid levels (L0 widest … Ln−1 finest coarse step). |
| l0_fov_um | float | "max" | Widest (L0) horizontal FOV in µm, or "max" to resolve from the device at save time. |
FindRoiResult
Returned by imaging.find_roi(). Reports whether the ROI was found, the final stage pose,
and per-iteration diagnostics.
| Field | Type | Description |
|---|---|---|
| found | bool | Whether the ROI was successfully relocated. |
| final_pose | dict | None | Final stage position (x, y, optionally r, fov_um). |
| iterations | int | Total iterations performed across all levels. |
| level_history | list[dict] | Per-iteration diagnostics (confidence, residuals, etc.). |
| metrics | dict | Summary metrics from the find_roi orchestration. |
Guardrails
Guardrails enforce safety rules during a session. Pass an ImagingGuardrails
instance when creating a session; the SDK checks guardrails before each capability call and
raises SemphonyGuardrailException if a rule is violated.
from semphony import (
ImagingGuardrails,
ChamberBeamGuardrail,
StageAbsoluteLimits,
StageRelativeLimits,
)
guardrails = ImagingGuardrails(
chamber_beam=ChamberBeamGuardrail(
require_vacuum_for_beam=True,
require_beam_off_for_vent=True,
require_beam_on_for_scan=True,
),
stage_absolute=StageAbsoluteLimits(
x=(-50.0, 50.0),
y=(-50.0, 50.0),
),
stage_relative=StageRelativeLimits(
x_pct=200, # max 200% of FOV per move
y_pct=200,
r_max_deg=5,
),
)
session = run.session(guardrails=guardrails).start()
ChamberBeamGuardrail
Enforces chamber and beam safety. All fields default to True.
require_vacuum_for_beam— beam can only be enabled when vacuum is present.require_beam_off_for_vent— venting requires beam to be off.require_beam_on_for_scan— acquiring images requires beam to be on.
StageAbsoluteLimits
Sets hard min/max boundaries for stage axes. Each axis is a (min, max) tuple or None.
x,y,z— position limits in µm (Semphony canonical, same units asstage.get_pos()).r— rotation limit in degrees.t— tilt limit in degrees.
StageRelativeLimits
Limits the maximum movement per command. For x/y/z this is a percentage of the current FOV; for rotation and tilt it is a fixed maximum in degrees.
x_pct,y_pct,z_pct— max % of FOV per move.r_max_deg,t_max_deg— max degrees per move.
Error handling
The SDK raises SemphonyApiError when the control server cannot be reached,
returns a non-2xx status, or returns a non-JSON response (e.g. a login redirect). Acquisition failures
reported by the device (e.g. ScScanXY return value) are also wrapped in SemphonyApiError
with the device message.
SemphonyGuardrailException is raised when a guardrail rule is violated.
It includes a guardrail_type and details dict.
from semphony.client import SemphonyApiError
from semphony import SemphonyGuardrailException
try:
result = tescan.acquire(config)
except SemphonyApiError as e:
print(f"API failed: {e}")
except SemphonyGuardrailException as e:
print(f"Guardrail violated: {e}")
print(f"Type: {e.guardrail_type}, Details: {e.details}")