From b414697cfbc2cd81a6930b167ca799c95b6ff691 Mon Sep 17 00:00:00 2001 From: Joe Knapper Date: Tue, 15 Apr 2025 16:29:29 +0100 Subject: [PATCH] Update testing for multiple sample shapes --- .../scan_planners.py | 123 ------------------ tests/test_scan_planners.py | 23 +++- tests/utilities/example_smart_spiral.pkl | Bin 13513 -> 0 bytes tests/utilities/example_smart_spiral_core.pkl | Bin 0 -> 4139 bytes .../utilities/example_smart_spiral_lobed.pkl | Bin 0 -> 8295 bytes .../example_smart_spiral_regular.pkl | Bin 0 -> 5877 bytes tests/utilities/scan_test_helpers.py | 57 +++++--- 7 files changed, 61 insertions(+), 142 deletions(-) delete mode 100644 tests/utilities/example_smart_spiral.pkl create mode 100644 tests/utilities/example_smart_spiral_core.pkl create mode 100644 tests/utilities/example_smart_spiral_lobed.pkl create mode 100644 tests/utilities/example_smart_spiral_regular.pkl diff --git a/src/openflexure_microscope_server/scan_planners.py b/src/openflexure_microscope_server/scan_planners.py index 35f5f00b..38a8d317 100644 --- a/src/openflexure_microscope_server/scan_planners.py +++ b/src/openflexure_microscope_server/scan_planners.py @@ -240,129 +240,6 @@ class ScanPlanner: class SmartSpiral(ScanPlanner): - """ - This is a smart spiral scan that spirals out from the centre. - - Each time and image is taken the four neighbouring images are added - to the list of poisitions to image (unless they are already listed or - tried). However if a location is not imaged due no sample being detected - then neibouring positions are not imaged. - - The next image taken is the closes to the centre (considering the largest - of vertical or horizontal distance), ties are broken by the distance from - the current position. - """ - - _max_dist: int = 0 - _dx: int = 0 - _dy: int = 0 - - def _parse(self, planner_settings: Optional[dict] = None) -> None: - """ - Parse SmartSpiral Settings. This should be a dictionary - - "dx" - the movement size in x - "dy" - the movement size in y - "max_dist" - The maximum distance to a location can be from the centre. - """ - - expected_keys = ["max_dist", "dx", "dy"] - invalid_msg = "SmartSpiral requires a planner_settings dictionary with keys: " - if not planner_settings: - raise ValueError(invalid_msg + ",".join(expected_keys)) - if not all(keys in planner_settings for keys in expected_keys): - raise KeyError(invalid_msg + ",".join(expected_keys)) - - self._dx = int(planner_settings["dx"]) - self._dy = int(planner_settings["dy"]) - self._max_dist = int(planner_settings["max_dist"]) - - def _intial_location_list(self) -> XYPosList: - """ - Called on initalisation. Sets the initial list of locations for this scan planner - - For smart spiral this is just the first point - """ - return [self._initial_position] - - def mark_location_visited( - self, xyz_pos: XYZPos, imaged: bool = True, focused: bool = True - ) -> None: - """ - Mark the location as visited. Adjust extra positions accordingly - - Args: - xyz_pos: the x_y_z position - imaged: true if an image was taken, false if not (due to background detect) - focused: true if autofocus completed successfully - """ - # First call the base class to update the positions - super().mark_location_visited(xyz_pos, imaged, focused) - - xy_pos = enforce_xy_tuple(xyz_pos[:2]) - if imaged: - self._add_surrounding_positions(xy_pos) - self._re_sort_remaining_locations(xy_pos) - - def _add_surrounding_positions(self, xy_pos: XYPos) -> None: - """ - This adds the surrounding (4 point connectivity) positions - to the remaining locations if they are not too far away or - already planned or already visited - """ - new_positions = [ - (xy_pos[0] - self._dx, xy_pos[1]), - (xy_pos[0] + self._dx, xy_pos[1]), - (xy_pos[0], xy_pos[1] - self._dy), - (xy_pos[0], xy_pos[1] + self._dy), - ] - - for new_pos in new_positions: - # Skip position if already planned or visited - if self.position_planned(new_pos) or self.position_visited(new_pos): - continue - - dist = distance_between(new_pos, self._initial_position) - if dist > self._max_dist: - LOGGER.debug("Rejected moving to %s as it is out of range", new_pos) - continue - self._remaining_locations.append(new_pos) - - def _re_sort_remaining_locations(self, current_pos: XYPos) -> None: - """ - Sort the remaining positions besed on the current location - """ - - # Defined rather than use a lambda for readability - def sort_key(pos): - return self.moves_from_centre(pos), distance_between(current_pos, pos) - - self._remaining_locations.sort(key=sort_key) - - def moves_from_centre( - self, - xy_pos: XYPos, - ) -> float: - """ - Return the number of moves from the centre in the x or y direction - whichever is largest - - Args: - xy_pos: the position - - Note this has been renamed from `steps_from_centre` as that implied - stepper motor steps not number of moves in a scan - """ - move_size = np.array([self._dx, self._dy]) - starting_pos = np.array(self._initial_position, dtype="float64") - current_pos = np.array(xy_pos, dtype="float64") - - displacement_in_moves = (current_pos - starting_pos) / move_size - - return np.max(np.abs(displacement_in_moves)) - - -class ShortSmartSpiral(ScanPlanner): """ This is a smart spiral scan that spirals out from the centre, but prioritises short moves over rigidly sticking to minimising radius from the centre of the diff --git a/tests/test_scan_planners.py b/tests/test_scan_planners.py index da5ff961..93750764 100644 --- a/tests/test_scan_planners.py +++ b/tests/test_scan_planners.py @@ -253,7 +253,22 @@ def test_closest_focus_wth_large_numbers(): def test_example_smart_spiral(): - _, planner = scan_test_helpers.example_smart_spiral() - expected_planner = scan_test_helpers.get_expected_result_for_example_smart_spiral() - assert planner.path_history == expected_planner.path_history - assert planner.imaged_locations == expected_planner.imaged_locations + """Test the smart spiral scan algorithm on the sample types listed + below and defined in scan_test_helpers.load_sample_points + + Will fail if the locations or path between locations visited has changed + for any of the samples listed""" + example_samples = [ + "regular", + "lobed", + "core", + ] + for sample_type in example_samples: + _, planner = scan_test_helpers.example_smart_spiral(sample=sample_type) + expected_planner = ( + scan_test_helpers.get_expected_result_for_example_smart_spiral( + sample=sample_type + ) + ) + assert planner.path_history == expected_planner.path_history + assert planner.imaged_locations == expected_planner.imaged_locations diff --git a/tests/utilities/example_smart_spiral.pkl b/tests/utilities/example_smart_spiral.pkl deleted file mode 100644 index 5d5727d87df59a640d40cb8366f60a0e22d91b1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13513 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 diff --git a/tests/utilities/example_smart_spiral_core.pkl b/tests/utilities/example_smart_spiral_core.pkl new file mode 100644 index 0000000000000000000000000000000000000000..ee598e73eecccadf0a81492f082dbece7809a3c5 GIT binary patch literal 4139 zcmZo*ovI+f00uqU`30$YX*sDCrA4XnxtYmD`Nhfk1*!4HsYPX}MS8`_iFxq_If;3B zsYS(8dbopg6N^fM3o?rmbEZt5qS-j5c8W%iV0>m?W=UpZPJBUrab`(oe%=&s25*M8 zDLu^bDHT(EH?V*hl~a5bn0q+ma}z7#Q!pTkH&+$1|$bD*9*jiS_WY|uz}nH zHp~~o_D$e~s_;$VglO|k;6yklffH_zuK*uRsQ@2TsQ@2BsQ@3cQm};}+d#&F90F!< zV1bK!Gr*Z(2O)SM)d=2)kN^Lp@!+8XmV^5o#DloY3&eyv7Q%-37QzO3w0(;20U@Xg z-vdGrZN3MD5Z*Z;gz(M*A-D@bY8pO6BFI;O&kN2@;6$)Du)x_~4sVg&59Yz$59Yz$ z58^=_0@eg|9fS>aKS&8UqS~kU7KlSt_!fvmwD}f@Bivsgj&Og0IKuq};&8Wt)F*s^ z`sIL-7o07?2WNXtc=7)~G_gR~kOU28L#zce;TA)9a4&+i!z~BPLER5wH}HVch1Y|} z|Nr|UvmtQ=5r_I6tOja1hz+$I#6(yQ=D{ro^FYZ7WQnhW4BS^BHazAOWZ(`2iNkb* z*s!?qRgi&L=c^zC3-t>M2;(j&AOiJ*0>Zcp3W!L!pa6HK?*#>@aTgSz#(5dsM@}bT z9?T^WIhb3(JcxEM6WIV*M1i!!!WqnlhAo)AfFBebUJbX9Ed=x67J_+j3qd@ng&-!( zLNFT|Ibb$4(!gw}g$#5k`DSO5Qq8VF`13By%`CE(^jc(8;7=D|W5Y#7wzU^dj_ zU^c|#UJ4ig|Mx{^L)C!Ap?bk=Xkdcb(3B2hLmdcWA{+?j!6GcRM<_lmKe@CRy}rue z%izxt$PmmB$`H;F$q>yD%Mj0y$dJsC%8<^G$&k&E%aG4d$WY8s%23Ww$xzKu%TUkI z$k5Et%Fxcx$$}r9_$uP|@%P`Nd$gs??%COF`$*|3^%dpRI$Z*VX z%5ctb$#BhZ%W%)|$nebY%J9zc$?(na%ka+#$Oy~`$_UN~$q3B|%Lvbi$cW5{%81U0 z$%xH}%ZSfN$Vkjc%1F*g$wh$;i#f%gE0t$SBMx$|%k#$tcYz z%P7yN$f(Sy%Baq$$*9e!%c#$2$Y{)H%4p7L$!N`J%V^K&$mq=I%IMDM$>`1K%jnOT zkTEf1QpV(rDH&5Ure#den2|9vV^(SpZ+t;wNk)7|W^qY=QRS4_Dd5_@4OX|eK`L-? zh(p<+Mg_RC@>O64sRL7x8odqF&H%}SYH(1_0Skar5J)AI0oDv-gVGZU8=?)GlG~<$ z8DJ|QEC)8IGkifTZw4?0vK_>QROD?_z_}hwK^+dNe?iFvEC$g6uE^V__=2i&Fa=Wz zt->K-F9gm@Dq1a=}s zEP)di2w)bdo#hK+fm$M9KZC3AwkhBW98AGH0Xv{7}zkdf59xUFTtz@{B2Vp z^*vY&RCR+R8zKhsIfMna9wZC49>joI4`xHH2eYBpgV|8)L2O@;RiL&TD0Cs=0c914 zgJYp>3aIXfhKzy?ECiwL1c)re9*{a{=!04aU@346gW3roH-i*F4TrWD+NStITMG~t z#E~E|sFBci0$3L0M_+Io0n7!*0!S&uNO1KJOMRfK9afrv*${Vu)qsovGr(?xut2VZ zu)wha(gI0yU=}EdAhHL9+NOY6&|pBc8``Eo*bsL^*icJB)jrr#5CdW_WXgSH#mrhvpC7W;zQ3}6AUrJ$Ar$V!j`XmmEH z!lKwf3zpEKEs3@%zR-3Agaz>zNDOK?s09I*0vir#27r?zsImup7sP-iM=%>=23RR9 zqQK%1&w$0jkqTjf0|g`xi3u|IRLuA2@1Brnh z2V%e+2WCSZ2WCUU6rv4ek?#XNkS5;;dQdGO7DNMx1yK%SL48ti2HGWUo8kp#L&6Nq f1{nlqK*9|q4e>OX1$H=?1@;V>1@d%iX_6iQH|ltB literal 0 HcmV?d00001 diff --git a/tests/utilities/example_smart_spiral_lobed.pkl b/tests/utilities/example_smart_spiral_lobed.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b64c0a6765f23f80d576e0969615161b168a90ab GIT binary patch literal 8295 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 MatPa return MatPath(path_points, closed=True) -def example_smart_spiral() -> tuple[FakeSample, scan_planners.ScanPlanner]: +def example_smart_spiral( + sample: str = "lobed", +) -> tuple[FakeSample, scan_planners.ScanPlanner]: """ Run an example scan and return the sample scanned and the planner object after scan is complete """ - xy_sample_points = [ - (-5000, -5000), - (-2000, 10000), - (1000, 2000), - (6000, 7000), - (9000, 2000), - ] + xy_sample_points = load_sample_points(sample=sample) sample = FakeSample(xy_sample_points) img_size = (1000, 1000) intial_position = (0, 0) - planner_settings = {"dx": 700, "dy": 700, "max_dist": 100000} - planner = scan_planners.ShortSmartSpiral( + planner_settings = {"dx": 1200, "dy": 800, "max_dist": 100000} + planner = scan_planners.SmartSpiral( intial_position=intial_position, planner_settings=planner_settings ) @@ -166,7 +162,7 @@ def profile_and_save_plot_for_example_smart_spiral(): run_stats.print_stats("scan_planners.py") -def update_example_smart_spiral_pickle(): +def update_example_smart_spiral_pickle(sample: str): """ Pickle the ScanPlanner for the example_smart_spiral(), this is done so the history can be compared by testing to check @@ -174,23 +170,54 @@ def update_example_smart_spiral_pickle(): If the algorithm is purposefully changed then this will need to be run to update the pickle for the test to pass. + + Takes sample, the sample type we have generated, so we can make a + pickle for each sample type """ - pkl_fname = os.path.join(THIS_DIR, "example_smart_spiral.pkl") + pkl_fname = os.path.join(THIS_DIR, f"example_smart_spiral_{sample}.pkl") with open(pkl_fname, "wb") as pkl_file_obj: - _, planner = example_smart_spiral() + _, planner = example_smart_spiral(sample=sample) pickle.dump(planner, pkl_file_obj, pickle.HIGHEST_PROTOCOL) -def get_expected_result_for_example_smart_spiral(): +def get_expected_result_for_example_smart_spiral(sample: str): """ Return the expected ScanPlanner object for the example_smart_spiral(), this is pickled, so that it can be committed. """ - pkl_fname = os.path.join(THIS_DIR, "example_smart_spiral.pkl") + pkl_fname = os.path.join(THIS_DIR, f"example_smart_spiral_{sample}.pkl") with open(pkl_fname, "rb") as pkl_file_obj: planner = pickle.load(pkl_file_obj) return planner +def load_sample_points(sample: str): + """Returns the points to generate a FakeSample of sample type "sample" """ + sample_options = { + "lobed": [ + (-5000, -5000), + (-2000, 16000), + (1000, 2000), + (6000, 7000), + (9000, 2000), + ], + "regular": [ + (-5000, -5000), + (-5000, 5000), + (5000, 5000), + (5000, -5000), + ], + "core": [ + (-12000, 2000), + (-12000, 1000), + (0, -2000), + (10000, -2000), + (10000, -1000), + (1000, 0), + ], + } + return sample_options[sample] + + if __name__ == "__main__": profile_and_save_plot_for_example_smart_spiral()