ASE, RDKit and PLAMS
********************


ASE Atoms
=========

ChemicalSystem instances can be converted to and from the ase.Atoms
class that is part of the Atomic Simulation Environment:

ChemicalSystem.to_ase_atoms() -> ase.Atoms

   Converts a ChemicalSystem to an "ase.Atoms" instance.

   Calling this method may throw an ImportError if the "ase" package
   can not be found in your Python environment.

   Handles coordinates, atomic numbers, regions, and lattice vectors
   (if present). The order of atoms is preserved. The systems total
   charge is saved as the "charge" entry in the "info" dictionary of
   the returned instance. All other molecular and atomic attributes,
   bonds, and the atom selection is lost in the conversion.

   The regions are stored on "atoms.info["ams_regions"]" as a string
   of this format:

   >>> atoms.info["ams_regions"] == "region A(0,1,2)second region(0,1)etc(0,1)"

classmethod ChemicalSystem.from_ase_atoms(ase_atoms: ase.Atoms) -> ChemicalSystem

   Converts an "ase.Atoms" instance to a ChemicalSystem.

   Calling this method may throw an ImportError if the "ase" package
   can not be found in your Python environment.

   Handles coordinates, atomic numbers, regions, and lattice vectors
   (if present). The order of atoms is preserved. If the "info"
   dictionary of the "Atoms" instance contains an entry "charge", it
   is used as the ChemicalSystem's total charge. All other molecular
   or atomic attributes, as well as the ASE calculator derived
   properties, such as forces or calculated charges are lost in the
   conversion.

   Note that the used lattice vectors from the "ase.Atoms" object are
   those for which "get_pbc" is set to True. Those should already
   conform to the AMS convention of having the first lattice vector
   along the x-axis and the second vector in the xy-plane. A
   ChemicalSystemError will be thrown if that is not the case.

   To recover regions, they need to be stored in
   "atoms.info["ams_regions"]" as a string with this format:

   >>> atoms.info["ams_regions"] = "region A(0,1,2)second region(0,1)etc(0,1)"

In addition, ChemicalSystem instances can be generated directly from
files (via "ase.Atoms"):

classmethod ChemicalSystem.from_ase_read(filename: str | IO, index: Any | None = None, format: str | None = None, **kwargs) -> ChemicalSystem

   Loads a ChemicalSystem from a file using "ase.io.read". See ASE
   documentation for details.

   Calling this method may throw an ImportError if the "ase" package
   can not be found in your Python environment.

   Note that the construction of the ChemicalSystem is via
   "ase.Atoms". See "ChemicalSystem.from_ase_atoms" for details and
   restrictions.


RDKit Molecule
==============

ChemicalSystem instances can be converted to and from the
"rdkit.Chem.Mol" class that is part of RDKit:

ChemicalSystem.to_rdkit_mol() -> rdkit.Chem.Mol

   Converts a ChemicalSystem to an "rdkit.Chem.Mol" instance.

   Calling this method may throw an ImportError if the "rdkit" package
   can not be found in your Python environment.

   Handles coordinates, atomic numbers, and bonds (if present). The
   order of atoms is preserved. All other molecular and atomic
   attributes, lattice, regions and the atom selection is lost in the
   conversion.

classmethod ChemicalSystem.from_rdkit_mol(rdkit_mol: rdkit.Chem.Mol, conformer_id: int | None = None) -> ChemicalSystem

   Converts an "rdkit.Chem.Mol" instance to a ChemicalSystem.

   Calling this method may throw an ImportError if the "rdkit" package
   can not be found in your Python environment.

   Handles coordinates, atomic numbers, and bonds (if present). The
   order of atoms is preserved. All other molecular or atomic
   attributes and properties are lost in the conversion.

   An integer "conformer_id" can be provided to select a specific
   conformer from the molecule. If omitted, the default conformer will
   be used.

In addition, ChemicalSystem instances can be converted to and from
SMILES strings (via "rdkit.Mol"):

classmethod ChemicalSystem.from_smiles(smiles: str, optimize_with_uff: bool = True, num_trial_conformers: int = 10) -> ChemicalSystem

   Converts a SMILES string to a ChemicalSystem.

   To generate a reasonable starting configuration, by default
   multiple trials conformers will be generated and optimized with
   UFF. The lowest energy of these conformers is then selected. This
   behaviour can be altered by setting "optimize_with_uff=False", or
   modifying "num_trial_conformers". Note this may raise a
   ChemicalSystemError if the conversion cannot be completed.

   Calling this method may throw an ImportError if the "rdkit" package
   can not be found in your Python environment.

ChemicalSystem.to_smiles() -> str

   Converts a ChemicalSystem to a SMILES string.

   Note this does not take into account any atomic charges, and may
   raise a ChemicalSystemError if the conversion cannot be completed.

   Calling this method may throw an ImportError if the "rdkit" package
   can not be found in your Python environment.


PLAMS Molecule
==============

ChemicalSystem instances and PLAMS Molecule objects can be converted
into each other using the following conversion functions:
"scm.utils.conversions.plams_molecule_to_chemsys" and
"scm.utils.conversions.chemsys_to_plams_molecule".

Example:

   from scm.base import ChemicalSystem
   from scm.plams import from_smiles, Molecule
   from scm.utils.conversions import plams_molecule_to_chemsys, chemsys_to_plams_molecule

   # Create a PLAMS molecule from a SMILES string:
   plams_molecule = from_smiles('CCO')

   # Convert from a PLAMS molecule to a ChemicalSystem:
   chemical_system = plams_molecule_to_chemsys(plams_molecule)

   # Convert back from ChemicalSystem to a PLAMS molecule:
   plams_molecule = chemsys_to_plams_molecule(chemical_system)
