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}
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)
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)
def calculate_q_phi(self, pos): [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices( pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi) u1a = (DELTA * GAMMA - ALPHA.I) * y u1p = PHI.I * CHI.I * OMEGA.I * u1a return u1p
def _hklToAnglesZaxisModes(self, h, k, l, wavelength): """ Return VliegPosition and virtual angles in radians from h, k & l and wavelength in Angstroms for z-axis modes. The virtual angles are those fixed or generated while calculating the position: Bin, Bout, and 2theta. """ # Section 6: # Results in radians during calculations, returned in degreess pos = VliegPosition(None, None, None, None, None, None) # Normalise hkl wavevector = 2 * pi / wavelength hkl = matrix([[h], [k], [l]]) hklNorm = hkl * (1.0 / wavevector) # Compute hkl in phi axis coordinate frame hklPhi = self._getUBMatrix() * hkl hklPhiNorm = self._getUBMatrix() * hklNorm # Determine Chi and Phi (Equation 29): pos.phi = -self._getTau() * TORAD pos.chi = -self._getSigma() * TORAD # Equation 30: [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(None, None, None, None, pos.chi, pos.phi) del ALPHA, DELTA, GAMMA, OMEGA Hw = CHI * PHI * hklPhi # Determine Bin and Bout: (Bin, Bout) = self._determineBinAndBoutInZaxisModes(Hw[2, 0] / wavevector) # Determine Alpha and Gamma (Equation 32): pos.alpha = Bin pos.gamma = Bout # Determine Delta: (pos.delta, twotheta) = self._determineDelta(hklPhiNorm, pos.alpha, pos.gamma) # Determine Omega: delta = pos.delta gamma = pos.gamma d1 = (Hw[1, 0] * sin(delta) * cos(gamma) - Hw[0, 0] * (cos(delta) * cos(gamma) - cos(pos.alpha))) d2 = (Hw[0, 0] * sin(delta) * cos(gamma) + Hw[1, 0] * (cos(delta) * cos(gamma) - cos(pos.alpha))) if fabs(d2) < 1e-30: pos.omega = sign(d1) * sign(d2) * pi / 2.0 else: pos.omega = atan2(d1, d2) # Gather up the virtual angles calculated along the way return pos, {'2theta': twotheta, 'Bin': Bin, 'Bout': Bout}
def _hklToAnglesZaxisModes(self, h, k, l, wavelength): """ Return VliegPosition and virtual angles in radians from h, k & l and wavelength in Angstroms for z-axis modes. The virtual angles are those fixed or generated while calculating the position: Bin, Bout, and 2theta. """ # Section 6: # Results in radians during calculations, returned in degreess pos = VliegPosition(None, None, None, None, None, None) # Normalise hkl wavevector = 2 * pi / wavelength hkl = matrix([[h], [k], [l]]) hklNorm = hkl * (1.0 / wavevector) # Compute hkl in phi axis coordinate frame hklPhi = self._getUBMatrix() * hkl hklPhiNorm = self._getUBMatrix() * hklNorm # Determine Chi and Phi (Equation 29): pos.phi = -self._getTau() * TORAD pos.chi = -self._getSigma() * TORAD # Equation 30: [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices( None, None, None, None, pos.chi, pos.phi) del ALPHA, DELTA, GAMMA, OMEGA Hw = CHI * PHI * hklPhi # Determine Bin and Bout: (Bin, Bout) = self._determineBinAndBoutInZaxisModes( Hw[2, 0] / wavevector) # Determine Alpha and Gamma (Equation 32): pos.alpha = Bin pos.gamma = Bout # Determine Delta: (pos.delta, twotheta) = self._determineDelta(hklPhiNorm, pos.alpha, pos.gamma) # Determine Omega: delta = pos.delta gamma = pos.gamma d1 = (Hw[1, 0] * sin(delta) * cos(gamma) - Hw[0, 0] * (cos(delta) * cos(gamma) - cos(pos.alpha))) d2 = (Hw[0, 0] * sin(delta) * cos(gamma) + Hw[1, 0] * (cos(delta) * cos(gamma) - cos(pos.alpha))) if fabs(d2) < 1e-30: pos.omega = sign(d1) * sign(d2) * pi / 2.0 else: pos.omega = atan2(d1, d2) # Gather up the virtual angles calculated along the way return pos, {'2theta': twotheta, 'Bin': Bin, 'Bout': Bout}
def calculate_q_phi(self, pos): [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi) u1a = (DELTA * GAMMA - ALPHA.I) * y u1p = PHI.I * CHI.I * OMEGA.I * u1a return u1p
def try__findOmegaAndChiToRotateHchiIntoQalpha(self, omega, chi): h_chi = matrix([[1], [1], [1]]) h_chi = h_chi * (1 / norm(h_chi)) [_, _, _, OMEGA, CHI, _] = createVliegMatrices( None, None, None, omega * TORAD, chi * TORAD, None) q_alpha = OMEGA * CHI * h_chi try: omega_calc, chi_calc = _findOmegaAndChiToRotateHchiIntoQalpha( h_chi, q_alpha) except ValueError, e: raise ValueError(str(e) + "\n, resulting from test where omega:%f" " chi%f" % (self.omega, self.chi))
def try__findOmegaAndChiToRotateHchiIntoQalpha(self, omega, chi): h_chi = matrix([[1], [1], [1]]) h_chi = h_chi * (1 / norm(h_chi)) [_, _, _, OMEGA, CHI, _] = createVliegMatrices(None, None, None, omega * TORAD, chi * TORAD, None) q_alpha = OMEGA * CHI * h_chi try: omega_calc, chi_calc = _findOmegaAndChiToRotateHchiIntoQalpha( h_chi, q_alpha) except ValueError, e: raise ValueError( str(e) + "\n, resulting from test where omega:%f" " chi%f" % (self.omega, self.chi))
def _anglesToPsi(self, pos, wavelength): """ pos assumed in radians. -180<= psi <= 180 """ # Using Vlieg section 7.2 # Needed througout: [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi) # Solve equation 49 for psi, the rotation of the a reference solution # about Qalpha or H_phi## # Find Ro, the reference solution to equation 46: R*H_phi=Q_alpha # 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)) # Finh H_phi h, k, l = self._anglesToHkl(pos, wavelength) H_phi = self._getUBMatrix() * matrix([[h], [k], [l]]) normh = norm(H_phi) check(normh >= 1e-10, "reciprical lattice vector too close to zero") H_phi = H_phi * (1 / normh) # Find a solution Ro to Ro*H_phi=Q_alpha # This the reference solution with zero azimuth (psi) Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha) # equation 48: R = OMEGA * CHI * PHI ## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]]) D = self._findMatrixToTransformAIntoB(Q_alpha, matrix([[1], [0], [0]])) # solve equation 49 for psi # D*R = PSI*D*Ro # D*R*(D*Ro)^-1 = PSI PSI = D * R * ((D * Ro).I) # Find psi within PSI as defined in equation 51 PSI_23 = PSI[1, 2] PSI_33 = PSI[2, 2] psi = atan2(PSI_23, PSI_33) #print "PSI: ", PSI.tolist() return psi
def _anglesToPsi(self, pos, wavelength): """ pos assumed in radians. -180<= psi <= 180 """ # Using Vlieg section 7.2 # Needed througout: [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices( pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi) # Solve equation 49 for psi, the rotation of the a reference solution # about Qalpha or H_phi## # Find Ro, the reference solution to equation 46: R*H_phi=Q_alpha # 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)) # Finh H_phi h, k, l = self._anglesToHkl(pos, wavelength) H_phi = self._getUBMatrix() * matrix([[h], [k], [l]]) normh = norm(H_phi) check(normh >= 1e-10, "reciprical lattice vector too close to zero") H_phi = H_phi * (1 / normh) # Find a solution Ro to Ro*H_phi=Q_alpha # This the reference solution with zero azimuth (psi) Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha) # equation 48: R = OMEGA * CHI * PHI ## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]]) D = self._findMatrixToTransformAIntoB(Q_alpha, matrix([[1], [0], [0]])) # solve equation 49 for psi # D*R = PSI*D*Ro # D*R*(D*Ro)^-1 = PSI PSI = D * R * ((D * Ro).I) # Find psi within PSI as defined in equation 51 PSI_23 = PSI[1, 2] PSI_33 = PSI[2, 2] psi = atan2(PSI_23, PSI_33) #print "PSI: ", PSI.tolist() return psi
def vliegAnglesToHkl(pos, wavelength, UBMatrix): """ Returns hkl indices from pos object in radians. """ wavevector = 2 * pi / wavelength # Create transformation matrices [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices( pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi) # Create the plane normal vector in the alpha axis coordinate frame qa = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [wavevector], [0]]) # Transform the plane normal vector from the alpha frame to reciprical # lattice frame. hkl = UBMatrix.I * PHI.I * CHI.I * OMEGA.I * qa return hkl[0, 0], hkl[1, 0], hkl[2, 0]
def vliegAnglesToHkl(pos, wavelength, UBMatrix): """ Returns hkl indices from pos object in radians. """ wavevector = 2 * pi / wavelength # Create transformation matrices [ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi) # Create the plane normal vector in the alpha axis coordinate frame qa = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [wavevector], [0]]) # Transform the plane normal vector from the alpha frame to reciprical # lattice frame. hkl = UBMatrix.I * PHI.I * CHI.I * OMEGA.I * qa return hkl[0, 0], hkl[1, 0], hkl[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}
def armAnglesToLabVector(alpha, delta, gamma): [ALPHA, DELTA, GAMMA, _, _, _] = createVliegMatrices( alpha, delta, gamma, None, None, None) return ALPHA * DELTA * GAMMA * y_vector
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)
def baseAnglesToLabVector(delta, gamma): [_, DELTA, GAMMA, _, _, _] = createVliegMatrices( None, delta, gamma, None, None, None) return GAMMA * DELTA * y_vector
def armAnglesToLabVector(alpha, delta, gamma): [ALPHA, DELTA, GAMMA, _, _, _] = createVliegMatrices(alpha, delta, gamma, None, None, None) return ALPHA * DELTA * GAMMA * y_vector
def baseAnglesToLabVector(delta, gamma): [_, DELTA, GAMMA, _, _, _] = createVliegMatrices(None, delta, gamma, None, None, None) return GAMMA * DELTA * y_vector
class TestVliegCoreMathBits(object): def setup_method(self): self.many = [ -91, -90, -89, -46, -45, -44, -1, 0, 1, 44, 45, 46, 89, 90, 91 ] self.many = (self.many + map(lambda x: x + 180, self.many) + map(lambda x: x - 180, self.many)) def test_check(self): check(True, 'Should not throw') with pytest.raises(Exception): check(False, 'string') with pytest.raises(DiffcalcException): check(False, DiffcalcException('dce')) def acallable(toPrint=None): if toPrint is None: print "Not throwing exception" else: print toPrint check(False, acallable) check(False, acallable, 'this should be printed') # TODO: Removed 2017-03-06, deprecated started code failing -- RobW. def SKIP__findOmegaAndChiToRotateHchiIntoQalpha_WithIntegerValues(self): for omega in self.many: for chi in self.many: print str(omega), ",", str(chi) self.try__findOmegaAndChiToRotateHchiIntoQalpha(omega, chi) def SKIP_findOmegaAndChiToRotateHchiIntoQalpha_WithRandomValues(self): for _ in range(10): for omega in self.many: for chi in self.many: omega = omega + random.uniform(-.001, .001) chi = chi + random.uniform(-.001, .001) self.try__findOmegaAndChiToRotateHchiIntoQalpha(omega, chi) #print str(omega), ",", str(chi) def test__findOmegaAndChiToRotateHchiIntoQalpha_WithTrickyOnes(self): tricky_ones = [(-45., -180.), (45., -180.), (135., -180.), (2000, 0.), (225., 0.), (225., -180.), (-225., 0.), (-225., 0.), (-225., -180.), (-135., -180.), (89.998894, -44.999218)] for omega, chi in tricky_ones: self.try__findOmegaAndChiToRotateHchiIntoQalpha(omega, chi) def try__findOmegaAndChiToRotateHchiIntoQalpha(self, omega, chi): h_chi = matrix([[1], [1], [1]]) h_chi = h_chi * (1 / norm(h_chi)) [_, _, _, OMEGA, CHI, _] = createVliegMatrices(None, None, None, omega * TORAD, chi * TORAD, None) q_alpha = OMEGA * CHI * h_chi try: omega_calc, chi_calc = _findOmegaAndChiToRotateHchiIntoQalpha( h_chi, q_alpha) except ValueError, e: raise ValueError( str(e) + "\n, resulting from test where omega:%f" " chi%f" % (self.omega, self.chi)) [_, _, _, OMEGA, CHI, _] = createVliegMatrices(None, None, None, omega_calc, chi_calc, None) self.assertArraysNearlyEqual(OMEGA * CHI * h_chi, q_alpha, .000001, "omega: %f chi:%f" % (omega, chi))
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)