Introduction to atomman: POSCAR conversions

Lucas M. Hale, lucas.hale@nist.gov, Materials Science and Engineering Division, NIST.

Disclaimers

1. Introduction

The POSCAR format is the default atomic configuration representation used by the VASP DFT software. As such, a large amount of reference data can be found in the POSCAR format and the format is supported by many different atomistic programs.

Currently, atomman offers basic support for loading/dumping the box and atomic coordination information stored in the POSCAR format. The reading and writing of additional flags and values is not yet included.

Library Imports

[1]:
# Standard Python libraries
import datetime

# http://www.numpy.org/
import numpy as np

import atomman as am
import atomman.unitconvert as uc

# Show atomman version
print('atomman version =', am.__version__)

# Show date of Notebook execution
print('Notebook executed on', datetime.date.today())
atomman version = 1.4.11
Notebook executed on 2024-04-29

Generate test system information (CsCl)

[2]:
# Generate box
alat = uc.set_in_units(3.2, 'angstrom')
box = am.Box(a=alat, b=alat, c=alat)

# Generate atoms with atype, pos, charge, and stress properties
atype = [1, 2]
pos = [[0,0,0], [0.5, 0.5, 0.5]]
charge = uc.set_in_units([1, -1], 'e')
stress = uc.set_in_units(np.zeros((2, 3, 3)), 'MPa')
atoms = am.Atoms(pos=pos, atype=atype, charge=charge, stress=stress)

# Build system from box and atoms, and scale atoms
system = am.System(atoms=atoms, box=box, scale=True, symbols=['Cs', 'Cl'])

# Print system information
print(system)
system.atoms_df()
avect =  [ 3.200,  0.000,  0.000]
bvect =  [ 0.000,  3.200,  0.000]
cvect =  [ 0.000,  0.000,  3.200]
origin = [ 0.000,  0.000,  0.000]
natoms = 2
natypes = 2
symbols = ('Cs', 'Cl')
pbc = [ True  True  True]
per-atom properties = ['atype', 'pos', 'charge', 'stress']
     id   atype  pos[0]  pos[1]  pos[2]
      0       1   0.000   0.000   0.000
      1       2   1.600   1.600   1.600
[2]:
atype pos[0] pos[1] pos[2] charge stress[0][0] stress[0][1] stress[0][2] stress[1][0] stress[1][1] stress[1][2] stress[2][0] stress[2][1] stress[2][2]
0 1 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1 2 1.6 1.6 1.6 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

2. System.dump(‘poscar’)

Generates a POSCAR file based on the System. Note: the POSCAR format only captures per-atom data for each atom’s type and position. Therefore, it does not offer a lossless representation of a System object.

Parameters

  • f (str or file-like object, optional) File path or file-like object to write the content to. If not given, then the content is returned as a str.

  • header (str, optional) The comment line to place at the top of the file. Default value is ‘’.

  • symbols (list of str, optional) List of the element symbols that correspond to the atom types. If not given, will use system.symbols if set, otherwise no element content will be included.

  • coordstyle (str, optional) The poscar coordinate style to use: ‘cartesian’ or ‘direct’ (i.e. box relative). Default value is ‘direct’.

  • box_scale (float, optional) A universal scaling constant applied to the box vectors. Default value is 1.0.

  • float_format (str, optional) c-style format for printing the floating point numbers. Default value is ‘%.13e’.

Returns

  • poscar_str (str) String of the poscar object (only returned if fname is not given).

Dump with mostly default values

[3]:
poscar = system.dump('poscar', header='Test POSCAR content for CsCl')
print(poscar)
Test POSCAR content for CsCl
1.0000000000000e+00
3.2000000000000e+00 0.0000000000000e+00 0.0000000000000e+00
0.0000000000000e+00 3.2000000000000e+00 0.0000000000000e+00
0.0000000000000e+00 0.0000000000000e+00 3.2000000000000e+00
Cs Cl
1 1
direct
0.0000000000000e+00 0.0000000000000e+00 0.0000000000000e+00
5.0000000000000e-01 5.0000000000000e-01 5.0000000000000e-01

Change parameters and repeat

[4]:
poscar = system.dump('poscar', header='Test POSCAR content for CsCl',
                    coordstyle='Cartesian', box_scale=3.2, float_format='%f')
print(poscar)
Test POSCAR content for CsCl
3.200000
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000
Cs Cl
1 1
Cartesian
0.000000 0.000000 0.000000
1.600000 1.600000 1.600000

3. atomman.load(‘poscar’)

POSCAR files can be read in to an atomman.System using atomman.load() with the POSCAR style.

Parameters

  • poscar (str or file-like object) The POSCAR content to read.

  • symbols (tuple, optional) Allows the list of element symbols to be assigned during loading. Useful if the symbols for the model differ from the standard element tags or if the poscar file has no elemental information.

  • prop (dict, optional) Dictionary containing any extra per-atom properties to include.

Returns

  • system (atomman.System) The system object associated with the data model.

Load the poscar generated above. Note that charge and stress are missing because POSCAR cannot represent them.

[5]:
# Load poscar and pass in prop dictionary
poscar_system = am.load('poscar', poscar)
print(poscar_system)
poscar_system.atoms_df()
avect =  [ 3.200,  0.000,  0.000]
bvect =  [ 0.000,  3.200,  0.000]
cvect =  [ 0.000,  0.000,  3.200]
origin = [ 0.000,  0.000,  0.000]
natoms = 2
natypes = 2
symbols = ('Cs', 'Cl')
pbc = [ True  True  True]
per-atom properties = ['atype', 'pos']
     id   atype  pos[0]  pos[1]  pos[2]
      0       1   0.000   0.000   0.000
      1       2   1.600   1.600   1.600
[5]:
atype pos[0] pos[1] pos[2]
0 1 0.0 0.0 0.0
1 2 1.6 1.6 1.6

If additional properties were stored elsewhere, they can be passed in during loading using the prop parameter

[6]:
# Define prop with charge and stress from the original system
prop = {}
prop['charge'] = system.atoms.charge
prop['stress'] = system.atoms.stress

# Load poscar and pass in prop dictionary
poscar_system = am.load('poscar', poscar, prop=prop)
print(poscar_system)
poscar_system.atoms_df()
avect =  [ 3.200,  0.000,  0.000]
bvect =  [ 0.000,  3.200,  0.000]
cvect =  [ 0.000,  0.000,  3.200]
origin = [ 0.000,  0.000,  0.000]
natoms = 2
natypes = 2
symbols = ('Cs', 'Cl')
pbc = [ True  True  True]
per-atom properties = ['atype', 'pos', 'charge', 'stress']
     id   atype  pos[0]  pos[1]  pos[2]
      0       1   0.000   0.000   0.000
      1       2   1.600   1.600   1.600
[6]:
atype pos[0] pos[1] pos[2] charge stress[0][0] stress[0][1] stress[0][2] stress[1][0] stress[1][1] stress[1][2] stress[2][0] stress[2][1] stress[2][2]
0 1 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1 2 1.6 1.6 1.6 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

Note: POSCAR files occasionally have additional flags and lines. Right now, these are ignored by atomman.

[7]:
poscar="""Test POSCAR with extra flags and lines
3.200000
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000
Cs Cl
1 1
Cartesian
0.000000 0.000000 0.000000 1 0 0
1.600000 1.600000 1.600000 1 0 0

extra data down here

"""
poscar_system = am.load('poscar', poscar)
print(poscar_system)
avect =  [ 3.200,  0.000,  0.000]
bvect =  [ 0.000,  3.200,  0.000]
cvect =  [ 0.000,  0.000,  3.200]
origin = [ 0.000,  0.000,  0.000]
natoms = 2
natypes = 2
symbols = ('Cs', 'Cl')
pbc = [ True  True  True]
per-atom properties = ['atype', 'pos']
     id   atype  pos[0]  pos[1]  pos[2]
      0       1   0.000   0.000   0.000
      1       2   1.600   1.600   1.600