def _symmetric(self): if abs(self._eigenvalues[0] - self._eigenvalues[1]) < self.tolerance: idx = 2 elif abs(self._eigenvalues[0] - self._eigenvalues[2]) < self.tolerance: idx = 1 else: idx = 0 main_axis = self._eigenvectors[idx, :] self.check_order_rot(main_axis) self.rot_sym.append((main_axis, self._max_order)) # Obtain all the c2 vectors perpendicular to main axis for ida, axis in enumerate(self._eigenvectors): if ida != idx: p_axis = axis break for angle in np.linspace(0, 360, 144, endpoint=False): axis = np.matmul(np.array(rotation_matrix(main_axis, angle)), np.array(p_axis)) c2 = rotation_matrix(axis, 360 / 2) if self.check_op(c2): self.sym_op.append(c2) self.rot_sym.append((axis / np.linalg.norm(axis), 2)) self.check_consistency() if len(self.rot_sym) >= 2: self._dihedral() elif len(self.rot_sym) == 1: self._cyclic() else: self._no_rot_axis()
def check_order_rot(self, axis): order = 0 for i in list(range(2, 9)): Cn = rotation_matrix(axis, 360 / i) if self.check_op(Cn): order = i self.sym_op.append(Cn) self._max_order = order
def _improper_rot(self): for axis, order in self.rot_sym: if order == 2: ref_mat = reflection(axis) for n in range(20, 0, -2): Cn = rotation_matrix(axis, 360 / n) Sn = np.dot(Cn, ref_mat) if self.check_op(Sn): self.rot_sym.append((axis, 'S' + str(n))) self.sym_op.append(Sn) break
def orthogonal_c4(c3, c4): def calculate_angle(axis1, axis2): axis1 /= np.linalg.norm(axis1) axis2 /= np.linalg.norm(axis2) return np.arccos( np.dot(axis1, axis2) / (np.linalg.norm(axis1) * np.linalg.norm(axis2))) * 180 / np.pi perfect_c3_c4 = 125.26438968275465 c3 /= np.linalg.norm(c3) c4 /= np.linalg.norm(c4) angle_c3_c4 = calculate_angle(c3, c4) diff_angle = perfect_c3_c4 - angle_c3_c4 if abs(diff_angle) <= 1E-8: new_c4 = c4 else: new_c4 = np.dot(rotation_matrix(np.cross(c3, c4), diff_angle), c4) warn('ChangedAxisWarning: Set C4 axis to: {}'.format(new_c4)) rot_mat = rotation_matrix(c3, 120.0) c4_2 = np.dot(rot_mat, new_c4) return new_c4, c4_2 / np.linalg.norm(c4_2)
def _asymmetric(self): for axis in self._eigenvectors: c2 = rotation_matrix(axis, 180) if self.check_op(c2): self.sym_op.append(c2) self.rot_sym.append((axis, 2)) if len(self.sym_op) == 0: self._no_rot_axis() elif len(self.sym_op) == 1: self._cyclic() else: self._dihedral()
def mirror_plane(self, main_axis): m_type = '' if self.check_op(reflection(main_axis)): self.rot_sym.append((main_axis, 'Sh')) self.sym_op.append(reflection(main_axis)) m_type = 'h' else: # Sv planes # p_axis = np.random.randn(3) p_axis -= np.dot(p_axis, main_axis) * main_axis p_axis /= np.linalg.norm(p_axis) for angle in np.linspace(0, 360, 144, endpoint=False): axis = np.matmul(np.array(rotation_matrix(main_axis, angle)), np.array(p_axis)) possible_mirror = reflection(axis) if self.check_op(possible_mirror): m_type = 'v' self.rot_sym.append((axis, 'Sv')) self.sym_op.append(possible_mirror) # Sd planes # c2_axes, gt_axes = [], [] for axis, order in self.rot_sym: if order == 2: c2_axes.append(axis) if order == self._max_order: gt_axes.append(axis) for c2_1, c2_2 in itertools.combinations(c2_axes, 2): c2_vector = c2_1 + c2_2 if all(c2_vector < 1e-8): continue else: c2_vector /= np.linalg.norm(c2_vector) for gt_vector in gt_axes: p_axis = np.cross(c2_vector, gt_vector) possible_mirror = reflection(p_axis) if self.check_op(reflection(p_axis)): m_type = 'd' self.rot_sym.append( (p_axis / np.linalg.norm(p_axis), 'Sd')) self.sym_op.append(possible_mirror) return m_type
def _spherical(self): # I or Ih for axis in self._eigenvectors: c5 = rotation_matrix(axis, 360 / 5) if self.check_op(c5): self.sym_op.append(c5) self.rot_sym.append((axis, 5)) self.schoenflies_symbol = "I" self._max_order = 5 if self.schoenflies_symbol and self.check_op(inversion()): self.schoenflies_symbol += 'h' # O or Oh if not self.schoenflies_symbol: for axis in self._eigenvectors: c4 = rotation_matrix(axis, 360 / 4) if self.check_op(c4): self.sym_op.append(c4) self.rot_sym.append((axis, 4)) self.schoenflies_symbol = "O" self._max_order = 4 if self.schoenflies_symbol and self.check_op(inversion()): self.schoenflies_symbol += 'h' # Obtain all the c2 vectors and matrices for angle1 in np.linspace(0, 360, 72, endpoint=False): axis1 = np.matmul(np.array(rotation_matrix([1, 0, 0], angle1)), np.array([0, 0, 1])) for angle2 in np.linspace(0, 180, 72, endpoint=False): axis2 = np.matmul(np.array(rotation_matrix([0, 1, 0], angle2)), axis1) c2 = rotation_matrix(axis2, 360 / 2) if self.check_op(c2): self.sym_op.append(c2) self.rot_sym.append((axis2 / np.linalg.norm(axis2), 2)) if self.rot_sym: self.check_consistency() # T or Td, Th m_type = '' if not self.schoenflies_symbol: # Obtain all the c3 vectors and matrices for angle1 in np.linspace(0, 360, 72, endpoint=False): axis1 = np.matmul(np.array(rotation_matrix([1, 0, 0], angle1)), np.array([0, 0, 1])) for angle2 in np.linspace(0, 180, 72, endpoint=False): axis2 = np.matmul( np.array(rotation_matrix([0, 1, 0], angle2)), axis1) c3 = rotation_matrix(axis2, 360 / 3) if self.check_op(c3): self.sym_op.append(c3) self.rot_sym.append((axis2 / np.linalg.norm(axis2), 3)) self.schoenflies_symbol = "T" self._max_order = 3 self.check_consistency() for axis, order in self.rot_sym: if order == 3: m_type = self.mirror_plane(axis) break if m_type == '': if self.check_op(inversion()): self.rot_sym.append(([0, 0, 0], 'i')) self.sym_op.append(inversion()) self.schoenflies_symbol += 'h' # else: # self.schoenflies_symbol += 'd' else: self.schoenflies_symbol += 'd' self._improper_rot()