Read, write, file formats

Overview

A ChemicalSystem can be created from, and saved to, many file formats commonly used in computational chemistry (see Supported formats).

These are coordinate-based formats: each file stores a list of atoms with their positions, and, depending on the format, extra data such as the lattice, bonds, charges and atomic attributes. Most are plain text; the exception is the binary kf/rkf format.

Most formats cannot capture everything a ChemicalSystem holds, so reading or writing may lose information (e.g. .xyz files carry no bonds). Only the AMS-native in and kf / rkf formats are lossless.

Read/write to file

The two main entry points are from_file() and write_file(), which deduce the format from the file extension (or from an explicit format argument):

from scm.base import ChemicalSystem, Lattice

# Creating some systems for testing
water = ChemicalSystem.from_smiles("O")
periodic_water = water.copy()
periodic_water.lattice = Lattice.from_lattice_parameters(5,5,5) # 5 Å cubic cell

# Writing to file
# ===============

# File format deduced from the file extension (".xyz" in this case)
water.write_file("water.xyz")

# Optionally you can explicitly specify the file format.
# This takes precedence over the file extension.
periodic_water.write_file("periodic_water", format="cif")

# There are also dedicated methods to read/write in specific formats,
# some of which might take format-specific options, e.g.:
water.write_kf("ams.rkf", section="Molecule")
periodic_water.write_ase_xyz("periodic_water.xyz")

# Reading from file
# =================

# from_file is a constructor: it returns a NEW ChemicalSystem.
# File format deduced from the file extension
water_from_disk = ChemicalSystem.from_file("water.xyz")
print(water_from_disk)

# Optionally you can explicitly specify the file format.
periodic_water_from_disk = ChemicalSystem.from_file("periodic_water", format="cif")

# In case of failure to read/write, an exception will be raised.
try:
    water.write_file("water", format="cif") # writing a non-periodic system to CIF fails
except Exception as e:
    print(e)

Read/write to strings

Because most formats are plain text, you can also read from or write to an in-memory string, using from_string() and Python’s format:

from scm.base import ChemicalSystem

# Reading from strings
# ====================

xyz_string = """3

O   0.0   0.0     -0.3772
H   0.0   0.8002   0.1886
H   0.0  -0.8002   0.1886
"""
# The from_string method needs the format to be explicitly defined
water = ChemicalSystem.from_string(xyz_string, format="xyz")

# Printing / writing to strings
# =============================

# When converting the chemical system to string, the default format is "in"
print(water)

# ...but you can use Python f-string formatting to specify the file format:
print(f"{water:xyz}")
print(f"{water:mol}")

# Equivalently, you can use the format method:
pdb_string = format(water, "pdb")
print(pdb_string)

Line notation (SMILES)

A ChemicalSystem can also be created from a line notation such as SMILES, and a system that has bonds can be written back out as SMILES with to_smiles().

Note that, unlike other formats described on this page, SMILES encodes only the connectivity (the molecular graph) and no coordinates, so a 3D geometry is generated when it is read. See SMILES.

from scm.base import ChemicalSystem

benzene = ChemicalSystem.from_smiles("c1ccccc1")
print(benzene)

# Note: the xyz format does not include bonds.
water = ChemicalSystem.from_file("water.xyz") # assumes water.xyz from the example above

# When converting to a SMILES string, the bonds in the chemical system
# will be used for the connectivity. You can use the guess_bonds() method
# if the chemical system does not already have bonds
water.guess_bonds()
print(water.to_smiles())

Supported formats

These are the supported coordinate-based formats (all can be both read and written). The check marks show which extra information, besides the atomic coordinates, each format is able to store:

Format

Bonds

Periodic

Total Charge

Atomic attributes

Description

Encoding

in

Any

AMS-native System block. Lossless.

text

kf / rkf

Any

AMS-native binary file. Lossless.

binary

xyz

Any

XYZ file. Extended AMS and ASE variants add extra info (see xyz).

text

mol2

see notes

Tripos MOL2. Atomic attributes: only forcefield atom types and charges.

text

pdb

Protein Data Bank. Often omits hydrogen atoms.

text

mol

MDL Molfile.

text

cif

3D only

Crystallographic Information File. Symmetry is expanded on read; writing produces a P1 cell.

text

poscar

3D only

VASP POSCAR / CONTCAR. The files are conventionally extensionless.

text

dmol

Any

DMol3 file.

text

API

Besides the generic from_file() / write_file() interface, every supported format has dedicated from_* and write_* methods. Use these when you want to be explicit about the format, or when you need a format-specific option (such as the KF section name).

Generic from/to file

The generic methods from_file() and write_file() deduce the file format from the file extension. Pass the optional format argument to override that, or when the file has no usable extension.

classmethod ChemicalSystem.from_file(filename: str, format: str = '') ChemicalSystem

Constructs and returns a new ChemicalSystem from a file.

The file format is deduced from the extension of filename unless it is given explicitly through the format argument. The supported format identifiers are: kf/rkf (binary KF files), in (AMS System blocks), xyz (extended XYZ files), mol2 (MOL2 files), pdb (PDB files), mol (MDL MOL files), cif (Crystallographic Information Files), poscar (VASP POSCAR/CONTCAR files) and dmol (DMol3 files). POSCAR files are additionally auto-detected from a .vasp or .contcar extension, or a POSCAR/CONTCAR filename.

Parameters:
  • filename – Path to the file to read.

  • format – File format, e.g. "xyz". If empty, it is deduced from the filename extension.

Returns:

A new ChemicalSystem read from the file.

Note this may raise a ChemicalSystemError if the format cannot be deduced or is not supported, or if the file does not exist or cannot be parsed.

ChemicalSystem.write_file(filename: str, format: str = '') None

Writes the ChemicalSystem to a file.

This is the complement of from_file(): the format is deduced from the extension of filename unless given explicitly through format. The same formats are supported as for reading, with the caveat that cif and poscar require a 3D lattice, and pdb/mol are written via RDKit.

Parameters:
  • filename – Path to the file to write.

  • format – File format, e.g. "xyz". If empty, it is deduced from the filename extension.

Note this may raise a ChemicalSystemError if the format cannot be deduced or is not supported, or if the system cannot be written in the requested format.

Generic from/to strings

A ChemicalSystem can be converted to a string and parsed back from one, without going through a file.

classmethod ChemicalSystem.from_string(content: str, format: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from an in-memory string.

This is the in-memory counterpart of from_file(). Unlike from_file(), the format is required, as there is no filename to deduce it from. The same text formats are supported as for from_file() (in, xyz, mol2, pdb, mol, cif, poscar and dmol); the binary kf/rkf format is not supported and raises.

Parameters:
  • content – The file contents to parse.

  • format – File format, e.g. "xyz".

Returns:

A new ChemicalSystem parsed from the string.

Note this may raise a ChemicalSystemError if the format is missing, unsupported (e.g. kf), or if the content cannot be parsed.

ChemicalSystem.__format__(format_spec: str) str

Formats a ChemicalSystem into a string representation.

The format_spec string starts with and identifier for the format to write, followed and optional : and a list of space separated key=value pairs configuring options of the format. E.g. the following would produce the AMS System block format in internal units (bohr) with the string “H2O” as a System name in the block header:

cs = ChemicalSystem(...)
print(f"{cs:in:units=internal name=H2O}")

Would produce the output:

System H2O
    Atoms [bohr]
        O 0 0 -0.7262847342654172
        H 0 1.4669943905469853 0.3631423765813393
        H 0 -1.4669943905469853 0.3631423765813393
    End
End

The following formats and options are supported at the moment:

  • in for writing the AMS System block. This is the default format, if none is specified. The following options are supported:

    • name=... to put an arbitrary string as the system’s name into the block header.

    • units=[default|internal] to switch between default units and the units used by the ChemicalSystem internally. Internally the ChemicalSystem uses atomic units (e.g. bohr for lengths). Printing the System block in internal units avoids a possible loss in precision in the unit conversion and guarantees an exact ChemicalSystem -> str -> ChemicalSystem round-trip, i.e.:

      cs = ChemicalSystem(...)
      assert ChemicalSystem(f"{cs:in:units=internal}") == cs
      
    • skip=[gui|adf|band|forcefield|dftb|reaxff|qe|...] to avoid printing of a particular property group in the end-of-line string of an atom in the System%Atoms subblock. Multiple groups may be specified as a comma separated list.

    • unused_atom_attributes=[drop|include] to determine whether unused atomic attributes groups should be written out as Modify%EnableAtomAttributes entries. The default is not to do this, aka drop. This means that unused atomic attributes groups get lost in the ChemicalSystem -> str -> ChemicalSystem round-trip. If preserving them is important, this can be achieved by setting this option to include.

  • xyz for writing a plain XYZ file without lattice or atomic attributes. This format has no options.

  • extended_xyz for writing the AMS extended XYZ format. This format has no options.

  • ase_xyz for writing the ASE-style extended XYZ format (lattice on the comment line as Lattice="..."). This format has no options.

  • mol2, cif, poscar, dmol, pdb and mol for the corresponding file formats (the same ones supported by from_file() / write_file()). These have no options. cif and poscar require a 3D lattice; pdb and mol are produced via RDKit.

  • out for a human-readable summary of the system (as printed to standard output by AMS). No options.

  • ase for formatting using ASE. Examples: print(f"{cs:ase:extxyz}") for the ASE extended XYZ format, or print(f"{cs:ase:vasp}") for the POSCAR format. The full list of allowed formats can be obtained by running the command amspython -m ase info --formats.

SMILES

A ChemicalSystem can be created from a SMILES string, generating a reasonable 3D geometry, and conversely a canonical SMILES string can be derived from an existing ChemicalSystem’s bonds and geometry:

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 trial 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. Disconnected molecules (separated by .) are arranged non-overlapping in space. Note this may raise a ChemicalSystemError if the conversion cannot be completed.

ChemicalSystem.to_smiles() str

Converts a ChemicalSystem to a canonical SMILES string, derived from its bonds and geometry.

The SMILES is built from the system’s bonds, so the ChemicalSystem must contain bonding information for the result to be meaningful. If the bonds are not already defined, call guess_bonds() first to perceive them from the geometry.

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

in (System block)

The System block is an AMS-native, lossless, human-readable text format that describes the full chemical system, including bonds, lattice, charges and atomic attributes. For the full syntax and options, see the AMS System Block documentation. Example of an in file (System block) for a water molecule:

System
    Atoms
        O 0.0  0.0      -0.404121
        H 0.0  0.783036  0.202060
        H 0.0 -0.783036  0.202060
    End
    BondOrders
        1 2 1
        1 3 1
    End
End
classmethod ChemicalSystem.from_in(filename: str, name: str = '') ChemicalSystem

Constructs and returns a new ChemicalSystem from a (possibly named) System block in an AMS input file.

ChemicalSystem.write_in(filename: str) None

Writes a ChemicalSystem to file as an AMS System block.

kf / rkf

The AMS binary kf file is lossless and can hold several systems in different sections, so both methods take a section argument (default "Molecule").

classmethod ChemicalSystem.from_kf(filename: str, section: str = 'Molecule') ChemicalSystem
classmethod ChemicalSystem.from_kf(kf: KFFile, section: str = 'Molecule') ChemicalSystem

Constructs and returns a new ChemicalSystem from a section on a KF file.

ChemicalSystem.write_kf(filename: str, section: str = 'Molecule', omode: OpenMode = KFFile.OpenMode.Any) None
ChemicalSystem.write_kf(kf: KFFile, section: str = 'Molecule') None

Writes a ChemicalSystem to a section on a KF file.

xyz

The XYZ format is a simple text format storing element symbols and Cartesian coordinates, but no bonds. AMS handles three variants:

plain XYZ: coordinates only, no periodicity. Example for a water molecule:

3

O  0.0  0.0      -0.404121
H  0.0  0.783036  0.202060
H  0.0 -0.783036  0.202060

AMS-extended XYZ: additionally stores the lattice, total charge and atomic attributes (see the AMS-extended XYZ documentation). Example for diamond:

2

C -0.44625 -0.44625 -0.44625
C  0.44625  0.44625  0.44625
VEC1  0.000  1.785  1.785
VEC2  1.785  0.000  1.785
VEC3  1.785  1.785  0.000

ASE-extended XYZ: the ASE convention, which stores the lattice on the comment line as Lattice="...". Example for diamond:

2
Lattice="0 1.785 1.785 1.785 0 1.785 1.785 1.785 0" pbc="T T T" Properties=species:S:1:pos:R:3
C -0.44625 -0.44625 -0.44625
C  0.44625  0.44625  0.44625

Note: all three variants conventionally have the same .xyz extension.

from_xyz() reads all three automatically. write_xyz() writes the AMS-extended variant by default; pass extended_xyz_format=False for a plain XYZ file, or use write_ase_xyz() for the ASE variant.

classmethod ChemicalSystem.from_xyz(filename: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from an extended XYZ file.

Lattice vectors may be given either in the AMS style, as VEC1/VEC2/VEC3 lines following the atoms, or in the ASE style, as a Lattice="ax ay az bx by bz cx cy cz" entry on the comment line (the second line), optionally accompanied by a pbc="px py pz" flag marking which directions are periodic. If both are present, the VEC lines take precedence.

ChemicalSystem.write_xyz(filename: str, extended_xyz_format: bool = True) None

Writes a ChemicalSystem to an XYZ file.

By default the file is written in the AMS extended XYZ file format, which includes lattice vectors, atomic attributes, regions and some system properties such as the total charge. In order to write a plain standard XYZ files without any of these extensions, set extended_xyz_format to False.

ChemicalSystem.write_ase_xyz(filename: str) None

Writes a ChemicalSystem to an ASE-style extended XYZ file.

This is an alternative to write_xyz(): instead of the AMS VEC1/VEC2/VEC3 lines, the lattice is written on the comment line as Lattice="ax ay az bx by bz cx cy cz" together with a pbc="..." flag and an extended-XYZ Properties field, and each atom is written as symbol x y z. Such files can be read back with from_xyz() / from_file().

mol2

The MOL2 format is a text format that stores bonds, along with per-atom types and partial charges. Example of a .mol2 file for water:

# mol2 file for water

@<TRIPOS>MOLECULE
LIG
    3     2     1     0     0
SMALL

@<TRIPOS>ATOM
    1 O            0.0000     0.0000    -0.4041 O          0 LIG       0.000000
    2 H            0.0000     0.7830     0.2021 H          0 LIG       0.000000
    3 H            0.0000    -0.7830     0.2021 H          0 LIG       0.000000
@<TRIPOS>BOND
    1     1     2 1
    2     1     3 1
@<TRIPOS>SUBSTRUCTURE
    1 LIG         1 TEMP              0 ****  ****    0 ROOT
classmethod ChemicalSystem.from_mol2(filename: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from an extended MOL2 file.

ChemicalSystem.write_mol2(filename: str) None

Writes a ChemicalSystem to a MOL2 file.

The MOL2 file does not support lattice vectors, or any atom attributes except forcefield types end charges.

pdb

PDB files are read and written using RDKit as backend. Note that PDB files often omit hydrogen atoms, so the resulting system may be missing hydrogens. Example of a .pdb file for water:

HETATM    1  O1  UNL     1       0.000   0.000  -0.404  1.00  0.00           O
HETATM    2  H1  UNL     1       0.000   0.783   0.202  1.00  0.00           H
HETATM    3  H2  UNL     1       0.000  -0.783   0.202  1.00  0.00           H
CONECT    1    2    3
END
classmethod ChemicalSystem.from_pdb(filename: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from a PDB file.

The file is parsed using RDKit as backend. All atoms are kept exactly as they appear in the file, including hydrogens, and no chemical sanitization is performed, so unusual or incomplete structures (common in PDB files) will not cause the read to fail. Bonds are taken from the file’s CONECT records and, where those are absent, perceived from interatomic distances.

Parameters:

filename – Path to the PDB file to read.

Returns:

A new ChemicalSystem holding the atoms, coordinates and bonds from the file.

Note this may raise a ChemicalSystemError if the file cannot be read or parsed.

ChemicalSystem.write_pdb(filename: str) None

Writes the ChemicalSystem to a PDB file, using RDKit as backend.

mol

MDL MOL files are read and written using RDKit as backend, and include bonds. Example of a .mol file for water:

water


  3  2  0  0  0  0  0  0  0  0999 V2000
    0.0000    0.0000    0.0000 O   0  0  0  0  0  0  0  0  0  0  0  0
    0.7570    0.5860    0.0000 H   0  0  0  0  0  0  0  0  0  0  0  0
   -0.7570    0.5860    0.0000 H   0  0  0  0  0  0  0  0  0  0  0  0
  1  2  1  0
  1  3  1  0
M  END
classmethod ChemicalSystem.from_mol(filename: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from an MDL MOL file.

The file is parsed using RDKit as backend. All atoms are kept exactly as they appear in the file, including hydrogens, and no chemical sanitization is performed, so unusual or incomplete structures will not cause the read to fail. Bonds and their bond orders are taken from the file’s bond block.

Parameters:

filename – Path to the MOL file to read.

Returns:

A new ChemicalSystem holding the atoms, coordinates and bonds from the file.

Note this may raise a ChemicalSystemError if the file cannot be read or parsed.

ChemicalSystem.write_mol(filename: str) None

Writes the ChemicalSystem to an MDL MOL file, using RDKit as backend.

cif

The CIF format describes periodic (crystalline) systems. Reading expands the asymmetric unit into the full unit cell: using the file’s explicit symmetry operators if present, otherwise the operators of the space group looked up in spglib from the space-group number or Hermann-Mauguin symbol. A file with neither is read as the asymmetric unit only. Writing produces a P1 cell (no symmetry reduction) and requires a 3D lattice. Example of .cif for diamond:

data_diamond_cif_file
_symmetry_space_group_name_H-M   'P 1'
_symmetry_Int_Tables_number      1
_cell_length_a    2.5243712088
_cell_length_b    2.5243712088
_cell_length_c    2.5243712088
_cell_angle_alpha 60.0
_cell_angle_beta  60.0
_cell_angle_gamma 60.0
loop_
_symmetry_equiv_pos_as_xyz
'x, y, z'
loop_
_atom_site_label
_atom_site_type_symbol
_atom_site_fract_x
_atom_site_fract_y
_atom_site_fract_z
C1 C -0.1250000000 -0.1250000000 -0.1250000000
C2 C 0.1250000000  0.1250000000  0.1250000000
classmethod ChemicalSystem.from_cif(filename: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from a CIF (Crystallographic Information File).

The cell parameters and the atoms of the asymmetric unit (given in fractional or Cartesian coordinates) are read. If the file lists explicit symmetry operations (_symmetry_equiv_pos_as_xyz or _space_group_symop_operation_xyz), they are applied to expand the asymmetric unit into the full unit cell, with atoms on coinciding positions deduplicated. If the file has no explicit operator list but does identify a space group (through _symmetry_Int_Tables_number or a Hermann-Mauguin symbol _symmetry_space_group_name_H-M), the operators are looked up in spglib’s space-group database and applied. When this lookup is needed and the file supplies both identifiers, they must admit a common Hall setting. Identifier inconsistencies are ignored when explicit operators are present, because those operators are authoritative. A structure with neither operators nor an identifiable space group is read as the asymmetric unit only.

Parameters:

filename – Path to the CIF file to read.

Returns:

A new ChemicalSystem holding the (expanded) atoms and the unit cell.

Note this may raise a ChemicalSystemError if the file cannot be read or parsed.

ChemicalSystem.write_cif(filename: str) None

Writes the ChemicalSystem to a CIF file.

A minimal P1 file is written (the cell, an explicit identity symmetry operation, and every atom in fractional coordinates); no symmetry reduction is attempted. Requires a 3D lattice, otherwise a ChemicalSystemError is raised.

poscar

POSCAR (and CONTCAR) files describe periodic systems for VASP. These files conventionally have no extension. Writing requires a 3D lattice. Example of a POSCAR file for diamond:

Diamond
1.0
    0.0000000000000000    1.7849999999999999    1.7849999999999999
    1.7849999999999999    0.0000000000000000    1.7849999999999999
    1.7849999999999999    1.7849999999999999    0.0000000000000000
C
2
Direct
   -0.1250000000000000   -0.1250000000000000   -0.1250000000000000
    0.1250000000000000    0.1250000000000000    0.1250000000000000
classmethod ChemicalSystem.from_poscar(filename: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from a VASP POSCAR / CONTCAR file.

The unit cell, element symbols and atom positions (in direct/fractional or Cartesian coordinates) are read. The scale line may contain one universal factor (including the negative-value “target volume” convention) or three positive factors for the Cartesian x, y and z components. Both the VASP 5 format (with an explicit element-symbol line) and the legacy VASP 4 format (with the element symbols on the comment line) are supported. Any “Selective dynamics” flags are ignored.

Parameters:

filename – Path to the POSCAR/CONTCAR file to read.

Returns:

A new ChemicalSystem holding the atoms and the unit cell.

Note this may raise a ChemicalSystemError if the file cannot be read or parsed.

ChemicalSystem.write_poscar(filename: str) None

Writes the ChemicalSystem to a VASP POSCAR file (Direct/fractional coordinates).

Requires a 3D lattice, otherwise a ChemicalSystemError is raised.

dmol

The DMol3 format is a simple text format storing Cartesian coordinates (in angstrom) and, for periodic systems, the cell vectors. It does not include bonds. Example of a .dmol file for diamond:

$cell_vectors
        0.0000000000        1.7850000000        1.7850000000
        1.7850000000        0.0000000000        1.7850000000
        1.7850000000        1.7850000000        0.0000000000
$coordinates
C        -0.4462500000       -0.4462500000       -0.4462500000
C         0.4462500000        0.4462500000        0.4462500000
$end
classmethod ChemicalSystem.from_dmol(filename: str) ChemicalSystem

Constructs and returns a new ChemicalSystem from a DMol3 .dmol file.

The Cartesian atom coordinates and, if present, the cell vectors are read (both in angstrom).

Parameters:

filename – Path to the .dmol file to read.

Returns:

A new ChemicalSystem holding the atoms and (optionally) the unit cell.

Note this may raise a ChemicalSystemError if the file cannot be read or parsed.

ChemicalSystem.write_dmol(filename: str) None

Writes the ChemicalSystem to a DMol3 .dmol file (Cartesian coordinates, plus cell vectors for periodic systems).

ASE formats

A ChemicalSystem can also be created from any format supported by ASE via an intermediate ase.Atoms instance.

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.