Ran update-copyright.py
[hooke.git] / hooke / plugin / convfilt.py
index e7debb6acbb43c772d563c13a61c6b0fbd78947d..2146d26702ccb00d02fdeb07003ee9f5b05a5af5 100644 (file)
@@ -1,25 +1,21 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (C) 2008-2010 Alberto Gomez-Casado
-#                         Fabrizio Benedetti
-#                         Massimo Sandal <devicerandom@gmail.com>
-#                         W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2010-2012 W. Trevor King <wking@tremily.us>
 #
 # This file is part of Hooke.
 #
-# Hooke is free software: you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation, either
-# version 3 of the License, or (at your option) any later version.
+# Hooke is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
 #
-# Hooke is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
+# Hooke is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
 #
-# You should have received a copy of the GNU Lesser General Public
-# License along with Hooke.  If not, see
-# <http://www.gnu.org/licenses/>.
+# You should have received a copy of the GNU Lesser General Public License
+# along with Hooke.  If not, see <http://www.gnu.org/licenses/>.
 
 """The ``convfilt`` module provides :class:`ConvFiltPlugin` and
 for convolution-based filtering of :mod:`hooke.curve.Curve`\s.
@@ -38,14 +34,13 @@ from multiprocessing import Queue
 
 import numpy
 
-from ..command import Command, Argument, Failure
+from ..command import Command, Argument, Success, Failure
 from ..config import Setting
-from ..experiment import VelocityClamp
-from ..plugin import Plugin, argument_to_setting
-from ..plugin.curve import CurveArgument
-from ..plugin.playlist import FilterCommand
-from ..plugin.vclamp import scale
-from ..util.peak import find_peaks, find_peaks_arguments, Peak
+from ..util.fit import PoorFit
+from ..util.peak import find_peaks, find_peaks_arguments, Peak, _kwargs
+from . import Plugin, argument_to_setting
+from .curve import CurveArgument
+from .playlist import FilterCommand
 
 
 class ConvFiltPlugin (Plugin):
@@ -54,7 +49,7 @@ class ConvFiltPlugin (Plugin):
     def __init__(self):
         super(ConvFiltPlugin, self).__init__(name='convfilt')
         self._arguments = [ # for Command initialization
-            Argument('convolution', type='float', count='-1',
+            Argument('convolution', type='float', count=-1,
                      default=[11.0]+[-1.0]*11, help="""
 Convolution vector roughly matching post-peak cantilever rebound.
 This should roughly match the shape of the feature you're looking for.
@@ -72,9 +67,9 @@ Minimum number of peaks for curve acceptance.
         for key,value in [('cut side', 'positive'),
                           ('stable', 0.005),
                           ('max cut', 0.2),
-                          ('min deviation', 5.0),
+                          ('min deviations', 5.0),
                           ('min points', 1),
-                          ('see double', 10e-9),
+                          ('see double', 10), # TODO: points vs. meters. 10e-9),
                           ]:
             argument = [a for a in self._arguments if a.name == key][0]
             argument.default = value
@@ -130,31 +125,25 @@ class ConvolutionPeaksCommand (Command):
             help=self.__doc__, plugin=plugin)
 
     def _run(self, hooke, inqueue, outqueue, params):
-        z_data,d_data,params = self._setup(params)
+        z_data,d_data,params = self._setup(hooke, params)
         start_index = 0
         while z_data[start_index] < params['bind window']:
             start_index += 1
         conv = numpy.convolve(d_data[start_index:], params['convolution'],
                               mode='valid')
-        kwargs = dict([(a.name, params[a.name]) for a in find_peaks_arguments])
-        peaks = find_peaks(conv, **kwargs)
+        peaks = find_peaks(conv, **_kwargs(params, find_peaks_arguments,
+                                            argument_input_keys=True))
         for peak in peaks:
             peak.name = 'convolution of %s with %s' \
                 % (params['deflection column name'], params['convolution'])
             peak.index += start_index
         outqueue.put(peaks)
 
-    def _setup(self, params):
+    def _setup(self, hooke, params):
         """Setup `params` from config and return the z piezo and
         deflection arrays.
         """
         curve = params['curve']
-        if curve.info['experiment'] != VelocityClamp:
-            raise Failure('%s operates on VelocityClamp experiments, not %s'
-                          % (self.name, curve.info['experiment']))
-        for col in ['surface z piezo (m)', 'deflection (N)']:
-            if col not in curve.data[0].info['columns']:
-                scale(curve)
         data = None
         for block in curve.data:
             if block.info['name'].startswith('retract'):
@@ -162,7 +151,7 @@ class ConvolutionPeaksCommand (Command):
                 break
         if data == None:
             raise Failure('No retraction blocks in %s.' % curve)
-        z_data = data[:,data.info['columns'].index('surface z piezo (m)')]
+        z_data = data[:,data.info['columns'].index('surface distance (m)')]
         if 'flattened deflection (N)' in data.info['columns']:
             params['deflection column name'] = 'flattened deflection (N)'
         else:
@@ -189,7 +178,7 @@ class ConvolutionFilterCommand (FilterCommand):
     .. [#brucale2009] M. Brucale, M. Sandal, S. Di Maio, A. Rampioni,
       I. Tessari, L. Tosatto, M. Bisaglia, L. Bubacco, B. Samorì.
       "Pathogenic mutations shift the equilibria of
-      :math:`\alpha`-Synuclein single molecules towards structured
+      α-Synuclein single molecules towards structured
       conformers."
       Chembiochem., 2009.
       doi: `10.1002/cbic.200800581 <http://dx.doi.org/10.1002/cbic.200800581>`_
@@ -204,15 +193,21 @@ class ConvolutionFilterCommand (FilterCommand):
         self.arguments.extend(plugin._arguments)
 
     def filter(self, curve, hooke, inqueue, outqueue, params):
+        params['curve'] = curve
         inq = Queue()
         outq = Queue()
-        conv_command = [c for c in self.hooke.commands
-                        if c.name=='convolution peaks'][0]
+        conv_command = self.hooke.command_by_name['convolution peaks']
         conv_command.run(hooke, inq, outq, **params)
         peaks = outq.get()
-        if not isinstance(peaks[0], Peak):
+        if isinstance(peaks, UncaughtException) \
+                and isinstance(peaks.exception, PoorFit):
+            return False
+        if not (isinstance(peaks, list) and (len(peaks) == 0
+                                             or isinstance(peaks[0], Peak))):
             raise Failure('Expected a list of Peaks, not %s' % peaks)
         ret = outq.get()
         if not isinstance(ret, Success):
             raise ret
+        if params['min peaks'] == None: # Use configured default value.
+            params['min peaks'] = self.plugin.config['min peaks']
         return len(peaks) >= params['min peaks']