6 Alberto Gomez-Casado, (c) 2010, University of Twente (The Netherlands)
7 Licensed under GNU GPL v2
10 #FIXME clean this, probably some dependencies are not needed
12 from ..libhooke import WX_GOOD, ClickedPoint
14 wxversion.select(WX_GOOD)
15 from wx import PostEvent
23 warnings.simplefilter('ignore',np.RankWarning)
27 global EVT_MEASURE_WLC
29 global events_from_fit
30 events_from_fit=Queue.Queue() #GUI ---> CLI COMMUNICATION
33 class multifitCommands:
35 def do_multifit(self,args):
39 Presents curves for manual analysis in a comfortable mouse-only fashion.
40 Obtains contour length, persistance length, rupture force and
42 WLC is shown in red, eFJC in blue.
45 multifit [pl=value] [kl=value] [t=value] [slopew=value] [basew=value]
48 pl=[value] and kl=[value]: Use a fixed persistent length (WLC) or Kuhn
49 length (eFJC) for the fit. If pl is not given, the fit will be
51 DO NOT put spaces between 'pl', '=' and the value.
52 eFJC fit works better with a fixed kl
53 The value must be in nanometers.
55 t=[value] : Use a user-defined temperature. The value must be in
56 kelvins; by default it is 293 K.
57 DO NOT put spaces between 't', '=' and the value.
59 slopew and basew : width in points for slope fitting (points to the
60 right of clicked rupture) and base level fitting (points to
61 the left of clicked top of rupture).
62 If slopew is not provided, the routine will ask for a 5th
63 point to fit the slope.
64 DO NOT put spaces between 'slopew' or 'basew', '=' value.
66 slope2p : calculates the slope from the two clicked points,
67 instead of fitting data between them
69 justone : performs the fits over current curve instead of iterating
71 See fit command help for more information on the options and fit
73 NOTE: centerzero plot modifier should be activated (set centerzero 1).
76 #NOTE duplicates a lot of code from do_fit in fit.py, a call to it could be used directly
77 #but it is easier to control the program flow bypassing it
81 T=self.config['temperature']
87 #FIXME spaces are not allowed between pl or t and value
88 for arg in args.split():
89 #look for a persistent length argument.
91 pl_expression=arg.split('=')
92 pl_value=float(pl_expression[1]) #actual value
94 kl_expression=arg.split('=')
95 kl_value=float(kl_expression[1]) #actual value
96 #look for a T argument.
97 if ('t=' in arg) or ('T=' in arg):
98 t_expression=arg.split('=')
99 T=float(t_expression[1])
100 #look for a basew argument.
101 if ('basew=' in arg):
102 basew_expression=arg.split('=')
103 basew=int(basew_expression[1])
104 #look for a slopew argument.
105 if ('slopew=' in arg):
106 slopew_expression=arg.split('=')
107 slopew=int(slopew_expression[1])
108 if('justone' in arg):
110 if('slope2p' in arg):
118 print 'What curve no. you would like to start? (enter for ignoring)'
121 if skip.isdigit()==False:
125 print 'Skipping '+str(skip)+ ' curves'
128 #begin presenting curves for analysis
129 while curveindex <len(self.current_list):
132 curve=self.current_list[curveindex]
137 #give periodically the opportunity to stop the analysis
138 if counter%20==0 and counter>0:
139 print '\nYou checked '+str(counter)+' curves. Do you want to continue?'
153 print '\nCurve '+str(curveindex+1)+' of '+str(len(self.current_list))
154 print 'Click contact point or left end (red area)of the curve to skip'
155 #hightlights an area dedicated to reject current curve
156 sizeret=len(self.plots[0].vectors[1][0])
157 noarea=self.plots[0].vectors[1][0][-sizeret/6:-1]
158 noareaplot=copy.deepcopy(self._get_displayed_plot())
159 #noise dependent slight shift to improve visibility
160 noareaplot.add_set(noarea,np.ones_like(noarea)*5.0*np.std(self.plots[0].vectors[1][1][-sizeret/6:-1]))
161 noareaplot.styles+=['scatter']
162 noareaplot.colors+=["red"]
163 self._send_plot([noareaplot])
164 contact_point=self._measure_N_points(N=1, whatset=1)[0]
165 contact_point_index=contact_point.index
166 noareaplot.remove_set(-1)
167 #remove set leaves some styles disturbing the next graph, fixed by doing do_plot
169 if contact_point_index>5.0/6.0*sizeret:
175 self.wlccontact_point=contact_point
176 self.wlccontact_index=contact_point.index
177 self.wlccurrent=self.current.path
179 print 'Now click two points for the fitting area (one should be the rupture point)'
180 wlcpoints=self._measure_N_points(N=2,whatset=1)
181 print 'And one point of the top of the jump'
182 toppoint=self._measure_N_points(N=1,whatset=1)
183 slopepoint=ClickedPoint()
185 print 'Click a point to calculate slope'
186 slopepoint=self._measure_N_points(N=1,whatset=1)
188 fitpoints=[contact_point]+wlcpoints
189 #use the currently displayed plot for the fit
190 displayed_plot=self._get_displayed_plot()
192 #use both fit functions
194 wlcparams, wlcyfit, wlcxfit, wlcfit_errors,wlc_qstd = self.wlc_fit(fitpoints, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],pl_value,T, return_errors=True )
197 print 'WLC fit not possible'
201 fjcparams, fjcyfit, fjcxfit, fjcfit_errors,fjc_qstd = self.efjc_fit(fitpoints, displayed_plot.vectors[1][0], displayed_plot.vectors[1][1],kl_value,T, return_errors=True )
204 print 'eFJC fit not possible'
207 #Measure rupture force
208 ruptpoint=ClickedPoint()
209 if wlcpoints[0].graph_coords[1]<wlcpoints[1].graph_coords[1]:
210 ruptpoint=wlcpoints[0]
212 ruptpoint=wlcpoints[1]
213 tpindex=toppoint[0].index
214 toplevel=np.average(displayed_plot.vectors[1][1][tpindex:tpindex+basew])
215 force=toplevel-ruptpoint.graph_coords[1]
217 #Measure the slope - loading rate
221 xint=ruptpoint.graph_coords[0]-slopepoint[0].graph_coords[0]
222 yint=ruptpoint.graph_coords[1]-slopepoint[0].graph_coords[1]
224 slopeplot=self._get_displayed_plot(0) #get topmost displayed plot
225 slopeplot.add_set([ruptpoint.graph_coords[0],slopepoint[0].graph_coords[0]],[ruptpoint.graph_coords[1],slopepoint[0].graph_coords[1]])
226 if slopeplot.styles==[]:
227 slopeplot.styles=[None,None,'scatter']
228 slopeplot.colors=[None,None,'red']
230 slopeplot.styles+=['scatter']
231 slopeplot.colors+=['red']
233 slope=self._slope([ruptpoint]+slopepoint,slopew)
235 slope=self._slope([ruptpoint],slopew)
237 #plot results (_slope already did)
239 #now we have the fit, we can plot it
240 #add the clicked points in the final PlotObject
241 clickvector_x, clickvector_y=[], []
242 for item in wlcpoints:
243 clickvector_x.append(item.graph_coords[0])
244 clickvector_y.append(item.graph_coords[1])
246 #create a custom PlotObject to gracefully plot the fit along the curves
248 #first fix those irritating zoom-destroying fits
249 lowestpoint=min(displayed_plot.vectors[1][1])
250 for i in np.arange(0,len(wlcyfit)):
251 if wlcyfit[i] < 1.2*lowestpoint:
253 for i in np.arange(0,len(fjcyfit)):
254 if fjcyfit[i] < 1.2*lowestpoint:
257 fitplot=copy.deepcopy(displayed_plot)
258 fitplot.add_set(wlcxfit,wlcyfit)
259 fitplot.add_set(fjcxfit,fjcyfit)
260 fitplot.add_set(clickvector_x,clickvector_y)
262 fitplot.styles+=[None,None,'scatter']
263 fitplot.colors+=["red","blue",None]
265 self._send_plot([fitplot])
268 #present results of measurement
269 if len(wlcparams)==1:
270 wlcparams.append(pl_value*1e-9)
271 if len(fjcparams)==1:
272 fjcparams.append(kl_value*1e-9)
275 fjcfit_nm=[i*(10**9) for i in fjcfit_errors]
276 if len(fjcfit_nm)==1:
281 wlcfit_nm=[i*(10**9) for i in wlcfit_errors]
282 if len(wlcfit_nm)==1:
287 wlc_fitq=wlc_qstd/np.std(displayed_plot.vectors[1][1][-20:-1])
288 fjc_fitq=fjc_qstd/np.std(displayed_plot.vectors[1][1][-20:-1])
291 print 'WLC contour : '+str(1e9*wlcparams[0])+u' \u00b1 '+str(wlcfit_nm[0])+' nm'
292 print 'Per. length : '+str(1e9*wlcparams[1])+u' \u00b1 '+str(wlcfit_nm[1])+' nm'
293 print 'Quality :'+str(wlc_fitq)
295 print 'eFJC contour : '+str(1e9*fjcparams[0])+u' \u00b1 '+str(fjcfit_nm[0])+' nm'
296 print 'Kuhn length (e): '+str(1e9*fjcparams[1])+u' \u00b1 '+str(fjcfit_nm[1])+' nm'
297 print 'Quality :'+str(fjc_fitq)
299 print 'Force : '+str(1e12*force)+' pN'
300 print 'Slope : '+str(slope)+' N/m'
303 #FIXME all drivers should provide retract velocity, in SI or homogeneous units
304 lrate=slope*self.current.curve.retract_velocity
305 print 'Loading rate (UNTESTED):'+str(lrate)
307 print 'Loading rate : n/a'
313 #save accept/discard/repeat
314 print '\n\nDo you want to save these?'
318 if self.autofile=='':
319 self.autofile=raw_input('Results filename? (press enter for a random generated name)')
320 if self.autofile=='':
321 [osf,name]=tempfile.mkstemp(prefix='analysis-',suffix='.txt',text=True,dir=self.config['hookedir'])
322 print 'saving in '+name
325 f=open(self.autofile,'a+')
326 f.write('Analysis started '+time.asctime()+'\n')
327 f.write('----------------------------------------\n')
328 f.write(' File ; WLC Cont. length (nm) ; Sigma WLC cl; Per. Length (nm) ; Sigma pl ; WLC-Q ; eFJC Cont. length (nm) ; Sigma eFJC cl ; Kuhn length (nm); Sigma kl ; FJC-Q ;Force (pN) ; Slope (N/m) ; (untested) Loading rate (pN/s)\n')
331 if not os.path.exists(self.autofile):
332 f=open(self.autofile,'a+')
333 f.write('Analysis started '+time.asctime()+'\n')
334 f.write('----------------------------------------\n')
335 f.write(' File ; WLC Cont. length (nm) ; Sigma WLC cl; Per. Length (nm) ; Sigma pl; WLC-Q ;eFJC Cont. length (nm) ; Sigma eFJC cl ; Kuhn length (nm); Sigma kl ; FJC-Q ;Force (pN) ; Slope (N/m) ; (untested) Loading rate (pN/s)\n')
340 f=open(self.autofile,'a+')
341 f.write(self.current.path)
342 f.write(' ; '+str(1e9*wlcparams[0])+' ; '+str(wlcfit_nm[0])+' ; '+str(1e9*wlcparams[1])+' ; '+str(wlcfit_nm[1])+' ; '+ str(wlc_fitq)+' ; '+str(1e9*fjcparams[0])+' ; '+str(fjcfit_nm[0])+' ; '+str(1e9*fjcparams[1])+' ; '+str(fjcfit_nm[1])+' ; '+str(fjc_fitq)+' ; '+str(1e12*force)+' ; '+ str(slope)+' ; '+str(lrate)+'\n')
345 print '\nWould you like to try again on this same curve?'
351 print 'You saved '+str(savecounter)+' out of '+str(len(self.current_list))+' total curves.'
356 #shows something in the graph to indicate we expect YNclick
357 #FIXME is there an easy way to write in the graph?
358 askplot=self._get_displayed_plot()
359 center=np.min(askplot.vectors[1][0])+15e-9
360 scale=np.std(askplot.vectors[1][1][-50:-1])
361 hscale=np.mean(np.diff(askplot.vectors[1][0][-10:-1]))
362 xhline=[center-20*hscale,center-10*hscale,center+10*hscale,center+20*hscale]
363 ytopline=[15*scale,20*scale,20*scale,15*scale]
364 ybotline=[-15*scale,-20*scale,-20*scale,-15*scale]
365 yvline=np.arange(-25*scale,26*scale,scale/2)
366 xvline=np.ones_like(yvline)*center
367 xshow=np.concatenate((xvline,xhline,xhline))
368 yshow=np.concatenate((yvline,ytopline,ybotline))
369 askplot.add_set(xshow,yshow)
370 askplot.styles+=['scatter']
371 askplot.colors+=["black"]
372 self._send_plot([askplot])
373 print 'Click any point over y=0 for Yes, under it for No'
374 point=self._measure_N_points(N=1,whatset=1)[0]
375 value=point.absolute_coords[1]
376 askplot.remove_set(-1)
377 self._send_plot([askplot])