def solve(desiredSetting, VL, orthogMatrices, U0, Goniometer, PG_permutions=[[X,Y,Z]]): """ Solve for datum position Uses: VL Laboratory vectors to match orthogMatrices Dict containing {'rec':Bm1t, 'dir':B} desiredSetting List of the two vectors defining the desired setting U0 Zero-angle setting matrix PG_permutions Point group permutations Return: datumSolutions (list of datum solutions in degrees) Local variables U0m1 [U0]**-1 C base vectors in crystal frame Cm1 [C]**-1 L base vectors in laboratory frame SL L matrix with permuted signs CU [C]**-1 [U0]**-1 """ # Orthogonalize crystal vectors h -> yv # YV crystal frame vectors defining desired setting (orthogonalized) YV = [] for vi in 0, 1: # if reciproc: B*vi.vector elif direct: B1mt*vi.vector B = orthogMatrices[desiredSetting[vi].space] YV.append(B*desiredSetting[vi]) # referential_permutations sign permutations for four permutations of # parallel/antiparallel (rotation axis & beam) # y1 // e1, y2 // beamVector; y1 anti// e1, y2 // beamVector # y1 // e1, y2 anti// beamVector; y1 anti// e1, y2 anti// beamVector referential_permutations = [ ex, ey, ez], \ [-ex, -ey, ez], \ [ ex, -ey, -ez], \ [-ex, ey, -ez] # Construct orthogonal frame in crystal space defined by vectors # y1 = yv(,1) and y2 = yv(,2). The base vectors form the COLUMNS # of matrix C # - 1st vector along YV1 # - 3rd vector perpendicular to YV1 & YV2 # - 2nd vector completes the RH set C1 = YV[0].normalize() C3 = YV[0].cross(YV[1]).normalize() C2 = C3.cross(C1).normalize() C = mat3(C1, C2, C3) # Similarly, construct laboratory frame matrix defined by VL1, VL2 # 1st vector along VL1 # 3rd vector perpendicular to VL1 & VL2 # 2nd vector completes the RH set L1 = VL[0].normalize() L3 = VL[0].cross(VL[1]).normalize() L2 = L3.cross(L1).normalize() L = mat3(L1, L2, L3) # The matrix which superimposes the two frames is L C**-1. This # is then the orientation matrix DU, including the required datum # position D. The datum matrix is then D = L C**-1 U**-1 # We need to consider four possible alignments & values of D, # corresponding to y1 parallel & antiparallel to vl1, and y2 # parallel & antiparallel to vl2. To get these, we change # the signs of l1 & l2, or l2 & l3, or both, as set out in array LS. datumSolutions = [] independentSolution = [] # Loop four solutions for D, each with possibly two sets of goniostat # angles Cm1 = C.inverse() B = orthogMatrices['rec'] UB0 = U0 * B # Loop for introducing Point Group permutations: for PG_operator in PG_permutions: # We use the operator in reciprocal space so it need a transposition. PG_operator = mat3T(PG_operator) # printmat(B.dot(PG_operator),'B.dot(PG_operator)') # The PG operator is applied on the UB0 matrix U0perm = UB0 * PG_operator * B.inverse() if _debug: print printmat(PG_operator, 'PG_operator', "%12.6f") printmat(U0, 'U0', "%12.6f") printmat(U0perm, 'U0perm', "%12.6f") if not is_orthogonal(U0perm): print "!!!!!!!!!!!!!!! ERROR: Improper U0perm matrice!!" # CU = C**-1 . U**-1 CU = Cm1 * U0perm.inverse() for referential_permut in referential_permutations: SL = L * mat3T(referential_permut) _DM = SL * CU # angles: there are zero or two possible sets of goniostat angles # which correspond to D, although one or both may be inaccessible try: _2s = ThreeAxisRotation2(_DM.mlist, Goniometer.rotationAxes, inversAxesOrder=0).getAngles() twoSolutions = (_2s[0][2],_2s[0][1],_2s[0][0]), \ (_2s[1][2],_2s[1][1],_2s[1][0]) for oneSolution in twoSolutions: solutionKey = "%6.2f%6.2f%6.2f" % tuple(oneSolution) if solutionKey not in independentSolution: independentSolution.append(solutionKey) datumSolutions.append(map(radian2degree, oneSolution)) #print ">>>>>>>>>",solutionKey,"number ", #print len(independentSolution) else: if _debug: print ">>>>>>>>> Redundant solution" except ValueError: pass return datumSolutions
def solve(desiredSetting, VL, orthogMatrices, U0, Goniometer, PG_permutions=[[X, Y, Z]]): """ Solve for datum position Uses: VL Laboratory vectors to match orthogMatrices Dict containing {'rec':Bm1t, 'dir':B} desiredSetting List of the two vectors defining the desired setting U0 Zero-angle setting matrix PG_permutions Point group permutations Return: datumSolutions (list of datum solutions in degrees) Local variables U0m1 [U0]**-1 C base vectors in crystal frame Cm1 [C]**-1 L base vectors in laboratory frame SL L matrix with permuted signs CU [C]**-1 [U0]**-1 """ # Orthogonalize crystal vectors h -> yv # YV crystal frame vectors defining desired setting (orthogonalized) YV = [] for vi in 0, 1: # if reciproc: B*vi.vector elif direct: B1mt*vi.vector B = orthogMatrices[desiredSetting[vi].space] YV.append(B * desiredSetting[vi]) # referential_permutations sign permutations for four permutations of # parallel/antiparallel (rotation axis & beam) # y1 // e1, y2 // beamVector; y1 anti// e1, y2 // beamVector # y1 // e1, y2 anti// beamVector; y1 anti// e1, y2 anti// beamVector referential_permutations = [ ex, ey, ez], \ [-ex, -ey, ez], \ [ ex, -ey, -ez], \ [-ex, ey, -ez] # Construct orthogonal frame in crystal space defined by vectors # y1 = yv(,1) and y2 = yv(,2). The base vectors form the COLUMNS # of matrix C # - 1st vector along YV1 # - 3rd vector perpendicular to YV1 & YV2 # - 2nd vector completes the RH set C1 = YV[0].normalize() C3 = YV[0].cross(YV[1]).normalize() C2 = C3.cross(C1).normalize() C = mat3(C1, C2, C3) # Similarly, construct laboratory frame matrix defined by VL1, VL2 # 1st vector along VL1 # 3rd vector perpendicular to VL1 & VL2 # 2nd vector completes the RH set L1 = VL[0].normalize() L3 = VL[0].cross(VL[1]).normalize() L2 = L3.cross(L1).normalize() L = mat3(L1, L2, L3) # The matrix which superimposes the two frames is L C**-1. This # is then the orientation matrix DU, including the required datum # position D. The datum matrix is then D = L C**-1 U**-1 # We need to consider four possible alignments & values of D, # corresponding to y1 parallel & antiparallel to vl1, and y2 # parallel & antiparallel to vl2. To get these, we change # the signs of l1 & l2, or l2 & l3, or both, as set out in array LS. datumSolutions = [] independentSolution = [] # Loop four solutions for D, each with possibly two sets of goniostat # angles Cm1 = C.inverse() B = orthogMatrices['rec'] UB0 = U0 * B # Loop for introducing Point Group permutations: for PG_operator in PG_permutions: # We use the operator in reciprocal space so it need a transposition. PG_operator = mat3T(PG_operator) # printmat(B.dot(PG_operator),'B.dot(PG_operator)') # The PG operator is applied on the UB0 matrix U0perm = UB0 * PG_operator * B.inverse() if _debug: print printmat(PG_operator, 'PG_operator', "%12.6f") printmat(U0, 'U0', "%12.6f") printmat(U0perm, 'U0perm', "%12.6f") if not is_orthogonal(U0perm): print "!!!!!!!!!!!!!!! ERROR: Improper U0perm matrice!!" # CU = C**-1 . U**-1 CU = Cm1 * U0perm.inverse() for referential_permut in referential_permutations: SL = L * mat3T(referential_permut) _DM = SL * CU # angles: there are zero or two possible sets of goniostat angles # which correspond to D, although one or both may be inaccessible try: _2s = ThreeAxisRotation2(_DM.mlist, Goniometer.rotationAxes, inversAxesOrder=0).getAngles() twoSolutions = (_2s[0][2],_2s[0][1],_2s[0][0]), \ (_2s[1][2],_2s[1][1],_2s[1][0]) for oneSolution in twoSolutions: solutionKey = "%6.2f%6.2f%6.2f" % tuple(oneSolution) if solutionKey not in independentSolution: independentSolution.append(solutionKey) datumSolutions.append(map(radian2degree, oneSolution)) #print ">>>>>>>>>",solutionKey,"number ", #print len(independentSolution) else: if _debug: print ">>>>>>>>> Redundant solution" except ValueError: pass return datumSolutions
""" % _progname from XOconv import mat3T, printmat, is_orthogonal, spg_num2symb, BusingLevy, \ SPGlib, map_r2d, PGequiv, openWriteClose, openReadClose, \ rootSquareSum, random_3axes, kappaVector, SPGlib2 from XOconv import MosflmParser, DenzoParser, XDSParser VERBOSE = True r2d = 180/math.pi radian2degree = lambda a: a*r2d degree2radian = lambda a: a/r2d ex, ey, ez = vec3(1,0,0), vec3(0,1,0), vec3(0,0,1) X, Y, Z = ex, ey, ez Qdnz2mos = mat3T(ez, ex, ey) class CrystalVector(vec3): """ Define a crystal vector to represent reciprocal or direct space vectors NOTE that it can accept fractional coordinates like CrystalVector("(1.2 1.22 4.9)") NOTE that as it inherit from the Vector class, CrystalVectors support the usual arithmetic operations ('v1', 'v2': vectors, 's': scalar): - 'v1+v2' (addition) - 'v1-v2' (subtraction) - 'v1*v2' (scalar product) - 's*v1', 'v1*s' (multiplication with a scalar) - 'v1/s' (division by a scalar)
""" % _progname from XOconv import mat3T, printmat, is_orthogonal, spg_num2symb, BusingLevy, \ SPGlib, map_r2d, PGequiv, openWriteClose, openReadClose, \ rootSquareSum, random_3axes, kappaVector, SPGlib2 from XOconv import MosflmParser, DenzoParser, XDSParser VERBOSE = True r2d = 180 / math.pi radian2degree = lambda a: a * r2d degree2radian = lambda a: a / r2d ex, ey, ez = vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1) X, Y, Z = ex, ey, ez Qdnz2mos = mat3T(ez, ex, ey) class CrystalVector(vec3): """ Define a crystal vector to represent reciprocal or direct space vectors NOTE that it can accept fractional coordinates like CrystalVector("(1.2 1.22 4.9)") NOTE that as it inherit from the Vector class, CrystalVectors support the usual arithmetic operations ('v1', 'v2': vectors, 's': scalar): - 'v1+v2' (addition) - 'v1-v2' (subtraction) - 'v1*v2' (scalar product) - 's*v1', 'v1*s' (multiplication with a scalar)