Пример #1
0
 def prepareTaskStart(self):
     ## check power before starting task.
     if self.ui.checkPowerCheck.isChecked():
         power = self.dev.outputPower()  ## request current power from laser
         valid = self.dev.checkPowerValidity(power)
         if power is None:
             raise HelpfulException(
                 "The current laser power for '%s' is unknown." %
                 self.dev.name)
         if not valid:
             powerStr = siFormat(power, suffix='W')
             raise HelpfulException(
                 "The current laser power for '%s' (%s) is outside the expected range."
                 % (self.dev.name(), powerStr))
Пример #2
0
 def saveMA(self, fileName=None):
     if self.imgData is None:
         raise HelpfulException("There is no processed data to save.")
     if fileName is None:
         dh = self.getElement("File Loader").baseDir().name()
         self.fileDialog = FileDialog(None, "Save image data", dh, '*.ma')
         self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
         self.fileDialog.show()
         self.fileDialog.fileSelected.connect(self.saveMA)
         return  
     
     table = self.dbquery.table()
     x = table['xPos'].min()
     y = table['yPos'].min()        
     
     #print "params:", self.imgData.dtype.names
     #print "shape:", self.imgData.shape
     #arr = MetaArray(self.currentData) ### need to format this with axes and info
     arr = MetaArray([self.imgData[p] for p in self.imgData.dtype.names], info=[
         {'name':'vals', 'cols':[{'name':p} for p in self.imgData.dtype.names]},
         {'name':'xPos', 'units':'m', 'values':np.arange(self.imgData.shape[0])*self.spacing+x},
         {'name':'yPos', 'units':'m', 'values':np.arange(self.imgData.shape[1])*self.spacing+y},
         
         {'spacing':self.spacing}
     ]) 
     
     arr.write(fileName)    
Пример #3
0
    def generateTask(self, dh, params=None, progressDlg=None):
        #prof = Profiler("Generate Task: %s" % str(params))
        ## Never put {} in the function signature
        if params is None:
            params = {}
        prot = {'protocol': self.protoStateGroup.state()}

        # Disable timeouts for these tasks because we don't know how long to wait
        # for external triggers. TODO: use the default timeout, but also allow devices
        # in the task to modify the default.
        prot['protocol']['timeout'] = None

        #prof.mark('protocol state')
        store = (dh is not None)
        prot['protocol']['storeData'] = store
        if store:
            if params != {}:
                name = '_'.join(map(lambda i: '%03d'%i, params.values()))
                #print "mkdir", name
                info = params.copy()
                info['dirType'] = 'Protocol'
                dh1 = dh.mkdir(name, info=info)
                #prof.mark('create storage dir')
            else:
                dh1 = dh
            prot['protocol']['storageDir'] = dh1
        #prof.mark('selected storage dir.')
        prot['protocol']['name'] = self.currentTask.fileName
        
        for d in self.currentTask.devices:
            if self.currentTask.deviceEnabled(d):
                ## select out just the parameters needed for this device
                p = dict([(i[1], params[i]) for i in params.keys() if i[0] == d])
                ## Ask the device to generate its task command
                if d not in self.docks:
                    raise HelpfulException("The device '%s' currently has no dock loaded." % d,
                                           reasons=[
                                               "This device name does not exist in the system's configuration",
                                               "There was an error when creating the device at program startup",
                                               ],
                                           tags={},
                                           importance=8,

                                           docSections=['userGuide/modules/TaskRunner/loadingNonexistentDevices']
                                           )
                prot[d] = self.docks[d].widget().generateTask(p)
                #prof.mark("get task from %s" % d)
        #print prot['protocol']['storageDir'].name()
        
        if progressDlg is not None:
            progressDlg.setValue(progressDlg.value()+1)
            ## only do UI updates every 1 sec.
            now = ptime.time()
            if now - self.lastQtProcessTime > 1.0:
                self.lastQtProcessTime = now
                QtGui.QApplication.processEvents()
            if progressDlg.wasCanceled():
                raise Exception("Target sequence computation canceled by user.")
        #prof.mark('done')
        return prot
Пример #4
0
    def mapToScanner(self, x, y, laser, opticState=None):
        """Convert global coordinates to voltages required to set scan mirrors
        *laser* and *opticState* are used to look up the correct calibration data.
        If *opticState* is not given, then the current optical state is used instead.
        """
        if opticState is None:
            opticState = self.getDeviceStateKey(
            )  ## this tells us about objectives, filters, etc
        cal = self.getCalibration(laser, opticState)

        if cal is None:
            raise HelpfulException(
                "The scanner device '%s' is not calibrated for this combination of laser and objective (%s, %s)"
                % (self.name(), laser, str(opticState)))

        ## map from global coordinates to parent
        parentPos = self.mapGlobalToParent((x, y))
        if isinstance(parentPos, Qt.QPointF):
            x = parentPos.x()
            y = parentPos.y()
        else:
            x = parentPos[0]
            y = parentPos[1]

        ## map to voltages using calibration
        cal = cal['params']
        x2 = x**2
        y2 = y**2
        x1 = cal[0][0] + cal[0][1] * x + cal[0][2] * y + cal[0][3] * x2 + cal[
            0][4] * y2
        y1 = cal[1][0] + cal[1][1] * x + cal[1][2] * y + cal[1][3] * x2 + cal[
            1][4] * y2
        #print "voltage:", x1, y1
        return [x1, y1]
Пример #5
0
 def pointSize(self):
     ## returns (calibrated spot size, requested display size)
     try:
         #camMod = self.cameraModule()
         #if camMod is None:
             #return (1,1)
         #cam = camMod.config['camDev']
         laser = self.getLaser()
         cal = self.dev.getCalibration(laser)
         ss = cal['spot'][1]
         
         
     except:
         #logMsg("Could not find spot size from calibration.", msgType='error') ### This should turn into a HelpfulException.
         exc = sys.exc_info()
         raise HelpfulException("Could not find spot size from calibration. ", exc=exc, reasons=["Correct camera and/or laser device are not selected.", "There is no calibration file for selected camera and laser."], errId=1)
         
     if self.ui.sizeFromCalibrationRadio.isChecked():
         displaySize = ss
         ## reconnecting before this to get around reload errors, breaks the disconnect
         #try:
             #self.ui.sizeSpin.valueChanged.disconnect(self.sizeSpinEdited)
         #except TypeError:
             #logExc("A TypeError was caught in ScannerTaskGui.pointSize(). It was probably caused by a reload.", msgType='status', importance=0)
         self.stateGroup.setState({'spotSize':ss})
         #self.ui.sizeSpin.valueChanged.connect(self.sizeSpinEdited)
         self.displaySize[(laser, self.currentOpticState)] = None
     elif self.ui.sizeCustomRadio.isChecked():
         displaySize = self.ui.sizeSpin.value()
         self.displaySize[(laser, self.currentOpticState)] = displaySize
         
     return (ss, displaySize)
Пример #6
0
 def makeError2(self):
     try:
         print(y)
     except:
         t, exc, tb = sys.exc_info()
         raise HelpfulException(message='msg from makeError',
                                exc=(t, exc, tb),
                                reasons=["reason one", "reason 2"],
                                docs=['what, you expect documentation?'])
Пример #7
0
 def setWavelength(self, wl):
     """Set the laser's wavelength (if tunable).
     Arguments:
       wl:  """
     raise HelpfulException(
         "%s device does not support wavelength tuning." % str(self.name()),
         reasons=[
             "Hardware doesn't support tuning.",
             "setWavelenth function is not reimplemented in subclass."
         ])
Пример #8
0
    def addItem(self, itemType, state=None):
        
        if state is None:
            state = {}
            
        if state.get('name', None) is None:
            state['name'] = self.getNextItemName(itemType)
            
        try:
            ptSize, dispSize = self.pointSize()
        except HelpfulException as ex:
            exc = sys.exc_info()
            if ex.kwargs.get('errId', None) == 1:
                raise HelpfulException('Cannot add items: %s is not calibrated for %s.' %(str(self.ui.laserCombo.currentText()), self.currentOpticState), exc=exc)
            else:
                raise
            
        state['ptSize'] = dispSize
        
        cls = {'Grid': Grid, 'Point': TargetPoint, 'Occlusion': TargetOcclusion}[itemType]
        item = cls(**state)
        
        camMod = self.cameraModule()
        if camMod is None:
            raise HelpfulException("Cannot add control items until a camera module is available to display them.")
            return False

        item.opticState = self.currentOpticState
        self.items[item.name] = item
        
        pos = state.get('pos', None)  ## if no position is given, the camera will automatically place the item in the middle fo the view
        camMod.ui.addItem(item, pos, [1, 1], 1000)
            
        self.positionCtrlGroup.addChild(item.parameters())
        
        item.sigStateChanged.connect(self.itemChanged)
        item.parameters().sigValueChanged.connect(self.itemActivationChanged)
        
        self.itemChanged(item)
        self.storeConfiguration()
Пример #9
0
    def storeDBScan(self, scan, storeEvents=True):
        """Store all data for a scan, using cached values if possible"""
        p = debug.Profiler("Photostim.storeDBScan", disabled=True)

        if storeEvents:
            self.clearDBScan(scan)

        with pg.BusyCursor():
            #dh = scan.source()
            #print "Store scan:", scan.source().name()
            events = []
            stats = []
            spots = scan.spots()
            with pg.ProgressDialog("Preparing data for %s" % scan.name(), 0,
                                   len(spots) + 1) as dlg:

                ## collect events and stats from all spots in the scan
                for i in xrange(len(spots)):
                    s = spots[i]
                    fh = self.dataModel.getClampFile(s.data())
                    try:
                        ev = scan.getEvents(fh)['events']
                        events.append(ev)
                    except:
                        print fh, scan.getEvents(fh)
                        raise
                    st = scan.getStats(s.data())
                    stats.append(st)
                    dlg.setValue(i)
                    if dlg.wasCanceled():
                        raise HelpfulException("Scan store canceled by user.",
                                               msgType='status')

                p.mark("Prepared data")

            dbui = self.getElement('Database')
            db = dbui.getDb()
            with db.transaction():
                ## Store all events for this scan
                if storeEvents:
                    events = [x for x in events if len(x) > 0]

                    if len(events) > 0:
                        ev = np.concatenate(events)
                        p.mark("concatenate events")
                        self.detector.storeToDB(ev)
                        p.mark("stored all events")

                ## Store spot data
                self.storeStats(stats)
                p.mark("stored all stats")
                p.finish()
Пример #10
0
    def storeStats(self, data):
        ## Store a list of dict records, one per spot.
        ## data: {'SourceFile': clamp file handle, 'xPos':, 'yPos':, ...other fields from stats flowchart...}
        ## parentDir: protocolSequence dir handle (or protocol for single spots)

        #print "Store stats:", fh

        ## If only one record was given, make it into a list of one record
        if isinstance(data, dict):
            data = [data]

        dbui = self.getElement('Database')
        identity = self.dbIdentity + '.sites'
        table = dbui.getTableName(identity)
        db = dbui.getDb()

        if db is None:
            raise Exception("No DB selected")

        ## determine the set of fields we expect to find in the table

        fields = db.describeData(data)

        ## override directory fields since describeData can't guess these for us
        fields['ProtocolDir'] = 'directory:Protocol'
        fields['ProtocolSequenceDir'] = 'directory:ProtocolSequence'

        with db.transaction():
            ## Make sure target table exists and has correct columns, links to input file
            db.checkTable(table,
                          owner=identity,
                          columns=fields,
                          create=True,
                          addUnknownColumns=True,
                          indexes=[['ProtocolDir'], ['ProtocolSequenceDir']])

            # delete old
            for source in set([d['ProtocolDir'] for d in data]):
                #name = rec['SourceFile']
                db.delete(table, where={'ProtocolDir': source})

            # write new
            with pg.ProgressDialog("Storing spot stats...", 0, 100) as dlg:
                for n, nmax in db.iterInsert(table, data, chunkSize=30):
                    dlg.setMaximum(nmax)
                    dlg.setValue(n)
                    if dlg.wasCanceled():
                        raise HelpfulException("Scan store canceled by user.",
                                               msgType='status')
Пример #11
0
    def runSingle(self, store=True):

        if self.protoStateGroup.state()['loop']:
            self.loopEnabled = True

        # good time to collect garbage
        gc.collect()

        self.lastProtoTime = ptime.time()
        ## Disable all start buttons
        self.enableStartBtns(False)

        ## Set storage dir
        try:
            if store:
                currentDir = self.manager.getCurrentDir()
                name = self.currentTask.name()
                if name is None:
                    name = 'protocol'
                info = self.taskInfo()
                info['dirType'] = 'Protocol'
                ## Create storage directory with all information about the task to be executed
                dh = currentDir.mkdir(name, autoIncrement=True, info=info)
            else:
                dh = None

            ## Tell devices to prepare for task start.
            for d in self.currentTask.devices:
                if self.currentTask.deviceEnabled(d):
                    self.docks[d].widget().prepareTaskStart()

            ## Generate executable conf from task object
            prot = self.generateTask(dh)
            #print prot
            self.sigTaskSequenceStarted.emit({})
            #print "runSingle: Starting taskThread.."
            self.taskThread.startTask(prot)
            #print "runSingle: taskThreadStarted"
        except:
            exc = sys.exc_info()
            self.enableStartBtns(True)
            self.loopEnabled = False
            #print "Error starting task. "
            raise HelpfulException("Error occurred while starting task",
                                   exc=exc)
Пример #12
0
 def makeError1(self):
     try:
         self.makeError2()
         #print x
     except:
         t, exc, tb = sys.exc_info()
         #logExc(message="This button doesn't work", reasons='reason a, reason b', docs='documentation')
         #if isinstance(exc, HelpfulException):
         #exc.prependErr("Button doesn't work", (t,exc,tb), reasons = ["It's supposed to raise an error for testing purposes", "You're doing it wrong."])
         #raise
         #else:
         raise HelpfulException(
             message='This button does not work.',
             exc=(t, exc, tb),
             reasons=[
                 "It's supposed to raise an error for testing purposes",
                 "You're doing it wrong."
             ])
Пример #13
0
    def setData(self, arr=None, xPos=None, yPos=None, numOfPostEvents=None):
        if arr is not None:
            self.checkArrayInput(arr)
            self.populateEventsCombo(arr)
            fields = arr.dtype.names
            if 'xPos' not in fields or 'yPos' not in fields:
                raise HelpfulException(
                    "Array input to Spatial correlator needs to have the following fields: 'xPos', 'yPos'"
                )
        elif arr is None:
            self.data = None
            return

        self.data = np.zeros(len(arr),
                             dtype=arr.dtype.descr + [('prob', float)])
        self.data[:] = arr

        if 'numOfPreEvents' in fields and 'PreRegionLen' in fields:
            self.calculateSpontRate()
        if 'PostRegionLen' in fields:
            self.ctrl.deltaTSpin.setValue(self.data['PostRegionLen'][0])

        self.process()
Пример #14
0
    def scan(self):
        """Scan over x and y ranges in a nPts x nPts grid, return the image recorded at each location."""
        camera = str(self.ui.cameraCombo.currentText())
        laser = str(self.ui.laserCombo.currentText())
        
        ## Camera settings to use during scan
        camParams = self.dev.getCameraConfig(camera)        
        
        duration = self.ui.scanDurationSpin.value()
        rate = 10000
        nPts = int(rate * duration)
        sweeps = 20

        #cameraTrigger = ones(nPts, dtype=byte)

        ##(cmdMin, cmdMax) = self.dev.config['commandLimits']
        xRange = (self.ui.xMinSpin.value(), self.ui.xMaxSpin.value())
        yRange = (self.ui.yMinSpin.value(), self.ui.yMaxSpin.value())
        xDiff = xRange[1] - xRange[0]
        yDiff = yRange[1] - yRange[0]
        
        xCommand = np.fromfunction(lambda i: xRange[0] + ((xDiff * i * float(sweeps) / nPts) % xDiff), (nPts,), dtype=float)
        xCommand[-1] = 0.0
        yCommand = np.empty((nPts,), dtype=float)
        start = 0
        for i in range(sweeps):
            stop = start + (nPts / sweeps)
            yCommand[start:stop] = yRange[0] + yDiff * (float(i)/(sweeps-1))
            start = stop
        yCommand[-1] = 0.0
        daqName = self.dev.config['XAxis']['device']

        ## Record 10 camera frames with the shutter closed 
        #print "parameters:", camParams
        cmd = {
            'protocol': {'duration': 0.0, 'timeout': 5.0},
            camera: {'record': True, 'minFrames': 10, 'params': camParams, 'pushState': 'scanProt'}, 
            #laser: {'Shutter': {'preset': 0, 'holding': 0}}
        }
        #print "\n\n====> Record background\n"
        task = acq4.Manager.getManager().createTask(cmd)
        task.execute()
        result = task.getResult()
        ## pull result, convert to ndarray float, take average over all frames
        background = result[camera].asArray().astype(float).mean(axis=0)
        #print "Background shape:", result[camera]['frames'].shape
        
        ## Record full scan.
        cmd = {
            'protocol': {'duration': duration, 'timeout': duration+5.0},
            camera: {'record': True, 'triggerProtocol': True, 'params': camParams, 'channels': {
                'exposure': {'record': True}, 
                },
                'popState': 'scanProt'},
            #laser: {'shutter': {'preset': 0, 'holding': 0, 'command': np.ones(len(xCommand), dtype=byte)}},
            laser: {'alignMode': True},
            self.dev.name(): {'xCommand': xCommand, 'yCommand': yCommand},
            daqName: {'numPts': nPts, 'rate': rate, 'triggerDevice': camera}
        }
        #print "\n\n====> Scan\n"
        task = acq4.Manager.getManager().createTask(cmd)
        task.execute(block=False)
        with pg.ProgressDialog("Calibrating scanner: Running scan protocol..", 0, 100) as dlg:
            while not task.isDone():
                dlg.setValue(100.*task.runTime()/task.duration())
                if dlg.wasCanceled():
                    task.abort()
                    raise HelpfulException('Calibration canceled by user.', msgType='warning')
                time.sleep(0.2)
        
        result = task.getResult()
        
        frames = result[camera].asMetaArray()
        if frames._info[-1]['preciseTiming'] is not True:
            raise HelpfulException("Calibration could not accurately measure camera frame timing.",
                                   reasons=["The exposure signal from the camera was not recorded by the DAQ."])
        #print "scan shape:", frames.shape
        #print "parameters:", camParams
        
        ## Generate a list of the scanner command values for each frame
        positions = []
        for i in range(frames.shape[0]):
            t = frames.xvals('Time')[i]
            ind = int((t/duration) * nPts)
            if ind >= len(xCommand):
                break
            positions.append([xCommand[ind], yCommand[ind]])
            
        if frames.ndim != 3 or frames.shape[0] < 5:
            raise Exception("Camera did not collect enough frames (data shape is %s)" % str(frames.shape))
            
        if background.shape != frames.shape[1:]:
            raise Exception("Background measurement frame has different shape %s from scan frames %s" % (str(background.shape), str(frames.shape[1:])))
        
        return (background, result[camera], positions)
Пример #15
0
    def runCalibration(self):
        """The scanner calibration routine:
            1) Measure background frame, then scan mirrors 
               while collecting frames as fast as possible (self.scan())
            2) Locate spot in every frame using gaussian fit
            3) Map image spot locations to coordinate system of Scanner device's parent
            3) Do parabolic fit to determine mapping between voltage and position
        """
        camera = str(self.ui.cameraCombo.currentText())
        laser = str(self.ui.laserCombo.currentText())
        blurRadius = 5
        
        ## Do fast scan of entire allowed command range
        (background, cameraResult, positions) = self.scan()
        #self.calibrationResult = {'bg': background, 'frames': cameraResult, 'pos': positions}

        with pg.ProgressDialog("Calibrating scanner: Computing spot positions...", 0, 100) as dlg:
            dlg.show()
            dlg.raise_()  # Not sure why this is needed here..

            ## Forget first 2 frames since some cameras can't seem to get these right.
            frames = cameraResult.asArray()
            frames = frames[2:]
            positions = positions[2:]
            
            ## Do background subtraction
            ## take out half the data until it can do the calculation without having a MemoryError.
            finished = False
            gc.collect()
            while not finished:
                try:
                    frames = frames.astype(np.float32)
                    frames -= background.astype(np.float32)
                    finished=True
                except MemoryError:
                    frames = frames[::2,:,:]
                    positions = positions[::2]
                    finished = False
                
            ## Find a frame with a spot close to the center (within center 1/3)
            cx = frames.shape[1] / 3
            cy = frames.shape[2] / 3
            centerSlice = blur(frames[:, cx:cx*2, cy:cy*2], (0, 5, 5)).max(axis=1).max(axis=1)
            maxIndex = argmax(centerSlice)
            maxFrame = frames[maxIndex]
            dlg.setValue(5)

            ## Determine spot intensity and width
            mfBlur = blur(maxFrame, blurRadius)
            amp = mfBlur.max() - median(mfBlur)  ## guess intensity of spot
            (x, y) = argwhere(mfBlur == mfBlur.max())[0]   ## guess location of spot
            fit = fitGaussian2D(maxFrame, [amp, x, y, maxFrame.shape[0] / 10, 0.])[0]  ## gaussian fit to locate spot exactly
            # convert sigma to full width at 1/e
            fit[3] = abs(2 * (2 ** 0.5) * fit[3]) ## sometimes the fit for width comes out negative. *shrug*
            someFrame = cameraResult.frames()[0]
            frameTransform = pg.SRTTransform(someFrame.globalTransform())
            pixelSize = someFrame.info()['pixelSize'][0]
            spotAmplitude = fit[0]
            spotWidth = abs(fit[3] * pixelSize)
            size = self.spotSize(mfBlur)
            dlg.setValue(50)

            ## Determine location of spot within each frame, 
            ## ignoring frames where the spot is too dim or too close to the frame edge
            spotLocations = []
            globalSpotLocations = []
            spotCommands = []
            spotFrames = []
            margin = fit[3]
            
            for i in range(len(positions)):
                dlg.setValue(50. + 50. * i / frames.shape[0])
                if dlg.wasCanceled():
                    raise HelpfulException('Calibration canceled by user.', msgType='warning')

                frame = frames[i]
                fBlur = blur(frame.astype(np.float32), blurRadius)
    
                mx = fBlur.max()
                diff = mx - fBlur.min()
                ss = self.spotSize(fBlur)
                if ss < size * 0.6:
                    #print "Ignoring spot:", ss
                    continue
                #else:
                    #print "Keeping spot:", ss
                    
                (x, y) = argwhere(fBlur == mx)[0]   # guess location of spot
                if x < margin or x > frame.shape[0] - margin:
                    #print "   ..skipping; too close to edge", x, y
                    continue
                if y < margin or y > frame.shape[1] - margin:
                    #print "   ..skipping; too close to edge", x, y
                    continue
                
                frame[x,y] = -1  ## mark location of peak in image
                
                ## convert pixel location to coordinate system of scanner's parent
                globalPos = frameTransform.map(pg.Point(x, y))  ## Map from frame pixel location to global coordinates
                localPos = self.dev.mapGlobalToParent(globalPos)  ## map from global to parent coordinate system. This is the position we calibrate to.
                #print (x, y), (globalPos.x(), globalPos.y()), (localPos.x(), localPos.y())
                
                spotLocations.append([localPos.x(), localPos.y()])
                globalSpotLocations.append([globalPos.x(), globalPos.y()])
                spotCommands.append(positions[i])
                spotFrames.append(frame[newaxis])
        
        ## sanity check on spot frame
        if len(spotFrames) == 0:
            self.ui.view.setImage(frames)
            raise HelpfulException('Calibration never detected laser spot!  Looking for spots that are %f pixels wide.'% fit[3], reasons=['shutter is disabled', 'mirrors are disabled', 'objective is not clean', 'spot is not visible or not bright enough when shutter is open'])

        spotFrameMax = concatenate(spotFrames).max(axis=0)
        self.ui.view.setImage(spotFrameMax, transform=frameTransform)
        
        self.clearSpots()
        for sl in globalSpotLocations:
            #self.addSpot(sl, fit[3]*binning[0])
            self.addSpot(sl, spotWidth)
        self.ui.view.autoRange()
        
        if len(spotFrames) < 10:
            raise HelpfulException('Calibration detected only %d frames with laser spot; need minimum of 10.' % len(spotFrames), reasons=['spot is too dim for camera sensitivity', 'objective is not clean', 'mirrors are scanning too quickly', 'mirror scanning region is not within the camera\'s view'])
        
        ## Fit all data to a map function
        mapParams = self.generateMap(array(spotLocations), array(spotCommands))
        #print 
        #print "Map parameters:", mapParams
        
        if spotWidth < 0:
            raise Exception()
        return (mapParams, (spotAmplitude, spotWidth))
Пример #16
0
    def runOnce(self, params=None):
        # good time to collect garbage
        gc.collect()

        prof = Profiler("TaskRunner.TaskThread.runOnce",
                        disabled=True,
                        delayed=False)
        startTime = ptime.time()
        if params is None:
            params = {}

        ## Select correct command to execute
        cmd = self.task
        if params is not None:
            for p in params:
                cmd = cmd[p:params[p]]
        prof.mark('select command')

        ## Wait before starting if we've already run too recently
        while (self.lastRunTime
               is not None) and (ptime.time() < self.lastRunTime +
                                 cmd['protocol']['cycleTime']):
            with self.lock:
                if self.abortThread or self.stopThread:
                    #print "Task run aborted by user"
                    return
            time.sleep(1e-3)
        prof.mark('sleep')

        emitSig = True
        while True:
            with self.lock:
                if self.abortThread or self.stopThread:
                    return
                pause = self.paused
            if not pause:
                break
            if emitSig:
                emitSig = False
                self.sigPaused.emit()
            time.sleep(10e-3)

        prof.mark('pause')

        if type(cmd) is not dict:
            print("========= TaskRunner.runOnce cmd: ==================")
            print(cmd)
            print("========= TaskRunner.runOnce params: ==================")
            print("Params:", params)
            print("===========================")
            raise Exception(
                "TaskRunner.runOnce failed to generate a proper command structure. Object type was '%s', should have been 'dict'."
                % type(cmd))

        task = self.dm.createTask(cmd)
        prof.mark('create task')

        self.lastRunTime = ptime.time()

        try:
            with self.lock:
                self._currentTask = task
            task.execute(block=False)
            # record estimated end time
            endTime = time.time() + cmd['protocol']['duration']
            self.sigTaskStarted.emit(params)
            prof.mark('execute')
        except:
            with self.lock:
                self._currentTask = None
            try:
                task.stop(abort=True)
            except:
                pass
            printExc("\nError starting task:")
            exc = sys.exc_info()
            raise HelpfulException("\nError starting task:", exc)

        prof.mark('start task')
        ### Do not put code outside of these try: blocks; may cause device lockup

        try:
            ## wait for finish, watch for abort requests
            while True:
                if task.isDone():
                    prof.mark('task done')
                    break
                with self.lock:
                    if self.abortThread:
                        # should be taken care of in TaskThread.abort()
                        # NO -- task.stop() is not thread-safe.
                        task.stop(abort=True)
                        return
                # adjust sleep time based on estimated time remaining in the task.
                sleep = np.clip((endTime - time.time()) * 0.5, 1e-3, 20e-3)
                time.sleep(sleep)

            result = task.getResult()
        except:
            ## Make sure the task is fully stopped if there was a failure at any point.
            #printExc("\nError during task execution:")
            print("\nStopping task..")
            task.stop(abort=True)
            print("")
            raise HelpfulException("\nError during task execution:",
                                   sys.exc_info())
        finally:
            with self.lock:
                self._currentTask = None
        prof.mark('getResult')

        frame = {'params': params, 'cmd': cmd, 'result': result}
        self.sigNewFrame.emit(frame)
        prof.mark('emit newFrame')
        if self.stopThread:
            raise Exception('stop', result)

        ## Give everyone else a chance to catch up
        Qt.QThread.yieldCurrentThread()
        prof.mark('yield')
        prof.finish()
Пример #17
0
    def getChannelCmds(self, cmd, rate):
        ### cmd is a dict and can contain 'powerWaveform' or 'switchWaveform' keys with the array as a value

        if 'switchWaveform' in cmd:
            cmdWaveform = cmd['switchWaveform']
            vals = np.unique(cmd['switchWaveform'])
            if not self.hasPCell and len(vals) == 2 and (
                    1 or 1.0
            ) not in vals:  ## check to make sure we can give the specified power.
                raise Exception(
                    'An analog power modulator is neccessary to get power values other than zero and one (full power). The following values (as percentages of full power) were requested: %s. This %s device does not have an analog power modulator.'
                    % (str(vals), self.name()))
        elif 'powerWaveform' in cmd:
            cmdWaveform = cmd['powerWaveform']
        else:
            raise Exception(
                'Not sure how to generate channel commands for %s' % str(cmd))

        nPts = len(cmdWaveform)
        daqCmd = {}
        #if self.dev.config.get('pCell', None) is not None:
        if self.hasPCell:
            ## convert power values using calibration data
            if 'switchWaveform' in cmd:
                with self.variableLock:
                    if self.params['useExpectedPower']:
                        power = self.params['expectedPower']
                    else:
                        power = self.params['currentPower']
                    transmission = self.params['scopeTransmission']
                    if transmission is None:
                        raise Exception(
                            'Power transmission has not been calibrated for "%s" with the current optics and wavelength.'
                            % self.name())
                    #transmission = 0.1
                powerCmd = cmd['switchWaveform'] * power * transmission
            else:
                powerCmd = cmd['powerWaveform']
            daqCmd['pCell'] = self.getPCellWaveform(powerCmd, cmd)
        else:
            if len(
                    np.unique(cmdWaveform)
            ) > 2:  ## check to make sure command doesn't specify powers we can't do
                raise Exception(
                    "%s device does not have an analog power modulator, so can only have a binary power command."
                    % str(self.name()))

        if self.hasQSwitch:
            #if self.dev.config.get('qSwitch', None) is not None:
            qswitchCmd = np.zeros(nPts, dtype=np.byte)
            qswitchCmd[cmdWaveform > 1e-5] = 1
            daqCmd['qSwitch'] = qswitchCmd

        if self.hasTriggerableShutter:
            shutterCmd = np.zeros(nPts, dtype=np.byte)
            delay = self.config['shutter'].get('delay', 0.0)
            shutterCmd[
                cmdWaveform != 0] = 1  ## open shutter when we expect power
            ## open shutter a little before we expect power because it has a delay
            delayPts = int(delay * rate)
            a = np.argwhere(shutterCmd[1:] - shutterCmd[:-1] == 1) + 1
            for i in a:
                start = i - delayPts
                if start < 0:
                    print start, delayPts, i
                    raise HelpfulException(
                        "Shutter takes %g seconds to open. Power pulse cannot be started before then."
                        % delay)
                shutterCmd[start:i + 1] = 1
            daqCmd['shutter'] = shutterCmd

        return daqCmd
Пример #18
0
    def checkArrayInput(self, arr):
        fields = arr.dtype.names
        if 'xPos' not in fields or 'yPos' not in fields or 'numOfPostEvents' not in fields:
            raise HelpfulException(
                "Array input needs to have the following fields: 'xPos', 'yPos', 'numOfPostEvents'. Current fields are: %s"
                % str(fields))
        else:
            return True

    #@staticmethod
    #def bendelsSpatialCorrelationAlgorithm(data, radius, spontRate, timeWindow):
    #SpatialCorrelator.checkArrayInput(data) ## check that data has 'xPos', 'yPos' and 'numOfPostEvents'

    ### add 'prob' field to data array
    #if 'prob' not in data.dtype.names:
    #arr = np.zeros(len(data), dtype=data.dtype.descr + [('prob', float)])
    #arr[:] = data
    #data = arr
    #else:
    #data['prob']=0

    ### spatial correlation algorithm from :
    ### Bendels, MHK; Beed, P; Schmitz, D; Johenning, FW; and Leibold C. Etection of input sites in
    ### scanning photostimulation data based on spatial correlations. 2010. Journal of Neuroscience Methods.

    ### calculate probability of seeing a spontaneous event in time window
    #p = 1-np.exp(-spontRate*timeWindow)

    ### for each spot, calculate the probability of having the events in nearby spots occur randomly
    #for x in data:
    #spots = data[(np.sqrt((data['xPos']-x['xPos'])**2+(data['yPos']-x['yPos'])**2)) < radius]
    #nSpots = len(spots)
    #nEventSpots = len(spots[spots['numOfPostEvents'] > 0])

    #prob = 0
    #for j in range(nEventSpots, nSpots+1):
    #prob += ((p**j)*((1-p)**(nSpots-j))*math.factorial(nEventSpots))/(math.factorial(j)*math.factorial(nSpots-j))
    ##j = arange(nEventSponts, nSpots+1)
    ##prob = (((p**j)*((1-p)**(nSpots-j))*np.factorial(nEventSpots))/(np.factorial(j)*np.factorial(nSpots-j))).sum() ## need a factorial function that works on arrays

    #x['prob'] = prob

    #return data


#class SpatialOutline(pg.GraphicsObject):

#def __init__(self, parent=None, pen=None, spots=None, radius=25e-6):
#pg.GraphicsObject.__init__(self, parent)

#if pen is None:
#pen = (255, 255, 255)
#self.setPen(pen)

#self.path = Qt.QPainterPath()
#self.spots = spots
#self.radius = radius
#if spots is not None:
#self.makePath()

#def setData(self, spots):
#self.spots = spots
#self.makePath()
#self.update(self.boundingRect())

#def setRadius(self, radius):
#self.radius = radius
#self.makePath()
#self.update(self.boundingRect())

#def setPen(self, pen):
#self.pen = pg.mkPen(pen)
#self.currentPen = self.pen
#self.update()

#def makePath(self):
#if self.spots is None:
#return
#path = Qt.QPainterPath()
#for s in self.spots:
#path.addEllipse(s['xPos'], s['yPos'], self.radius, self.radius)

##pps = Qt.QPainterPathStroker()

##self.path = pps.createStroke(path)
#self.path=path

#def boundingRect(self):
#if self.spots is None:
#return Qt.QRectF()
##x = self.spots['xPos'].min()
##y = self.spots['yPos'].min()
##return Qt.QRectF(x,y , self.spots['xPos'].max()-x, self.spots['yPos'].max()-y)
##print "outline.boundingRect: ", self.path.boundingRect()
#return self.path.boundingRect()

#def paint(self, p, *args):
#p.setRenderHint(Qt.QPainter.Antialiasing)
##path = self.shape()
#p.setPen(self.currentPen)
#p.drawPath(self.path)
##p.setPen(Qt.QPen(Qt.QColor(255,0,0)))
##p.drawPath(self.shape())
#p.setPen(Qt.QPen(Qt.QColor(0,0,255)))
#p.drawRect(self.boundingRect())
Пример #19
0
    def __init__(self, manager, name, config):
        Module.__init__(self, manager, name, config)
        self.lastProtoTime = None
        self.loopEnabled = False
        self.devListItems = {}

        self.docks = {}
        self.firstDock = None  # all new docks should stack here
        self.analysisDocks = {}
        self.deleteState = 0
        self.ui = Ui_MainWindow()
        self.win = Window(self)

        g = self.win.geometry()
        self.ui.setupUi(self.win)
        self.win.setGeometry(g)
        self.win.setStatusBar(StatusBar())

        self.ui.protoDurationSpin.setOpts(dec=True,
                                          bounds=[1e-3, None],
                                          step=1,
                                          minStep=1e-3,
                                          suffix='s',
                                          siPrefix=True)
        self.ui.protoLeadTimeSpin.setOpts(dec=True,
                                          bounds=[0, None],
                                          step=1,
                                          minStep=10e-3,
                                          suffix='s',
                                          siPrefix=True)
        self.ui.protoCycleTimeSpin.setOpts(dec=True,
                                           bounds=[0, None],
                                           step=1,
                                           minStep=1e-3,
                                           suffix='s',
                                           siPrefix=True)
        self.ui.seqCycleTimeSpin.setOpts(dec=True,
                                         bounds=[0, None],
                                         step=1,
                                         minStep=1e-3,
                                         suffix='s',
                                         siPrefix=True)
        self.protoStateGroup = pg.WidgetGroup([
            (self.ui.protoContinuousCheck, 'continuous'),
            (self.ui.protoDurationSpin, 'duration'),
            (self.ui.protoLeadTimeSpin, 'leadTime'),
            (self.ui.protoLoopCheck, 'loop'),
            (self.ui.protoCycleTimeSpin, 'loopCycleTime'),
            (self.ui.seqCycleTimeSpin, 'cycleTime'),
            (self.ui.seqRepetitionSpin, 'repetitions', 1),
        ])

        try:
            try:
                taskDir = config['taskDir']
            except KeyError:
                taskDir = self.manager.config[
                    'protocolDir']  # for backward compatibility
            self.taskList = Loader(self, taskDir)
        except KeyError:
            raise HelpfulException(
                "Config is missing 'taskDir'; cannot load task list.")

        self.ui.LoaderDock.setWidget(self.taskList)

        self.currentTask = None  ## pointer to current task object

        for m in analysisModules.MODULES:
            item = Qt.QListWidgetItem(m, self.ui.analysisList)
            item.setFlags(Qt.Qt.ItemIsSelectable | Qt.Qt.ItemIsEnabled
                          | Qt.Qt.ItemIsUserCheckable)
            item.setCheckState(Qt.Qt.Unchecked)

        self.taskThread = TaskThread(self)

        self.newTask()

        self.ui.testSingleBtn.clicked.connect(self.testSingleClicked)
        self.ui.runTaskBtn.clicked.connect(self.runSingleClicked)
        self.ui.testSequenceBtn.clicked.connect(self.testSequence)
        self.ui.runSequenceBtn.clicked.connect(self.runSequenceClicked)
        self.ui.stopSingleBtn.clicked.connect(self.stopSingle)
        self.ui.stopSequenceBtn.clicked.connect(self.stopSequence)
        self.ui.pauseSequenceBtn.toggled.connect(self.pauseSequence)
        self.ui.deviceList.itemClicked.connect(self.deviceItemClicked)
        self.taskList.sigCurrentFileChanged.connect(
            self.fileChanged
        )  ## called if loaded task file is renamed or moved
        self.taskThread.finished.connect(self.taskThreadStopped)
        self.taskThread.sigNewFrame.connect(self.handleFrame)
        self.taskThread.sigPaused.connect(self.taskThreadPaused)
        self.taskThread.sigTaskStarted.connect(self.taskStarted)
        self.taskThread.sigExitFromError.connect(self.taskErrored)
        self.protoStateGroup.sigChanged.connect(self.protoGroupChanged)
        self.win.show()
        self.ui.sequenceParamList.itemChanged.connect(self.updateSeqReport)
        self.ui.analysisList.itemClicked.connect(self.analysisItemClicked)