1 # Copyright (C) 2008-2010 Alberto Gomez-Casado
3 # Massimo Sandal <devicerandom@gmail.com>
4 # W. Trevor King <wking@drexel.edu>
6 # This file is part of Hooke.
8 # Hooke is free software: you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation, either
11 # version 3 of the License, or (at your option) any later version.
13 # Hooke is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with Hooke. If not, see
20 # <http://www.gnu.org/licenses/>.
22 """The ``curve`` module provides :class:`CurvePlugin` and several
23 associated :class:`hooke.command.Command`\s for handling
24 :mod:`hooke.curve` classes.
27 from ..command import Command, Argument, Failure
28 from ..curve import Data
29 from ..plugin import Builtin
30 from ..plugin.playlist import current_playlist_callback
31 from ..util.calculus import derivative
34 class CurvePlugin (Builtin):
36 super(CurvePlugin, self).__init__(name='curve')
39 return [InfoCommand(), ExportCommand()]
42 # Define common or complicated arguments
44 def current_curve_callback(hooke, command, argument, value):
47 playlist = current_playlist_callback(hooke, command, argument, value)
48 curve = playlist.current()
50 raise Failure('No curves in %s' % playlist)
53 CurveArgument = Argument(
54 name='curve', type='curve', callback=current_curve_callback,
56 :class:`hooke.curve.Curve` to act on. Defaults to the current curve
57 of the current playlist.
63 class InfoCommand (Command):
64 """Get selected information about a :class:`hooke.curve.Curve`.
69 Argument(name='all', type='bool', default=False, count=1,
70 help='Get all curve information.'),
72 self.fields = ['name', 'path', 'experiment', 'driver', 'filetype', 'note',
73 'blocks', 'block sizes']
74 for field in self.fields:
76 name=field, type='bool', default=False, count=1,
77 help='Get curve %s' % field))
78 super(InfoCommand, self).__init__(
79 name='curve info', arguments=args, help=self.__doc__)
81 def _run(self, hooke, inqueue, outqueue, params):
83 for key in self.fields:
84 fields[key] = params[key]
85 if reduce(lambda x,y: x and y, fields.values()) == False:
86 params['all'] = True # No specific fields set, default to 'all'
87 if params['all'] == True:
88 for key in self.fields:
91 for key in self.fields:
92 if fields[key] == True:
93 get = getattr(self, '_get_%s' % key.replace(' ', '_'))
94 lines.append('%s: %s' % (key, get(params['curve'])))
95 outqueue.put('\n'.join(lines))
97 def _get_name(self, curve):
100 def _get_path(self, curve):
103 def _get_experiment(self, curve):
104 return curve.info.get('experiment', None)
106 def _get_driver(self, curve):
109 def _get_filetype(self, curve):
110 return curve.info.get('filetype', None)
112 def _get_note(self, curve):
113 return curve.info.get('note', None)
115 def _get_blocks(self, curve):
116 return len(curve.data)
118 def _get_block_sizes(self, curve):
119 return [block.shape for block in curve.data]
121 class ExportCommand (Command):
122 """Export a :class:`hooke.curve.Curve` data block as TAB-delimeted
126 super(ExportCommand, self).__init__(
130 Argument(name='block', aliases=['set'], type='int', default=0,
132 Data block to save. For an approach/retract force curve, `0` selects
133 the approacing curve and `1` selects the retracting curve.
135 Argument(name='output', type='file', default='curve.dat',
137 File name for the output data. Defaults to 'curve.dat'
142 def _run(self, hooke, inqueue, outqueue, params):
143 data = params['curve'].data[params['block']]
144 f = open(params['output'], 'w')
145 data.tofile(f, sep='\t')
148 class DifferenceCommand (Command):
149 """Calculate the derivative (actually, the discrete differentiation)
150 of a curve data block.
152 See :func:`hooke.util.calculus.derivative` for implementation
156 super(DifferenceCommand, self).__init__(
157 name='block difference',
160 Argument(name='block one', aliases=['set one'], type='int',
163 Block A in A-B. For an approach/retract force curve, `0` selects the
164 approacing curve and `1` selects the retracting curve.
166 Argument(name='block two', aliases=['set two'], type='int',
168 help='Block B in A-B.'),
169 Argument(name='x column', type='int', default=0,
171 Column of data block to differentiate with respect to.
173 Argument(name='y column', type='int', default=1,
175 Column of data block to differentiate.
180 def _run(self, hooke, inqueue, outqueue, params):
181 a = params['curve'].data[params['block one']]
182 b = params['curve'].data[params['block two']]
183 assert a[:,params['x column']] == b[:,params['x column']]:
184 out = Data((a.shape[0],2), dtype=a.dtype)
185 out[:,0] = a[:,params['x column']]
186 out[:,1] = a[:,params['y column']] - b[:,params['y column']]:
189 class DerivativeCommand (Command):
190 """Calculate the difference between two blocks of data.
193 super(DerivativeCommand, self).__init__(
194 name='block derivative',
197 Argument(name='block', aliases=['set'], type='int', default=0,
199 Data block to differentiate. For an approach/retract force curve, `0`
200 selects the approacing curve and `1` selects the retracting curve.
202 Argument(name='x column', type='int', default=0,
204 Column of data block to differentiate with respect to.
206 Argument(name='y column', type='int', default=1,
208 Column of data block to differentiate.
210 Argument(name='weights', type='dict', default={-1:-0.5, 1:0.5},
212 Weighting scheme dictionary for finite differencing. Defaults to
213 central differencing.
218 def _run(self, hooke, inqueue, outqueue, params):
219 data = params['curve'].data[params['block']]
220 outqueue.put(derivative(
221 block, x_col=params['x column'], y_col=params['y column'],
222 weights=params['weights']))