CI / lint (pull_request) Successful in 2m49s
CI / test (3.11) (pull_request) Successful in 1m26s
CI / test (3.13) (pull_request) Successful in 2m7s
CI / test (3.12) (pull_request) Successful in 2m38s
CI / lint (push) Canceled after 13s
CI / test (3.11) (push) Canceled after 0s
CI / test (3.12) (push) Canceled after 0s
CI / test (3.13) (push) Canceled after 0s
Build and Publish / release (push) Successful in 14s
69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
"""GridScanDecision wire contract: wraps the analysis result verbatim."""
|
|
|
|
import json
|
|
|
|
import numpy as np
|
|
|
|
from aarecommon.math.jfjoch_gridscan_union import Thresholds, analyse
|
|
from aarecommon.models.gridscan_decision import GridScanDecision
|
|
from aarecommon.models.raster_grid import RasterPayloadModel
|
|
|
|
|
|
def _synthetic_scan(ny_n=20, nx_n=20):
|
|
"""A gaussian protein blob on a flat loop, as plain dicts (jfjoch-free)."""
|
|
rng = np.random.default_rng(0)
|
|
yy, xx = np.mgrid[0:ny_n, 0:nx_n]
|
|
blob = 80 * np.exp(-(((xx - 7) ** 2 + (yy - 12) ** 2) / 8.0))
|
|
images = [
|
|
{
|
|
"number": int(y * nx_n + x),
|
|
"nx": int(x),
|
|
"ny": int(y),
|
|
"spots": int(blob[y, x] + 10 + rng.integers(0, 3)),
|
|
"spots_low_res": int(4 + rng.integers(0, 2)),
|
|
"spots_ice": 0,
|
|
"bkg": float(30 + 40 * np.exp(-(((x - 9) ** 2 + (y - 10) ** 2) / 90.0))),
|
|
"res": 2.0,
|
|
}
|
|
for y in range(ny_n)
|
|
for x in range(nx_n)
|
|
]
|
|
return {"file_prefix": "decision-test", "images": images}
|
|
|
|
|
|
def test_decision_round_trips_without_pictures(request):
|
|
th = Thresholds.model_validate({})
|
|
r = analyse(_synthetic_scan(), {"step_x_um": 10.0, "step_y_um": 10.0}, thresholds=th)
|
|
assert r.found
|
|
assert r.contour_cells, "the chosen 50 % blob must ship its cells"
|
|
assert all(0 <= x < r.n_fast and 0 <= y < r.n_slow for x, y in r.contour_cells)
|
|
# the centre lies within the contour's bounding box
|
|
assert r.centre is not None
|
|
xs = [x for x, _ in r.contour_cells]
|
|
ys = [y for _, y in r.contour_cells]
|
|
assert min(xs) - 1 <= r.centre.nx <= max(xs) + 1
|
|
assert min(ys) - 1 <= r.centre.ny <= max(ys) + 1
|
|
|
|
d = GridScanDecision(
|
|
algorithm="jfjoch_gridscan_union",
|
|
algorithm_version="test",
|
|
thresholds=th.model_dump(),
|
|
result=r,
|
|
)
|
|
wire = json.loads(d.model_dump_json())
|
|
assert wire["contract"] == 1
|
|
assert "jpeg" not in wire["result"], "pictures never ride the JSON"
|
|
assert wire["result"]["centre"]["image_number"] == r.centre.image_number
|
|
assert wire["thresholds"]["object_union_spots"] is True
|
|
back = GridScanDecision.model_validate(wire)
|
|
assert back.result.centre is not None
|
|
assert back.result.contour_cells is not None
|
|
assert back.result.centre.nx == r.centre.nx
|
|
assert [tuple(c) for c in back.result.contour_cells] == r.contour_cells
|
|
|
|
|
|
def test_payload_decision_is_optional():
|
|
fields = RasterPayloadModel.model_fields
|
|
assert "decision" in fields
|
|
assert fields["decision"].default is None
|