def relax(dim=2, submit=True, force_overwrite=False): """ Writes input files and (optionally) submits a self-consistent relaxation. Should be run before pretty much anything else, in order to get the right energy and structure of the material. Args: dim (int): 2 for relaxing a 2D material, 3 for a 3D material. submit (bool): Whether or not to submit the job. force_overwrite (bool): Whether or not to overwrite files if an already converged vasprun.xml exists in the directory. """ if force_overwrite or not utl.is_converged(os.getcwd()): directory = os.getcwd().split('/')[-1] # vdw_kernel.bindat file required for VDW calculations. if VDW_KERNEL: os.system('cp {} .'.format(VDW_KERNEL)) # KPOINTS Kpoints.automatic_density(Structure.from_file('POSCAR'), 1000).write_file('KPOINTS') # INCAR INCAR_DICT.update( {'MAGMOM': utl.get_magmom_string(Structure.from_file('POSCAR'))} ) Incar.from_dict(INCAR_DICT).write_file('INCAR') # POTCAR utl.write_potcar() # Special tasks only performed for 2D materials. if dim == 2: # Ensure 20A interlayer vacuum utl.ensure_vacuum(Structure.from_file('POSCAR'), 20) # Remove all z k-points. kpts_lines = open('KPOINTS').readlines() with open('KPOINTS', 'w') as kpts: for line in kpts_lines[:3]: kpts.write(line) kpts.write(kpts_lines[3].split()[0] + ' ' + kpts_lines[3].split()[1] + ' 1') # Submission script if dim == 2: binary = VASP_TWOD_BIN elif dim == 3: binary = VASP_STD_BIN if QUEUE_SYSTEM == 'pbs': utl.write_pbs_runjob(directory, 1, 16, '800mb', '6:00:00', binary) submission_command = 'qsub runjob' elif QUEUE_SYSTEM == 'slurm': utl.write_slurm_runjob(directory, 16, '800mb', '6:00:00', binary) submission_command = 'sbatch runjob' if submit: os.system(submission_command)
def relax(dim=2, submit=True, force_overwrite=False): """ Writes input files and (optionally) submits a self-consistent relaxation. Should be run before pretty much anything else, in order to get the right energy and structure of the material. Args: dim (int): 2 for relaxing a 2D material, 3 for a 3D material. submit (bool): Whether or not to submit the job. force_overwrite (bool): Whether or not to overwrite files if an already converged vasprun.xml exists in the directory. """ if force_overwrite or not utl.is_converged(os.getcwd()): directory = os.getcwd().split('/')[-1] # vdw_kernel.bindat file required for VDW calculations. if VDW_KERNEL: os.system('cp {} .'.format(VDW_KERNEL)) # KPOINTS Kpoints.automatic_density(Structure.from_file('POSCAR'), 1000).write_file('KPOINTS') # INCAR INCAR_DICT.update( {'MAGMOM': utl.get_magmom_string(Structure.from_file('POSCAR'))}) Incar.from_dict(INCAR_DICT).write_file('INCAR') # POTCAR utl.write_potcar() # Special tasks only performed for 2D materials. if dim == 2: # Ensure 20A interlayer vacuum utl.ensure_vacuum(Structure.from_file('POSCAR'), 20) # Remove all z k-points. kpts_lines = open('KPOINTS').readlines() with open('KPOINTS', 'w') as kpts: for line in kpts_lines[:3]: kpts.write(line) kpts.write(kpts_lines[3].split()[0] + ' ' + kpts_lines[3].split()[1] + ' 1') # Submission script if dim == 2: binary = VASP_TWOD_BIN elif dim == 3: binary = VASP_STD_BIN if QUEUE_SYSTEM == 'pbs': utl.write_pbs_runjob(directory, 1, 16, '800mb', '6:00:00', binary) submission_command = 'qsub runjob' elif QUEUE_SYSTEM == 'slurm': utl.write_slurm_runjob(directory, 16, '800mb', '6:00:00', binary) submission_command = 'sbatch runjob' if submit: os.system(submission_command)
def get_hull_distance(competing_phase_directory='../competing_phases'): """ Calculate the material's distance to the thermodynamic hull, based on species in the Materials Project database. Args: competing_phase_directory (str): absolute or relative path to the location where your competing phases have been relaxed. The default expectation is that they are stored in a directory named 'competing_phases' at the same level as your material's relaxation directory. Returns: float: distance (eV/atom) between the material and the hull. """ finished_competitors = {} original_directory = os.getcwd() # Determine which competing phases have been relaxed in the current # framework and store them in a dictionary ({formula: entry}). if os.path.isdir(competing_phase_directory): os.chdir(competing_phase_directory) for comp_dir in [dir for dir in os.listdir(os.getcwd()) if os.path.isdir(dir) and is_converged(dir)]: vasprun = Vasprun('{}/vasprun.xml'.format(comp_dir)) composition = vasprun.final_structure.composition energy = vasprun.final_energy finished_competitors[comp_dir] = ComputedEntry(composition, energy) os.chdir(original_directory) else: raise ValueError('Competing phase directory does not exist.') composition = Structure.from_file('POSCAR').composition try: energy = Vasprun('vasprun.xml').final_energy except: raise ValueError('This directory does not have a converged vasprun.xml') my_entry = ComputedEntry(composition, energy) # 2D material entries = MPR.get_entries_in_chemsys([elt.symbol for elt in composition]) # If the energies of competing phases have been calculated in # the current framework, put them in the phase diagram instead # of the MP energies. for i in range(len(entries)): formula = entries[i].composition.reduced_formula if formula in finished_competitors: entries[i] = finished_competitors[formula] else: entries[i] = ComputedEntry(entries[i].composition, 100) entries.append(my_entry) # 2D material #pda = PDAnalyzer(PhaseDiagram(entries)) pda = PhaseDiagram(entries) decomp = pda.get_decomp_and_e_above_hull(my_entry, allow_negative=True) return decomp[1]
def plot_ion_hull_and_voltages(ion, fmt='pdf'): """ Plots the phase diagram between the pure material and pure ion, Connecting the points on the convex hull of the phase diagram. Args: ion (str): name of atom that was intercalated, e.g. 'Li'. fmt (str): matplotlib format style. Check the matplotlib docs for options. """ # Calculated with the relax() function in # mat2d.stability.startup. If you are using other input # parameters, you need to recalculate these values! ion_ev_fu = {'Li': -1.7540797, 'Mg': -1.31976062, 'Al': -3.19134607} energy = Vasprun('vasprun.xml').final_energy composition = Structure.from_file('POSCAR').composition # Get the formula (with single-digit integers preceded by a '_'). twod_material = list(composition.reduced_formula) twod_formula = str() for i in range(len(twod_material)): try: int(twod_material[i]) twod_formula += '_{}'.format(twod_material[i]) except: twod_formula += twod_material[i] twod_ev_fu = energy / composition.get_reduced_composition_and_factor()[1] data = [(0, 0, 0, twod_ev_fu)] # (at% ion, n_ions, E_F, abs_energy) dirs = [dir for dir in os.listdir(os.getcwd()) if os.path.isdir(dir)] for directory in dirs: if is_converged(directory): os.chdir(directory) energy = Vasprun('vasprun.xml').final_energy composition = Structure.from_file('POSCAR').composition ion_fraction = composition.get_atomic_fraction(ion) no_ion_comp_dict = composition.as_dict() no_ion_comp_dict.update({ion: 0}) no_ion_comp = Composition.from_dict(no_ion_comp_dict) n_twod_fu = no_ion_comp.get_reduced_composition_and_factor()[1] n_ions = composition[ion] / n_twod_fu E_F = ((energy - composition[ion] * ion_ev_fu[ion] - twod_ev_fu * n_twod_fu)/ composition.num_atoms) data.append((ion_fraction, n_ions, E_F, energy / n_twod_fu)) os.chdir('../') data.append((1, 1, 0, ion_ev_fu[ion])) # Pure ion sorted_data = sorted(data, key=operator.itemgetter(0)) # Determine which compositions are on the convex hull. energy_profile = np.array([[item[0], item[2]] for item in sorted_data if item[2] <= 0]) hull = ConvexHull(energy_profile) convex_ion_fractions = [energy_profile[vertex, 0] for vertex in hull.vertices] convex_formation_energies = [energy_profile[vertex, 1] for vertex in hull.vertices] convex_ion_fractions.append(convex_ion_fractions.pop(0)) convex_formation_energies.append(convex_formation_energies.pop(0)) concave_ion_fractions = [pt[0] for pt in sorted_data if pt[0] not in convex_ion_fractions] concave_formation_energies = [pt[2] for pt in sorted_data if pt[0] not in convex_ion_fractions] voltage_profile = [] j = 0 k = 0 for i in range(1, len(sorted_data) - 1): if sorted_data[i][0] in convex_ion_fractions: voltage = -(((sorted_data[i][3] - sorted_data[k][3])- (sorted_data[i][1] - sorted_data[k][1]) * ion_ev_fu[ion]) / (sorted_data[i][1] - sorted_data[k][1])) voltage_profile.append((sorted_data[k][0], voltage)) voltage_profile.append((sorted_data[i][0], voltage)) j += 1 k = i voltage_profile.append((voltage_profile[-1][0], 0)) voltage_profile.append((1, 0)) voltage_profile_x = [tup[0] for tup in voltage_profile] voltage_profile_y = [tup[1] for tup in voltage_profile] ax = plt.figure(figsize=(14, 10)).gca() ax.plot([0, 1], [0, 0], 'k--') ax.plot(convex_ion_fractions, convex_formation_energies, 'b-', marker='o', markersize=12, markeredgecolor='none') ax.plot(concave_ion_fractions, concave_formation_energies, 'r', marker='o', linewidth=0, markersize=12, markeredgecolor='none') ax2 = ax.twinx() ax2.plot(voltage_profile_x, voltage_profile_y, 'k-', marker='o') ax.text(0, 0.002, r'$\mathrm{%s}$' % twod_formula, family='serif', size=24) ax.text(0.99, 0.002, r'$\mathrm{%s}$' % ion, family='serif', size=24, horizontalalignment='right') ax.set_xticklabels(ax.get_xticks(), family='serif', size=20) ax.set_yticklabels(ax.get_yticks(), family='serif', size=20) ax2.set_yticklabels(ax2.get_yticks(), family='serif', size=20) ax.set_xlabel('at% {}'.format(ion), family='serif', size=28) ax.set_ylabel(r'$\mathrm{E_F\/(eV/atom)}$', size=28) ax2.yaxis.set_label_position('right') if ion == 'Li': ax2.set_ylabel(r'$\mathrm{Potential\/vs.\/Li/Li^+\/(V)}$', size=28) elif ion == 'Mg': ax2.set_ylabel(r'$\mathrm{Potential\/vs.\/Mg/Mg^{2+}\/(V)}$', size=28) elif ion == 'Al': ax2.set_ylabel(r'$\mathrm{Potential\/vs.\/Al/Al^{3+}\/(V)}$', size=28) plt.savefig('{}_hull.{}'.format(ion, fmt), transparent=True)
def plot_band_alignments(directories, run_type='PBE', fmt='pdf'): """ Plot CBM's and VBM's of all compounds together, relative to the band edges of H2O. Args: directories (list): list of the directory paths for materials to include in the plot. run_type (str): 'PBE' or 'HSE', so that the function knows which subdirectory to go into (pbe_bands or hse_bands). fmt (str): matplotlib format style. Check the matplotlib docs for options. """ if run_type == 'HSE': subdirectory = 'hse_bands' else: subdirectory = 'pbe_bands' band_gaps = {} for directory in directories: sub_dir = os.path.join(directory, subdirectory) if is_converged(sub_dir): os.chdir(sub_dir) band_structure = Vasprun('vasprun.xml').get_band_structure() band_gap = band_structure.get_band_gap() # Vacuum level energy from LOCPOT. locpot = Locpot.from_file('LOCPOT') evac = max(locpot.get_average_along_axis(2)) if not band_structure.is_metal(): is_direct = band_gap['direct'] cbm = band_structure.get_cbm() vbm = band_structure.get_vbm() else: cbm = None vbm = None is_direct = False band_gaps[directory] = { 'CBM': cbm, 'VBM': vbm, 'Direct': is_direct, 'Metal': band_structure.is_metal(), 'E_vac': evac } os.chdir('../../') ax = plt.figure(figsize=(16, 10)).gca() x_max = len(band_gaps) * 1.315 ax.set_xlim(0, x_max) # Rectangle representing band edges of water. ax.add_patch( plt.Rectangle((0, -5.67), height=1.23, width=len(band_gaps), facecolor='#00cc99', linewidth=0)) ax.text(len(band_gaps) * 1.01, -4.44, r'$\mathrm{H+/H_2}$', size=20, verticalalignment='center') ax.text(len(band_gaps) * 1.01, -5.67, r'$\mathrm{O_2/H_2O}$', size=20, verticalalignment='center') x_ticklabels = [] y_min = -8 i = 0 # Nothing but lies. are_directs, are_indirects, are_metals = False, False, False for compound in [cpd for cpd in directories if cpd in band_gaps]: x_ticklabels.append(compound) # Plot all energies relative to their vacuum level. evac = band_gaps[compound]['E_vac'] if band_gaps[compound]['Metal']: cbm = -8 vbm = -2 else: cbm = band_gaps[compound]['CBM']['energy'] - evac vbm = band_gaps[compound]['VBM']['energy'] - evac # Add a box around direct gap compounds to distinguish them. if band_gaps[compound]['Direct']: are_directs = True linewidth = 5 elif not band_gaps[compound]['Metal']: are_indirects = True linewidth = 0 # Metals are grey. if band_gaps[compound]['Metal']: are_metals = True linewidth = 0 color_code = '#404040' else: color_code = '#002b80' # CBM ax.add_patch( plt.Rectangle((i, cbm), height=-cbm, width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00")) # VBM ax.add_patch( plt.Rectangle((i, y_min), height=(vbm - y_min), width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00")) i += 1 ax.set_ylim(y_min, 0) # Set tick labels ax.set_xticks([n + 0.4 for n in range(i)]) ax.set_xticklabels(x_ticklabels, family='serif', size=20, rotation=60) ax.set_yticklabels(ax.get_yticks(), family='serif', size=20) # Add a legend height = y_min if are_directs: ax.add_patch( plt.Rectangle((i * 1.165, height), width=i * 0.15, height=(-y_min * 0.1), facecolor='#002b80', edgecolor='#e68a00', linewidth=5)) ax.text(i * 1.24, height - y_min * 0.05, 'Direct', family='serif', color='w', size=20, horizontalalignment='center', verticalalignment='center') height -= y_min * 0.15 if are_indirects: ax.add_patch( plt.Rectangle((i * 1.165, height), width=i * 0.15, height=(-y_min * 0.1), facecolor='#002b80', linewidth=0)) ax.text(i * 1.24, height - y_min * 0.05, 'Indirect', family='serif', size=20, color='w', horizontalalignment='center', verticalalignment='center') height -= y_min * 0.15 if are_metals: ax.add_patch( plt.Rectangle((i * 1.165, height), width=i * 0.15, height=(-y_min * 0.1), facecolor='#404040', linewidth=0)) ax.text(i * 1.24, height - y_min * 0.05, 'Metal', family='serif', size=20, color='w', horizontalalignment='center', verticalalignment='center') # Who needs axes? ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['bottom'].set_visible(False) ax.spines['left'].set_visible(False) ax.yaxis.set_ticks_position('left') ax.xaxis.set_ticks_position('bottom') ax.set_ylabel('eV', family='serif', size=24) if fmt == "None": return ax else: plt.savefig('band_alignments.{}'.format(fmt), transparent=True) plt.close()
def run_pbe_calculation(dim=2, submit=True, force_overwrite=False): """ Setup and submit a normal PBE calculation for band structure along high symmetry k-paths. Args: dim (int): 2 for relaxing a 2D material, 3 for a 3D material. submit (bool): Whether or not to submit the job. force_overwrite (bool): Whether or not to overwrite files if an already converged vasprun.xml exists in the directory. """ PBE_INCAR_DICT = { 'EDIFF': 1e-6, 'IBRION': 2, 'ISIF': 3, 'ISMEAR': 1, 'NSW': 0, 'LVTOT': True, 'LVHAR': True, 'LORBIT': 1, 'LREAL': 'Auto', 'NPAR': 4, 'PREC': 'Accurate', 'LWAVE': True, 'SIGMA': 0.1, 'ENCUT': 500, 'ISPIN': 2 } directory = os.path.basename(os.getcwd()) if not os.path.isdir('pbe_bands'): os.mkdir('pbe_bands') if force_overwrite or not is_converged('pbe_bands'): shutil.copy("CONTCAR", "pbe_bands/POSCAR") if os.path.isfile('POTCAR'): shutil.copy("POTCAR", "pbe_bands") PBE_INCAR_DICT.update( {'MAGMOM': get_magmom_string(Structure.from_file('POSCAR'))}) Incar.from_dict(PBE_INCAR_DICT).write_file('pbe_bands/INCAR') structure = Structure.from_file('POSCAR') kpath = HighSymmKpath(structure) Kpoints.automatic_linemode(20, kpath).write_file('pbe_bands/KPOINTS') os.chdir('pbe_bands') if dim == 2: remove_z_kpoints() if QUEUE_SYSTEM == 'pbs': write_pbs_runjob(directory, 1, 16, '800mb', '6:00:00', VASP_STD_BIN) submission_command = 'qsub runjob' elif QUEUE_SYSTEM == 'slurm': write_slurm_runjob(directory, 16, '800mb', '6:00:00', VASP_STD_BIN) submission_command = 'sbatch runjob' if submit: _ = subprocess.check_output(submission_command.split()) os.chdir('../')
def run_hse_calculation(dim=2, submit=True, force_overwrite=False, destroy_prep_directory=False): """ Setup/submit an HSE06 calculation to get an accurate band structure. Requires a previous IBZKPT from a standard DFT run. See http://cms.mpi.univie.ac.at/wiki/index.php/Si_bandstructure for more details. Args: dim (int): 2 for relaxing a 2D material, 3 for a 3D material. submit (bool): Whether or not to submit the job. force_overwrite (bool): Whether or not to overwrite files if an already converged vasprun.xml exists in the directory. destroy_prep_directory (bool): whether or not to remove (rm -r) the hse_prep directory, if it exists. This can help to automatically clean up and save space. """ HSE_INCAR_DICT = { 'LHFCALC': True, 'HFSCREEN': 0.2, 'AEXX': 0.25, 'ALGO': 'D', 'TIME': 0.4, 'NSW': 0, 'LVTOT': True, 'LVHAR': True, 'LORBIT': 11, 'LWAVE': True, 'NPAR': 8, 'PREC': 'Accurate', 'EDIFF': 1e-4, 'ENCUT': 450, 'ICHARG': 2, 'ISMEAR': 1, 'SIGMA': 0.1, 'IBRION': 2, 'ISIF': 3, 'ISPIN': 2 } if not os.path.isdir('hse_bands'): os.mkdir('hse_bands') if force_overwrite or not is_converged('hse_bands'): os.chdir('hse_bands') os.system('cp ../CONTCAR ./POSCAR') if os.path.isfile('../POTCAR'): os.system('cp ../POTCAR .') HSE_INCAR_DICT.update( {'MAGMOM': get_magmom_string(Structure.from_file('POSCAR'))}) Incar.from_dict(HSE_INCAR_DICT).write_file('INCAR') # Re-use the irreducible brillouin zone KPOINTS from a # previous standard DFT run. if os.path.isdir('../hse_prep'): ibz_lines = open('../hse_prep/IBZKPT').readlines() if destroy_prep_directory: os.system('rm -r ../hse_prep') else: ibz_lines = open('../IBZKPT').readlines() n_ibz_kpts = int(ibz_lines[1].split()[0]) kpath = HighSymmKpath(Structure.from_file('POSCAR')) Kpoints.automatic_linemode(20, kpath).write_file('KPOINTS') if dim == 2: remove_z_kpoints() linemode_lines = open('KPOINTS').readlines() abs_path = [] i = 4 while i < len(linemode_lines): start_kpt = linemode_lines[i].split() end_kpt = linemode_lines[i + 1].split() increments = [(float(end_kpt[0]) - float(start_kpt[0])) / 20, (float(end_kpt[1]) - float(start_kpt[1])) / 20, (float(end_kpt[2]) - float(start_kpt[2])) / 20] abs_path.append(start_kpt[:3] + ['0', start_kpt[4]]) for n in range(1, 20): abs_path.append([ str(float(start_kpt[0]) + increments[0] * n), str(float(start_kpt[1]) + increments[1] * n), str(float(start_kpt[2]) + increments[2] * n), '0' ]) abs_path.append(end_kpt[:3] + ['0', end_kpt[4]]) i += 3 n_linemode_kpts = len(abs_path) with open('KPOINTS', 'w') as kpts: kpts.write('Automatically generated mesh\n') kpts.write('{}\n'.format(n_ibz_kpts + n_linemode_kpts)) kpts.write('Reciprocal Lattice\n') for line in ibz_lines[3:]: kpts.write(line) for point in abs_path: kpts.write('{}\n'.format(' '.join(point))) if QUEUE_SYSTEM == 'pbs': write_pbs_runjob('{}_hsebands'.format(os.getcwd().split('/')[-2]), 2, 64, '1800mb', '50:00:00', VASP_STD_BIN) submission_command = 'qsub runjob' elif QUEUE_SYSTEM == 'slurm': write_slurm_runjob( '{}_hsebands'.format(os.getcwd().split('/')[-2]), 64, '1800mb', '50:00:00', VASP_STD_BIN) submission_command = 'sbatch runjob' if submit: _ = subprocess.check_output(submission_command.split()) os.chdir('../')
def plot_band_alignments(directories, run_type='PBE', fmt='pdf'): """ Plot CBM's and VBM's of all compounds together, relative to the band edges of H2O. Args: directories (list): list of the directory paths for materials to include in the plot. run_type (str): 'PBE' or 'HSE', so that the function knows which subdirectory to go into (pbe_bands or hse_bands). fmt (str): matplotlib format style. Check the matplotlib docs for options. """ if run_type == 'HSE': subdirectory = 'hse_bands' else: subdirectory = 'pbe_bands' band_gaps = {} for directory in directories: sub_dir = os.path.join(directory, subdirectory) if is_converged(sub_dir): os.chdir(sub_dir) band_structure = Vasprun('vasprun.xml').get_band_structure() band_gap = band_structure.get_band_gap() # Vacuum level energy from LOCPOT. locpot = Locpot.from_file('LOCPOT') evac = max(locpot.get_average_along_axis(2)) if not band_structure.is_metal(): is_direct = band_gap['direct'] cbm = band_structure.get_cbm() vbm = band_structure.get_vbm() else: cbm = None vbm = None is_direct = False band_gaps[directory] = {'CBM': cbm, 'VBM': vbm, 'Direct': is_direct, 'Metal': band_structure.is_metal(), 'E_vac': evac} os.chdir('../../') ax = plt.figure(figsize=(16, 10)).gca() x_max = len(band_gaps) * 1.315 ax.set_xlim(0, x_max) # Rectangle representing band edges of water. ax.add_patch(plt.Rectangle((0, -5.67), height=1.23, width=len(band_gaps), facecolor='#00cc99', linewidth=0)) ax.text(len(band_gaps) * 1.01, -4.44, r'$\mathrm{H+/H_2}$', size=20, verticalalignment='center') ax.text(len(band_gaps) * 1.01, -5.67, r'$\mathrm{O_2/H_2O}$', size=20, verticalalignment='center') x_ticklabels = [] y_min = -8 i = 0 # Nothing but lies. are_directs, are_indirects, are_metals = False, False, False for compound in [cpd for cpd in directories if cpd in band_gaps]: x_ticklabels.append(compound) # Plot all energies relative to their vacuum level. evac = band_gaps[compound]['E_vac'] if band_gaps[compound]['Metal']: cbm = -8 vbm = -2 else: cbm = band_gaps[compound]['CBM']['energy'] - evac vbm = band_gaps[compound]['VBM']['energy'] - evac # Add a box around direct gap compounds to distinguish them. if band_gaps[compound]['Direct']: are_directs = True linewidth = 5 elif not band_gaps[compound]['Metal']: are_indirects = True linewidth = 0 # Metals are grey. if band_gaps[compound]['Metal']: are_metals = True linewidth = 0 color_code = '#404040' else: color_code = '#002b80' # CBM ax.add_patch(plt.Rectangle((i, cbm), height=-cbm, width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00")) # VBM ax.add_patch(plt.Rectangle((i, y_min), height=(vbm - y_min), width=0.8, facecolor=color_code, linewidth=linewidth, edgecolor="#e68a00")) i += 1 ax.set_ylim(y_min, 0) # Set tick labels ax.set_xticks([n + 0.4 for n in range(i)]) ax.set_xticklabels(x_ticklabels, family='serif', size=20, rotation=60) ax.set_yticklabels(ax.get_yticks(), family='serif', size=20) # Add a legend height = y_min if are_directs: ax.add_patch(plt.Rectangle((i*1.165, height), width=i*0.15, height=(-y_min*0.1), facecolor='#002b80', edgecolor='#e68a00', linewidth=5)) ax.text(i*1.24, height - y_min * 0.05, 'Direct', family='serif', color='w', size=20, horizontalalignment='center', verticalalignment='center') height -= y_min * 0.15 if are_indirects: ax.add_patch(plt.Rectangle((i*1.165, height), width=i*0.15, height=(-y_min*0.1), facecolor='#002b80', linewidth=0)) ax.text(i*1.24, height - y_min * 0.05, 'Indirect', family='serif', size=20, color='w', horizontalalignment='center', verticalalignment='center') height -= y_min * 0.15 if are_metals: ax.add_patch(plt.Rectangle((i*1.165, height), width=i*0.15, height=(-y_min*0.1), facecolor='#404040', linewidth=0)) ax.text(i*1.24, height - y_min * 0.05, 'Metal', family='serif', size=20, color='w', horizontalalignment='center', verticalalignment='center') # Who needs axes? ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['bottom'].set_visible(False) ax.spines['left'].set_visible(False) ax.yaxis.set_ticks_position('left') ax.xaxis.set_ticks_position('bottom') ax.set_ylabel('eV', family='serif', size=24) if fmt == "None": return ax else: plt.savefig('band_alignments.{}'.format(fmt), transparent=True) plt.close()
def run_hse_calculation(dim=2, submit=True, force_overwrite=False): """ Setup/submit an HSE06 calculation to get an accurate band structure. See http://cms.mpi.univie.ac.at/wiki/index.php/Si_bandstructure for more details. Args: dim (int): 2 for relaxing a 2D material, 3 for a 3D material. submit (bool): Whether or not to submit the job. force_overwrite (bool): Whether or not to overwrite files if an already converged vasprun.xml exists in the directory. """ HSE_INCAR_DICT = { 'LHFCALC': True, 'HFSCREEN': 0.2, 'AEXX': 0.25, 'ALGO': 'D', 'TIME': 0.4, 'NSW': 0, 'LVTOT': True, 'LVHAR': True, 'LORBIT': 11, 'LWAVE': True, 'NPAR': 8, 'PREC': 'Accurate', 'EDIFF': 1e-4, 'ENCUT': 450, 'ICHARG': 2, 'ISMEAR': 1, 'SIGMA': 0.1, 'IBRION': 2, 'ISIF': 3, 'ISPIN': 2 } if not os.path.isdir('hse_bands'): os.mkdir('hse_bands') if force_overwrite or not is_converged('hse_bands'): os.chdir('hse_bands') os.system('cp ../CONTCAR ./POSCAR') structure = Structure.from_file("POSCAR") if os.path.isfile('../POTCAR'): os.system('cp ../POTCAR .') HSE_INCAR_DICT.update({'MAGMOM': get_magmom_string(structure)}) Incar.from_dict(HSE_INCAR_DICT).write_file('INCAR') # Re-use the irreducible brillouin zone KPOINTS from a # previous standard DFT run. write_band_structure_kpoints(structure, dim=dim) if QUEUE_SYSTEM == 'pbs': write_pbs_runjob('{}_hsebands'.format(os.getcwd().split('/')[-2]), 2, 64, '1800mb', '50:00:00', VASP_STD_BIN) submission_command = 'qsub runjob' elif QUEUE_SYSTEM == 'slurm': write_slurm_runjob( '{}_hsebands'.format(os.getcwd().split('/')[-2]), 64, '1800mb', '50:00:00', VASP_STD_BIN) submission_command = 'sbatch runjob' if submit: _ = subprocess.check_output(submission_command.split()) os.chdir('../')