def test_init(self): test_dir = os.path.join(os.path.dirname(__file__), "..", "..", "..", "test_files") analysis = BaderAnalysis(os.path.join(test_dir, "CHGCAR.Fe3O4"), os.path.join(test_dir, "POTCAR.Fe3O4")) self.assertEqual(len(analysis.data), 14) self.assertAlmostEqual(analysis.data[0]["charge"], 6.1485) self.assertAlmostEqual(analysis.nelectrons, 96) self.assertAlmostEqual(analysis.vacuum_charge, 0) ans = [ -1.8515, -1.8132, -1.8132, -1.5562, -1.8132, -1.8515, 1.3369, 1.3378, 1.3373, 1.3374, 1.3374, 1.3369, 1.3373, 1.3378, ] for i in range(14): self.assertAlmostEqual(ans[i], analysis.get_charge_transfer(i)) s = analysis.get_oxidation_state_decorated_structure() self.assertAlmostEqual(s[0].specie.oxi_state, -1.8515)
def test_from_path(self): test_dir = os.path.join(PymatgenTest.TEST_FILES_DIR, "bader") analysis = BaderAnalysis.from_path(test_dir) chgcar = os.path.join(test_dir, "CHGCAR.gz") chgref = os.path.join(test_dir, "_CHGCAR_sum.gz") analysis0 = BaderAnalysis(chgcar_filename=chgcar, chgref_filename=chgref) charge = np.array(analysis.summary["charge"]) charge0 = np.array(analysis0.summary["charge"]) self.assertTrue(np.allclose(charge, charge0)) if os.path.exists("CHGREF"): os.remove("CHGREF")
def test_init(self): test_dir = os.path.join(os.path.dirname(__file__), "..", "..", "..", 'test_files') analysis = BaderAnalysis(os.path.join(test_dir, "CHGCAR.Fe3O4"), os.path.join(test_dir, "POTCAR.Fe3O4")) self.assertEqual(len(analysis.data), 14) self.assertAlmostEqual(analysis.data[0]["charge"], 6.1485) self.assertAlmostEqual(analysis.nelectrons, 96) self.assertAlmostEqual(analysis.vacuum_charge, 0) ans = [-1.8515, -1.8132, -1.8132, -1.5562, -1.8132, -1.8515, 1.3369, 1.3378, 1.3373, 1.3374, 1.3374, 1.3369, 1.3373, 1.3378] for i in range(14): self.assertAlmostEqual(ans[i], analysis.get_charge_transfer(i))
def test_atom_parsing(self): # test with reference file analysis = BaderAnalysis( chgcar_filename=os.path.join(PymatgenTest.TEST_FILES_DIR, "CHGCAR.Fe3O4"), potcar_filename=os.path.join(PymatgenTest.TEST_FILES_DIR, "POTCAR.Fe3O4"), chgref_filename=os.path.join(PymatgenTest.TEST_FILES_DIR, "CHGCAR.Fe3O4_ref"), parse_atomic_densities=True, ) self.assertEqual(len(analysis.atomic_densities), len(analysis.chgcar.structure)) self.assertAlmostEqual( np.sum(analysis.chgcar.data["total"]), np.sum([np.sum(d["data"]) for d in analysis.atomic_densities]), )
def from_files(cls, density_path, pseudopotential_paths, with_core=True, workdir=None, **kwargs): """ Uses the abinit density files and the bader_ executable from Henkelmann et al. to calculate the bader charges of the system. If pseudopotentials are given, the atomic charges will be extracted as well. See also :cite:`Henkelman2006`. The extraction of the core charges may be a time consuming calculation, depending on the size of the system. A tuning of the parameters may be required (see Density.ae_core_density_on_mesh). Args: density_path: Path to the abinit density file. Can be a fortran _DEN or a netCDF DEN.nc file. In case of fortran file, requires cut3d (version >= 8.6.1) for the convertion. pseudopotential_paths: Dictionary {element: pseudopotential path} for all the elements present in the system. with_core: Core charges will be extracted from the pseudopotentials with the Density.ae_core_density_on_mesh method. Requires pseudopotential_paths. workdir: Working directory. If None, a temporary directory is created. kwargs: arguments passed to the method ``Density.ae_core_density_on_mesh`` Returns: An instance of :class:`BaderCharges` """ # read the valence density # if density is not a netcdf file, convert with cut3d if not density_path.endswith('.nc'): dff = DensityFortranFile.from_file(density_path) density = dff.get_density() else: density = Density.from_file(density_path) structure = density.structure atomic_charges = None if with_core: if not pseudopotential_paths: raise ValueError("pseudopotentials should be provided to extract the core densities") try: from pseudo_dojo.ppcodes.oncvpsp import psp8_get_densities except ImportError as exc: print("PseudoDojo package required to extract core densities. " "Please install it with `pip install pseudo_dojo`") raise exc # extract core charge from pseudopotentials on a radial grid in the correct units rhoc = {} for specie, ppath in pseudopotential_paths.items(): r = psp8_get_densities(ppath) rhoc[specie] = [r.rmesh * bohr_to_angstrom, r.aecore / (4.0 * np.pi) / (bohr_to_angstrom ** 3)] workdir = tempfile.mkdtemp() if workdir is None else workdir # extrapolate the core density on the density grid core_density = Density.ae_core_density_on_mesh(density, structure, rhoc, **kwargs) density += core_density atomic_charges = [s.specie.Z for s in structure] elif pseudopotential_paths: pseudos = {k: Pseudo.from_file(p) for k, p in pseudopotential_paths.items()} atomic_charges = [pseudos[s.specie.name].Z_val for s in structure] chgcar_path = os.path.join(workdir, 'CHGCAR') density.to_chgcar(chgcar_path) ba = BaderAnalysis(chgcar_path) charges = [ba.get_charge(i) for i in range(len(structure))] return cls(charges, structure, atomic_charges)
def test_init(self): # test with reference file analysis = BaderAnalysis( chgcar_filename=os.path.join(PymatgenTest.TEST_FILES_DIR, "CHGCAR.Fe3O4"), potcar_filename=os.path.join(PymatgenTest.TEST_FILES_DIR, "POTCAR.Fe3O4"), chgref_filename=os.path.join(PymatgenTest.TEST_FILES_DIR, "CHGCAR.Fe3O4_ref"), ) self.assertEqual(len(analysis.data), 14) self.assertAlmostEqual(analysis.data[0]["charge"], 6.6136782, 3) self.assertEqual(analysis.data[0]["charge"], analysis.get_charge(0)) self.assertAlmostEqual(analysis.nelectrons, 96) self.assertAlmostEqual(analysis.vacuum_charge, 0) ans = [ -1.3863218, -1.3812175, -1.3812175, -1.2615902, -1.3812175, -1.3862971, 1.021523, 1.024357, 1.021523, 1.021523, 1.021523, 1.021523, 1.021523, 1.024357, ] for i in range(14): self.assertAlmostEqual(ans[i], analysis.get_charge_transfer(i), 3) self.assertEqual(analysis.get_partial_charge(0), -analysis.get_charge_transfer(0)) s = analysis.get_oxidation_state_decorated_structure() self.assertAlmostEqual(s[0].specie.oxi_state, 1.3863218, 3) # make sure bader still runs without reference file analysis = BaderAnalysis(chgcar_filename=os.path.join( PymatgenTest.TEST_FILES_DIR, "CHGCAR.Fe3O4")) self.assertEqual(len(analysis.data), 14) # Test Cube file format parsing analysis = BaderAnalysis(cube_filename=os.path.join( PymatgenTest.TEST_FILES_DIR, "bader/elec.cube.gz")) self.assertEqual(len(analysis.data), 9)
These two charge density files can be summed using the chgsum.pl script: chgsum.pl AECCAR0 AECCAR2 The total charge will be written to CHGCAR_sum. The bader analysis can then be done on this total charge density file: bader CHGCAR -ref CHGCAR_sum One finally note is that you need a fine fft grid to accurately reproduce the correct total core charge. It is essential to do a few calculations, increasing NG(X,Y,Z)F until the total charge is correct. """ ba = BaderAnalysis( 'CHGCAR', 'POTCAR') # this is a good example for running code and capturing stdout # print(ba.get_charge(1)) from ocelot.routines.pbc import PBCparser from pymatgen.core.structure import Structure struct = Structure.from_file('CONTCAR') mols, unwrap_str_sorted, unwrap_pblock_list = PBCparser.unwrap(struct) def parse_acf(acfdata_fn='./ACF.dat'): acfdata = [] with open(acfdata_fn, 'r') as f: ls = f.readlines() for l in ls[2:-4]: