Пример #1
0
    def _determineBinAndBoutInFourAndFiveCirclesModes(self, hklNorm):
        """(Bin, Bout) = _determineBinAndBoutInFourAndFiveCirclesModes()"""
        BinModes = ('4cBin', '5cgBin', '5caBin')
        BoutModes = ('4cBout', '5cgBout', '5caBout')
        BeqModes = ('4cBeq', '5cgBeq', '5caBeq')
        azimuthModes = ('4cAzimuth')
        fixedBusingAndLeviWmodes = ('4cFixedw')

        # Calculate RHS of equation 20
        # RHS (1/K)(S^-1*U*B*H)_3 where H/K = hklNorm
        UB = self._getUBMatrix()
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD, self._getTau() * TORAD)
        #S = SIGMA * TAU
        S = TAU * SIGMA
        RHS = (S.I * UB * hklNorm)[2, 0]

        if self._getMode().name in BinModes:
            Bin = self._getParameter('betain')
            check(Bin != None, "The parameter betain must be set for mode %s" %
                  self._getMode().name)
            Bin = Bin * TORAD
            sinBout = RHS - sin(Bin)
            check(fabs(sinBout) <= 1, "Could not compute Bout")
            Bout = asin(sinBout)

        elif self._getMode().name in BoutModes:
            Bout = self._getParameter('betaout')
            check(Bout != None, "The parameter Bout must be set for mode %s" %
                  self._getMode().name)
            Bout = Bout * TORAD
            sinBin = RHS - sin(Bout)
            check(fabs(sinBin) <= 1, "Could not compute Bin")
            Bin = asin(sinBin)

        elif self._getMode().name in BeqModes:
            sinBeq = RHS / 2
            check(fabs(sinBeq) <= 1, "Could not compute Bin=Bout")
            Bin = Bout = asin(sinBeq)

        elif self._getMode().name in azimuthModes:
            azimuth = self._getParameter('azimuth')
            check(azimuth != None, "The parameter azimuth must be set for "
                  "mode %s" % self._getMode().name)
            del azimuth
            # TODO: codeit
            raise NotImplementedError()

        elif self._getMode().name in fixedBusingAndLeviWmodes:
            bandlomega = self._getParameter('blw')
            check(bandlomega != None, "The parameter abandlomega must be set "
                  "for mode %s" % self._getMode().name)
            del bandlomega
            # TODO: codeit
            raise NotImplementedError()
        else:
            raise RuntimeError("AngleCalculator does not know how to handle "
                               "mode %s" % self._getMode().name)

        return (Bin, Bout)
Пример #2
0
    def _anglesToVirtualAngles(self, pos, wavelength):
        """
        Return dictionary of all virtual angles in radians from VliegPosition
        object win radians and wavelength in Angstroms. The virtual angles are:
        Bin, Bout, azimuth and 2theta.
        """

        # Create transformation matrices
        [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
            pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD, self._getTau() * TORAD)

        S = TAU * SIGMA
        y_vector = matrix([[0], [1], [0]])

        # Calculate Bin from equation 15:
        surfacenormal_alpha = OMEGA * CHI * PHI * S * matrix([[0], [0], [1]])
        incoming_alpha = ALPHA.I * y_vector
        minusSinBetaIn = dot3(surfacenormal_alpha, incoming_alpha)
        Bin = asin(bound(-minusSinBetaIn))

        # Calculate Bout from equation 16:
        #  surfacenormal_alpha has just ben calculated
        outgoing_alpha = DELTA * GAMMA * y_vector
        sinBetaOut = dot3(surfacenormal_alpha, outgoing_alpha)
        Bout = asin(bound(sinBetaOut))

        # Calculate 2theta from equation 25:

        cosTwoTheta = dot3(ALPHA * DELTA * GAMMA * y_vector, y_vector)
        twotheta = acos(bound(cosTwoTheta))
        psi = self._anglesToPsi(pos, wavelength)

        return {'Bin': Bin, 'Bout': Bout, 'azimuth': psi, '2theta': twotheta}
Пример #3
0
    def _determineAlphaAndGammaForFiveCircleModes(self, Bin, hklPhiNorm):

        ## Solve equation 34 for one possible Y, Yo
        # Calculate surface normal in phi frame
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD, self._getTau() * TORAD)
        S = TAU * SIGMA
        surfaceNormalPhi = S * matrix([[0], [0], [1]])
        # Compute beta in vector
        BetaVector = matrix([[0], [-sin(Bin)], [cos(Bin)]])
        # Find Yo
        Yo = self._findMatrixToTransformAIntoB(surfaceNormalPhi, BetaVector)

        ## Calculate Hv from equation 39
        Z = matrix([[1, 0, 0],
                    [0, cos(Bin), sin(Bin)],
                    [0, -sin(Bin), cos(Bin)]])
        Hv = Z * Yo * hklPhiNorm
        # Fixed gamma:
        if self._getMode().group == 'fivecFixedGamma':
            gamma = self._getParameter(self._getGammaParameterName())
            check(gamma != None,
                  "gamma parameter must be set in fivecFixedGamma modes")
            gamma = gamma * TORAD
            H2 = (hklPhiNorm[0, 0] ** 2 + hklPhiNorm[1, 0] ** 2 +
                  hklPhiNorm[2, 0] ** 2)
            a = -(0.5 * H2 * sin(Bin) - Hv[2, 0])
            b = -(1.0 - 0.5 * H2) * cos(Bin)
            c = cos(Bin) * sin(gamma)
            check((b * b + a * a - c * c) >= 0, 'Could not solve for alpha')
            alpha = 2 * atan2(-(b + sqrt(b * b + a * a - c * c)), -(a + c))

        # Fixed Alpha:
        elif self._getMode().group == 'fivecFixedAlpha':
            alpha = self._getParameter('alpha')
            check(alpha != None,
                  "alpha parameter must be set in fivecFixedAlpha modes")
            alpha = alpha * TORAD
            H2 = (hklPhiNorm[0, 0] ** 2 + hklPhiNorm[1, 0] ** 2 +
                  hklPhiNorm[2, 0] ** 2)
            t0 = ((2 * cos(alpha) * Hv[2, 0] - sin(Bin) * cos(alpha) * H2 +
                  cos(Bin) * sin(alpha) * H2 - 2 * cos(Bin) * sin(alpha)) /
                  (cos(Bin) * 2.0))
            check(abs(t0) <= 1, "Cannot compute gamma: sin(gamma)>1")
            gamma = asin(t0)
        else:
            raise RuntimeError(
                "determineAlphaAndGammaInFiveCirclesModes() is not "
                "appropriate for %s modes" % self._getMode().group)

        return (alpha, gamma)
Пример #4
0
    def _determineAlphaAndGammaForFiveCircleModes(self, Bin, hklPhiNorm):

        ## Solve equation 34 for one possible Y, Yo
        # Calculate surface normal in phi frame
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD,
            self._getTau() * TORAD)
        S = TAU * SIGMA
        surfaceNormalPhi = S * matrix([[0], [0], [1]])
        # Compute beta in vector
        BetaVector = matrix([[0], [-sin(Bin)], [cos(Bin)]])
        # Find Yo
        Yo = self._findMatrixToTransformAIntoB(surfaceNormalPhi, BetaVector)

        ## Calculate Hv from equation 39
        Z = matrix([[1, 0, 0], [0, cos(Bin), sin(Bin)],
                    [0, -sin(Bin), cos(Bin)]])
        Hv = Z * Yo * hklPhiNorm
        # Fixed gamma:
        if self._getMode().group == 'fivecFixedGamma':
            gamma = self._getParameter(self._getGammaParameterName())
            check(gamma != None,
                  "gamma parameter must be set in fivecFixedGamma modes")
            gamma = gamma * TORAD
            H2 = (hklPhiNorm[0, 0]**2 + hklPhiNorm[1, 0]**2 +
                  hklPhiNorm[2, 0]**2)
            a = -(0.5 * H2 * sin(Bin) - Hv[2, 0])
            b = -(1.0 - 0.5 * H2) * cos(Bin)
            c = cos(Bin) * sin(gamma)
            check((b * b + a * a - c * c) >= 0, 'Could not solve for alpha')
            alpha = 2 * atan2(-(b + sqrt(b * b + a * a - c * c)), -(a + c))

        # Fixed Alpha:
        elif self._getMode().group == 'fivecFixedAlpha':
            alpha = self._getParameter('alpha')
            check(alpha != None,
                  "alpha parameter must be set in fivecFixedAlpha modes")
            alpha = alpha * TORAD
            H2 = (hklPhiNorm[0, 0]**2 + hklPhiNorm[1, 0]**2 +
                  hklPhiNorm[2, 0]**2)
            t0 = ((2 * cos(alpha) * Hv[2, 0] - sin(Bin) * cos(alpha) * H2 +
                   cos(Bin) * sin(alpha) * H2 - 2 * cos(Bin) * sin(alpha)) /
                  (cos(Bin) * 2.0))
            check(abs(t0) <= 1, "Cannot compute gamma: sin(gamma)>1")
            gamma = asin(t0)
        else:
            raise RuntimeError(
                "determineAlphaAndGammaInFiveCirclesModes() is not "
                "appropriate for %s modes" % self._getMode().group)

        return (alpha, gamma)
Пример #5
0
    def _anglesToVirtualAngles(self, pos, wavelength):
        """
        Return dictionary of all virtual angles in radians from VliegPosition
        object win radians and wavelength in Angstroms. The virtual angles are:
        Bin, Bout, azimuth and 2theta.
        """

        # Create transformation matrices
        [ALPHA, DELTA, GAMMA, OMEGA, CHI,
         PHI] = createVliegMatrices(pos.alpha, pos.delta, pos.gamma, pos.omega,
                                    pos.chi, pos.phi)
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD,
            self._getTau() * TORAD)

        S = TAU * SIGMA
        y_vector = matrix([[0], [1], [0]])

        # Calculate Bin from equation 15:
        surfacenormal_alpha = OMEGA * CHI * PHI * S * matrix([[0], [0], [1]])
        incoming_alpha = ALPHA.I * y_vector
        minusSinBetaIn = dot3(surfacenormal_alpha, incoming_alpha)
        Bin = asin(bound(-minusSinBetaIn))

        # Calculate Bout from equation 16:
        #  surfacenormal_alpha has just ben calculated
        outgoing_alpha = DELTA * GAMMA * y_vector
        sinBetaOut = dot3(surfacenormal_alpha, outgoing_alpha)
        Bout = asin(bound(sinBetaOut))

        # Calculate 2theta from equation 25:

        cosTwoTheta = dot3(ALPHA * DELTA * GAMMA * y_vector, y_vector)
        twotheta = acos(bound(cosTwoTheta))
        psi = self._anglesToPsi(pos, wavelength)

        return {'Bin': Bin, 'Bout': Bout, 'azimuth': psi, '2theta': twotheta}
Пример #6
0
    def _determineSampleAnglesInFourAndFiveCircleModes(self, hklPhiNorm, alpha,
                                                       delta, gamma, Bin):
        """
        (omega, chi, phi, psi)=determineNonZAxisSampleAngles(hklPhiNorm, alpha,
        delta, gamma, sigma, tau) where hkl has been normalised by the
        wavevector and is in the phi Axis coordinate frame. All angles in
        radians. hklPhiNorm is a 3X1 matrix
        """

        def equation49through59(psi):
            # equation 49 R = (D^-1)*PI*D*Ro
            PSI = createVliegsPsiTransformationMatrix(psi)
            R = D.I * PSI * D * Ro

            #  eq 57: extract omega from R
            if abs(R[0, 2]) < 1e-20:
                omega = -sign(R[1, 2]) * sign(R[0, 2]) * pi / 2
            else:
                omega = -atan2(R[1, 2], R[0, 2])

            # eq 58: extract chi from R
            sinchi = sqrt(pow(R[0, 2], 2) + pow(R[1, 2], 2))
            sinchi = bound(sinchi)
            check(abs(sinchi) <= 1, 'could not compute chi')
            # (there are two roots to this equation, but only the first is also
            # a solution to R33=cos(chi))
            chi = asin(sinchi)

            # eq 59: extract phi from R
            if abs(R[2, 0]) < 1e-20:
                phi = sign(R[2, 1]) * sign(R[2, 1]) * pi / 2
            else:
                phi = atan2(-R[2, 1], -R[2, 0])
            return omega, chi, phi

        def checkSolution(omega, chi, phi):
            _, _, _, OMEGA, CHI, PHI = createVliegMatrices(
                None, None, None, omega, chi, phi)
            R = OMEGA * CHI * PHI
            RtimesH_phi = R * H_phi
            print ("R*H_phi=%s, Q_alpha=%s" %
                   (R * H_phi.tolist(), Q_alpha.tolist()))
            return not differ(RtimesH_phi, Q_alpha, .0001)

        # Using Vlieg section 7.2

        # Needed througout:
        [ALPHA, DELTA, GAMMA, _, _, _] = createVliegMatrices(
            alpha, delta, gamma, None, None, None)

        ## Find Ro, one possible solution to equation 46: R*H_phi=Q_alpha

        # Normalise hklPhiNorm (As it is currently normalised only to the
        # wavevector)
        normh = norm(hklPhiNorm)
        check(normh >= 1e-10, "reciprical lattice vector too close to zero")
        H_phi = hklPhiNorm * (1 / normh)

        # Create Q_alpha from equation 47, (it comes normalised)
        Q_alpha = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [1], [0]])
        Q_alpha = Q_alpha * (1 / norm(Q_alpha))

        if self._getMode().name == '4cPhi':
            ### Use the fixed value of phi as the final constraint ###
            phi = self._getParameter('phi') * TORAD
            PHI = calcPHI(phi)
            H_chi = PHI * H_phi
            omega, chi = _findOmegaAndChiToRotateHchiIntoQalpha(H_chi, Q_alpha)
            return (omega, chi, phi, None)  # psi = None as not calculated
        else:
            ### Use Bin as the final constraint ###

            # Find a solution Ro to Ro*H_phi=Q_alpha
            Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha)

            ## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]])
            D = self._findMatrixToTransformAIntoB(
                Q_alpha, matrix([[1], [0], [0]]))

            ## Find psi and create PSI

            # eq 54: compute u=D*Ro*S*[[0],[0],[1]], the surface normal in
            # psi frame
            [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
                self._getSigma() * TORAD, self._getTau() * TORAD)
            S = TAU * SIGMA
            [u1], [u2], [u3] = (D * Ro * S * matrix([[0], [0], [1]])).tolist()
            # TODO: If u points along 100, then any psi is a solution. Choose 0
            if not differ([u1, u2, u3], [1, 0, 0], 1e-9):
                psi = 0
                omega, chi, phi = equation49through59(psi)
            else:
                # equation 53: V=A*(D^-1)
                V = ALPHA * D.I
                v21 = V[1, 0]
                v22 = V[1, 1]
                v23 = V[1, 2]
                # equation 55
                a = v22 * u2 + v23 * u3
                b = v22 * u3 - v23 * u2
                c = -sin(Bin) - v21 * u1  # TODO: changed sign from paper

                # equation 44
                # Try first root:
                def myatan2(y, x):
                    if abs(x) < 1e-20 and abs(y) < 1e-20:
                        return pi / 2
                    else:
                        return atan2(y, x)
                psi = 2 * myatan2(-(b - sqrt(b * b + a * a - c * c)), -(a + c))
                #psi = -acos(c/sqrt(a*a+b*b))+atan2(b,a)# -2*pi
                omega, chi, phi = equation49through59(psi)

            # if u points along z axis, the psi could have been either 0 or 180
            if (not differ([u1, u2, u3], [0, 0, 1], 1e-9) and
                abs(psi - pi) < 1e-10):
                # Choose 0 to match that read up by  angles-to-virtual-angles
                psi = 0.
            # if u points a long
            return (omega, chi, phi, psi)
Пример #7
0
    def _determineSampleAnglesInFourAndFiveCircleModes(self, hklPhiNorm, alpha,
                                                       delta, gamma, Bin):
        """
        (omega, chi, phi, psi)=determineNonZAxisSampleAngles(hklPhiNorm, alpha,
        delta, gamma, sigma, tau) where hkl has been normalised by the
        wavevector and is in the phi Axis coordinate frame. All angles in
        radians. hklPhiNorm is a 3X1 matrix
        """
        def equation49through59(psi):
            # equation 49 R = (D^-1)*PI*D*Ro
            PSI = createVliegsPsiTransformationMatrix(psi)
            R = D.I * PSI * D * Ro

            #  eq 57: extract omega from R
            if abs(R[0, 2]) < 1e-20:
                omega = -sign(R[1, 2]) * sign(R[0, 2]) * pi / 2
            else:
                omega = -atan2(R[1, 2], R[0, 2])

            # eq 58: extract chi from R
            sinchi = sqrt(pow(R[0, 2], 2) + pow(R[1, 2], 2))
            sinchi = bound(sinchi)
            check(abs(sinchi) <= 1, 'could not compute chi')
            # (there are two roots to this equation, but only the first is also
            # a solution to R33=cos(chi))
            chi = asin(sinchi)

            # eq 59: extract phi from R
            if abs(R[2, 0]) < 1e-20:
                phi = sign(R[2, 1]) * sign(R[2, 1]) * pi / 2
            else:
                phi = atan2(-R[2, 1], -R[2, 0])
            return omega, chi, phi

        def checkSolution(omega, chi, phi):
            _, _, _, OMEGA, CHI, PHI = createVliegMatrices(
                None, None, None, omega, chi, phi)
            R = OMEGA * CHI * PHI
            RtimesH_phi = R * H_phi
            print("R*H_phi=%s, Q_alpha=%s" %
                  (R * H_phi.tolist(), Q_alpha.tolist()))
            return not differ(RtimesH_phi, Q_alpha, .0001)

        # Using Vlieg section 7.2

        # Needed througout:
        [ALPHA, DELTA, GAMMA, _, _,
         _] = createVliegMatrices(alpha, delta, gamma, None, None, None)

        ## Find Ro, one possible solution to equation 46: R*H_phi=Q_alpha

        # Normalise hklPhiNorm (As it is currently normalised only to the
        # wavevector)
        normh = norm(hklPhiNorm)
        check(normh >= 1e-10, "reciprical lattice vector too close to zero")
        H_phi = hklPhiNorm * (1 / normh)

        # Create Q_alpha from equation 47, (it comes normalised)
        Q_alpha = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [1], [0]])
        Q_alpha = Q_alpha * (1 / norm(Q_alpha))

        if self._getMode().name == '4cPhi':
            ### Use the fixed value of phi as the final constraint ###
            phi = self._getParameter('phi') * TORAD
            PHI = calcPHI(phi)
            H_chi = PHI * H_phi
            omega, chi = _findOmegaAndChiToRotateHchiIntoQalpha(H_chi, Q_alpha)
            return (omega, chi, phi, None)  # psi = None as not calculated
        else:
            ### Use Bin as the final constraint ###

            # Find a solution Ro to Ro*H_phi=Q_alpha
            Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha)

            ## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]])
            D = self._findMatrixToTransformAIntoB(Q_alpha,
                                                  matrix([[1], [0], [0]]))

            ## Find psi and create PSI

            # eq 54: compute u=D*Ro*S*[[0],[0],[1]], the surface normal in
            # psi frame
            [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
                self._getSigma() * TORAD,
                self._getTau() * TORAD)
            S = TAU * SIGMA
            [u1], [u2], [u3] = (D * Ro * S * matrix([[0], [0], [1]])).tolist()
            # TODO: If u points along 100, then any psi is a solution. Choose 0
            if not differ([u1, u2, u3], [1, 0, 0], 1e-9):
                psi = 0
                omega, chi, phi = equation49through59(psi)
            else:
                # equation 53: V=A*(D^-1)
                V = ALPHA * D.I
                v21 = V[1, 0]
                v22 = V[1, 1]
                v23 = V[1, 2]
                # equation 55
                a = v22 * u2 + v23 * u3
                b = v22 * u3 - v23 * u2
                c = -sin(Bin) - v21 * u1  # TODO: changed sign from paper

                # equation 44
                # Try first root:
                def myatan2(y, x):
                    if abs(x) < 1e-20 and abs(y) < 1e-20:
                        return pi / 2
                    else:
                        return atan2(y, x)

                psi = 2 * myatan2(-(b - sqrt(b * b + a * a - c * c)), -(a + c))
                #psi = -acos(c/sqrt(a*a+b*b))+atan2(b,a)# -2*pi
                omega, chi, phi = equation49through59(psi)

            # if u points along z axis, the psi could have been either 0 or 180
            if (not differ([u1, u2, u3], [0, 0, 1], 1e-9)
                    and abs(psi - pi) < 1e-10):
                # Choose 0 to match that read up by  angles-to-virtual-angles
                psi = 0.
            # if u points a long
            return (omega, chi, phi, psi)
Пример #8
0
    def _determineBinAndBoutInFourAndFiveCirclesModes(self, hklNorm):
        """(Bin, Bout) = _determineBinAndBoutInFourAndFiveCirclesModes()"""
        BinModes = ('4cBin', '5cgBin', '5caBin')
        BoutModes = ('4cBout', '5cgBout', '5caBout')
        BeqModes = ('4cBeq', '5cgBeq', '5caBeq')
        azimuthModes = ('4cAzimuth')
        fixedBusingAndLeviWmodes = ('4cFixedw')

        # Calculate RHS of equation 20
        # RHS (1/K)(S^-1*U*B*H)_3 where H/K = hklNorm
        UB = self._getUBMatrix()
        [SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
            self._getSigma() * TORAD,
            self._getTau() * TORAD)
        #S = SIGMA * TAU
        S = TAU * SIGMA
        RHS = (S.I * UB * hklNorm)[2, 0]

        if self._getMode().name in BinModes:
            Bin = self._getParameter('betain')
            check(
                Bin != None, "The parameter betain must be set for mode %s" %
                self._getMode().name)
            Bin = Bin * TORAD
            sinBout = RHS - sin(Bin)
            check(fabs(sinBout) <= 1, "Could not compute Bout")
            Bout = asin(sinBout)

        elif self._getMode().name in BoutModes:
            Bout = self._getParameter('betaout')
            check(
                Bout != None, "The parameter Bout must be set for mode %s" %
                self._getMode().name)
            Bout = Bout * TORAD
            sinBin = RHS - sin(Bout)
            check(fabs(sinBin) <= 1, "Could not compute Bin")
            Bin = asin(sinBin)

        elif self._getMode().name in BeqModes:
            sinBeq = RHS / 2
            check(fabs(sinBeq) <= 1, "Could not compute Bin=Bout")
            Bin = Bout = asin(sinBeq)

        elif self._getMode().name in azimuthModes:
            azimuth = self._getParameter('azimuth')
            check(
                azimuth != None, "The parameter azimuth must be set for "
                "mode %s" % self._getMode().name)
            del azimuth
            # TODO: codeit
            raise NotImplementedError()

        elif self._getMode().name in fixedBusingAndLeviWmodes:
            bandlomega = self._getParameter('blw')
            check(
                bandlomega != None, "The parameter abandlomega must be set "
                "for mode %s" % self._getMode().name)
            del bandlomega
            # TODO: codeit
            raise NotImplementedError()
        else:
            raise RuntimeError("AngleCalculator does not know how to handle "
                               "mode %s" % self._getMode().name)

        return (Bin, Bout)