Beispiel #1
0
def project_orbitals_mgs(obasis0, obasis1, exp0, exp1, eps=1e-10):
    '''Project the orbitals in ``exp0`` (wrt ``obasis0``) on ``obasis1`` and store in ``exp1`` with the modified Gram-Schmidt algorithm.

       **Arguments:**

       obasis0
            The orbital basis for the original wavefunction expansion.

       obasis1
            The new orbital basis for the projected wavefunction expansion.

       exp0
            The expansion of the original orbitals.

       exp1 (output)
            An output argument in which the projected orbitals will be stored.

       **Optional arguments:**

       eps
            A threshold for the renormalization in the Gram-Schmidt procedure

       The projection is based on the Modified Gram-Schmidt (MGS) process. In
       each iteration of the MGS, a renormalization is carried out. If the norm
       in this step is smaller than ``eps``, an error is raised.

       Note that ``exp1`` will be incomplete in several ways. The orbital
       energies are not copied. Only the occupied orbitals in ``exp0`` are
       projected. Coefficients of higher orbitals are set to zero. The orbital
       occupations are simply copied. This should be sufficient to construct
       an initial guess in a new orbital basis set based on a previous solution.

       If the number of orbitals in ``exp1`` is too small to store all projected
       orbitals, an error is raised.
    '''
    # Compute the overlap matrix of the combined orbital basis
    obasis_both = GOBasis.concatenate(obasis0, obasis1)
    lf = DenseLinalgFactory(obasis_both.nbasis)
    olp_both = obasis_both.compute_overlap(lf)

    # Select the blocks of interest from the big overlap matrix
    olp_21 = olp_both._array[obasis0.nbasis:, :obasis0.nbasis]
    olp_22 = olp_both._array[obasis0.nbasis:, obasis0.nbasis:]

    # construct the projector
    projector = np.dot(np.linalg.pinv(olp_22), olp_21)

    # project occupied orbitals
    i1 = 0
    for i0 in xrange(exp0.nfn):
        if exp0.occupations[i0] == 0.0:
            continue
        if i1 > exp1.nfn:
            raise ProjectionError('Not enough functions available in exp1 to store the projected orbitals.')
        exp1.coeffs[:,i1] = np.dot(projector, exp0.coeffs[:,i0])
        exp1.occupations[i1] = exp0.occupations[i0]
        i1 += 1

    # clear all parts of exp1 that were not touched by the projection loop
    ntrans = i1
    del i1
    exp1.coeffs[:,ntrans:] = 0.0
    exp1.occupations[ntrans:] = 0.0
    exp1.energies[:] = 0.0

    # auxiliary function for the MGS algo
    def dot22(a, b):
        return np.dot(np.dot(a, olp_22), b)

    # Apply the MGS algorithm to orthogonalize the orbitals
    for i1 in xrange(ntrans):
        orb = exp1.coeffs[:,i1]

        # Subtract overlap with previous orbitals
        for j1 in xrange(i1):
            other = exp1.coeffs[:,j1]
            orb -= other*dot22(other, orb)/np.sqrt(dot22(orb, orb))

        # Renormalize
        norm = np.sqrt(dot22(orb, orb))
        if norm < eps:
            raise ProjectionError('The norm of a vector in the MGS algorithm becomes too small. Orbitals are redundant in new basis.')
        orb /= norm
Beispiel #2
0
def project_orbitals_mgs(obasis0, obasis1, orb0, orb1, eps=1e-10):
    '''Project the orbitals onto a new basis set with the modified Gram-Schmidt algorithm.

    The orbitals in ``orb0`` (w.r.t. ``obasis0``) are projected onto ``obasis1`` and
    stored in ``orb1``.

    Parameters
    ----------

    obasis0 : GOBasis
             The orbital basis for the original wavefunction expansion.
    obasis1 : GOBasis
             The new orbital basis for the projected wavefunction expansion.
    orb0 : Orbitals
          The expansion of the original orbitals.
    orb1 : Orbitals
          An output argument in which the projected orbitals will be stored.
    eps : float
         A threshold for the renormalization in the Gram-Schmidt procedure

    Notes
    -----

    The projection is based on the Modified Gram-Schmidt (MGS) process. In
    each iteration of the MGS, a renormalization is carried out. If the norm
    in this step is smaller than ``eps``, an error is raised.

    Note that ``orb1`` will be incomplete in several ways. The orbital
    energies are not copied. Only the occupied orbitals in ``orb0`` are
    projected. Coefficients of higher orbitals are set to zero. The orbital
    occupations are simply copied. This should be sufficient to construct
    an initial guess in a new orbital basis set based on a previous solution.

    If the number of orbitals in ``orb1`` is too small to store all projected
    orbitals, an error is raised.
    '''
    # Compute the overlap matrix of the combined orbital basis
    obasis_both = GOBasis.concatenate(obasis0, obasis1)
    olp_both = obasis_both.compute_overlap()

    # Select the blocks of interest from the big overlap matrix
    olp_21 = olp_both[obasis0.nbasis:, :obasis0.nbasis]
    olp_22 = olp_both[obasis0.nbasis:, obasis0.nbasis:]

    # Construct the projector. This minimizes the L2 norm between the new and old
    # orbitals, which does not account for orthonormality.
    projector = np.dot(np.linalg.pinv(olp_22), olp_21)

    # Project occupied orbitals.
    i1 = 0
    for i0 in xrange(orb0.nfn):
        if orb0.occupations[i0] == 0.0:
            continue
        if i1 > orb1.nfn:
            raise ProjectionError('Not enough functions available in orb1 to store the '
                                  'projected orbitals.')
        orb1.coeffs[:,i1] = np.dot(projector, orb0.coeffs[:,i0])
        orb1.occupations[i1] = orb0.occupations[i0]
        i1 += 1

    # clear all parts of orb1 that were not touched by the projection loop
    ntrans = i1
    del i1
    orb1.coeffs[:,ntrans:] = 0.0
    orb1.occupations[ntrans:] = 0.0
    orb1.energies[:] = 0.0

    # auxiliary function for the MGS algo
    def dot22(a, b):
        return np.dot(np.dot(a, olp_22), b)

    # Apply the MGS algorithm to orthogonalize the orbitals
    for i1 in xrange(ntrans):
        orb = orb1.coeffs[:, i1]

        # Subtract overlap with previous orbitals
        for j1 in xrange(i1):
            other = orb1.coeffs[:, j1]
            orb -= other*dot22(other, orb)/np.sqrt(dot22(other, other))

        # Renormalize
        norm = np.sqrt(dot22(orb, orb))
        if norm < eps:
            raise ProjectionError('The norm of a vector in the MGS algorithm becomes too '
                                  'small. Orbitals are redundant in new basis.')
        orb /= norm
Beispiel #3
0
def project_orbitals_mgs(obasis0, obasis1, exp0, exp1, eps=1e-10):
    '''Project the orbitals onto a new basis set with the modified Gram-Schmidt algorithm.

    The orbitals in ``exp0`` (w.r.t. ``obasis0``) are projected onto ``obasis1`` and
    stored in ``exp1``.

    Parameters
    ----------

    obasis0 : GOBasis
             The orbital basis for the original wavefunction expansion.
    obasis1 : GOBasis
             The new orbital basis for the projected wavefunction expansion.
    exp0 : DenseExpansion
          The expansion of the original orbitals.
    exp1 : DenseExpansion
          An output argument in which the projected orbitals will be stored.
    eps : float
         A threshold for the renormalization in the Gram-Schmidt procedure

    Notes
    -----

    The projection is based on the Modified Gram-Schmidt (MGS) process. In
    each iteration of the MGS, a renormalization is carried out. If the norm
    in this step is smaller than ``eps``, an error is raised.

    Note that ``exp1`` will be incomplete in several ways. The orbital
    energies are not copied. Only the occupied orbitals in ``exp0`` are
    projected. Coefficients of higher orbitals are set to zero. The orbital
    occupations are simply copied. This should be sufficient to construct
    an initial guess in a new orbital basis set based on a previous solution.

    If the number of orbitals in ``exp1`` is too small to store all projected
    orbitals, an error is raised.
    '''
    # Compute the overlap matrix of the combined orbital basis
    obasis_both = GOBasis.concatenate(obasis0, obasis1)
    lf = DenseLinalgFactory(obasis_both.nbasis)
    olp_both = obasis_both.compute_overlap(lf)

    # Select the blocks of interest from the big overlap matrix
    olp_21 = olp_both._array[obasis0.nbasis:, :obasis0.nbasis]
    olp_22 = olp_both._array[obasis0.nbasis:, obasis0.nbasis:]

    # Construct the projector. This minimizes the L2 norm between the new and old
    # orbitals, which does not account for orthonormality.
    projector = np.dot(np.linalg.pinv(olp_22), olp_21)

    # Project occupied orbitals.
    i1 = 0
    for i0 in xrange(exp0.nfn):
        if exp0.occupations[i0] == 0.0:
            continue
        if i1 > exp1.nfn:
            raise ProjectionError(
                'Not enough functions available in exp1 to store the '
                'projected orbitals.')
        exp1.coeffs[:, i1] = np.dot(projector, exp0.coeffs[:, i0])
        exp1.occupations[i1] = exp0.occupations[i0]
        i1 += 1

    # clear all parts of exp1 that were not touched by the projection loop
    ntrans = i1
    del i1
    exp1.coeffs[:, ntrans:] = 0.0
    exp1.occupations[ntrans:] = 0.0
    exp1.energies[:] = 0.0

    # auxiliary function for the MGS algo
    def dot22(a, b):
        return np.dot(np.dot(a, olp_22), b)

    # Apply the MGS algorithm to orthogonalize the orbitals
    for i1 in xrange(ntrans):
        orb = exp1.coeffs[:, i1]

        # Subtract overlap with previous orbitals
        for j1 in xrange(i1):
            other = exp1.coeffs[:, j1]
            orb -= other * dot22(other, orb) / np.sqrt(dot22(other, other))

        # Renormalize
        norm = np.sqrt(dot22(orb, orb))
        if norm < eps:
            raise ProjectionError(
                'The norm of a vector in the MGS algorithm becomes too '
                'small. Orbitals are redundant in new basis.')
        orb /= norm