def fitConstant(self, raddata, PSDarray):
		onevec = numpy.ones(raddata.shape)
		sqrtvec = numpy.sqrt(raddata)
		squarevec = raddata**2
		X = numpy.array([onevec]).transpose()
		fitparams = leastsq.totalLeastSquares(X, PSDarray, onevec)
		return fitparams[0]
	def fitLinearPlus(self, raddata, PSDarray):
		onevec = numpy.ones(raddata.shape)
		sqrtvec = numpy.sqrt(raddata)
		squarevec = raddata**2
		X = numpy.array([onevec, sqrtvec, raddata, squarevec]).transpose()
		fitparams = leastsq.totalLeastSquares(X, PSDarray, onevec)
		fitdata = fitparams[0] + fitparams[1]*sqrtvec + fitparams[2]*raddata + fitparams[3]*squarevec
		return fitdata
Example #3
0
def refineCTF(radial_array,
              angle_array,
              amp_con,
              z1,
              z2,
              angle_astig,
              normPSD,
              cs,
              wavelength,
              refineFlags=(1, 1, 1, 1),
              weights=None,
              msg=True):
    """
	take a 2D normalized PSB and refines all CTF parameters
	using a linear least squares

	all values in meters
	"""
    print "BEFORE ac=%.3f, z1=%.3e, z2=%.3e, astig=%.1f" % (amp_con, z1, z2,
                                                            angle_astig)
    print cs, wavelength
    print "resolution limits %.2f <> %.2f" % (1.0e10 / radial_array.max(),
                                              1.0e10 / radial_array.min())

    ### convert parameters
    C = math.sin(math.asin(amp_con) - math.pi / 4.)
    D = math.sqrt(1 - C**2)
    zavg = (z1 + z2) / 2.0
    zdiff = z2 - z1
    if abs(zdiff) < 1e-9:
        # this prevents singular matrices
        zdiff = 1e-9
    astigrad = math.radians(angle_astig)

    ### create astigmatic gamma function
    radialsq_array = radial_array**2
    astigcos_array = numpy.cos(2.0 * (angle_array - astigrad))
    defocus_array = zavg - zdiff / 2.0 * astigcos_array
    gamma_array = (-0.5 * math.pi * cs * wavelength**3 * radialsq_array**2 +
                   math.pi * wavelength * radialsq_array * defocus_array)
    del defocus_array, radial_array

    ### create refinement vectors
    cosvec = numpy.cos(2 * gamma_array)  #C
    sinvec = numpy.sin(2 * gamma_array)  #D
    dCTFdGamma_array = -2 * C * sinvec + 2 * D * cosvec
    onevec = numpy.ones(radialsq_array.shape)
    zavgvec = wavelength * math.pi * radialsq_array * dCTFdGamma_array
    zdiffvec = -0.5 * zavgvec * astigcos_array
    zastigvec = zavgvec * zdiff * numpy.sin(2.0 * (angle_array - astigrad))
    del gamma_array, astigcos_array, dCTFdGamma_array

    ### create X data matrix and adjust y values
    #X = numpy.array([cosvec, sinvec]).transpose()
    X = numpy.vstack([cosvec, sinvec])
    if refineFlags[0] == 1:
        X = numpy.vstack([X, zavgvec])
    if refineFlags[1] == 1:
        X = numpy.vstack([X, zdiffvec])
    if refineFlags[2] == 1:
        X = numpy.vstack([X, zastigvec])
    X = numpy.vstack([X, onevec, radialsq_array])
    X = X.transpose()
    del cosvec, sinvec, zavgvec, zdiffvec, zastigvec, angle_array

    # create weighted matrix
    if weights is None:
        # make an identity matrix for no weights
        weights = numpy.ones(normPSD.shape[0])

    # adjust y values
    yprime = 2 * normPSD - 1

    ## solve it
    beta = leastsq.totalLeastSquares(X, yprime, weights)
    if beta is None:
        beta = leastsq.numpyLeastSquares(X, yprime)
    del X, weights
    if beta is None:
        apDisplay.printWarning("Least squares failed")
        return None

    #translate the values
    index = 0
    C = beta[index]
    index += 1
    D = beta[index]
    index += 1
    if refineFlags[0] == 1:
        dzavg = beta[index]
        print "dzavg", dzavg
        index += 1
    else:
        dzavg = 0
    if refineFlags[1] == 1:
        dzdiff = beta[index]
        index += 1
        print "dzdiff", dzdiff
    else:
        dzdiff = 0
    if refineFlags[2] == 1:
        dtheta = beta[index] % 2 * math.pi
        index += 1
        print "dtheta", dtheta
    else:
        dtheta = 0
    constant = beta[index]
    index += 1
    sqterm = beta[index]
    index += 1
    if refineFlags[3] == 1:
        psi = 0.5 * math.atan2(C, D)
        phi = psi + math.pi / 4
        amp_con = math.sin(phi)

    zavg += dzavg
    zdiff += dzdiff
    if zdiff < 0:
        zdiff = 0

    z1 = zavg - zdiff / 2
    z2 = zavg + zdiff / 2.

    if refineFlags[2] == 1:
        astigrad += dtheta
        angle_astig = math.degrees(astigrad)

    print "AFTER ac=%.3f, z1=%.3e, z2=%.3e, astig=%.1f" % (amp_con, z1, z2,
                                                           angle_astig)

    if msg is True:
        from matplotlib import pyplot
        args = numpy.argsort(radialsq_array)
        radialsq_array = radialsq_array[args]
        yprime = yprime[args]
        pyplot.clf()
        yprime2 = yprime - constant - sqterm * radialsq_array
        yprime2 /= numpy.abs(yprime2).max()
        newGamma = (-0.5 * math.pi * cs * wavelength**3 * radialsq_array**2 +
                    math.pi * wavelength * radialsq_array * zavg)
        newB = math.sqrt(1 - amp_con**2)
        adjctf1 = 2 * numpy.power(
            amp_con * numpy.cos(newGamma) + newB * numpy.sin(newGamma), 2) - 1
        pyplot.plot(radialsq_array, yprime2, '.', color="gray")
        #pyplot.plot(radialsq_array, yprime2, 'k-',)
        pyplot.plot(
            radialsq_array,
            adjctf1,
            'b--',
        )
        pyplot.title("CTF Refine 2D Fit")
        pyplot.subplots_adjust(
            wspace=0.05,
            hspace=0.05,
            bottom=0.05,
            left=0.05,
            top=0.95,
            right=0.95,
        )
        pyplot.show()

    if amp_con < 0.0:
        apDisplay.printWarning(
            "amp contrast is negative (reduce defocus): %.4f" % (amp_con))
        #return None

    if amp_con > 0.5:
        apDisplay.printWarning(
            "amp contrast is too large (increase defocus): %.8f" % (amp_con))
        #return None

    return amp_con, z1, z2, angle_astig
Example #4
0
def refineCTFOneDimension(radial_array,
                          amp_con,
                          zavg,
                          normPSD,
                          cs,
                          wavelength,
                          weights=None,
                          msg=True):
    """
	take a 2D normalized PSB and refines all CTF parameters
	using a linear least squares

	all values in meters
	"""
    apDisplay.printColor("BEFORE ac=%.3f, zavg=%.3e" % (amp_con, zavg), "cyan")
    print cs, wavelength
    print "resolution limits %.2f <> %.2f" % (1.0e10 / radial_array.max(),
                                              1.0e10 / radial_array.min())

    ### convert parameters
    C = math.sin(math.asin(amp_con) - math.pi / 4.)
    D = math.sqrt(1 - C**2)

    ### create astigmatic gamma function
    radialsq_array = radial_array**2
    gamma_array = (-0.5 * math.pi * cs * wavelength**3 * radialsq_array**2 +
                   math.pi * wavelength * radialsq_array * zavg)

    ### create refinement vectors
    cosvec = numpy.cos(2 * gamma_array)  #C
    sinvec = numpy.sin(2 * gamma_array)  #D
    onevec = numpy.ones(radialsq_array.shape)
    dCTFdGamma_array = -2 * C * sinvec + 2 * D * cosvec
    zavgvec = wavelength * math.pi * radialsq_array * dCTFdGamma_array

    ### create X data matrix and adjust
    X = numpy.array([cosvec, sinvec, zavgvec, onevec,
                     radialsq_array]).transpose()

    # create weighted matrix
    if weights is None:
        # make an identity matrix for no weights
        weights = numpy.ones(normPSD.shape[0])

    # adjust y values
    yprime = (normPSD - normPSD.mean())
    yprime /= numpy.abs(yprime).max()

    ## solve it
    beta = leastsq.totalLeastSquares(X, yprime, weights)
    if beta is None:
        beta = leastsq.numpyLeastSquares(X, yprime)
    del X, weights
    if beta is None:
        apDisplay.printWarning("Least squares failed")
        return None

    #translate the values
    C = beta[0]
    D = beta[1]
    dzavg = beta[2]
    constant = beta[3]
    sqterm = beta[4]
    print beta
    psi = 0.5 * math.atan2(C, D)
    print "psi=", psi
    phi = psi + math.pi / 4
    print "phi=", phi
    amp_con = math.sin(phi)

    if dzavg / zavg > 1:
        apDisplay.printWarning("Bad defocus change: %.4e --> %.4e" %
                               (zavg, zavg + dzavg))
        return None

    zavg += dzavg

    print "AFTER ac=%.3f, zavg=%.3e" % (amp_con, zavg)

    apDisplay.printColor("AFTER ac=%.3f, zavg=%.3e" % (amp_con, zavg), "cyan")

    newGamma = (-0.5 * math.pi * cs * wavelength**3 * radialsq_array**2 +
                math.pi * wavelength * radialsq_array * zavg)

    fitctf1 = C * cosvec + D * sinvec
    fitctf1b = numpy.sin(2 * gamma_array + 2 * psi)
    fitctf2 = numpy.sin(2 * newGamma + 2 * psi)
    newB = math.sqrt(1 - amp_con**2)
    # need to do the y' = 2 y - 1
    adjctf1 = 2 * numpy.power(
        amp_con * numpy.cos(newGamma) + newB * numpy.sin(newGamma), 2) - 1

    crosscorr = scipy.stats.pearsonr(fitctf2, adjctf1)[0]

    if crosscorr < -0.6:
        print "likely 180 degree out of phase"
        apDisplay.printWarning("Bad angle translation: %.8f" % (amp_con))

    if msg is True:
        from matplotlib import pyplot
        pyplot.clf()
        yprime2 = yprime - constant - sqterm * radialsq_array
        yprime2 /= numpy.abs(yprime2).max()
        pyplot.plot(radialsq_array, yprime2, '.', color="gray")
        pyplot.plot(
            radialsq_array,
            yprime2,
            'k-',
        )
        pyplot.plot(
            radialsq_array,
            fitctf1b,
            'r--',
        )
        pyplot.plot(
            radialsq_array,
            fitctf2,
            'g--',
        )
        pyplot.plot(
            radialsq_array,
            adjctf1,
            'b--',
        )

        conf1 = scipy.stats.pearsonr(yprime2, fitctf1b)[0]
        conf2 = scipy.stats.pearsonr(yprime2, adjctf1)[0]
        conf3 = scipy.stats.pearsonr(yprime2, fitctf2)[0]

        #pyplot.ylim(ymin=-1.05, ymax=1.05)
        pyplot.title("CTF Refine 1D Fit (%.2f, %.2f, %.2f) CC=%.3f" %
                     (conf1, conf2, conf3, crosscorr))
        pyplot.subplots_adjust(
            wspace=0.05,
            hspace=0.05,
            bottom=0.05,
            left=0.05,
            top=0.95,
            right=0.95,
        )
        pyplot.show()

    if crosscorr < 0.5:
        apDisplay.printWarning("Bad angle translation: %.8f" % (amp_con))
        return None

    if zavg > 20e-6 or zavg < 0.1e-6:
        apDisplay.printWarning("Bad defocus change: %.4e --> %.4e" %
                               (zavg - dzavg, zavg))
        return None

    if amp_con < 0.0:
        apDisplay.printWarning(
            "amp contrast is negative (reduce defocus): %.4f" % (amp_con))
        #return None

    if amp_con > 0.6:
        apDisplay.printWarning(
            "amp contrast is too large (increase defocus): %.8f" % (amp_con))
        #return None

    return amp_con, zavg
Example #5
0
def refineAmplitudeContrast(radial_array,
                            defocus,
                            normPSD,
                            cs,
                            wavelength,
                            weights=None,
                            msg=True):
    """
	takes elliptical average data and fits it to the equation
	A cos(x) + B sin(x)
	"""

    if msg is True:
        print "resolution limits %.2f <> %.2f" % (1.0e10 / radial_array.max(),
                                                  1.0e10 / radial_array.min())

    # create X matrix
    radialsq = radial_array**2
    if msg is True:
        print 1.0 / radial_array[-1], wavelength, defocus, cs
    gamma = (-0.5 * math.pi * cs * wavelength**3 * radialsq**2 +
             math.pi * wavelength * radialsq * defocus)
    cosvec = numpy.cos(2 * gamma)  #C
    sinvec = numpy.sin(2 * gamma)  #D
    onevec = numpy.ones(gamma.shape)  #extra constant
    X = numpy.array([cosvec, sinvec, onevec, radialsq]).transpose()
    #del cosvec, sinvec, gamma

    # create weighted matrix
    if weights is None:
        # make an identity matrix for no weights
        weights = numpy.ones(normPSD.shape[0])

    # adjust y values
    yprime = (normPSD - normPSD.mean())
    yprime /= numpy.abs(yprime).max()

    ## solve it
    beta = leastsq.totalLeastSquares(X, yprime, weights)
    if beta is None:
        beta = leastsq.numpyLeastSquares(X, yprime)
    del X, weights
    if beta is None:
        apDisplay.printWarning("Least squares failed")
        return None

    #translate the values
    C = beta[0]
    D = beta[1]
    constant = beta[2]
    sqterm = beta[3]
    if msg is True:
        print beta, radial_array.shape
    psi = 0.5 * math.atan2(C, D)
    if msg is True:
        print "psi=", psi
    phi = psi + math.pi / 4
    if msg is True:
        print "phi=", phi
    amp_con = math.sin(phi)

    if msg is True:
        apDisplay.printColor("amplitude contrast = %.8f" % (amp_con), "cyan")

    fitctf1 = C * cosvec + D * sinvec
    fitctf2 = numpy.sin(2 * gamma + 2 * psi)
    newB = math.sqrt(1 - amp_con**2)
    # need to do the y' = 2 y - 1
    adjctf1 = 2 * numpy.power(
        amp_con * numpy.cos(gamma) + newB * numpy.sin(gamma), 2) - 1
    #adjctf2 = 2 * numpy.power(numpy.sin(gamma + math.asin(amp_con)), 2) - 1

    crosscorr = scipy.stats.pearsonr(fitctf2, adjctf1)[0]
    yprime2 = yprime - constant - sqterm * radialsq
    yprime2 /= numpy.abs(yprime2).max()
    fitconf = scipy.stats.pearsonr(yprime2, fitctf2)[0]

    if msg is True:
        from matplotlib import pyplot
        pyplot.clf()

        pyplot.plot(radialsq, yprime2, '.', color="gray")
        pyplot.plot(
            radialsq,
            yprime2,
            'k-',
        )
        pyplot.plot(
            radialsq,
            fitctf1,
            'r--',
        )
        pyplot.plot(
            radialsq,
            fitctf2,
            'g--',
        )
        pyplot.plot(
            radialsq,
            adjctf1,
            'b--',
        )

        conf1 = scipy.stats.pearsonr(yprime2, fitctf1)[0]
        conf2 = scipy.stats.pearsonr(yprime2, adjctf1)[0]
        conf3 = scipy.stats.pearsonr(yprime2, fitctf2)[0]

        print "conf %.4f, %.4f, %.4f; cc = %.4f" % (conf1, conf2, conf3,
                                                    crosscorr)

        #pyplot.ylim(ymin=-1.05, ymax=1.05)
        pyplot.title("Amplitude Contrast Fit (%.2f, %.2f, %.2f) CC=%.3f" %
                     (conf1, conf2, conf3, crosscorr))
        pyplot.subplots_adjust(
            wspace=0.05,
            hspace=0.05,
            bottom=0.05,
            left=0.05,
            top=0.95,
            right=0.95,
        )
        pyplot.show()

    if crosscorr < -0.6:
        print "likely 180 degree out of phase"
        apDisplay.printWarning("Bad angle translation: %.8f" % (amp_con))
        return None

    if fitconf < 0.1 and amp_con > 0.4:
        apDisplay.printWarning("Bad fit confidence %.3f, ac=%.8f" %
                               (fitconf, amp_con))
        return None

    if crosscorr < 0.5:
        apDisplay.printWarning("Bad angle translation: %.8f" % (amp_con))
        return None

    if amp_con < 0.0:
        apDisplay.printWarning(
            "amp contrast is negative (reduce defocus): %.4f" % (amp_con))
        #return None

    if amp_con > 0.6:
        apDisplay.printWarning(
            "amp contrast is too large (increase defocus): %.8f" % (amp_con))
        #return None

    return amp_con
def refineCTF(radial_array, angle_array, 
        amp_con, z1, z2, angle_astig, 
        normPSD, cs, wavelength, refineFlags=(1,1,1,1), weights=None, msg=True):
        """
        take a 2D normalized PSB and refines all CTF parameters
        using a linear least squares

        all values in meters
        """
        print "BEFORE ac=%.3f, z1=%.3e, z2=%.3e, astig=%.1f"%(amp_con, z1, z2, angle_astig)
        print cs, wavelength
        print "resolution limits %.2f <> %.2f"%(1.0e10/radial_array.max(), 1.0e10/radial_array.min())

        ### convert parameters
        C = math.sin(math.asin(amp_con) - math.pi/4.)
        D = math.sqrt(1 - C**2)
        zavg = (z1 + z2)/2.0
        zdiff = z2 - z1
        if abs(zdiff) < 1e-9:
                # this prevents singular matrices
                zdiff = 1e-9
        astigrad = math.radians(angle_astig)

        ### create astigmatic gamma function
        radialsq_array = radial_array**2
        astigcos_array = numpy.cos(2.0*(angle_array - astigrad))
        defocus_array = zavg - zdiff/2.0 * astigcos_array
        gamma_array = ( -0.5*math.pi * cs * wavelength**3 * radialsq_array**2
                + math.pi * wavelength * radialsq_array * defocus_array )
        del defocus_array, radial_array

        ### create refinement vectors
        cosvec = numpy.cos(2*gamma_array) #C
        sinvec = numpy.sin(2*gamma_array) #D
        dCTFdGamma_array = -2*C*sinvec + 2*D*cosvec
        onevec = numpy.ones(radialsq_array.shape)
        zavgvec = wavelength*math.pi*radialsq_array * dCTFdGamma_array
        zdiffvec = -0.5*zavgvec * astigcos_array
        zastigvec = zavgvec * zdiff * numpy.sin(2.0*(angle_array- astigrad))
        del gamma_array, astigcos_array, dCTFdGamma_array

        ### create X data matrix and adjust y values
        #X = numpy.array([cosvec, sinvec]).transpose()
        X = numpy.vstack([cosvec, sinvec])
        if refineFlags[0] == 1:
                X = numpy.vstack([X, zavgvec])
        if refineFlags[1] == 1:
                X = numpy.vstack([X, zdiffvec])
        if refineFlags[2] == 1:
                X = numpy.vstack([X, zastigvec])
        X = numpy.vstack([X, onevec, radialsq_array])
        X = X.transpose()
        del cosvec, sinvec, zavgvec, zdiffvec, zastigvec, angle_array

        # create weighted matrix
        if weights is None:
                # make an identity matrix for no weights
                weights = numpy.ones(normPSD.shape[0])

        # adjust y values
        yprime = 2 * normPSD - 1

        ## solve it
        beta = leastsq.totalLeastSquares(X, yprime, weights)
        if beta is None:
                beta = leastsq.numpyLeastSquares(X, yprime)
        del X, weights
        if beta is None:
                apDisplay.printWarning("Least squares failed")
                return None

        #translate the values
        index = 0
        C = beta[index]
        index += 1
        D = beta[index]
        index += 1
        if refineFlags[0] == 1:
                dzavg = beta[index]
                print "dzavg", dzavg
                index += 1
        else:
                dzavg = 0
        if refineFlags[1] == 1:
                dzdiff = beta[index]
                index += 1
                print "dzdiff", dzdiff
        else:
                dzdiff = 0
        if refineFlags[2] == 1:
                dtheta = beta[index] % 2*math.pi
                index += 1
                print "dtheta", dtheta
        else:
                dtheta = 0
        constant = beta[index]
        index += 1
        sqterm = beta[index]
        index += 1
        if refineFlags[3] == 1:
                psi = 0.5*math.atan2(C,D)
                phi = psi + math.pi/4
                amp_con = math.sin(phi)

        zavg += dzavg
        zdiff += dzdiff
        if zdiff < 0:
                zdiff = 0

        z1 = zavg - zdiff/2
        z2 = zavg + zdiff/2.

        if refineFlags[2] == 1:
                astigrad += dtheta
                angle_astig = math.degrees(astigrad)

        print "AFTER ac=%.3f, z1=%.3e, z2=%.3e, astig=%.1f"%(amp_con, z1, z2, angle_astig)

        if msg is True:
                from matplotlib import pyplot
                args = numpy.argsort(radialsq_array)
                radialsq_array = radialsq_array[args]
                yprime = yprime[args]
                pyplot.clf()
                yprime2 = yprime - constant - sqterm*radialsq_array
                yprime2 /= numpy.abs(yprime2).max()
                newGamma = ( -0.5*math.pi * cs * wavelength**3 * radialsq_array**2
                        + math.pi * wavelength * radialsq_array * zavg )
                newB = math.sqrt(1 - amp_con**2)
                adjctf1 = 2 * numpy.power(amp_con*numpy.cos(newGamma) + newB*numpy.sin(newGamma), 2) - 1
                pyplot.plot(radialsq_array, yprime2, '.', color="gray")
                #pyplot.plot(radialsq_array, yprime2, 'k-',)
                pyplot.plot(radialsq_array, adjctf1, 'b--',)
                pyplot.title("CTF Refine 2D Fit")
                pyplot.subplots_adjust(wspace=0.05, hspace=0.05,
                        bottom=0.05, left=0.05, top=0.95, right=0.95, )
                pyplot.show()

        if amp_con < 0.0:
                apDisplay.printWarning("amp contrast is negative (reduce defocus): %.4f"%(amp_con))
                #return None

        if amp_con > 0.5:
                apDisplay.printWarning("amp contrast is too large (increase defocus): %.8f"%(amp_con))
                #return None

        return amp_con, z1, z2, angle_astig
def refineCTFOneDimension(radial_array, amp_con, zavg, normPSD, cs, wavelength, weights=None, msg=True):
        """
        take a 2D normalized PSB and refines all CTF parameters
        using a linear least squares

        all values in meters
        """
        apDisplay.printColor("BEFORE ac=%.3f, zavg=%.3e"%(amp_con, zavg), "cyan")
        print cs, wavelength
        print "resolution limits %.2f <> %.2f"%(1.0e10/radial_array.max(), 1.0e10/radial_array.min())

        ### convert parameters
        C = math.sin(math.asin(amp_con) - math.pi/4.)
        D = math.sqrt(1 - C**2)

        ### create astigmatic gamma function
        radialsq_array = radial_array**2
        gamma_array = ( -0.5*math.pi * cs * wavelength**3 * radialsq_array**2
                + math.pi * wavelength * radialsq_array * zavg )

        ### create refinement vectors
        cosvec = numpy.cos(2*gamma_array) #C
        sinvec = numpy.sin(2*gamma_array) #D
        onevec = numpy.ones(radialsq_array.shape)
        dCTFdGamma_array = -2*C*sinvec + 2*D*cosvec
        zavgvec = wavelength*math.pi*radialsq_array * dCTFdGamma_array

        ### create X data matrix and adjust
        X = numpy.array([cosvec, sinvec, zavgvec, onevec, radialsq_array]).transpose()

        # create weighted matrix
        if weights is None:
                # make an identity matrix for no weights
                weights = numpy.ones(normPSD.shape[0])

        # adjust y values
        yprime = (normPSD - normPSD.mean())
        yprime /= numpy.abs(yprime).max()

        ## solve it
        beta = leastsq.totalLeastSquares(X, yprime, weights)
        if beta is None:
                beta = leastsq.numpyLeastSquares(X, yprime)
        del X, weights
        if beta is None:
                apDisplay.printWarning("Least squares failed")
                return None

        #translate the values
        C = beta[0]
        D = beta[1]
        dzavg = beta[2]
        constant = beta[3]
        sqterm = beta[4]
        print beta
        psi = 0.5*math.atan2(C,D)
        print "psi=", psi
        phi = psi + math.pi/4
        print "phi=", phi
        amp_con = math.sin(phi)

        if dzavg/zavg > 1:
                apDisplay.printWarning("Bad defocus change: %.4e --> %.4e"%(zavg, zavg+dzavg))
                return None

        zavg += dzavg

        print "AFTER ac=%.3f, zavg=%.3e"%(amp_con, zavg)

        apDisplay.printColor("AFTER ac=%.3f, zavg=%.3e"%(amp_con, zavg), "cyan")

        newGamma = ( -0.5*math.pi * cs * wavelength**3 * radialsq_array**2
                + math.pi * wavelength * radialsq_array * zavg )

        fitctf1 = C*cosvec + D*sinvec
        fitctf1b = numpy.sin(2*gamma_array + 2*psi)
        fitctf2 = numpy.sin(2*newGamma + 2*psi)
        newB = math.sqrt(1 - amp_con**2)
        # need to do the y' = 2 y - 1
        adjctf1 = 2 * numpy.power(amp_con*numpy.cos(newGamma) + newB*numpy.sin(newGamma), 2) - 1

        crosscorr = scipy.stats.pearsonr(fitctf2, adjctf1)[0]

        if crosscorr < -0.6:
                print "likely 180 degree out of phase"
                apDisplay.printWarning("Bad angle translation: %.8f"%(amp_con))

        if msg is True:
                from matplotlib import pyplot
                pyplot.clf()
                yprime2 = yprime - constant - sqterm*radialsq_array
                yprime2 /= numpy.abs(yprime2).max()
                pyplot.plot(radialsq_array, yprime2, '.', color="gray")
                pyplot.plot(radialsq_array, yprime2, 'k-',)
                pyplot.plot(radialsq_array, fitctf1b, 'r--',)
                pyplot.plot(radialsq_array, fitctf2, 'g--',)
                pyplot.plot(radialsq_array, adjctf1, 'b--',)

                conf1 = scipy.stats.pearsonr(yprime2, fitctf1b)[0]
                conf2 = scipy.stats.pearsonr(yprime2, adjctf1)[0]
                conf3 = scipy.stats.pearsonr(yprime2, fitctf2)[0]

                #pyplot.ylim(ymin=-1.05, ymax=1.05)
                pyplot.title("CTF Refine 1D Fit (%.2f, %.2f, %.2f) CC=%.3f"%(conf1, conf2, conf3, crosscorr))
                pyplot.subplots_adjust(wspace=0.05, hspace=0.05,
                        bottom=0.05, left=0.05, top=0.95, right=0.95, )
                pyplot.show()

        if crosscorr < 0.5:
                apDisplay.printWarning("Bad angle translation: %.8f"%(amp_con))
                return None

        if zavg > 20e-6 or zavg < 0.1e-6:
                apDisplay.printWarning("Bad defocus change: %.4e --> %.4e"%(zavg-dzavg, zavg))
                return None

        if amp_con < 0.0:
                apDisplay.printWarning("amp contrast is negative (reduce defocus): %.4f"%(amp_con))
                #return None

        if amp_con > 0.6:
                apDisplay.printWarning("amp contrast is too large (increase defocus): %.8f"%(amp_con))
                #return None

        return amp_con, zavg
def refineAmplitudeContrast(radial_array, defocus, normPSD, cs, wavelength, weights=None, msg=True):
        """
        takes elliptical average data and fits it to the equation
        A cos(x) + B sin(x)
        """

        if msg is True:
                print "resolution limits %.2f <> %.2f"%(1.0e10/radial_array.max(), 1.0e10/radial_array.min())

        # create X matrix
        radialsq = radial_array**2
        if msg is True:
                print 1.0/radial_array[-1], wavelength, defocus, cs
        gamma = ( -0.5 * math.pi * cs * wavelength**3 * radialsq**2
                + math.pi * wavelength * radialsq * defocus )
        cosvec = numpy.cos(2*gamma) #C
        sinvec = numpy.sin(2*gamma) #D
        onevec = numpy.ones(gamma.shape) #extra constant
        X = numpy.array([cosvec, sinvec, onevec, radialsq]).transpose()
        #del cosvec, sinvec, gamma

        # create weighted matrix
        if weights is None:
                # make an identity matrix for no weights
                weights = numpy.ones(normPSD.shape[0])

        # adjust y values
        yprime = (normPSD - normPSD.mean())
        yprime /= numpy.abs(yprime).max()

        ## solve it
        beta = leastsq.totalLeastSquares(X, yprime, weights)
        if beta is None:
                beta = leastsq.numpyLeastSquares(X, yprime)
        del X, weights
        if beta is None:
                apDisplay.printWarning("Least squares failed")
                return None

        #translate the values
        C = beta[0]
        D = beta[1]
        constant = beta[2]
        sqterm = beta[3]
        if msg is True:
                print beta, radial_array.shape
        psi = 0.5*math.atan2(C,D)
        if msg is True:
                print "psi=", psi
        phi = psi + math.pi/4
        if msg is True:
                print "phi=", phi
        amp_con = math.sin(phi)

        if msg is True:
                apDisplay.printColor("amplitude contrast = %.8f"%(amp_con), "cyan")

        fitctf1 = C*cosvec + D*sinvec
        fitctf2 = numpy.sin(2*gamma + 2*psi)
        newB = math.sqrt(1 - amp_con**2)
        # need to do the y' = 2 y - 1
        adjctf1 = 2 * numpy.power(amp_con*numpy.cos(gamma) + newB*numpy.sin(gamma), 2) - 1
        #adjctf2 = 2 * numpy.power(numpy.sin(gamma + math.asin(amp_con)), 2) - 1

        crosscorr = scipy.stats.pearsonr(fitctf2, adjctf1)[0]
        yprime2 = yprime - constant - sqterm*radialsq
        yprime2 /= numpy.abs(yprime2).max()
        fitconf = scipy.stats.pearsonr(yprime2, fitctf2)[0]

        if msg is True:
                from matplotlib import pyplot
                pyplot.clf()

                pyplot.plot(radialsq, yprime2, '.', color="gray")
                pyplot.plot(radialsq, yprime2, 'k-',)
                pyplot.plot(radialsq, fitctf1, 'r--',)
                pyplot.plot(radialsq, fitctf2, 'g--',)
                pyplot.plot(radialsq, adjctf1, 'b--',)

                conf1 = scipy.stats.pearsonr(yprime2, fitctf1)[0]
                conf2 = scipy.stats.pearsonr(yprime2, adjctf1)[0]
                conf3 = scipy.stats.pearsonr(yprime2, fitctf2)[0]

                print "conf %.4f, %.4f, %.4f; cc = %.4f"%(conf1, conf2, conf3, crosscorr)

                #pyplot.ylim(ymin=-1.05, ymax=1.05)
                pyplot.title("Amplitude Contrast Fit (%.2f, %.2f, %.2f) CC=%.3f"%(conf1, conf2, conf3, crosscorr))
                pyplot.subplots_adjust(wspace=0.05, hspace=0.05,
                        bottom=0.05, left=0.05, top=0.95, right=0.95, )
                pyplot.show()

        if crosscorr < -0.6:
                print "likely 180 degree out of phase"
                apDisplay.printWarning("Bad angle translation: %.8f"%(amp_con))
                return None

        if fitconf < 0.1 and amp_con > 0.4:
                apDisplay.printWarning("Bad fit confidence %.3f, ac=%.8f"%(fitconf, amp_con))
                return None

        if crosscorr < 0.5:
                apDisplay.printWarning("Bad angle translation: %.8f"%(amp_con))
                return None

        if amp_con < 0.0:
                apDisplay.printWarning("amp contrast is negative (reduce defocus): %.4f"%(amp_con))
                #return None

        if amp_con > 0.6:
                apDisplay.printWarning("amp contrast is too large (increase defocus): %.8f"%(amp_con))
                #return None

        return amp_con