1 """Provides a visual panel (L{qubx.faces.Face}) to optimize rate constants from ensemble measurement.
2
3 /* Copyright 2008-2013 Research Foundation State University of New York */
4
5 /* This file is part of QUB Express. */
6
7 /* QUB Express is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation, either version 3 of the License, or */
10 /* (at your option) any later version. */
11
12 /* QUB Express is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
16
17 /* You should have received a copy of the GNU General Public License, */
18 /* named LICENSE.txt, in the QUB Express program directory. If not, see */
19 /* <http://www.gnu.org/licenses/>. */
20
21 """
22
23 import cStringIO
24 import itertools
25 import gc
26 import operator
27 import os
28 import sys
29 import time
30 import traceback
31
32 from qubx.data_types import *
33 from qubx.util_types import *
34 from qubx.faces import *
35 from qubx.GTK import *
36 import qubx.fast.data
37 import qubx.fast.model
38 import qubx.notebook
39 import qubx.optimize
40 import qubx.optimizeGTK
41 import qubx.pyenv
42 import qubx.tree
43 from qubx.model import *
44 from qubx.task import *
45 from qubx.settings import Propertied, Property
46 from qubx.trialset import add_trial_rates, add_trial_amps, add_trial_nChannel
47 import macro_r_lib
48 from . import qubx_plugin
49
50 import scipy.optimize
51 from numpy import *
52
53 import ctypes
54 from ctypes import c_int, c_float, c_double, c_void_p, c_char_p, Structure, POINTER, CFUNCTYPE, byref, sizeof, py_object, pointer, cast
55 pybuf = ctypes.pythonapi.PyBuffer_FromReadWriteMemory
56 pybuf.restype = py_object
57
58
59 MIN_SECONDS_BETWEEN_FIT = 3
60 MAXITER = 300
63 """Represents data ready for computation."""
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 @Propertied(Property('use_Peq', True, "True to start each segment from equilibrium; False to use States:Pr"),
83 Property('use_group', False, "True to fit a group of data files", in_tree=False),
84 Property('use_group_index', 1, "Group of interest in Data table"),
85 Property('resample', False, "True to resample by delta y"),
86 Property('resample_delta', 0.5, 'an interval with std < delta is resampled as one data point'),
87 Property('Gleak', 0.0, 'Leakage conductance (pS)'),
88 Property('Vleak', 0.0, 'Leak voltage (mV)'),
89 Property('opt_Nchannel', False, "True to optimize the model's channel count"),
90 Property('opt_cond', False, "True to optimize the model's Amps/Conds"),
91 Property('opt_var', False, "True to optimize the model's Stds/CondStds"),
92 Property('recursive_fit', False, "Toggle non-recursive (MacRates) and recursive (MacroR) fits"),
93
94 Property('live', False, "True to redo fit curve when model changes", in_tree=False),
95 Property('use_GPU', False, "True to use OpenCL-capable graphics card, if avail", in_tree=False)
96 )
98 """Calculates log-likelihood and optimizes model parameters, a la Moffatt 2007.
99
100 @ivar OnIterationMR: L{WeakEvent}(iteration, LL, grads, K0, K1, amp, std, amp0, std0, Nchannel)
101 @ivar OnIteration2MR: L{WeakEvent}(iteration, LL, grads, K0, K1, K2, amp, std, amp0, std0, Nchannel)
102 @ivar OnLiveLL: L{WeakEvent}(LL)
103 """
104 __explore_featured = ['accel', 'rates', 'OnIterationMR', 'LL', 'last_LL', 'grads', 'OnLiveLL', 'fitbot', 'outStatus',
105 'get_ndata', 'add_trial_fields', 'wait_for_fits']
106 - def __init__(self, name='MacroR', global_name='QubX.Modeling.MacroR'):
107 super(RatesFace, self).__init__(name, global_name,
108 "qubx_macror_optimize",
109 {"max step" : 0.1,
110 "num grad dx" : 1e-4,
111 "conv ll" : 1e-3,
112 "conv grad" : 1e-3})
113 self.__ref = Reffer()
114 self.__invalid_score = False
115 self.__invalid_live = True
116 self.accel = 1
117 self.QubX = qubx.pyenv.env.globals['QubX']
118 self.QubX.OnQuit += self.__ref(self.mac_finalize)
119 self.propertied_connect_settings('MacroR')
120 self.data.use_group = self.use_group_index if self.use_group else None
121 self.rates = Product(self.__get_rates)
122 self.rates.OnInvalidate += self.__ref(self.__onInvalidateRates)
123 self.OnIterationMR = WeakEvent()
124 self.OnIteration2MR = WeakEvent()
125
126 self.robot.working = False
127 self.robot.workspaces = None
128 self.robot.optNchannel = self.robot.optCond = self.robot.optVar = False
129 self.iterations = 0
130 self.LL = self.last_LL = 0.0
131 self.grads = []
132 self.__Ndata = 0
133 self.OnLiveLL = WeakEvent()
134
135
136
137
138 self.fitbot = Robot('Apply Fit')
139 self.fitbot.OnException += self.__ref(self.on_exception)
140 self.fitbot.serial = self.fitbot.last_serial = 0
141
142 self.__last_fits_time = datetime.datetime.now()
143
144 if self.__last_fits_time.hour:
145 self.__last_fits_time = self.__last_fits_time.replace(hour=self.__last_fits_time.hour-1)
146
147
148
149 qubx.notebook.Notebook.register_auto('MacroR_eval.Messages', 'Messages, on MacroR: Get LL', False)
150 qubx.notebook.Notebook.register_auto('MacroR_eval.Model.Picture', 'Model picture, on MacroR: Get LL', False)
151 qubx.notebook.Notebook.register_auto('MacroR_eval.Model.PictureNO', 'Model picture, no overlays, on MacroR: Get LL', False)
152 qubx.notebook.Notebook.register_auto('MacroR_eval.Data.Picture', 'Data picture, on MacroR: Get LL', False)
153 qubx.notebook.Notebook.register_auto('MacroR_eval.Model.Classes', 'Classes table, on MacroR: Get LL', False)
154 qubx.notebook.Notebook.register_auto('MacroR_eval.Model.Rates', 'Rates table, on MacroR: Get LL', False)
155
156 qubx.notebook.Notebook.register_auto('MacroR_opt.Iterations', 'Iteration log, on MacroR: Optimize', True)
157 qubx.notebook.Notebook.register_auto('MacroR_opt.Messages', 'Messages, on MacroR: Optimize', True)
158 qubx.notebook.Notebook.register_auto('MacroR_opt.Model.Picture', 'Model picture, on MacroR: Optimize', True)
159 qubx.notebook.Notebook.register_auto('MacroR_opt.Model.PictureNO', 'Model picture, no overlays, on MacroR: Optimize', False)
160 qubx.notebook.Notebook.register_auto('MacroR_opt.Data.Picture', 'Data picture, on MacroR: Optimize', True)
161 qubx.notebook.Notebook.register_auto('MacroR_opt.Model.Classes', 'Classes table, on MacroR: Optimize', True)
162 qubx.notebook.Notebook.register_auto('MacroR_opt.Model.Rates', 'Rates table, on MacroR: Optimize', False)
163 qubx.notebook.Notebook.register_auto('MacroR_opt.Model.Constraints', 'Kinetic Constraints table, on MacroR: Optimize', True)
164
165 col = pack_item(gtk.VBox(), self.top_panel)
166 self.chkPeq = pack_check('start at equilibrium p', col)
167 self.chkPeq.set_tooltip_text('otherwise use States:Pr')
168 self.propertied_connect_check('use_Peq', self.chkPeq)
169 h = pack_item(gtk.HBox(), col)
170 self.chkResample = pack_check('resample by delta:', h)
171 self.chkResample.set_tooltip_text('skip slow changes:\ncompress data with std.dev < delta into a single point')
172 self.propertied_connect_check('resample', self.chkResample)
173 self.txtResample = pack_item(NumEntry(self.resample_delta, acceptFloatGreaterThan(0.0), '%.3g', width_chars=6), h)
174 self.propertied_connect_NumEntry('resample_delta', self.txtResample)
175
176 pack_space(self.top_panel, x=20)
177 col = pack_item(gtk.VBox(), self.top_panel)
178 h = pack_item(gtk.HBox(), col)
179 pack_label('Gleak:', h)
180 self.txtGleak = pack_item(NumEntry(self.Gleak, acceptFloat, '%.3g', width_chars=6), h, at_end=True)
181 self.propertied_connect_NumEntry('Gleak', self.txtGleak)
182 h = pack_item(gtk.HBox(), col)
183 pack_label('Vleak:', h)
184 self.txtVleak = pack_item(NumEntry(self.Vleak, acceptFloat, '%.3g', width_chars=6), h, at_end=True)
185 self.propertied_connect_NumEntry('Vleak', self.txtVleak)
186
187 pack_space(self.top_panel, expand=True)
188 col = pack_item(gtk.VBox(True), self.top_panel)
189 lbl_d = pack_label('Multi-data:', col)
190
191 col = pack_item(gtk.VBox(True), self.top_panel)
192 h = pack_item(gtk.HBox(), col)
193 self.chkUseGroup = pack_check('Group', h)
194 self.propertied_connect_check('use_group', self.chkUseGroup)
195 self.txtUseGroup = pack_item(qubx.GTK.NumEntry(self.use_group_index, acceptIntGreaterThan(-1), width_chars=3), h)
196 self.txtUseGroup.set_sensitive(self.use_group)
197 self.propertied_connect_NumEntry('use_group_index', self.txtUseGroup)
198 for widget in (lbl_d, self.chkUseGroup, self.txtUseGroup):
199 widget.set_tooltip_text('To select data files, set their Group number in the Data table.\nThey will be fit to common parameters')
200
201
202
203
204
205
206
207
208
209 pack_space(self.top_panel, expand=True)
210 col = pack_item(gtk.VBox(True), self.top_panel)
211 self.chkLive = pack_check('live ', col)
212 self.chkLive.set_tooltip_text('update LL and fit curve when the model changes')
213 self.propertied_connect_check('live', self.chkLive)
214 self.chkRecursiveFit = pack_check('rec. fit', col)
215 self.chkRecursiveFit.set_tooltip_text('on: shows the recursive prior distribution;\noff: shows the MacRates (non-recursive) fit')
216 self.propertied_connect_check('recursive_fit', self.chkRecursiveFit)
217 self.chkGPU = pack_check('use GPU ', col, show=False)
218 self.chkGPU.set_tooltip_text('use graphics card if available; faster but less accurate')
219 self.propertied_connect_check('use_GPU', self.chkGPU)
220
221 self.lblScore.set_text('LL:')
222 self.btnGetScore.set_label('Get LL')
223
224 pack_label('Optimize:', self.right_panel)
225 self.chkOptNchannel = pack_check('channel count', self.right_panel)
226 self.propertied_connect_check('opt_Nchannel', self.chkOptNchannel)
227 self.chkOptCond = pack_check('conductance', self.right_panel)
228 self.propertied_connect_check('opt_cond', self.chkOptCond)
229 self.chkOptVar = pack_check('variance', self.right_panel)
230 self.propertied_connect_check('opt_var', self.chkOptVar)
231 self.chkOptRates = pack_check('rates', self.right_panel, active=True)
232 self.chkOptRates.set_tooltip_text('To hold a rate constant, right-click it, "Add Constraint...," "Fix..."')
233 self.chkOptRates.set_sensitive(False)
234
235 self.outStatus = TextViewAppender(self.txtStatus)
236 self.outStatus.write('Based on "Estimation of ion channel kinetics from fluctuations of macroscopic currents," Moffatt L., Biophys J. 2007 Jul 1; 93(1):74-91\n')
237 self.outStatus.OnWrite += self.__ref(self.__onWriteStatus)
238 self.__nb_iter_buf = None
240 """Stops the worker threads; call this in qubx_plugin_fini."""
241 self.robot.stop()
242 self.fitbot.stop()
243 self.data = self.data_prep = None
245 traceback.print_exception(typ, val, trace)
246 traceback.print_exception(typ, val, trace, file=self.outStatus)
248 if not (self.__nb_iter_buf is None):
249 self.__nb_iter_buf.write(msg)
272 """Changes LL text color gray (outdated) or black (up-to-date), and starts computation if showing in live mode."""
273 if self.__invalid_score != gray:
274 self.__invalid_score = gray
275 color = gdk.color_parse(gray and "#999999" or "#000000")
276 self.txtScore.modify_text(gtk.STATE_NORMAL, color)
277 if gray and self.showing and self.chkLive.get_active():
278 self.__queue_robot_live()
291 try:
292 self.chkPeq.set_sensitive(sens)
293 except:
294 pass
304 if data_prep and data_prep.workspaces:
305 return reduce(operator.add, (ws.data.Ndata for ws in data_prep.workspaces), 0)
306 else:
307 return self.__Ndata
312 - def add_trial_fields(self, row, mtree, prefix='', model_prep=None, data_prep=None):
313 add_trial_rates(row, mtree, prefix)
314 if (not prefix) or self.robot.optNchannel:
315 add_trial_nChannel(row, mtree, prefix)
316 if (not prefix) or self.robot.optCond or self.robot.optVar:
317 add_trial_amps(row, mtree, prefix)
336 - def calculate_score(self, model_prep=None, data_prep=None, wait=True, receiver=lambda score: None, on_trial=None, **kw):
339 - def optimize(self, model_prep=None, data_prep=None, wait=True, receiver=None, ext_return=False, on_trial=None):
344 - def __onOptDone(self, LL, iterations, grads, Hessian, workspaces, model_prep, data_prep):
345 self.QubX.Models.view.optimizing = False
346 self.LL = LL
347 self.iterations = iterations
348 self.grads = grads
349 iteration_messages = self.__nb_iter_buf.getvalue() if self.__nb_iter_buf else ""
350 self.__nb_iter_buf = cStringIO.StringIO()
351 for source in model_prep.sources:
352 source.undoStack.seal_undo('set rates')
353 Ndata = self.__Ndata
354 self.append_output('===================================================\n')
355 self.outStatus.write("""MacroR: finished optimizing %d points after %d iterations.
356 Data: %s
357 Model: %s
358 P0: %s
359 Resample: %s
360 Gleak: %.4g
361 Vleak: %.4g
362 GPU: %s
363 Optimize: %s
364 Gradient: %s
365 """ % (Ndata,
366 iterations,
367 '\n '.join(os.path.split(ws.data.file.path)[1] for ws in workspaces),
368 model_prep.sources and ', '.join([os.path.split(source.path)[1] for source in model_prep.sources]) or "from script",
369 self.robot.Peq and "equilibrium" or "fixed (States table)",
370 self.data.resample and ("by delta = %.4g" % self.data.resample_std) or "no",
371 self.robot.Gleak,
372 self.robot.Vleak,
373 self.chkGPU.get_active() and "yes" or "no",
374 ((self.robot.optNchannel and "channel count, " or "") +
375 (self.robot.optCond and "conductance, " or "") +
376 (self.robot.optVar and "variance, " or "") +
377 "rates"),
378 ', '.join('%8.5g' % x for x in grads)))
379 if workspaces:
380 self.__set_model_confidence(workspaces[0], model_prep)
381 self.outStatus.write('\nLL: ')
382 self.outStatus.write_bold('%.5g' % LL)
383 if self.last_LL:
384 self.outStatus.write(' last LL: %.5g' % self.last_LL)
385 self.append_output('\n===================================================\n')
386 self.invalidate_controls(False)
387 qubx.notebook.Notebook.send(qubx.notebook.NbText(iteration_messages), auto_id='MacroR_opt.Iterations')
388 qubx.notebook.Notebook.send(qubx.notebook.NbText(self.__nb_iter_buf.getvalue()), auto_id='MacroR_opt.Messages')
389 self.__nb_iter_buf = None
390 if self.QubX.Models.file in model_prep.sources:
391 qubx.notebook.Notebook.send(self.QubX.Models.view.nbPicture, auto_id='MacroR_opt.Model.Picture')
392 qubx.notebook.Notebook.send(self.QubX.Models.view.nbPictureNO, auto_id='MacroR_opt.Model.PictureNO')
393 qubx.notebook.Notebook.send(self.QubX.Tables.find_view('Classes').nbTable, auto_id='MacroR_opt.Model.Classes')
394 qubx.notebook.Notebook.send(self.QubX.Tables.find_view('Rates').nbTable, auto_id='MacroR_opt.Model.Rates')
395 qubx.notebook.Notebook.send(self.QubX.Tables.find_view('Kinetic Constraints').nbTable, auto_id='MacroR_opt.Model.Constraints')
396
397 fitbot = qubx.global_namespace.QubX.Modeling.MacRates.fitbot if ((not self.recursive_fit) and hasattr(qubx.global_namespace.QubX.Modeling, 'MacRates')) else self.fitbot
398 fitbot.do(self.fitbot_send_datapic, 'MacroR_opt.Data.Picture')
399 self.last_opt_model = workspaces[0].param.modelinfo[0].fastmodel if workspaces else None
400 self.last_LL = LL
402 for mi in ws.param.modelinfo:
403 self.outStatus.write("\n", scroll=False)
404 if self.robot.optNchannel:
405 self.outStatus.write("Channel count: ", scroll=False)
406 self.outStatus.write_bold('%i' % mi.fastmodel.Nchannel, scroll=False)
407 self.outStatus.write(" +/- %.1f\n" % mi.fastmodel.Nchannel_err, scroll=False)
408 if self.robot.optCond or self.robot.optVar:
409 amp_lbl, std_lbl = ('Amp', 'Variance') if (not mi.fastmodel.IeqFv) else ('Cond', 'CondVar')
410 if mi.fastmodel.IeqFv and mi.fastmodel.iVoltage:
411 if self.robot.optCond:
412 self.outStatus.write('Baseline Amp: ', scroll=False)
413 self.outStatus.write_bold('%.5g' % mi.fastmodel.amp0, scroll=False)
414 self.outStatus.write(' +/- %.5g\n' % mi.fastmodel.amp0_err, scroll=False)
415 if self.robot.optVar:
416 self.outStatus.write('Baseline Variance: ', scroll=False)
417 self.outStatus.write_bold('%.5g' % mi.fastmodel.var0, scroll=False)
418 self.outStatus.write(' +/- %.5g\n' % mi.fastmodel.var0_err, scroll=False)
419 self.outStatus.write('%7s' % 'State', scroll=False)
420 if self.robot.optCond:
421 self.outStatus.write_bold('%14s' % amp_lbl, scroll=False)
422 self.outStatus.write('%14s' % (amp_lbl+' err'), scroll=False)
423 if self.robot.optVar:
424 self.outStatus.write_bold('%14s' % std_lbl, scroll=False)
425 self.outStatus.write('%14s' % (std_lbl+' err'), scroll=False)
426 self.outStatus.write('\n', scroll=False)
427 for c in xrange(mi.fastmodel.Nclass):
428 self.outStatus.write('%7d' % c)
429 if self.robot.optCond:
430 self.outStatus.write_bold('%14.5g' % mi.fastmodel.amp[c], scroll=False)
431 self.outStatus.write('%14.5g' % mi.fastmodel.amp_err[c], scroll=False)
432 if self.robot.optVar:
433 self.outStatus.write_bold('%14.5g' % mi.fastmodel.var[c], scroll=False)
434 self.outStatus.write('%14.5g' % mi.fastmodel.var[c], scroll=False)
435 self.outStatus.write('\n', scroll=False)
436 self.outStatus.write('%10s%7s' % ("Rate From", "To"), scroll=False)
437 self.outStatus.write_bold('%14s' % "k0", scroll=False)
438 self.outStatus.write('%11s' % "+/-", scroll=False)
439 self.outStatus.write_bold('%14s' % 'k1', scroll=False)
440 self.outStatus.write('%11s' % "+/-", scroll=False)
441 self.outStatus.write_bold('%14s' % 'k2', scroll=False)
442 self.outStatus.write('%11s' % "+/-", scroll=False)
443 for mi, source in itertools.izip(ws.param.modelinfo, model_prep.sources):
444 self.outStatus.write('\n', scroll=False)
445 for rate in source.rates:
446 a,b = rate.From, rate.To
447 source.rates[rate.Index, 'k0 std'] = mi.fastmodel.K0_err[a,b]
448 source.rates[rate.Index, 'k1 std'] = mi.fastmodel.K1_err[a,b]
449 source.rates[rate.Index, 'k2 std'] = mi.fastmodel.K2_err[a,b]
450 self.outStatus.write('%10d%7d' % (a, b), scroll=False)
451 self.outStatus.write_bold('%14.5g' % rate.k0, scroll=False)
452 self.outStatus.write('%11.3g' % mi.fastmodel.K0_err[a,b], scroll=False)
453 self.outStatus.write_bold('%14.5g' % rate.k1, scroll=False)
454 self.outStatus.write('%11.3g' % mi.fastmodel.K1_err[a,b], scroll=False)
455 self.outStatus.write_bold('%14.5g' % rate.k2, scroll=False)
456 self.outStatus.write('%11.3g' % mi.fastmodel.K2_err[a,b], scroll=False)
457 self.outStatus.write('\n')
458 - def __onIteration(self, iteration, LL, grads, optNchannel, workspaces, modelinfo, K0s, K1s, K2s, amps, stds, amp0s, std0s, Nchannels):
459 self.LL = LL
460 self.iterations = iteration
461 self.grads = grads
462 for mi, K0, K1, K2, amp, std, amp0, std0, Nchannel in itertools.izip(modelinfo, K0s, K1s, K2s, amps, stds, amp0s, std0s, Nchannels):
463 model = mi.prep.source
464 if not model:
465 continue
466 K012ToModel(K0, K1, K2, model)
467 if model.IeqFv:
468 for c,a in enumerate(amp):
469 model.classes.set(c, 'Cond', a)
470 model.classes.set(c, 'CondStd', std[c])
471 model.classes.set(0, 'Amp', amp0)
472 model.classes.set(0, 'Std', std0)
473 else:
474 for c,a in enumerate(amp):
475 model.classes.set(c, 'Amp', a)
476 model.classes.set(c, 'Std', std[c])
477 model.set_channelCount(Nchannel, seal=False)
478 if (self.__Ndata > 1) and optNchannel and (len(modelinfo) == 1):
479 for i, ws in enumerate(workspaces):
480 datafile = qubx.global_namespace.QubX.Data.views[ws.param.data.file_index].file
481 try:
482 cc_ix = datafile.constants.index('Channel Count')
483 datafile.constants[cc_ix, 'Value'] = ws.param.modelinfo[0].fastmodel.Nchannel
484 except KeyError:
485 datafile.constants.append({'Name' : 'Channel Count', 'Value' : ws.param.modelinfo[0].fastmodel.Nchannel})
486 self.invalidate_controls(False)
487 self.outStatus.write('Iter: %i\tLL: %8.5g\tgrads: %s\n' % (iteration, LL, ', '.join("%8.5g"%g for g in grads)))
488 self.OnIterationMR(iteration, LL, grads, K0s, K1s, amps, stds, amp0s, std0s, Nchannels)
489 self.OnIteration2MR(iteration, LL, grads, K0s, K1s, K2s, amps, stds, amp0s, std0s, Nchannels)
491 cancel()
492 for ws in self.robot.workspaces:
493 for mi in ws.param.modelinfo:
494 mi.fastmodel.obj[0].stop_flag = 1
502 - def request_data_prep(self, receiver, segs, model_prep, last_data_prep=None, resample=None, resample_std=None):
503 QubX = qubx.global_namespace.QubX
504 view_of_file = dict([(view.file, view) for view in QubX.Data.views])
505 view_segm = []
506 vs_by_file = {}
507 for seg in segs:
508 if not (seg.file in vs_by_file):
509 vs = (view_of_file[seg.file], [])
510 view_segm.append(vs)
511 vs_by_file[seg.file] = vs
512 vs_by_file[seg.file][1].append(seg)
513 if not view_segm:
514 if receiver:
515 gobject.idle_add(receiver, DataPrep(segs, []))
516 return
517
518 resamp = QubX.Modeling.MacroR.resample if (resample is None) else resample
519 resamp_std = QubX.Modeling.MacroR.resample_delta if (resample_std is None) else resample_std
520
521 datas = []
522 data_prep = DataPrep(segs, datas)
523 self.last_LL = 0.0
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540 rcv_stims = None
541 def rcv_hack(*args):
542 rcv_stims.send(args)
543 def receive_stims():
544 stim_names = iunion((prep.source or prep.model).variables for prep in model_prep.preps)
545 for dataview, segsrc in view_segm:
546
547 if last_data_prep and len(last_data_prep.datas) and (len(view_segm) == 1):
548 data = last_data_prep.datas[0]
549 data.reset(len(stim_names))
550 else:
551 data = macro_r_lib.Data(len(stim_names), file_index=QubX.Data.views.index(dataview))
552
553 sampling_sec = dataview.file.sampling
554 if 'Voltage' in stim_names:
555 data.iVoltage = stim_names.index('Voltage') + 1
556 else:
557 data.iVoltage = 0
558 data.signal_names = ['Current'] + stim_names
559 data.ff_ll_counts = []
560
561 iseg = -1
562 for seg in segsrc:
563 data.file = seg.file
564 data.iSignal = seg.signal
565 QubX.Modeling.Stimulus.call_with_stimulus_idl(rcv_hack, [(chunk.f, chunk.l) for chunk in seg.chunks], datafile=dataview.file, names=stim_names)
566 stim_names, stimidl = (yield)
567 chunkidl = [ Anon(dwellCounts=[], classeses=[], durationses=[], ampses=[]) for chunk in seg.chunks]
568 missing = False
569 for segs_flcda in stimidl:
570 for ichunk, flcda in enumerate(segs_flcda):
571 ff, ll, cc, dd, aa = flcda
572 if not len(cc):
573 missing = True
574 chunkidl[ichunk].dwellCounts.append(len(cc))
575 chunkidl[ichunk].classeses.append(cc)
576 chunkidl[ichunk].durationses.append(dd)
577 chunkidl[ichunk].ampses.append(aa)
578 if missing:
579 continue
580
581 iseg += 1
582 data.append_segment()
583 for ichunk, chunk in enumerate(seg.chunks):
584 if chunk.included:
585 Nd = chunk.n
586 chunkoff = chunk.f - seg.f
587 xx = arange(chunkoff, chunkoff+Nd, dtype='float32')
588 xx *= sampling_sec
589 yy = zeros(shape=(Nd,), dtype='float32')
590 ii = 0
591 for ch in generate_chunk_samples([chunk]):
592 yy[ii:ii+ch.n] = ch.samples
593 ii += ch.n
594 if resamp:
595 means, stds, ff, ll, closest = qubx.fast.data.adaptive_resample(yy, resamp_std)
596 xx = array(xx[closest], dtype='float32', copy=True)
597 yy = array(yy[closest], dtype='float32', copy=True)
598 ff += chunk.f
599 ll += chunk.f
600 Nd = len(means)
601 else:
602 ff = arange(seg.f+chunkoff, seg.f+chunkoff+Nd, dtype='int32')
603 ll = ff
604 data.ff_ll_counts.append( (ff, ll, Nd) )
605 else:
606 Nd = 0
607 xx = yy = None
608 data.append_chunk(iseg, (chunk.l - chunk.f + 1) * sampling_sec, Nd, xx, yy, None,
609 chunkidl[ichunk].dwellCounts, chunkidl[ichunk].classeses,
610 chunkidl[ichunk].durationses, chunkidl[ichunk].ampses,
611 (not resamp) and sampling_sec or 0.0)
612 datas.append(data)
613 gobject.idle_add(receiver, data_prep)
614 yield None
615
616 rcv_stims = receive_stims()
617 rcv_stims.next()
619 self.chkGPU.set_active(False)
620 self.chkGPU.set_sensitive(False)
621 self.chkGPU.set_tooltip_text('no OpenCL-compatible graphics processor is available')
645 model_prep = self.robot.model_prep
646 self.robot.models = model_prep.models
647 self.robot.modelinfo = [Anon(model=prep.model, prep=prep) for prep in model_prep.preps if prep.model.states.size]
648 self.data.model_prep = model_prep
649
650 for mi in self.robot.modelinfo:
651 mi.clazz = ModelToClazz(mi.model)
652 mi.Nclass = int(max(mi.clazz) + 1) if mi.clazz.shape[0] else 0
653
654 datas = self.robot.data = self.data_prep.datas
655 if self.robot.workspaces:
656 for ws in self.robot.workspaces:
657 try:
658 ws.fastmodel.dispose()
659 except:
660 pass
661 workspaces = self.robot.workspaces = []
662 self.__Ndata = reduce(operator.add, (data.Ndata for data in datas), 0)
663
664 for data in datas:
665 stimclasses = data.get_stimclasses()
666 Nstim = data.Nstim
667 Nsig = data.Nsig
668 sc_frac = data.get_stimclass_frac()
669 param = macro_r_lib.Param()
670 param.modelinfo = []
671 param.data = data
672 param.useVar = True
673 param.optNchannel = self.robot.optNchannel
674 param.accel = self.robot.accel
675
676 for im, mi in enumerate(self.robot.modelinfo):
677 fastmodel = ModelToFast(mi.model, data.signal_names, self.robot_on_status)
678 fastmodel.usePeq = self.robot.Peq
679 fastmodel.iVoltage = data.iVoltage
680 fastmodel.Gleak = self.robot.Gleak
681 fastmodel.Vleak = self.robot.Vleak
682 K0, K1, K2, L, V, P = ModelToRateMatricesP(mi.model, data.signal_names)
683 fastmodel.K0[:], fastmodel.K1[:], fastmodel.K2[:] = K0, K1, K2 = self.robot.K012[im]
684
685 if len(datas) > 1:
686 try:
687 fastmodel.Nchannel = qubx.global_namespace.QubX.Data.views[data.file_index].file.constants.get_by_name('Channel Count', 'Value')
688 except:
689 pass
690
691 ratesm = qubx.fast.model.StimRates(fastmodel, Nstim, Nsig, stimclasses, sc_frac, 0.0)
692 A, B = mi.model.constraints_kin.get_matrices_p(K0, K1, K2, L, V, P, auto=False)
693 if A != None:
694 ratesm.cns.Ain[:A.shape[0],:A.shape[1]] = A
695 ratesm.cns.Bin[:B.shape[0]] = B.flatten()
696 ratesm.cns.Ncns = B.shape[0]
697 else:
698 ratesm.cns.Ncns = 0
699
700 ampm = qubx.fast.model.StimAmps(fastmodel, Nstim, Nsig, stimclasses, sc_frac)
701 if not self.robot.optCond:
702 for c in xrange(fastmodel.Nclass):
703 ampm.fix_amp(c)
704 if fastmodel.IeqFv:
705 ampm.fix_amp0()
706 if not self.robot.optVar:
707 for c in xrange(fastmodel.Nclass):
708 ampm.fix_var(c)
709 if fastmodel.IeqFv:
710 ampm.fix_var0()
711 param.add_model(fastmodel, ampm, ratesm)
712 param.modelinfo.append(mi)
713 mi.fastmodel = fastmodel
714 mi.Nchannel = fastmodel.Nchannel
715
716 if param.models:
717 param.setup_constraints()
718 workspaces.append(Anon(param=param, data=data, modelinfo=param.modelinfo, L=L, V=V))
720 if self.__invalid_live and not self.robot.working:
721 if model_prep is None:
722 with self.robot.main_hold:
723 mp = self.model_prep.val
724 else:
725 mp = model_prep
726 self.robot_setup_data(mp, None)
727 LL = self.robot_calculate_score()
728 gobject.idle_add(self.OnLiveLL, LL)
730 LL = 0.0
731 try:
732 self.robot.working = True
733 self.__invalid_live = False
734 if not self.optimizing:
735 self.robot_setup()
736 LL = 0.0
737 for ws in self.robot.workspaces:
738 try:
739 LL += macro_r_lib.mac_ll(ws.param)
740 except:
741 gobject.idle_add(self.outStatus.write, traceback.format_exc() + '\n')
742 LL += -1.0
743 if ws.param.gpu_fail:
744 gobject.idle_add(self.__onGPUFail)
745 self.robot.accel -= 1
746 for ws2 in self.robot.workspaces:
747 ws2.param.accel = self.robot.accel
748 self.robot_queue_fits(0, True)
749 except:
750 self.robot.send_exception()
751 gobject.idle_add(self.__onGotLL, LL)
752 self.robot.working = False
753 return LL
755 """Returns the list of initial parameter values, on worker thread; override this method.
756 Derive parameter values from self.robot.model and/or from your own widgets."""
757 self.robot_setup()
758 if self.robot.workspaces:
759 pars = [float(x) for x in self.robot.workspaces[0].param.fPars[:self.robot.workspaces[0].param.NfPar]]
760 else:
761 pars = []
762
763 if (len(self.robot.workspaces) > 1) and self.robot.optNchannel and (len(self.robot.models) == 1):
764 pars.extend([1.0] * (len(self.robot.workspaces)-1))
765 self.__scale_Nchannel = [log(ws.param.Nchannel) for ws in self.robot.workspaces[1:]]
766 return array(pars)
768 if (pars != None) and self.robot.workspaces:
769 NfPar = self.robot.workspaces[0].param.NfPar
770 self.robot.workspaces[0].param.fPars[:NfPar] = pars[:NfPar]
771 self.robot.workspaces[0].param.do_fPars_to_model()
772 if (len(self.robot.workspaces) > 1) and self.robot.optNchannel and (len(self.robot.models) == 1):
773 ccpar = pars[-(len(self.robot.workspaces)-1):]
774 for i, ws in enumerate(self.robot.workspaces[1:]):
775 float_Nchannel = max(1.0, exp(self.__scale_Nchannel[i] * ccpar[i]))
776 ws.param.float_Nchannel = float_Nchannel
777 ws.param.modelinfo[0].fastmodel.Nchannel = int(round(float_Nchannel))
779 try:
780 self.robot.working = True
781 self.robot.LL = 0.0
782 self.__last_fits_iter = -1
783 iterations = 0
784 pars = grads = []
785 Hessian = None
786 self.robot.LL, pars, iterations, grads, Hessian = super(RatesFace, self).robot_optimize()
787 self.robot.workspaces[0].param.calc_std(Hessian)
788 if self.accel and (self.__last_fits_iter < iterations):
789 self.robot_queue_fits(iterations, True)
790 except:
791 self.robot.send_exception()
792 gobject.idle_add(self.__onOptDone, self.robot.LL, iterations, grads, Hessian, self.robot.workspaces, self.robot.model_prep, self.data_prep)
793 self.robot.working = False
794 return self.robot.LL, pars, iterations, grads, Hessian
796 if self.robot.workspaces[0].param.modelinfo[0].fastmodel.obj[0].stop_flag:
797 raise KeyboardInterrupt()
798 else:
799 self.robot_set_pars(pars)
800 self.robot_queue_fits(iterations)
801 self.robot.LL = score
802 K0s = [array(mi.fastmodel.K0, copy=True) for mi in self.robot.workspaces[0].param.modelinfo]
803 K1s = [array(mi.fastmodel.K1, copy=True) for mi in self.robot.workspaces[0].param.modelinfo]
804 K2s = [array(mi.fastmodel.K2, copy=True) for mi in self.robot.workspaces[0].param.modelinfo]
805 rest = ([array(mi.fastmodel.amp, copy=True) for mi in self.robot.workspaces[0].param.modelinfo],
806 [numpy.sqrt(array(mi.fastmodel.var, copy=True)) for mi in self.robot.workspaces[0].param.modelinfo],
807 [mi.fastmodel.amp0 for mi in self.robot.workspaces[0].param.modelinfo],
808 [sqrt(mi.fastmodel.var0) for mi in self.robot.workspaces[0].param.modelinfo],
809 [mi.fastmodel.Nchannel for mi in self.robot.workspaces[0].param.modelinfo])
810 gobject.idle_add(self.__onIteration, iterations, - score, grads, self.robot.optNchannel,
811 self.robot.workspaces, self.robot.workspaces[0].param.modelinfo,
812 K0s, K1s, K2s, *rest)
814 if (not force) and self.optimizing and self.accel:
815 if (datetime.datetime.now() - self.__last_fits_time).seconds < MIN_SECONDS_BETWEEN_FIT:
816 return
817 if (not self.recursive_fit) and hasattr(qubx.global_namespace.QubX.Modeling, 'MacRates'):
818 MacRates = qubx.global_namespace.QubX.Modeling.MacRates
819 if not MacRates.live:
820 MacRates.live = True
821 MacRates.live = False
822 return
823 self.__last_fits_time = datetime.datetime.now()
824 self.__last_fits_iter = iteration
825 self.fitbot.serial += 1
826 for data in self.robot.data:
827
828 chunks = []
829 samples = data.get_buffer()
830 Ndata = data.Ndata
831 start = 0
832 for firsts, lasts, count in data.ff_ll_counts:
833 means = numpy.array(samples[start:start+count, 0], copy=True)
834 stds = numpy.sqrt(array(samples[start:start+count, 1]))
835
836
837 chunks.append((firsts, lasts, means, stds))
838 start += count
839 self.fitbot.do(self.fitbot_set_fits, data.file, data.iSignal, chunks, self.fitbot.serial)
841 gobject.idle_add(self.outStatus.write, s+"\n")
843
844 if serial == self.fitbot.serial:
845 gobject.idle_add(self.do_set_fits, datafile, iSignal, chunks)
846 self.fitbot.last_serial = serial
848 fits = datafile.fits[iSignal].idl
849 fits.clear()
850 for ff, ll, mm, ss in chunks:
851 fits.set_fit(ff, ll, mm, ss)
852 datafile.OnChangeFits(datafile, iSignal)
853
856
857 def set_rates(*K012s):
858 for prep, K012 in itertools.izip(mp.preps, K012s):
859 prep.K0, prep.K1, prep.K2 = K012
860 K012ToModel(prep.K0, prep.K1, prep.K2, prep.model)
861 return set_rates
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882