Source code for twod_materials.friction.startup

from __future__ import print_function, division, unicode_literals

import os

import math

import numpy as np

from monty.serialization import loadfn

import twod_materials.utils as utl

from pymatgen.core.structure import Structure
from pymatgen.io.vasp.inputs import Incar

import twod_materials


PACKAGE_PATH = twod_materials.__file__.replace('__init__.pyc', '')
PACKAGE_PATH = PACKAGE_PATH.replace('__init__.py', '')
PACKAGE_PATH = '/'.join(PACKAGE_PATH.split('/')[:-2])

try:
    config_vars = loadfn(os.path.join(os.path.expanduser('~'), 'config.yaml'))
except:
    print('WARNING: No config.yaml file was found. please configure the '\
    'config.yaml and put it in your home directory.')
    # Still set them for testing purposes.
    config_vars = loadfn(os.path.join(PACKAGE_PATH, 'config.yaml'))
VASP = config_vars['normal_binary']
VASP_2D = config_vars['twod_binary']
VDW_KERNEL = config_vars['vdw_kernel']
if 'queue_system' in config_vars:
    QUEUE = config_vars['queue_system'].lower()
elif '/ufrc/' in os.getcwd():
    QUEUE = 'slurm'
elif '/scratch/' in os.getcwd():
    QUEUE = 'pbs'


[docs]def run_gamma_calculations(submit=True, step_size=0.5): """ Setup a 2D grid of static energy calculations to plot the Gamma surface between two layers of the 2D material. These calculations are run and stored in subdirectories under 'friction/lateral'. Args: submit (bool): Whether or not to submit the jobs. step_size (float): the distance between grid points in Angstroms. """ if not os.path.isdir('friction'): os.mkdir('friction') os.chdir('friction') if not os.path.isdir('lateral'): os.mkdir('lateral') os.chdir('lateral') os.system('cp ../../CONTCAR POSCAR') # Pad the bottom layer with 20 Angstroms of vacuum. utl.add_vacuum(20 - utl.get_spacing(), 0.8) structure = Structure.from_file('POSCAR') n_sites_per_layer = structure.num_sites n_divs_x = int(math.ceil(structure.lattice.a / step_size)) n_divs_y = int(math.ceil(structure.lattice.b / step_size)) # Get the thickness of the material. max_height = max([site.coords[2] for site in structure.sites]) min_height = min([site.coords[2] for site in structure.sites]) thickness = max_height - min_height # Make a new layer. new_sites = [] for site in structure.sites: new_sites.append((site.specie, [site.coords[0], site.coords[1], site.coords[2] + thickness + 3.5])) for site in new_sites: structure.append(site[0], site[1], coords_are_cartesian=True) #structure.get_sorted_structure().to('POSCAR', 'POSCAR') structure.to('POSCAR', 'POSCAR') for x in range(n_divs_x): for y in range(n_divs_y): dir = '{}x{}'.format(x, y) if not os.path.isdir(dir): os.mkdir(dir) # Copy input files os.chdir(dir) os.system('cp ../../../INCAR .') os.system('cp ../../../KPOINTS .') os.system('cp ../POSCAR .') if VDW_KERNEL != '/path/to/vdw_kernel.bindat': os.system('cp {} .'.format(VDW_KERNEL)) utl.write_potcar() incar_dict = Incar.from_file('INCAR').as_dict() incar_dict.update({'NSW': 0, 'LAECHG': False, 'LCHARG': False, 'LWAVE': False, 'MAGMOM': utl.get_magmom_string()}) incar_dict.pop('NPAR', None) Incar.from_dict(incar_dict).write_file('INCAR') # Shift the top layer poscar_lines = open('POSCAR').readlines() with open('POSCAR', 'w') as poscar: for line in poscar_lines[:8 + n_sites_per_layer]: poscar.write(line) for line in poscar_lines[8 + n_sites_per_layer:]: split_line = line.split() new_coords = [ float(split_line[0]) + float(x)/float(n_divs_x), float(split_line[1]) + float(y)/float(n_divs_y), float(split_line[2])] poscar.write(' '.join([str(i) for i in new_coords]) + '\n') if QUEUE == 'pbs': utl.write_pbs_runjob(dir, 1, 4, '800mb', '1:00:00', VASP) submission_command = 'qsub runjob' elif QUEUE == 'slurm': utl.write_slurm_runjob(dir, 4, '800mb', '1:00:00', VASP) submission_command = 'sbatch runjob' if submit: os.system(submission_command) os.chdir('../') os.chdir('../../')
[docs]def run_normal_force_calculations(basin_and_saddle_dirs, spacings=np.arange(1.5, 4.25, 0.25), submit=True): """ Set up and run static calculations of the basin directory and saddle directory at specified interlayer spacings to get f_N and f_F. Args: basin_and_saddle_dirs (tuple): Can be obtained by the get_basin_and_peak_locations() function under friction.analysis. For example, run_normal_force_calculations(('0x0', '3x6')) or run_normal_force_calculations(get_basin_and_peak_locations()) will both work. spacings (list): list of interlayer spacings (in Angstroms, as floats) at which to run the calculations. submit (bool): Whether or not to submit the jobs. """ spacings = [str(spc) for spc in spacings] os.chdir('friction') if not os.path.isdir('normal'): os.mkdir('normal') os.chdir('normal') for spacing in spacings: if not os.path.isdir(spacing): os.mkdir(spacing) for subdirectory in basin_and_saddle_dirs: os.system('cp -r ../lateral/{} {}/'.format(subdirectory, spacing)) os.chdir('{}/{}'.format(spacing, subdirectory)) structure = Structure.from_file('POSCAR') n_sites = len(structure.sites) top_layer = structure.sites[int(n_sites / 2):] bottom_of_top_layer = min( [z_coord for z_coord in [site.coords[2] for site in top_layer]]) remove_indices = range(int(n_sites / 2), n_sites) structure.remove_sites(remove_indices) max_height = max([site.coords[2] for site in structure.sites]) for site in top_layer: structure.append( site.specie, [site.coords[0], site.coords[1], site.coords[2] - bottom_of_top_layer + max_height + float(spacing)], coords_are_cartesian=True ) structure.to('POSCAR', 'POSCAR') if QUEUE == 'pbs': utl.write_pbs_runjob('{}_{}'.format(subdirectory, spacing), 1, 4, '400mb', '1:00:00', VASP) submission_command = 'qsub runjob' elif QUEUE == 'slurm': utl.write_slurm_runjob('{}_{}'.format(subdirectory, spacing), 4, '400mb', '1:00:00', VASP) submission_command = 'sbatch runjob' if submit: os.system(submission_command) os.chdir('../../') os.chdir('../../')