#!/usr/bin/env amspython
# coding: utf-8
# ## Complete guide to storing and converting PLAMS Molecules between Python libraries and file formats
import os
from os.path import expandvars
from pathlib import Path
# make sure to source amsbashrc.sh before launching this example so that
# the AMSHOME environment variable is set.
AMSHOME = os.environ["AMSHOME"]
cif_file = f"{AMSHOME}/atomicdata/Molecules/IZA-Zeolites/ABW.cif"
xyz_file = f"{AMSHOME}/scripting/scm/params/examples/benchmark/ISOL6/e_13.xyz"
assert Path(cif_file).exists(), f"{cif_file} does not exist."
assert Path(xyz_file).exists(), f"{xyz_file} does not exist."
def head(filename, n: int = 4):
"""Print the first ``n`` lines of a file"""
with open(filename, "r") as f:
lines = f.readlines()
lines = lines[: min(n, len(lines))]
print("".join(lines))
# ### SMILES
# #### Load PLAMS Molecule from SMILES string
from scm.plams import from_smiles, Molecule, plot_molecule
mol = from_smiles("CCCCO")
print(f"{type(mol)=}")
plot_molecule(mol)
# #### Convert PLAMS Molecule to SMILES string
#
# Note: This requires that bonds are defined in the PLAMS Molecule.
from scm.plams import to_smiles
smiles = to_smiles(mol)
print(smiles)
# ### .xyz files
# #### Load PLAMS Molecule from .xyz file
from scm.plams import Molecule, plot_molecule
mol = Molecule(xyz_file)
print(f"{type(mol)=}")
plot_molecule(mol)
# #### Write PLAMS Molecule to .xyz file
mol.properties.comment = "The comment line (2nd line after the number of atoms)"
mol.write("out.xyz")
head("out.xyz")
# ### .cif files
# #### Load PLAMS Molecule from .cif file
#
# PLAMS cannot natively read .cif files. Instead, go through another library, for example ASE or pymatgen.
from ase.io import read
from scm.plams import fromASE
mol: Molecule = fromASE(read(cif_file))
print(f"{type(mol)=}")
plot_molecule(mol)
# #### Write PLAMS Molecule to .cif file
#
# PLAMS cannot natively export to .cif files. Instead, go through another library, for example ASE or pymatgen.
#
# ASE can be used to write many file formats. See https://wiki.fysik.dtu.dk/ase/ase/io/io.html
from scm.plams import toASE
toASE(mol).write("out.cif")
head("out.cif")
# ### AMS .in system block format
#
# #### Write PLAMS Molecule to AMS .in system file
mol.write("ams_system_block.in")
head("ams_system_block.in")
# #### Load PLAMS Molecule from AMS .in system file
from scm.plams import Molecule
mol = Molecule("ams_system_block.in")
plot_molecule(mol)
# ### POSCAR/CONTCAR (VASP input format)
# #### Write PLAMS Molecule to POSCAR/CONTCAR (VASP input format)
#
# ASE can be used to write many file formats. See https://wiki.fysik.dtu.dk/ase/ase/io/io.html
from scm.plams import toASE
toASE(mol).write("POSCAR")
head("POSCAR", 10)
# #### Load PLAMS Molecule from POSCAR/CONTCAR (VASP input format)
from scm.plams import fromASE
from ase.io import read
mol: Molecule = fromASE(read("POSCAR"))
print(f"{type(mol)=}")
plot_molecule(mol)
# ### ASE Atoms Python class
# #### Convert PLAMS Molecule to ASE Atoms
from scm.plams import toASE
from ase import Atoms
from ase.visualize.plot import plot_atoms
print(f"{type(mol)=}")
print(f"{mol.get_formula()=}")
ase_atoms: Atoms = toASE(mol)
print(f"{type(ase_atoms)=}")
print(f"{ase_atoms.get_chemical_formula()=}")
plot_atoms(ase_atoms, rotation="-85x,5y,0z")
# #### Convert ASE Atoms to PLAMS Molecule
from scm.plams import fromASE, plot_molecule, Molecule
mol: Molecule = fromASE(ase_atoms)
print(f"{type(mol)=}")
plot_molecule(mol, rotation="-85x,5y,0z")
# ### RDKit Mol Python class
# #### Convert PLAMS Molecule to RDKit Mol
from scm.plams import to_rdmol, Molecule
from rdkit.Chem import Draw
from rdkit.Chem.Draw import IPythonConsole
IPythonConsole.ipython_useSVG = True
IPythonConsole.molSize = 250, 250
plams_mol = Molecule(xyz_file)
# guess bonds, the bonds will be included in the RDKit molecule
plams_mol.guess_bonds()
rdkit_mol = to_rdmol(plams_mol)
print(f"{type(rdkit_mol)=}")
rdkit_mol
# #### Convert RDKit Mol to PLAMS Molecule
from scm.plams import from_rdmol, plot_molecule, Molecule
mol: Molecule = from_rdmol(rdkit_mol)
print(f"{type(rdkit_mol)=}")
print(f"{type(mol)=}")
plot_molecule(mol)
# ### SCM libbase UnifiedChemicalSystem Python class
#
# #### Convert PLAMS Molecule to UnifiedChemicalSystem
from scm.utils.conversions import plams_molecule_to_chemsys, chemsys_to_plams_molecule
from scm.plams import Molecule
from scm.libbase import UnifiedChemicalSystem
mol = Molecule(xyz_file)
chemsys = plams_molecule_to_chemsys(mol)
print(f"{type(chemsys)=}")
print(chemsys)
# #### Convert UnifiedChemicalSystem to PLAMS Molecule
from scm.utils.conversions import plams_molecule_to_chemsys, chemsys_to_plams_molecule
from scm.plams import Molecule
from scm.libbase import UnifiedChemicalSystem
mol = chemsys_to_plams_molecule(chemsys)
print(f"{type(chemsys)=}")
print(f"{type(mol)=}")
plot_molecule(mol)
# ### pymatgen Structure and Molecule Python classes
# #### Convert PLAMS Molecule to pymatgen Structure (periodic)
#
# There is no builtin converter between PLAMS Molecule and pymatgen Structure (periodic crystal). Instead, you need to go through the ASE interface to both packages:
from pymatgen.core.structure import Structure
from pymatgen.io.ase import AseAtomsAdaptor
import scm.plams
from scm.plams import fromASE, toASE, Molecule
from ase.io import read
def convert_plams_molecule_to_pymatgen_structure(mol: Molecule) -> Structure:
return AseAtomsAdaptor().get_structure(toASE(mol))
mol: scm.plams.Molecule = fromASE(read(cif_file))
pymatgen_structure: Structure = convert_plams_molecule_to_pymatgen_structure(mol)
print(f"{type(mol)=}")
print(f"{type(pymatgen_structure)=}")
print(pymatgen_structure)
# #### Convert pymatgen Structure (periodic) to PLAMS Molecule
#
# Go through the ASE interface:
from pymatgen.io.ase import AseAtomsAdaptor
from pymatgen.core.structure import Structure
from scm.plams import fromASE
from scm.plams import Molecule
def pymatgen_structure_to_plams_molecule(pymatgen_structure: Structure) -> Molecule:
return fromASE(AseAtomsAdaptor().get_atoms(pymatgen_structure))
print(f"{type(pymatgen_structure)=}")
mol = pymatgen_structure_to_plams_molecule(pymatgen_structure)
print(f"{type(mol)=}")
# #### Convert PLAMS Molecule to pymatgen Molecule (non-periodic)
#
# pymatgen has a special ``Molecule`` class for non-periodic systems. In PLAMS, the ``Molecule`` class is used for both periodic and non-periodic systems.
import pymatgen.core.structure
import scm.plams
from pymatgen.io.ase import AseAtomsAdaptor
from scm.plams import toASE
def convert_plams_molecule_to_pymatgen_molecule(
mol: scm.plams.Molecule,
) -> pymatgen.core.structure.Molecule:
return AseAtomsAdaptor().get_molecule(toASE(mol))
plams_molecule = scm.plams.Molecule(xyz_file)
pymatgen_molecule: pymatgen.core.structure.Molecule = convert_plams_molecule_to_pymatgen_molecule(plams_molecule)
print(f"{type(plams_molecule)=}")
print(f"{type(pymatgen_molecule)=}")
print(pymatgen_molecule)
# #### Convert pymatgen Molecule (non-periodic) to PLAMS Molecule
from pymatgen.io.ase import AseAtomsAdaptor
import pymatgen.core.structure
from scm.plams import fromASE
from scm.plams import Molecule
def pymatgen_molecule_to_plams_molecule(
pymatgen_molecule: pymatgen.core.structure.Molecule,
) -> scm.plams.Molecule:
return fromASE(AseAtomsAdaptor().get_atoms(pymatgen_molecule))
print(f"{type(pymatgen_molecule)=}")
mol = pymatgen_molecule_to_plams_molecule(pymatgen_molecule)
print(f"{type(mol)=}")
plot_molecule(mol)