pymatgen
pymatgen copied to clipboard
Thickness of generated slab is smaller than min_slab_size
Bug Description
When using generate_all_slabs to generate surfaces by primitive=True, I have found some surfaces will have thickness smaller than the min_slab_size value.
Reproduce the bug
from pymatgen.core.surface import generate_all_slabs
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from pymatgen.core import Structure
bulk_structure = Structure.from_file('TiNb_conv.cif') # I attach this as `TiNb_conv.cif`
sga = SpacegroupAnalyzer(bulk_structure)
conv_structure = sga.get_conventional_standard_structure()
slabs = generate_all_slabs(structure=conv_structure,
max_index=2,
min_slab_size=8,
min_vacuum_size=15,
center_slab=True,
primitive=True)
The slab thickness of TiNb(111) surface is 7.06Å, which is less than min_slab_size, which is 8Å.
Slab thickness is calculated by the maximal distance of z-component of cartesian coordinates:
coords = structure.cart_coords
sorted_coords = sorted(coords, key=lambda x: x[2])
thickness = sorted_coords[-1][2] - sorted_coords[0][2]
Since cif file cannot be uploaded, I paste the cif file (TiNb_conv.cif, conventional cell of TiNb) in the following:
# generated using pymatgen
data_TiNb
_symmetry_space_group_name_H-M 'P 1'
_cell_length_a 3.28200886
_cell_length_b 4.63609090
_cell_length_c 4.64594597
_cell_angle_alpha 90.00000000
_cell_angle_beta 90.00000000
_cell_angle_gamma 90.00000000
_symmetry_Int_Tables_number 1
_chemical_formula_structural TiNb
_chemical_formula_sum 'Ti2 Nb2'
_cell_volume 70.69128019
_cell_formula_units_Z 2
loop_
_symmetry_equiv_pos_site_id
_symmetry_equiv_pos_as_xyz
1 'x, y, z'
loop_
_atom_site_type_symbol
_atom_site_label
_atom_site_symmetry_multiplicity
_atom_site_fract_x
_atom_site_fract_y
_atom_site_fract_z
_atom_site_occupancy
Ti Ti0 1 0.50000000 0.00000000 0.50000000 1.0
Ti Ti1 1 0.00000000 0.50000000 0.50000000 1.0
Nb Nb2 1 0.00000000 0.00000000 0.00000000 1.0
Nb Nb3 1 0.50000000 0.50000000 0.00000000 1.0
Try to pin point the bug
I have done some digging myself. It seems to me the problem lies in the following code of get_slab() function:
if self.primitive:
prim = slab.get_primitive_structure(tolerance=tol)
if energy is not None:
energy = prim.volume / slab.volume * energy
slab = prim
I have checked the lattice constant and fractional coordinates before and after the get_primitive_structure(), it seems the third component of the coordinates don't change.
Here's the lattice constant and fractional coordinates before get_primitive_structure():
lattice matrix of slab before primitive
-3.28, 4.64, 0.00
-3.28, 0.00, 4.65
36.10, 0.00, 0.00
fractional coordinates of slab before primitive
0.00, 0.50, 0.36
0.50, 0.50, 0.36
0.00, 0.00, 0.36
0.50, 0.00, 0.36
0.00, 0.50, 0.45
0.50, 0.50, 0.45
0.00, 0.00, 0.45
0.50, 0.00, 0.45
0.00, 0.50, 0.55
0.50, 0.50, 0.55
0.00, 0.00, 0.55
0.50, 0.00, 0.55
0.00, 0.50, 0.64
0.50, 0.50, 0.64
0.00, 0.00, 0.64
0.50, 0.00, 0.64
Here's the lattice constant and fractional coordinates after get_primitive_structure():
lattice matrix of slab after primitive
-1.64, 2.32, 0.00
1.64, 2.32, -4.65
-18.05, -11.59, -13.94
fractional coordinates of slab after primitive
0.91, 0.91, 0.36
0.41, 0.41, 0.36
0.14, 0.14, 0.45
0.64, 0.64, 0.45
0.36, 0.36, 0.55
0.86, 0.86, 0.55
0.09, 0.09, 0.64
0.59, 0.59, 0.64
As you can see although the lattice matrix has been changed, the third component of the fractional coordinates don't change. This could cause the thickness of the generated slab to be smaller than min_slab_size. Is that an issue?