def get_integer(vec): # Used vec = np.array(vec, dtype=float) before, but does not work for # [5.00000000e-01, -5.00000000e-01, 2.22044605e-16] in Sigma3[112] vec = np.round(vec, 12) vec_sign = np.array([1 if abs(i) == i else -1 for i in vec]) vec = list(abs(vec)) new_vec = [] if 0.0 in vec: zero_ind = vec.index(0) vec.pop(zero_ind) if 0.0 in vec: new_vec = [get_smallest_multiplier(vec) * i for i in vec] else: frac = Fraction(vec[0] / vec[1]).limit_denominator() new_vec = [frac.numerator, frac.denominator] new_vec.insert(zero_ind, 0) else: for i in range(len(vec) - 1): frac = Fraction(vec[i] / vec[i + 1]).limit_denominator() new_vec.extend([frac.numerator, frac.denominator]) if new_vec[1] == new_vec[2]: new_vec = [new_vec[0], new_vec[1], new_vec[3]] else: new_vec = reduce_vector([new_vec[0] * new_vec[2], new_vec[1] * new_vec[2], new_vec[3] * new_vec[1]]) assert is_integer(new_vec) return new_vec * vec_sign
def orthogonalize_csl(csl, axis): """ (1) Set the 3rd column of csl same as the rotation axis. The algorithm was borrowed from gosam project with slight changes. Link to the project: https://github.com/wojdyr/gosam (2) Orthogonalize CSL, which is essentially a Gram-Schmidt process. At the same time, we want to make sure the column vectors of orthogonalized csl has the smallest value possible. That's why we compared two different ways. csl = [v1, v2, v3], vi is the column vector u1 = v3/||v3||, y2 = v1 - (v1 . u1)u1 u2 = y2/||y2||, y3 = v3 - [(v3 . u1)u1 + (v3 . u2)u2] u3 = y3/||y3|| """ axis = np.array(axis) c = solve(csl.transpose(), axis) if not is_integer(c): mult = get_smallest_multiplier(c) c *= mult c = c.round().astype(int) ind = min([(i, v) for i, v in enumerate(c) if not np.allclose(v, 0)], key=lambda x: abs(x[1]))[0] if ind != 2: csl[ind], csl[2] = csl[2].copy(), -csl[ind] c[ind], c[2] = c[2], -c[ind] csl[2] = np.dot(c, csl) if c[2] < 0: csl[1] *= -1 def get_integer(vec): # Used vec = np.array(vec, dtype=float) before, but does not work for # [5.00000000e-01, -5.00000000e-01, 2.22044605e-16] in Sigma3[112] vec = np.round(vec, 12) vec_sign = np.array([1 if abs(i) == i else -1 for i in vec]) vec = list(abs(vec)) new_vec = [] if 0.0 in vec: zero_ind = vec.index(0) vec.pop(zero_ind) if 0.0 in vec: new_vec = [get_smallest_multiplier(vec) * i for i in vec] else: frac = Fraction(vec[0] / vec[1]).limit_denominator() new_vec = [frac.numerator, frac.denominator] new_vec.insert(zero_ind, 0) else: for i in range(len(vec) - 1): frac = Fraction(vec[i] / vec[i + 1]).limit_denominator() new_vec.extend([frac.numerator, frac.denominator]) if new_vec[1] == new_vec[2]: new_vec = [new_vec[0], new_vec[1], new_vec[3]] else: new_vec = reduce_vector([new_vec[0] * new_vec[2], new_vec[1] * new_vec[2], new_vec[3] * new_vec[1]]) assert is_integer(new_vec) return new_vec * vec_sign u1 = csl[2] / norm(csl[2]) y2_1 = csl[1] - np.dot(csl[1], u1) * u1 c0_1 = get_integer(y2_1) y2_2 = csl[0] - np.dot(csl[0], u1) * u1 c0_2 = get_integer(y2_2) if sum(abs(c0_1)) > sum(abs(c0_2)): u2 = y2_2 / norm(y2_2) y3 = csl[1] - np.dot(csl[1], u1) * u1 - np.dot(csl[1], u2) * u2 csl[1] = get_integer(y3) csl[0] = c0_2 else: u2 = y2_1 / norm(y2_1) y3 = csl[0] - np.dot(csl[0], u1) * u1 - np.dot(csl[0], u2) * u2 csl[1] = c0_1 csl[0] = get_integer(y3) for i in range(3): for j in range(i + 1, 3): if not np.allclose(np.dot(csl[i], csl[j]), 0): raise ValueError("Non-orthogonal basis: %s" % csl) return csl.round().astype(int)