def test___add___spin_polarised_procars(self): pcar1 = procar.Procar() pcar2 = procar.Procar() with warnings.catch_warnings(): warnings.simplefilter('ignore') pcar1._read_from_file(test_procar_spin_polarised_filename) pcar2._read_from_file(test_procar_spin_polarised_filename) combined_pcar = pcar1 + pcar2 self.assertEqual(combined_pcar.spin_channels, 2) self.assertEqual(combined_pcar.number_of_ions, 25) self.assertEqual(combined_pcar.number_of_bands, 112) self.assertEqual(combined_pcar.number_of_k_points, 16)
def test_read_from_file_warns_about_negative_occupancies(self): pcar = procar.Procar() with warnings.catch_warnings(record=True) as w: pcar.read_from_file(test_procar_filename, negative_occupancies='warn') self.assertEqual(len(w), 1) self.assertTrue("negative" in str(w[-1].message))
def test_read_from_file_zeros_occupancies_if_negative_occupancies_is_zero( self): pcar = procar.Procar() pcar.read_from_file(test_procar_filename, negative_occupancies='zero') np.testing.assert_array_equal( pcar.occupancy[:, 1], np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0]))
def test_procar_occupation_values_are_read(self): pcar = procar.Procar() with warnings.catch_warnings(): warnings.simplefilter('ignore') pcar.read_from_file(test_procar_filename) np.testing.assert_array_equal( pcar.occupancy[:, 1], np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -0.03191968]))
def test_spin_polarised_procar_is_read_from_file(self): """Checking that `PROCAR_spin_polarised_test` is read""" pcar = procar.Procar() pcar.read_from_file(test_procar_spin_polarised_filename) self.assertEqual(pcar.spin_channels, 2) self.assertEqual(pcar.number_of_ions, 25) self.assertEqual(pcar.number_of_bands, 112) self.assertEqual(pcar.number_of_k_points, 8)
def test___add___( self ): pcar1 = procar.Procar() pcar2 = procar.Procar() with warnings.catch_warnings(): warnings.simplefilter('ignore') pcar1._read_from_file( test_procar_filename ) pcar2._read_from_file( test_procar_filename ) combined_pcar = pcar1 + pcar2 self.assertEqual( combined_pcar.spin_channels, 4 ) self.assertEqual( combined_pcar.number_of_ions, 22 ) self.assertEqual( combined_pcar.number_of_bands, 4 ) self.assertEqual( combined_pcar.number_of_k_points, 4 ) expected_bands = np.ravel( np.concatenate( [ pcar1.bands, pcar2.bands ], axis=1 ) ) np.testing.assert_equal( combined_pcar._bands, expected_bands ) for k1, k2 in zip( combined_pcar.k_points, pcar1.k_points + pcar2.k_points ): np.testing.assert_equal( k1.frac_coords, k2.frac_coords ) self.assertEqual( k1.weight, k2.weight ) self.assertEqual( [ k.index for k in combined_pcar.k_points ], [ 1, 2, 3, 4 ] )
def test_procar_is_read_from_file(self): """Checking that `PROCAR_test` is read""" pcar = procar.Procar() with warnings.catch_warnings(): warnings.simplefilter('ignore') pcar.read_from_file(test_procar_filename) self.assertEqual(pcar.spin_channels, 4) self.assertEqual(pcar.number_of_ions, 22) self.assertEqual(pcar.number_of_bands, 4) self.assertEqual(pcar.number_of_k_points, 2)
def main(): parser = argparse.ArgumentParser( description= 'Calculate an effective mass from a VASP PROCAR using a fitted quadratic' ) parser.add_argument( '-k', '--k-points', help='index of k-points for calculating effective mass', nargs='+', type=int, required=True, action=minimum_length(2)) parser.add_argument('-b', '--band-index', help='index of band for calculating effective mass', type=int, required=True) parser.add_argument('-f', '--procar', help='PROCAR filename (default PROCAR)', type=str, default='PROCAR') parser.add_argument('-v', '--verbose', help='Verbose output', action='store_true') parser.add_argument('-o', '--outcar', help='OUTCAR filename (default OUTCAR)', type=str, default='OUTCAR') parser.add_argument( '-s', '--spin', help='select spin channel (default 1 / non-spin-polarised)', type=int, default='1') args = parser.parse_args() reciprocal_lattice = reciprocal_lattice_from_outcar( 'OUTCAR') # Move reading the reciprocal lattice to procar.py pcar = procar.Procar() pcar.read_from_file(args.procar) effective_mass = pcar.effective_mass_calc( k_point_indices=args.k_points, band_index=args.band_index, reciprocal_lattice=reciprocal_lattice, spin=args.spin, printing=args.verbose) print(effective_mass)
def test_procar_from_file_correctly_parses_bands(self): pcar = procar.Procar() with warnings.catch_warnings(): warnings.simplefilter('ignore') pcar._read_from_file(test_procar_filename) np.testing.assert_equal([b.index for b in pcar._bands], [1., 2., 3., 4., 1., 2., 3., 4.]) np.testing.assert_equal([b.energy for b in pcar._bands], [ -13.17934476, -13.17934476, -13.16936722, -13.16936722, -13.1849117, -13.1849117, -13.16621473, -13.16621472 ]) np.testing.assert_equal([b.occupancy for b in pcar._bands], [1., 1., 1., 1., 1., 1., 1., -0.03191968])
def test_procar_is_initialised( self ): pcar = procar.Procar() self.assertEqual( pcar.spin_channels, 1 ) self.assertEqual( pcar.number_of_k_points, None ) self.assertEqual( pcar.number_of_ions, None ) self.assertEqual( pcar.number_of_bands, None ) self.assertEqual( pcar.data, None ) self.assertEqual( pcar.bands, None ) self.assertEqual( pcar.occupancy, None ) self.assertEqual( pcar.number_of_projections, None ) self.assertEqual( pcar.k_point_blocks, None ) self.assertEqual( pcar.calculation, { 'non_spin_polarised': False, 'non_collinear': False, 'spin_polarised': False } )
def __init__(self, outcar_path, procar_path, ignore=0): r""" Initialises an instance of the :class:`~effmass.inputs.Data` class and checks data using :meth:`check_data`. Args: outcar_path (str): The path to the OUTCAR file procar_path (str): The path to the PROCAR file ignore (int): The number of kpoints to ignore at the beginning of the bandstructure slice through kspace (useful for hybrid calculations where zero weightings are appended to a previous self-consistent calculation). Returns: None. """ assert (type(outcar_path) == str), "The OUTCAR path must be a string" assert (type(procar_path) == str), "The PROCAR path must be a string" assert (type(ignore) == int and ignore >= 0 ), "The number of kpoints to ignore must be a positive integer" reciprocal_lattice = outcar.reciprocal_lattice_from_outcar(outcar_path) vasp_data = procar.Procar() vasp_data.read_from_file(procar_path) if vasp_data.calculation[ 'spin_polarised']: # to account for the change in PROCAR format for calculations with 2 spin channels (1 k-point block ---> 2 k-point blocks) blocks = 2 else: blocks = 1 self.spin_channels = vasp_data.spin_channels self.number_of_kpoints = vasp_data.number_of_k_points - ignore self.number_of_bands = vasp_data.number_of_bands self.number_of_ions = vasp_data.number_of_ions self.kpoints = vasp_data.k_points[ignore:] self.energies = vasp_data.bands[self.number_of_bands * ignore:, 1:].reshape( self.number_of_kpoints, self.number_of_bands * blocks).T self.occupancy = vasp_data.occupancy[self.number_of_bands * ignore:, 1:].reshape( self.number_of_kpoints, self.number_of_bands * blocks).T self.reciprocal_lattice = reciprocal_lattice * 2 * math.pi self.CBM = extrema._calc_CBM(self.occupancy, self.energies) self.VBM = extrema._calc_VBM(self.occupancy, self.energies) self.fermi_energy = (self.CBM + self.VBM) / 2 self.dos = [] self.integrated_dos = [] self.check_data()
def setUp(self): self.procar = procar.Procar()
def main(): parser = argparse.ArgumentParser() parser.add_argument( '-i', '--ions', help='ion indices for band projection (default: sum over all ions)', nargs='+', type=int) parser.add_argument( '-s', '--spins', help='spin indices for band projection (default [ 1 ])', nargs='+', type=int, default=[1]) parser.add_argument( '-o', '--orbitals', help= 'orbital indices for band projection (default: sum over all orbitals)', nargs='+', type=int) parser.add_argument('-e', '--efermi', help='set fermi energy as reference for energy scale', type=float, default=0.0) parser.add_argument( '-l', '--l-angular-momentum', help= 'select all orbitals with angular momentum L for band projection. This supercedes the --orbitals option', choices=['s', 'p', 'd', 'f', 'all']) parser.add_argument('-f', '--procar', help='PROCAR filename (default PROCAR)', type=str, default='PROCAR') parser.add_argument('--scaling', help='Energy scaling for band widths (default 0.2 eV)', type=float, default=0.2) parser.add_argument( '-x', '--xscaling', help= 'Automatic scaling of x-axis using reciprocal lattice vectors read from OUTCAR', action='store_true', default=False) args = parser.parse_args() if args.l_angular_momentum: args.orbitals = orbitals_with_l(args.l_angular_momentum) if args.xscaling: reciprocal_lattice = reciprocal_lattice_from_outcar( 'OUTCAR') # Move reading the reciprocal lattice to procar.py else: reciprocal_lattice = None pcar = procar.Procar() pcar.read_from_file(args.procar) pcar.print_weighted_band_structure(spins=args.spins, ions=args.ions, orbitals=args.orbitals, scaling=args.scaling, e_fermi=args.efermi, reciprocal_lattice=reciprocal_lattice)
def test_read_from_file_if_negative_occupancies_is_ignore(self): pcar = procar.Procar() pcar.read_from_file(test_procar_filename, negative_occupancies='ignore')
def test_read_from_file_raises_exception_if_negative_occupancies_is_raise( self): pcar = procar.Procar() with self.assertRaises(ValueError): pcar.read_from_file(test_procar_filename, negative_occupancies='raise')
def test_read_from_file_raises_valueerror_if_negative_occupancies_is_invalid( self): pcar = procar.Procar() with self.assertRaises(ValueError): pcar.read_from_file(test_procar_filename, negative_occupancies='foo')
def __init__(self, outcar_path, procar_path, ignore=0): r""" Initialises an instance of the :class:`~effmass.inputs.Data` class and checks data using :meth:`check_data`. Args: outcar_path (str): The path to the OUTCAR file procar_path (str): The path to the PROCAR file ignore (int): The number of kpoints to ignore at the beginning of the bandstructure slice through kspace (useful for hybrid calculations where zero weightings are appended to a previous self-consistent calculation). Returns: None. """ assert (type(outcar_path) == str), "The OUTCAR path must be a string" assert (type(procar_path) == str), "The PROCAR path must be a string" assert (type(ignore) == int and ignore >= 0 ), "The number of kpoints to ignore must be a positive integer" reciprocal_lattice = outcar.reciprocal_lattice_from_outcar(outcar_path) vasp_data = procar.Procar() vasp_data.read_from_file(procar_path) self.spin_channels = vasp_data.spin_channels self.number_of_bands = vasp_data.number_of_bands self.number_of_ions = vasp_data.number_of_ions number_of_kpoints = vasp_data.number_of_k_points if vasp_data.calculation[ 'spin_polarised']: # to account for the change in PROCAR format for calculations with 2 spin channels (1 k-point block ---> 2 k-point blocks) energies = np.zeros( [self.number_of_bands * 2, number_of_kpoints] ) # This is a very ugly way to slice 'n' dice. Should avoid creating new array and use array methods instead. But it does the job so will keep for now. for i in range(self.number_of_bands): energies[i] = vasp_data.bands[:, 1:].reshape( number_of_kpoints * 2, # factor or 2 for each kpoint block self.number_of_bands).T[i][:number_of_kpoints] energies[self.number_of_bands + i] = vasp_data.bands[:, 1:].reshape( number_of_kpoints * 2, self.number_of_bands).T[i][number_of_kpoints:] occupancy = np.zeros([self.number_of_bands * 2, number_of_kpoints]) for i in range(self.number_of_bands): occupancy[i] = vasp_data.occupancy[:, 1:].reshape( number_of_kpoints * 2, self.number_of_bands).T[i][:number_of_kpoints] occupancy[self.number_of_bands + i] = vasp_data.occupancy[:, 1:].reshape( number_of_kpoints * 2, self.number_of_bands).T[i][number_of_kpoints:] else: energies = vasp_data.bands[:, 1:].reshape(number_of_kpoints, self.number_of_bands).T occupancy = vasp_data.occupancy[:, 1:].reshape( number_of_kpoints, self.number_of_bands).T # remove values which are from the self-consistent calculation prior to the bandstructure calculation (workflow for hybrid functionals) self.energies = np.delete(energies, list(range(ignore)), 1) self.occupancy = np.delete(occupancy, list(range(ignore)), 1) self.number_of_kpoints = number_of_kpoints - ignore # handle negative occupancy values if np.any(self.occupancy < 0): warnings.warn( "One or more occupancies in your PROCAR file are negative. All negative occupancies will be set to zero." ) self.occupancy[self.occupancy < 0] = 0.0 self.kpoints = vasp_data.k_points[ignore:vasp_data.number_of_k_points] self.reciprocal_lattice = reciprocal_lattice * 2 * math.pi self.CBM = extrema._calc_CBM(self.occupancy, self.energies) self.VBM = extrema._calc_VBM(self.occupancy, self.energies) self.fermi_energy = (self.CBM + self.VBM) / 2 self.dos = [] self.integrated_dos = [] self.check_data()
return to_return[ l ] if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument( '-i', '--ions', help='ion indices for band projection (default: sum over all ions)', nargs='+', type=int ) parser.add_argument( '-s', '--spins', help='spin indices for band projection (default [ 1 ])', nargs='+', type=int, default=[ 1 ] ) parser.add_argument( '-o', '--orbitals', help='orbital indices for band projection (default: sum over all orbitals)', nargs='+', type=int ) parser.add_argument( '-e', '--efermi', help='set fermi energy as reference for energy scale', type=float, default=0.0 ) parser.add_argument( '-l', '--l-angular-momentum', help='select all orbitals with angular momentum L for band projection. This supercedes the --orbitals option', choices=[ 's', 'p', 'd', 'f', 'all' ] ) parser.add_argument( '-f', '--procar', help='PROCAR filename (default PROCAR)', type=str, default='PROCAR' ) parser.add_argument( '--scaling', help='Energy scaling for band widths (default 0.2 eV)', type=float, default=0.2 ) parser.add_argument( '-x', '--xscaling', help='Automatic scaling of x-axis using reciprocal lattice vectors read from OUTCAR', action='store_true', default=False ) args = parser.parse_args() if args.l_angular_momentum: args.orbitals = orbitals_with_l( args.l_angular_momentum ) if args.xscaling: reciprocal_lattice = reciprocal_lattice_from_outcar( 'OUTCAR' ) # Move reading the reciprocal lattice to procar.py else: reciprocal_lattice = None pcar = procar.Procar() pcar.read_from_file( args.procar ) pcar.print_weighted_band_structure( spins = args.spins, ions = args.ions, orbitals = args.orbitals, scaling = args.scaling, e_fermi = args.efermi, reciprocal_lattice = reciprocal_lattice )