def main(GoniometerAxes, inputFile, mode, v1, v2, datum, beam, spgn=None): global XOfileType # The goniostat consists of axes e1 carrying e2 carrying e3 # (eg Omega, Kappa, Phi). GoniometerAxes = e1, e2, e3 # gnsdtm calculate D from datum and GoniometerAxes. # D == Goniometer.tensor == datum matrix Goniometer = ThreeAxisRotation2((0.,0.,0.), GoniometerAxes, inversAxesOrder=0) # DATUM definition in degree. setDatum = tuple(datum) # in degree Goniometer.setAngles(map(degree2radian,setDatum)) # MODE = 'CUSP' or 'MAIN' VL = gnsmod(mode, beam, Goniometer) # V1/V2 V1 = CrystalVector(v1, printPrecision=4) V2 = CrystalVector(v2, printPrecision=4) if "%s" % V1 != "%s" % V2: desiredSetting = V1, V2 else: print "ERROR: The two crystal aligned vector can't be identical!" sys.exit(2) if type(inputf[0]) == str: gotcha = False for parser in (DenzoParser, XDSParser, MosflmParser): try: XOparser = parser(inputf[0]) gotcha = True except : pass if gotcha: break if not gotcha: raise Exception, "Can't parse input orientation matrix file: %s" %\ inputf[0] elif hasattr(inputf, "fileType"): XOparser = inputf if VERBOSE: print "\n %s used to read input file: %s" % (XOparser.info, inputf[0]) XOfileType = XOparser.fileType if not spgn: spgn = XOparser.spaceGroupNumber spg = XOparser.spaceGroupName else: spg = spg_num2symb[spgn] pointGroup = SPGlib[spgn][-1] if VERBOSE: print "\n Space group symbol: %s, Number: %d, Point Group: %s" % \ (spg.upper(),spgn, pointGroup) print ("\n Real cell: "+3*"%10.3f"+3*"%8.2f") % \ tuple(XOparser.cell) print (" Reciprocal cell: "+3*"%10.6f"+3*"%8.2f") % \ tuple(XOparser.cell_r) Bmos = BusingLevy(XOparser.cell_r) # Umos = setting matrix at current datum # Getting Mosflm XO if XOparser.fileType == "Mosflm": UBmos = XOparser.U * Bmos # whitout wavelength scaling Umos = XOparser.U # XOparser.UB = UBmos * wavelength # Converting Denzo XO to Mosflm convention elif XOparser.fileType == "Denzo": UBmos = Qdnz2mos * XOparser.UB Umos = (UBmos) * Bmos.inverse() # Converting XDS XO to Mosflm convention elif XOparser.fileType == "XDS": UBmos = XOparser.UBxds_to_mos()/ XOparser.dict["wavelength"] Umos = (UBmos) * Bmos.inverse() is_orthogonal(Umos) if VERBOSE: printmat( Umos,'\n U', "%12.6f") printmat( Bmos,'\n B', "%12.6f") printmat( UBmos,'\n UB', "%12.6f") Bm1t = Bmos.inverse().transpose() orthogMatrices = {'rec':Bmos, 'dir':Bm1t} # There are two ways to write the crystal orientation in mosflm: # using the U matrix or the phi1, phi2, phi3 misseting angles (in degree). # == gnspxg: decompose Umos into 3 "missetting" angles phi123 phi123r = ThreeAxisRotation2(Umos.mlist, inversAxesOrder=1).getAngles() # keep only the first solution and convert it in degre. phi123 = map_r2d(phi123r[0]) # This new Umos def - equivalent to the previous - is needed to # stay exactly compatible with gonset. # Umos2 = ThreeAxisRotation(phi123r[0], inversAxesOrder=1).tensor # printmat(Umos2, 'Umos2') # print "\nDiff Umos/Umos2 =======>> %8.1e" % diffMAT(Umos2,Umos) # U0mos = zero-angle setting matrix # [U] = [D] [U0] so [U0] = [D]**-1 [U] U0mos = Goniometer.tensor.inverse() * Umos # == gnsszr if VERBOSE: print ("\n phixyz: "+3*"%8.2f"+"\n") % tuple(phi123) now(XOparser.cell, Umos, U0mos, phi123, orthogMatrices, Goniometer, beam, setDatum, desiredSetting) PG_permutions = [[X,Y,Z]] if _do_PG_permutations: PG_permutions.extend(PGequiv[pointGroup]) datumSolutions = solve(desiredSetting, VL, orthogMatrices, U0mos, Goniometer, PG_permutions) # Ajouter la verification directement au moment du calcul # Permutation of the UB matrix... (U matrix) only? # How the permutation is handled for hexagonal. # n = 0 #if 0: if _debug: for newdatum in datumSolutions: n += 1 Goniometer.setAngles(map(degree2radian, newdatum)) newUmos = Goniometer.tensor * U0mos printmat(newUmos, "\nNew Umos matrix. Solution numb. %3d" % n,\ "%12.6f") phi123 = ThreeAxisRotation2(newUmos.mlist, inversAxesOrder=1).getAngles() phi123 = map_r2d(phi123[0]) print ("\n phixyz: "+3*"%8.2f"+"\n") % tuple(phi123) return datumSolutions
def main(GoniometerAxes, inputFile, mode, v1, v2, datum, beam, spgn=None): global XOfileType # The goniostat consists of axes e1 carrying e2 carrying e3 # (eg Omega, Kappa, Phi). GoniometerAxes = e1, e2, e3 # gnsdtm calculate D from datum and GoniometerAxes. # D == Goniometer.tensor == datum matrix Goniometer = ThreeAxisRotation2((0., 0., 0.), GoniometerAxes, inversAxesOrder=0) # DATUM definition in degree. setDatum = tuple(datum) # in degree Goniometer.setAngles(map(degree2radian, setDatum)) # MODE = 'CUSP' or 'MAIN' VL = gnsmod(mode, beam, Goniometer) # V1/V2 V1 = CrystalVector(v1, printPrecision=4) V2 = CrystalVector(v2, printPrecision=4) if "%s" % V1 != "%s" % V2: desiredSetting = V1, V2 else: print "ERROR: The two crystal aligned vector can't be identical!" sys.exit(2) if type(inputf[0]) == str: gotcha = False for parser in (DenzoParser, XDSParser, MosflmParser): try: XOparser = parser(inputf[0]) gotcha = True except: pass if gotcha: break if not gotcha: raise Exception, "Can't parse input orientation matrix file: %s" %\ inputf[0] elif hasattr(inputf, "fileType"): XOparser = inputf if VERBOSE: print "\n %s used to read input file: %s" % (XOparser.info, inputf[0]) XOfileType = XOparser.fileType if not spgn: spgn = XOparser.spaceGroupNumber spg = XOparser.spaceGroupName else: spg = spg_num2symb[spgn] pointGroup = SPGlib[spgn][-1] if VERBOSE: print "\n Space group symbol: %s, Number: %d, Point Group: %s" % \ (spg.upper(),spgn, pointGroup) print ("\n Real cell: "+3*"%10.3f"+3*"%8.2f") % \ tuple(XOparser.cell) print (" Reciprocal cell: "+3*"%10.6f"+3*"%8.2f") % \ tuple(XOparser.cell_r) Bmos = BusingLevy(XOparser.cell_r) # Umos = setting matrix at current datum # Getting Mosflm XO if XOparser.fileType == "Mosflm": UBmos = XOparser.U * Bmos # whitout wavelength scaling Umos = XOparser.U # XOparser.UB = UBmos * wavelength # Converting Denzo XO to Mosflm convention elif XOparser.fileType == "Denzo": UBmos = Qdnz2mos * XOparser.UB Umos = (UBmos) * Bmos.inverse() # Converting XDS XO to Mosflm convention elif XOparser.fileType == "XDS": UBmos = XOparser.UBxds_to_mos() / XOparser.dict["wavelength"] Umos = (UBmos) * Bmos.inverse() is_orthogonal(Umos) if VERBOSE: printmat(Umos, '\n U', "%12.6f") printmat(Bmos, '\n B', "%12.6f") printmat(UBmos, '\n UB', "%12.6f") Bm1t = Bmos.inverse().transpose() orthogMatrices = {'rec': Bmos, 'dir': Bm1t} # There are two ways to write the crystal orientation in mosflm: # using the U matrix or the phi1, phi2, phi3 misseting angles (in degree). # == gnspxg: decompose Umos into 3 "missetting" angles phi123 phi123r = ThreeAxisRotation2(Umos.mlist, inversAxesOrder=1).getAngles() # keep only the first solution and convert it in degre. phi123 = map_r2d(phi123r[0]) # This new Umos def - equivalent to the previous - is needed to # stay exactly compatible with gonset. # Umos2 = ThreeAxisRotation(phi123r[0], inversAxesOrder=1).tensor # printmat(Umos2, 'Umos2') # print "\nDiff Umos/Umos2 =======>> %8.1e" % diffMAT(Umos2,Umos) # U0mos = zero-angle setting matrix # [U] = [D] [U0] so [U0] = [D]**-1 [U] U0mos = Goniometer.tensor.inverse() * Umos # == gnsszr if VERBOSE: print("\n phixyz: " + 3 * "%8.2f" + "\n") % tuple(phi123) now(XOparser.cell, Umos, U0mos, phi123, orthogMatrices, Goniometer, beam, setDatum, desiredSetting) PG_permutions = [[X, Y, Z]] if _do_PG_permutations: PG_permutions.extend(PGequiv[pointGroup]) datumSolutions = solve(desiredSetting, VL, orthogMatrices, U0mos, Goniometer, PG_permutions) # Ajouter la verification directement au moment du calcul # Permutation of the UB matrix... (U matrix) only? # How the permutation is handled for hexagonal. # n = 0 #if 0: if _debug: for newdatum in datumSolutions: n += 1 Goniometer.setAngles(map(degree2radian, newdatum)) newUmos = Goniometer.tensor * U0mos printmat(newUmos, "\nNew Umos matrix. Solution numb. %3d" % n,\ "%12.6f") phi123 = ThreeAxisRotation2(newUmos.mlist, inversAxesOrder=1).getAngles() phi123 = map_r2d(phi123[0]) print("\n phixyz: " + 3 * "%8.2f" + "\n") % tuple(phi123) 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
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