1 # Copyright (C) 2011 W. Trevor King <wking@drexel.edu>
3 # This file is part of unfold_protein.
5 # Unfold_protein is free software: you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation, either
8 # version 3 of the License, or (at your option) any later version.
10 # Unfold_protein is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with unfold_protein. If not, see
17 # <http://www.gnu.org/licenses/>.
19 """Define `UnfoldScanner` for sequential unfolding experiments."""
21 import signal as _signal
23 from calibcant.calibrate import move_far_from_surface as _move_far_from_surface
24 import pypiezo.base as _pypiezo_base
26 from . import LOG as _LOG
27 from .unfolder import ExceptionTooFar as _ExceptionTooFar
28 from .unfolder import ExceptionTooClose as _ExceptionTooClose
30 class UnfoldScanner (object):
31 def __init__(self, config, unfolder):
33 self.unfolder = unfolder
34 self._state = {'x direction': 1}
38 _signal.signal(_signal.SIGTERM, self._handle_stop_signal)
39 for i in range(self.config['velocity']['num loops']):
40 for velocity in self.config['velocity']['unfolding velocities']:
43 self.unfolder.config['unfold']['velocity'] = velocity
46 except _ExceptionTooFar:
47 self.stepper_approach()
48 except _ExceptionTooClose:
49 self.move_far_from_surface()
50 self.stepper_approach()
52 self.position_scan_step()
54 def _handle_stop_signal(self, signal, frame):
57 def move_far_from_surface(self):
58 _LOG.info('retract with the stepper motor by {} m'.format(
59 self.unfolder.config['approach']['far']))
60 _move_far_from_surface(
61 stepper=self.unfolder.afm.stepper,
62 distance=self.unfolder.config['approach']['far'])
64 def stepper_approach(self):
65 config = self.unfolder.config['approach']
66 deflection = self.unfolder.read_deflection()
67 setpoint = deflection + config['relative setpoint']
68 def_config = self.unfolder.afm.piezo.config.select_config(
69 'inputs', 'deflection')
70 setpoint_bits = _pypiezo_base.convert_volts_to_bits(
72 self.unfolder.afm.stepper_approach(target_deflection=setpoint_bits)
74 def position_scan_step(self):
76 config = self.config['position']
77 axis_config = self.unfolder.afm.piezo.config.select_config(
78 'axes', self.unfolder.afm.axis_name,
79 get_attribute=_pypiezo_base.get_axis_name
81 pos = self.unfolder.afm.piezo.last_output[axis_name]
82 pos_m = _pypiezo_base.convert_bits_to_meters(axis_config, pos)
83 next_pos_m = pos_m + self._state['x direction']*config['x step']
84 if next_pos_m > config['x max']:
85 self._state['x direction'] = -1
86 next_pos_m = pos_m + self._state['x direction']*config['x step']
87 elif next_pos_m < config['x min']:
88 self._state['x direction'] = 1
89 next_pos_m = pos_m + self._state['x direction']*config['x step']
90 next_pos = _pypiezo_base.convert_meters_to_bits(
91 axis_config, next_pos_m)
92 _LOG.info('move {} from {:g} to {:g} bits'.format(
93 axis_name, pos, next_pos))
94 self.unfolder.afm.piezo.jump(axis_name, next_pos)