Esempio n. 1
0
 def activate_robust_minimization(self):
     """
     Method to modify the set to use more robust SCF minimization technique
     """
     ot = OrbitalTransformation(
         minimizer="CG",
         preconditioner="FULL_ALL",
         algorithm="STRICT",
         energy_gap=0.05,
         linesearch="3PNT",
     )
     self.update({"FORCE_EVAL": {"DFT": {"SCF": {"OT": ot}}}})
Esempio n. 2
0
 def activate_very_strict_minimization(self):
     """
     Method to modify the set to use very strict SCF minimization scheme
     :return:
     """
     ot = OrbitalTransformation(
         minimizer="CG",
         preconditioner="FULL_ALL",
         algorithm="STRICT",
         energy_gap=0.05,
         linesearch="GOLD",
     )
     self.update({"FORCE_EVAL": {"DFT": {"SCF": {"OT": ot}}}})
Esempio n. 3
0
 def activate_fast_minimization(self, on):
     """
     Method to modify the set to use fast SCF minimization.
     """
     if on:
         ot = OrbitalTransformation(
             minimizer="DIIS",
             preconditioner="FULL_ALL",
             algorithm="IRAC",
             energy_gap=0.01,
             linesearch="2PNT",
         )
         self.update({"FORCE_EVAL": {"DFT": {"SCF": {"OT": ot}}}})
Esempio n. 4
0
    def __init__(
        self,
        structure: Union[Structure, Molecule],
        ot: bool = True,
        band_gap: float = 0.01,
        eps_default: float = 1e-12,
        eps_scf: float = 1e-7,
        max_scf: Union[int, None] = None,
        minimizer: str = "DIIS",
        preconditioner: str = "FULL_ALL",
        algorithm: str = "STRICT",
        linesearch: str = "2PNT",
        cutoff: int = 1200,
        rel_cutoff: int = 80,
        ngrids: int = 5,
        progression_factor: int = 3,
        override_default_params: Dict = {},
        wfn_restart_file_name: str = None,
        kpoints: Union[Kpoints, None] = None,
        smearing: bool = False,
        **kwargs
    ):
        """
        Args:
            structure: Pymatgen structure or molecule object
            ot (bool): Whether or not to use orbital transformation method for matrix diagonalization. OT is the
                flagship scf solver of CP2K, and will provide huge speed-ups for this part of the calculation,
                but the system must have a band gap for OT to be used (higher band-gap --> faster convergence).
                Band gap is also used by the preconditioner for OT, and should be set as a value SMALLER than the true
                band gap to get good efficiency. Generally, this parameter does not need to be changed from
                default of 0.01
            band_gap (float): The band gap can also be specified in order to determine if ot should be turned on.
            eps_default (float): Replaces all EPS_XX Keywords in the DFT section (NOT its subsections!) to have this
                value, ensuring an overall accuracy of at least this much.
            eps_scf (float): The convergence criteria for leaving the SCF loop in Hartrees. Default is 1e-7. Should
                ensure reasonable results for all properties. Smaller than 1e-7 is generally not needed unless
                you need very high precision. 1e-6 may be used for difficult systems, and should still give
                reasonable results for most properties.
            max_scf (int): The max number of SCF cycles before terminating the solver. NOTE: With the OT solver, this
                corresponds to the max number of INNER scf loops, and then the outer loops are set with outer_max_scf,
                while with diagnolization it corresponds to the overall (INNER*OUTER) number of SCF steps, with the
                inner loop limit set by
            minimizer (str): The minimization scheme. DIIS can be as much as 50% faster than the more robust conjugate
                gradient method, and so it is chosen as default. Switch to CG if dealing with a difficult system.
            preconditioner (str): Preconditioner for the OT method. FULL_ALL is the most reliable, and is the
                default. Though FULL_SINGLE_INVERSE has faster convergence according to our internal tests. Should
                only change from theses two when simulation cell gets to be VERY large,
                in which case FULL_KINETIC might be preferred.
            cutoff (int): Cutoff energy (in Ry) for the finest level of the multigrid. A high cutoff will allow you to
                have very accurate calculations PROVIDED that REL_CUTOFF is appropriate.
            rel_cutoff (int): This cutoff decides how the Guassians are mapped onto the different levels of the
                multigrid. From CP2K: A Gaussian is mapped onto the coarsest level of the multi-grid, on which the
                    function will cover number of grid points greater than or equal to the number of grid points
                    will cover on a reference grid defined by REL_CUTOFF.
            progression_factor (int): Divisor of CUTOFF to get the cutoff for the next level of the multigrid.

            Takeaway for the cutoffs: https://www.cp2k.org/howto:converging_cutoff
            If CUTOFF is too low, then all grids will be coarse and the calculation may become inaccurate; and if
            REL_CUTOFF is too low, then even if you have a high CUTOFF, all Gaussians will be mapped onto the coarsest
            level of the multi-grid, and thus the effective integration grid for the calculation may still be too
            coarse.
        """

        super().__init__(structure, **kwargs)

        self.structure = structure
        self.ot = ot
        self.band_gap = band_gap
        self.eps_default = eps_default
        self.eps_scf = eps_scf
        self.max_scf = max_scf
        self.minimizer = minimizer
        self.preconditioner = preconditioner
        self.algorithm = algorithm
        self.linesearch = linesearch
        self.cutoff = cutoff
        self.rel_cutoff = rel_cutoff
        self.ngrids = ngrids
        self.progression_factor = progression_factor
        self.override_default_params = override_default_params
        self.wfn_restart_file_name = wfn_restart_file_name
        self.kpoints = kpoints
        self.smearing = smearing
        self.kwargs = kwargs

        # Build the QS Section
        qs = QS(eps_default=eps_default)
        max_scf = (
            max_scf if max_scf else 20 if ot else 400
        )  # If ot, max_scf is for inner loop
        scf = Scf(eps_scf=eps_scf, max_scf=max_scf, subsections={})

        # If there's a band gap, use OT, else use Davidson
        if ot:
            if band_gap <= 0:
                warnings.warn(
                    "Orbital Transformation method is being used for"
                    "a system without a bandgap. OT can have very poor"
                    "convergence for metallic systems, proceed with caution.",
                    UserWarning,
                )
            scf.insert(
                OrbitalTransformation(
                    minimizer=minimizer,
                    preconditioner=preconditioner,
                    energy_gap=band_gap,
                    algorithm=algorithm,
                    linesearch=linesearch,
                )
            )
            scf.insert(
                Section(
                    "OUTER_SCF",
                    subsections={},
                    keywords={
                        "MAX_SCF": Keyword("MAX_SCF", kwargs.get("outer_max_scf", 20)),
                        "EPS_SCF": Keyword(
                            "EPS_SCF", kwargs.get("outer_eps_scf", eps_scf)
                        ),
                    },
                )
            )
        else:
            scf.insert(Section("DIAGONALIZATION", subsections={}))
            mixing_kwds = {
                "METHOD": Keyword("METHOD", "BROYDEN_MIXING"),
                "ALPHA": Keyword("ALPHA", 0.2),
                "NBUFFER": Keyword("NBUFFER", 5),
            }
            mixing = Section("MIXING", keywords=mixing_kwds, subsections=None)
            scf.insert(mixing)
            davidson_kwds = {"PRECONDITIONER": Keyword("PRECONDITIONER", "FULL_ALL")}
            davidson = Section("DAVIDSON", keywords=davidson_kwds, subsections=None)
            scf["DIAGONALIZATION"].insert(davidson)

        # Create the multigrid for FFTs
        mgrid = Mgrid(
            cutoff=cutoff,
            rel_cutoff=rel_cutoff,
            ngrids=ngrids,
            progression_factor=progression_factor,
        )

        # Set the DFT calculation with global parameters
        dft = Dft(
            MULTIPLICITY=self.multiplicity,
            CHARGE=self.charge,
            basis_set_filenames=self.basis_set_file_names,
            potential_filename=self.potential_file_name,
            subsections={"QS": qs, "SCF": scf, "MGRID": mgrid},
            wfn_restart_file_name=wfn_restart_file_name,
        )

        if kpoints:
            dft.insert(Kpoints.from_kpoints(kpoints))
        if smearing or (band_gap <= 0.0):
            scf.kwargs["ADDED_MOS"] = 100
            scf["ADDED_MOS"] = 100  # TODO: how to grab the appropriate number?
            scf.insert(Smear())

        # Create subsections and insert into them
        self["FORCE_EVAL"].insert(dft)
        xc_functional = XC_FUNCTIONAL(functional=kwargs.get("functional", "PBE"))
        xc = Section("XC", subsections={"XC_FUNCTIONAL": xc_functional})
        self["FORCE_EVAL"]["DFT"].insert(xc)
        self["FORCE_EVAL"]["DFT"].insert(Section("PRINT", subsections={}))

        if isinstance(structure, Molecule):
            self.activate_nonperiodic()

        if kwargs.get("print_pdos", True):
            self.print_pdos()
        if kwargs.get("print_ldos", False):
            self.print_ldos()
        if kwargs.get("print_mo_cubes", True):
            self.print_mo_cubes()
        if kwargs.get("print_hartree_potential", False):
            self.print_hartree_potential()
        if kwargs.get("print_e_density", False):
            self.print_e_density()

        self.update(self.override_default_params)