Пример #1
0
    def run_task(self, fw_spec):

        directory = self.get("directory", os.getcwd())
        multiplier = self.get("multiplier", 3)

        os.chdir(directory)

        nelect_written = False

        try:
            with open("OUTCAR", "r") as file:
                if "NELECT" in file.read():
                    nelect_written = True
        except FileNotFoundError:
            pass

        if not nelect_written:

            # Do a trial run to figure out the number of standard bands
            stdout_file = "temp.out"
            stderr_file = "temp.out"
            vasp_cmd = fw_spec["_fw_env"]["vasp_cmd"].split(" ")

            with open(stdout_file, 'w') as f_std, \
                    open(stderr_file, "w", buffering=1) as f_err:
                p = subprocess.Popen(vasp_cmd, stdout=f_std, stderr=f_err,
                                     preexec_fn=os.setsid)

                while not nelect_written:
                    try:
                        with open("OUTCAR", "r") as file:
                            if "NELECT" in file.read():
                                nelect_written = True
                    except FileNotFoundError:
                        pass
                    time.sleep(1)

                os.killpg(os.getpgid(p.pid), signal.SIGTERM)

            time.sleep(3)
            os.remove(os.path.join(directory, "temp.out"))

        outcar = Outcar("OUTCAR")
        incar = Incar.from_file("INCAR")
        pattern = r"\s+NELECT\s=\s+(\d+).\d+\s+total\snumber\sof\selectrons"
        outcar.read_pattern({"nelect": pattern})

        nions = len(Structure.from_file("POSCAR"))
        nelect = int(outcar.data["nelect"][0][0])
        ispin = int(incar.get("ISPIN", 1))

        if ispin == 1:
            nbands = int(round(nelect / 2 + nions / 2)) * multiplier
        elif ispin == 2:
            nbands = int(nelect * 3 / 5 + nions) * multiplier
        else:
            raise ValueError("ISPIN Value is not set to 1 or 2!")

        incar.update({"NBANDS": nbands})
        incar.write_file("INCAR")
Пример #2
0
    def load_polarization(self, path):
        """
    This function tries to read Berry phase calculations from three files:
    filename+'_berry_1' filename+'_berry_2' filename+'_berry_3'
    If the files are not readable, no polarization attribute is set.
    On successful run this method fills the following attributes:
    - self.polarization - polarization as calculated from the three files, in cartesian coordinates (3 e/A**2)
    - self.ev_phase - expectation value reported by VASP for each of the three directions (3x3 -e*A)
    - self.ev_recip - the mean of the expectation value projected to internal coordinates (3 -e)
    - self.berry_phase - berry phases of all strings in each of the directions (3xN 1)
    - self.polarization_quant - polarization quant for the calculation (3x3 e/A**2)
    - self.i_polarization_quant - inverse of polarization quant
    """
        self.berry_phase = 3 * [None]
        self.berry_ev = 3 * [None]
        self.berry_ion = 3 * [None]
        self.num_per_type = []

        # Noncollinear calculations are officially numspin==1, but they do contain separate electrons, not electron pairs,
        # Therefore, they should be treated as numspin==2 for calculation of polarizations.
        self.numspin = 2

        # Extract information from OUTCAR file in each of 3 directions.
        for kdirection in range(1, 4):
            fname = os.path.join(path, 'Berry_%d/OUTCAR' % kdirection)

            if os.access(fname, os.R_OK):

                # open and read OUTCAR file
                outcar = Outcar(fname)

                # berry phase
                outcar.read_pattern(
                    {
                        'berry_phase':
                        r"Im\s+ln\[Det\|M_k\|\]=\s+([+-]?\d+\.\d+)\s"
                    },
                    terminate_on_match=False,
                    postprocess=float)
                bphase = [
                    item for sublist in outcar.data.get("berry_phase")
                    for item in sublist
                ]
                # k-point weights
                outcar.read_pattern(
                    {
                        'kpoint_weights':
                        r"K-point string #\s+\S+\s+weight=\s+([+-]?\d+\.\d+)\s"
                    },
                    terminate_on_match=False,
                    postprocess=float)
                kpoint_weights = [
                    item for sublist in outcar.data.get("kpoint_weights")
                    for item in sublist
                ]

                self.berry_phase[kdirection - 1] = np.array(
                    [list(x) for x in zip(bphase, kpoint_weights)])

                #self.berry_ev[kdirection-1] = self.read_berry_ev(fname)
                # alternative way to read berry_ev from Outcar
                self.berry_ev[kdirection - 1] = self.read_berry_ev_old(fname)

                outcar.read_lcalcpol()

            else:
                # Make sure, we have 0,0,0 as polarisation in case there is no berry phase output available
                print('No file with polarization')
                self.berry_phase = 3 * [np.zeros((1, 2))]
                self.berry_ev = 3 * [np.zeros((3))]
                self.berry_ion = 3 * [[[0., 0., 0.]]]

                self.polarization_quant = self.unit_cell.copy() / self.volume
                self.berry_multiplier = 1.
                self.polarization_quant *= self.berry_multiplier

                self.i_polarization_quant = np.linalg.inv(
                    self.polarization_quant)
                self.ev_recip = np.dot(np.mean(self.berry_ev, axis=0),
                                       self.recip_cell)

                self.recalculate_polarization()
                return
        self.polarization_quant = self.unit_cell.copy() / self.volume

        # In case of nonpolarised calculations, we have two electrons per each Berry string
        # So the quantum needs to be doubled.
        self.berry_multiplier = 3 - self.numspin
        self.polarization_quant *= self.berry_multiplier
        self.i_polarization_quant = np.linalg.inv(self.polarization_quant)

        self.ev_recip = np.dot(np.mean(self.berry_ev, axis=0), self.recip_cell)
        self.recalculate_polarization()
Пример #3
0
    def load_from_outcar(self, path, structure, mode):
        """
    This function reads atom positions, unit cell, forces and stress tensor from the VASP
    OUTCAR file
    path: 
    structure: 
    """
        if mode == 'scf':
            filename = os.path.join(path, 'OUTCAR')
            self.name = filename.split('/')[-2]
        elif mode == 'nscf':
            filename = os.path.join(path, 'nscf_SOC/OUTCAR')
            self.name = filename.split('/')[-3]
        else:
            raise Exception(
                f"Calculation mode {mode} is wrong. Must be scf or nscf")

        if os.access(filename, os.R_OK):
            outcar = Outcar(filename)
        else:
            raise Exception("Missing OUTCAR file in {}".format(filename))

        print(self.name)

        # ATOMIC PROPERTIES
        self.num_atoms = int(
            structure.composition.num_atoms)  # total number of atoms
        self.atoms_frac = structure.frac_coords  # fraction coordinates
        self.atoms_cart = structure.cart_coords  # cartesian coordinates
        self.num_per_type = [
            int(x) for x in structure.composition.get_el_amt_dict().values()
        ]  # number of atoms per type
        self.species = [x.symbol for x in structure.species
                        ]  # list with atomic symbols for each specie
        self.pomass = [
            Element(x.symbol).atomic_mass for x in structure.species
        ]  # list with atomic masses for each specie
        self.charges = [x['tot'] for x in outcar.charge]  # list with charges

        # read zval dict and create a mapping
        outcar.read_pseudo_zval()
        zval_dict = outcar.zval_dict
        self.zvals = [zval_dict[x.symbol] for x in structure.species]

        # UNIT CELL
        self.unit_cell = structure.lattice.matrix  # unit cell
        self.recip_cell = structure.lattice.inv_matrix  # inverse unit cell
        self.volume = structure.lattice.volume

        # total energy in eV
        self.energy = outcar.final_energy
        # atomic positions read from Outcar
        self.atoms = np.array(
            outcar.read_table_pattern(
                header_pattern=r"\sPOSITION\s+TOTAL-FORCE \(eV/Angst\)\n\s-+",
                row_pattern=
                r"\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+",
                footer_pattern=r"\s--+",
                postprocess=lambda x: float(x),
                last_one_only=False)[0])
        # forces acting on atoms from Outcar
        self.forces = np.array(
            outcar.read_table_pattern(
                header_pattern=r"\sPOSITION\s+TOTAL-FORCE \(eV/Angst\)\n\s-+",
                row_pattern=
                r"\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+[+-]?\d+\.\d+\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)\s+([+-]?\d+\.\d+)",
                footer_pattern=r"\s--+",
                postprocess=lambda x: float(x),
                last_one_only=False)[0])

        # READ STRESS: (XX, YY, ZZ, XY, YZ, ZX) and convert values to array
        outcar.read_pattern(
            {
                'stress':
                r"in kB\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)"
            },
            terminate_on_match=False,
            postprocess=float)
        stress = outcar.data.get("stress")[0]
        self.stress = np.array([[stress[0], stress[3], stress[5]],
                                [stress[3], stress[1], stress[4]],
                                [stress[5], stress[4], stress[2]]])
        # Conversion from kbar to ev/A^3.
        self.stress *= KBAR_TO_EVA3
        # MAGNETIZATION and its PROJECTION ON EVERY ATOM
        try:
            # non-collinear
            outcar.read_pattern(
                {
                    'total_mag':
                    r"number of electron\s+\S+\s+magnetization\s+([\.\-\d]+)\s+([\.\-\d]+)\s+([\.\-\d]+)\s"
                },
                terminate_on_match=False,
                postprocess=float)
            self.__magnetization = outcar.data.get("total_mag")[-1]

            self.proj_magn = np.array([
                mag['tot'].moment for mag in outcar.magnetization
            ])  # 2-D array
        except:
            # collinear
            outcar.read_pattern(
                {
                    'total_mag':
                    r"number of electron\s+\S+\s+magnetization\s+("
                    r"\S+)"
                },
                terminate_on_match=False,
                postprocess=float)
            self.__magnetization = np.zeros(3)
            self.__magnetization[2] = outcar.data.get("total_mag")[-1][0]

            self.proj_magn = np.zeros((self.num_atoms, 3))
            for i in range(self.num_atoms):
                self.proj_magn[i,
                               2] = outcar.magnetization[i]['tot']  # 2-D array

        # NOTE: sum of magnetization projected on atoms differs from the total magnetization
        self.proj_magn_sum = np.sum(self.proj_magn, axis=0)
        self.get__magnetization()

        # POLARIZATION
        self.load_polarization(path)
        self.fileID = filename
Пример #4
0
def dos(relax_dir, k_product, hse_calc=False):
    """
    Set up the work function calculation based on the output of the geometry
    optimization.

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

    try:
        # Try reading the vasprun.xml file
        relax_vasprun = Vasprun(os.path.join(relax_dir, "vasprun.xml"))

        # Triple the amount of bands compared to the minimum
        nbands = relax_vasprun.parameters["NBANDS"] * 3

    except FileNotFoundError:
        # In case this file is not present, try the OUTCAR file.
        relax_outcar = Outcar(os.path.join(relax_dir, "OUTCAR"))

        relax_outcar.read_pattern(
            {"nbands":  r"\s+k-points\s+NKPTS =\s+[0123456789]+\s+k-points "
                        r"in BZ\s+NKDIM =\s+[0123456789]+\s+number of "
                        r"bands\s+NBANDS=\s+([\.\-\d]+)"},
            postprocess=int)

        # Include a significant number of empty bands
        nbands = relax_outcar.data['nbands'][0][0] * 3

    # Add some typical extra settings for the DOS calculation
    dos_incar = {"NEDOS": 2000, "NBANDS": nbands}

    if hse_calc:

        # Set up the calculation
        dos_calc = slabWorkFunctionHSESet.from_relax_calc(
            relax_dir=relax_dir,
            k_product=k_product,
            user_incar_settings=dos_incar
        )

        # Set up the calculation directory
        calculation_dir = os.path.join(os.path.split(relax_dir)[0], "hse_dos")

    else:

        # Use the charge density from the geometry optimization
        # dos_incar["ICHARG"] = 11

        # Set up the calculation
        dos_calc = slabWorkFunctionSet.from_relax_calc(
            relax_dir=relax_dir,
            k_product=k_product,
            user_incar_settings=dos_incar
        )

        # Set up the calculation directory
        calculation_dir = os.path.join(os.path.split(relax_dir)[0], "dftu_dos")

    if os.path.exists(calculation_dir):
        clean_dir(calculation_dir)

    # Write the input files of the calculation
    dos_calc.write_input(calculation_dir)

    # Return the calculation director for workflow purposes
    return calculation_dir