def create_interface(self): """ add params that you want to vary """ structure = self.input_structure.copy() iface = Interface(structure, hkl=self.system['hkl'], ligand=Ligand.from_dict(self.system['ligand']), from_ase=self.from_ase) iface.sort() sd = self.set_sd_flags(iface, n_layers=2) # if there are other paramters that are being varied # change the comment accordingly comment = self.system['hkl'] + self.system['ligand']['name'] return Poscar(iface, comment=comment, selective_dynamics=sd)
def create_interface(self): """ add params that you want to vary """ structure = self.input_structure.copy() iface = Interface(structure, hkl=self.system['hkl'], ligand = Ligand.from_dict(self.system['ligand']), from_ase=self.from_ase) iface.sort() sd = self.set_sd_flags(iface, n_layers=2) #if there are other paramters that are being varied #change the comment accordingly comment = self.system['hkl']+self.system['ligand']['name'] return Poscar(iface, comment=comment, selective_dynamics=sd)
def upload_file(): stamp = "" if request.method == 'POST': #request.environ['REMOTE_ADDR'] if request.environ.get('HTTP_X_FORWARDED_FOR') is None: ip = request.environ['REMOTE_ADDR'] else: ip = request.environ['HTTP_X_FORWARDED_FOR'] # if behind a proxy #substrate information# f1 = request.files['POSCAR_sub'] stamp = time.strftime("%Y%m%d-%H%M%S") + '-' + ip poscar_sub = stamp + '-' + f1.filename f1.save(upload_dir + os.sep + secure_filename(poscar_sub)) h_sub = int(request.form["h_sub"]) k_sub = int(request.form["k_sub"]) l_sub = int(request.form["l_sub"]) nlayers_substrate = int(request.form["nlayers_substrate"]) min_thick_sub = float(request.form["min_thick_sub"]) min_vac_sub = float(request.form["min_vac_sub"]) #is_primitive = request.form.get["is_primitive"] hkl_sub = [h_sub, k_sub, l_sub] #2d information# f2 = request.files['POSCAR_2d'] poscar_2d = stamp + '-' + f2.filename f2.save(upload_dir + os.sep + secure_filename(poscar_2d)) h_2d = int(request.form["h_2d"]) k_2d = int(request.form["k_2d"]) l_2d = int(request.form["l_2d"]) nlayers_2d = int(request.form["nlayers_2d"]) hkl_2d = [h_2d, k_2d, l_2d] #General information# separation = float(request.form["separation"]) max_area = float(request.form["max_area"]) max_mismatch = float(request.form["max_mismatch"]) max_angle_diff = float(request.form["max_angle_diff"]) #Matching# try: substrate_bulk = pymatgen.Structure.from_file(upload_dir + os.sep + poscar_sub) sa_sub = pymatgen.symmetry.analyzer.SpacegroupAnalyzer( substrate_bulk) substrate_bulk = sa_sub.get_conventional_standard_structure() substrate_slab = Interface(substrate_bulk, hkl=hkl_sub, min_thick=min_thick_sub, min_vac=min_vac_sub, primitive=False, from_ase=True) mat2d_slab = utils.slab_from_file(hkl_2d, upload_dir + os.sep + poscar_2d) operation_dir = "static" + os.sep + "operations" + os.sep + stamp if not os.path.exists(operation_dir): os.makedirs(operation_dir) mat2d_slab.to(fmt="poscar", filename=operation_dir + "POSCAR_mat2d_slab.vasp") sd_flags = CalibrateSlab.set_sd_flags(interface=substrate_slab, n_layers=nlayers_substrate, top=True, bottom=False) poscar = pymatgen.io.vasp.inputs.Poscar( substrate_slab, selective_dynamics=sd_flags) poscar.write_file(filename=operation_dir + os.sep + "POSCAR_substrate_slab.vasp") substrate_slab_aligned, mat2d_slab_aligned, mismatch = transformations.get_aligned_lattices( substrate_slab, mat2d_slab, max_area=max_area, max_mismatch=max_mismatch, max_angle_diff=max_angle_diff, r1r2_tol=0.01) substrate_slab_aligned.to(fmt="poscar", filename=operation_dir + os.sep + "POSCAR_substrate_aligned.vasp") mat2d_slab_aligned.to(fmt="poscar", filename=operation_dir + os.sep + "POSCAR_mat2d_aligned.vasp") hetero_interfaces = transformations.generate_all_configs( mat2d_slab_aligned, substrate_slab_aligned, nlayers_2d, nlayers_substrate, separation) for i, iface in enumerate(hetero_interfaces): sd_flags = CalibrateSlab.set_sd_flags(interface=iface, n_layers=nlayers_2d + nlayers_substrate, top=True, bottom=False) poscar = pymatgen.io.vasp.inputs.Poscar( iface, selective_dynamics=sd_flags) poscar.write_file(filename=operation_dir + os.sep + 'POSCAR_final_{}.vasp'.format(i)) p = Poscar.from_file(operation_dir + os.sep + 'POSCAR_final_{}.vasp'.format(i)) w = CifWriter(p.structure) w.write_file(operation_dir + os.sep + 'POSCAR_final_{}.cif'.format(i)) # st = pychemia.code.vasp.read_poscar(operation_dir+os.sep+'POSCAR_final_{}.vasp'.format(i)) #rf = open("testing") #rf.write("reading succesful") #rf.close() # pychemia.io.cif.save(structure=st,filename=operation_dir+os.sep+'POSCAR_final_{}.xyz'.format(i)) except: #redirect(url_for("error",_id="matching",stamp=stamp)) return ("Error") return redirect(url_for('result', stamp=stamp)) return render_template("matching.html", _id="matching", test_var="test", stamp=stamp)
# slab thickness and vacuum set manual for now to converged values, surface coverage fixed at 0.014 ligand/sq.Angstrom #for consistency, best ligand spacing at the coverage min_thick= 19 min_vac= 12 surface_coverage= 0.014 #hkl of facet to reproduce hkl= [1,0,0] # specify the species on slab to adsorb over slab_species= 'Pb' # specify the species onb ligand serving as the bridge atom adatom_on_ligand= 'O' #initial adsorption distance in angstrom ads_distance = 3.0 # create the interface iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=surface_coverage, ligand=DMF, displacement=ads_distance, adatom_on_lig= adatom_on_ligand, adsorb_on_species= slab_species, primitive= True) iface.create_interface() iface.sort() #separate slab iface_slab = iface.slab iface_slab.sort() #set selective dynamics flags as required true_site= [1, 1, 1] false_site= [0, 0, 0] sd_flag_iface= [] j= 0 sd_flag_slab= [] for i in iface.sites: sd_flag_iface.append(false_site) for i in iface_slab.sites:
# firework 4 firetask1: convergence of thickness and vacuum slab_firetasks = [] slab_fireworks = [] #NOTE: This should be the CONTCAR file under the directory BulkRelax/CONTCAR #for testing purposes this is the same bulk structure pulled from matproj slab = Interface(bulk, hkl=[1, 0, 0], min_thick=10, min_vac=10, supercell=[1, 1, 1], name=None, adsorb_on_species='Pb', adatom_on_lig='O', ligand=None, displacement=3.0, surface_coverage=0.01, scell_nmax=10, coverage_tol=0.25, solvent="amine", start_from_slab=False, validate_proximity=False, to_unit_cell=False, coords_are_cartesian=False, primitive=True, from_ase=True, x_shift=0, y_shift=0) slab_firetasks.append(get_calibration_task(structure=slab, \ turn_knobs={'VACUUM':[400,500,600], 'THICKNESS':range(5,20)}))
mol = Molecule(mol_struct.species, mol_struct.cart_coords) hydrazine = Ligand([mol]) supercell = [1, 1, 1] hkl = [1, 1, 1] min_thick = 10 min_vac = 12 surface_coverage = 0.01 adsorb_on_species = 'S' adatom_on_lig = 'Pb' displacement = 3.0 iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=0.01, ligand=hydrazine, displacement=displacement, adatom_on_lig=adatom_on_lig, adsorb_on_species=adsorb_on_species, primitive=False, coverage_tol=0.5) iface.create_interface() iface.sort() incarparams = { 'System': 'test', 'ENCUT': 400, 'ISMEAR': 1, 'SIGMA': 0.1, 'EDIFF': 1E-6 }
adatom_on_lig = 'N' # ligand displacement from the slab surface along the surface normal # i.e adatom_on_lig will be displced by this amount from the # adsorb_on_species atom # on the slab # in Angstrom displacement = 3.0 # here we create the interface iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=0.01, ligand=hydrazine, displacement=displacement, adatom_on_lig='N', adsorb_on_species='Pb', primitive=False) iface.create_interface() iface.sort() # extract bare slab iface_slab = iface.slab iface_slab.sort() # set selective dynamics flags as required true_site = [1, 1, 1] false_site = [0, 0, 0] sd_flag_iface = [] sd_flag_slab = []
#atom on ligand that will be attached to the slab surface adatom_on_lig='N' #ligand displacement from the slab surface along the surface normal #i.e adatom_on_lig will be displced by this amount from the #adsorb_on_species atom #on the slab #in Angstrom displacement = 3.0 #here we create the adsorbate slab Interface iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=surface_coverage, ligand=hydrazine, displacement=displacement, adatom_on_lig=adatom_on_lig, adsorb_on_species= adsorb_on_species, primitive= False, from_ase=True) iface.create_interface() iface.sort() energy=iface.calc_energy() iface.to('poscar','POSCAR_interface.vasp') interfaces= coloumb_configured_interface(iface, random=True, translations= None, rotations=None, samples=20, lowest=5, ecut=energy) for i, iface in enumerate(interfaces): print ("Coloumb Energy") print (i, iface[0])
def coloumb_configured_interface(iface, random=True, translations=None, rotations=None, samples=10, lowest=5, ecut=None): """ Creates Ligand Slab interfaces of user specified translations and rotations away from the initial guess of binding site configuration, returns lowest energy structure according to Coulomb model Args: Interface: Interface object: initial interface object random: True for using Gaussian sampled random numbers for rotations and translations translations: list of [x,y,z] translations to be performed rotation: list of [a,b,c] rotations to be performed w.r.t Ligand axis samples: number of interfaces to create lowest: number of structures to return according to order of minimum energies Returns: list of lowest energy interface objects """ ifaces = [] transform = [] for i in range(samples): if random: x = np.random.normal() # shift along x direction y = np.random.normal() # shift along y direction z = np.random.normal() # shift aling z direction a = SymmOp.from_axis_angle_and_translation(axis=[1, 0, 0], \ angle=np.random.normal(0, 180)) b = SymmOp.from_axis_angle_and_translation(axis=[0, 1, 0], \ angle=np.random.normal(0, 180)) c = SymmOp.from_axis_angle_and_translation(axis=[0, 0, 1], \ angle=np.random.normal(0, 180)) ligand = iface.ligand ligand.apply_operation(a) ligand.apply_operation(b) ligand.apply_operation(c) # check if created interface maintains the ligand adsorbed # over the surface for j in iface.top_atoms: if not iface.cart_coords[j][2] + iface.displacement > \ min(ligand.cart_coords[:, 2]): transform.append(True) if all(transform): iface = Interface(iface.strt, hkl=iface.hkl, min_thick=iface.min_thick, min_vac=iface.min_vac, supercell=iface.supercell, surface_coverage=iface.surface_coverage, ligand=iface.ligand, displacement=z, adatom_on_lig=iface.adatom_on_lig, adsorb_on_species=iface.adsorb_on_species, primitive=False, from_ase=True, x_shift=x, y_shift=y) iface.create_interface() energy = iface.calc_energy() iface.sort() if energy < ecut: ifaces.append((energy, iface)) # ifaces.zip(energy, iface) return ifaces
import sys from pymatgen.core import Structure from pymatgen.io.vasp.inputs import Poscar from mpinterfaces.interface import Interface if __name__=='__main__': # input structure file: bulk fin = 'POSCAR.bulk' # output file name fout = 'POSCAR' hkl = [0,0,1] # hkl wrt the input structure min_thick = 15 # angstroms min_vac = 30 # angstroms #use ase to create an orthogonal slab bulk = Structure.from_file(fin) iface = Interface(bulk, hkl=hkl, min_thick=min_thick, min_vac=min_vac, primitive= False, from_ase = True) iface.create_interface() iface.sort() #set selective dynamics flags # 1 --> T and 0 --> F sd_flags = [[1,1,1] for i in iface.sites] iface_poscar = Poscar(iface, selective_dynamics= sd_flags) #write to file iface_poscar.write_file(fout)
workflows.append(get_workflow(lig_fireworks, name='Ligand')) ####################################################################################### ################# THIRD WORKFLOW: SLAB Convergence ##################################### # construct slab from relaxation firework CONTCAR of firework 2 # firework 4 firetask1: convergence of thickness and vacuum slab_firetasks = [] slab_fireworks = [] #NOTE: This should be the CONTCAR file under the directory BulkRelax/CONTCAR #for testing purposes this is the same bulk structure pulled from matproj slab = Interface(bulk, hkl=[1,0,0], min_thick=10, min_vac=10, supercell=[1,1,1], name=None, adsorb_on_species='Pb', adatom_on_lig='O', ligand=None, displacement=3.0, surface_coverage=0.01, scell_nmax=10, coverage_tol=0.25, solvent="amine", start_from_slab=False, validate_proximity=False, to_unit_cell=False, coords_are_cartesian=False, primitive = True, from_ase=True, x_shift= 0, y_shift= 0) slab_firetasks.append(get_calibration_task(structure=slab, \ turn_knobs={'VACUUM':[400,500,600], 'THICKNESS':range(5,20)})) slab_fireworks.append(Firework(slab_firetasks[0], name='slab_convergence')) workflows.append(get_workflow(slab_fireworks, name='Slab')) #########################################################################################
# atom on ligand that will be attached to the slab surface adatom_on_lig = 'N' # ligand displacement from the slab surface along the surface normal # i.e adatom_on_lig will be displced by this amount from the # adsorb_on_species atom # on the slab # in Angstrom displacement = 3.0 # here we create the adsorbate slab Interface iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=surface_coverage, ligand=hydrazine, displacement=displacement, adatom_on_lig=adatom_on_lig, adsorb_on_species=adsorb_on_species, primitive=False, from_ase=True) iface.create_interface() iface.sort() energy = iface.calc_energy() iface.to('poscar', 'POSCAR_interface.vasp') interfaces = coloumb_configured_interface(iface, random=True, translations=None, rotations=None, samples=20, lowest=5, ecut=energy) for i, iface in enumerate(interfaces): print("Coloumb Energy") print(i, iface[0])
substrate_bulk = Structure.from_file(bulk_filename) analyzer = SpacegroupAnalyzer(substrate_bulk) substrate_bulk_conv = analyzer.get_conventional_standard_structure() writer = CifWriter(substrate_bulk_conv) writer.write_file("conv_" + bulk_filename) #| - Loop over all surface surface_cuts for surface_cut in surface_cuts: substrate_slab = Interface( substrate_bulk_conv, hkl=surface_cut, min_thick=10, min_vac=25, primitive=False, from_ase=True, ) if strain_sys == "support": lower_mat = mat2d_slab upper_mat = substrate_slab elif strain_sys == "overlayer": lower_mat = substrate_slab upper_mat = mat2d_slab # mat2d_slab_aligned, substrate_slab_aligned = get_aligned_lattices( lower_mat_aligned, upper_mat_aligned = get_aligned_lattices( lower_mat, upper_mat,
substrate_bulk = Structure.from_file('POSCAR.mp-2534_GaAs') mat2d_bulk = Structure.from_file('POSCAR.mp-406_CdTe') # initialize the substrate and 2d material slabs, constructed # from the respective bulk unit cells # notes: # ase backend used to ensure that the generated slabs have # orthogonal z axis # 2d material vacuum spacing = 0 # keep in mind that the 2d material will be put on top of # the subtrate in the substrate's vacuum space. # So ensure that the substrate vacuum spacing is sufficietly # large enough to contain the 2d material substrate = Interface(substrate_bulk, hkl = [1,1,0], min_thick = 10, min_vac = 25, primitive = False, from_ase = True) mat2d = Interface(mat2d_bulk, hkl = [1,1,0], min_thick = 2, min_vac = 0, primitive = False, from_ase = True) substrate.to(fmt='poscar', filename='POSCAR_substrate_initial.vasp') mat2d.to(fmt='poscar', filename='POSCAR_mat2d_initial.vasp') # get the matching substrate and 2D material lattices uv_substrate, uv_mat2d = get_matching_lattices(substrate, mat2d, max_area = 200, max_mismatch = 0.01, max_angle_diff = 1,
def coloumb_configured_interface(iface, random=True, translations= None, rotations=None, samples=10, lowest=5, ecut=None): """ Creates Ligand Slab interfaces of user specified translations and rotations away from the initial guess of binding site configuration, returns lowest energy structure according to Coulomb model Args: Interface: Interface object: initial interface object random: True for using Gaussian sampled random numbers for rotations and translations translations: list of [x,y,z] translations to be performed rotation: list of [a,b,c] rotations to be performed w.r.t Ligand axis samples: number of interfaces to create lowest: number of structures to return according to order of minimum energies Returns: list of lowest energy interface objects """ ifaces= [] transform= [] for i in range(samples): if random: x = np.random.normal() # shift along x direction y = np.random.normal() # shift along y direction z = np.random.normal() # shift aling z direction a= SymmOp.from_axis_angle_and_translation(axis=[1,0,0],\ angle=np.random.normal(0,180)) b= SymmOp.from_axis_angle_and_translation(axis=[0,1,0],\ angle=np.random.normal(0,180)) c= SymmOp.from_axis_angle_and_translation(axis=[0,0,1],\ angle=np.random.normal(0,180)) ligand=iface.ligand ligand.apply_operation(a) ligand.apply_operation(b) ligand.apply_operation(c) # check if created interface maintains the ligand adsorbed # over the surface for j in iface.top_atoms: if not iface.cart_coords[j][2] + iface.displacement > \ min(ligand.cart_coords[:,2]): transform.append(True) if all(transform): iface= Interface(iface.strt, hkl=iface.hkl, min_thick=iface.min_thick, min_vac=iface.min_vac, supercell=iface.supercell, surface_coverage=iface.surface_coverage, ligand=iface.ligand, displacement=z, adatom_on_lig=iface.adatom_on_lig, adsorb_on_species=iface.adsorb_on_species, primitive= False, from_ase=True, x_shift=x, y_shift=y) iface.create_interface() energy= iface.calc_energy() iface.sort() if energy<ecut: ifaces.append((energy,iface)) # ifaces.zip(energy, iface) return ifaces
def get_entry(args): # return -1 ran with an error # return 0 ran with no error # return 1 match was not found # return 2 skiped because radioactive # return 3 skipped because noble gas # return 4 skipped because atomic number greater than 83 _id = args[0] counter = args[1] mat2d_slab = args[2] if counter % 1000 ==0 : print("Reached entry number {}".format(counter)) radioactive_elemets = ["U","Ra","Th","Rn","Po","Pu","Tc","Np","Fr","Cm","Pm","Hs","Re"] noble_gases = ["He","Ne","Ar","Kr","Xe","Rn"] client = pymongo.MongoClient() entries = client.PyChemiaDB_OQMD12.pychemia_entries entry = entries.find_one({'_id':_id}) if len(entry['init_structure']) != 0 : st_dict = entry['init_structure'] elif len(entry['structure']) !=0 : st_dict = entry['structure'] else : print("Structure {} was not found".format(_id)) return -1 substrate_bulk = pymatgen.core.Structure(lattice=st_dict["cell"], species=st_dict['symbols'],coords=st_dict['positions'],coords_are_cartesian=True) for element in substrate_bulk.symbol_set : if element in radioactive_elemets : return 2 elif element in noble_gases : return 3 elif pymatgen.core.Element(element).number > 83 : return 4 sa_sub = pymatgen.symmetry.analyzer.SpacegroupAnalyzer(substrate_bulk) try : substrate_bulk = sa_sub.get_conventional_standard_structure() except : return -1 spg = sa_sub.get_space_group_number() directions = [ [1,0,0],[0,1,0],[0,0,1], [1,1,0],[0,1,1],[1,0,1], [1,1,1]] formula = substrate_bulk.composition.hill_formula data = {} data[formula] = {} data[formula]["space_group_pymatgen"] = spg data[formula]["space_group_oqmd"] = entry['properties']['oqmd']['spacegroup_number'] data[formula]["_id"] = _id found_one = False for direction in directions : data[formula][str(direction)] = {} substrate_slab = Interface(substrate_bulk, hkl=direction, min_thick=10, min_vac=15, primitive=False, from_ase=True) try : substrate_slab_aligned, mat2d_slab_aligned,mismatch = transformations.get_aligned_lattices(substrate_slab, mat2d_slab , max_area = 20 , max_mismatch = 0.05, max_angle_diff = 1, r1r2_tol = 0.01) except : print("Except error Matching {} ,id : {}".format(formula,_id)) continue if substrate_slab_aligned == None or mat2d_slab_aligned == None : continue else : data[formula][str(direction)]["mismatch"] = mismatch if any(mismatch) : found_one = True if found_one : wf = open("results"+os.sep+str(spg)+'-'+_id+".json",'w') json.dump(data,wf,sort_keys=True,indent=4,separators=(',',': ')) wf.close() return 0 else : return 1
strt = Structure.from_file("POSCAR.mp-21276_PbS") mol_struct = Structure.from_file("POSCAR_diacetate") mol = Molecule(mol_struct.species, mol_struct.cart_coords) hydrazine = Ligand([mol]) supercell = [1, 1, 1] hkl = [1, 1, 1] min_thick = 10 min_vac = 12 surface_coverage = 0.01 adsorb_on_species = 'S' adatom_on_lig = 'Pb' displacement = 3.0 iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=0.01, ligand=hydrazine, displacement=displacement, adatom_on_lig=adatom_on_lig, adsorb_on_species=adsorb_on_species, primitive=False, coverage_tol=0.5) iface.create_interface() iface.sort() incarparams = {'System': 'test', 'ENCUT': 400, 'ISMEAR': 1, 'SIGMA': 0.1, 'EDIFF': 1E-6} incar = Incar(params=incarparams) poscar = Poscar(iface) potcar = Potcar(symbols=poscar.site_symbols, functional='PBE', sym_potcar_map=None)
def get_grain_boundary_interface(structure=None, hkl_pair= {'hkl': [[1,0,0],[1,1,0]],\ 'thickness':[10,10]}, twist = 0, tilt = 0, separation=0): """ Args: structure: pymatgen structure to create grain boundary in hkl_pair: dict of {'hkl':thickness} twist: twist in degrees tilt: tilt in degrees """ structure = get_struct_from_mp(structure, MAPI_KEY="") sa = SpacegroupAnalyzer(structure) structure_conventional = sa.get_conventional_standard_structure() structure = structure_conventional.copy() structure.sort() #creation of lower part of grain boundary lower= Interface(structure,\ hkl = hkl_pair['hkl'][0], min_thick = hkl_pair['thickness'][0], min_vac = separation+hkl_pair['thickness'][1], primitive = False, from_ase = True, center_slab=False) lower.to(fmt="poscar", filename="POSCAR_lower.vasp") #creation of upper part of grain boundary upper= Interface(structure,\ hkl = hkl_pair['hkl'][1], min_thick = hkl_pair['thickness'][1], min_vac = 0, primitive = False, from_ase = True) #find top atoms reference of lower part of gb substrate_top_z = np.max(np.array([site.coords for site in lower])[:, 2]) # define twist and tilt vectors twist_shift_normal = lower.lattice.matrix[2,:]/\ np.linalg.norm(lower.lattice.matrix[2,:]) tilt_normal = upper.lattice.matrix[1,:]/\ np.linalg.norm(upper.lattice.matrix[2,:]) #define twist operation SymmOp object twist_op = SymmOp.from_axis_angle_and_translation(axis= twist_shift_normal,\ angle=twist, angle_in_radians=False,translation_vec=(0, 0, 0)) #define tilt operation SymmOp object tilt_op = SymmOp.from_axis_angle_and_translation(axis= tilt_normal,\ angle=tilt, angle_in_radians=False,translation_vec=(0, 0, 0)) upper.apply_operation(twist_op) upper.to(fmt="poscar", filename="POSCAR_upper.vasp") upper.apply_operation(tilt_op) #define shift separation along twist vector normal to upper plane shift = -1 * twist_shift_normal / np.linalg.norm( twist_shift_normal) * separation #define origin to shift w.r.t top of the lower grain origin = np.array([0, 0, substrate_top_z]) #shift sites in upper for site in upper: new_coords = site.coords - origin + shift lower.append(site.specie, new_coords, coords_are_cartesian=True) return lower
from mpinterfaces import get_struct_from_mp from mpinterfaces.interface import Interface from mpinterfaces.transformations import * from mpinterfaces.utils import * seperation = 3 # in angstroms nlayers_2d = 2 nlayers_substrate = 2 substrate_bulk = Structure.from_file('POSCAR_substrate') #substrate_bulk = get_struct_from_mp('Ag') sa_sub = SpacegroupAnalyzer(substrate_bulk) substrate_bulk = sa_sub.get_conventional_standard_structure() substrate_slab = Interface(substrate_bulk, hkl=[1, 1, 1], min_thick=10, min_vac=25, primitive=False, from_ase=True) #substrate_slab = slab_from_file([0,0,1], 'POSCAR_substrate') mat2d_slab = slab_from_file([0, 0, 1], 'POSCAR_2D') # get the in-plane lattice aligned slabs #substrate_slab.to(fmt='poscar', filename='POSCAR_substrate_slab.vasp') mat2d_slab.to(fmt='poscar', filename='POSCAR_mat2d_slab.vasp') # selective dynamics flag sd_flags = CalibrateSlab.set_sd_flags(interface=substrate_slab, n_layers=nlayers_substrate, top=True, bottom=False) poscar = Poscar(substrate_slab, selective_dynamics=sd_flags) poscar.write_file(filename='POSCAR_substrate_slab.vasp') # get aligned lattices
from pymatgen.core import Structure from pymatgen.io.vasp.inputs import Poscar from mpinterfaces.interface import Interface if __name__ == '__main__': # input structure file: bulk fin = 'POSCAR.bulk' # output file name fout = 'POSCAR' hkl = [0, 0, 1] # hkl wrt the input structure min_thick = 15 # angstroms min_vac = 30 # angstroms # use ase to create an orthogonal slab bulk = Structure.from_file(fin) iface = Interface(bulk, hkl=hkl, min_thick=min_thick, min_vac=min_vac, primitive=False, from_ase=True) iface.create_interface() iface.sort() # set selective dynamics flags # 1 --> T and 0 --> F sd_flags = [[1, 1, 1] for i in iface.sites] iface_poscar = Poscar(iface, selective_dynamics=sd_flags) # write to file iface_poscar.write_file(fout)
for direction in data[key]: if ('_' not in direction) and (len(data[key][direction]) != 0): directions.append(json.loads(direction)) dir_name = "matched_poscars" + os.sep + str(spg) + '-' + _id if not os.path.exists(dir_name): os.mkdir(dir_name) substrate_bulk.to(fmt='poscar', filename=dir_name + os.sep + item.replace('json', 'vasp')) for direction in directions: address = dir_name + os.sep + str(direction) if not os.path.exists(address): os.mkdir(address) substrate_slab = Interface(substrate_bulk, hkl=direction, min_thick=10, min_vac=15, primitive=False, from_ase=True) sd_flags = CalibrateSlab.set_sd_flags(interface=substrate_slab, n_layers=nlayers_substrate, top=True, bottom=False) substrate_slab_aligned, mat2d_slab_aligned, mismatch = transformations.get_aligned_lattices( substrate_slab, mat2d_slab, max_area=40, max_mismatch=0.05, max_angle_diff=20, r1r2_tol=0.01) substrate_slab_aligned.to(fmt='poscar',
substrate_bulk = Structure.from_file('POSCAR.mp-2534_GaAs') mat2d_bulk = Structure.from_file('POSCAR.mp-406_CdTe') # initialize the substrate and 2d material slabs, constructed # from the respective bulk unit cells # notes: # ase backend used to ensure that the generated slabs have # orthogonal z axis # 2d material vacuum spacing = 0 # keep in mind that the 2d material will be put on top of # the subtrate in the substrate's vacuum space. # So ensure that the substrate vacuum spacing is sufficietly # large enough to contain the 2d material substrate = Interface(substrate_bulk, hkl=[1, 1, 0], min_thick=10, min_vac=25, primitive=False, from_ase=True) mat2d = Interface(mat2d_bulk, hkl=[1, 1, 0], min_thick=2, min_vac=0, primitive=False, from_ase=True) substrate.to(fmt='poscar', filename='POSCAR_substrate_initial.vasp') mat2d.to(fmt='poscar', filename='POSCAR_mat2d_initial.vasp') # get the matching substrate and 2D material lattices uv_substrate, uv_mat2d = get_matching_lattices(substrate, mat2d, max_area=200,
from mpinterfaces.interface import Interface from mpinterfaces.utils import get_run_cmmnd MAPI_KEY = os.environ.get("MAPI_KEY", "") # get structure from materialsproject, use your own key strt = get_struct_from_mp('PbS', MAPI_KEY=MAPI_KEY) # convert from fcc primitive to conventional cell # the conventional unit cell is used to create the slab # this is important becasue the hkl specification for the required slab # is wrt the provided unit cell sa = SpacegroupAnalyzer(strt) structure_conventional = sa.get_conventional_standard_structure() strt = structure_conventional.copy() # create slab iface = Interface(strt, hkl=[1, 1, 1], min_thick=10, min_vac=10, supercell=[1, 1, 1]) # sort structure into groups of elements atoms for Potcar mapping iface.sort() # vasp input incar_dict = { 'SYSTEM': 'test', 'ENCUT': 500, 'ISIF': 2, 'IBRION': 2, 'ISMEAR': 1, 'EDIFF': 1e-06, 'NPAR': 8, 'SIGMA': 0.1, 'NSW': 100, 'PREC': 'Accurate'
def create_heterostructure( bulk_structure=None, slab_structure=None, strain_sys="overlayer", # 'support' or 'overlayer' surface_cut=[0, 0, 1], separation=3, nlayers_2d=1, nlayers_substrate=4, # Lattice matching algorithm parameters max_area=40, max_mismatch=1, max_angle_diff=0.1, r1r2_tol=0.01, ): """ bulk_structure: ase atoms object for the support material slab_structure: overlayer material strain_sys: surface_cut: separation: nlayers_2d: nlayers_substrate: max_area: max_mismatch: max_angle_diff: r1r2_tol: """ #| - create_heterostructure #| - Generate Heterostructures # substrate_bulk = Structure.from_file(bulk_filename) substrate_slab = Interface( bulk_structure, # substrate_bulk, hkl=surface_cut, min_thick=20, min_vac=30, primitive=False, from_ase=True, ) # mat2d_slab = slab_from_file([0, 0, 1], graphene_filename) mat2d_slab = slab_structure if strain_sys == "support": lower_mat = mat2d_slab upper_mat = substrate_slab elif strain_sys == "overlayer": lower_mat = substrate_slab upper_mat = mat2d_slab # mat2d_slab_aligned, substrate_slab_aligned = get_aligned_lattices( lower_mat_aligned, upper_mat_aligned = get_aligned_lattices( lower_mat, upper_mat, max_area=max_area, max_mismatch=max_mismatch, max_angle_diff=max_angle_diff, r1r2_tol=r1r2_tol, ) if strain_sys == "support": mat2d_slab_aligned = lower_mat_aligned substrate_slab_aligned = upper_mat_aligned elif strain_sys == "overlayer": mat2d_slab_aligned = upper_mat_aligned substrate_slab_aligned = lower_mat_aligned # Writing hetero_interfaces to pickle file with open('aligned_latt_materials.pickle', 'wb') as fle: pickle.dump((substrate_slab_aligned, mat2d_slab_aligned), fle) substrate_slab_aligned.to(filename='00_substrate_opt.POSCAR') mat2d_slab_aligned.to(filename='00_graphene_opt.POSCAR') # merge substrate and mat2d in all possible ways hetero_interfaces = generate_all_configs( mat2d_slab_aligned, substrate_slab_aligned, nlayers_2d, nlayers_substrate, separation, ) # Writing hetero_interfaces to pickle file with open('hetero_interfaces.pickle', 'wb') as fle: pickle.dump(hetero_interfaces, fle) #__| return(hetero_interfaces)
def get_grain_boundary_interface(structure=None, hkl_pair= {'hkl': [[1,0,0],[1,1,0]],\ 'thickness':[10,10]}, twist = 0, tilt = 0, separation=0): """ Args: structure: pymatgen structure to create grain boundary in hkl_pair: dict of {'hkl':thickness} twist: twist in degrees tilt: tilt in degrees """ structure = get_struct_from_mp(structure, MAPI_KEY="") sa = SpacegroupAnalyzer(structure) structure_conventional = sa.get_conventional_standard_structure() structure = structure_conventional.copy() structure.sort() #creation of lower part of grain boundary lower= Interface(structure,\ hkl = hkl_pair['hkl'][0], min_thick = hkl_pair['thickness'][0], min_vac = separation+hkl_pair['thickness'][1], primitive = False, from_ase = True, center_slab=False) lower.to(fmt="poscar", filename="POSCAR_lower.vasp") #creation of upper part of grain boundary upper= Interface(structure,\ hkl = hkl_pair['hkl'][1], min_thick = hkl_pair['thickness'][1], min_vac = 0, primitive = False, from_ase = True) #find top atoms reference of lower part of gb substrate_top_z = np.max(np.array([site.coords for site in lower])[:,2]) # define twist and tilt vectors twist_shift_normal = lower.lattice.matrix[2,:]/\ np.linalg.norm(lower.lattice.matrix[2,:]) tilt_normal = upper.lattice.matrix[1,:]/\ np.linalg.norm(upper.lattice.matrix[2,:]) #define twist operation SymmOp object twist_op = SymmOp.from_axis_angle_and_translation(axis= twist_shift_normal,\ angle=twist, angle_in_radians=False,translation_vec=(0, 0, 0)) #define tilt operation SymmOp object tilt_op = SymmOp.from_axis_angle_and_translation(axis= tilt_normal,\ angle=tilt, angle_in_radians=False,translation_vec=(0, 0, 0)) upper.apply_operation(twist_op) upper.to(fmt="poscar", filename="POSCAR_upper.vasp") upper.apply_operation(tilt_op) #define shift separation along twist vector normal to upper plane shift = -1*twist_shift_normal/np.linalg.norm(twist_shift_normal) * separation #define origin to shift w.r.t top of the lower grain origin = np.array([0,0, substrate_top_z]) #shift sites in upper for site in upper: new_coords = site.coords - origin + shift lower.append(site.specie, new_coords, coords_are_cartesian=True) return lower
adsorb_on_species = 'Pb' # atom on ligand that will be attached to the slab surface adatom_on_lig = 'N' # ligand displacement from the slab surface along the surface normal # i.e adatom_on_lig will be displced by this amount from the # adsorb_on_species atom # on the slab # in Angstrom displacement = 3.0 # here we create the interface iface = Interface(strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=0.01, ligand=hydrazine, displacement=displacement, adatom_on_lig='N', adsorb_on_species='Pb', primitive=False) iface.create_interface() iface.sort() # extract bare slab iface_slab = iface.slab iface_slab.sort() # set selective dynamics flags as required true_site = [1, 1, 1] false_site = [0, 0, 0] sd_flag_iface = [] sd_flag_slab = [] # selective dynamics flags for the interface for i in iface.sites: sd_flag_iface.append(false_site)
# ligand displacement from the slab surface along the surface normal # i.e adatom_on_lig will be displced by this amount from the # adsorb_on_species atom # on the slab # in Angstrom displacement = 3.0 # here we create the interface iface = Interface( strt, hkl=hkl, min_thick=min_thick, min_vac=min_vac, supercell=supercell, surface_coverage=0.01, ligand=hydrazine, displacement=displacement, adatom_on_lig="N", adsorb_on_species="Pb", primitive=False, ) iface.create_interface() iface.sort() # extract bare slab iface_slab = iface.slab iface_slab.sort() # set selective dynamics flags as required true_site = [1, 1, 1] false_site = [0, 0, 0] sd_flag_iface = []