示例#1
0
    def test_soc_chgcar(self):

        filepath = os.path.join(test_dir, "CHGCAR.NiO_SOC.gz")
        chg = Chgcar.from_file(filepath)
        self.assertEqual(set(chg.data.keys()),
                         {'total', 'diff_x', 'diff_y', 'diff_z', 'diff'})
        self.assertTrue(chg.is_soc)
        self.assertEqual(chg.data['diff'].shape, chg.data['diff_y'].shape)

        # check our construction of chg.data['diff'] makes sense
        # this has been checked visually too and seems reasonable
        self.assertEqual(
            abs(chg.data['diff'][0][0][0]),
            np.linalg.norm([
                chg.data['diff_x'][0][0][0], chg.data['diff_y'][0][0][0],
                chg.data['diff_z'][0][0][0]
            ]))

        # and that the net magnetization is about zero
        # note: we get ~ 0.08 here, seems a little high compared to
        # vasp output, but might be due to chgcar limitations?
        self.assertAlmostEqual(chg.net_magnetization, 0.0, places=0)

        chg.write_file("CHGCAR_pmg_soc")
        chg_from_file = Chgcar.from_file("CHGCAR_pmg_soc")
        self.assertTrue(chg_from_file.is_soc)
        os.remove("CHGCAR_pmg_soc")
示例#2
0
文件: fields.py 项目: gmatteo/abipy
    def to_chgcar(self, filename=None):
        """
        Convert a :class:`Density` object into a ``Chgar`` object.
        If ``filename`` is not None, density is written to this file in Chgar format

        Return:
            :class:`Chgcar` instance.

        .. note::

            From: http://cms.mpi.univie.ac.at/vasp/vasp/CHGCAR_file.html:

            This file contains the total charge density multiplied by the volume
            For spinpolarized calculations, two sets of data can be found in the CHGCAR file.
            The first set contains the total charge density (spin up plus spin down),
            the second one the magnetization density (spin up minus spin down).
            For non collinear calculations the CHGCAR file contains the total charge density
            and the magnetisation density in the x, y and z direction in this order.
        """
        myrhor = self.datar * self.structure.volume

        if self.nspinor == 1:
            if self.nsppol == 1:
                data_dict = {"total": myrhor[0]}
            if self.nsppol == 2:
                data_dict = {"total": myrhor[0] + myrhor[1], "diff": myrhor[0] - myrhor[1]}

        elif self.nspinor == 2:
            raise NotImplementedError("pymatgen Chgcar does not implement nspinor == 2")

        chgcar = Chgcar(Poscar(self.structure), data_dict)
        if filename is not None:
            chgcar.write_file(filename)

        return chgcar
示例#3
0
    def test_writestate_ncl(self):
        print("TEST WRITE NCL")
        sys.stdout.flush()
        from pymatgen.io.vasp.outputs import Chgcar

        wf = NCLWavefunction.from_directory("noncollinear")
        fileprefix = ""
        b, k, s = 10, 1, 0
        state1, state2 = wf.write_state_realspace(b, k, s, fileprefix="")
        state1, state2 = wf.write_state_realspace(b,
                                                  k,
                                                  s,
                                                  fileprefix="",
                                                  dim=np.array([30, 30, 30]))
        assert state1.shape[0] == 30
        assert state1.shape[1] == 30
        assert state1.shape[2] == 30
        assert state1.dtype == np.complex128
        filename_base = "%sB%dK%dS%d" % (fileprefix, b, k, s)
        filename1 = "%s_UP_REAL.vasp" % filename_base
        filename2 = "%s_UP_IMAG.vasp" % filename_base
        filename3 = "%s_DOWN_REAL.vasp" % filename_base
        filename4 = "%s_DOWN_IMAG.vasp" % filename_base
        chg1 = Chgcar.from_file(filename1)
        chg2 = Chgcar.from_file(filename2)
        chg3 = Chgcar.from_file(filename3)
        chg4 = Chgcar.from_file(filename4)
        upart = chg1.data["total"]**2 + chg2.data["total"]**2
        dpart = chg3.data["total"]**2 + chg4.data["total"]**2
        vol = chg1.poscar.structure.volume
        assert_almost_equal(np.sum((upart + dpart) * vol / 30**3), 1, 2)
        os.remove(filename1)
        os.remove(filename2)
        os.remove(filename3)
        os.remove(filename4)
示例#4
0
    def from_path(cls, path, suffix="", zpsp=None):
        """
        Convenience method to run critic2 analysis on a folder containing
        typical VASP output files.
        This method will:

        1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped
        counterparts.

        2. If AECCAR* files are present, constructs a temporary reference
        file as AECCAR0 + AECCAR2.

        3. Runs critic2 analysis twice: once for charge, and a second time
        for the charge difference (magnetization density).

        :param path: path to folder to search in
        :param suffix: specific suffix to look for (e.g. '.relax1' for
            'CHGCAR.relax1.gz')
        :param zpsp: manually specify ZPSP if POTCAR not present
        :return:
        """

        chgcar_path = get_filepath("CHGCAR", "Could not find CHGCAR!", path, suffix)
        chgcar = Chgcar.from_file(chgcar_path)
        chgcar_ref = None

        if not zpsp:

            potcar_path = get_filepath(
                "POTCAR",
                "Could not find POTCAR, will not be able to calculate charge transfer.",
                path,
                suffix,
            )

            if potcar_path:
                potcar = Potcar.from_file(potcar_path)
                zpsp = {p.element: p.zval for p in potcar}

        if not zpsp:
            # try and get reference "all-electron-like" charge density if zpsp not present
            aeccar0_path = get_filepath(
                "AECCAR0",
                "Could not find AECCAR0, interpret Bader results with caution.",
                path,
                suffix,
            )
            aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None

            aeccar2_path = get_filepath(
                "AECCAR2",
                "Could not find AECCAR2, interpret Bader results with caution.",
                path,
                suffix,
            )
            aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None

            chgcar_ref = aeccar0.linear_add(aeccar2) if (aeccar0 and aeccar2) else None

        return cls(chgcar.structure, chgcar, chgcar_ref, zpsp=zpsp)
示例#5
0
    def from_path(cls, path, suffix=""):
        """
        Convenient constructor that takes in the path name of VASP run
        to perform Bader analysis.

        Args:
            path (str): Name of directory where VASP output files are
                stored.
            suffix (str): specific suffix to look for (e.g. '.relax1'
                for 'CHGCAR.relax1.gz').

        """
        def _get_filepath(filename):
            name_pattern = (filename + suffix +
                            "*" if filename != "POTCAR" else filename + "*")
            paths = glob.glob(os.path.join(path, name_pattern))
            fpath = None
            if len(paths) >= 1:
                # using reverse=True because, if multiple files are present,
                # they likely have suffixes 'static', 'relax', 'relax2', etc.
                # and this would give 'static' over 'relax2' over 'relax'
                # however, better to use 'suffix' kwarg to avoid this!
                paths.sort(reverse=True)
                warning_msg = ("Multiple files detected, using %s" %
                               os.path.basename(paths[0])
                               if len(paths) > 1 else None)
                fpath = paths[0]
            else:
                warning_msg = "Could not find %s" % filename
                if filename in ["AECCAR0", "AECCAR2"]:
                    warning_msg += ", cannot calculate charge transfer."
                elif filename == "POTCAR":
                    warning_msg += ", interpret Bader results with caution."
            if warning_msg:
                warnings.warn(warning_msg)
            return fpath

        chgcar_filename = _get_filepath("CHGCAR")
        if chgcar_filename is None:
            raise IOError("Could not find CHGCAR!")
        potcar_filename = _get_filepath("POTCAR")
        aeccar0 = _get_filepath("AECCAR0")
        aeccar2 = _get_filepath("AECCAR2")
        if aeccar0 and aeccar2:
            # `chgsum.pl AECCAR0 AECCAR2` equivalent to obtain chgref_file
            chgref = Chgcar.from_file(aeccar0) + Chgcar.from_file(aeccar2)
            chgref_filename = "CHGREF"
            chgref.write_file(chgref_filename)
        else:
            chgref_filename = None
        return cls(
            chgcar_filename=chgcar_filename,
            potcar_filename=potcar_filename,
            chgref_filename=chgref_filename,
        )
示例#6
0
    def from_path(cls, path, suffix=''):
        """
        Convenience method to run critic2 analysis on a folder containing
        typical VASP output files.
        This method will:

        1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped
        counterparts.

        2. If AECCAR* files are present, constructs a temporary reference
        file as AECCAR0 + AECCAR2.

        3. Runs critic2 analysis twice: once for charge, and a second time
        for the charge difference (magnetization density).

        :param path: path to folder to search in
        :param suffix: specific suffix to look for (e.g. '.relax1' for
            'CHGCAR.relax1.gz')
        :return:
        """
        def _get_filepath(filename, warning, path=path, suffix=suffix):
            paths = glob.glob(os.path.join(path, filename + suffix + '*'))
            if not paths:
                warnings.warn(warning)
                return None
            if len(paths) > 1:
                # using reverse=True because, if multiple files are present,
                # they likely have suffixes 'static', 'relax', 'relax2', etc.
                # and this would give 'static' over 'relax2' over 'relax'
                # however, better to use 'suffix' kwarg to avoid this!
                paths.sort(reverse=True)
                warnings.warn('Multiple files detected, using {}'.format(
                    os.path.basename(path)))
            path = paths[0]
            return path

        chgcar_path = _get_filepath('CHGCAR', 'Could not find CHGCAR!')
        chgcar = Chgcar.from_file(chgcar_path)

        aeccar0_path = _get_filepath(
            'AECCAR0',
            'Could not find AECCAR0, interpret Bader results with caution.')
        aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None

        aeccar2_path = _get_filepath(
            'AECCAR2',
            'Could not find AECCAR2, interpret Bader results with caution.')
        aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None

        chgcar_ref = aeccar0.linear_add(aeccar2) if (aeccar0
                                                     and aeccar2) else None

        return cls(chgcar.structure, chgcar, chgcar_ref)
示例#7
0
    def from_path(cls, path, suffix=""):
        """
        Convenient constructor that takes in the path name of VASP run
        to perform Bader analysis.

        Args:
            path (str): Name of directory where VASP output files are
                stored.
            suffix (str): specific suffix to look for (e.g. '.relax1'
                for 'CHGCAR.relax1.gz').

        """

        def _get_filepath(filename):
            name_pattern = filename + suffix + '*' if filename != 'POTCAR' \
                else filename + '*'
            paths = glob.glob(os.path.join(path, name_pattern))
            fpath = None
            if len(paths) >= 1:
                # using reverse=True because, if multiple files are present,
                # they likely have suffixes 'static', 'relax', 'relax2', etc.
                # and this would give 'static' over 'relax2' over 'relax'
                # however, better to use 'suffix' kwarg to avoid this!
                paths.sort(reverse=True)
                warning_msg = "Multiple files detected, using %s" \
                              % os.path.basename(paths[0]) if len(paths) > 1 \
                    else None
                fpath = paths[0]
            else:
                warning_msg = "Could not find %s" % filename
                if filename in ['AECCAR0', 'AECCAR2']:
                    warning_msg += ", cannot calculate charge transfer."
                elif filename == "POTCAR":
                    warning_msg += ", interpret Bader results with caution."
            if warning_msg:
                warnings.warn(warning_msg)
            return fpath

        chgcar_filename = _get_filepath("CHGCAR")
        if chgcar_filename is None:
            raise IOError("Could not find CHGCAR!")
        potcar_filename = _get_filepath("POTCAR")
        aeccar0 = _get_filepath("AECCAR0")
        aeccar2 = _get_filepath("AECCAR2")
        if (aeccar0 and aeccar2):
            # `chgsum.pl AECCAR0 AECCAR2` equivalent to obtain chgref_file
            chgref = Chgcar.from_file(aeccar0) + Chgcar.from_file(aeccar2)
            chgref_filename = "CHGREF"
            chgref.write_file(chgref_filename)
        else:
            chgref_filename = None
        return cls(chgcar_filename, potcar_filename=potcar_filename,
                   chgref_filename=chgref_filename)
示例#8
0
def bader_analysis_from_path(path, suffix=""):
    """
    Convenience method to run Bader analysis on a folder containing
    typical VASP output files.

    This method will:

    1. Look for files CHGCAR, AECCAR0, AECCAR2, POTCAR or their gzipped
    counterparts.
    2. If AECCAR* files are present, constructs a temporary reference
    file as AECCAR0 + AECCAR2
    3. Runs Bader analysis twice: once for charge, and a second time
    for the charge difference (magnetization density).

    :param path: path to folder to search in
    :param suffix: specific suffix to look for (e.g. '.relax1' for 'CHGCAR.relax1.gz'
    :return: summary dict
    """
    def _get_filepath(filename, warning, path=path, suffix=suffix):
        paths = glob.glob(os.path.join(path, filename + suffix + "*"))
        if not paths:
            warnings.warn(warning)
            return None
        if len(paths) > 1:
            # using reverse=True because, if multiple files are present,
            # they likely have suffixes 'static', 'relax', 'relax2', etc.
            # and this would give 'static' over 'relax2' over 'relax'
            # however, better to use 'suffix' kwarg to avoid this!
            paths.sort(reverse=True)
            warnings.warn(
                f"Multiple files detected, using {os.path.basename(path)}")
        path = paths[0]
        return path

    chgcar_path = _get_filepath("CHGCAR", "Could not find CHGCAR!")
    chgcar = Chgcar.from_file(chgcar_path)

    aeccar0_path = _get_filepath(
        "AECCAR0",
        "Could not find AECCAR0, interpret Bader results with caution.")
    aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None

    aeccar2_path = _get_filepath(
        "AECCAR2",
        "Could not find AECCAR2, interpret Bader results with caution.")
    aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None

    potcar_path = _get_filepath(
        "POTCAR", "Could not find POTCAR, cannot calculate charge transfer.")
    potcar = Potcar.from_file(potcar_path) if potcar_path else None

    return bader_analysis_from_objects(chgcar, potcar, aeccar0, aeccar2)
示例#9
0
 def setUp(self):
     # This is a CHGCAR_sum file with reduced grid size
     chgcar_path = os.path.join(test_dir, "CHGCAR.FePO4")
     chg_FePO4 = Chgcar.from_file(chgcar_path)
     self.chgcar_path = chgcar_path
     self.chg_FePO4 = chg_FePO4
     self.cia_FePO4 = ChargeInsertionAnalyzer(chg_FePO4)
示例#10
0
    def test_init(self):
        filepath = os.path.join(test_dir, "CHGCAR.nospin")
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 2)[0, 1], 0)
        filepath = os.path.join(test_dir, "CHGCAR.spin")
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1], -0.0043896932237534022)
        # test sum
        chg += chg
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1], -0.0043896932237534022 * 2)

        filepath = os.path.join(test_dir, "CHGCAR.Fe3O4")
        chg = Chgcar.from_file(filepath)
        ans = [1.93313368, 3.91201473, 4.11858277, 4.1240093, 4.10634989, 3.38864822]
        myans = chg.get_integrated_diff(0, 3, 6)
        self.assertTrue(np.allclose(myans[:, 1], ans))
示例#11
0
def bader_analysis_from_path(path, suffix=''):
    """
    Convenience method to run Bader analysis on a folder containing
    typical VASP output files.

    This method will:

    1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped
    counterparts.
    2. If AECCAR* files are present, constructs a temporary reference
    file as AECCAR0 + AECCAR2
    3. Runs Bader analysis twice: once for charge, and a second time
    for the charge difference (magnetization density).

    :param path: path to folder to search in
    :param suffix: specific suffix to look for (e.g. '.relax1' for 'CHGCAR.relax1.gz'
    :return: summary dict
    """

    def _get_filepath(filename, warning, path=path, suffix=suffix):
        paths = glob.glob(os.path.join(path, filename + suffix + '*'))
        if not paths:
            warnings.warn(warning)
            return None
        if len(paths) > 1:
            # using reverse=True because, if multiple files are present,
            # they likely have suffixes 'static', 'relax', 'relax2', etc.
            # and this would give 'static' over 'relax2' over 'relax'
            # however, better to use 'suffix' kwarg to avoid this!
            paths.sort(reverse=True)
            warnings.warn('Multiple files detected, using {}'.format(os.path.basename(path)))
        path = paths[0]
        return path

    chgcar_path = _get_filepath('CHGCAR', 'Could not find CHGCAR!')
    chgcar = Chgcar.from_file(chgcar_path)

    aeccar0_path = _get_filepath('AECCAR0', 'Could not find AECCAR0, interpret Bader results with caution.')
    aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None

    aeccar2_path = _get_filepath('AECCAR2', 'Could not find AECCAR2, interpret Bader results with caution.')
    aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None

    potcar_path = _get_filepath('POTCAR', 'Could not find POTCAR, cannot calculate charge transfer.')
    potcar = Potcar.from_file(potcar_path) if potcar_path else None

    return bader_analysis_from_objects(chgcar, potcar, aeccar0, aeccar2)
示例#12
0
 def setUp(self):
     # This is a CHGCAR_sum file with reduced grid size
     chgcar_path = os.path.join(test_dir, "CHGCAR.FePO4")
     chg_FePO4 = Chgcar.from_file(chgcar_path)
     self.chgcar_path = chgcar_path
     self.chg_FePO4 = chg_FePO4
     self.ca_FePO4 = ChargeDensityAnalyzer(chg_FePO4)
     self.s_LiFePO4 = Structure.from_file(os.path.join(test_dir, "LiFePO4.cif"))
示例#13
0
 def setUp(self):
     # This is a CHGCAR_sum file with reduced grid size
     chgcar_path = os.path.join(test_dir, "CHGCAR.FePO4")
     chg_FePO4 = Chgcar.from_file(chgcar_path)
     self.chgcar_path = chgcar_path
     self.chg_FePO4 = chg_FePO4
     self.ca_FePO4 = ChargeDensityAnalyzer(chg_FePO4)
     self.s_LiFePO4 = Structure.from_file(os.path.join(test_dir, "LiFePO4.cif"))
示例#14
0
	def test_density(self):
		print("TEST DENSITY")
		sys.stdout.flush()
		wf = Wavefunction.from_directory('nosym')
		#wf = wf.desymmetrized_copy()
		wf.write_density_realspace(dim=np.array([40,40,40]), scale = wf.structure.lattice.volume)
		tstchg = Chgcar.from_file("AECCAR2").data['total']# / wf.structure.volume
		chg = Chgcar.from_file("PYAECCAR").data['total']
		reldiff = np.sqrt(np.mean(((chg-tstchg)/tstchg)**2))
		newchg = chg-tstchg
		Chgcar(Poscar(wf.structure), {'total': newchg}).write_file('DIFFCHGCAR.vasp')
		print(np.sum(chg)/40**3, np.sum(tstchg)/40**3)
		assert_almost_equal(reldiff, 0, decimal=2)
		wf = Wavefunction.from_directory('nosym')
		res = wf.write_density_realspace(filename="BAND4DENS", bands=4)
		#os.remove('PYAECCAR')
		print("DENS shape", res.shape)
		assert_almost_equal(np.sum(res)*wf.structure.lattice.volume/np.cumprod(res.shape)[-1], 1, 4)
示例#15
0
	def test_density_ncl(self):
		print("TEST DENSITY NCL")
		sys.stdout.flush()
		print("LOAD WAVEFUNCTION")
		sys.stdout.flush()
		wf = NCLWavefunction.from_directory('noncollinear')
		print("FINISHED LOAD WAVEFUNCTION")
		sys.stdout.flush()
		#wf = wf.desymmetrized_copy()
		wf.write_density_realspace(scale = wf.structure.lattice.volume)
		wf.write_density_realspace(dim=np.array([40,40,40]), scale = wf.structure.lattice.volume)
		tstchg = Chgcar.from_file("AECCAR2").data['total']# / wf.structure.volume
		chg = Chgcar.from_file("PYAECCAR").data['total']
		reldiff = np.sqrt(np.mean(((chg-tstchg)/tstchg)**2))
		newchg = chg-tstchg
		Chgcar(Poscar(wf.structure), {'total': newchg}).write_file('DIFFCHGCAR.vasp')
		print(np.sum(chg)/40**3, np.sum(tstchg)/40**3)
		assert_almost_equal(reldiff, 0, decimal=3)
示例#16
0
    def test_init(self):
        filepath = os.path.join(test_dir, 'CHGCAR.nospin')
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 2)[0, 1], 0)
        filepath = os.path.join(test_dir, 'CHGCAR.spin')
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1],
                               -0.0043896932237534022)
        #test sum
        chg += chg
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1],
                               -0.0043896932237534022 * 2)

        filepath = os.path.join(test_dir, 'CHGCAR.Fe3O4')
        chg = Chgcar.from_file(filepath)
        ans = [1.56472768, 3.25985108, 3.49205728, 3.66275028, 3.8045896, 5.10813352]
        myans = chg.get_integrated_diff(0, 3, 6)
        self.assertTrue(np.allclose(myans[:, 1], ans))
示例#17
0
    def test_init(self):
        filepath = os.path.join(test_dir, 'CHGCAR.nospin')
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 2)[0, 1], 0)
        filepath = os.path.join(test_dir, 'CHGCAR.spin')
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1],
                               -0.0043896932237534022)
        #test sum
        chg += chg
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1],
                               -0.0043896932237534022 * 2)

        filepath = os.path.join(test_dir, 'CHGCAR.Fe3O4')
        chg = Chgcar.from_file(filepath)
        ans = [1.56472768, 3.25985108, 3.49205728, 3.66275028, 3.8045896, 5.10813352]
        myans = chg.get_integrated_diff(0, 3, 6)
        self.assertTrue(np.allclose(myans[:, 1], ans))
示例#18
0
    def test_init(self):
        filepath = os.path.join(test_dir, 'CHGCAR.nospin')
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 2)[0, 1], 0)
        filepath = os.path.join(test_dir, 'CHGCAR.spin')
        chg = Chgcar.from_file(filepath)
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1],
                               -0.0043896932237534022)
        #test sum
        chg += chg
        self.assertAlmostEqual(chg.get_integrated_diff(0, 1)[0, 1],
                               -0.0043896932237534022 * 2)

        filepath = os.path.join(test_dir, 'CHGCAR.Fe3O4')
        chg = Chgcar.from_file(filepath)
        ans = [1.93313368, 3.91201473, 4.11858277, 4.1240093, 4.10634989,
               3.38864822]
        myans = chg.get_integrated_diff(0, 3, 6)
        self.assertTrue(np.allclose(myans[:, 1], ans))
示例#19
0
    def to_chgcar(self, filename=None):
        from pymatgen.io.vasp.inputs import Poscar
        from pymatgen.io.vasp.outputs import Chgcar

        # From: http://cms.mpi.univie.ac.at/vasp/vasp/CHGCAR_file.html
        # This file contains the total charge density multiplied by the volume
        # For spinpolarized calculations, two sets of data can be found in the CHGCAR file.
        # The first set contains the total charge density (spin up plus spin down),
        # the second one the magnetization density (spin up minus spin down).
        # For non collinear calculations the CHGCAR file contains the total charge density
        # and the magnetisation density in the x, y and z direction in this order.
        myrhor = self.datar * self.structure.volume
        data_dict = {"total": myrhor[0]}
        if self.nsppol == 2: {"diff": myrhor[0] - myrhor[1]}
        if self.nspinor == 2: raise NotImplementedError("pymatgen Chgcar does not implement nspinor == 2")

        chgcar = Chgcar(Poscar(self.structure), data_dict)
        if filename is not None: chgcar.write_file(filename)
        return chgcar
示例#20
0
 def test_write(self):
     filepath = os.path.join(test_dir, 'CHGCAR.spin')
     chg = Chgcar.from_file(filepath)
     chg.write_file("CHGCAR_pmg")
     with open("CHGCAR_pmg") as f:
         for i, line in enumerate(f):
             if i == 22130:
                 self.assertEqual("augmentation occupancies   1  15\n", line)
             if i == 44255:
                 self.assertEqual("augmentation occupancies   1  15\n", line)
     os.remove("CHGCAR_pmg")
示例#21
0
 def test_write(self):
     filepath = os.path.join(test_dir, 'CHGCAR.spin')
     chg = Chgcar.from_file(filepath)
     chg.write_file("CHGCAR_pmg")
     with open("CHGCAR_pmg") as f:
         for i, line in enumerate(f):
             if i == 22130:
                 self.assertEqual("augmentation occupancies   1  15\n", line)
             if i == 44255:
                 self.assertEqual("augmentation occupancies   1  15\n", line)
     os.remove("CHGCAR_pmg")
示例#22
0
def bader_analysis_from_path(path, suffix=''):
    """
    Convenience method to run Bader analysis on a folder containing
    typical VASP output files.

    This method will:

    1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped
    counterparts.
    2. If AECCAR* files are present, constructs a temporary reference
    file as AECCAR0 + AECCAR2
    3. Runs Bader analysis twice: once for charge, and a second time
    for the charge difference (magnetization density).

    :param path: path to folder to search in
    :param suffix: specific suffix to look for (e.g. '.relax1' for 'CHGCAR.relax1.gz'
    :return: summary dict
    """

    chgcar_path = get_filepath('CHGCAR', 'Could not find CHGCAR!', path,
                               suffix)
    chgcar = Chgcar.from_file(chgcar_path)

    aeccar0_path = get_filepath(
        'AECCAR0',
        'Could not find AECCAR0, interpret Bader results with caution.', path,
        suffix)
    aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None

    aeccar2_path = get_filepath(
        'AECCAR2',
        'Could not find AECCAR2, interpret Bader results with caution.', path,
        suffix)
    aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None

    potcar_path = get_filepath(
        'POTCAR', 'Could not find POTCAR, cannot calculate charge transfer.',
        path, suffix)
    potcar = Potcar.from_file(potcar_path) if potcar_path else None

    return bader_analysis_from_objects(chgcar, potcar, aeccar0, aeccar2)
示例#23
0
    def _load_parchg(self):
        if self.preloaded_data:
            with open(os.path.join(self.folder, 'parchg.npy'), 'rb') as p:
                data = np.load(p)
        else:
            parchg = Chgcar.from_file(os.path.join(self.folder, 'PARCHG'))
            data = parchg.data['total']
            np.save(os.path.join(self.folder, 'parchg.npy'), data)

        a_vals = np.linspace(0, 1, data.shape[0])
        b_vals = np.linspace(0, 1, data.shape[1])
        c_vals = np.linspace(0, 1, data.shape[2])

        return data, a_vals, b_vals, c_vals
示例#24
0
    def test_soc_chgcar(self):

        filepath = os.path.join(test_dir, "CHGCAR.NiO_SOC.gz")
        chg = Chgcar.from_file(filepath)
        self.assertEqual(set(chg.data.keys()), {'total', 'diff_x', 'diff_y', 'diff_z', 'diff'})
        self.assertTrue(chg.is_soc)
        self.assertEqual(chg.data['diff'].shape, chg.data['diff_y'].shape)

        # check our construction of chg.data['diff'] makes sense
        # this has been checked visually too and seems reasonable
        self.assertEqual(abs(chg.data['diff'][0][0][0]),
                         np.linalg.norm([chg.data['diff_x'][0][0][0],
                                         chg.data['diff_y'][0][0][0],
                                         chg.data['diff_z'][0][0][0]]))

        # and that the net magnetization is about zero
        # note: we get ~ 0.08 here, seems a little high compared to
        # vasp output, but might be due to chgcar limitations?
        self.assertAlmostEqual(chg.net_magnetization, 0.0, places=0)

        chg.write_file("CHGCAR_pmg_soc")
        chg_from_file = Chgcar.from_file("CHGCAR_pmg_soc")
        self.assertTrue(chg_from_file.is_soc)
        os.remove("CHGCAR_pmg_soc")
示例#25
0
    def test_hdf5(self):
        chgcar = Chgcar.from_file(os.path.join(test_dir, "CHGCAR.NiO_SOC.gz"))
        chgcar.to_hdf5("chgcar_test.hdf5")
        import h5py
        with h5py.File("chgcar_test.hdf5", "r") as f:
            self.assertArrayAlmostEqual(np.array(f["vdata"]["total"]),
                                        chgcar.data["total"])
            self.assertArrayAlmostEqual(np.array(f["vdata"]["diff"]),
                                        chgcar.data["diff"])
            self.assertArrayAlmostEqual(np.array(f["lattice"]),
                                        chgcar.structure.lattice.matrix)
            self.assertArrayAlmostEqual(np.array(f["fcoords"]),
                                        chgcar.structure.frac_coords)
            for z in f["Z"]:
                self.assertIn(z, [Element.Ni.Z, Element.O.Z])

            for sp in f["species"]:
                self.assertIn(sp, ["Ni", "O"])

        chgcar2 = Chgcar.from_hdf5("chgcar_test.hdf5")
        self.assertArrayAlmostEqual(chgcar2.data["total"],
                                    chgcar.data["total"])

        os.remove("chgcar_test.hdf5")
示例#26
0
    def __init__(self, chgcar_filename, potcar_filename=None):
        """
        Initializes the Bader caller.

        Args:
            chgcar_filename: The filename of the CHGCAR.
            potcar_filename: Optional: the filename of the corresponding
                POTCAR file. Used for calculating the charge transfer. If
                None, the get_charge_transfer method will raise a ValueError.
        """
        self.chgcar = Chgcar.from_file(chgcar_filename)
        self.potcar = Potcar.from_file(potcar_filename) \
            if potcar_filename is not None else None
        self.natoms = self.chgcar.poscar.natoms
        chgcarpath = os.path.abspath(chgcar_filename)

        with ScratchDir(".") as temp_dir:
            shutil.copy(chgcarpath, os.path.join(temp_dir, "CHGCAR"))

            rs = subprocess.Popen(["bader", "CHGCAR"],
                                  stdout=subprocess.PIPE,
                                  stdin=subprocess.PIPE, close_fds=True)
            rs.communicate()
            if rs.returncode != 0:
                raise RuntimeError("bader exited with return code %d. "
                                   "Pls check your bader installation."
                                   % rs.returncode)
            data = []
            with open("ACF.dat") as f:
                raw = f.readlines()
                headers = [s.lower() for s in raw.pop(0).split()]
                raw.pop(0)
                while True:
                    l = raw.pop(0).strip()
                    if l.startswith("-"):
                        break
                    vals = map(float, l.split()[1:])
                    data.append(dict(zip(headers[1:], vals)))
                for l in raw:
                    toks = l.strip().split(":")
                    if toks[0] == "VACUUM CHARGE":
                        self.vacuum_charge = float(toks[1])
                    elif toks[0] == "VACUUM VOLUME":
                        self.vacuum_volume = float(toks[1])
                    elif toks[0] == "NUMBER OF ELECTRONS":
                        self.nelectrons = float(toks[1])
            self.data = data
示例#27
0
文件: fields.py 项目: gmatteo/abipy
    def from_chgcar_poscar(cls, chgcar, poscar):
        """
        Build a :class`Density` object from Vasp data.

        Args:
            chgcar: Either string with the name of a CHGCAR file or :class:`Chgcar` pymatgen object.
            poscar: Either string with the name of a POSCAR file or :class:`Poscar` pymatgen object.

        .. warning:

            The present version does not support non-collinear calculations.
            The Chgcar object provided by pymatgen does not provided enough information
            to understand if the calculation is collinear or no.
        """
        if is_string(chgcar):
            chgcar = Chgcar.from_file(chgcar)
        if is_string(poscar):
            poscar = Poscar.from_file(poscar, check_for_POTCAR=False, read_velocities=False)

        nx, ny, nz = chgcar.dim
        nspinor = 1
        nsppol = 2 if chgcar.is_spin_polarized else 1
        nspden = 2 if nsppol == 2 else 1

        # Convert pymatgen chgcar data --> abipy representation.
        abipy_datar = np.empty((nspden, nx, ny, nz))

        if nspinor == 1:
            if nsppol == 1:
                abipy_datar = chgcar.data["total"]
            elif nsppol == 2:
                total, diff = chgcar.data["total"], chgcar.data["diff"]
                abipy_datar[0] = 0.5 * (total + diff)
                abipy_datar[1] = 0.5 * (total - diff)
            else:
                raise ValueError("Wrong nspden %s" % nspden)

        else:
            raise NotImplementedError("nspinor == 2 requires more info in Chgcar")

        # density in Chgcar is multiplied by volume!
        abipy_datar /= poscar.structure.volume

        return cls(nspinor=nspinor, nsppol=nsppol, nspden=nspden, datar=abipy_datar,
                   structure=poscar.structure, iorder="c")
示例#28
0
        def callback_update_structure(contents, filename, last_modified):

            if not contents:
                raise PreventUpdate

            # assume we only want the first input for now
            content_type, content_string = contents.split(",")
            decoded_contents = b64decode(content_string)

            error = None
            data = None

            # necessary to write to file so pymatgen's filetype detection can work
            with NamedTemporaryFile(suffix=filename) as tmp:
                tmp.write(decoded_contents)
                tmp.flush()
                try:
                    struct_or_mol = Structure.from_file(tmp.name)
                    data = self.to_data(struct_or_mol)
                except:
                    try:
                        struct_or_mol = Molecule.from_file(tmp.name)
                        data = self.to_data(struct_or_mol)
                    except:
                        try:
                            struct_or_mol = Chgcar.from_file(tmp.name)
                        except:
                            # TODO: fix these horrible try/excepts, loadfn may be dangerous
                            try:
                                struct_or_mol = loadfn(tmp.name)
                                data = self.to_data(struct_or_mol)
                            except:
                                error = (
                                    "Could not parse uploaded file. "
                                    "If this seems like a bug, please report it. "
                                    "Crystal Toolkit understands all crystal "
                                    "structure file types and molecule file types "
                                    "supported by pymatgen.")

            return {
                "data": data,
                "error": error,
                "time_requested": self.get_time()
            }
示例#29
0
    def __init__(self, chgcar_filename, potcar_filename=None):
        """
        Initializes the Bader caller.

        Args:
            chgcar_filename: The filename of the CHGCAR.
            potcar_filename: Optional: the filename of the corresponding
                POTCAR file. Used for calculating the charge transfer. If
                None, the get_charge_transfer method will raise a ValueError.
        """
        self.chgcar = Chgcar.from_file(chgcar_filename)
        self.potcar = Potcar.from_file(potcar_filename) \
            if potcar_filename is not None else None
        self.natoms = self.chgcar.poscar.natoms
        chgcarpath = os.path.abspath(chgcar_filename)

        with ScratchDir(".") as temp_dir:
            shutil.copy(chgcarpath, os.path.join(temp_dir, "CHGCAR"))

            rs = subprocess.Popen(["bader", "CHGCAR"],
                                  stdout=subprocess.PIPE,
                                  stdin=subprocess.PIPE,
                                  close_fds=True)
            rs.communicate()
            data = []
            with open("ACF.dat") as f:
                raw = f.readlines()
                headers = [s.lower() for s in raw.pop(0).split()]
                raw.pop(0)
                while True:
                    l = raw.pop(0).strip()
                    if l.startswith("-"):
                        break
                    vals = map(float, l.split()[1:])
                    data.append(dict(zip(headers[1:], vals)))
                for l in raw:
                    toks = l.strip().split(":")
                    if toks[0] == "VACUUM CHARGE":
                        self.vacuum_charge = float(toks[1])
                    elif toks[0] == "VACUUM VOLUME":
                        self.vacuum_volume = float(toks[1])
                    elif toks[0] == "NUMBER OF ELECTRONS":
                        self.nelectrons = float(toks[1])
            self.data = data
示例#30
0
文件: stm_sim.py 项目: kvs11/simstm
    def __init__(self, filename):
        """
        Reads PARCHG file and make class attributes
        """
        self.filename = filename
        self.parchg = Chgcar.from_file(filename)

        # charge data from CHGCAR
        self.chgdata = self.parchg.data['total']

        # structure associated w/ volumetric data
        self.structure = self.parchg.structure

        # fraction of cell occupied by structure
        self.zmax = self.structure.cart_coords[:, 2].max() \
                            / self.structure.lattice.c
        # max charge density
        # rmax should be maximum rho value within the stm_cell
        # i.e., [X, Y, Z[nzmin:nzmax]] rather than the whole box
        self.rmax = None
示例#31
0
def get_chg_matrix(folder):
    chg = Chgcar.from_file(os.path.join(folder, 'CHGCAR'))
    chg_matrix = chg.data['total'] / chg.ngridpts
    potcar = Potcar.from_file(os.path.join(folder, 'POTCAR'))
    poscar = Poscar.from_file(os.path.join(folder, 'POSCAR'))
    natoms = poscar.natoms
    cumm_natoms = np.array([sum(natoms[0:i + 1]) for i in range(len(natoms))])

    lengths = []
    for i in range(3):
        lengths.append(len(chg.get_axis_grid(i)))
    lengths = np.array(lengths)

    for atom in range(len(chg.structure.sites)):  # iterating over ion centers
        potcarsingle = potcar[np.argmax(cumm_natoms >= (atom+1))]  # get Potcarsingle for each atom
        charge = potcarsingle.nelectrons
        site = chg.structure.sites[atom]  # atoms are 1 indexed
        # number = site.species_and_occu.elements[0].number
        i = np.round(np.array([site.a, site.b, site.c]) * lengths)  # getting indecies to place atomic charges in cell
        chg_matrix[int(i[0] % lengths[0])][int(i[1] % lengths[1])][int(i[2] % lengths[2])] -= (charge)  # placing ionic centers in cell

    return -chg_matrix
示例#32
0
    def process_vasprun(self, dir_name, taskname, filename):
        """
        Adapted from matgendb.creator

        Process a vasprun.xml file.
        """
        vasprun_file = os.path.join(dir_name, filename)

        vrun = Vasprun(vasprun_file, parse_potcar_file=self.parse_potcar_file)

        d = vrun.as_dict()

        # rename formula keys
        for k, v in {
                "formula_pretty": "pretty_formula",
                "composition_reduced": "reduced_cell_formula",
                "composition_unit_cell": "unit_cell_formula"
        }.items():
            d[k] = d.pop(v)

        for k in ["eigenvalues", "projected_eigenvalues"
                  ]:  # large storage space breaks some docs
            if k in d["output"]:
                del d["output"][k]

        comp = Composition(d["composition_unit_cell"])
        d["formula_anonymous"] = comp.anonymized_formula
        d["formula_reduced_abc"] = comp.reduced_composition.alphabetical_formula
        d["dir_name"] = os.path.abspath(dir_name)
        d["completed_at"] = str(
            datetime.datetime.fromtimestamp(os.path.getmtime(vasprun_file)))
        d["density"] = vrun.final_structure.density

        # replace 'crystal' with 'structure'
        d["input"]["structure"] = d["input"].pop("crystal")
        d["output"]["structure"] = d["output"].pop("crystal")
        for k, v in {
                "energy": "final_energy",
                "energy_per_atom": "final_energy_per_atom"
        }.items():
            d["output"][k] = d["output"].pop(v)

        # Process bandstructure and DOS
        if self.bandstructure_mode != False:
            bs = self.process_bandstructure(vrun)
            if bs:
                d["bandstructure"] = bs

        if self.parse_dos != False:
            dos = self.process_dos(vrun)
            if dos:
                d["dos"] = dos

        # Parse electronic information if possible.
        # For certain optimizers this is broken and we don't get an efermi resulting in the bandstructure
        try:
            bs = vrun.get_band_structure()
            bs_gap = bs.get_band_gap()
            d["output"]["vbm"] = bs.get_vbm()["energy"]
            d["output"]["cbm"] = bs.get_cbm()["energy"]
            d["output"]["bandgap"] = bs_gap["energy"]
            d["output"]["is_gap_direct"] = bs_gap["direct"]
            d["output"]["is_metal"] = bs.is_metal()
            if not bs_gap["direct"]:
                d["output"]["direct_gap"] = bs.get_direct_band_gap()
            if isinstance(bs, BandStructureSymmLine):
                d["output"]["transition"] = bs_gap["transition"]

        except Exception:
            logger.warning("Error in parsing bandstructure")
            if vrun.incar["IBRION"] == 1:
                logger.warning(
                    "Vasp doesn't properly output efermi for IBRION == 1")
            if self.bandstructure_mode is True:
                logger.error(traceback.format_exc())
                logger.error("Error in " + os.path.abspath(dir_name) + ".\n" +
                             traceback.format_exc())
                raise

        # Should roughly agree with information from .get_band_structure() above, subject to tolerances
        # If there is disagreement, it may be related to VASP incorrectly assigning the Fermi level
        try:
            band_props = vrun.eigenvalue_band_properties
            d["output"]["eigenvalue_band_properties"] = {
                "bandgap": band_props[0],
                "cbm": band_props[1],
                "vbm": band_props[2],
                "is_gap_direct": band_props[3]
            }
        except Exception:
            logger.warning("Error in parsing eigenvalue band properties")

        # store run name and location ,e.g. relax1, relax2, etc.
        d["task"] = {"type": taskname, "name": taskname}

        # include output file names
        d["output_file_paths"] = self.process_raw_data(dir_name,
                                                       taskname=taskname)

        # parse axially averaged locpot
        if "locpot" in d["output_file_paths"] and self.parse_locpot:
            locpot = Locpot.from_file(
                os.path.join(dir_name, d["output_file_paths"]["locpot"]))
            d["output"]["locpot"] = {
                i: locpot.get_average_along_axis(i)
                for i in range(3)
            }

        if self.store_volumetric_data:
            for file in self.store_volumetric_data:
                if file in d["output_file_paths"]:
                    try:
                        # assume volumetric data is all in CHGCAR format
                        data = Chgcar.from_file(
                            os.path.join(dir_name,
                                         d["output_file_paths"][file]))
                        d[file] = data.as_dict()
                    except:
                        raise ValueError("Failed to parse {} at {}.".format(
                            file, d["output_file_paths"][file]))

        # parse force constants
        if hasattr(vrun, "force_constants"):
            d["output"]["force_constants"] = vrun.force_constants.tolist()
            d["output"][
                "normalmode_eigenvals"] = vrun.normalmode_eigenvals.tolist()
            d["output"][
                "normalmode_eigenvecs"] = vrun.normalmode_eigenvecs.tolist()

        # perform Bader analysis using Henkelman bader
        if self.parse_bader and "chgcar" in d["output_file_paths"]:
            suffix = '' if taskname == 'standard' else ".{}".format(taskname)
            bader = bader_analysis_from_path(dir_name, suffix=suffix)
            d["bader"] = bader

        return d
示例#33
0
VASP chgcar file is required
'''

import sys
import json
import numpy as np
from pymatgen.io.vasp.outputs import Chgcar
from ase.calculators.vasp import VaspChargeDensity
from PIL import Image

from ChargeDensity.image_file_process import charge_file_crop_2d
from CrystalToolkit.geometry_properties import symmetry_order_2d, rectangle_transform_2d
from CrystalToolkit.vasp_chgcar import chgcar_file_slice_2d, charge_file_2d_reformat

file_chgcar = sys.argv[1]
stru = Chgcar.from_file(file_chgcar).poscar.structure
'''
# find the symmetry order of the 2D structure
with open('data.json') as json_file:
    symmetry_data = json.load(json_file)
point_group_list = symmetry_data['point_group_list']
symmetry_order_2d(structure=stru, point_group_list=point_group_list)
'''
# slice the vasp chgcar file into 2D
vasp_charge = VaspChargeDensity(filename=file_chgcar)
density = vasp_charge.chg[-1]
atoms = vasp_charge.atoms[-1]
*_, chgden_2d = chgcar_file_slice_2d(density=density, atoms=atoms)
# change to RGB values, type must be unit 8 otherwise PIL will complain
chgden_2d = (255.0 / chgden_2d.max() * (chgden_2d - chgden_2d.min())).astype(
    np.uint8)
示例#34
0
    def __init__(self,
                 chgcar_filename,
                 potcar_filename=None,
                 chgref_filename=None,
                 parse_atomic_densities=False):
        """
        Initializes the Bader caller.

        Args:
            chgcar_filename (str): The filename of the CHGCAR.
            potcar_filename (str): Optional: the filename of the corresponding
                POTCAR file. Used for calculating the charge transfer. If
                None, the get_charge_transfer method will raise a ValueError.
            chgref_filename (str): Optional. The filename of the reference
                CHGCAR, which calculated by AECCAR0 + AECCAR2. (See
                http://theory.cm.utexas.edu/henkelman/code/bader/ for details.)
            parse_atomic_densities (bool): Optional. turns on atomic partition of the charge density
                charge densities are atom centered

        """
        if not BADEREXE:
            raise RuntimeError(
                "BaderAnalysis requires the executable bader to be in the path."
                " Please download the library at http://theory.cm.utexas"
                ".edu/vasp/bader/ and compile the executable.")
        self.chgcar = Chgcar.from_file(chgcar_filename)
        self.potcar = Potcar.from_file(potcar_filename) \
            if potcar_filename is not None else None
        self.natoms = self.chgcar.poscar.natoms
        chgcarpath = os.path.abspath(chgcar_filename)
        chgrefpath = os.path.abspath(
            chgref_filename) if chgref_filename else None
        self.reference_used = bool(chgref_filename)
        self.parse_atomic_densities = parse_atomic_densities
        with ScratchDir("."):
            with zopen(chgcarpath, 'rt') as f_in:
                with open("CHGCAR", "wt") as f_out:
                    shutil.copyfileobj(f_in, f_out)
            args = [BADEREXE, "CHGCAR"]
            if chgref_filename:
                with zopen(chgrefpath, 'rt') as f_in:
                    with open("CHGCAR_ref", "wt") as f_out:
                        shutil.copyfileobj(f_in, f_out)
                args += ['-ref', 'CHGCAR_ref']
            if parse_atomic_densities:
                args += ['-p', 'all_atom']
            rs = subprocess.Popen(args,
                                  stdout=subprocess.PIPE,
                                  stdin=subprocess.PIPE,
                                  close_fds=True)
            stdout, stderr = rs.communicate()
            if rs.returncode != 0:
                raise RuntimeError("bader exited with return code %d. "
                                   "Please check your bader installation." %
                                   rs.returncode)

            try:
                self.version = float(stdout.split()[5])
            except Exception:
                self.version = -1  # Unknown
            if self.version < 1.0:
                warnings.warn('Your installed version of Bader is outdated, '
                              'calculation of vacuum charge may be incorrect.')

            data = []
            with open("ACF.dat") as f:
                raw = f.readlines()
                headers = ('x', 'y', 'z', 'charge', 'min_dist', 'atomic_vol')
                raw.pop(0)
                raw.pop(0)
                while True:
                    line = raw.pop(0).strip()
                    if line.startswith("-"):
                        break
                    vals = map(float, line.split()[1:])
                    data.append(dict(zip(headers, vals)))
                for l in raw:
                    toks = l.strip().split(":")
                    if toks[0] == "VACUUM CHARGE":
                        self.vacuum_charge = float(toks[1])
                    elif toks[0] == "VACUUM VOLUME":
                        self.vacuum_volume = float(toks[1])
                    elif toks[0] == "NUMBER OF ELECTRONS":
                        self.nelectrons = float(toks[1])
            self.data = data

            if self.parse_atomic_densities:
                # convert the charge denisty for each atom spit out by Bader into Chgcar objects for easy parsing
                atom_chgcars = [
                    Chgcar.from_file("BvAt{}.dat".format(str(i).zfill(4)))
                    for i in range(1,
                                   len(self.chgcar.structure) + 1)
                ]

                atomic_densities = []
                # For each atom in the structure
                for atom, loc, chg in zip(self.chgcar.structure,
                                          self.chgcar.structure.frac_coords,
                                          atom_chgcars):
                    # Find the index of the atom in the charge density atom
                    index = np.round(np.multiply(loc, chg.dim))

                    data = chg.data['total']
                    # Find the shift vector in the array
                    shift = (np.divide(chg.dim, 2) - index).astype(int)

                    # Shift the data so that the atomic charge density to the center for easier manipulation
                    shifted_data = np.roll(data, shift, axis=(0, 1, 2))

                    # Slices a central window from the data array
                    def slice_from_center(data, xwidth, ywidth, zwidth):
                        x, y, z = data.shape
                        startx = x // 2 - (xwidth // 2)
                        starty = y // 2 - (ywidth // 2)
                        startz = z // 2 - (zwidth // 2)
                        return data[startx:startx + xwidth,
                                    starty:starty + ywidth,
                                    startz:startz + zwidth]

                    # Finds the central encompassing volume which holds all the data within a precision
                    def find_encompassing_vol(data, prec=1e-3):
                        total = np.sum(data)
                        for i in range(np.max(data.shape)):
                            sliced_data = slice_from_center(data, i, i, i)
                            if total - np.sum(sliced_data) < 0.1:
                                return sliced_data
                        return None

                    d = {
                        "data": find_encompassing_vol(shifted_data),
                        "shift": shift,
                        "dim": self.chgcar.dim
                    }
                    atomic_densities.append(d)
                self.atomic_densities = atomic_densities
示例#35
0
文件: utils.py 项目: albalu/pymatgen
 def from_file(cls, chgcar_filename):
     chgcar = Chgcar.from_file(chgcar_filename)
     return cls(chgcar=chgcar)
示例#36
0
def asym(chg, n):
    data = []
    for j in range(chg.dim[1]):
        for i in range(chg.dim[0]):
            for k in range(chg.dim[2]):
                if i + k == int(chg.dim[0] + chg.dim[2]) / 2 + n:
                    data.append(chg.data['total'][i, j, k])

    data = np.array(data)
    data = np.reshape(data, (chg.dim[1], len(data) // chg.dim[1]))
    return data.astype(float)


os.chdir('/home/jinho93/molecule/ddt/vasp/2020/bulk/sym/t1')
chgcar = Chgcar.from_file('SPIN.vasp')
dsym = sym(chgcar, 5)

os.chdir('/home/jinho93/molecule/ddt/vasp/2020/bulk/asym/t1')
chgcar = Chgcar.from_file('SPIN.vasp')
dasym = asym(chgcar, 5)

#%%
os.chdir('/home/jinho93/molecule/ddt/vasp/2020/bulk/sym/t1')
chgcar = Chgcar.from_file('SPIN.vasp')
mlist = []
for i in range(25):
    mlist.append(np.max(sym(chgcar, i)))
print(np.argmax(mlist), mlist[np.argmax(mlist)])

# %%
示例#37
0
def dipole_chgcar(args):
    # Getting info about the cell
    print('Getting Electron Densities...', end='')
    sys.stdout.flush()
    chg = Chgcar.from_file('BvAt_summed.dat')
    s = chg.structure
    d = chg.data['total'] / chg.ngridpts   # get charge density in e-/A^2
    lengths = []
    for i in range(3):
        lengths.append(len(chg.get_axis_grid(i)))
    lengths = np.array(lengths)
    print('done')

    # Adding ionic centers to cell
    print('Adding Ions to Cell...', end='')
    sys.stdout.flush()
    poscar = Poscar.from_file('POSCAR')
    potcar = Potcar.from_file('POTCAR')
    natoms = poscar.natoms
    cumm_natoms = np.array([ sum(natoms[0:i+1]) for i in range(len(natoms)) ])
    for atom in args.atoms:   # iterating over ion centers
        potcarsingle = potcar[np.argmax(cumm_natoms>=atom)] # get Potcarsingle for each atom
        charge = potcarsingle.nelectrons
        site = s.sites[atom - 1] # atoms are 1 indexed
        # number = site.species_and_occu.elements[0].number
        i = np.round(np.array([site.a, site.b, site.c]) * lengths)  # getting indecies to place atomic charges in cell
        d[i[0] % lengths[0]][i[1] % lengths[1]][i[2] % lengths[2]] -= (charge)  # placing ionic centers in cell
    print('done')

    # Make correction for charged species
    print('Calculating Correction for Charged Species...', end='')
    sys.stdout.flush()
    element_charge = sum(sum(sum(d)))
    bader_gridpts = len(np.nonzero(d)[2])# number of gridpoints in bader volume
    correction = element_charge / bader_gridpts  # normalization constant to account for charged species
    print('done')
    print('\nCharge = ' + str(-element_charge) + ' e-\n')
    # print('\nCorrection = ' + str(correction) + ' e-\n')

    # Calculating lattice
    #axis = np.array(args.axis) # / np.linalg.norm(np.array(args.axis))
    cart_axis = np.matrix(args.axis) * s.lattice.matrix
    unit_vector = cart_axis / np.linalg.norm((cart_axis))
    a_axis = chg.get_axis_grid(0)
    b_axis = chg.get_axis_grid(1)
    c_axis = chg.get_axis_grid(2)
    len_a = len(a_axis)
    len_b = len(b_axis)
    len_c = len(c_axis)
    mod_a = int(np.round(float(len_a) * args.origin[0]))
    mod_b = int(np.round(float(len_b) * args.origin[1]))
    mod_c = int(np.round(float(len_c) * args.origin[2]))
    mat = s.lattice.matrix
    def get_first_moment(a, b, c, x):
        a = float((a - mod_a) % len_a) / len_a
        b = float((b - mod_b) % len_b) / len_b
        c = float((c - mod_c) % len_c) / len_c
        cart_vector = np.matrix([a, b, c]) * mat
        return float(np.dot(cart_vector, unit_vector.transpose())) * (x - correction)

    # integrate over charge density
    print('Calculating Dipole... ')
    sys.stdout.flush()
    dipole = 0
    for a in range(lengths[0]):
        sys.stdout.write('\r%d percent' % int(a * 100 / len_a))
        sys.stdout.flush()
        for b in range(lengths[1]):
            for c in range(lengths[2]):
                x = d[a][b][c]
                if x != 0:
                    dipole += get_first_moment(a, b, c, x)
    print('done')
    print('Dipole = ' + str(dipole) + ' eA')
    print('Dipole = ' + str(dipole / 0.20819434) + ' D')
    return dipole
    sys.stdout.flush()
示例#38
0
#%%

from pymatgen.io.vasp.outputs import Chgcar
from pymatgen.io.cube import Cube
import os

os.chdir('/home/jinho93/molecule/ddt/cp2k/bulk/asym/t1')
cub = Cube('s1-SPIN_DENSITY-1_0.cube')
cub.NZ
for i in range(cub.NX):
    for j in range(cub.NY):
        for k in range(cub.NZ):
            if i + k > cub.NZ + 2 or i + k < cub.NZ / 2 + 5:
                cub.data[i, j, k] = 0
chg = Chgcar(cub.structure, {'total': cub.data})
chg.write_file('NEW_CHGCAR')

# chg = Chgcar(cub.structure, cub.data)

# %%
示例#39
0
    def from_path(cls, path, suffix="", zpsp=None):
        """
        Convenience method to run critic2 analysis on a folder containing
        typical VASP output files.
        This method will:

        1. Look for files CHGCAR, AECAR0, AECAR2, POTCAR or their gzipped
        counterparts.

        2. If AECCAR* files are present, constructs a temporary reference
        file as AECCAR0 + AECCAR2.

        3. Runs critic2 analysis twice: once for charge, and a second time
        for the charge difference (magnetization density).

        :param path: path to folder to search in
        :param suffix: specific suffix to look for (e.g. '.relax1' for
            'CHGCAR.relax1.gz')
        :param zpsp: manually specify ZPSP if POTCAR not present
        :return:
        """
        def _get_filepath(filename, warning, path=path, suffix=suffix):
            paths = glob.glob(os.path.join(path, filename + suffix + "*"))
            if not paths:
                warnings.warn(warning)
                return None
            if len(paths) > 1:
                # using reverse=True because, if multiple files are present,
                # they likely have suffixes 'static', 'relax', 'relax2', etc.
                # and this would give 'static' over 'relax2' over 'relax'
                # however, better to use 'suffix' kwarg to avoid this!
                paths.sort(reverse=True)
                warnings.warn("Multiple files detected, using {}".format(
                    os.path.basename(path)))
            path = paths[0]
            return path

        chgcar_path = _get_filepath("CHGCAR", "Could not find CHGCAR!")
        chgcar = Chgcar.from_file(chgcar_path)
        chgcar_ref = None

        if not zpsp:

            potcar_path = _get_filepath(
                "POTCAR",
                "Could not find POTCAR, will not be able to calculate charge transfer.",
            )

            if potcar_path:
                potcar = Potcar.from_file(potcar_path)
                zpsp = {p.symbol: p.zval for p in potcar}

        if not zpsp:

            # try and get reference "all-electron-like" charge density if zpsp not present
            aeccar0_path = _get_filepath(
                "AECCAR0",
                "Could not find AECCAR0, interpret Bader results with caution.",
            )
            aeccar0 = Chgcar.from_file(aeccar0_path) if aeccar0_path else None

            aeccar2_path = _get_filepath(
                "AECCAR2",
                "Could not find AECCAR2, interpret Bader results with caution.",
            )
            aeccar2 = Chgcar.from_file(aeccar2_path) if aeccar2_path else None

            chgcar_ref = aeccar0.linear_add(aeccar2) if (aeccar0
                                                         and aeccar2) else None

        return cls(chgcar.structure, chgcar, chgcar_ref, zpsp=zpsp)
示例#40
0
def neb(directory,
        nimages=7,
        functional=("pbe", {}),
        is_metal=False,
        is_migration=False):
    """
    Set up the NEB calculation from the initial and final structures.

    Args:
        directory (str): Directory in which the transition calculations should be
            set up.
        functional (tuple): Tuple with the functional choices. The first element
            contains a string that indicates the functional used ("pbe", "hse", ...),
            whereas the second element contains a dictionary that allows the user
            to specify the various functional tags.
        nimages (int): Number of images to use in the NEB calculation.
        is_metal (bool): Flag that indicates the material being studied is a
            metal, which changes the smearing from Gaussian to second order
            Methfessel-Paxton of 0.2 eV.
        is_migration (bool): Flag that indicates that the transition is a migration
            of an atom in the structure.

    Returns:
        None

    """
    directory = os.path.abspath(directory)

    # Extract the optimized initial and final geometries
    initial_dir = os.path.join(directory, "initial")
    final_dir = os.path.join(directory, "final")

    try:
        # Check to see if the initial final_cathode structure is present
        initial_structure = Cathode.from_file(
            os.path.join(initial_dir,
                         "final_cathode.json")).as_ordered_structure()

    except FileNotFoundError:
        # In case the required json file is not present, check to see if
        # there is VASP output which can be used
        initial_structure = Structure.from_file(
            os.path.join(initial_dir, "CONTCAR"))

        # Add the magnetic configuration to the initial structure
        initial_out = Outcar(os.path.join(initial_dir, "OUTCAR"))
        initial_magmom = [site["tot"] for site in initial_out.magnetization]

        try:
            initial_structure.add_site_property("magmom", initial_magmom)
        except ValueError:
            if len(initial_magmom) == 0:
                print("No magnetic moments found in OUTCAR file. Setting "
                      "magnetic moments to zero.")
                initial_magmom = [0] * len(initial_structure)
                initial_structure.add_site_property("magmom", initial_magmom)
            else:
                raise ValueError("Number of magnetic moments in OUTCAR file "
                                 "do not match the number of sites!")
    except BaseException:
        raise FileNotFoundError("Could not find required structure "
                                "information in " + initial_dir + ".")

    try:
        final_structure = Structure.from_file(
            os.path.join(final_dir, "CONTCAR"))
    except FileNotFoundError:
        final_structure = Cathode.from_file(
            os.path.join(final_dir,
                         "final_cathode.json")).as_ordered_structure()

    # In case the transition is a migration
    if is_migration:
        # Set up the static potential for the Pathfinder from the host charge
        # density
        host_charge_density = Chgcar.from_file(os.path.join(directory, "host"))
        host_potential = ChgcarPotential(host_charge_density)

        migration_site_index = find_migrating_ion(initial_structure,
                                                  final_structure)

        neb_path = NEBPathfinder(start_struct=initial_structure,
                                 end_struct=final_structure,
                                 relax_sites=migration_site_index,
                                 v=host_potential)

        images = neb_path.images
        neb_path.plot_images("neb.vasp")

    # In case an "middle image" has been provided via which to interpolate
    elif os.path.exists(os.path.join(directory, "middle")):
        print("Found a 'middle' directory in the NEB directory. Interpolating "
              "via middle geometry.")
        # Load the middle image
        middle_structure = Structure.from_file(
            os.path.join(directory, "middle", "CONTCAR"))
        # Perform an interpolation via this image
        images_1 = initial_structure.interpolate(
            end_structure=middle_structure,
            nimages=int((nimages + 1) / 2),
            interpolate_lattices=True)
        images_2 = middle_structure.interpolate(end_structure=final_structure,
                                                nimages=int((nimages) / 2 + 1),
                                                interpolate_lattices=True)

        images = images_1[:-1] + images_2

    else:
        # Linearly interpolate the initial and final structures
        images = initial_structure.interpolate(end_structure=final_structure,
                                               nimages=nimages + 1,
                                               interpolate_lattices=True)

    # TODO Add functionality for NEB calculations with changing lattices

    user_incar_settings = {}

    # Set up the functional
    if functional[0] != "pbe":
        functional_config = _load_yaml_config(functional[0] + "Set")
        functional_config["INCAR"].update(functional[1])
        user_incar_settings.update(functional_config["INCAR"])

    # Add the standard Methfessel-Paxton smearing for metals
    if is_metal:
        user_incar_settings.update({"ISMEAR": 2, "SIGMA": 0.2})

    neb_calculation = PybatNEBSet(images,
                                  potcar_functional=DFT_FUNCTIONAL,
                                  user_incar_settings=user_incar_settings)

    # Set up the NEB calculation
    neb_calculation.write_input(directory)

    # Make a file to visualize the transition
    neb_calculation.visualize_transition(
        os.path.join(directory, "transition.cif"))
示例#41
0
    def __init__(
        self,
        chgcar_filename=None,
        potcar_filename=None,
        chgref_filename=None,
        parse_atomic_densities=False,
        cube_filename=None,
    ):
        """
        Initializes the Bader caller.

        Args:
            chgcar_filename (str): The filename of the CHGCAR.
            potcar_filename (str): The filename of the POTCAR.
            chgref_filename (str): The filename of the reference charge density.
            parse_atomic_densities (bool): Optional. turns on atomic partition of the charge density
                charge densities are atom centered
            cube_filename (str): Optional. The filename of the cube file.
        """
        if not BADEREXE:
            raise RuntimeError(
                "BaderAnalysis requires the executable bader to be in the path."
                " Please download the library at http://theory.cm.utexas"
                ".edu/vasp/bader/ and compile the executable.")

        if not (cube_filename or chgcar_filename):
            raise ValueError("You must provide either a cube file or a CHGCAR")
        if cube_filename and chgcar_filename:
            raise ValueError(
                "You cannot parse a cube and a CHGCAR at the same time.")
        self.parse_atomic_densities = parse_atomic_densities

        if chgcar_filename:
            fpath = os.path.abspath(chgcar_filename)
            self.is_vasp = True
            self.chgcar = Chgcar.from_file(fpath)
            self.structure = self.chgcar.structure
            self.potcar = Potcar.from_file(
                potcar_filename) if potcar_filename is not None else None
            self.natoms = self.chgcar.poscar.natoms
            chgrefpath = os.path.abspath(
                chgref_filename) if chgref_filename else None
            self.reference_used = bool(chgref_filename)

            # List of nelects for each atom from potcar
            potcar_indices = []
            for i, v in enumerate(self.natoms):
                potcar_indices += [i] * v
            self.nelects = ([
                self.potcar[potcar_indices[i]].nelectrons
                for i in range(len(self.structure))
            ] if self.potcar else [])

        else:
            fpath = os.path.abspath(cube_filename)
            self.is_vasp = False
            self.cube = Cube(fpath)
            self.structure = self.cube.structure
            self.nelects = None
            chgrefpath = os.path.abspath(
                chgref_filename) if chgref_filename else None
            self.reference_used = bool(chgref_filename)

        with ScratchDir("."):
            tmpfile = "CHGCAR" if chgcar_filename else "CUBE"
            with zopen(fpath, "rt") as f_in:
                with open(tmpfile, "wt") as f_out:
                    shutil.copyfileobj(f_in, f_out)
            args = [BADEREXE, tmpfile]
            if chgref_filename:
                with zopen(chgrefpath, "rt") as f_in:
                    with open("CHGCAR_ref", "wt") as f_out:
                        shutil.copyfileobj(f_in, f_out)
                args += ["-ref", "CHGCAR_ref"]
            if parse_atomic_densities:
                args += ["-p", "all_atom"]
            with subprocess.Popen(args,
                                  stdout=subprocess.PIPE,
                                  stdin=subprocess.PIPE,
                                  close_fds=True) as rs:
                stdout, _ = rs.communicate()
            if rs.returncode != 0:
                raise RuntimeError(
                    f"bader exited with return code {rs.returncode}. Please check your bader installation."
                )

            try:
                self.version = float(stdout.split()[5])
            except ValueError:
                self.version = -1  # Unknown
            if self.version < 1.0:
                warnings.warn(
                    "Your installed version of Bader is outdated, calculation of vacuum charge may be incorrect.",
                    UserWarning,
                )

            data = []
            with open("ACF.dat") as f:
                raw = f.readlines()
                headers = ("x", "y", "z", "charge", "min_dist", "atomic_vol")
                raw.pop(0)
                raw.pop(0)
                while True:
                    l = raw.pop(0).strip()
                    if l.startswith("-"):
                        break
                    vals = map(float, l.split()[1:])
                    data.append(dict(zip(headers, vals)))
                for l in raw:
                    toks = l.strip().split(":")
                    if toks[0] == "VACUUM CHARGE":
                        self.vacuum_charge = float(toks[1])
                    elif toks[0] == "VACUUM VOLUME":
                        self.vacuum_volume = float(toks[1])
                    elif toks[0] == "NUMBER OF ELECTRONS":
                        self.nelectrons = float(toks[1])
            self.data = data

            if self.parse_atomic_densities:
                # convert the charge density for each atom spit out by Bader into Chgcar objects for easy parsing
                atom_chgcars = [
                    Chgcar.from_file(f"BvAt{str(i).zfill(4)}.dat")
                    for i in range(1,
                                   len(self.chgcar.structure) + 1)
                ]

                atomic_densities = []
                # For each atom in the structure
                for _, loc, chg in zip(
                        self.chgcar.structure,
                        self.chgcar.structure.frac_coords,
                        atom_chgcars,
                ):
                    # Find the index of the atom in the charge density atom
                    index = np.round(np.multiply(loc, chg.dim))

                    data = chg.data["total"]
                    # Find the shift vector in the array
                    shift = (np.divide(chg.dim, 2) - index).astype(int)

                    # Shift the data so that the atomic charge density to the center for easier manipulation
                    shifted_data = np.roll(data, shift, axis=(0, 1, 2))

                    # Slices a central window from the data array
                    def slice_from_center(data, xwidth, ywidth, zwidth):
                        x, y, z = data.shape
                        startx = x // 2 - (xwidth // 2)
                        starty = y // 2 - (ywidth // 2)
                        startz = z // 2 - (zwidth // 2)
                        return data[startx:startx + xwidth,
                                    starty:starty + ywidth,
                                    startz:startz + zwidth, ]

                    # Finds the central encompassing volume which holds all the data within a precision
                    def find_encompassing_vol(data):
                        total = np.sum(data)
                        for i in range(np.max(data.shape)):
                            sliced_data = slice_from_center(data, i, i, i)
                            if total - np.sum(sliced_data) < 0.1:
                                return sliced_data
                        return None

                    d = {
                        "data": find_encompassing_vol(shifted_data),
                        "shift": shift,
                        "dim": self.chgcar.dim,
                    }
                    atomic_densities.append(d)
                self.atomic_densities = atomic_densities
示例#42
0
    def __init__(
        self,
        path=None,
        atomic_densities_path=None,
        run_chargemol=True,
    ):
        """
        Initializes the Chargemol Analysis.

        Args:
            path (str): Path to the CHGCAR, POTCAR, AECCAR0, and AECCAR files.
            Note that it doesn't matter if the files gzip'd or not.
                Default: None (current working directory).
            atomic_densities_path (str|None): Path to the atomic densities directory
            required by Chargemol. If None, Pymatgen assumes that this is
            defined in a "DDEC6_ATOMIC_DENSITIES_DIR" environment variable.
            Only used if run_chargemol is True.
                Default: None.
            run_chargemol (bool): Whether to run the Chargemol analysis. If False,
            the existing Chargemol output files will be read from path.
                Default: True.
        """
        if not path:
            path = os.getcwd()
        if run_chargemol and not (which("Chargemol_09_26_2017_linux_parallel")
                                  or which("Chargemol_09_26_2017_linux_serial")
                                  or which("chargemol"), ):
            raise OSError(
                "ChargemolAnalysis requires the Chargemol executable to be in the path."
                " Please download the library at https://sourceforge.net/projects/ddec/files"
                "and follow the instructions.")
        if atomic_densities_path == "":
            atomic_densities_path = os.getcwd()
        self._atomic_densities_path = atomic_densities_path

        self._chgcarpath = self._get_filepath(path, "CHGCAR")
        self._potcarpath = self._get_filepath(path, "POTCAR")
        self._aeccar0path = self._get_filepath(path, "AECCAR0")
        self._aeccar2path = self._get_filepath(path, "AECCAR2")
        if run_chargemol and not (self._chgcarpath and self._potcarpath
                                  and self._aeccar0path and self._aeccar2path):
            raise FileNotFoundError(
                "CHGCAR, AECCAR0, AECCAR2, and POTCAR are all needed for Chargemol."
            )
        if self._chgcarpath:
            self.chgcar = Chgcar.from_file(self._chgcarpath)
            self.structure = self.chgcar.structure
            self.natoms = self.chgcar.poscar.natoms
        else:
            self.chgcar = None
            self.structure = None
            self.natoms = None
            warnings.warn(
                "No CHGCAR found. Some properties may be unavailable.",
                UserWarning)
        if self._potcarpath:
            self.potcar = Potcar.from_file(self._potcarpath)
        else:
            warnings.warn(
                "No POTCAR found. Some properties may be unavailable.",
                UserWarning)
        self.aeccar0 = Chgcar.from_file(
            self._aeccar0path) if self._aeccar0path else None
        self.aeccar2 = Chgcar.from_file(
            self._aeccar2path) if self._aeccar2path else None

        if run_chargemol:
            self._execute_chargemol()
        else:
            self._from_data_dir(chargemol_output_path=path)
示例#43
0
    def __init__(self, chgcar_filename, potcar_filename=None,
                 chgref_filename=None, parse_atomic_densities=False):
        """
        Initializes the Bader caller.

        Args:
            chgcar_filename (str): The filename of the CHGCAR.
            potcar_filename (str): Optional: the filename of the corresponding
                POTCAR file. Used for calculating the charge transfer. If
                None, the get_charge_transfer method will raise a ValueError.
            chgref_filename (str): Optional. The filename of the reference
                CHGCAR, which calculated by AECCAR0 + AECCAR2. (See
                http://theory.cm.utexas.edu/henkelman/code/bader/ for details.)
            parse_atomic_densities (bool): Optional. turns on atomic partition of the charge density
                charge densities are atom centered

        """
        if not BADEREXE:
            raise RuntimeError(
                "BaderAnalysis requires the executable bader to be in the path."
                " Please download the library at http://theory.cm.utexas"
                ".edu/vasp/bader/ and compile the executable.")
        self.chgcar = Chgcar.from_file(chgcar_filename)
        self.potcar = Potcar.from_file(potcar_filename) \
            if potcar_filename is not None else None
        self.natoms = self.chgcar.poscar.natoms
        chgcarpath = os.path.abspath(chgcar_filename)
        chgrefpath = os.path.abspath(chgref_filename) if chgref_filename else None
        self.reference_used = True if chgref_filename else False
        self.parse_atomic_densities = parse_atomic_densities
        with ScratchDir(".") as temp_dir:
            with zopen(chgcarpath, 'rt') as f_in:
                with open("CHGCAR", "wt") as f_out:
                    shutil.copyfileobj(f_in, f_out)
            args = [BADEREXE, "CHGCAR"]
            if chgref_filename:
                with zopen(chgrefpath, 'rt') as f_in:
                    with open("CHGCAR_ref", "wt") as f_out:
                        shutil.copyfileobj(f_in, f_out)
                args += ['-ref', 'CHGCAR_ref']
            if parse_atomic_densities:
                args += ['-p', 'all_atom']
            rs = subprocess.Popen(args,
                                  stdout=subprocess.PIPE,
                                  stdin=subprocess.PIPE, close_fds=True)
            stdout, stderr = rs.communicate()
            if rs.returncode != 0:
                raise RuntimeError("bader exited with return code %d. "
                                   "Please check your bader installation."
                                   % rs.returncode)

            try:
                self.version = float(stdout.split()[5])
            except:
                self.version = -1  # Unknown
            if self.version < 1.0:
                warnings.warn('Your installed version of Bader is outdated, '
                              'calculation of vacuum charge may be incorrect.')

            data = []
            with open("ACF.dat") as f:
                raw = f.readlines()
                headers = ('x', 'y', 'z', 'charge', 'min_dist', 'atomic_vol')
                raw.pop(0)
                raw.pop(0)
                while True:
                    l = raw.pop(0).strip()
                    if l.startswith("-"):
                        break
                    vals = map(float, l.split()[1:])
                    data.append(dict(zip(headers, vals)))
                for l in raw:
                    toks = l.strip().split(":")
                    if toks[0] == "VACUUM CHARGE":
                        self.vacuum_charge = float(toks[1])
                    elif toks[0] == "VACUUM VOLUME":
                        self.vacuum_volume = float(toks[1])
                    elif toks[0] == "NUMBER OF ELECTRONS":
                        self.nelectrons = float(toks[1])
            self.data = data

            if self.parse_atomic_densities:
                # convert the charge denisty for each atom spit out by Bader into Chgcar objects for easy parsing
                atom_chgcars = [Chgcar.from_file("BvAt{}.dat".format(str(i).zfill(4))) for i in
                                range(1, len(self.chgcar.structure) + 1)]

                atomic_densities = []
                # For each atom in the structure
                for atom, loc, chg in zip(self.chgcar.structure,
                                          self.chgcar.structure.frac_coords,
                                          atom_chgcars):
                    # Find the index of the atom in the charge density atom
                    index = np.round(np.multiply(loc, chg.dim))

                    data = chg.data['total']
                    # Find the shift vector in the array
                    shift = (np.divide(chg.dim, 2) - index).astype(int)

                    # Shift the data so that the atomic charge density to the center for easier manipulation
                    shifted_data = np.roll(data, shift, axis=(0, 1, 2))

                    # Slices a central window from the data array
                    def slice_from_center(data, xwidth, ywidth, zwidth):
                        x, y, z = data.shape
                        startx = x // 2 - (xwidth // 2)
                        starty = y // 2 - (ywidth // 2)
                        startz = z // 2 - (zwidth // 2)
                        return data[startx:startx + xwidth, starty:starty + ywidth, startz:startz + zwidth]

                    # Finds the central encompassing volume which holds all the data within a precision
                    def find_encompassing_vol(data,prec=1e-3):
                        total = np.sum(data)
                        for i in range(np.max(data.shape)):
                            sliced_data = slice_from_center(data,i,i,i)
                            if total - np.sum(sliced_data) < 0.1:
                                return sliced_data
                        return None

                    d = {
                        "data": find_encompassing_vol(shifted_data),
                        "shift": shift,
                        "dim": self.chgcar.dim
                    }
                    atomic_densities.append(d)
                self.atomic_densities = atomic_densities
示例#44
0
 def from_file(filename):
     cc = Chgcar.from_file(filename)
     return Pathfinder(cc)