Ejemplo n.º 1
0
def trans_point(p, theta=0., scale=1.):
    """
    simple in-plane rotation of points
    """
    M = num.array([[cosd(theta), -sind(theta)], [sind(theta), cosd(theta)]])
    pp = scale * num.dot(M, p)
    return pp
Ejemplo n.º 2
0
def calc_D(nu=0.0, delta=0.0):
    """
    Calculate the detector rotation matrix.
    Angles are in degrees

    Notes:
    ------
    D is the matrix that rotates a vector defined in the phi frame
    ie a vector defined with all angles zero => vphi.  After rotation
    the lab frame coordinates of the vector => vm are given by:
         vm = D*vphi
    For example 
                            |0|   
         kr_phi = (2pi/lam) |1|
                            |0|
    Since kr is defined by the detector rotation, the lab frame 
    coordinates of the kr vector after detector rotation are
         kr_m = D*kr_phi
    
    """
    D1 = num.array([[cosd(delta), sind(delta), 0.],
                    [-sind(delta), cosd(delta), 0.], [0., 0., 1.]])

    D2 = num.array([[1., 0., 0.], [0., cosd(nu), -sind(nu)],
                    [0., sind(nu), cosd(nu)]])

    D = num.dot(D2, D1)
    return (D)
Ejemplo n.º 3
0
    def _calc_omega(self):
        """
        calc omega, this is the angle between Q and the plane
        which is perpendicular to the axis of the chi circle.

        Notes:
        ------
        For nu=mu=0 this is the same as the four circle def:
        omega = 0.5*TTH - TH, where TTH is the detector motor (=del)
        and TH is the sample circle (=eta).  Therefore, for 
        mu=nu=0 and del=0.5*eta, omega = 0, which means that Q
        is in the plane perpendicular to the chi axis.

        Note check sign of results??? 
        """
        phi = self.angles['phi']
        chi = self.angles['chi']
        eta = self.angles['eta']
        mu = self.angles['mu']
        H = num.array([[cosd(eta), sind(eta), 0.],
                       [-sind(eta), cosd(eta), 0.], [0., 0., 1.]], float)
        M = num.array([[1., 0., 0.], [0., cosd(mu), -sind(mu)],
                       [0., sind(mu), cosd(mu)]], float)
        # check the mult order here!!!!
        # T = num.dot(H.transpose(),M.transpose())
        T = num.dot(M.transpose(), H.transpose())
        Qpp = num.dot(T, self.Q)
        #omega = -1.*cartesian_angle([Qpp[0], 0, Qpp[2]],Qpp)
        omega = cartesian_angle([Qpp[0], 0, Qpp[2]], Qpp)
        self.pangles['omega'] = omega
Ejemplo n.º 4
0
def calc_D(nu=0.0,delta=0.0):
    """
    Calculate the detector rotation matrix.
    Angles are in degrees

    Notes:
    ------
    D is the matrix that rotates a vector defined in the phi frame
    ie a vector defined with all angles zero => vphi.  After rotation
    the lab frame coordinates of the vector => vm are given by:
         vm = D*vphi
    For example 
                            |0|   
         kr_phi = (2pi/lam) |1|
                            |0|
    Since kr is defined by the detector rotation, the lab frame 
    coordinates of the kr vector after detector rotation are
         kr_m = D*kr_phi
    
    """
    D1 = num.array([[cosd(delta),  sind(delta),  0.], 
                    [-sind(delta), cosd(delta),  0.],
                    [     0.     ,     0.     ,  1.]])
          
    D2 = num.array([[    1.,     0.   ,      0.  ],
                    [    0.,  cosd(nu), -sind(nu)], 
                    [    0.,  sind(nu),  cosd(nu)]])
          
    D = num.dot(D2,D1)
    return (D)
Ejemplo n.º 5
0
    def _calc_omega(self):
        """
        calc omega, this is the angle between Q and the plane
        which is perpendicular to the axis of the chi circle.

        Notes:
        ------
        For nu=mu=0 this is the same as the four circle def:
        omega = 0.5*TTH - TH, where TTH is the detector motor (=del)
        and TH is the sample circle (=eta).  Therefore, for 
        mu=nu=0 and del=0.5*eta, omega = 0, which means that Q
        is in the plane perpendicular to the chi axis.

        Note check sign of results??? 
        """
        phi=self.angles['phi']
        chi=self.angles['chi']
        eta=self.angles['eta']
        mu=self.angles['mu']
        H = num.array([[ cosd(eta), sind(eta), 0.],
                       [-sind(eta), cosd(eta), 0.],
                       [   0.,         0.,     1.]],float)
        M  = num.array([[  1.,         0.,     0.      ],
                        [  0.,      cosd(mu), -sind(mu)],
                        [  0.,      sind(mu), cosd(mu)]],float)
        # check the mult order here!!!!
        # T = num.dot(H.transpose(),M.transpose())
        T     = num.dot(M.transpose(),H.transpose())
        Qpp   = num.dot(T,self.Q)
        #omega = -1.*cartesian_angle([Qpp[0], 0, Qpp[2]],Qpp)
        omega = cartesian_angle([Qpp[0], 0, Qpp[2]],Qpp)
        self.pangles['omega'] = omega
Ejemplo n.º 6
0
def trans_point(p, theta=0.0, scale=1.0):
    """
    simple in-plane rotation of points
    """
    M = num.array([[cosd(theta), -sind(theta)], [sind(theta), cosd(theta)]])
    pp = scale * num.dot(M, p)
    return pp
Ejemplo n.º 7
0
def _spec_or_angles(angles,calc_kappa=False):
    """
    Angles defined by spec for the OR's.
    See specfile.py

    Notes:
    ------
    Assume the following.
    
    If parsing angles from the P array:
    (generally shouldnt need this since angles
    are tagged with motor labels on read)
    angles = P
    if psic:
       angles = angles[0:5]
    elif kappa fourc
       angles = [angles[0:3], angles[8], angles[7]]

    If parsing angles from the G array:
      angles = G[x:y]
    where x:y depend on whether you are
    parsing out or0 or or1.
    See spec_G below

    We then assume the following:
      del = angles[0]
      eta = angles[1]
      chi = angles[2]
      phi = angles[3]
      nu  = angles[4]
      mu  = angles[5]

    Note: calc kappa, keta and kphi
    kap_alp = 50.031;
    keta    = eta - asin(-tan(chi/2)/tan(kap_alp))
    kphi    = phi - asin(-tan(chi/2)/tan(kap_alp))
    kappa   = asin(sin(chi/2)/sin(kap_alp))
    """
    # angles from spec
    delta = angles[0]
    eta   = angles[1]
    chi   = angles[2]
    phi   = angles[3]
    nu    = angles[4]
    mu    = angles[5]

    # kappa angles
    if calc_kappa:
        kap_alp = 50.031;
        keta    = eta - arcsind(-tand(chi/2.)/tand(kap_alp))
        kphi    = phi - arcsind(-tand(chi/2.)/tand(kap_alp))
        kappa   = asind(sind(chi/2.)/sind(kap_alp))
        return {'phi':phi,'chi':chi,'eta':eta,'mu':mu,
                'delta':delta,'nu':nu,
                'keta':keta,'kphi':kphi,'kappa':kappa}
    else:
        return {'phi':phi,'chi':chi,'eta':eta,'mu':mu,
                'delta':delta,'nu':nu}
Ejemplo n.º 8
0
 def _calc_qaz(self):
     """
     Calc qaz, the angle btwn Q and the yz plane 
     """
     nu = self.angles['nu']
     delta = self.angles['delta']
     qaz = num.arctan2(sind(delta), cosd(delta) * sind(nu))
     qaz = num.degrees(qaz)
     self.pangles['qaz'] = qaz
Ejemplo n.º 9
0
 def _calc_qaz(self):
     """
     Calc qaz, the angle btwn Q and the yz plane 
     """
     nu    = self.angles['nu']
     delta = self.angles['delta']
     qaz = num.arctan2(sind(delta), cosd(delta)*sind(nu) )
     qaz = num.degrees(qaz)
     self.pangles['qaz'] = qaz
Ejemplo n.º 10
0
def calc_kvecs(nu=0.0,delta=0.0,lam=1.0):
    """
    Calculate psic ki, kr in the cartesian lab frame.
    nu and delta are in degrees, lam is in angstroms
    """
    k  = (2.* num.pi / lam)
    ki = k * num.array([0.,1.,0.],dtype=float)
    kr = k * num.array([sind(delta),
                        cosd(nu)*cosd(delta),
                        sind(nu)*cosd(delta)],dtype=float)
    return (ki,kr)
Ejemplo n.º 11
0
def calc_kvecs(nu=0.0, delta=0.0, lam=1.0):
    """
    Calculate psic ki, kr in the cartesian lab frame.
    nu and delta are in degrees, lam is in angstroms
    """
    k = (2. * num.pi / lam)
    ki = k * num.array([0., 1., 0.], dtype=float)
    kr = k * num.array(
        [sind(delta),
         cosd(nu) * cosd(delta),
         sind(nu) * cosd(delta)],
        dtype=float)
    return (ki, kr)
Ejemplo n.º 12
0
    def calc_n(self, fchi=0.0, fphi=0.0):
        """
        Calculate the hkl values of a reference vector given
        the chi and phi settings that align this
        vector with the eta axis.

        Notes:
        ------
        This algorith is used, for example, 
        to compute the surface normal from the (flat) chi and
        (flat) phi angles that leave an optical reflection in
        a fixed position during an eta rotation 

        Note the vector is normalized such that
        the largest component is unity,
        ie n_hkl isn't a unit vector!
        
        """
        # polar angles
        sig_az = -fchi
        tau_az = -fphi

        # this block converts the chi and phi values to correctly
        # defined polar coordinates, ie 0<= sig_az <= 180deg .....
        if sig_az < 0.:
            sig_az = -1. * sig_az
            if tau_az < 0.:
                tau_az = 180. + tau_az
            elif tau_az > 0.:
                tau_az = tau_az - 180.

        # n in the unrotated lab frame (ie phi frame):
        # this is a unit vector!
        n_phi = num.array([
            sind(sig_az) * cosd(tau_az), -sind(sig_az) * sind(tau_az),
            cosd(sig_az)
        ])
        # n in HKL
        n_hkl = num.dot(num.linalg.inv(self.UB), n_phi)
        n_hkl = n_hkl / num.max(num.abs(n_hkl))

        # note if l-component is negative, then its
        # pointing into the surface (ie assume positive L
        # is the positive direction away from the surface)
        # careful here!!
        if n_hkl[2] < 0.:
            n_hkl = -1. * n_hkl

        # set n which triggers recalc of
        # all the psuedo angles
        self.set_n(n_hkl)
Ejemplo n.º 13
0
def calc_Z(phi=0.0,chi=0.0,eta=0.0,mu=0.0):
    """
    Calculate the psic goniometer rotation matrix Z
    for the 4 sample angles. Angles are in degrees

    Notes:
    ------
    Z is the matrix that rotates a vector defined in the phi frame
    ie a vector defined with all angles zero => vphi.  After rotation
    the lab frame coordinates of the vector => vm are given by:
         vm = Z*vphi
    """
    P = num.array([[ cosd(phi), sind(phi), 0.],
                   [-sind(phi), cosd(phi), 0.],
                   [  0.,          0.,     1.]],float)
    X = num.array([[ cosd(chi), 0., sind(chi)],
                   [   0.,      1.,    0.],
                   [-sind(chi), 0., cosd(chi)]],float)
    H = num.array([[ cosd(eta), sind(eta), 0.],
                   [-sind(eta), cosd(eta), 0.],
                   [   0.,         0.,     1.]],float)
    M  = num.array([[  1.,         0.,     0.      ],
                    [  0.,      cosd(mu), -sind(mu)],
                    [  0.,      sind(mu), cosd(mu)]],float)
    Z = num.dot(num.dot(num.dot(M,H),X),P)
    return Z
Ejemplo n.º 14
0
    def calc_n(self,fchi=0.0,fphi=0.0):
        """
        Calculate the hkl values of a reference vector given
        the chi and phi settings that align this
        vector with the eta axis.

        Notes:
        ------
        This algorith is used, for example, 
        to compute the surface normal from the (flat) chi and
        (flat) phi angles that leave an optical reflection in
        a fixed position during an eta rotation 

        Note the vector is normalized such that
        the largest component is unity,
        ie n_hkl isn't a unit vector!
        
        """
        # polar angles
        sig_az = -fchi
        tau_az = -fphi

        # this block converts the chi and phi values to correctly 
        # defined polar coordinates, ie 0<= sig_az <= 180deg .....
        if sig_az < 0.:
            sig_az = -1.*sig_az
            if tau_az < 0.:
                tau_az = 180. + tau_az
            elif tau_az > 0.:
                tau_az = tau_az - 180.

        # n in the unrotated lab frame (ie phi frame):
        # this is a unit vector!
        n_phi = num.array([ sind(sig_az)*cosd(tau_az),
                           -sind(sig_az)*sind(tau_az), 
                                  cosd(sig_az)        ])
        # n in HKL
        n_hkl = num.dot(num.linalg.inv(self.UB),n_phi)
        n_hkl = n_hkl/ num.max(num.abs(n_hkl))
        
        # note if l-component is negative, then its
        # pointing into the surface (ie assume positive L
        # is the positive direction away from the surface)
        # careful here!!
        if n_hkl[2] < 0.:
            n_hkl = -1.*n_hkl

        # set n which triggers recalc of
        # all the psuedo angles
        self.set_n(n_hkl)
Ejemplo n.º 15
0
    def _calc_psi(self):
        """
        calc psi, this is the azmuthal angle of n wrt Q. 
        ie for tau != 0, psi is the rotation of n about Q

        Notes:
        ------
        Note this must be calc after tth, tau, and alpha!
        """
        tau   = self.pangles['tau']
        tth   = self.pangles['tth']
        alpha = self.pangles['alpha']
        #beta = self.calc_beta()
        #xx = (-cosd(tau)*sind(tth/2.) + sind(beta))
        xx    = (cosd(tau)*sind(tth/2.) - sind(alpha))
        denom = (sind(tau)*cosd(tth/2.))
        if denom == 0: 
            self.pangles['psi'] = 0.
            return
        xx    = xx /denom
        psi = arccosd( xx )
        self.pangles['psi'] = psi
Ejemplo n.º 16
0
    def _calc_psi(self):
        """
        calc psi, this is the azmuthal angle of n wrt Q. 
        ie for tau != 0, psi is the rotation of n about Q

        Notes:
        ------
        Note this must be calc after tth, tau, and alpha!
        """
        tau = self.pangles['tau']
        tth = self.pangles['tth']
        alpha = self.pangles['alpha']
        #beta = self.calc_beta()
        #xx = (-cosd(tau)*sind(tth/2.) + sind(beta))
        xx = (cosd(tau) * sind(tth / 2.) - sind(alpha))
        denom = (sind(tau) * cosd(tth / 2.))
        if denom == 0:
            self.pangles['psi'] = 0.
            return
        xx = xx / denom
        psi = arccosd(xx)
        self.pangles['psi'] = psi
Ejemplo n.º 17
0
 def cartesian(self, shift=[0., 0., 0.]):
     """
     Calculates a cartesian basis using:
       Va = a' is parallel to a
       Vb = b' is perpendicular to a' and in the a/b plane
       Vc = c' is perpendicular to the a'/c' plane
     A shift vector may be specified to shift the origin
     of the cartesian lattice relative to the original lattice
     origin (specify shift in fractional coordinates of
     the original lattice)
     """
     (a, b, c, alp, bet, gam) = self.lattice.cell()
     (ar, br, cr, alpr, betr, gamr) = self.lattice.rcell()
     Va = [1. / a, 0., 0.]
     Vb = [-1. / (a * tand(gam)), 1. / (b * sind(gam)), 0.]
     Vc = [ar * cosd(betr), br * cosd(alpr), cr]
     self.basis(Va=Va, Vb=Vb, Vc=Vc, shift=shift)
Ejemplo n.º 18
0
Archivo: lattice.py Proyecto: FHe/tdl
 def cartesian(self,shift=[0.,0.,0.]):
     """
     Calculates a cartesian basis using:
       Va = a' is parallel to a
       Vb = b' is perpendicular to a' and in the a/b plane
       Vc = c' is perpendicular to the a'/c' plane
     A shift vector may be specified to shift the origin
     of the cartesian lattice relative to the original lattice
     origin (specify shift in fractional coordinates of
     the original lattice)
     """
     (a,b,c,alp,bet,gam) = self.lattice.cell()
     (ar,br,cr,alpr,betr,gamr) = self.lattice.rcell()
     Va = [1./a,                 0. ,             0.]
     Vb = [-1./(a*tand(gam)), 1./(b*sind(gam)),   0.]
     Vc = [ar*cosd(betr),     br*cosd(alpr),      cr]
     self.basis(Va=Va,Vb=Vb,Vc=Vc,shift=shift)
Ejemplo n.º 19
0
def calc_Z(phi=0.0, chi=0.0, eta=0.0, mu=0.0):
    """
    Calculate the psic goniometer rotation matrix Z
    for the 4 sample angles. Angles are in degrees

    Notes:
    ------
    Z is the matrix that rotates a vector defined in the phi frame
    ie a vector defined with all angles zero => vphi.  After rotation
    the lab frame coordinates of the vector => vm are given by:
         vm = Z*vphi
    """
    P = num.array([[cosd(phi), sind(phi), 0.], [-sind(phi),
                                                cosd(phi), 0.], [0., 0., 1.]],
                  float)
    X = num.array([[cosd(chi), 0., sind(chi)], [0., 1., 0.],
                   [-sind(chi), 0., cosd(chi)]], float)
    H = num.array([[cosd(eta), sind(eta), 0.], [-sind(eta),
                                                cosd(eta), 0.], [0., 0., 1.]],
                  float)
    M = num.array([[1., 0., 0.], [0., cosd(mu), -sind(mu)],
                   [0., sind(mu), cosd(mu)]], float)
    Z = num.dot(num.dot(num.dot(M, H), X), P)
    return Z
Ejemplo n.º 20
0
def _spec_or_angles(angles, calc_kappa=False):
    """
    Angles defined by spec for the OR's.
    See specfile.py

    Notes:
    ------
    Assume the following.
    
    If parsing angles from the P array:
    (generally shouldnt need this since angles
    are tagged with motor labels on read)
    angles = P
    if psic:
       angles = angles[0:5]
    elif kappa fourc
       angles = [angles[0:3], angles[8], angles[7]]

    If parsing angles from the G array:
      angles = G[x:y]
    where x:y depend on whether you are
    parsing out or0 or or1.
    See spec_G below

    We then assume the following:
      del = angles[0]
      eta = angles[1]
      chi = angles[2]
      phi = angles[3]
      nu  = angles[4]
      mu  = angles[5]

    Note: calc kappa, keta and kphi
    kap_alp = 50.031;
    keta    = eta - asin(-tan(chi/2)/tan(kap_alp))
    kphi    = phi - asin(-tan(chi/2)/tan(kap_alp))
    kappa   = asin(sin(chi/2)/sin(kap_alp))
    """
    # angles from spec
    delta = angles[0]
    eta = angles[1]
    chi = angles[2]
    phi = angles[3]
    nu = angles[4]
    mu = angles[5]

    # kappa angles
    if calc_kappa:
        kap_alp = 50.031
        keta = eta - arcsind(-tand(chi / 2.) / tand(kap_alp))
        kphi = phi - arcsind(-tand(chi / 2.) / tand(kap_alp))
        kappa = asind(sind(chi / 2.) / sind(kap_alp))
        return {
            'phi': phi,
            'chi': chi,
            'eta': eta,
            'mu': mu,
            'delta': delta,
            'nu': nu,
            'keta': keta,
            'kphi': kphi,
            'kappa': kappa
        }
    else:
        return {
            'phi': phi,
            'chi': chi,
            'eta': eta,
            'mu': mu,
            'delta': delta,
            'nu': nu
        }
Ejemplo n.º 21
0
    def _calc_UB(self,):
        """
        Calculate the orientation matrix, U,
        from the primary and secondary
        reflectons and given lattice

        Note dont really ever use B by itself.  so we
        should combine this and above to calc_UB and
        just store UB??
        """
        # use these, note they are used below on vectors
        # defined in the cartesian lab frame basis
        cross = num.cross
        norm  = num.linalg.norm

        #Calculate the B matrix
        (a,b,c,alp,bet,gam)       = self.lattice.cell()
        (ar,br,cr,alpr,betr,gamr) = self.lattice.rcell()
        B = num.array([[ar,  br*cosd(gamr),     cr*cosd(betr)        ],
                       [0.,  br*sind(gamr),  -cr*sind(betr)*cosd(alp)],
                       [0.,      0.,                 1./c            ]])
        self.B = B
        
        # calc Z and Q for the OR reflections
        Z1 = calc_Z(self.or0['phi'],self.or0['chi'],self.or0['eta'],self.or0['mu'])
        Q1 = calc_Q(self.or0['nu'],self.or0['delta'],self.or0['lam'])
        #
        Z2 = calc_Z(self.or1['phi'],self.or1['chi'],self.or1['eta'],self.or1['mu'])
        Q2 = calc_Q(self.or1['nu'],self.or1['delta'],self.or1['lam'])

        # calc the phi frame coords for diffraction vectors
        # note divide out 2pi since the diffraction condition
        # is 2pi*h = Q
        vphi_1 = num.dot(num.linalg.inv(Z1), (Q1/(2.*num.pi)))
        vphi_2 = num.dot(num.linalg.inv(Z2), (Q2/(2.*num.pi)))
        
        #calc cartesian coords of h vectors
        hc_1 = num.dot(self.B, self.or0['h'])
        hc_2 = num.dot(self.B, self.or1['h'])

        #So at this point the following should be true:
        #     vphi_1 = U*hc_1
        #     vphi_2 = U*hc_2
        # and we could use these relations to solve for U.
        # But U solved directly from above is likely not to be orthogonal
        # since the angles btwn (vphi_1 and vphi_2) and (hc_1 and hc_2) are 
        # not exactly the same due to expt errors.....
        # Therefore, get an orthogonal solution for U from the below treatment
        
        #define the following normalized vectors from hc vectors 
        tc_1 = hc_1 / norm(hc_1)
        tc_3 = cross(tc_1, hc_2) / norm(cross(tc_1, hc_2))
        tc_2 = cross(tc_3, tc_1) / norm(cross(tc_3, tc_1))

        #define tphi vectors from vphi vectors
        tphi_1 = vphi_1 / norm(vphi_1)
        tphi_3 = cross(tphi_1,vphi_2) / norm(cross(tphi_1,vphi_2))
        tphi_2 = cross(tphi_3,tphi_1) / norm(cross(tphi_3,tphi_1))

        #define the following matrices
        Tc   = num.transpose(num.array([tc_1,tc_2,tc_3]))
        Tphi = num.transpose(num.array([tphi_1,tphi_2,tphi_3]))
        
        # calc orientation matrix U
        # note either of the below work since Tc is orthogonal
        #self.U = num.dot(Tphi, Tc.transpose())
        self.U = num.dot(Tphi, num.linalg.inv(Tc))

        # calc UB
        self.UB = num.dot(self.U,self.B)

        #update h and psuedo angles...
        self.set_angles()
Ejemplo n.º 22
0
    def _calc_UB(self, ):
        """
        Calculate the orientation matrix, U,
        from the primary and secondary
        reflectons and given lattice

        Note dont really ever use B by itself.  so we
        should combine this and above to calc_UB and
        just store UB??
        """
        # use these, note they are used below on vectors
        # defined in the cartesian lab frame basis
        cross = num.cross
        norm = num.linalg.norm

        #Calculate the B matrix
        (a, b, c, alp, bet, gam) = self.lattice.cell()
        (ar, br, cr, alpr, betr, gamr) = self.lattice.rcell()
        B = num.array([[ar, br * cosd(gamr), cr * cosd(betr)],
                       [0., br * sind(gamr), -cr * sind(betr) * cosd(alp)],
                       [0., 0., 1. / c]])
        self.B = B

        # calc Z and Q for the OR reflections
        Z1 = calc_Z(self.or0['phi'], self.or0['chi'], self.or0['eta'],
                    self.or0['mu'])
        Q1 = calc_Q(self.or0['nu'], self.or0['delta'], self.or0['lam'])
        #
        Z2 = calc_Z(self.or1['phi'], self.or1['chi'], self.or1['eta'],
                    self.or1['mu'])
        Q2 = calc_Q(self.or1['nu'], self.or1['delta'], self.or1['lam'])

        # calc the phi frame coords for diffraction vectors
        # note divide out 2pi since the diffraction condition
        # is 2pi*h = Q
        vphi_1 = num.dot(num.linalg.inv(Z1), (Q1 / (2. * num.pi)))
        vphi_2 = num.dot(num.linalg.inv(Z2), (Q2 / (2. * num.pi)))

        #calc cartesian coords of h vectors
        hc_1 = num.dot(self.B, self.or0['h'])
        hc_2 = num.dot(self.B, self.or1['h'])

        #So at this point the following should be true:
        #     vphi_1 = U*hc_1
        #     vphi_2 = U*hc_2
        # and we could use these relations to solve for U.
        # But U solved directly from above is likely not to be orthogonal
        # since the angles btwn (vphi_1 and vphi_2) and (hc_1 and hc_2) are
        # not exactly the same due to expt errors.....
        # Therefore, get an orthogonal solution for U from the below treatment

        #define the following normalized vectors from hc vectors
        tc_1 = hc_1 / norm(hc_1)
        tc_3 = cross(tc_1, hc_2) / norm(cross(tc_1, hc_2))
        tc_2 = cross(tc_3, tc_1) / norm(cross(tc_3, tc_1))

        #define tphi vectors from vphi vectors
        tphi_1 = vphi_1 / norm(vphi_1)
        tphi_3 = cross(tphi_1, vphi_2) / norm(cross(tphi_1, vphi_2))
        tphi_2 = cross(tphi_3, tphi_1) / norm(cross(tphi_3, tphi_1))

        #define the following matrices
        Tc = num.transpose(num.array([tc_1, tc_2, tc_3]))
        Tphi = num.transpose(num.array([tphi_1, tphi_2, tphi_3]))

        # calc orientation matrix U
        # note either of the below work since Tc is orthogonal
        #self.U = num.dot(Tphi, Tc.transpose())
        self.U = num.dot(Tphi, num.linalg.inv(Tc))

        # calc UB
        self.UB = num.dot(self.U, self.B)

        #update h and psuedo angles...
        self.set_angles()