def test_run(self): self.o.registrar = MagicMock() # This would have been done by configure self.o.is_hardware_triggered = False self.o.on_run(self.context) assert self.child.handled_requests.mock_calls == [ call.post("start"), call.when_value_matches("acquiring", True, None), call.when_value_matches("arrayCounterReadback", 0, None), ] assert self.o.registrar.report.call_count == 2 assert self.o.registrar.report.call_args[0][0].steps == 0
def test_configure_from_armed_but_not_continuous_state(self): # Set the attributes to appear already armed in wrong image mode self.set_attributes(self.child, acquiring=True, imageMode="Single") self._do_configure() assert self.child.handled_requests.mock_calls == [ call.post("stop"), call.when_value_matches("acquiring", False, None), call.put("imageMode", "Continuous"), call.post("start"), call.when_value_matches("acquiring", True, None), ]
def test_move(self): self.mock_when_value_matches(self.child) # Move time is converted into milliseconds move_time = 2.3 expected_move_time = move_time * 1000.0 self.b.moveCS1(a=32, c=19.1, moveTime=move_time) assert self.child.handled_requests.mock_calls == [ call.put("deferMoves", True), call.put("csMoveTime", expected_move_time), call.put("demandA", 32), call.put("demandC", 19.1), call.when_value_matches("demandA", 32, None), call.when_value_matches("demandC", 19.1, None), call.put("deferMoves", False), ]
def test_configure_with_hardware_trigger_and_breakpoints(self): xs = LineGenerator("x", "mm", 0.0, 0.5, 20, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 3) generator = CompoundGenerator([ys, xs], [], [], 0.1) generator.prepare() completed_steps = 0 steps_to_do = 15 info = ExposureDeadtimeInfo(0.01, 1000, 0.0) part_info = dict(anyname=[info]) self.set_attributes(self.child, triggerMode="Hardware") self.o.on_configure( self.context, completed_steps, steps_to_do, part_info, generator, fileDir="/tmp", breakpoints=[15, 35, 10], exposure=info.calculate_exposure(generator.duration), ) assert self.child.handled_requests.mock_calls == [ call.put("arrayCallbacks", True), call.put("arrayCounter", 0), call.put("exposure", 0.1 - 0.01 - 0.0001), call.put("imageMode", "Multiple"), call.put("numImages", 15), call.put("acquirePeriod", 0.1 - 0.0001), call.post("start"), call.when_value_matches("acquiring", True, None), ] assert self.o.is_hardware_triggered
def test_configure(self): tmp_dir = mkdtemp() + os.path.sep vds_file = "odin2" start_time = datetime.now() self.o.on_configure( self.context, self.completed_steps, self.steps_to_do, generator=self.generator, fileDir=tmp_dir, formatName=vds_file, ) assert self.child.handled_requests.mock_calls == [ call.put("fileName", "odin2_raw_data"), call.put("filePath", tmp_dir), call.put("numCapture", self.steps_to_do), call.post("start"), call.when_value_matches("numCaptured", greater_than_zero, None), ] print(self.child.handled_requests.mock_calls) print("OdinWriter configure {} points took {} secs".format( self.steps_to_do, datetime.now() - start_time)) rmtree(tmp_dir)
def test_configure_with_hardware_start_trigger_succeeds(self): xs = LineGenerator("x", "mm", 0.0, 0.5, 3, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 2) generator = CompoundGenerator([ys, xs], [], [], 0.1) generator.prepare() completed_steps = 0 steps_to_do = 6 # We are not gated self.o.gated_trigger = False # We want to be armed and in a hardware trigger mode self.set_attributes(self.child, acquiring=True, triggerMode="Rising Edge") self.o.on_configure(self.context, completed_steps, steps_to_do, {}, generator, fileDir="/tmp") assert self.child.handled_requests.mock_calls == [ call.put("arrayCallbacks", True), call.put("arrayCounter", 0), call.put("imageMode", "Multiple"), call.put("numImages", 6), call.put("postCount", 999), call.post("start"), call.when_value_matches("acquiring", True, None), ]
def test_execute_profile(self): self.mock_when_value_matches(self.child) self.b.executeProfile() assert self.child.handled_requests.mock_calls == [ call.post("executeProfile"), call.when_value_matches("pointsScanned", 0, None), ]
def test_post_run_armed_with_hardware_trigger_and_breakpoints(self): xs = LineGenerator("x", "mm", 0.0, 0.5, 100, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 5) generator = CompoundGenerator([ys, xs], [], [], 0.1) generator.prepare() info = ExposureDeadtimeInfo(0.01, 1000, 0.0) part_info = dict(anyname=[info]) breakpoints = [100, 400] # This would have been done by initial configure self.o.is_hardware_triggered = True self.o.done_when_reaches = 100 self.o.on_post_run_armed(self.context, 100, 400, part_info, generator, breakpoints) assert self.child.handled_requests.mock_calls == [ call.put("arrayCallbacks", True), call.put("arrayCounter", 100), call.put("imageMode", "Multiple"), call.put("numImages", 400), call.put("acquirePeriod", 0.1 - 0.0001), call.post("start"), call.when_value_matches("acquiring", True, None), ] assert self.o.done_when_reaches == 500
def test_configure_from_disarmed_state(self): self._do_configure() assert self.child.handled_requests.mock_calls == [ call.put("imageMode", "Continuous"), call.post("start"), call.when_value_matches("acquiring", True, None), ]
def test_configure(self): completed_steps = 0 steps_to_do = 456 part_info = {"sth": [FilePathTranslatorInfo("Z", "/tmp", "")]} self.o.post_configure = MagicMock() # We wait to be armed, so set this here self.set_attributes(self.child, acquiring=True) extra_attributes = ExtraAttributesTable( name=["test1", "test2", "test3"], sourceId=["PV1", "PV2", "PARAM1"], sourceType=[SourceType.PV, SourceType.PV, SourceType.PARAM], description=[ "a test pv", "another test PV", "a param, for testing" ], dataType=[DataType.INT, DataType.STRING, DataType.STRING], datasetType=[ AttributeDatasetType.MONITOR, AttributeDatasetType.DETECTOR, AttributeDatasetType.POSITION, ], ) self.o.extra_attributes.set_value(extra_attributes) self.o.on_configure( self.context, completed_steps, steps_to_do, part_info, generator=MagicMock(duration=1.0), fileDir="/tmp", ) assert self.child.handled_requests.mock_calls == [ call.put("arrayCallbacks", True), call.put("arrayCounter", completed_steps), call.put("autoPixelsPerBuffer", "Manual"), call.put("binsInSpectrum", 2048), call.put("collectMode", "MCA mapping"), call.put("ignoreGate", "No"), call.put("inputLogicPolarity", "Normal"), call.put("pixelAdvanceMode", "Gate"), call.put("pixelsPerBuffer", 1), call.put("pixelsPerRun", steps_to_do), call.put("presetMode", "No preset"), call.post("start"), call.when_value_matches("acquiring", True, None), call.put("attributesFile", "Z:\\mri-attributes.xml"), ] with open("/tmp/mri-attributes.xml") as f: actual_xml = f.read().replace(">", ">\n") actual_tree = ElementTree.XML(actual_xml) expected_tree = ElementTree.XML(expected_xml) assert ElementTree.dump(actual_tree) == ElementTree.dump(expected_tree)
def test_nested_hardware_triggered_configure(self): self.set_attributes(self.child, triggerMode="External") self.configure() # When hardware triggered we set numImages to the total frames and call start assert self.child.handled_requests.mock_calls == [ call.put("arrayCallbacks", True), call.put("arrayCounter", 0), call.put("exposure", 0.1 - 0.01 - 0.0001), call.put("imageMode", "Multiple"), call.put("numImages", 50), call.put("acquirePeriod", 0.1 - 0.0001), call.post("start"), call.when_value_matches("acquiring", True, None), ]
def test_seek(self): self.mock_when_value_matches(self.child) self.o = HDFWriterPart(name="m", mri="BLOCK:HDF5") self.context.set_notify_dispatch_request( self.o.notify_dispatch_request) self.o.done_when_reaches = 10 completed_steps = 4 steps_to_do = 3 self.o.on_seek(self.context, completed_steps, steps_to_do) assert self.child.handled_requests.mock_calls == [ call.put("arrayCounter", 0), call.when_value_matches("arrayCounterReadback", greater_than_zero, None), ] assert self.o.done_when_reaches == 13
def test_run(self): self.o = HDFWriterPart(name="m", mri="BLOCK:HDF5") self.context.set_notify_dispatch_request( self.o.notify_dispatch_request) self.o.done_when_reaches = 38 self.o.completed_offset = 0 # Say that we're getting the first frame self.o.array_future = Future(None) self.o.array_future.set_result(None) self.o.registrar = MagicMock() # run waits for this value, so say we have finished immediately self.set_attributes(self.child, uniqueId=self.o.done_when_reaches) self.mock_when_value_matches(self.child) self.o.on_run(self.context) assert self.child.handled_requests.mock_calls == [ call.when_value_matches("uniqueId", 38, None) ] assert self.o.registrar.report.called_once assert self.o.registrar.report.call_args_list[0][0][0].steps == 38
def test_run(self): self.o = HDFWriterPart(name="m", mri="BLOCK:HDF5") self.context.set_notify_dispatch_request( self.o.notify_dispatch_request) self.o.done_when_captured = 38 # Need a registrar object or we get AssertionError self.o.registrar = MagicMock() # Run waits for this value, so say we have finished immediately self.set_attributes(self.child, numCapturedReadback=self.o.done_when_captured) self.mock_when_value_matches(self.child) # Run self.o.on_run(self.context) # Check calls assert self.child.handled_requests.mock_calls == [ call.when_value_matches("numCapturedReadback", 38, None) ] assert self.o.registrar.report.called_once assert self.o.registrar.report.call_args_list[0][0][0].steps == 38
def test_seek_with_hardware_trigger_and_breakpoints(self): self.o.is_hardware_triggered = True # Calling seek after 10 completed steps with 10 left until a breakpoint self.o.done_when_reaches = 10 # Build our seek parameters xs = LineGenerator("x", "mm", 0.0, 0.5, 20, alternate=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 3) generator = CompoundGenerator([ys, xs], [], [], 0.1) generator.prepare() completed_steps = 10 steps_to_do = 10 info = ExposureDeadtimeInfo(0.01, 1000, 0.0) part_info = dict(anyname=[info]) breakpoints = [20, 20, 20] self.o.on_seek( self.context, completed_steps, steps_to_do, part_info, generator, fileDir="/tmp", breakpoints=breakpoints, exposure=info.calculate_exposure(generator.duration), ) # Check we got the right calls to setup the driver assert self.child.handled_requests.mock_calls == [ call.put("arrayCallbacks", True), call.put("arrayCounter", 10), call.put("exposure", 0.1 - 0.01 - 0.0001), call.put("imageMode", "Multiple"), call.put("numImages", 10), call.put("acquirePeriod", 0.1 - 0.0001), call.post("start"), call.when_value_matches("acquiring", True, None), ] assert self.o.done_when_reaches == 20 assert len(self.context._subscriptions) == 0
def test_configure_frame_transfer(self): accumulate_period = 0.08 # We wait to be armed, so set this here self.set_attributes(self.child, acquiring=True) # Set what we need to simulate frame transfer mode self.set_attributes( self.child, andorFrameTransferMode=True, andorAccumulatePeriod=accumulate_period, ) self.do_configure() assert self.child.handled_requests.mock_calls == [ call.put("exposure", 0.0), call.put("acquirePeriod", 0.0), call.put("arrayCallbacks", True), call.put("arrayCounter", 0), call.put("exposure", 0.0), call.put("imageMode", "Multiple"), call.put("numImages", 6000000), call.put("acquirePeriod", accumulate_period), call.post("start"), call.when_value_matches("acquiring", True, None), ]
def test_configure(self): # We wait to be armed, so set this here self.set_attributes(self.child, acquiring=True) # This is what the detector does when exposure and acquirePeriod are # both set to 0.1 self.set_attributes(self.child, exposure=0.1, acquirePeriod=0.105) self.do_configure() # duration - readout - fudge_factor - crystal offset expected_exposure = pytest.approx(0.1 - 0.005 - 0.0014 - 5e-6) assert self.child.handled_requests.mock_calls == [ # Checking for readout time call.put("exposure", 0.1), call.put("acquirePeriod", 0.1), # Setup of detector call.put("arrayCallbacks", True), call.put("arrayCounter", 0), call.put("exposure", expected_exposure), call.put("imageMode", "Multiple"), call.put("numImages", 6000000), call.put("acquirePeriod", 0.1 - 5e-6), call.post("start"), call.when_value_matches("acquiring", True, None), ] assert self.andor_driver_part.exposure.value == expected_exposure
def test_run(self): tmp_dir = mkdtemp() + os.path.sep self.o.on_configure( self.context, self.completed_steps, self.steps_to_do, generator=self.generator, fileDir=tmp_dir, formatName="odin2", fileTemplate="a_unique_name_%s_from_gda.h5", ) self.child.handled_requests.reset_mock() self.o.registrar = MagicMock() # run waits for this value self.child.field_registry.get_field("numCaptured").set_value( self.o.done_when_reaches) self.o.on_run(self.context) assert self.child.handled_requests.mock_calls == [ call.when_value_matches("numCaptured", self.steps_to_do, None) ] assert self.o.registrar.report.called_once assert self.o.registrar.report.call_args_list[0][0][ 0].steps == self.steps_to_do rmtree(tmp_dir)
def test_abort(self): self.o.on_abort(self.context) assert self.child.handled_requests.mock_calls == [ call.post("stop"), call.when_value_matches("acquiring", False, None), ]
def configure_and_check_output(self, on_windows=False): energy = LineGenerator("energy", "kEv", 13.0, 15.2, 2) spiral = SpiralGenerator(["x", "y"], ["mm", "mm"], [0.0, 0.0], 5.0, scale=2.0) generator = CompoundGenerator([energy, spiral], [], [], 0.1) generator.prepare() fileDir = "/tmp" formatName = "xspress3" fileTemplate = "thing-%s.h5" completed_steps = 0 steps_to_do = 38 part_info = { "DET": [NDArrayDatasetInfo(2)], "PANDA": [ NDAttributeDatasetInfo.from_attribute_type( "I0", AttributeDatasetType.DETECTOR, "COUNTER1.COUNTER"), NDAttributeDatasetInfo.from_attribute_type( "It", AttributeDatasetType.MONITOR, "COUNTER2.COUNTER"), NDAttributeDatasetInfo.from_attribute_type( "t1x", AttributeDatasetType.POSITION, "INENC1.VAL"), ], "STAT": [CalculatedNDAttributeDatasetInfo("sum", "StatsTotal")], } if on_windows: part_info["WINPATH"] = [FilePathTranslatorInfo("Y", "/tmp", "")] infos = self.o.on_configure( self.context, completed_steps, steps_to_do, part_info, generator, fileDir, formatName, fileTemplate, ) assert len(infos) == 8 assert infos[0].name == "xspress3.data" assert infos[0].filename == "thing-xspress3.h5" assert infos[0].type == DatasetType.PRIMARY assert infos[0].rank == 4 assert infos[0].path == "/entry/detector/detector" assert infos[0].uniqueid == "/entry/NDAttributes/NDArrayUniqueId" assert infos[1].name == "xspress3.sum" assert infos[1].filename == "thing-xspress3.h5" assert infos[1].type == DatasetType.SECONDARY assert infos[1].rank == 2 assert infos[1].path == "/entry/sum/sum" assert infos[1].uniqueid == "/entry/NDAttributes/NDArrayUniqueId" assert infos[2].name == "I0.data" assert infos[2].filename == "thing-xspress3.h5" assert infos[2].type == DatasetType.PRIMARY assert infos[2].rank == 2 assert infos[2].path == "/entry/I0.data/I0.data" assert infos[2].uniqueid == "/entry/NDAttributes/NDArrayUniqueId" assert infos[3].name == "It.data" assert infos[3].filename == "thing-xspress3.h5" assert infos[3].type == DatasetType.MONITOR assert infos[3].rank == 2 assert infos[3].path == "/entry/It.data/It.data" assert infos[3].uniqueid == "/entry/NDAttributes/NDArrayUniqueId" assert infos[4].name == "t1x.value" assert infos[4].filename == "thing-xspress3.h5" assert infos[4].type == DatasetType.POSITION_VALUE assert infos[4].rank == 2 assert infos[4].path == "/entry/t1x.value/t1x.value" assert infos[4].uniqueid == "/entry/NDAttributes/NDArrayUniqueId" assert infos[5].name == "energy.value_set" assert infos[5].filename == "thing-xspress3.h5" assert infos[5].type == DatasetType.POSITION_SET assert infos[5].rank == 1 assert infos[5].path == "/entry/detector/energy_set" assert infos[5].uniqueid == "" assert infos[6].name == "x.value_set" assert infos[6].filename == "thing-xspress3.h5" assert infos[6].type == DatasetType.POSITION_SET assert infos[6].rank == 1 assert infos[6].path == "/entry/detector/x_set" assert infos[6].uniqueid == "" assert infos[7].name == "y.value_set" assert infos[7].filename == "thing-xspress3.h5" assert infos[7].type == DatasetType.POSITION_SET assert infos[7].rank == 1 assert infos[7].path == "/entry/detector/y_set" assert infos[7].uniqueid == "" expected_xml_filename_local = "/tmp/BLOCK_HDF5-layout.xml" if on_windows: expected_xml_filename_remote = "Y:\\BLOCK_HDF5-layout.xml" expected_filepath = "Y:" + os.sep else: expected_xml_filename_remote = expected_xml_filename_local expected_filepath = "/tmp" + os.sep # Wait for the start_future so the post gets through to our child # even on non-cothread systems self.o.start_future.result(timeout=1) assert self.child.handled_requests.mock_calls == [ call.put("positionMode", True), call.put("arrayCounter", 0), call.put("dimAttDatasets", True), call.put("enableCallbacks", True), call.put("fileName", "xspress3"), call.put("filePath", expected_filepath), call.put("fileTemplate", "%sthing-%s.h5"), call.put("fileWriteMode", "Stream"), call.put("lazyOpen", True), call.put("storeAttr", True), call.put("swmrMode", True), call.put("extraDimSize3", 1), call.put("extraDimSize4", 1), call.put("extraDimSize5", 1), call.put("extraDimSize6", 1), call.put("extraDimSize7", 1), call.put("extraDimSize8", 1), call.put("extraDimSize9", 1), call.put("extraDimSizeN", 20), call.put("extraDimSizeX", 2), call.put("extraDimSizeY", 1), call.put("numExtraDims", 1), call.put("posNameDim3", ""), call.put("posNameDim4", ""), call.put("posNameDim5", ""), call.put("posNameDim6", ""), call.put("posNameDim7", ""), call.put("posNameDim8", ""), call.put("posNameDim9", ""), call.put("posNameDimN", "d1"), call.put("posNameDimX", "d0"), call.put("posNameDimY", ""), call.put("flushAttrPerNFrames", 0), call.put("flushDataPerNFrames", 38), call.put("xmlLayout", expected_xml_filename_remote), call.put("numCapture", 0), call.post("start"), call.when_value_matches("arrayCounterReadback", greater_than_zero, None), ] with open(expected_xml_filename_local) as f: actual_xml = f.read().replace(">", ">\n") # Check the layout filename Malcolm uses for file creation assert self.o.layout_filename == expected_xml_filename_local return actual_xml