def update(self, coords, lattice=None, absolute=False, update_mol=True): """ After the geometry relaxation, the returned atomic coordinates maybe rescaled to [0, 1] bound. In this case, we need to refind the molecular coordinates according to the original neighbor list. If the list does not change, we return the new coordinates otherwise, terminate the calculation. """ from pyxtal.molecule import compare_mol_connectivity, Orientation try: from openbabel import pybel, openbabel except: import pybel, openbabel if lattice is not None: self.lattice = lattice if not absolute: coords = coords.dot(self.lattice.matrix) #mol = Molecule(self.symbols, coords-np.mean(coords, axis=0)) center = self.molecule.get_center(coords) mol = Molecule(self.symbols, coords - center) #match, _ = compare_mol_connectivity(mol, self.mol, True) match, _ = compare_mol_connectivity(mol, self.mol) if match: #position = np.mean(coords, axis=0).dot(self.lattice.inv_matrix) position = center.dot(self.lattice.inv_matrix) #position -= np.floor(position) self.position = position - np.floor(position) if update_mol: self.orientation = Orientation(np.eye(3)) self.mol = mol else: m1 = pybel.readstring('xyz', self.mol.to('xyz')) m2 = pybel.readstring('xyz', mol.to('xyz')) aligner = openbabel.OBAlign(True, False) aligner.SetRefMol(m1.OBMol) aligner.SetTargetMol(m2.OBMol) if aligner.Align(): print("RMSD: ", aligner.GetRMSD()) rot = np.zeros([3, 3]) for i in range(3): for j in range(3): rot[i, j] = aligner.GetRotMatrix().Get(i, j) if abs(np.linalg.det(rot) - 1) < 1e-2: self.orientation.matrix = rot self.orientation.r = R.from_matrix(rot) else: raise ValueError("rotation matrix is wrong") else: import pickle with open('wrong.pkl', "wb") as f: pickle.dump([mol, self.mol], f) mol.to(filename='Wrong.xyz', fmt='xyz') self.mol.to(filename='Ref.xyz', fmt='xyz') raise ValueError("molecular connectivity changes! Exit")