Beispiel #1
0
 def cal_ki2(self, Qlab, ny, phi):
     """Calculate the incoming wavevector for given Qlab vector, energy
     transfer and sample scattering angle.
     """
     try:
         ki = 0
         phi *= D2R
         Qabs = norm(Qlab)
         a1 = (Qabs / sin(phi))**2
         a2 = K * ny
         a3 = a2 / sin(phi)
         a3 = a1**2 - a3**2
         if a3 > 0:
             ki = a1 + a2 + cos(phi) * sqrt(a3)
             ki /= 2
         if ki > 0.000001:
             ki = sqrt(ki)
             return ki
         else:
             raise ComputationError('energy transfer of %s THz not possible '
                                    'with phi = %s' % (ny, phi))
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError('%s when calculating k_i' % err) from None
Beispiel #2
0
    def calc_orient(self, h1, h2, r1, r2, mode='3x3'):
        """This is Eckolds SR ORIENT.

        Given h1,r1 h2,r2 four vectors in laboratory coordinates,
        orient calculates the matrix
        transforming h1 in r1 and h2 in r2 simultanously.
        """
        # Normalize all vectors
        h1n = h1 / norm(h1)
        h2n = h2 / norm(h2)
        r1n = r1 / norm(r1)
        r2n = r2 / norm(r2)
        y1 = r1n - h1n
        y2 = r2n - h2n
        # calculate the axis of rotation
        if norm(y1) < 0.001 and norm(y2) < 0.001:
            return identity(3)
        if norm(y1) < 0.001:
            r0 = r1n
        elif norm(y2) < 0.001:
            r0 = r2n
        else:
            r0 = cross(y1, y2)
            if norm(r0) < 0:
                raise ComputationError('error in orient: no solution for Omat')
            r0 = r0 / norm(r0)
        rr1 = dot(r0, r1n)
        rr2 = dot(r0, r2n)
        rh1 = dot(r0, h1n)
        rh2 = dot(r0, h2n)
        r1n = r1n - rr1*r0
        r2n = r2n - rr2*r0
        h1n = h1n - rh1*r0
        h2n = h2n - rh2*r0
        x1 = cross(r1n, h1n)
        x2 = cross(r2n, h2n)
        cos1 = dot(h1n, r1n)
        cos2 = dot(h2n, r2n)
        xx1 = dot(x1, r0)
        xx2 = dot(x2, r0)
        cos1 = cos1 / norm(r1n) / norm(h1n)
        cos2 = cos2 / norm(r2n) / norm(h2n)
        a1 = sqrt(1 - cos1**2)
        a2 = sqrt(1 - cos2**2)
        if xx1 > 0:
            a1 *= -1
        if xx2 > 0:
            a2 *= -1
        alfa1 = arctan2(a1, cos1)/D2R
        # print alfa1
        alfa2 = arctan2(a2, cos2)/D2R
        # print alfa2
        if abs(alfa1 - alfa2) > 0.7:
            raise ComputationError('error in orient: no solution for Omat')
        alfa = (alfa1 + alfa2)/2
        if mode == '3x3':
            return self.calc_rotmat(r0, alfa)
        return [r0[0], r0[1], r0[2], alfa]  # Eckold's notation
Beispiel #3
0
 def cal_phi(self, q, ki, kf, sense):
     """Return the sample scattering angle."""
     try:
         qabs = norm(q)
         temp = (ki**2 + kf**2 - qabs**2) / (2.0 * ki * kf)
         if -1 <= temp <= 1:
             phi = arctan2(sqrt(1 - temp**2), temp) * sense * R2D
             return phi
         else:
             raise ComputationError('scattering triangle not closed when '
                                    'calculating phi angle')
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError('%s when calculating phi angle' % err)
Beispiel #4
0
 def angle2Qlab(self, angles, coupled=False):
     """Calculate Qlab from instrument [ki, kf, phi, psi]."""
     result = dot(self.angle2Qcart(angles, coupled), self._matrix_cardan)
     if abs(result[2]) > 0.001:
         raise ComputationError(
             'out of plane vector; check your scattering plane')
     return result
Beispiel #5
0
    def cal_vec_angle(self, h1, k1, l1, h2, k2, l2):
        try:
            hkl1 = array([h1, k1, l1], float)
            hkl2 = array([h2, k2, l2], float)
            g = self.metric_tensor_rec()

            skalpro = 0.0
            for i in range(3):
                for j in range(3):
                    skalpro += hkl1[i] * hkl2[j] * g[i, j]

            hkl1_len = hkl2_len = 0
            for i in range(3):
                for j in range(3):
                    hkl1_len += hkl1[i] * hkl1[j] * g[i, j]
                    hkl2_len += hkl2[i] * hkl2[j] * g[i, j]
            hkl1_len = sqrt(hkl1_len)
            hkl2_len = sqrt(hkl2_len)

            a = skalpro / (hkl1_len * hkl2_len)
            try:
                an = arccos(a) * R2D
            except Exception:
                if a < -1:
                    an = 180
                elif a > 1:
                    an = 0
            return an
        except ComputationError:
            raise
        except Exception as err:
            raise ComputationError(
                '%s when calculating angle between vectors' % err) from None
Beispiel #6
0
    def cal_Y(self, r1, r2, hkl):
        """Calculate angle between 1st orientation reflection and Q vector."""
        # this function doesn't use r1 or r2...
        try:
            crit = 0.000001
            hkl = self.hkl2Qlab(hkl[0], hkl[1], hkl[2])
            qs = hkl[0]**2 + hkl[1]**2
            qabs = sqrt(qs)

            Y = hkl[1] / qabs
            a1 = arcsin(Y)

            if -crit < hkl[0] < crit:
                Y = pi / 2
                if hkl[1] < crit:
                    Y = -Y
            elif hkl[0] < -crit:
                Y = -a1
                if hkl[1] > crit:
                    Y += pi
                else:
                    Y -= pi
            elif hkl[0] > crit:
                Y = a1

            Y *= R2D
            return Y
        except ComputationError:
            raise
        except Exception as err:
            raise ComputationError(
                '%s when calculating angle (r1, Q)' % err) from None
Beispiel #7
0
    def matrix_crystal2lab(self):
        try:
            B = zeros((3, 3))
            U = zeros((3, 3))

            B[0, 0] = self._lattice_rec[0] * 2 * pi
            B[0, 1] = self._lattice_rec[1] * cos(self._angles_rec[2]) * 2 * pi
            B[0, 2] = self._lattice_rec[2] * cos(self._angles_rec[1]) * 2 * pi
            B[1, 0] = 0
            B[1, 1] = self._lattice_rec[1] * sin(self._angles_rec[2]) * 2 * pi
            B[1, 2] = -self._lattice_rec[2] * sin(self._angles_rec[1]) * \
                     cos(self._angles[0] * D2R) * 2 * pi
            B[2, 0] = 0
            B[2, 1] = 0
            B[2, 2] = 2 * pi / self._lattice[2]

            for i in range(3):
                for j in range(3):
                    if -0.000001 < B[i, j] < 0.000001:
                        B[i, j] = 0.0

            vec1 = dot(B, self._orient1)
            vec2 = dot(B, self._orient2)
            vec3 = cross(vec1, vec2)
            vec2 = cross(vec3, vec1)

            # XXX use self.coordinatesystem instead of hardcoded 1?
            U = self.cal_Umatrix(vec1, vec2, vec3, 1)
            return dot(U, B)
        except ComputationError:
            raise
        except Exception as err:
            raise ComputationError(
                '%s when calculating UB matrix' % err) from None
Beispiel #8
0
 def cal_ki3(self, Qlab, ny, alpha):
     """Calculate the incoming wavevector for given Qlab vector, energy
     transfer and angle alpha(ki, Q).
     """
     try:
         alpha *= D2R
         Qabs = norm(Qlab)
         ki = (Qabs**2 + K * ny) / (2.0 * Qabs * cos(alpha))
         if ki > 0.000001:
             return ki
         else:
             raise ComputationError('energy transfer of %s THz not possible;'
                                    ' scattering triangle not closed' % ny)
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError('%s when calculating k_i' % err) from None
Beispiel #9
0
 def cal_alpha1(self, Qlab, ny, ki, sense):
     """Calculate the angle alpha (ki, Q) for given Qlab vector, energy
     transfer, incoming wavevector and scattering sense (sample).
     """
     try:
         Qabs = norm(Qlab)
         temp = (Qabs**2 + K * ny) / (2 * Qabs * ki)
         if -1 <= temp < 1:
             alpha = arctan2(sqrt(1 - temp**2), temp) * sense * R2D
             return alpha
         else:
             raise ComputationError('energy transfer of %s THz not possible;'
                                    ' scattering triangle not closed' % ny)
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError('%s when calculating alpha' % err) from None
Beispiel #10
0
 def cal_dvalue_rec(self, Qhkl):
     try:
         return 1 / self.cal_dvalue_real(Qhkl)
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError('%s when calculating d value in '
                                'reciprocal space' % err) from None
Beispiel #11
0
 def cal_volume_rec(self):
     try:
         return 1 / self.cal_volume_real()
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError('%s when calculating reciprocal space cell '
                                'volume' % err) from None
Beispiel #12
0
 def hkl2Qlab(self, h, k, l):
     """Transform a vector given in real lattice with (h,k,l) Miller indices
     in Qlab with coordinates in system:
     x in beam direction, z direction upwards, y making a right handed system.
     """
     hklcart = self.hkl2Qcart(h, k, l)
     result = dot(hklcart, self._matrix_cardan)
     if abs(result[2]) > 0.001:
         raise ComputationError('out of plane vector; check your scattering plane')
     return result
Beispiel #13
0
 def cal_ki1(self, ny, kf):
     """Calculate the incoming wavevector for given energy transfer and
     outgoing wavevector.
     """
     ki = kf**2 + K * ny
     if ki > 0.000001:
         ki = sqrt(ki)
         return ki
     else:
         raise ComputationError('energy transfer of %s THz not possible '
                                'with k_f = %s' % (ny, kf))
Beispiel #14
0
 def cal_kf(self, ny, ki):
     """Calculate the outgoing wavevector for given energy transfer and
     incoming wavevector.
     """
     kf = ki**2 - K * ny
     if kf > 0.000001:
         kf = sqrt(kf)
         return kf
     else:
         raise ComputationError('energy transfer of %s THz not possible '
                                'with k_i = %s' % (ny, ki))
Beispiel #15
0
 def cal_theta(self, Ei_f, Qhkl, sense):
     """Calculate theta for given incoming and outgoing wavevector, hkl and
     scattering sense.
     """
     d = self.cal_dvalue_rec(Qhkl)
     temp = pi / d / Ei_f
     if temp < 1:
         theta = arcsin(temp) * sense * R2D
         return theta
     else:
         raise ComputationError("arcsin > 1 when calculating theta")
Beispiel #16
0
 def cal_volume_real(self):
     try:
         co = cos(self._angles * D2R)
         mul = self._lattice[0] * self._lattice[1] * self._lattice[2]
         V = mul * sqrt(1 - dot(co, co) + 2 * co[0] * co[1] * co[2])
         return V
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError(
             '%s when calculating real space cell volume' % err) from None
Beispiel #17
0
 def Qlab2hkl(self, Qlab):
     """Calculate the retransformation of a vector given in Qlab to
     crystal lattice with (h,k,l) Miller indices.
     """
     try:
         matcardan_inv = inv(self._matrix_cardan)
         mat_inv = inv(self._matrix)
         result = dot(Qlab, matcardan_inv)
         return dot(mat_inv, result)
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError('%s when transforming Qlab -> hkl' % err)
Beispiel #18
0
def from_k(value, unit):
    try:
        if unit == 'A-1':
            return value
        elif unit == 'A':
            return 2.0 * pi / value
        elif unit == 'meV':
            return ANG2MEV * value**2 / (2 * pi)**2
        elif unit == 'THz':
            return ANG2MEV / THZ2MEV * value**2 / (2 * pi)**2
        else:
            raise ProgrammingError('unknown energy unit %r' % unit)
    except (ArithmeticError, ValueError) as err:
        raise ComputationError('cannot convert %s A-1 to %s: %s' %
                               (value, unit, err)) from None
Beispiel #19
0
def to_k(value, unit):
    try:
        if unit == 'A-1':
            return value
        elif unit == 'A':
            return 2.0 * pi / value
        elif unit == 'meV':
            return 2.0 * pi * sqrt(value / ANG2MEV)
        elif unit == 'THz':
            return 2.0 * pi * sqrt(value * THZ2MEV / ANG2MEV)
        else:
            raise ProgrammingError('unknown energy unit %r' % unit)
    except (ArithmeticError, ValueError) as err:
        raise ComputationError('cannot convert %s A-1 to %s: %s' %
                               (value, unit, err))
Beispiel #20
0
 def cal_dvalue_real(self, Qhkl):
     try:
         hkl = array(Qhkl, float)
         mul = self._lattice_rec * hkl  # elementwise multiplication
         co = cos(self._angles_rec)
         sqresult = dot(mul, mul) + \
                    2 * mul[0] * mul[1] * co[2] + \
                    2 * mul[0] * mul[2] * co[1] + \
                    2 * mul[1] * mul[2] * co[0]
         return sqrt(sqresult)
     except ComputationError:
         raise
     except Exception as err:
         raise ComputationError(
             '%s when calculating d value in real space' % err) from None
Beispiel #21
0
def angles_to_currents(coeff, chi1, chi2, lam_in, lam_out, gamma):
    """Return currents (i1, i2) for the precession angles (chi1, chi2)
    and the given in/out wavelengths and scattering angle.
    """
    if coeff[4] != 0 or coeff[5] != 0:
        # for Cryopad-II
        gamma = 2 * radians(gamma)
        coeff2 = coeff[2] + coeff[4] * gamma**2 + coeff[5] * gamma**4
    else:
        coeff2 = 0
    det = (lam_in * coeff[0] * lam_out * coeff[3] -
           lam_out * coeff2 * lam_in * coeff[1])
    if det == 0:
        raise ComputationError('lambda matrix determinant is null')
    i1 = (lam_out * coeff[3] * chi1 - lam_in * coeff[1] * chi2) / det
    i2 = (lam_in * coeff[0] * chi2 - lam_out * coeff2 * chi1) / det
    return i1, i2
Beispiel #22
0
    def lattice_rec(self):
        try:
            astar = zeros(3)
            alphastar = zeros(3)
            V = self.cal_volume_real()

            co = cos(self._angles * D2R)
            si = sin(self._angles * D2R)

            astar[0] = self._lattice[1] * self._lattice[2] * si[0] / V
            astar[1] = self._lattice[2] * self._lattice[0] * si[1] / V
            astar[2] = self._lattice[0] * self._lattice[1] * si[2] / V
            alphastar[0] = arccos((co[1] * co[2] - co[0]) / (si[1] * si[2]))
            alphastar[1] = arccos((co[0] * co[2] - co[1]) / (si[0] * si[2]))
            alphastar[2] = arccos((co[0] * co[1] - co[2]) / (si[0] * si[1]))
            return [astar, alphastar]
        except Exception as err:
            raise ComputationError(
                '%s when calculating reciprocal lattice' % err) from None
Beispiel #23
0
 def _find_window(self, gamma, magnet):
     # find a free window for incoming and outgoing beam, which is closest
     # to the current position of the magnet
     result = []
     for pos in range(0, 360, self.windowstep):
         for (a1, a2) in self.blocked:
             # check for blocked incoming beam
             if in_range(pos, -a2, -a1):
                 break
             # check for blocked outgoing beam
             if in_range(pos, -a2 + 180 + gamma, -a1 + 180 + gamma):
                 break
         else:  # no "break"
             result.append(pos)
     self.log.debug('gamma: %.3f, magnet: %.3f', gamma, magnet)
     self.log.debug('new possible positions: %s', result)
     if not result:
         raise ComputationError(self, 'no position found for magnet with '
                                'incoming and outgoing beam free')
     return min(result, key=lambda pos: abs(pos - 0.1))
Beispiel #24
0
    def angle2Qcart(self, angles, coupled=False):
        """Calculate Q cartesian from instrument [ki, kf, phi, psi]."""
        try:
            ki, kf, phi, psi = angles
            psi *= D2R
            psi += self._psi0 * D2R
            phi *= D2R
            if coupled:
                psi += phi

            Qcart = zeros(3)
            Qcart[0] = ki * cos(psi) - kf * cos(phi - psi)
            Qcart[1] = ki * sin(psi) + kf * sin(phi - psi)

            return Qcart
        except ComputationError:
            raise
        except Exception as err:
            raise ComputationError(
                '%s when transforming angles -> Q cartesian' % err) from None
Beispiel #25
0
    def cal_Umatrix(self, vec1, vec2, vec3, direction):
        try:
            U = zeros((3, 3))
            U[2] = vec3 / norm(vec3)

            if direction == 1:
                U[0] = vec1 / norm(vec1)
                U[1] = vec2 / norm(vec2)
            elif direction == 2:
                U[0] = vec2 / norm(vec2)
                U[1] = vec1 / norm(vec1)
            elif direction == -1:
                U[0] = -vec1 / norm(vec1)
                U[1] = vec2 / norm(vec2)
            elif direction == -2:
                U[0] = -vec2 / norm(vec2)
                U[1] = vec1 / norm(vec1)
            return U
        except ComputationError:
            raise
        except Exception as err:
            raise ComputationError('%s when calculating U matrix' % err)
Beispiel #26
0
    def euler_angles(self, target_q, another, ki, kf, sense,
                     chilimits=(-180, 180), omlimits=(-180, 180)):
        """Calculates the eulerian angles of *target_q* with the condition
        that the scattering plane is spanned by q and the *another* vector.

        Local variables used by calec from Eckold start with ec_...

        The result is the vector of the euler angles (psi, chi, om, phi) in
        Eckolds notation.
        """
        omat = self._omat
        Bmat = self._Bmat

        # calculate phi from q, ki, kf
        self.log.debug("Bmat = %s", Bmat)
        ##was: ec_q = dot(Bmat, target_q)
        ec_q = self._attached_cell.hkl2Qcart(*target_q)
        self.log.debug("ec_q = %s", ec_q)
        phi = self._attached_cell.cal_phi(ec_q, ki, kf, sense)
        self.log.debug("phi = %s", phi)
        ec_ql = norm(ec_q)
        ec_a = dot(Bmat, another)

        ec_al = norm(ec_a)
        ec_b  = cross(ec_q, ec_a)
        ec_bl = norm(ec_b)
        self.log.debug('vector perp q and sp1 ec_b = %s', ec_b)
        if ec_bl < 0.01:
            # should be:
            # der Q-Vektor ist parallel zu sp1 (der erste Reflex)
            raise ComputationError('selected Q and second vector are parallel; '
                                   'no scattering plane is defined by them')

        # transform q and a to lab coordinates
        ec_r = dot(omat, ec_q/ec_ql)
        self.log.debug('unit Q vector in lab system ec_r = %s', ec_r)
        ec_a = dot(omat, ec_a/ec_al)
        self.log.debug('reflection 1 in lab system ec_a = %s', ec_a)

        # calculate Q1 defined by ki, kf and phi

        ec_q1 = array([ki-kf*cos(phi*D2R), -kf*sin(phi*D2R), 0])
        self.log.debug('scattering vector as function of ki 2: ec_q1 = %s', ec_q1)
        ec_q1 = ec_q1/ec_ql
        self.log.debug('unit scattering vector: ec_q1 = %s', ec_q1)

        # calculate the angles
        ec_b = cross(ec_r, ec_a)
        ec_bl = norm(ec_b)
        ec_bl2 = sqrt(ec_b[0]**2 + ec_b[1]**2)
        self.log.debug('B vector as ec_b = %s', ec_b)

        # now the case selection

        # eckolds case 2 first

        if ec_bl2 < 0.001:  # means b[0]=b[1]=0
            self.log.debug('case 2: b[0] == b[1] == 0')
            ec_chi = 0
            if ec_b[2] >= 0:
                ec_xlchi = 1.0
            else:
                ec_xlchi = -1.0
                ec_chi = 180
            # this is direct what stands in calec
            ec_copom = ec_xlchi*ec_q1[1]*ec_r[1] + ec_q1[0]*ec_r[0]
            ec_sipom = ec_xlchi*ec_q1[1]*ec_r[0] - ec_q1[0]*ec_r[1]
            ec_pom = arctan2(ec_sipom, ec_copom)/D2R

            # acos(ec_copom) should be the same!

            ec_psi = phi/2
            ec_om = ec_pom - ec_psi*ec_xlchi
            if ec_om < -180:
                ec_om += 360
            if ec_om > 180:
                ec_om -= 360
            return array([ec_psi, ec_chi, ec_om, phi])

        #  now the distinction for b [1] >< 0

        if abs(ec_b[0]) < 0.001:   # b[0] = 0
            self.log.debug('case 1: b[0] == 0 and b[1] != 0')
            if ec_b[1] >= 0:
                ec_xlb = 1
            else:
                ec_xlb = -1
            ec_coom = 1
            ec_siom = 0
            ec_cochi = ec_xlb*ec_b[2]/ec_bl
            ec_sichi = ec_xlb*ec_b[1]/ec_bl
            ec_xh = ec_sichi*(ec_r[1]*ec_b[2]/ec_b[1] - ec_r[2])
            ec_xah = ec_r[0]**2 + ec_xh**2
            # in der folgenden Zeile gabe es Fehler:
            # die r[1] muss r[0] heissen
            # ec_copsi1 = ec_q1[0]*ec_r[1]/ec_xah
            ec_copsi1 = ec_q1[0]*ec_r[0]/ec_xah
            ec_copsi2 = ec_xh/ec_xah*ec_q1[1]
            ec_sipsi1 = ec_q1[1]*ec_r[0]/ec_xah
            ec_sipsi2 = -ec_xh/ec_xah*ec_q1[0]
        else:               # b[0] >< 0
            self.log.debug('case 3: b[0] != 0 and b[1] != 0')
            if ec_b[0] >= 0:
                ec_xlb = 1
            else:
                ec_xlb = -1
            ec_a2 = cross(ec_r, ec_b)
            ec_xh = (ec_a2[0]*ec_b[1] - ec_a2[1]*ec_b[0])/ec_bl/ec_bl2
            ec_xa = ec_a2[2]/ec_bl2
            ec_xah = ec_xa*ec_xa+ec_xh*ec_xh
            ec_coom = ec_xlb*ec_b[1]/ec_bl2
            ec_siom = ec_xlb*ec_b[0]/ec_bl2
            ec_cochi = ec_xlb*ec_b[2]/ec_bl
            ec_sichi = ec_bl2/ec_bl
            ec_copsi1 = ec_xlb*ec_xa*ec_q1[0]/ec_xah
            ec_copsi2 = ec_xh*ec_q1[1]/ec_xah
            ec_sipsi1 = ec_xlb*ec_xa*ec_q1[1]/ec_xah
            ec_sipsi2 = -ec_xh*ec_q1[0]/ec_xah

        self.log.debug('cochi  = %s, sichi  = %s', ec_cochi, ec_sichi)
        self.log.debug('copsi1 = %s, copsi2 = %s', ec_copsi1, ec_copsi2)
        self.log.debug('sipsi1 = %s, sipsi2 = %s', ec_sipsi1, ec_sipsi2)

        #
        #   THE SIGNES OF OM AND CHI CAN BE CHOOSEN ARBITRARILY
        #   CALCULATE THE 4 DIFFERENT SETS OF ANGLES CORRESPONDING
        #   TO THE COMBINATIONS OF THESE SIGNES
        #
        #   SELECT THE MOST APPROPRIATE SET OF ANGLES
        #
        #   FIRST CRITERION: SCATTERING VECTOR Q AND REFERENCE VECTOR A1
        #             ARE ORIENTED IN A WAY THAT THE ANGLE BETWEEN
        #             Q AND A1 IS POSITIV
        #
        #   SECOND CRITERION:  CHI MUST BE WITHIN THE ALLOWED RANGE
        #             GIVEN BY SOFT LIMITS
        #   THIRD CRITERION: PSI MUST BE CHOSEN IN SUCH A WAY THAT
        #             NEITHER THE INCIDENT NOR THE SCATTERED
        #             BEAM IS SHADED BY THE LARGE CIRCLE OF THE
        #             EULARIAN CRADLE
        #

        ec_chil, ec_chiu = chilimits
        ec_oml, ec_omu = omlimits
        for ec_xlom in [-1, 1]:   # has been do 8
            for ec_xlchi in [-1, 1]:  # has been do 9
                self.log.debug('xlom, xlchi, xlb, mmm = %s, %s, %s, %s',
                               ec_xlom, ec_xlchi, ec_xlb, ec_xlchi*ec_xlom*ec_xlb)
                if ec_xlchi*ec_xlom*ec_xlb < 0:
                    continue   # corresponds to: go to 9
                ec_d1 = ec_xlom*ec_xlchi*ec_cochi
                ec_d2 = ec_xlchi*ec_sichi
                ec_cc = arctan2(ec_d2, ec_d1)/D2R
                self.log.debug('xlom, xlchi, ec_cc = %s, %s, %s',
                               ec_xlom, ec_xlchi, ec_cc)
                if ec_cc < -180:
                    ec_cc += 360
                if ec_cc > 180:
                    ec_cc -= 360
                if ec_cc < ec_chil or ec_cc > ec_chiu:
                    continue
                ec_d1 = ec_xlom*ec_copsi1 + ec_xlchi*ec_copsi2
                ec_d2 = ec_xlom*ec_sipsi1 + ec_xlchi*ec_sipsi2
                ec_p = arctan2(ec_d2, ec_d1)/D2R
                self.log.debug('ec_p = %s', ec_p)
                if ec_p < -180:
                    ec_p += 360.
                if ec_p > 180:
                    ec_p -= 360.
                self.log.debug('ec_p = %s', ec_p)
    #
    #         treatment of the third criterion
    #
    #
    #   if j=1 the incident beam is considered
    #   if j-2 the scattered beam is considered
    #       attention made ec_aa = 180 or phi directly
    #
    #            for ec_aa in [180,phi]:   #    do 10 jj=1,2
    #                for ec_ii in [-360,0,360]:    # do 11 ii=1,3
    #                    ec_x=ec_p+ec_ii
    #                    if((ec_x>ec_aa+55) and (ec_x<ec_aa+90)):break          # go to 9
    #                    if((ec_x>ec_aa-90) and (ec_x<ec_aa-55)):break                  # go to 9
    #                    if((ec_cc<-160) or (ec_cc>150)):continue               # go to 11
    #                    if(ec_cc>-30):                                         # has been go to 110
    #                         if(ec_cc<20.): continue                            # go to 11
    #                         if((ec_x>ec_aa-135.) and (ec_x<ec_aa-55)):break    # go to 9
    #                         if(ec_cc<30.): continue                            # go to 11
    #                         if((ec_x>ec_aa+35.) and (ec_x<ec_aa+90)):break     # go to 9
    #                         if((ec_x>ec_aa+55) and (ec_x<ec_aa+135.)):break    # go to 9
    #                         if(ec_cc<-150):continue                            # go to 11
    #                         if((ec_x>ec_aa-90) and (ec_x<ec_aa-35)):break      # go to 9
    #   11     continue
    #                    break
    #   10   continue
                ec_d1 = ec_xlom*ec_coom
                ec_d2 = ec_xlom*ec_siom
                ec_om = arctan2(ec_d2, ec_d1)/D2R
                self.log.debug('ec_om = %s', ec_om)
                if ec_om < -180.:
                    ec_om += 360.
                if ec_om > 180.:
                    ec_om -= 360.
                if ec_om < ec_oml or ec_om > ec_omu:
                    continue                 # go to 9
                return array([ec_p, ec_cc, ec_om, phi])

        raise ComputationError('could not find a Eulerian cradle position for '
                               'q = %s' % (target_q,))
Beispiel #27
0
    def cal_angles(self, Qhkl, ny, SM, SC, sense, coupled=False, psi360=True):
        """
        Calculate instrument angles for given HKL and energy transfer, for
        a specific scan mode, scan constant and scattering sense.

        Scanmodes:

            'CKI': constant Ki -> incoming energy
            'CKF': constant Kf -> outgoing energy
            'CPSI': constant PSI -> angle between ki and orientation
                    reflection r1; psi in 0 ... 180; -180 ... 0
            'CPHI': constant PHI -> scattering angle of sample
            'DIFF': powder sample

            unimplemented:
             6: constant Ki, absolut Q
             7: constant Kf, absolut Q
             8: without analyser

        psi0:  angle between orientation reflection r1 and zero of sample rotation axis
        Y:     angle between orientation refection r1, Q
        alpha: angle between ki and Q
        """
        try:
            Qlab = self.hkl2Qlab(Qhkl[0], Qhkl[1], Qhkl[2])
            Y = self.cal_Y(self._orient1, self._orient2, Qhkl)

            if SM in ['CKI', 'DIFF']:
                ki = SC
                kf = self.cal_kf(ny, ki)
                phi = self.cal_phi(Qlab, ki, kf, sense)
                alpha = self.cal_alpha1(Qlab, ny, ki, sense)
                psi = self.cal_psi(Y, alpha)

            elif SM == 'CKF':
                kf = SC
                ki = self.cal_ki1(ny, kf)
                phi = self.cal_phi(Qlab, ki, kf, sense)
                alpha = self.cal_alpha1(Qlab, ny, ki, sense)
                psi = self.cal_psi(Y, alpha)

            elif SM == 'CPSI':
                psi = SC
                alpha = self.cal_alpha2(Y, psi)
                ki = self.cal_ki3(Qlab, ny, alpha)
                if alpha > 0:
                    sphi = 1
                else:
                    sphi = -1
                kf = self.cal_kf(ny, ki)
                phi = self.cal_phi(Qlab, ki, kf, sphi)

            elif SM == 'CPHI':
                phi = SC
                sphi = sign(phi)
                ki = self.cal_ki2(Qlab, ny, phi)
                kf = self.cal_kf(ny, ki)
                alpha = self.cal_alpha1(Qlab, ny, ki, sphi)
                psi = self.cal_psi(Y, alpha)

            psi -= self._psi0
            if coupled:
                psi -= phi
            while psi < -180:
                psi += 360
            while psi > 180:
                psi -= 360
            if psi360 and psi < 0:
                psi += 360

            return [ki, kf, phi, psi, alpha]
        except ComputationError:
            raise
        except Exception as err:
            raise ComputationError(
                '%s when calculating angles for hkl' % err) from None