pymatgen icon indicating copy to clipboard operation
pymatgen copied to clipboard

Thickness of generated slab is smaller than min_slab_size

Open hezhengda opened this issue 2 years ago • 0 comments

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?

hezhengda avatar Oct 17 '23 11:10 hezhengda