示例#1
0
def test_anapot_lanczos():
    geom = AnaPot.get_geom((-0.5767, 1.6810, 0.))
    guess = (0.4, 0.3, 0.0)
    w_min, v_min = geom_lanczos(geom, guess=guess, dx=1e-5, dl=1e-5, logger=logger)

    H = geom.hessian
    w, v = np.linalg.eigh(H)
    w_ref = w[0]
    v_ref = v[:,0]
    assert w_min == pytest.approx(w_ref, abs=1e-4)
    assert any([np.allclose(v, v_ref, atol=5e-2) for v in (v_min, -v_min)])
示例#2
0
def test_hcn_iso_lanczos(coord_type, guess):
    geom = geom_loader("lib:hcn_iso_hf_sto3g_ts_opt.xyz", coord_type=coord_type)
    calc = PySCF(pal=2, basis="sto3g")
    geom.set_calculator(calc)

    w_min, v_min = geom_lanczos(geom, guess=guess, logger=logger)

    # Reference values
    H = geom.hessian
    w, v = np.linalg.eigh(H)
    w_ref = w[0]
    v_ref = v[:,0]

    assert w_min == pytest.approx(w_ref, abs=1e-2)
    assert any([np.allclose(v, v_ref, atol=5e-2) for v in (v_min, -v_min)])
示例#3
0
    def get_tangent(self, i, kind="upwinding", lanczos_guess=None):
        """ [1] Equations (8) - (11)"""

        tangent_kinds = ("upwinding", "simple", "bisect", "lanczos")
        assert kind in tangent_kinds, \
            "Invalid kind! Valid kinds are: {tangent_kinds}"
        prev_index = max(i - 1, 0)
        next_index = min(i + 1, len(self.images) - 1)

        prev_image = self.images[prev_index]
        ith_image = self.images[i]
        next_image = self.images[next_index]

        # If (i == 0) or (i == len(self.images)-1) then one
        # of this tangents is zero.
        tangent_plus = next_image - ith_image
        tangent_minus = ith_image - prev_image

        # Handle first and last image
        if i == 0:
            return tangent_plus / np.linalg.norm(tangent_plus)
        elif i == (len(self.images) - 1):
            return tangent_minus / np.linalg.norm(tangent_minus)

        # [1], Eq. (1)
        if kind == "simple":
            tangent = next_image - prev_image
        # [1], Eq. (2)
        elif kind == "bisect":
            first_term = tangent_minus / np.linalg.norm(tangent_minus)
            sec_term = tangent_plus / np.linalg.norm(tangent_plus)
            tangent = first_term + sec_term
        # Upwinding tangent from [1] Eq. (8) and so on
        elif kind == "upwinding":
            prev_energy = prev_image.energy
            ith_energy = ith_image.energy
            next_energy = next_image.energy

            next_energy_diff = abs(next_energy - ith_energy)
            prev_energy_diff = abs(prev_energy - ith_energy)
            delta_energy_max = max(next_energy_diff, prev_energy_diff)
            delta_energy_min = min(next_energy_diff, prev_energy_diff)

            # Uphill
            if next_energy > ith_energy > prev_energy:
                tangent = tangent_plus
            # Downhill
            elif next_energy < ith_energy < prev_energy:
                tangent = tangent_minus
            # Minimum or Maximum
            else:
                if next_energy >= prev_energy:
                    tangent = (tangent_plus * delta_energy_max +
                               tangent_minus * delta_energy_min)
                # next_energy < prev_energy
                else:
                    tangent = (tangent_plus * delta_energy_min +
                               tangent_minus * delta_energy_max)
        elif kind == "lanczos":
            # Calculating a lanczos tangent is costly, so we store the
            # tangent in a dictionary. The current coordinates are
            # stringified with precision=4 and then hashed. The tangent
            # is stored/looked up with this hash.
            cur_hash = hash_arr(ith_image.coords, precision=4)
            try:
                tangent = self.lanczos_tangents[cur_hash]
                self.log(
                    "Returning previously calculated Lanczos tangent with "
                    f"hash={cur_hash}")
            except KeyError:
                # Try to use previous Lanczos tangent
                guess = lanczos_guess
                if (guess is None) and (self.prev_lanczos_hash is not None):
                    guess = self.lanczos_tangents[self.prev_lanczos_hash]
                    self.log(
                        f"Using tangent with hash={self.prev_lanczos_hash} "
                        "as initial guess for Lanczos algorithm.")
                w_min, tangent = geom_lanczos(ith_image,
                                              guess=guess,
                                              logger=self.logger)
                self.lanczos_tangents[cur_hash] = tangent
                # Update hash
                self.prev_lanczos_hash = cur_hash

        tangent /= np.linalg.norm(tangent)
        return tangent