def test_progress_monitor(self): current_index = [] total_positions = 0 current_percentage = [] def progress(current_position, max_position): current_index.append(current_position) current_percentage.append(100 * (current_position / max_position)) nonlocal total_positions total_positions = max_position positions = [1, 2, 3, 4, 5] positioner = VectorPositioner(positions) writables = epics_pv("PYSCAN:TEST:MOTOR1:SET", "PYSCAN:TEST:MOTOR1:GET") readables = epics_pv("PYSCAN:TEST:OBS1") settings = scan_settings(progress_callback=progress) scan(positioner, readables, writables, settings=settings) self.assertEqual( len(positions) + 1, len(current_index), "The number of reported positions is wrong.") self.assertEqual(total_positions, 5, "The number of total positions is wrong.") self.assertEqual(current_index, [0, 1, 2, 3, 4, 5], "The reported percentage is wrong.") self.assertEqual(current_percentage, [0, 20, 40, 60, 80, 100], "The reported percentage is wrong.")
def test_actions(self): positions = [[1, 1], [2, 2]] positioner = VectorPositioner(positions) writables = [ epics_pv("PYSCAN:TEST:MOTOR1:SET", "PYSCAN:TEST:MOTOR1:GET"), epics_pv("PYSCAN:TEST:MOTOR2:SET", "PYSCAN:TEST:MOTOR2:GET") ] readables = [epics_pv("PYSCAN:TEST:OBS1")] # MOTOR1 initial values should be -11, MOTOR2 -22. cached_initial_values["PYSCAN:TEST:MOTOR1:SET"] = -11 cached_initial_values["PYSCAN:TEST:MOTOR2:SET"] = -22 initialization = [action_set_epics_pv("PYSCAN:TEST:OBS1", -33)] finalization = [action_restore(writables)] result = scan(positioner=positioner, readables=readables, writables=writables, initialization=initialization, finalization=finalization, settings=scan_settings(measurement_interval=0.25, n_measurements=1)) self.assertEqual(pv_cache["PYSCAN:TEST:MOTOR1:SET"][0].value, -11, "Finalization did not restore original value.") self.assertEqual(pv_cache["PYSCAN:TEST:MOTOR2:SET"][0].value, -22, "Finalization did not restore original value.") self.assertEqual(result[0][0], -33, "Initialization action did not work.")
def test_mixed_sources(self): config.bs_connection_mode = "pull" config.bs_default_host = "localhost" config.bs_default_port = 9999 positions = [[1, 1], [2, 2], [3, 3], [4, 4]] positioner = VectorPositioner(positions) writables = [ epics_pv("PYSCAN:TEST:MOTOR1:SET", "PYSCAN:TEST:MOTOR1:GET"), epics_pv("PYSCAN:TEST:MOTOR2:SET", "PYSCAN:TEST:MOTOR2:GET") ] readables = [ bs_property("CAMERA1:X"), bs_property("CAMERA1:Y"), epics_pv("PYSCAN:TEST:OBS1") ] conditions = [ epics_condition("PYSCAN:TEST:VALID1", 10), bs_condition("CAMERA1:VALID", 10) ] initialization = [ action_set_epics_pv("PYSCAN:TEST:PRE1:SET", 1, "PYSCAN:TEST:PRE1:GET") ] finalization = [ action_set_epics_pv("PYSCAN:TEST:PRE1:SET", 0, "PYSCAN:TEST:PRE1:GET"), action_restore(writables) ] result = scan(positioner=positioner, readables=readables, writables=writables, conditions=conditions, initialization=initialization, finalization=finalization, settings=scan_settings(measurement_interval=0.25, n_measurements=1)) self.assertEqual(len(result), len(positions), "Not the expected number of results.") # The first 2 attributes are from bs_read, they should be equal to the pulse ID processed. self.assertTrue(all(x[0] == x[1] and x[2] == 1 for x in result), "The result is wrong.")
def test_bsread_positioner_multi_measurements(self): with self.assertRaisesRegex( ValueError, "When using BsreadPositioner the maximum number of n_measurements = 1" ): scan(readables=[epics_pv("something")], positioner=BsreadPositioner(10), settings=scan_settings(n_measurements=2))
def test_time_scan(self): n_intervals = 10 time_interval = 0.1 positioner = TimePositioner(time_interval, n_intervals) readables = epics_pv("PYSCAN:TEST:OBS1") data_processor = SimpleDataProcessor() scan(positioner, readables, data_processor=data_processor) result = data_processor.get_data() self.assertEqual(len(result), n_intervals) acquisition_times = data_processor.get_positions() for index in range(n_intervals - 1): time_difference = acquisition_times[index + 1] - acquisition_times[index] self.assertTrue( abs(time_difference - time_interval) < max_time_tolerance, "The acquisition time difference is larger than the minimum tolerance." )
def test_convert_readables(self): config.bs_connection_mode = "pull" config.bs_default_host = "localhost" config.bs_default_port = 9999 positions = [[0, 10], [1, 11], [2, 12], [2, 13]] positioner = VectorPositioner(positions) readables = [ bs_property("CAMERA1:X"), "bs://CAMERA1:X", "BS://CAMERA1:X", epics_pv("PYSCAN:TEST:OBS1"), "PYSCAN:TEST:OBS1", "ca://PYSCAN:TEST:OBS1", "CA://PYSCAN:TEST:OBS1" ] writables = ["ca://PYSCAN:TEST:MOTOR1:SET", "PYSCAN:TEST:MOTOR2:SET"] def collect_positions(): actual_positions.append([ pv_cache["PYSCAN:TEST:MOTOR1:SET"][0].value, pv_cache["PYSCAN:TEST:MOTOR2:SET"][0].value ]) actual_positions = [] result = scan(positioner=positioner, readables=readables, writables=writables, after_read=collect_positions) for index in range(len(positions)): self.assertTrue( result[index][0] == result[index][1] == result[index][2], "Not all acquisitions are equal.") self.assertTrue( result[index][3] == result[index][4] == result[index][5], "Not all acquisitions are equal.") self.assertEqual(positions, actual_positions, "Does not work for writables.")
def action_set_epics_pv(pv_name, value, readback_pv_name=None, tolerance=None, timeout=None): """ Construct a tuple for set PV representation. :param pv_name: Name of the PV. :param value: Value to set the PV to. :param readback_pv_name: Name of the readback PV. :param tolerance: Tolerance if the PV is writable. :param timeout: Timeout for setting the pv value. :return: Tuple of (pv_name, pv_readback, tolerance) """ _, pv_name, readback_pv_name, tolerance, readback_pv_value = epics_pv(pv_name, readback_pv_name, tolerance) if value is None: raise ValueError("pv value not specified.") if not timeout or timeout < 0: timeout = config.epics_default_set_and_match_timeout def execute(): writer = EPICS_WRITER(pv_name, readback_pv_name, tolerance, timeout) writer.set_and_match(value) writer.close() return execute