Esempio n. 1
0
    def runRefineCTF(self, imgdata, fftpath):
        ### reset important values
        self.bestres = 1e10
        self.bestellipse = None
        self.bestvalues = {}

        self.volts = imgdata['scope']['high tension']
        self.wavelength = ctftools.getTEMLambda(self.volts)
        ## get value in meters
        self.cs = apInstrument.getCsValueFromSession(
            self.getSessionData()) * 1e-3
        self.ctfvalues = {
            'volts': self.volts,
            'wavelength': self.wavelength,
            'cs': self.cs,
        }

        ### need to get FFT file open and freq of said file
        fftarray = mrc.read(fftpath).astype(numpy.float64)
        self.freq = self.freqdict[fftpath]

        ### convert resolution limit into pixel distance
        fftwidth = fftarray.shape[0]
        maxres = 2.0 / (self.freq * fftwidth)
        if maxres > self.params['reslimit']:
            apDisplay.printWarning(
                "Cannot get requested res %.1fA higher than max Nyquist resolution %.1fA"
                % (self.params['reslimit'], maxres))
            self.params['reslimit'] = math.ceil(maxres)

        limitwidth = int(math.ceil(2.0 /
                                   (self.params['reslimit'] * self.freq)))
        limitwidth = primefactor.getNextEvenPrime(limitwidth)
        requestres = 2.0 / (self.freq * limitwidth)
        if limitwidth > fftwidth:
            apDisplay.printError("Cannot get requested resolution" + (
                " request res %.1fA higher than max res %.1fA for new widths %d > %d"
                % (requestres, maxres, limitwidth, fftwidth)))

        apDisplay.printColor(
            "Requested resolution OK: " +
            (" request res %.1fA less than max res %.1fA with fft widths %d < %d"
             % (requestres, maxres, limitwidth, fftwidth)), "green")
        newshape = (limitwidth, limitwidth)
        fftarray = imagefilter.frame_cut(fftarray, newshape)

        ### spacing parameters
        self.mfreq = self.freq * 1e10
        fftwidth = min(fftarray.shape)
        self.apix = 1.0 / (fftwidth * self.freq)
        self.ctfvalues['apix'] = self.apix

        ### print message
        bestDbValues = ctfdb.getBestCtfByResolution(imgdata)
        if bestDbValues is None:
            apDisplay.printColor(
                "SKIPPING: No CTF values for image %s" %
                (apDisplay.short(imgdata['filename'])), "red")
            self.badprocess = True
            return

        ### skip if resolution > 90.
        if bestDbValues['resolution_50_percent'] > 90.:
            apDisplay.printColor(
                "SKIPPING: No decent CTF values for image %s" %
                (apDisplay.short(imgdata['filename'])), "yellow")
            self.badprocess = True
            return

        self.ctfvalues['amplitude_contrast'] = bestDbValues[
            'amplitude_contrast']

        lowerrad1 = ctftools.getCtfExtrema(
            bestDbValues['defocus1'], self.mfreq, self.cs, self.volts,
            self.ctfvalues['amplitude_contrast'], 1, "valley")
        lowerrad2 = ctftools.getCtfExtrema(
            bestDbValues['defocus2'], self.mfreq, self.cs, self.volts,
            self.ctfvalues['amplitude_contrast'], 1, "valley")
        meanRad = (lowerrad1[0] + lowerrad2[0]) / 2.0

        self.ellipseParams = {
            'a': lowerrad1[0],
            'b': lowerrad2[0],
            'alpha': math.radians(bestDbValues['angle_astigmatism']),
        }
        ellipratio = self.ellipseParams['a'] / self.ellipseParams['b']
        defratio = bestDbValues['defocus2'] / bestDbValues['defocus1']
        print "ellr=%.3f, defr=%.3f, sqrt(defr)=%.3f" % (ellipratio, defratio,
                                                         math.sqrt(defratio))
        self.bestvalues['defocus'] = (bestDbValues['defocus1'] +
                                      bestDbValues['defocus2']) / 2.0

        raddata, PSDarray = self.from2Dinto1D(fftarray)
        lowerbound = numpy.searchsorted(raddata, meanRad * self.freq)
        upperbound = numpy.searchsorted(raddata, 1 / 10.)

        ###
        #	This is the start of the actual program
        ###

        self.refineEllipseLoop(fftarray, lowerbound, upperbound)

        ##==================================
        ## FINISH UP
        ##==================================

        apDisplay.printColor("Finishing up using best found CTF values",
                             "blue")
        self.printBestValues()

        ### take best values and use them
        self.ctfvalues = self.bestvalues
        self.ellipseParams = self.bestellipse

        ### stupid fix, get value in millimeters
        self.ctfvalues['cs'] = apInstrument.getCsValueFromSession(
            self.getSessionData())

        ### translate ellipse into ctf values
        if self.ellipseParams is not None:
            self.ctfvalues['angle_astigmatism'] = math.degrees(
                self.ellipseParams['alpha'])
            ellipratio = self.ellipseParams['a'] / self.ellipseParams['b']
            phi = math.asin(self.ctfvalues['amplitude_contrast'])
            #note: a > b then def1 < def2
            #major axis
            self.ctfvalues['defocus1'] = self.ctfvalues['defocus'] / ellipratio
            #minor axis
            self.ctfvalues['defocus2'] = self.ctfvalues['defocus'] * ellipratio

            defdiff = 1.0 - 2 * self.ctfvalues['defocus'] / (
                self.ctfvalues['defocus1'] + self.ctfvalues['defocus2'])
            print "%.3e --> %.3e,%.3e" % (self.ctfvalues['defocus'],
                                          self.ctfvalues['defocus2'],
                                          self.ctfvalues['defocus1'])
            print defdiff * 100
            if defdiff * 100 > 1:
                apDisplay.printWarning("Large astigmatism")
                #sys.exit(1)
        else:
            ellipratio = 1.0
            self.ctfvalues['angle_astigmatism'] = 0.0
            self.ctfvalues['defocus1'] = self.ctfvalues['defocus']
            self.ctfvalues['defocus2'] = self.ctfvalues['defocus']
            self.badprocess = True
            return

        try:
            if self.ctfvalues['amplitude_contrast'] < self.minAmpCon:
                self.ctfvalues['amplitude_contrast'] = self.minAmpCon
            if self.ctfvalues['amplitude_contrast'] > self.maxAmpCon:
                self.ctfvalues['amplitude_contrast'] = self.maxAmpCon
        except KeyError:
            pass

        if abs(self.ctfvalues['defocus1']) > abs(self.ctfvalues['defocus2']):
            # incorrect, need to shift angle by 90 degrees
            apDisplay.printWarning("|def1| > |def2|, flipping defocus axes")
            tempdef = self.ctfvalues['defocus1']
            self.ctfvalues['defocus1'] = self.ctfvalues['defocus2']
            self.ctfvalues['defocus2'] = tempdef
            self.ctfvalues['angle_astigmatism'] += 90
        # get astig_angle within range -90 < angle <= 90
        while self.ctfvalues['angle_astigmatism'] > 90:
            self.ctfvalues['angle_astigmatism'] -= 180
        while self.ctfvalues['angle_astigmatism'] < -90:
            self.ctfvalues['angle_astigmatism'] += 180

        avgres = self.getResolution(self.ctfvalues['defocus'], raddata,
                                    PSDarray, lowerbound)
        apDisplay.printColor(
            "Final defocus values %.3e -> %.3e, %.3e; ac=%.2f, res=%.1f" %
            (self.ctfvalues['defocus'], self.ctfvalues['defocus1'],
             self.ctfvalues['defocus2'], self.ctfvalues['amplitude_contrast'],
             avgres / 2.0), "green")

        for i in range(10):
            print "===================================="

        print "PREVIOUS VALUES"
        ctfdb.getBestCtfByResolution(imgdata)
        print "CURRENT VALUES"
        defocusratio = self.ctfvalues['defocus2'] / self.ctfvalues['defocus1']
        apDisplay.printColor(
            "def1: %.2e | def2: %.2e | angle: %.1f | ampcontr %.2f | defratio %.3f"
            % (self.ctfvalues['defocus1'], self.ctfvalues['defocus2'],
               self.ctfvalues['angle_astigmatism'],
               self.ctfvalues['amplitude_contrast'], defocusratio), "blue")
        self.printBestValues()
        #ellipratio = self.ellipseParams['a']/self.ellipseParams['b']
        print "ellr=%.3f, defr=%.3f, sqrt(defr)=%.3f" % (
            ellipratio, defocusratio, math.sqrt(defocusratio))
        print "===================================="

        return
Esempio n. 2
0
    def getResolution(self, defocus, raddata, PSD, lowerBoundIndex, show=True):

        ctffitdata = genctf.generateCTF1d(
            raddata * 1e10,
            focus=defocus,
            cs=self.ctfvalues['cs'],
            volts=self.ctfvalues['volts'],
            ampconst=self.ctfvalues['amplitude_contrast'],
            failParams=False)

        peaks = ctftools.getCtfExtrema(defocus,
                                       self.freq * 1e10,
                                       self.ctfvalues['cs'],
                                       self.ctfvalues['volts'],
                                       self.ctfvalues['amplitude_contrast'],
                                       numzeros=25,
                                       zerotype="peak")

        ### get the confidence
        confraddata, confdata = ctfres.getCorrelationProfile(
            raddata, PSD, ctffitdata, peaks, self.freq)

        res5 = None
        res8 = None
        if confdata is not None and confdata.max() > self.maxAmpCon:
            res5 = ctfres.getResolutionFromConf(confraddata,
                                                confdata,
                                                limit=0.5)
            res8 = ctfres.getResolutionFromConf(confraddata,
                                                confdata,
                                                limit=0.8)

        if res8 is None:
            res8 = 100
        if res5 is None:
            res5 = 100

        if (res8 + res5) < self.bestres and self.minAmpCon < self.ctfvalues[
                'amplitude_contrast'] < self.maxAmpCon:
            apDisplay.printColor(
                "Congrats! Saving best resolution values %.3e and %.2f" %
                (defocus, self.ctfvalues['amplitude_contrast']), "green")
            self.bestres = (res8 + res5)
            self.bestvalues = copy.deepcopy(self.ctfvalues)
            self.bestvalues['defocus'] = defocus
            self.bestellipse = copy.deepcopy(self.ellipseParams)
        elif show is True:
            if (res8 + res5) >= self.bestres:
                print(
                    "not saving values %.2f, need an average better than %.2f"
                    % ((res8 + res5), self.bestres))
            elif not (self.minAmpCon < self.ctfvalues['amplitude_contrast'] <
                      self.maxAmpCon):
                print(
                    "not saving values amplitude contrast %.4f out of range (%.4f <> %.4f)"
                    % (self.ctfvalues['amplitude_contrast'], self.minAmpCon,
                       self.maxAmpCon))
            else:
                apDisplay.printError("Something went wrong")

        ## normalize the data
        PSD -= (PSD[lowerBoundIndex:]).min()
        PSD /= numpy.abs(PSD[lowerBoundIndex:]).max()

        if self.debug is True and show is True:
            ### Show the data
            raddatasq = raddata**2
            confraddatasq = confraddata**2
            peakradii = ctftools.getCtfExtrema(
                defocus,
                self.freq * 1e10,
                self.ctfvalues['cs'],
                self.ctfvalues['volts'],
                self.ctfvalues['amplitude_contrast'],
                numzeros=2,
                zerotype="peaks")
            firstpeak = peakradii[0]

            from matplotlib import pyplot
            pyplot.clf()
            ### raw powerspectra data
            pyplot.plot(raddatasq[lowerBoundIndex:],
                        PSD[lowerBoundIndex:],
                        '-',
                        color="red",
                        alpha=0.5,
                        linewidth=1)
            ### ctf fit data
            pyplot.plot(raddatasq[lowerBoundIndex:],
                        ctffitdata[lowerBoundIndex:],
                        '-',
                        color="black",
                        alpha=0.5,
                        linewidth=1)
            ### confidence profile
            pyplot.plot(confraddatasq,
                        confdata,
                        '.',
                        color="blue",
                        alpha=0.9,
                        markersize=10)
            pyplot.plot(confraddatasq,
                        confdata,
                        '-',
                        color="blue",
                        alpha=0.9,
                        linewidth=2)

            pyplot.axvline(x=1 / res8**2, linewidth=2, color="gold")
            pyplot.axvline(x=1 / res5**2, linewidth=2, color="red")

            pyplot.title("Resolution values of %.3fA at 0.8 and %.3fA at 0.5" %
                         (res8, res5))
            pyplot.xlim(xmin=raddatasq[lowerBoundIndex - 1],
                        xmax=raddatasq.max())
            pyplot.ylim(ymin=-0.05, ymax=1.05)
            pyplot.subplots_adjust(
                wspace=0.05,
                hspace=0.05,
                bottom=0.05,
                left=0.05,
                top=0.95,
                right=0.95,
            )
            pyplot.show()

        apDisplay.printColor(
            "Resolution values of %.4fA at 0.8 and %.4fA at 0.5" %
            (res8, res5), "magenta")

        return (res8 + res5) / 2.0
Esempio n. 3
0
    def fullTriSectionNormalize(self, raddata, PSD, defocus):
        t0 = time.time()

        ###
        ### PART 1: BACKGROUND NOISE SUBTRACTION
        ###

        # skip the center
        valleys = ctftools.getCtfExtrema(defocus,
                                         self.freq * 1e10,
                                         self.ctfvalues['cs'],
                                         self.ctfvalues['volts'],
                                         self.ctfvalues['amplitude_contrast'],
                                         numzeros=250,
                                         zerotype="valleys")
        firstvalley = valleys[0]
        valleyradii = numpy.array(valleys, dtype=numpy.float64) * self.freq
        firstvalleyindex = numpy.searchsorted(raddata, self.freq * firstvalley)
        apDisplay.printColor(
            "First valley: %.1f -> %d (1/%.1f A)" %
            (firstvalley, firstvalleyindex, 1 / (firstvalley * self.freq)),
            "yellow")

        ### split the function up in first 3/5 and last 3/5 of data with 1/5 overlap
        numpoints = len(raddata) - firstvalleyindex
        part1start = firstvalleyindex
        part1end = int(firstvalleyindex + numpoints * 6 / 10.)
        part2start = int(firstvalleyindex + numpoints * 5 / 10.)
        part2end = int(firstvalleyindex + numpoints * 9 / 10.)
        part3start = int(firstvalleyindex + numpoints * 8 / 10.)
        part3end = len(raddata)

        CtfNoise = ctfnoise.CtfNoise()
        if valleyradii is None:
            valleydata = ctfnoise.peakExtender(raddata, PSD, valleyradii,
                                               "below")
        else:
            valleydata = ndimage.minimum_filter(PSD, 4)

        ## first part data
        noisefitparams1 = CtfNoise.modelCTFNoise(
            raddata[part1start:part1end], valleydata[part1start:part1end],
            "below")
        noisedata1 = CtfNoise.noiseModel(noisefitparams1, raddata)

        ## second part data
        noisefitparams2 = CtfNoise.modelCTFNoise(
            raddata[part2start:part2end], valleydata[part2start:part2end],
            "below")
        noisedata2 = CtfNoise.noiseModel(noisefitparams2, raddata)

        ## third part data
        noisefitparams3 = CtfNoise.modelCTFNoise(
            raddata[part3start:part3end], valleydata[part3start:part3end],
            "below")
        noisedata3 = CtfNoise.noiseModel(noisefitparams3, raddata)

        ## merge data
        scale = numpy.arange(part1end - part2start, dtype=numpy.float32)
        scale /= scale.max()
        overlapdata1 = noisedata1[part2start:part1end] * (
            1 - scale) + noisedata2[part2start:part1end] * scale
        scale = numpy.arange(part2end - part3start, dtype=numpy.float32)
        scale /= scale.max()
        overlapdata2 = noisedata2[part3start:part2end] * (
            1 - scale) + noisedata3[part3start:part2end] * scale

        mergedata = numpy.hstack((noisedata1[:part2start], overlapdata1,
                                  noisedata2[part1end:part3start],
                                  overlapdata2, noisedata3[part2end:]))

        noisedata = mergedata

        ### DO THE SUBTRACTION
        normexpPSD = numpy.exp(PSD) - numpy.exp(noisedata)
        normlogPSD = numpy.log(numpy.where(normexpPSD < 1, 1, normexpPSD))

        ###
        ### PART 2: ENVELOPE NORMALIZATION
        ###

        # high pass filter the center
        peaks = ctftools.getCtfExtrema(defocus,
                                       self.freq * 1e10,
                                       self.ctfvalues['cs'],
                                       self.ctfvalues['volts'],
                                       self.ctfvalues['amplitude_contrast'],
                                       numzeros=250,
                                       zerotype="peaks")
        firstpeak = peaks[0]
        peakradii = numpy.array(peaks, dtype=numpy.float64) * self.freq

        firstpeakindex = numpy.searchsorted(raddata, firstpeak * self.freq)
        apDisplay.printColor(
            "First peak: %.1f (1/%.1f A)" %
            (firstpeakindex, 1 / (firstpeak * self.freq)), "yellow")

        ### split the function up in first 3/5 and last 3/5 of data with 1/5 overlap
        numpoints = len(raddata) - firstpeakindex
        part1start = firstpeakindex
        part1end = int(firstpeakindex + numpoints * 6 / 10.)
        part2start = int(firstpeakindex + numpoints * 5 / 10.)
        part2end = int(firstpeakindex + numpoints * 9 / 10.)
        part3start = int(firstpeakindex + numpoints * 8 / 10.)
        part3end = len(raddata)

        CtfNoise = ctfnoise.CtfNoise()
        if peakradii is None:
            peakdata = ctfnoise.peakExtender(raddata, normlogPSD, peakradii,
                                             "above")
        else:
            peakdata = ndimage.maximum_filter(normlogPSD, 4)

        ## first part data
        envelopfitparams1 = CtfNoise.modelCTFNoise(
            raddata[part1start:part1end], peakdata[part1start:part1end],
            "above")
        envelopdata1 = CtfNoise.noiseModel(envelopfitparams1, raddata)

        ## second part data
        envelopfitparams2 = CtfNoise.modelCTFNoise(
            raddata[part2start:part2end], peakdata[part2start:part2end],
            "above")
        envelopdata2 = CtfNoise.noiseModel(envelopfitparams2, raddata)

        ## third part data
        envelopfitparams3 = CtfNoise.modelCTFNoise(
            raddata[part3start:part3end], peakdata[part3start:part3end],
            "above")
        envelopdata3 = CtfNoise.noiseModel(envelopfitparams3, raddata)

        ## merge data
        scale = numpy.arange(part1end - part2start, dtype=numpy.float32)
        scale /= scale.max()
        overlapdata1 = envelopdata1[part2start:part1end] * (
            1 - scale) + envelopdata2[part2start:part1end] * scale
        scale = numpy.arange(part2end - part3start, dtype=numpy.float32)
        scale /= scale.max()
        overlapdata2 = envelopdata2[part3start:part2end] * (
            1 - scale) + envelopdata3[part3start:part2end] * scale

        mergedata = numpy.hstack((envelopdata1[:part2start], overlapdata1,
                                  envelopdata2[part1end:part3start],
                                  overlapdata2, envelopdata3[part2end:]))
        envelopdata = mergedata

        normnormexpPSD = normexpPSD / numpy.exp(envelopdata)

        if self.debug is True:
            from matplotlib import pyplot
            pyplot.clf()
            pyplot.subplot(3, 1, 1)
            raddatasq = raddata**2
            pyplot.plot(
                raddatasq,
                normnormexpPSD,
                'k.',
            )
            a = pyplot.plot(raddatasq, PSD, 'k-', alpha=0.5)
            a = pyplot.plot(raddatasq, valleydata, 'k-', alpha=0.5)
            b = pyplot.plot(raddatasq[firstvalleyindex:],
                            noisedata[firstvalleyindex:],
                            '--',
                            color="purple",
                            linewidth=2)
            c = pyplot.plot(raddatasq[part1start:part1end],
                            noisedata1[part1start:part1end],
                            'b-',
                            alpha=0.5,
                            linewidth=2)
            d = pyplot.plot(raddatasq[part2start:part2end],
                            noisedata2[part2start:part2end],
                            'r-',
                            alpha=0.5,
                            linewidth=2)
            e = pyplot.plot(raddatasq[part3start:part3end],
                            noisedata3[part3start:part3end],
                            '-',
                            alpha=0.5,
                            linewidth=2,
                            color="green")
            pyplot.legend([a, b, c, d, e],
                          ["data", "merge", "part 1", "part 2", "part 3"])
            pyplot.xlim(xmax=raddatasq.max())
            pyplot.ylim(ymin=noisedata.min(), ymax=PSD[part1start:].max())

            pyplot.subplot(3, 1, 2)
            a = pyplot.plot(
                raddatasq,
                normlogPSD,
                'k.',
            )
            a = pyplot.plot(raddatasq, normlogPSD, 'k-', alpha=0.5)
            a = pyplot.plot(raddatasq, peakdata, 'k-', alpha=0.5)
            b = pyplot.plot(raddatasq,
                            mergedata,
                            '--',
                            color="purple",
                            linewidth=2)
            c = pyplot.plot(raddatasq[part1start:part1end],
                            envelopdata1[part1start:part1end],
                            'b-',
                            alpha=0.5,
                            linewidth=2)
            d = pyplot.plot(raddatasq[part2start:part2end],
                            envelopdata2[part2start:part2end],
                            'r-',
                            alpha=0.5,
                            linewidth=2)
            e = pyplot.plot(raddatasq[part3start:part3end],
                            envelopdata3[part3start:part3end],
                            '-',
                            alpha=0.5,
                            linewidth=2,
                            color="green")
            pyplot.legend([a, b, c, d, e],
                          ["data", "merge", "part 1", "part 2", "part 3"])
            pyplot.xlim(xmax=raddatasq.max())
            pyplot.ylim(ymin=normlogPSD[part1start:].min(),
                        ymax=envelopdata.max())

            pyplot.subplot(3, 1, 3)
            pyplot.plot(
                raddatasq,
                normnormexpPSD,
                'k.',
            )
            pyplot.plot(raddatasq, normnormexpPSD, 'k-', alpha=0.5)
            pyplot.xlim(xmax=raddatasq.max())

            pyplot.subplots_adjust(
                wspace=0.05,
                hspace=0.05,
                bottom=0.05,
                left=0.05,
                top=0.95,
                right=0.95,
            )
            pyplot.show()

        apDisplay.printColor(
            "TriSection complete in %s" %
            (apDisplay.timeString(time.time() - t0)), "cyan")

        return normnormexpPSD
        def runRefineCTF(self, imgdata, fftpath):
                ### reset important values
                self.bestres = 1e10
                self.bestellipse = None
                self.bestvalues = {}

                self.volts = imgdata['scope']['high tension']
                self.wavelength = ctftools.getTEMLambda(self.volts)
                ## get value in meters
                self.cs = apInstrument.getCsValueFromSession(self.getSessionData())*1e-3
                self.ctfvalues = {
                        'volts': self.volts,
                        'wavelength': self.wavelength,
                        'cs': self.cs,
                }

                ### need to get FFT file open and freq of said file
                fftarray = mrc.read(fftpath).astype(numpy.float64)
                self.freq = self.freqdict[fftpath]

                ### convert resolution limit into pixel distance
                fftwidth = fftarray.shape[0]
                maxres = 2.0/(self.freq*fftwidth)
                if maxres > self.params['reslimit']:
                        apDisplay.printError("Cannot get requested res %.1fA higher than max res %.1fA"
                                %(maxres, self.params['reslimit']))

                limitwidth = int(math.ceil(2.0/(self.params['reslimit']*self.freq)))
                limitwidth = primefactor.getNextEvenPrime(limitwidth)
                requestres = 2.0/(self.freq*limitwidth)
                if limitwidth > fftwidth:
                        apDisplay.printError("Cannot get requested resolution"
                                +(" request res %.1fA higher than max res %.1fA for new widths %d > %d"
                                %(requestres, maxres, limitwidth, fftwidth)))

                apDisplay.printColor("Requested resolution OK: "
                        +(" request res %.1fA less than max res %.1fA with fft widths %d < %d"
                        %(requestres, maxres, limitwidth, fftwidth)), "green")
                newshape = (limitwidth, limitwidth)
                fftarray = imagefilter.frame_cut(fftarray, newshape)

                ### spacing parameters
                self.mfreq = self.freq*1e10
                fftwidth = min(fftarray.shape)
                self.apix = 1.0/(fftwidth*self.freq)
                self.ctfvalues['apix'] = self.apix

                ### print message
                bestDbValues = ctfdb.getBestCtfByResolution(imgdata)
                if bestDbValues is None:
                        apDisplay.printColor("SKIPPING: No CTF values for image %s"
                                %(apDisplay.short(imgdata['filename'])), "red")
                        self.badprocess = True
                        return

                ### skip if resolution > 90.
                if bestDbValues['resolution_50_percent'] > 90.:
                        apDisplay.printColor("SKIPPING: No decent CTF values for image %s"
                                %(apDisplay.short(imgdata['filename'])), "yellow")
                        self.badprocess = True
                        return

                self.ctfvalues['amplitude_contrast'] = bestDbValues['amplitude_contrast']

                lowerrad1 = ctftools.getCtfExtrema(bestDbValues['defocus1'], self.mfreq, self.cs, self.volts, 
                        self.ctfvalues['amplitude_contrast'], 1, "valley")
                lowerrad2 = ctftools.getCtfExtrema(bestDbValues['defocus2'], self.mfreq, self.cs, self.volts, 
                        self.ctfvalues['amplitude_contrast'], 1, "valley")
                meanRad = (lowerrad1[0] + lowerrad2[0])/2.0

                self.ellipseParams = {
                        'a': lowerrad1[0],
                        'b': lowerrad2[0],
                        'alpha': math.radians(bestDbValues['angle_astigmatism']),
                }
                ellipratio = self.ellipseParams['a']/self.ellipseParams['b']
                defratio = bestDbValues['defocus2']/bestDbValues['defocus1']
                print "ellr=%.3f, defr=%.3f, sqrt(defr)=%.3f"%(ellipratio, defratio, math.sqrt(defratio))
                self.bestvalues['defocus'] = (bestDbValues['defocus1']+bestDbValues['defocus2'])/2.0


                raddata, PSDarray = self.from2Dinto1D(fftarray)
                lowerbound = numpy.searchsorted(raddata, meanRad*self.freq)
                upperbound = numpy.searchsorted(raddata, 1/10.)

                ###
                #       This is the start of the actual program
                ###

                self.refineEllipseLoop(fftarray, lowerbound, upperbound)

                ##==================================
                ## FINISH UP
                ##==================================

                apDisplay.printColor("Finishing up using best found CTF values", "blue")
                self.printBestValues()

                ### take best values and use them
                self.ctfvalues = self.bestvalues
                self.ellipseParams = self.bestellipse

                ### stupid fix, get value in millimeters
                self.ctfvalues['cs'] = apInstrument.getCsValueFromSession(self.getSessionData())

                ### translate ellipse into ctf values
                if self.ellipseParams is not None:
                        self.ctfvalues['angle_astigmatism'] = math.degrees(self.ellipseParams['alpha'])
                        ellipratio = self.ellipseParams['a']/self.ellipseParams['b']
                        phi = math.asin(self.ctfvalues['amplitude_contrast'])
                        #note: a > b then def1 < def2
                        #major axis
                        self.ctfvalues['defocus1'] = self.ctfvalues['defocus']/ellipratio
                        #minor axis
                        self.ctfvalues['defocus2'] = self.ctfvalues['defocus']*ellipratio

                        defdiff = 1.0 - 2*self.ctfvalues['defocus']/(self.ctfvalues['defocus1']+self.ctfvalues['defocus2'])
                        print "%.3e --> %.3e,%.3e"%(self.ctfvalues['defocus'], 
                                        self.ctfvalues['defocus2'], self.ctfvalues['defocus1'])
                        print defdiff*100
                        if defdiff*100 > 1:
                                apDisplay.printWarning("Large astigmatism")
                                #sys.exit(1)
                else:
                        ellipratio = 1.0
                        self.ctfvalues['angle_astigmatism'] = 0.0
                        self.ctfvalues['defocus1'] = self.ctfvalues['defocus']
                        self.ctfvalues['defocus2'] = self.ctfvalues['defocus']

                if self.ctfvalues['amplitude_contrast'] < 0.0:
                        self.ctfvalues['amplitude_contrast'] = 0.0
                if self.ctfvalues['amplitude_contrast'] > self.maxAmpCon:
                        self.ctfvalues['amplitude_contrast'] = self.maxAmpCon

                if abs(self.ctfvalues['defocus1']) > abs(self.ctfvalues['defocus2']):
                        # incorrect, need to shift angle by 90 degrees
                        apDisplay.printWarning("|def1| > |def2|, flipping defocus axes")
                        tempdef = self.ctfvalues['defocus1']
                        self.ctfvalues['defocus1'] = self.ctfvalues['defocus2']
                        self.ctfvalues['defocus2'] = tempdef
                        self.ctfvalues['angle_astigmatism'] += 90
                # get astig_angle within range -90 < angle <= 90
                while self.ctfvalues['angle_astigmatism'] > 90:
                        self.ctfvalues['angle_astigmatism'] -= 180
                while self.ctfvalues['angle_astigmatism'] < -90:
                        self.ctfvalues['angle_astigmatism'] += 180

                avgres = self.getResolution(self.ctfvalues['defocus'], raddata, PSDarray, lowerbound)
                apDisplay.printColor("Final defocus values %.3e -> %.3e, %.3e; ac=%.2f, res=%.1f"
                        %(self.ctfvalues['defocus'], self.ctfvalues['defocus1'], self.ctfvalues['defocus2'],
                        self.ctfvalues['amplitude_contrast'], avgres/2.0), "green")

                for i in range(10):
                        print "===================================="

                print "PREVIOUS VALUES"
                ctfdb.getBestCtfByResolution(imgdata)
                print "CURRENT VALUES"
                defocusratio = self.ctfvalues['defocus2']/self.ctfvalues['defocus1']
                apDisplay.printColor("def1: %.2e | def2: %.2e | angle: %.1f | ampcontr %.2f | defratio %.3f"
                        %(self.ctfvalues['defocus1'], self.ctfvalues['defocus2'], self.ctfvalues['angle_astigmatism'],
                        self.ctfvalues['amplitude_contrast'], defocusratio), "blue")
                self.printBestValues()
                #ellipratio = self.ellipseParams['a']/self.ellipseParams['b']
                print "ellr=%.3f, defr=%.3f, sqrt(defr)=%.3f"%(ellipratio, defocusratio, math.sqrt(defocusratio))
                print "===================================="

                return
def findAstigmatism(fftarray, freq, defocus, resolution, ctfvalues, peakNum=1):
	"""
	find the astigmatism from a radial 1D estimate of the defocus
	"""
	#searchError = resolution/100.

	extrema = ctftools.getCtfExtrema(defocus, freq*1e10,
		ctfvalues['cs'], ctfvalues['volts'], ctfvalues['amplitude_contrast'],
		numzeros=peakNum*2+1, zerotype="all")
	if len(extrema) < 2*peakNum:
		return None
	minEdgeRadius = int(math.ceil(extrema[peakNum-1])) #first peak
	maxEdgeRadius = int(math.ceil(extrema[peakNum])) #second peak
	newshape = (maxEdgeRadius*2, maxEdgeRadius*2)

	print "newshape",newshape

	fftcenter = copy.deepcopy(imagefilter.frame_cut(fftarray, newshape))
	showImage(fftcenter)

	shape = fftcenter.shape
	## create a grid of distance from the center
	xhalfshape = shape[0]/2.0
	x = numpy.arange(-xhalfshape, xhalfshape, 1) + 0.5
	yhalfshape = shape[1]/2.0
	y = numpy.arange(-yhalfshape, yhalfshape, 1) + 0.5
	xx, yy = numpy.meshgrid(x, y)
	radialArray = xx**2 + yy**2 - 0.5
	#radialArray = numpy.sqrt(radial)

	maxVal = fftcenter.max()*2
	minVal = fftcenter.min()
	if debug is True:
		fftcenter = numpy.where(radialArray > maxEdgeRadius**2, maxVal, fftcenter)
		showImage(fftcenter)
		fftcenter = numpy.where(radialArray < minEdgeRadius**2, maxVal, fftcenter)
		showImage(fftcenter)

	angleArray = numpy.arctan2(-yy,xx)
	numSteps = 360
	angleArray += math.pi
	angleArray /= 2*math.pi
	angleArray *= numSteps
	angleArray = numpy.asarray(angleArray, dtype=numpy.uint16)

	showImage(angleArray)

	dataIntegers = numpy.array(range(numSteps))

	xyData = numpy.array(
		scipy.ndimage.measurements.minimum_position(
			fftcenter, angleArray, dataIntegers))

	if debug is True:
		fftcenter[xyData[:,0], xyData[:,1]] = maxVal*3
		showImage(fftcenter)

	ellipseParams = ellipse.totalLeastSquareEllipse(xyData, center=(xhalfshape, yhalfshape))
	if ellipseParams is None:
		return None
	ellipse.printParamsDict(ellipseParams)

	if debug is True:
		numPoints = int(math.pi*(ellipseParams['a']+ellipseParams['b']))
		ellPoints = ellipse.generate_ellipse(ellipseParams['a'], ellipseParams['b'], 
			ellipseParams['alpha'], center=ellipseParams['center'], numpoints=numPoints, integers=True)
		fftcenter[ellPoints[:,0], ellPoints[:,1]] += maxVal
		showImage(fftcenter)

	return ellipseParams
        def getResolution(self, defocus, raddata, PSD, lowerBoundIndex, show=True):

                ctffitdata = genctf.generateCTF1d(raddata*1e10, focus=defocus, cs=self.ctfvalues['cs'],
                        volts=self.ctfvalues['volts'], ampconst=self.ctfvalues['amplitude_contrast'], failParams=False)

                peaks = ctftools.getCtfExtrema(defocus, self.freq*1e10, self.ctfvalues['cs'], 
                        self.ctfvalues['volts'], self.ctfvalues['amplitude_contrast'], numzeros=25, zerotype="peak")

                ### get the confidence
                confraddata, confdata = ctfres.getCorrelationProfile(raddata, PSD, ctffitdata, peaks, self.freq)

                res5 = None
                res8 = None
                if confdata is not None and confdata.max() > self.maxAmpCon:
                        res5 = ctfres.getResolutionFromConf(confraddata, confdata, limit=0.5)
                        res8 = ctfres.getResolutionFromConf(confraddata, confdata, limit=0.8)

                if res8 is None:
                        res8 = 100
                if res5 is None:
                        res5 = 100

                if (res8+res5) < self.bestres and 0.0 < self.ctfvalues['amplitude_contrast'] < self.maxAmpCon:
                        apDisplay.printColor("Congrats! Saving best resolution values %.3e and %.2f"
                                %(defocus, self.ctfvalues['amplitude_contrast']), "green")
                        self.bestres = (res8+res5)
                        self.bestvalues = copy.deepcopy(self.ctfvalues)
                        self.bestvalues['defocus'] = defocus
                        self.bestellipse = copy.deepcopy(self.ellipseParams)
                elif show is True:
                        print "not saving values %.2f, need an average better than %.2f"%((res8+res5), self.bestres)

                ## normalize the data
                PSD -= (PSD[lowerBoundIndex:]).min()
                PSD /= numpy.abs(PSD[lowerBoundIndex:]).max()

                if self.debug is True and show is True:
                        ### Show the data
                        raddatasq = raddata**2
                        confraddatasq = confraddata**2
                        peakradii = ctftools.getCtfExtrema(defocus, self.freq*1e10,
                                self.ctfvalues['cs'], self.ctfvalues['volts'], self.ctfvalues['amplitude_contrast'],
                                numzeros=2, zerotype="peaks")
                        firstpeak = peakradii[0]

                        from matplotlib import pyplot
                        pyplot.clf()
                        ### raw powerspectra data
                        pyplot.plot(raddatasq[lowerBoundIndex:], PSD[lowerBoundIndex:], '-', color="red", alpha=0.5, linewidth=1)
                        ### ctf fit data
                        pyplot.plot(raddatasq[lowerBoundIndex:], ctffitdata[lowerBoundIndex:], '-', color="black", alpha=0.5, linewidth=1)
                        ### confidence profile
                        pyplot.plot(confraddatasq, confdata, '.', color="blue", alpha=0.9, markersize=10)
                        pyplot.plot(confraddatasq, confdata, '-', color="blue", alpha=0.9, linewidth=2)

                        pyplot.axvline(x=1/res8**2, linewidth=2, color="gold")
                        pyplot.axvline(x=1/res5**2, linewidth=2, color="red")
                
                        pyplot.title("Resolution values of %.3fA at 0.8 and %.3fA at 0.5"%(res8,res5))
                        pyplot.xlim(xmin=raddatasq[lowerBoundIndex-1], xmax=raddatasq.max())
                        pyplot.ylim(ymin=-0.05, ymax=1.05)
                        pyplot.subplots_adjust(wspace=0.05, hspace=0.05,
                                bottom=0.05, left=0.05, top=0.95, right=0.95, )
                        pyplot.show()

                apDisplay.printColor("Resolution values of %.4fA at 0.8 and %.4fA at 0.5"
                        %(res8,res5), "magenta")

                return (res8+res5)/2.0
        def fullTriSectionNormalize(self, raddata, PSD, defocus):
                t0 = time.time()

                ### 
                ### PART 1: BACKGROUND NOISE SUBTRACTION
                ### 

                # skip the center
                valleys = ctftools.getCtfExtrema(defocus, self.freq*1e10,
                        self.ctfvalues['cs'], self.ctfvalues['volts'], self.ctfvalues['amplitude_contrast'],
                        numzeros=250, zerotype="valleys")
                firstvalley = valleys[0]
                valleyradii = numpy.array(valleys, dtype=numpy.float64)*self.freq
                firstvalleyindex = numpy.searchsorted(raddata, self.freq*firstvalley)
                apDisplay.printColor("First valley: %.1f -> %d (1/%.1f A)"
                        %(firstvalley, firstvalleyindex, 1/(firstvalley*self.freq)), "yellow")

                ### split the function up in first 3/5 and last 3/5 of data with 1/5 overlap
                numpoints = len(raddata) - firstvalleyindex
                part1start = firstvalleyindex
                part1end = int(firstvalleyindex + numpoints*6/10.)
                part2start = int(firstvalleyindex + numpoints*5/10.)
                part2end = int(firstvalleyindex + numpoints*9/10.)
                part3start = int(firstvalleyindex + numpoints*8/10.)
                part3end = len(raddata)

                CtfNoise = ctfnoise.CtfNoise()
                if valleyradii is None:
                        valleydata = ctfnoise.peakExtender(raddata, PSD, valleyradii, "below")
                else:
                        valleydata = ndimage.minimum_filter(PSD, 4)

                ## first part data
                noisefitparams1 = CtfNoise.modelCTFNoise(raddata[part1start:part1end],
                        valleydata[part1start:part1end], "below")
                noisedata1 = CtfNoise.noiseModel(noisefitparams1, raddata)

                ## second part data
                noisefitparams2 = CtfNoise.modelCTFNoise(raddata[part2start:part2end],
                        valleydata[part2start:part2end], "below")
                noisedata2 = CtfNoise.noiseModel(noisefitparams2, raddata)

                ## third part data
                noisefitparams3 = CtfNoise.modelCTFNoise(raddata[part3start:part3end],
                        valleydata[part3start:part3end], "below")
                noisedata3 = CtfNoise.noiseModel(noisefitparams3, raddata)

                ## merge data
                scale = numpy.arange(part1end-part2start, dtype=numpy.float32)
                scale /= scale.max()
                overlapdata1 = noisedata1[part2start:part1end]*(1-scale) + noisedata2[part2start:part1end]*scale
                scale = numpy.arange(part2end-part3start, dtype=numpy.float32)
                scale /= scale.max()
                overlapdata2 = noisedata2[part3start:part2end]*(1-scale) + noisedata3[part3start:part2end]*scale

                mergedata = numpy.hstack((noisedata1[:part2start], overlapdata1,
                        noisedata2[part1end:part3start], overlapdata2,
                        noisedata3[part2end:]))

                noisedata = mergedata

                ### DO THE SUBTRACTION
                normexpPSD = numpy.exp(PSD) - numpy.exp(noisedata)
                normlogPSD = numpy.log(numpy.where(normexpPSD<1, 1, normexpPSD))

                ### 
                ### PART 2: ENVELOPE NORMALIZATION
                ### 

                # high pass filter the center
                peaks = ctftools.getCtfExtrema(defocus, self.freq*1e10,
                        self.ctfvalues['cs'], self.ctfvalues['volts'], self.ctfvalues['amplitude_contrast'],
                        numzeros=250, zerotype="peaks")
                firstpeak = peaks[0]
                peakradii = numpy.array(peaks, dtype=numpy.float64)*self.freq

                firstpeakindex = numpy.searchsorted(raddata, firstpeak*self.freq)
                apDisplay.printColor("First peak: %.1f (1/%.1f A)"%
                        (firstpeakindex, 1/(firstpeak*self.freq)), "yellow")

                ### split the function up in first 3/5 and last 3/5 of data with 1/5 overlap
                numpoints = len(raddata) - firstpeakindex
                part1start = firstpeakindex
                part1end = int(firstpeakindex + numpoints*6/10.)
                part2start = int(firstpeakindex + numpoints*5/10.)
                part2end = int(firstpeakindex + numpoints*9/10.)
                part3start = int(firstpeakindex + numpoints*8/10.)
                part3end = len(raddata)

                CtfNoise = ctfnoise.CtfNoise()
                if peakradii is None:
                        peakdata = ctfnoise.peakExtender(raddata, normlogPSD, peakradii, "above")
                else:
                        peakdata = ndimage.maximum_filter(normlogPSD, 4)

                ## first part data
                envelopfitparams1 = CtfNoise.modelCTFNoise(raddata[part1start:part1end],
                        peakdata[part1start:part1end], "above")
                envelopdata1 = CtfNoise.noiseModel(envelopfitparams1, raddata)

                ## second part data
                envelopfitparams2 = CtfNoise.modelCTFNoise(raddata[part2start:part2end],
                        peakdata[part2start:part2end], "above")
                envelopdata2 = CtfNoise.noiseModel(envelopfitparams2, raddata)

                ## third part data
                envelopfitparams3 = CtfNoise.modelCTFNoise(raddata[part3start:part3end],
                        peakdata[part3start:part3end], "above")
                envelopdata3 = CtfNoise.noiseModel(envelopfitparams3, raddata)

                ## merge data
                scale = numpy.arange(part1end-part2start, dtype=numpy.float32)
                scale /= scale.max()
                overlapdata1 = envelopdata1[part2start:part1end]*(1-scale) + envelopdata2[part2start:part1end]*scale
                scale = numpy.arange(part2end-part3start, dtype=numpy.float32)
                scale /= scale.max()
                overlapdata2 = envelopdata2[part3start:part2end]*(1-scale) + envelopdata3[part3start:part2end]*scale

                mergedata = numpy.hstack((envelopdata1[:part2start], overlapdata1,
                        envelopdata2[part1end:part3start], overlapdata2,
                        envelopdata3[part2end:]))
                envelopdata = mergedata

                normnormexpPSD = normexpPSD / numpy.exp(envelopdata)

                if self.debug is True:
                        from matplotlib import pyplot
                        pyplot.clf()
                        pyplot.subplot(3,1,1)
                        raddatasq = raddata**2
                        pyplot.plot(raddatasq, normnormexpPSD, 'k.',)
                        a = pyplot.plot(raddatasq, PSD, 'k-', alpha=0.5)
                        a = pyplot.plot(raddatasq, valleydata, 'k-', alpha=0.5)
                        b = pyplot.plot(raddatasq[firstvalleyindex:], noisedata[firstvalleyindex:], '--', color="purple", linewidth=2)
                        c = pyplot.plot(raddatasq[part1start:part1end],
                                noisedata1[part1start:part1end], 'b-', alpha=0.5, linewidth=2)
                        d = pyplot.plot(raddatasq[part2start:part2end],
                                noisedata2[part2start:part2end], 'r-', alpha=0.5, linewidth=2)
                        e = pyplot.plot(raddatasq[part3start:part3end],
                                noisedata3[part3start:part3end], '-', alpha=0.5, linewidth=2, color="green")
                        pyplot.legend([a, b, c, d, e], ["data", "merge", "part 1", "part 2", "part 3"])
                        pyplot.xlim(xmax=raddatasq.max())
                        pyplot.ylim(ymin=noisedata.min(), ymax=PSD[part1start:].max())

                        pyplot.subplot(3,1,2)
                        a = pyplot.plot(raddatasq, normlogPSD, 'k.',)
                        a = pyplot.plot(raddatasq, normlogPSD, 'k-', alpha=0.5)
                        a = pyplot.plot(raddatasq, peakdata, 'k-', alpha=0.5)
                        b = pyplot.plot(raddatasq, mergedata, '--', color="purple", linewidth=2)
                        c = pyplot.plot(raddatasq[part1start:part1end],
                                envelopdata1[part1start:part1end], 'b-', alpha=0.5, linewidth=2)
                        d = pyplot.plot(raddatasq[part2start:part2end],
                                envelopdata2[part2start:part2end], 'r-', alpha=0.5, linewidth=2)
                        e = pyplot.plot(raddatasq[part3start:part3end],
                                envelopdata3[part3start:part3end], '-', alpha=0.5, linewidth=2, color="green")
                        pyplot.legend([a, b, c, d, e], ["data", "merge", "part 1", "part 2", "part 3"])
                        pyplot.xlim(xmax=raddatasq.max())
                        pyplot.ylim(ymin=normlogPSD[part1start:].min(), ymax=envelopdata.max())

                        pyplot.subplot(3,1,3)
                        pyplot.plot(raddatasq, normnormexpPSD, 'k.',)
                        pyplot.plot(raddatasq, normnormexpPSD, 'k-', alpha=0.5)
                        pyplot.xlim(xmax=raddatasq.max())

                        pyplot.subplots_adjust(wspace=0.05, hspace=0.05,
                                bottom=0.05, left=0.05, top=0.95, right=0.95, )
                        pyplot.show()

                apDisplay.printColor("TriSection complete in %s"
                        %(apDisplay.timeString(time.time()-t0)), "cyan")

                return normnormexpPSD
	def runPhasorCTF(self, imgdata, fftpath):
		### reset important values
		self.bestres = 1e10
		self.bestellipse = None
		self.bestvalues = None
		self.ellipseParams = None
		self.volts = imgdata['scope']['high tension']
		self.wavelength = ctftools.getTEMLambda(self.volts)
		## get value in meters
		self.cs = apInstrument.getCsValueFromSession(self.getSessionData())*1e-3
		self.ctfvalues = {
			'volts': self.volts,
			'wavelength': self.wavelength,
			'cs': self.cs,
		}

		if self.params['astig'] is False:
			self.maxRatio=1.3
		else:
			self.maxRatio=2.0

		### need to get FFT file open and freq of said file
		fftarray = mrc.read(fftpath).astype(numpy.float64)
		self.freq = self.freqdict[fftpath]

		### print message
		ctfdb.getBestCtfByResolution(imgdata)

		### convert resolution limit into pixel distance
		fftwidth = fftarray.shape[0]
		maxres = 2.0/(self.freq*fftwidth)
		if maxres > self.params['reslimit']:
			apDisplay.printError("Cannot get requested res %.1fA higher than max res %.1fA"
				%(maxres, self.params['reslimit']))

		limitwidth = int(math.ceil(2.0/(self.params['reslimit']*self.freq)))
		limitwidth = primefactor.getNextEvenPrime(limitwidth)
		requestres = 2.0/(self.freq*limitwidth)
		if limitwidth > fftwidth:
			apDisplay.printError("Cannot get requested resolution"
				+(" request res %.1fA higher than max res %.1fA for new widths %d > %d"
				%(requestres, maxres, limitwidth, fftwidth)))

		apDisplay.printColor("Requested resolution OK: "
			+(" request res %.1fA less than max res %.1fA with fft widths %d < %d"
			%(requestres, maxres, limitwidth, fftwidth)), "green")
		newshape = (limitwidth, limitwidth)
		fftarray = imagefilter.frame_cut(fftarray, newshape)

		### spacing parameters
		self.mfreq = self.freq*1e10
		fftwidth = min(fftarray.shape)
		self.apix = 1.0/(fftwidth*self.freq)
		self.ctfvalues['apix'] = self.apix

		if self.params['sample'] is 'stain':
			self.ctfvalues['amplitude_contrast'] = 0.14
		else:
			self.ctfvalues['amplitude_contrast'] = 0.07

		###
		#	This is the start of the actual program
		###

		### this is either simple rotational average, 
		### or complex elliptical average with edge find and RANSAC
		raddata, PSDarray = self.from2Dinto1D(fftarray)

		lowerrad = ctftools.getCtfExtrema(self.params['maxdef'], self.mfreq, self.cs, self.volts, 
			self.ctfvalues['amplitude_contrast'], 1, "valley")
		lowerbound = numpy.searchsorted(raddata, lowerrad[0]*self.freq)

		if self.params['sample'] is 'stain':
			upperbound = numpy.searchsorted(raddata, 1/8.)
		else:
			upperbound = numpy.searchsorted(raddata, 1/12.)

		### fun way to get initial defocus estimate
		fitData = self.fitLinearPlus(raddata, PSDarray)
		#lowessFit = lowess.lowess(raddata**2, PSDarray, smoothing=0.6666)

		if self.debug is True:
			from matplotlib import pyplot
			pyplot.clf()
			pyplot.plot(raddata**2, PSDarray)
			pyplot.plot(raddata**2, fitData)
			pyplot.show()

		flatPSDarray = PSDarray-fitData
		flatPSDarray /= numpy.abs(flatPSDarray[lowerbound:upperbound]).max()

		defocus = self.gridSearch(raddata, flatPSDarray, lowerbound)

		#defocus = findroots.estimateDefocus(raddata[lowerbound:upperbound], flatPSDarray[lowerbound:upperbound], 
		#	cs=self.cs, wavelength=self.wavelength,  amp_con=self.ctfvalues['amplitude_contrast'], 
		#	mindef=self.params['mindef'], maxdef=self.params['maxdef'], volts=self.volts)
	
		amplitudecontrast = sinefit.refineAmplitudeContrast(raddata[lowerbound:upperbound]*1e10, defocus, 
			flatPSDarray[lowerbound:upperbound], self.ctfvalues['cs'], self.wavelength, msg=self.debug)
		if amplitudecontrast is not None:
			print "amplitudecontrast", amplitudecontrast
			self.ctfvalues['amplitude_contrast'] = amplitudecontrast
	
		defocus = self.defocusLoop(defocus, raddata, flatPSDarray, lowerbound, upperbound)

		#lowerrad = ctftools.getCtfExtrema(defocus, self.mfreq, self.cs, self.volts, 
		#	self.ctfvalues['amplitude_contrast'], 1, "valley")
		#lowerbound = numpy.searchsorted(raddata, lowerrad[0]*self.freq)

		normPSDarray = self.fullTriSectionNormalize(raddata, PSDarray, defocus)

		defocus = self.defocusLoop(defocus, raddata, normPSDarray, lowerbound, upperbound)

		self.findEllipseLoop(fftarray, lowerbound, upperbound)

		self.refineEllipseLoop(fftarray, lowerbound, upperbound)

		##==================================
		## FINISH UP
		##==================================

		apDisplay.printColor("Finishing up using best found CTF values", "blue")
		self.printBestValues()

		if self.bestvalues is None:
			apDisplay.printColor("No CTF estimate found for this image", "red")	
			self.badprocess = True
			return

		### take best values and use them
		self.ctfvalues = self.bestvalues
		self.ellipseParams = self.bestellipse

		### stupid fix, get value in millimeters
		self.ctfvalues['cs'] = apInstrument.getCsValueFromSession(self.getSessionData())

		### translate ellipse into ctf values
		if self.ellipseParams is not None:
			self.ctfvalues['angle_astigmatism'] = math.degrees(self.ellipseParams['alpha'])
			ellipratio = self.ellipseParams['a']/self.ellipseParams['b']
			phi = math.asin(self.ctfvalues['amplitude_contrast'])
			#note: a > b then def1 < def2
			#major axis
			self.ctfvalues['defocus1'] = self.ctfvalues['defocus']/ellipratio
			#minor axis
			self.ctfvalues['defocus2'] = self.ctfvalues['defocus']*ellipratio

			defdiff = 1.0 - 2*self.ctfvalues['defocus']/(self.ctfvalues['defocus1']+self.ctfvalues['defocus2'])
			print "%.3e --> %.3e,%.3e"%(self.ctfvalues['defocus'], 
					self.ctfvalues['defocus2'], self.ctfvalues['defocus1'])
			print defdiff*100
			if defdiff*100 > 1:
				apDisplay.printWarning("Large astigmatism")
				#sys.exit(1)
		else:
			self.ctfvalues['angle_astigmatism'] = 0.0
			self.ctfvalues['defocus1'] = self.ctfvalues['defocus']
			self.ctfvalues['defocus2'] = self.ctfvalues['defocus']

		if self.ctfvalues['amplitude_contrast'] < 0.0:
			self.ctfvalues['amplitude_contrast'] = 0.0
		if self.ctfvalues['amplitude_contrast'] > self.maxAmpCon:
			self.ctfvalues['amplitude_contrast'] = self.maxAmpCon

		if abs(self.ctfvalues['defocus1']) > abs(self.ctfvalues['defocus2']):
			# incorrect, need to shift angle by 90 degrees
			apDisplay.printWarning("|def1| > |def2|, flipping defocus axes")
			tempdef = self.ctfvalues['defocus1']
			self.ctfvalues['defocus1'] = self.ctfvalues['defocus2']
			self.ctfvalues['defocus2'] = tempdef
			self.ctfvalues['angle_astigmatism'] += 90
		# get astig_angle within range -90 < angle <= 90
		while self.ctfvalues['angle_astigmatism'] > 90:
			self.ctfvalues['angle_astigmatism'] -= 180
		while self.ctfvalues['angle_astigmatism'] < -90:
			self.ctfvalues['angle_astigmatism'] += 180

		avgres = self.getResolution(self.ctfvalues['defocus'], raddata, PSDarray, lowerbound)
		apDisplay.printColor("Final defocus values %.3e -> %.3e, %.3e; ac=%.2f, res=%.1f"
			%(self.ctfvalues['defocus'], self.ctfvalues['defocus1'], self.ctfvalues['defocus2'],
			self.ctfvalues['amplitude_contrast'], avgres/2.0), "green")

		for i in range(10):
			print "===================================="

		print "PREVIOUS VALUES"
		ctfdb.getBestCtfByResolution(imgdata)
		print "CURRENT VALUES"
		defocusratio = self.ctfvalues['defocus2']/self.ctfvalues['defocus1']
		apDisplay.printColor("def1: %.2e | def2: %.2e | angle: %.1f | ampcontr %.2f | defratio %.3f"
			%(self.ctfvalues['defocus1'], self.ctfvalues['defocus2'], self.ctfvalues['angle_astigmatism'],
			self.ctfvalues['amplitude_contrast'], defocusratio), "blue")
		self.printBestValues()
		print "===================================="

		return
	def findEllipseEdge(self, fftarray, mindef=None, maxdef=None):
		if mindef is None:
			mindef = self.params['mindef']
		if maxdef is None:
			maxdef = self.params['maxdef']

		minpeaks = ctftools.getCtfExtrema(maxdef, self.freq*1e10,
			self.ctfvalues['cs'], self.ctfvalues['volts'], 0.0,
			numzeros=3, zerotype="peaks")
		minEdgeRadius = minpeaks[0]

		maxvalleys = ctftools.getCtfExtrema(mindef, self.freq*1e10,
			self.ctfvalues['cs'], self.ctfvalues['volts'], 0.0,
			numzeros=3, zerotype="valleys")

		minEdgeRadius = (maxvalleys[0]+minpeaks[0])/2
		maxEdgeRadius = maxvalleys[2]

		minCircum = math.ceil(2 * minEdgeRadius * math.pi)
		minEdges = int(minCircum)

		maxCircum = math.ceil(2 * maxEdgeRadius * math.pi)
		maxEdges = 2*int(maxCircum)

		dograd = (minpeaks[1] - minpeaks[0])/3.0
		dogarray = apDog.diffOfGauss(fftarray, dograd, k=1.2)
		#dogarray = fftarray

		print "Edge range: ", minEdges, maxEdges

		edges = canny.canny_edges(dogarray, low_thresh=0.01,
			minEdgeRadius=minEdgeRadius, maxEdgeRadius=maxEdgeRadius, minedges=minEdges, maxedges=maxEdges)
		#minedges=2500, maxedges=15000,
		invedges = numpy.fliplr(numpy.flipud(edges))
		self.edgeMap = numpy.logical_and(edges, invedges)
		edges = self.edgeMap * (dogarray.max()/self.edgeMap.max())
		imagedata = dogarray.copy() + edges
		imagefile.arrayToJpeg(imagedata, "edges.jpg")

		edgeThresh = 3
		ellipseParams = ransac.ellipseRANSAC(self.edgeMap, edgeThresh, maxRatio=self.maxRatio)
		if ellipseParams is None:
			return None

		fitEllipse1 = ransac.generateEllipseRangeMap2(ellipseParams, edgeThresh, self.edgeMap.shape)
		fitEllipse2 = ransac.generateEllipseRangeMap2(ellipseParams, edgeThresh*3, self.edgeMap.shape)
		outlineEllipse = fitEllipse2 - fitEllipse1
		# image is draw upside down
		#outlineEllipse = numpy.flipud(outlineEllipse)

		imagedata = imagedata + 0.5*outlineEllipse*imagedata.max()

		if self.debug is True:
			from matplotlib import pyplot
			pyplot.clf()
			pyplot.imshow(imagedata)
			pyplot.gray()
			pyplot.show()

		self.ellipseParams = ellipseParams

		#self.convertEllipseToCtf(node=3)

		return ellipseParams
	def drawPowerSpecImage(self, origpowerspec, maxsize=1200):

		origpowerspec = ctftools.trimPowerSpectraToOuterResolution(origpowerspec, self.plotlimit2DAngstrom, self.trimfreq)

		if self.debug is True:
			print "origpowerspec shape", origpowerspec.shape

		#compute elliptical average and merge with original image
		pixelrdata, rotdata = ctftools.ellipticalAverage(origpowerspec, self.ellipratio, self.angle,
			self.ringwidth*3, 1, full=True)
		ellipavgpowerspec = ctftools.unEllipticalAverage(pixelrdata, rotdata, 
			self.ellipratio, self.angle, origpowerspec.shape)
		halfshape = origpowerspec.shape[1]/2
		halfpowerspec = numpy.hstack( (origpowerspec[:,:halfshape] , ellipavgpowerspec[:,halfshape:] ) )
		if halfpowerspec.shape != origpowerspec.shape:
			apDisplay.printError("Error in power spectra creation")

		if max(halfpowerspec.shape) > maxsize:
			scale = maxsize/float(max(halfpowerspec.shape))
			#scale = math.sqrt((random.random()+random.random()+random.random())/3.0)
			apDisplay.printMsg( "Scaling final powerspec image by %.3f"%(scale))
			powerspec = imagefilter.scaleImage(halfpowerspec, scale)
		else:
			scale = 1280./float(max(halfpowerspec.shape))
			powerspec = imagefilter.scaleImage(halfpowerspec, scale)
			#scale = 1.0
			#powerspec = halfpowerspec.copy()

		self.scaleapix = self.trimapix
		self.scalefreq = self.trimfreq/scale
		if self.debug is True:
			print "orig pixel", self.apix
			print "trim pixel", self.trimapix
			print "scale pixel", self.scaleapix

		numzeros = 13

		radii1 = ctftools.getCtfExtrema(self.defocus1, self.scalefreq*1e10, 
			self.cs, self.volts, self.ampcontrast, numzeros=numzeros, zerotype="valley")
		radii2 = ctftools.getCtfExtrema(self.defocus2, self.scalefreq*1e10, 
			self.cs, self.volts, self.ampcontrast, numzeros=numzeros, zerotype="valley")

		#smallest of two defocii
		firstpeak = radii2[0]

		### 
		### PART 9: DRAW THE 2D POWERSPEC IMAGE
		### 
		center = numpy.array(powerspec.shape, dtype=numpy.float)/2.0
		foundzeros = min(len(radii1), len(radii2))
		"""
		pyplot.clf()
		ax = pyplot.subplot(1,1,1)
		pyplot.xticks([], [])
		pyplot.yticks([], [])
		pyplot.imshow(powerspec)
		pyplot.gray()
		for i in range(foundzeros):
			# because |def1| < |def2| ==> firstzero1 > firstzero2
			major = radii1[i]*2
			minor = radii2[i]*2
			ell = Ellipse(xy=center, width=major, height=minor, angle=self.angle+90, 
				fill=False, edgecolor="yellow", antialiased=True, linewidth=0.5)
			ax.add_artist(ell)
		pyplot.subplots_adjust(wspace=0, hspace=0, bottom=0, left=0, top=1, right=1, )
		self.newpowerspecfile = apDisplay.short(self.imgname)+"-powerspec-new.png"
		pyplot.savefig(self.newpowerspecfile, format="png", dpi=150, pad_inches=0.0)
		"""

		### 
		### PART 9: DRAW THE 2D POWERSPEC IMAGE
		### 
		apDisplay.printColor("PART 9: DRAW THE 2D POWERSPEC IMAGE", "magenta")

		center = numpy.array(powerspec.shape, dtype=numpy.float)/2.0
		originalimage = imagefile.arrayToImage(powerspec)
		originalimage = originalimage.convert("RGB")
		pilimage = originalimage.copy()
		draw = ImageDraw.Draw(pilimage)

		#########
		## draw astig axis line, if astig > 5%
		#########
		perdiff = 2*abs(self.defocus1-self.defocus2)/abs(self.defocus1+self.defocus2)
		if self.debug is True:
			print "Percent Difference %.1f"%(perdiff*100)
		if perdiff > 0.05:
			#print self.angle, radii2[0], center
			x = 1*firstpeak*math.cos(math.radians(self.angle))
			y = firstpeak*math.sin(math.radians(self.angle))
			#print x,y
			xy = (x+center[0], y+center[1], -x+center[0], -y+center[1])
			#print xy
			draw.line(xy, fill="#f23d3d", width=10)
		elif perdiff > 1e-6:
			#print self.angle, radii2[0], center
			x = 1*firstpeak*math.cos(math.radians(self.angle))
			y = firstpeak*math.sin(math.radians(self.angle))
			#print x,y
			xy = (x+center[0], y+center[1], -x+center[0], -y+center[1])
			#print xy
			draw.line(xy, fill="#f23d3d", width=2)

		#########
		## draw colored CTF Thon rings
		#########
		foundzeros = min(len(radii1), len(radii2))
		#color="#3d3dd2" #blue
		color="#ffd700" #gold
		for i in range(foundzeros):

			# because |def1| < |def2| ==> firstzero1 > firstzero2
			major = radii1[i]
			minor = radii2[i]
			if self.debug is True: 
				print "major=%.1f, minor=%.1f, angle=%.1f"%(major, minor, self.angle)
			if minor > powerspec.shape[0]/math.sqrt(3):
				# this limits how far we draw out the ellipses sqrt(3) to corner, just 2 inside line
				break
			width = int(math.ceil(math.sqrt(numzeros - i)))*2

			### determine color of circle
			currentres = 1.0/(major*self.scalefreq)
			if currentres > self.res80:
				ringcolor = "green"
			elif currentres > self.res50:
				ringcolor = "gold"
			else:
				ringcolor = "red"

			### determine number of points to use to draw ellipse, minimize distance btw points
			#isoceles triangle, b: radius ot CTF ring, a: distance btw points
			#a = 2 * b sin (theta/2)
			#a / 2b = sin(theta/2)
			#theta = 2 * asin (a/2b)
			#numpoints = 2 pi / theta
			## define a to be 5 pixels
			a = 40
			theta = 2.0 * math.asin (a/(2.0*major))
			skipfactor = 2
			numpoints = int(math.ceil(2.0*math.pi/theta/skipfactor))*skipfactor + 1
			#print "numpoints", numpoints


			points = ellipse.generate_ellipse(major, minor, 
				math.radians(self.angle), center, numpoints, None, "step", True)
			x = points[:,0]
			y = points[:,1]

			## wrap around to end
			x = numpy.hstack((x, [x[0],]))
			y = numpy.hstack((y, [y[0],]))
			## convert image

			numsteps = int(math.floor((len(x)-2)/skipfactor))
			for j in range(numsteps):
				k = j*skipfactor
				xy = (x[k], y[k], x[k+1], y[k+1])
				draw.line(xy, fill=ringcolor, width=width)

		#########
		## draw blue resolution ring
		#########
		# 1/res = freq * pixrad => pixrad = 1/(res*freq)
		maxrad = (max(powerspec.shape)-1)/2.0 - 3
		maxres = 1.0/(self.scalefreq*maxrad)
		bestres = math.ceil(maxres)
		pixrad = 1.0/(self.scalefreq*bestres)
		if self.debug is True:
			print "bestres %d Angstroms (max: %.3f)"%(bestres, maxres)
			print "pixrad %d (max: %.3f)"%(pixrad, maxrad)
		if pixrad > maxrad:
			apDisplay.printError("Too big of outer radius to draw")
		outpixrad = math.ceil(pixrad)+1
		inpixrad = math.floor(pixrad)-1
		for i in numpy.arange(-4.0,4.01,0.01):
			r = pixrad + i
			blackxy = numpy.array((center[0]-r,center[1]-r, 
				center[0]+r,center[1]+r), dtype=numpy.float64)
			draw.ellipse(tuple(blackxy), outline="black")
		for i in numpy.arange(-1.50,1.51,0.01):
			r = pixrad + i
			whitexy = numpy.array((center[0]-r,center[1]-r, 
				center[0]+r,center[1]+r), dtype=numpy.float64)
			draw.ellipse(tuple(whitexy), outline="#0BB5FF")

		#########
		## setup font to add text
		#########
		fontpath = "/usr/share/fonts/liberation/LiberationSans-Regular.ttf"
		from PIL import ImageFont
		if os.path.isfile(fontpath):
			fontsize = int(math.ceil( 48/2. * min(powerspec.shape)/float(maxsize))*2)
			font = ImageFont.truetype(fontpath, fontsize)
		else:
			font = ImageFont.load_default()

		#########
		## add resolution ring text
		#########
		angrad = maxrad/math.sqrt(2) + 1
		coord = (angrad+maxrad, angrad+maxrad)
		for i in [-2,2]:
			for j in [-2,2]:
				draw.text((coord[0]+i,coord[1]+j), "%.1f A"%(bestres), font=font, fill="black")
		draw.text(coord, "%.1f A"%(bestres), font=font, fill="#0BB5FF")

		#########
		## add defocus value text
		#########
		meandef = abs(self.defocus1+self.defocus2)/2.0
		deftext = "%.2f um"%(meandef*1e6)
		tsize = draw.textsize(deftext, font=font)
		coord = (powerspec.shape[0]-4-tsize[0], powerspec.shape[0]-4-tsize[1])
		for i in [-2,2]:
			for j in [-2,2]:
				draw.text((coord[0]+i,coord[1]+j), deftext, font=font, fill="black")
		draw.text(coord, deftext, font=font, fill="#AB82FF")

		#########
		## add text about what sides of powerspec are:
		## left - raw data; right - elliptical average data
		#########
		leftcoord = (4, 4)
		for i in [-3, -1, 0, 1, 3]:
			for j in [-3, -1, 0, 1, 3]:
				draw.text((leftcoord[0]+i,leftcoord[1]+j) , "Raw CTF Data", font=font, fill="black")
		draw.text(leftcoord, "Raw CTF Data", font=font, fill="#00BFFF")

		tsize = draw.textsize("Elliptical Average", font=font)
		xdist = powerspec.shape[0] - 4 - tsize[0]
		rightcoord = (xdist, 4)
		for i in [-2,2]:
			for j in [-2,2]:
				draw.text((rightcoord[0]+i,rightcoord[1]+j), "Elliptical Average", font=font, fill="black")
		draw.text(rightcoord, "Elliptical Average", font=font, fill="#00BFFF")

		#########
		## create an alpha blend effect
		#########
		originalimage = Image.blend(originalimage, pilimage, 0.95)
		apDisplay.printMsg("Saving 2D powerspectra to file: %s"%(self.powerspecfile))
		#pilimage.save(self.powerspecfile, "JPEG", quality=85)
		originalimage.save(self.powerspecfile, "JPEG", quality=85)
		if not os.path.isfile(self.powerspecfile):
			apDisplay.printWarning("power spec file not created")
		if self.debug is True:
			#powerspecjpg = Image.open(self.powerspecfile)
			#powerspecjpg.show()
			pass
		return
	def normalizeCtf(self, zdata2d, twod=True):
		"""
		inner cut radius - radius for number of pixels to clip in the center of image
		"""
		### 
		### PART 1: SETUP PARAMETERS AND ELLIPTICAL AVERAGE
		###
		apDisplay.printColor("PART 1: SETUP PARAMETERS AND ELLIPTICAL AVERAGE", "magenta")

		meandefocus = math.sqrt(self.defocus1*self.defocus2)
		if meandefocus < 0.6e-6:
			self.ringwidth = 3.0
		elif meandefocus < 1.0e-6:
			self.ringwidth = 2.0
		elif meandefocus > 5.0e-6:
			self.ringwidth = 0.5

		### get all peak (not valley)
		peak = ctftools.getCtfExtrema(meandefocus, self.trimfreq*1e10, self.cs, self.volts, 
			self.ampcontrast, numzeros=250, zerotype="peak")
		apDisplay.printMsg("Number of available peaks is %d"%(len(peak)))
		if len(peak) < 6:
			apDisplay.printWarning("Too few peaks to work with, probably bad defocus estimate")
			return None
		firstpeak = peak[0]
		peakradii = numpy.array(peak, dtype=numpy.float64)*self.trimfreq
		### get all valley (not peak)
		valley = ctftools.getCtfExtrema(meandefocus, self.trimfreq*1e10, self.cs, self.volts, 
			self.ampcontrast, numzeros=250, zerotype="valley")
		firstvalley = valley[0]
		valleyradii = numpy.array(valley, dtype=numpy.float64)*self.trimfreq

		### do the elliptical average
		if self.ellipratio is None:
			return None
		pixelrdata, rotdata = ctftools.ellipticalAverage(zdata2d, self.ellipratio, self.angle,
			self.ringwidth, firstpeak, full=False)
		raddata = pixelrdata*self.trimfreq

		if self.debug is True:
			print "Elliptical CTF limits %.1f A -->> %.1fA"%(1./raddata.min(), 1./raddata.max())

		apDisplay.printMsg("Determine and subtract noise model")
		CtfNoise = ctfnoise.CtfNoise()

		### 
		### PART 2: BACKGROUND NOISE SUBTRACTION
		### 
		apDisplay.printColor("PART 2: BACKGROUND NOISE SUBTRACTION", "magenta")

		### split the function up in first 3/5 and last 3/5 of data with 1/5 overlap
		firstvalleyindex = numpy.searchsorted(raddata, self.trimfreq*firstvalley)
		numpoints = len(raddata) - firstvalleyindex
		# require at least 10 points past first peak of CTF to perform estimation
		if numpoints < 10:
			apDisplay.printWarning("Not enough points past first peak (n=%d < 10) to do background subtraction"
				%(numpoints))
			return None
		npart1start = firstvalleyindex
		npart1end = int(firstvalleyindex + numpoints*6/10.)
		npart2start = int(firstvalleyindex + numpoints*5/10.)
		npart2end = int(firstvalleyindex + numpoints*9/10.)
		npart3start = int(firstvalleyindex + numpoints*8/10.)
		npart3end = len(raddata)
		
		svalleydata = ctfnoise.peakExtender(raddata, rotdata, valleyradii, "below")

		### fit function below log(CTF), i.e., noise model	
		## first part data
		noisefitparams1 = CtfNoise.modelCTFNoise(raddata[npart1start:npart1end],
			svalleydata[npart1start:npart1end], "below")
		noisedata1 = CtfNoise.noiseModel(noisefitparams1, raddata)

		## second part data
		noisefitparams2 = CtfNoise.modelCTFNoise(raddata[npart2start:npart2end],
			rotdata[npart2start:npart2end], "below")
		noisedata2 = CtfNoise.noiseModel(noisefitparams2, raddata)

		## third part data
		#noisefitparams3 = CtfNoise.modelCTFNoise(raddata[npart3start:npart3end],
		#	svalleydata[npart3start:npart3end], "below")
		noisefitparams3 = CtfNoise.modelCTFNoise(raddata[npart3start:npart3end],
			rotdata[npart3start:npart3end], "below")
		noisedata3 = CtfNoise.noiseModel(noisefitparams3, raddata)

		## debug only
		if self.debug is True:
			singlenoisefitparams = CtfNoise.modelCTFNoise(raddata[npart1start:npart3end],
				svalleydata[npart1start:npart3end], "below")
			singlenoisedata = CtfNoise.noiseModel(singlenoisefitparams, raddata)

		## merge data
		scale = numpy.arange(npart1end-npart2start, dtype=numpy.float32)
		scale /= scale.max()
		overlapdata1 = noisedata1[npart2start:npart1end]*(1-scale) + noisedata2[npart2start:npart1end]*scale
		scale = numpy.arange(npart2end-npart3start, dtype=numpy.float32)
		scale /= scale.max()
		overlapdata2 = noisedata2[npart3start:npart2end]*(1-scale) + noisedata3[npart3start:npart2end]*scale

		mergedata = numpy.hstack((noisedata1[:npart2start], overlapdata1,
			noisedata2[npart1end:npart3start], overlapdata2,
			noisedata3[npart2end:]))

		noisedata = mergedata

		### DO THE SUBTRACTION
		normexprotdata = numpy.exp(rotdata) - numpy.exp(noisedata)

		### CUT OUT ANY NEGATIVE VALUES FOR DISPLAY AND FITTING PURPOSES ONLY
		minval = -1
		mindata = ndimage.maximum_filter(normexprotdata, 2)
		count = 0
		while minval < 3 and count < 10:
			count += 1
			mindata = ndimage.maximum_filter(mindata, 2)
			minval = mindata.min()
			if self.debug is True:
				apDisplay.printMsg("Minimum value for normalization: %.3f"%(minval))
		if minval < 3:
			minval = 3
		normlogrotdata = numpy.log(numpy.where(normexprotdata<minval, minval, normexprotdata))
		if numpy.isnan(normlogrotdata).any() is True:
			apDisplay.printError("Error in log normalization of CTF data")

		### 
		### PART 3: ENVELOPE NORMALIZATION
		### 
		apDisplay.printColor("PART 3: ENVELOPE NORMALIZATION", "magenta")

		### split the function up in first 3/5 and last 3/5 of data with 1/5 overlap
		firstpeakindex = numpy.searchsorted(raddata, firstpeak*self.trimfreq)
		numpoints = len(raddata) - firstpeakindex
		epart1start = firstpeakindex
		epart1end = int(firstpeakindex + numpoints*6/10.)
		epart2start = int(firstpeakindex + numpoints*5/10.)
		epart2end = int(firstpeakindex + numpoints*9/10.)
		epart3start = int(firstpeakindex + numpoints*8/10.)
		epart3end = len(raddata)

		peakdata = ctfnoise.peakExtender(raddata, normlogrotdata, peakradii, "above")

		## first part data
		envelopfitparams1 = CtfNoise.modelCTFNoise(raddata[epart1start:epart1end],
			peakdata[epart1start:epart1end], "above")
		envelopdata1 = CtfNoise.noiseModel(envelopfitparams1, raddata)

		## second part data
		envelopfitparams2 = CtfNoise.modelCTFNoise(raddata[epart2start:epart2end],
			peakdata[epart2start:epart2end], "above")
		envelopdata2 = CtfNoise.noiseModel(envelopfitparams2, raddata)

		## third part data
		envelopfitparams3 = CtfNoise.modelCTFNoise(raddata[epart3start:epart3end],
			peakdata[epart3start:epart3end], "above")
		envelopdata3 = CtfNoise.noiseModel(envelopfitparams3, raddata)

		## merge data
		scale = numpy.arange(epart1end-epart2start, dtype=numpy.float32)
		scale /= scale.max()
		overlapdata1 = envelopdata1[epart2start:epart1end]*(1-scale) + envelopdata2[epart2start:epart1end]*scale
		scale = numpy.arange(epart2end-epart3start, dtype=numpy.float32)
		scale /= scale.max()
		overlapdata2 = envelopdata2[epart3start:epart2end]*(1-scale) + envelopdata3[epart3start:epart2end]*scale

		mergedata = numpy.hstack((envelopdata1[:epart2start], overlapdata1,
			envelopdata2[epart1end:epart3start], overlapdata2,
			envelopdata3[epart2end:]))
		envelopdata = mergedata

		normnormexprotdata = normexprotdata / numpy.exp(envelopdata)

		### 
		### PART 4: PEAK EXTENSION
		### 
		apDisplay.printColor("PART 4: PEAK EXTENSION", "magenta")

		### Subtract fit valley locations
		valleydata = ctfnoise.peakExtender(raddata, normnormexprotdata, valleyradii, "below")
		valleydata = ndimage.gaussian_filter1d(valleydata, 1)
		normvalleydata = normnormexprotdata - valleydata

		### Normalize fit peak locations
		peakdata = ctfnoise.peakExtender(raddata, normvalleydata, peakradii, "above")
		peakdata = ndimage.gaussian_filter1d(peakdata, 1)
		normpeakdata = normvalleydata / peakdata

		### 
		### PART 5: CTF FIT AND CONFIDENCE
		### 
		apDisplay.printColor("PART 5: CTF FIT AND CONFIDENCE", "magenta")

		### everything in mks units, because rdata is 1/A multiply be 1e10 to get 1/m
		ctffitdata = genctf.generateCTF1d(raddata*1e10, focus=meandefocus, cs=self.cs,
			volts=self.volts, ampconst=self.ampcontrast, failParams=False)
		#ctffitdata2 = genctf.generateCTF1dACE2(raddata*1e10, focus=meandefocus, cs=self.cs,
		#	volts=self.volts, ampconst=self.ampcontrast, failParams=False)
		overctffitdata = genctf.generateCTF1d(raddata*1e10, focus=meandefocus, cs=self.cs,
			volts=self.volts, ampconst=self.ampcontrast, failParams=False, overfocus=True)

		ind30 = numpy.searchsorted(raddata, 1/30.)
		ind10 = numpy.searchsorted(raddata, 1/10.)
		self.conf3010 = scipy.stats.pearsonr(normpeakdata[ind30:ind10], ctffitdata[ind30:ind10])[0]
		self.overconf3010 = scipy.stats.pearsonr(normpeakdata[ind30:ind10], overctffitdata[ind30:ind10])[0]
		apDisplay.printColor("1/30A - 1/10A confidence is %.3f (overfocus %.3f)"%(self.conf3010, self.overconf3010), "green")
		if self.overconf3010 > self.conf3010*1.1:
			apDisplay.printWarning("Image is possibly over-focused")

		ind5peak1 = numpy.searchsorted(raddata, peakradii[0])
		ind5peak2 = numpy.searchsorted(raddata, peakradii[5])
		self.conf5peak = scipy.stats.pearsonr(normpeakdata[ind5peak1:ind5peak2], ctffitdata[ind5peak1:ind5peak2])[0]
		self.overconf5peak = scipy.stats.pearsonr(normpeakdata[ind5peak1:ind5peak2], overctffitdata[ind5peak1:ind5peak2])[0]
		apDisplay.printColor("5 peak confidence is %.3f (overfocus %.3f)"%(self.conf5peak, self.overconf5peak), "green")
		if self.overconf5peak > self.conf5peak*1.1:
			apDisplay.printWarning("Image is possibly over-focused")

		### 
		### PART 6: CTF RESOLUTION LIMITS
		### 
		apDisplay.printColor("PART 6: CTF RESOLUTION LIMITS", "magenta")

		confraddata, confdata = ctfres.getCorrelationProfile(raddata, 
			normpeakdata, ctffitdata, peak, self.trimfreq)
		overconfraddata, overconfdata = ctfres.getCorrelationProfile(raddata, 
			normpeakdata, overctffitdata, peak, self.trimfreq)

		self.res80 = ctfres.getResolutionFromConf(confraddata, confdata, limit=0.8)
		if self.res80 is None:
			self.res80 = 100.0
		self.overres80 = ctfres.getResolutionFromConf(overconfraddata, overconfdata, limit=0.8)
		if self.overres80 is None:
			self.overres80 = 100.0
		self.res50 = ctfres.getResolutionFromConf(confraddata, confdata, limit=0.5)
		if self.res50 is None:
			self.res50 = 100.0
			res50max = min(raddata.max(), 1/10.)
		elif self.res50 > 15.0:
			res50max = min(raddata.max(), 1/10.)
		else:
			res50max = min(raddata.max(), 1.5/self.res50)
		self.overres50 = ctfres.getResolutionFromConf(overconfraddata, overconfdata, limit=0.5)
		if self.overres50 is None:
			self.overres50 = 100.0


		apDisplay.printColor("Resolution limit is %.2f at 0.8 and %.2f at 0.5"
			%(self.res80, self.res50), "green")

		### 
		### PART 7: MAKE 1D PLOT SUMMARY FIGURE
		### 
		apDisplay.printColor("PART 7: MAKE 1D PLOT SUMMARY FIGURE", "magenta")

		titlefontsize=8
		axisfontsize=7
		raddatasq = raddata**2
		confraddatasq = confraddata**2
		valleyradiisq = valleyradii**2
		peakradiisq = peakradii**2
		fpi = firstpeakindex

		pyplot.clf()

		if 'subplot2grid' in dir(pyplot):
			pyplot.subplot2grid((3,2), (0,0))
		else:
			pyplot.subplot(2,2,1) # 2 rows, 2 columns, plot 1
		pyplot.title("Background Noise Subtraction", fontsize=titlefontsize)
		pyplot.ylabel("Log(PSD)", fontsize=axisfontsize)
		pyplot.plot(raddata[fpi:], rotdata[fpi:], 
			'-', color="blue", alpha=0.5, linewidth=0.5)
		pyplot.plot(raddata[fpi:], rotdata[fpi:], 
			'.', color="blue", alpha=0.75, markersize=2.0)
		pyplot.plot(raddata[npart1start:npart1end], noisedata1[npart1start:npart1end],
			'-', color="magenta", alpha=0.5, linewidth=2)
		pyplot.plot(raddata[npart2start:npart2end], noisedata2[npart2start:npart2end],
			'-', color="red", alpha=0.5, linewidth=2)
		pyplot.plot(raddata[npart3start:npart3end], noisedata3[npart3start:npart3end], 
			'-', color="orange", alpha=0.5, linewidth=2)
		pyplot.plot(raddata[fpi:], noisedata[fpi:], 
			'--', color="purple", alpha=1.0, linewidth=1)
		self.setPyPlotXLabels(raddata, valleyradii=valleyradii, maxloc=res50max)
		pyplot.ylim(ymin=noisedata.min())

		if 'subplot2grid' in dir(pyplot):
			pyplot.subplot2grid((3,2), (0,1))
		else:
			pyplot.subplot(2,2,2) # 2 rows, 2 columns, plot 2
		pyplot.title("Envelope Normalization", fontsize=titlefontsize)
		pyplot.ylabel("Log(PSD-Noise)", fontsize=axisfontsize)
		pyplot.plot(raddata[fpi:], normlogrotdata[fpi:],
			'-', color="blue", alpha=0.5, linewidth=0.5)
		pyplot.plot(raddata[fpi:], normlogrotdata[fpi:],
			'.', color="blue", alpha=0.75, markersize=2.0)
		pyplot.plot(raddata[epart1start:epart1end], envelopdata1[epart1start:epart1end],
			'-', color="magenta", alpha=0.5, linewidth=2)
		pyplot.plot(raddata[epart2start:epart2end], envelopdata2[epart2start:epart2end],
			'-', color="red", alpha=0.5, linewidth=2)
		pyplot.plot(raddata[epart3start:epart3end], envelopdata3[epart3start:epart3end],
			'-', color="orange", alpha=0.5, linewidth=2)
		pyplot.plot(raddata[fpi:], envelopdata[fpi:],
			'--', color="purple", alpha=1.0, linewidth=1)
		self.setPyPlotXLabels(raddata, peakradii=peakradii, maxloc=res50max)
		pyplot.ylim(ymax=envelopdata.max())

		if 'subplot2grid' in dir(pyplot):
			pyplot.subplot2grid((3,2), (1,0), colspan=2)
		else:
			pyplot.subplot(2,2,3) # 2 rows, 2 columns, plot 3
		pyplot.title("Fit of CTF data (30-10A %.3f / 5-peak %.3f) Def1= %.3e / Def2= %.3e"
			%(self.conf3010, self.conf5peak, self.defocus1, self.defocus2), fontsize=titlefontsize)
		pyplot.ylabel("Norm PSD", fontsize=titlefontsize)
		pyplot.plot(raddatasq[fpi:], ctffitdata[fpi:],
			'-', color="black", alpha=0.5, linewidth=1)
		#pyplot.plot(raddatasq[fpi:], overctffitdata[fpi:],
		#	'-', color="red", alpha=0.75, linewidth=1)
		pyplot.plot(raddatasq[fpi:], normpeakdata[fpi:],
			'-', color="blue", alpha=0.5, linewidth=0.5)
		pyplot.plot(raddatasq[fpi:], normpeakdata[fpi:],
			'.', color="blue", alpha=0.75, markersize=2.0)
		self.setPyPlotXLabels(raddatasq, maxloc=1.0/self.outerAngstrom1D**2, square=True)
		pyplot.grid(True, linestyle=':', )
		pyplot.ylim(-0.05, 1.05)

		"""
		pyplot.subplot2grid((3,2), (1,1))
		tenangindex = numpy.searchsorted(raddata, 1/10.)-1
		pyplot.title("Defocus1= %.3e / Defocus2= %.3e"
			%(self.defocus1, self.defocus2), fontsize=titlefontsize)
		pyplot.ylabel("Norm PSD", fontsize=titlefontsize)
		pyplot.plot(raddatasq[tenangindex:], ctffitdata[tenangindex:],
			'-', color="black", alpha=0.5, linewidth=1)
		pyplot.plot(raddatasq[tenangindex:], normpeakdata[tenangindex:],
			'-', color="blue", alpha=0.5, linewidth=0.5)
		pyplot.plot(raddatasq[tenangindex:], normpeakdata[tenangindex:],
			'.', color="blue", alpha=0.75, markersize=2.0)
		self.setPyPlotXLabels(raddatasq[tenangindex:], maxloc=1/7.**2, square=True)
		pyplot.grid(True, linestyle=':', )
		pyplot.ylim(-0.05, 1.05)
		"""

		if 'subplot2grid' in dir(pyplot):
			pyplot.subplot2grid((3,2), (2,0), colspan=2)
		else:
			pyplot.subplot(2,2,4) # 2 rows, 2 columns, plot 4
		pyplot.title("Resolution limits: %.2fA at 0.8 and %.2fA at 0.5"
			%(self.res80, self.res50), fontsize=titlefontsize)
		pyplot.ylabel("Correlation", fontsize=titlefontsize)
		pyplot.plot(raddata[fpi:], ctffitdata[fpi:],
			'-', color="black", alpha=0.2, linewidth=1)
		pyplot.plot(raddata[fpi:], normpeakdata[fpi:],
			'-', color="blue", alpha=0.2, linewidth=1)
		#pyplot.plot(raddata[fpi:], normpeakdata[fpi:],
		#	'.', color="black", alpha=0.25, markersize=1.0)
		pyplot.axvline(x=1.0/self.res80, linewidth=2, color="gold", alpha=0.95, ymin=0, ymax=0.8)
		pyplot.axvline(x=1.0/self.res50, linewidth=2, color="red", alpha=0.95, ymin=0, ymax=0.5)
		res80index = numpy.searchsorted(confraddata, 1.0/self.res80)
		pyplot.plot(confraddata[:res80index+1], confdata[:res80index+1],
			'-', color="green", alpha=1, linewidth=2)
		res50index = numpy.searchsorted(confraddata, 1.0/self.res50)
		pyplot.plot(confraddata[res80index-1:res50index+1], confdata[res80index-1:res50index+1],
			'-', color="orange", alpha=1, linewidth=2)
		pyplot.plot(confraddata[res50index-1:], confdata[res50index-1:],
			'-', color="red", alpha=1, linewidth=2)
		self.setPyPlotXLabels(raddata, maxloc=res50max)
		pyplot.grid(True, linestyle=':', )
		if self.res80 < 99:
			pyplot.ylim(-0.05, 1.05)
		elif self.res50 < 99:
			pyplot.ylim(-0.25, 1.05)
		else:
			pyplot.ylim(-0.55, 1.05)


		pyplot.subplots_adjust(wspace=0.22, hspace=0.50, 
			bottom=0.08, left=0.07, top=0.95, right=0.965, )
		self.plotsfile = apDisplay.short(self.imgname)+"-plots.png"
		apDisplay.printMsg("Saving 1D graph to file %s"%(self.plotsfile))
		pyplot.savefig(self.plotsfile, format="png", dpi=300, orientation='landscape', pad_inches=0.0)


		if self.debug is True:
			### write a 1d profile dat files

			f = open(apDisplay.short(self.imgname)+"-noise_fit.dat", "w")
			for i in range(npart1start, npart3end):
				f.write("%.16f\t%.16f\t%.16f\t%.16f\n"%(raddata[i], rotdata[i], singlenoisedata[i], noisedata[i]))
			f.write("&\n")
			for i in range(npart1start, npart1end):
				f.write("%.16f\t%.16f\n"%(raddata[i], noisedata1[i]))
			f.write("&\n")
			for i in range(npart2start, npart2end):
				f.write("%.16f\t%.16f\n"%(raddata[i], noisedata2[i]))
			f.write("&\n")
			for i in range(npart3start, npart3end):
				f.write("%.16f\t%.16f\n"%(raddata[i], noisedata3[i]))
			f.write("&\n")
			f.close()

			#smallrotdata = numpy.where(rotdata-singlenoisedata>0.19, 0.19, rotdata-singlenoisedata)
			noiseexp = numpy.exp(singlenoisedata)
			smallrotdata = numpy.exp(rotdata) - noiseexp
			minval = 3

			smallrotdata = numpy.log(numpy.where(smallrotdata<minval, minval, smallrotdata))
			smallnoise = numpy.exp(noisedata) - noiseexp
			smallnoise = numpy.log(numpy.where(smallnoise<minval, minval, smallnoise))
			smallnoise1 = numpy.exp(noisedata1) - noiseexp
			smallnoise1 = numpy.log(numpy.where(smallnoise1<minval, minval, smallnoise1))
			smallnoise2 = numpy.exp(noisedata2) - noiseexp
			smallnoise2 = numpy.log(numpy.where(smallnoise2<minval, minval, smallnoise2))
			smallnoise3 = numpy.exp(noisedata3) - noiseexp
			smallnoise3 = numpy.log(numpy.where(smallnoise3<minval, minval, smallnoise3))
			f = open(apDisplay.short(self.imgname)+"-noisesubt_fit.dat", "w")
			for i in range(len(ctffitdata)):
				f.write("%.16f\t%.16f\n"%(raddata[i], smallrotdata[i]))
			f.write("&\n")
			for i in range(npart1start, npart3end):
				f.write("%.16f\t%.16f\t%.16f\t%.16f\n"%(raddata[i], smallrotdata[i], smallnoise[i], 0))
			f.write("&\n")
			for i in range(npart1start, npart1end):
				f.write("%.16f\t%.16f\n"%(raddata[i], smallnoise1[i]))
			f.write("&\n")
			for i in range(npart2start, npart2end):
				f.write("%.16f\t%.16f\n"%(raddata[i], smallnoise2[i]))
			f.write("&\n")
			for i in range(npart3start, npart3end):
				f.write("%.16f\t%.16f\n"%(raddata[i], smallnoise3[i]))
			f.write("&\n")
			f.close()

			f = open(apDisplay.short(self.imgname)+"-ctf_fit.dat", "w")
			for i in range(len(ctffitdata)):
				f.write("%.16f\t%.16f\t%.16f\n"%(raddata[i], normpeakdata[i], ctffitdata[i]))
			f.close()
			#sys.exit(1)

		if self.debug is True:
			print "Showing results"
			#pyplot.show()
			#plotspng = Image.open(self.plotsfile)
			#plotspng.show()
		pyplot.clf()

		if twod is False:
			return zdata2d

		### 
		### PART 8: NORMALIZE THE 2D IMAGE
		### 
		apDisplay.printColor("PART 8: NORMALIZE THE 2D IMAGE", "magenta")

		### Convert 1D array into 2D array by un-elliptical average
		noise2d = ctftools.unEllipticalAverage(pixelrdata, noisedata,
			self.ellipratio, self.angle, zdata2d.shape)
		envelop2d = ctftools.unEllipticalAverage(pixelrdata, envelopdata,
			self.ellipratio, self.angle, zdata2d.shape)
		valley2d = ctftools.unEllipticalAverage(pixelrdata, valleydata,
			self.ellipratio, self.angle, zdata2d.shape)
		peak2d = ctftools.unEllipticalAverage(pixelrdata, peakdata,
			self.ellipratio, self.angle, zdata2d.shape)

		### Do the normalization on the 2d data
		#blur2d = ndimage.gaussian_filter(zdata2d, 2)
		normal2d = numpy.exp(zdata2d) - numpy.exp(noise2d)
		normal2d = normal2d / numpy.exp(envelop2d)
		normal2d = normal2d - valley2d
		normal2d = normal2d / peak2d
		normal2d = numpy.where(normal2d < -0.2, -0.2, normal2d)
		normal2d = numpy.where(normal2d > 1.2, 1.2, normal2d)

		return normal2d
Esempio n. 12
0
def findAstigmatism(fftarray, freq, defocus, resolution, ctfvalues, peakNum=1):
        """
        find the astigmatism from a radial 1D estimate of the defocus
        """
        #searchError = resolution/100.

        extrema = ctftools.getCtfExtrema(defocus, freq*1e10,
                ctfvalues['cs'], ctfvalues['volts'], ctfvalues['amplitude_contrast'],
                numzeros=peakNum*2+1, zerotype="all")
        if len(extrema) < 2*peakNum:
                return None
        minEdgeRadius = int(math.ceil(extrema[peakNum-1])) #first peak
        maxEdgeRadius = int(math.ceil(extrema[peakNum])) #second peak
        newshape = (maxEdgeRadius*2, maxEdgeRadius*2)

        print "newshape",newshape

        fftcenter = copy.deepcopy(imagefilter.frame_cut(fftarray, newshape))
        showImage(fftcenter)

        shape = fftcenter.shape
        ## create a grid of distance from the center
        xhalfshape = shape[0]/2.0
        x = numpy.arange(-xhalfshape, xhalfshape, 1) + 0.5
        yhalfshape = shape[1]/2.0
        y = numpy.arange(-yhalfshape, yhalfshape, 1) + 0.5
        xx, yy = numpy.meshgrid(x, y)
        radialArray = xx**2 + yy**2 - 0.5
        #radialArray = numpy.sqrt(radial)

        maxVal = fftcenter.max()*2
        minVal = fftcenter.min()
        if debug is True:
                fftcenter = numpy.where(radialArray > maxEdgeRadius**2, maxVal, fftcenter)
                showImage(fftcenter)
                fftcenter = numpy.where(radialArray < minEdgeRadius**2, maxVal, fftcenter)
                showImage(fftcenter)

        angleArray = numpy.arctan2(-yy,xx)
        numSteps = 360
        angleArray += math.pi
        angleArray /= 2*math.pi
        angleArray *= numSteps
        angleArray = numpy.asarray(angleArray, dtype=numpy.uint16)

        showImage(angleArray)

        dataIntegers = numpy.array(range(numSteps))

        xyData = numpy.array(
                scipy.ndimage.measurements.minimum_position(
                        fftcenter, angleArray, dataIntegers))

        if debug is True:
                fftcenter[xyData[:,0], xyData[:,1]] = maxVal*3
                showImage(fftcenter)

        ellipseParams = ellipse.totalLeastSquareEllipse(xyData, center=(xhalfshape, yhalfshape))
        if ellipseParams is None:
                return None
        ellipse.printParamsDict(ellipseParams)

        if debug is True:
                numPoints = int(math.pi*(ellipseParams['a']+ellipseParams['b']))
                ellPoints = ellipse.generate_ellipse(ellipseParams['a'], ellipseParams['b'], 
                        ellipseParams['alpha'], center=ellipseParams['center'], numpoints=numPoints, integers=True)
                fftcenter[ellPoints[:,0], ellPoints[:,1]] += maxVal
                showImage(fftcenter)

        return ellipseParams