Skip to content

Commit

Permalink
Merge pull request #32 from zhaojieincodes/dev
Browse files Browse the repository at this point in the history
读取预先提供的vasp/cif格式的slab结构文件
  • Loading branch information
wuyaos authored Apr 18, 2023
2 parents d22f1b7 + e9f1689 commit 2a94e51
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 54 deletions.
73 changes: 73 additions & 0 deletions example/yaml_read_struct/POSCARslab
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
Au C Cu H O
1.0000000000000000
11.7662568389441500 0.0000000000000000 0.0000000000000000
5.8831284194720741 10.1898773299780210 0.0000000000000000
0.0000000000000000 0.0000000000000000 23.2053313594865287
Au Cu
48 16
Selective dynamics
Direct
0.2500000000000001 -0.0000000000000000 0.3447483630406999 F F F
0.2499999999999999 0.7500000000000001 0.6552516369593001 T T T
0.7500000000000000 -0.0000000000000000 0.3447483630406999 F F F
0.5000000000000000 0.2500000000000001 0.3447483630406999 F F F
0.9166666666666667 0.1666666666666665 0.4482494543468999 F F F
0.9166666666666670 0.4166666666666664 0.4482494543468999 F F F
0.6666666666666669 0.4166666666666665 0.4482494543468999 F F F
0.5833333333333333 0.0833333333333332 0.5517505456531000 T T T
0.8333333333333333 0.0833333333333332 0.5517505456531000 T T T
0.5833333333333333 0.3333333333333334 0.5517505456531000 T T T
0.7500000000000000 0.0000000000000001 0.6552516369593001 T T T
0.5000000000000000 0.2500000000000001 0.6552516369593001 T T T
0.0000000000000000 0.7500000000000001 0.6552516369593001 T T T
0.7500000000000000 0.2500000000000001 0.6552516369593001 T T T
0.5000000000000001 0.7500000000000001 0.3447483630406999 F F F
0.7500000000000001 0.7500000000000001 0.3447483630406999 F F F
0.9166666666666667 0.6666666666666665 0.4482494543468999 F F F
0.9166666666666667 0.9166666666666665 0.4482494543468999 F F F
0.6666666666666669 0.9166666666666665 0.4482494543468999 F F F
0.5833333333333334 0.5833333333333331 0.5517505456531000 T T T
0.8333333333333335 0.5833333333333331 0.5517505456531000 T T T
0.5833333333333331 0.8333333333333335 0.5517505456531000 T T T
0.7499999999999998 0.5000000000000001 0.6552516369593001 T T T
0.5000000000000001 0.7500000000000001 0.6552516369593001 T T T
0.7499999999999998 0.7500000000000001 0.6552516369593001 T T T
0.7500000000000000 0.5000000000000000 0.3447483630406999 F F F
0.2499999999999999 0.5000000000000001 0.6552516369593001 T T T
0.7500000000000001 0.2500000000000001 0.3447483630406999 F F F
0.2500000000000001 0.7500000000000001 0.3447483630406999 F F F
0.1666666666666669 0.4166666666666665 0.4482494543468999 F F F
0.4166666666666669 0.4166666666666664 0.4482494543468999 F F F
0.0833333333333333 0.3333333333333334 0.5517505456531000 T T T
0.0833333333333333 0.8333333333333335 0.5517505456531000 T T T
0.2499999999999999 0.0000000000000001 0.6552516369593001 T T T
0.0000000000000000 0.2500000000000001 0.6552516369593001 T T T
0.2499999999999999 0.2500000000000001 0.6552516369593001 T T T
0.4166666666666667 0.1666666666666665 0.4482494543468999 F F F
0.2500000000000001 0.5000000000000000 0.3447483630406999 F F F
0.0000000000000000 0.7500000000000001 0.3447483630406999 F F F
0.0833333333333333 0.0833333333333332 0.5517505456531000 T T T
0.3333333333333334 0.0833333333333332 0.5517505456531000 T T T
0.4166666666666667 0.6666666666666665 0.4482494543468999 F F F
0.2500000000000001 0.2500000000000001 0.3447483630406999 F F F
0.0000000000000000 0.2500000000000001 0.3447483630406999 F F F
0.4166666666666667 0.9166666666666665 0.4482494543468999 F F F
0.1666666666666669 0.9166666666666665 0.4482494543468999 F F F
0.0833333333333333 0.5833333333333331 0.5517505456531000 T T T
0.3333333333333334 0.5833333333333331 0.5517505456531000 T T T
0.5000000000000000 0.5000000000000000 0.6552516369593001 T T T
0.8333333333333333 0.8333333333333333 0.5517505456531000 T T T
-0.0000000000000002 0.0000000000000001 0.3447483630406999 F F F
0.1666666666666668 0.1666666666666665 0.4482494543468999 F F F
0.0000000000000000 0.5000000000000000 0.6552516369593001 T T T
0.0000000000000000 0.0000000000000000 0.6552516369593001 T T T
0.4999999999999998 0.5000000000000001 0.3447483630406999 F F F
0.3333333333333333 0.3333333333333333 0.5517505456531000 T T T
0.5000000000000000 0.0000000000000000 0.6552516369593001 T T T
0.8333333333333331 0.3333333333333333 0.5517505456531000 T T T
-0.0000000000000002 0.5000000000000001 0.3447483630406999 F F F
0.1666666666666669 0.6666666666666665 0.4482494543468999 F F F
0.6666666666666669 0.1666666666666665 0.4482494543468999 F F F
0.4999999999999998 0.0000000000000001 0.3447483630406999 F F F
0.3333333333333334 0.8333333333333333 0.5517505456531000 T T T
0.6666666666666667 0.6666666666666665 0.4482494543468999 F F F
7 changes: 7 additions & 0 deletions example/yaml_read_struct/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
StrucInfo:
structfile: POSCARslab

Model:
SML: True
ads:
- ['C(=O)O',1]
44 changes: 25 additions & 19 deletions src/HTMACat/IO.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@author: YuxiaoLan
"""
from ruamel.yaml import YAML
from HTMACat.model.Substrate import substrate_from_input
from HTMACat.model.Substrate import substrate_from_input, substrate_from_file
from HTMACat.model.Ads import ads_from_input
from ase.io.vasp import write_vasp
from HTMACat.model.Structure import Structure
Expand All @@ -17,26 +17,32 @@ def Input(filename):

# A substrate is one facet with one dop element with on dop_type
struct_Info = result['StrucInfo']
struct_init_dict = {'element': struct_Info['element'],
'lattype': struct_Info['lattype'],
'latcont': struct_Info['latcont']}
dope_init_dict = {'element_dop': [], 'dop_type': []}
surface_init_dict = {'facet': []}
dope_system = struct_Info['dope']
dope_init_list = []
surface_init_list = []
for key, value in dope_system.items():
for i in value:
dope_init_list.append({'element_dop': key, 'dop_type': i})

for i in struct_Info['facet']:
surface_init_list.append({'facet': i})
try:
struct_filename = struct_Info['structfile']
except:
struct_filename = None
struct_init_dict = {'element': struct_Info['element'],
'lattype': struct_Info['lattype'],
'latcont': struct_Info['latcont']}
dope_init_dict = {'element_dop': [], 'dop_type': []}
surface_init_dict = {'facet': []}
dope_system = struct_Info['dope']
dope_init_list = []
surface_init_list = []
for key, value in dope_system.items():
for i in value:
dope_init_list.append({'element_dop': key, 'dop_type': i})
for i in struct_Info['facet']:
surface_init_list.append({'facet': i})
## substrates initialization
substrates = []
for i in range(len(dope_init_list)):
for j in range(len(surface_init_list)):
init_dict = {**struct_init_dict, **dope_init_list[i], **surface_init_list[j]}
substrates.append(substrate_from_input(init_dict))
if not struct_filename:
for i in range(len(dope_init_list)):
for j in range(len(surface_init_list)):
init_dict = {**struct_init_dict, **dope_init_list[i], **surface_init_list[j]}
substrates.append(substrate_from_input(init_dict))
else:
substrates.append(substrate_from_file(struct_filename))

## A adsorption is
ads_model = result['Model']
Expand Down
22 changes: 14 additions & 8 deletions src/HTMACat/model/Ads.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from HTMACat.model.Substrate import Slab
from catkit.gen.adsorption import AdsorptionSites
from HTMACat.model.Structure import Structure
import networkx.algorithms.isomorphism as iso

class Species(object):
def __init__(self, form, sml=False):
Expand All @@ -32,19 +33,23 @@ def out_print(self):

def MolToNXGraph(self, m):
"""
convert molecule object to graph in networkx
params:
m: RDKit Mol object
returns:
G: networkx Graph object of molecule m
Convert a molecule object to a graph.
Parameters
----------
m : mol
The RDKit molecule object to be converted into a networkx graph.
Returns
----------
G : Graph
The networkx Graph object derived from m.
"""
G = nx.Graph()
for i_n in range(m.GetNumAtoms()):
G.add_node(i_n)
G.add_nodes_from([(i_n, {'number':m.GetAtomWithIdx(i_n).GetAtomicNum()})])
bonds = [m.GetBondWithIdx(k) for k in range(len(m.GetBonds()))]
edges = []
for edge in bonds:
edges.append((edge.GetBeginAtomIdx(), edge.GetEndAtomIdx()))
edges.append((edge.GetBeginAtomIdx(),edge.GetEndAtomIdx()))
G.add_edges_from(edges)
return G

Expand All @@ -56,7 +61,8 @@ def get_molecule(self):
ads1_list = molecule(rdMolDescriptors.CalcMolFormula(mole))
ads_molecule = ads1_list[0]
for ads_ in ads1_list:
if nx.is_isomorphic(ads_._graph, G):
nm = iso.categorical_node_match('number', 6)
if nx.is_isomorphic(ads_._graph, G, node_match=nm):
ads_molecule = ads_
break
else:
Expand Down
113 changes: 86 additions & 27 deletions src/HTMACat/model/Substrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@

import math
from ase.build import bulk
from ase.io import read
from ase.constraints import FixAtoms
from catkit.gen.surface import SlabGenerator
from catkit.gen.adsorption import AdsorptionSites
from catkit.gratoms import Gratoms
import numpy as np
from HTMACat.model.Structure import Structure

Expand Down Expand Up @@ -98,13 +101,17 @@ def from_dict(cls, init_dict):


class Slab(Structure):
def __init__(self, in_bulk=Bulk(), facet='100'):
def __init__(self, in_bulk=Bulk(), facet='100', filename=None):
self.bulk = in_bulk
self.facet = facet
self.property = {}
if 'p1' not in self.property or 'p1_symb' not in self.property:
self.property['p1'] = []
self.property['p1_symb'] = []
if filename:
self.file = filename
else:
self.file = None
self.facet = facet
self.property = {}
if 'p1' not in self.property or 'p1_symb' not in self.property:
self.property['p1'] = []
self.property['p1_symb'] = []

def get_miller_index(self):
miller_index = tuple(list(map(int, list(self.facet))))
Expand All @@ -122,22 +129,28 @@ def get_facet(self):
return self.facet

def out_file_name(self):
mname = self.bulk.get_main_element()
if self.bulk.get_natom_dop() == '0':
return '_'.join([mname, self.facet])
if self.file:
return self.file
else:
ele_dop = self.bulk.get_dop_element()
natom_dop = self.bulk.get_natom_dop()
return '_'.join([mname, ele_dop, self.facet, natom_dop])
mname = self.bulk.get_main_element()
if self.bulk.get_natom_dop() == '0':
return '_'.join([mname, self.facet])
else:
ele_dop = self.bulk.get_dop_element()
natom_dop = self.bulk.get_natom_dop()
return '_'.join([mname, ele_dop, self.facet, natom_dop])

def out_print(self):
mname = self.bulk.get_main_element()
if self.bulk.get_natom_dop() == '0':
return '%s (%s) substrate' % (mname, self.facet)
if self.file:
return '%s substrate' % (self.file)
else:
ele_dop = self.bulk.get_dop_element()
natom_dop = self.bulk.get_natom_dop()
return '%s %s doped %s (%s) substrate' % (ele_dop, natom_dop, mname, self.facet)
mname = self.bulk.get_main_element()
if self.bulk.get_natom_dop() == '0':
return '%s (%s) substrate' % (mname, self.facet)
else:
ele_dop = self.bulk.get_dop_element()
natom_dop = self.bulk.get_natom_dop()
return '%s %s doped %s (%s) substrate' % (ele_dop, natom_dop, mname, self.facet)

def get_dis_inter(self):
latcon = self.bulk.lattice_constant
Expand All @@ -153,17 +166,55 @@ def get_dis_inter(self):
raise ValueError('Do not support facet: %s for generate inter distance' % self.facet)
return dis_inter

def find_topsurface_atoms(self, coords, tol_zdiff=0.7, tol_zangle_min=0): # (Last modified: 20230416, zjwang)
"""
Generate the list of surface atoms (top surface).
Parameters
----------
coords: array_like
Aoordinates of all atoms.
tol_zdiff: number
If the z_coord of an atom is higher than zmax-tol_zdiff, this atom is recognized as a "surface atom".
Returns
----------
index_topsurf: list
List of the indices of the surface atoms.
"""
index_topsurf = []
zmax = np.max(coords[:,2])
for i,icoord in enumerate(coords):
if icoord[2] > zmax - tol_zdiff:
index_topsurf.append(i)
return index_topsurf

def construct(self):
natom = self.bulk.get_natom_dop()
if natom == '0' or natom[0] == 'b':
slabs = self.Construct_slab()
elif natom == '1L':
slabs = self.Construct_1stLayer_slab()
elif natom.isdigit():
slabs = self.Construct_doped_slab()
if self.file:
try:
file_slab = read(self.file, format='vasp')
except:
file_slab = read(self.file, format='cif')
slab = Gratoms(positions=file_slab.positions,
numbers=file_slab.get_atomic_numbers(),
magmoms=file_slab.get_initial_magnetic_moments(),
cell=file_slab.cell,
pbc=[True, True, False])
topsurf_atoms = self.find_topsurface_atoms(coords=slab.positions)
bottomsurf_atoms = self.find_topsurface_atoms(coords=(-1)*slab.positions)
slab.set_surface_atoms(top=topsurf_atoms, bottom=bottomsurf_atoms)
c_fix = FixAtoms(indices=[atom.index for atom in slab if (not atom.index in topsurf_atoms) and (not atom.index in bottomsurf_atoms)])
slab.set_constraint(c_fix)
return [slab]
else:
raise ValueError('Do not support %s dop type to construct slab' % natom)
return slabs
natom = self.bulk.get_natom_dop()
if natom == '0' or natom[0] == 'b':
slabs = self.Construct_slab()
elif natom == '1L':
slabs = self.Construct_1stLayer_slab()
elif natom.isdigit():
slabs = self.Construct_doped_slab()
else:
raise ValueError('Do not support %s dop type to construct slab' % natom)
return slabs

def Construct_slab(self):
slab = []
Expand Down Expand Up @@ -241,8 +292,16 @@ def from_dict(cls, init_dict):
in_bulk = Bulk.from_dict(init_dict)
facet = init_dict['facet']
return cls(in_bulk, facet)

@classmethod
def from_file(cls, filename):
return cls(filename=filename)


def substrate_from_input(init_dict):
substrate = Slab.from_dict(init_dict)
return substrate

def substrate_from_file(filename):
substrate = Slab.from_file(filename)
return substrate

0 comments on commit 2a94e51

Please sign in to comment.