| import gradio as gr | |
| import shutil | |
| from rdkit import Chem | |
| from rdkit.Chem import AllChem | |
| import pandas as pd | |
| from ase import Atoms | |
| from ase.optimize import BFGS | |
| from ase.vibrations import Vibrations | |
| from ase.thermochemistry import IdealGasThermo | |
| from fairchem.core import FAIRChemCalculator, pretrained_mlip | |
| predictor = pretrained_mlip.get_predict_unit("uma-s-1", device="cpu") | |
| calculator = FAIRChemCalculator(predictor, task_name="omol") | |
| model = "UMA-OMOL" | |
| def calc_vibrations(smile: str, struct_type: str) -> str: | |
| """Calculate the vibrational frequencies of a molecule | |
| using the META UMA MLIP, starting from a SMILES string. | |
| Args: | |
| smile: The SMILES string of the molecule | |
| struct_type: The type of the molecule (linear or non-linear) | |
| Returns: | |
| The vibrational frequencies of the molecule in cm-1, the low | |
| frequency motions (typically corresponding to translation or | |
| rotation), and the number of imaginary frequencies in a text string | |
| """ | |
| mol = Chem.MolFromSmiles(smile) | |
| molH = Chem.AddHs(mol) | |
| AllChem.EmbedMolecule(molH) | |
| AllChem.MMFFOptimizeMolecule(molH) | |
| xyz_list = [] | |
| atoms_list = "" | |
| for atom in molH.GetAtoms(): | |
| atoms_list += atom.GetSymbol() | |
| pos = molH.GetConformer().GetAtomPosition(atom.GetIdx()) | |
| temp_tuple = (pos[0], pos[1], pos[2]) | |
| xyz_list.append(temp_tuple) | |
| atoms = Atoms(atoms_list,xyz_list) | |
| atoms.calc = calculator | |
| energy = atoms.get_potential_energy() | |
| dyn = BFGS(atoms) | |
| dyn.run(fmax=0.05) | |
| final_energy = atoms.get_potential_energy() | |
| vib = Vibrations(atoms) | |
| vib.run() | |
| vib_energies = vib.get_energies() | |
| real_vibs = [] | |
| number_imaginary = 0 | |
| for vib in vib_energies: | |
| if vib.imag < 0.00001: | |
| real_vibs.append(8065.56*vib.real.item()) | |
| else: | |
| number_imaginary += 1 | |
| num_atoms = molH.GetNumAtoms() | |
| if struct_type == "non-linear" or struct_type == "nonlinear": | |
| non_vib_dof = 6 - number_imaginary | |
| else: | |
| non_vib_dof = 5 - number_imaginary | |
| vib_dof = 3*num_atoms - non_vib_dof | |
| out_text = "" | |
| for i,vib in enumerate(real_vibs[3*num_atoms - vib_dof:]): | |
| out_text += f"Vibrational frequency {i+1}: {vib:.3f} cm-1\n" | |
| out_text += f"Also calculated the following low frequency motions:\n" | |
| for i,vib in enumerate(real_vibs[:3*num_atoms - vib_dof]): | |
| out_text += f"Frequency {i+1}: {vib:.3f} cm-1\n" | |
| out_text += f"Also found the following number of imaginary frequencies: {number_imaginary}" | |
| shutil.rmtree('vib') | |
| return out_text | |
| gradio_app = gr.Interface( | |
| calc_vibrations, | |
| inputs=[gr.Textbox(label="SMILES to calculate"),gr.Radio(label="Type of molecule", choices=["linear", "non-linear"])], | |
| outputs=[gr.Textbox(label="Frequencies: ")], | |
| title="Get Vibrational frequencies of a molecule from SMILES using the META UMA MLIP", | |
| ) | |
| if __name__ == "__main__": | |
| gradio_app.launch(mcp_server=True) |