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 modify it
9 # under the terms of the GNU Lesser General Public License as
10 # published by the Free Software Foundation, either version 3 of the
11 # License, or (at your option) any later version.
13 # Hooke is distributed in the hope that it will be useful, but WITHOUT
14 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
16 # 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 """Plugin regarding general force clamp measurements
25 from hooke.libhooke import WX_GOOD, ClickedPoint
28 wxversion.select(WX_GOOD)
29 from wx import PostEvent
31 from .. import curve as lhc
34 class generalclampCommands(object):
36 def plotmanip_clamp(self, plot, current, customvalue=False):
38 Handles some viewing options for the "force clamp" data format, depending on the state of these configuration variables:
39 (1) If self.config['fc_showphase'] != 0, the 'phase' data column (i.e. the 2nd) is shown in the 0th graph (else it isn't)
40 (2) If self.config['fc_showimposed'] != 0, the 'imposed deflection' data column (i.e. the 5th) is shown in the 1st graph (else it isn't)
41 (3) If self.config['fc_interesting'] == 0, the entire curve is shown in the graphs; if it has a non-zero value N, only phase N is shown.
43 NOTE - my implementation of point(3) feels quite awkward - someone smarter than me plz polish that!
47 #not a fclamp curve...
48 if current.curve.experiment != 'clamp':
51 if self.config['fc_interesting'] != 0 and plot.destination==0:
52 lower = int((self.config['fc_interesting'])-1)
53 upper = int((self.config['fc_interesting'])+1)
54 trim = current.curve.trimindexes()[lower:upper]
58 for x in range(trim[0],trim[1]):
59 newtime.append(self.plots[0].vectors[0][0][x])
60 newzpiezo.append(self.plots[0].vectors[0][1][x])
61 newphase.append(self.plots[0].vectors[1][1][x])
62 self.plots[0].vectors[0][0] = newtime
63 self.plots[0].vectors[0][1] = newzpiezo
64 self.plots[0].vectors[1][0] = newtime
65 self.plots[0].vectors[1][1] = newphase
67 if self.config['fc_interesting'] != 0 and plot.destination==1:
68 lower = int((self.config['fc_interesting'])-1)
69 upper = int((self.config['fc_interesting'])+1)
70 trim = current.curve.trimindexes()[lower:upper]
74 for x in range(trim[0],trim[1]):
75 newtime.append(self.plots[1].vectors[0][0][x])
76 newdefl.append(self.plots[1].vectors[0][1][x])
77 newimposed.append(self.plots[1].vectors[1][1][x])
78 self.plots[1].vectors[0][0] = newtime
79 self.plots[1].vectors[0][1] = newdefl
80 self.plots[1].vectors[1][0] = newtime
81 self.plots[1].vectors[1][1] = newimposed
83 if self.config['fc_showphase'] == 0 and plot.destination==0:
84 self.plots[0].remove_set(1)
86 if self.config['fc_showimposed'] == 0 and plot.destination==1:
87 self.plots[1].remove_set(1)
91 def do_time(self,args):
93 Measures the time difference (in seconds) between two points
94 Implemented only for force clamp
98 if self.current.curve.experiment == 'clamp':
99 time=self._delta(set=0)[0]
100 print str(time*1000)+' ms'
102 print 'This command makes no sense for a non-force clamp experiment.'
104 def do_zpiezo(self,args):
106 Measures the zpiezo difference (in nm) between two points
107 Implemented only for force clamp
111 if self.current.curve.experiment == 'clamp':
112 zpiezo=self._delta(set=0)[2]
113 print str(zpiezo*(10**9))+' nm'
115 print 'This command makes no sense for a non-force clamp experiment.'
117 def do_defl(self,args):
119 Measures the deflection difference (in nm) between two points
120 Implemented only for force clamp
121 NOTE: It makes sense only on the time VS defl plot; it is still not masked for the other plot...
125 if self.current.curve.experiment == 'clamp':
126 print "Warning - don't use on the zpiezo plot!"
127 defl=self._delta(set=1)[2]
128 print str(defl*(10**12))+' pN'
130 print 'This command makes no sense for a non-force clamp experiment.'
132 def do_step(self,args):
134 Measures the length and time duration of a time-Z step
138 if self.current.curve.experiment == 'clamp':
139 print 'Click three points in this fashion:'
140 print ' (0)-------(1)'
143 print ' (2)----------'
144 points=self._measure_N_points(N=3,whatset=0)
145 dz=abs(points[2].graph_coords[1]-points[1].graph_coords[1])*(10e+8)
146 dt=abs(points[1].graph_coords[0]-points[0].graph_coords[0])
147 print 'dZ: ',dz,' nm'
151 print 'This command makes no sense for a non-force clamp experiment.'
153 def do_fcfilt(self,args):
155 Filters out featureless force clamp curves of the current playlist.
156 It's very similar to 'flatfilt' for velocity clamp curves.
157 Creates a new playlist only containing non-empty curves.
159 WARNING - Only works if you set an appropriate fc_interesting config variable!
160 WARNING - arguments are NOT optional at the moment!
162 Syntax: fcfilt maxretraction(nm) mindeviation (pN)
164 Suggested values for an (i27)8 experiment with our setup are 200nm and 10-15 pN
167 if self.config['fc_interesting'] == 0:
168 print 'You must specify the phase of interest (using set fc_interesing X) prior to running fcfilt!'
175 maxretraction=int(args[0])
176 threshold=int(args[1])
178 print 'Arguments are not optional for fcfilt. You should pass two numbers:'
179 print '(1) the maximum plausible piezo retraction in NANOMETERS (e.g. the length of the protein)'
180 print "(2) the threshold, in PICONEWTONS. If signal deviates from imposed more than this, it's an event"
184 print 'Processing playlist... go get yourself a cup of coffee.'
189 for item in self.current_list:
192 notflat=self.has_stuff(item,maxretraction,threshold)
193 print 'Curve',item.path,'is',c,'of',len(self.current_list),'--->Has Stuff =',notflat
196 print 'Curve',item.path,'is',c,'of',len(self.current_list),'--->could not be processed'
198 item.features=notflat
200 notflat_list.append(item)
202 if len(notflat_list)==0:
203 print 'Nothing interesting here. Reconsider either your filtering criteria or your experimental data'
206 print 'Found',len(notflat_list),'potentially interesting curves.'
207 print 'Regenerating playlist...'
209 self.current_list=notflat_list
210 self.current=self.current_list[self.pointer]
213 def has_stuff(self,item,maxretraction,threshold):
215 Decides whether a curve has some features in the interesting phase.
217 - clip the interesting phase portion of the curve.
218 - discard the first 20 milliseconds (this is due to a quirk of our hardware).
219 - look at the zpiezo plot and note down when (if) retratcs more than [maxretraction] nm away from the first point.
220 - clip off any data after this point, with an excess of 100 points (again, an hardware quirk)
221 - if the remainder is less than 100 points, ditch the curve.
222 - now look at the deflection plot and check if there are points more than [threshold] pN over the 'flat zone'.
223 - if you find such points, bingo!
226 item.identify(self.drivers)
228 lower = int((self.config['fc_interesting'])-1)
229 upper = int((self.config['fc_interesting'])+1)
230 trim_idxs = item.curve.trimindexes()[lower:upper]
231 lo=trim_idxs[0]+20 #clipping the first 20 points off...
233 trimmed_zpiezo=item.curve.default_plots()[0].vectors[0][1][lo:hi]
234 trimmed_defl=item.curve.default_plots()[1].vectors[0][1][lo:hi]
235 trimmed_imposed=item.curve.default_plots()[1].vectors[1][1][lo:hi]
236 imposed=trimmed_imposed[21] #just to match the 20-pts clipping...
238 item.curve.close_all()
242 starting_z=trimmed_zpiezo[0]
243 plausible=starting_z-(maxretraction*1e-9)
245 while trimmed_zpiezo[det_trim]>plausible:
247 if det_trim >= len(trimmed_zpiezo): #breaking cycles makes me shiver...
248 det_trim=len(trimmed_zpiezo) #but I cannot think of anything better now.
250 further_trim=det_trim-100
253 trimmed_defl=trimmed_defl[:further_trim]
256 ninetypercent=int(0.9*len(trimmed_defl))
259 for j in trimmed_defl[:ninetypercent]:
261 avg=float(sum/ninetypercent)
262 sweetspot=float(avg+(threshold*1e-12))
263 if trimmed_defl[-1]>sweetspot:
268 del trimmed_defl,trimmed_zpiezo,trimmed_imposed