diff --git a/concert/processes/__init__.py b/concert/processes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/concert/processes/beamline.py b/concert/processes/beamline.py new file mode 100644 index 000000000..9395b5306 --- /dev/null +++ b/concert/processes/beamline.py @@ -0,0 +1,61 @@ +"""A synchrotron beam line specific processes.""" +import numpy as np +from concert.async import async, wait +from concert.quantities import q +from concert.imageprocessing import compute_rotation_axis, flat_correct + + +@async +def acquire_dark(camera, shutter): + """Use *camera* and *shutter* to acquire a dark field.""" + if shutter.state != 'closed': + shutter.close().join() + + return _grab_software_trigger(camera) + + +@async +def acquire_image_with_beam(camera, shutter, flat_motor, position): + """Use *camera*, *shutter* and *flat_motor* to move the sample to the *position* and acquire an + image. + """ + futures = [] + if shutter.state != 'open': + futures.append(shutter.open()) + futures.append(flat_motor.set_position(position)) + wait(futures) + + return _grab_software_trigger(camera) + + +@async +def determine_rotation_axis(camera, shutter, flat_motor, rotation_motor, flat_position, + radio_position): + """Determine tomographic rotation axis using *camera*, *shutter*, *rotation_motor* and + *flat_motor* devices. *flat_position* is the position for making a flat field, *radio_position* + is the position with the sample in the field of view. + """ + dark = acquire_dark(camera, shutter).result().astype(np.float32) + flat = acquire_image_with_beam(camera, shutter, flat_motor, flat_position).result() + first = acquire_image_with_beam(camera, shutter, flat_motor, radio_position).result() + rotation_motor.move(180 * q.deg).join() + last = acquire_image_with_beam(camera, shutter, flat_motor, radio_position).result() + + # flat correct + flat_corr_first = flat_correct(first, flat, dark=dark) + flat_corr_last = flat_correct(last, flat, dark=dark) + + return compute_rotation_axis(flat_corr_first, flat_corr_last) + + +def _grab_software_trigger(camera): + """Switch *camera* to software trigger mode and take an image. The mode is restored afterwards. + """ + camera['trigger_mode'].stash().join() + camera.trigger_mode = camera.trigger_modes.SOFTWARE + + try: + camera.trigger() + return camera.grab() + finally: + camera['trigger_mode'].restore().join() diff --git a/concert/processes.py b/concert/processes/common.py similarity index 92% rename from concert/processes.py rename to concert/processes/common.py index 5c9ad0b9a..7da497abb 100644 --- a/concert/processes.py +++ b/concert/processes/common.py @@ -600,62 +600,6 @@ def center_to_beam(cam, xmotor, zmotor, pixelsize, xborder, zborder, cam.stop_recording() -@async -def acquire_dark(camera, shutter): - """Use *camera* and *shutter* to acquire a dark field.""" - if shutter.state != 'closed': - shutter.close().join() - - return _grab_software_trigger(camera) - - -@async -def acquire_image_with_beam(camera, shutter, flat_motor, position): - """Use *camera*, *shutter* and *flat_motor* to move the sample to the *position* and acquire an - image. - """ - futures = [] - if shutter.state != 'open': - futures.append(shutter.open()) - futures.append(flat_motor.set_position(position)) - wait(futures) - - return _grab_software_trigger(camera) - - -@async -def determine_rotation_axis(camera, shutter, flat_motor, rotation_motor, flat_position, - radio_position): - """Determine tomographic rotation axis using *camera*, *shutter*, *rotation_motor* and - *flat_motor* devices. *flat_position* is the position for making a flat field, *radio_position* - is the position with the sample in the field of view. - """ - dark = acquire_dark(camera, shutter).result().astype(np.float32) - flat = acquire_image_with_beam(camera, shutter, flat_motor, flat_position).result() - first = acquire_image_with_beam(camera, shutter, flat_motor, radio_position).result() - rotation_motor.move(180 * q.deg).join() - last = acquire_image_with_beam(camera, shutter, flat_motor, radio_position).result() - - # flat correct - flat_corr_first = flat_correct(first, flat, dark=dark) - flat_corr_last = flat_correct(last, flat, dark=dark) - - return compute_rotation_axis(flat_corr_first, flat_corr_last) - - -def _grab_software_trigger(camera): - """Switch *camera* to software trigger mode and take an image. The mode is restored afterwards. - """ - camera['trigger_mode'].stash().join() - camera.trigger_mode = camera.trigger_modes.SOFTWARE - - try: - camera.trigger() - return camera.grab() - finally: - camera['trigger_mode'].restore().join() - - class ProcessException(Exception): """ diff --git a/concert/tests/integration/test_processes.py b/concert/tests/integration/test_processes.py index 53893fc16..680160aba 100644 --- a/concert/tests/integration/test_processes.py +++ b/concert/tests/integration/test_processes.py @@ -3,11 +3,11 @@ from scipy.ndimage import fourier from concert.tests import assert_almost_equal, TestCase from concert.quantities import q -from concert.processes import focus from concert.devices.cameras.dummy import Base as DummyCameraBase, Camera from concert.devices.motors.dummy import LinearMotor, RotationMotor from concert.devices.shutters.dummy import Shutter -from concert.processes import acquire_dark, acquire_image_with_beam, determine_rotation_axis +from concert.processes.common import focus +from concert.processes.beamline import acquire_dark, acquire_image_with_beam, determine_rotation_axis MIN_POSITION = 0 * q.mm diff --git a/concert/tests/integration/test_rotationaxisalignment.py b/concert/tests/integration/test_rotationaxisalignment.py index ccae478f7..63c0e1796 100644 --- a/concert/tests/integration/test_rotationaxisalignment.py +++ b/concert/tests/integration/test_rotationaxisalignment.py @@ -2,7 +2,7 @@ from nose.plugins.attrib import attr from concert.quantities import q from concert.devices.motors.dummy import ContinuousRotationMotor -from concert.processes import align_rotation_axis +from concert.processes.common import align_rotation_axis from concert.tests import slow, TestCase from concert.tests.util.rotationaxis import SimulationCamera diff --git a/concert/tests/integration/test_scan.py b/concert/tests/integration/test_scan.py index 799985803..f599ee6df 100644 --- a/concert/tests/integration/test_scan.py +++ b/concert/tests/integration/test_scan.py @@ -3,7 +3,7 @@ from concert.quantities import q from concert.tests import assert_almost_equal, TestCase from concert.devices.motors.dummy import LinearMotor -from concert.processes import scan, ascan, dscan, scan_param_feedback +from concert.processes.common import scan, ascan, dscan, scan_param_feedback from concert.async import resolve from concert.helpers import Region diff --git a/concert/tests/unit/test_expects.py b/concert/tests/unit/test_expects.py index 1a7530627..22134dd42 100644 --- a/concert/tests/unit/test_expects.py +++ b/concert/tests/unit/test_expects.py @@ -1,5 +1,5 @@ from concert.tests import TestCase -from concert.processes import focus, align_rotation_axis, find_beam +from concert.processes.common import focus, align_rotation_axis, find_beam from concert.devices.motors.dummy import LinearMotor, RotationMotor from concert.devices.cameras.dummy import Camera from concert.quantities import q diff --git a/concert/tests/unit/test_measures.py b/concert/tests/unit/test_measures.py index 043eb75b6..15eb5a4e2 100644 --- a/concert/tests/unit/test_measures.py +++ b/concert/tests/unit/test_measures.py @@ -4,7 +4,7 @@ from concert.devices.motors.dummy import ContinuousRotationMotor from concert.tests import slow, TestCase from concert.tests.util.rotationaxis import SimulationCamera -from concert.processes import scan +from concert.processes.common import scan from concert.measures import rotation_axis from concert.helpers import Region diff --git a/docs/devel/reference/process.rst b/docs/devel/reference/process.rst index 7de1a735a..b5230add3 100644 --- a/docs/devel/reference/process.rst +++ b/docs/devel/reference/process.rst @@ -4,25 +4,25 @@ Processes Scanning -------- -.. autofunction:: concert.processes.scan -.. autofunction:: concert.processes.ascan -.. autofunction:: concert.processes.dscan -.. autofunction:: concert.processes.scan_param_feedback +.. autofunction:: concert.processes.common.scan +.. autofunction:: concert.processes.common.ascan +.. autofunction:: concert.processes.common.dscan +.. autofunction:: concert.processes.common.scan_param_feedback Focusing -------- -.. autofunction:: concert.processes.focus +.. autofunction:: concert.processes.common.focus Alignment --------- -.. autofunction:: concert.processes.align_rotation_axis -.. autofunction:: concert.processes.center_to_beam -.. autofunction:: concert.processes.drift_to_beam -.. autofunction:: concert.processes.find_beam +.. autofunction:: concert.processes.common.align_rotation_axis +.. autofunction:: concert.processes.common.center_to_beam +.. autofunction:: concert.processes.common.drift_to_beam +.. autofunction:: concert.processes.common.find_beam Coroutines diff --git a/docs/user/topics/processes.rst b/docs/user/topics/processes.rst index 82a99d4e1..f37df02a9 100644 --- a/docs/user/topics/processes.rst +++ b/docs/user/topics/processes.rst @@ -9,7 +9,7 @@ Scanning For instance, to set 10 motor positions between 5 and 12 millimeter and acquire the flow rate of a pump could be written like:: - from concert.processes import scan + from concert.processes.common import scan from concert.helpers import Region # Assume motor and pump are already defined @@ -91,7 +91,7 @@ exposure times and flat field images you can do:: in a similar way as SPEC:: from concert.quantities import q - from concert.processes import ascan + from concert.processes.common import ascan def do_something(parameters): for each parameter in parameters: @@ -107,7 +107,7 @@ Focusing To adjust the focal plane of a camera, you use :func:`.focus` like this:: - from concert.processes import focus + from concert.processes.common import focus from concert.cameras.uca import Camera from concert.motors.dummy import LinearMotor