Complete Python code

#!/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)