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
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
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