Beispiel #1
0
def _fix_molden_from_buggy_codes(result, filename):
    """Detect errors in the data loaded from a molden/mkl/... file and correct.

       **Argument:**

       result
            A dictionary with the data loaded in the ``load_molden`` function.

       This function can recognize erroneous files created by PSI4 and ORCA. The
       data in the obasis and signs fields will be updated accordingly.
    """
    obasis = result['obasis']
    permutation = result.get('permutation', None)
    if _is_normalized_properly(result['lf'], obasis, permutation,
                               result['exp_alpha'], result.get('exp_beta')):
        # The file is good. No need to change data.
        return
    if log.do_medium:
        log('Detected incorrect normalization of orbitals loaded from a file.')
    # Try to fix it as if it was a file generated by ORCA.
    orca_signs = _get_orca_signs(obasis)
    orca_con_coeffs = _get_fixed_con_coeffs(obasis, 'orca')
    orca_obasis = GOBasis(obasis.centers, obasis.shell_map, obasis.nprims,
                          obasis.shell_types, obasis.alphas, orca_con_coeffs)
    if _is_normalized_properly(result['lf'], orca_obasis,
                               permutation, result['exp_alpha'],
                               result.get('exp_beta'), orca_signs):
        if log.do_medium:
            log('Detected typical ORCA errors in file. Fixing them...')
        result['obasis'] = orca_obasis
        result['signs'] = orca_signs
        return
    # Try to fix it as if it was a file generated by PSI4 (pre 1.0).
    psi4_con_coeffs = _get_fixed_con_coeffs(obasis, 'psi4')
    psi4_obasis = GOBasis(obasis.centers, obasis.shell_map, obasis.nprims,
                          obasis.shell_types, obasis.alphas, psi4_con_coeffs)
    if _is_normalized_properly(result['lf'], psi4_obasis, permutation,
                               result['exp_alpha'], result.get('exp_beta')):
        if log.do_medium:
            log('Detected typical PSI4 errors in file. Fixing them...')
        result['obasis'] = psi4_obasis
        return
    # Last resort: simply renormalize all contractions
    normed_con_coeffs = _normalized_contractions(obasis)
    normed_obasis = GOBasis(obasis.centers, obasis.shell_map, obasis.nprims,
                            obasis.shell_types, obasis.alphas,
                            normed_con_coeffs)
    if _is_normalized_properly(result['lf'], normed_obasis, permutation,
                               result['exp_alpha'], result.get('exp_beta')):
        if log.do_medium:
            log('Detected unnormalized contractions in file. Fixing them...')
        result['obasis'] = normed_obasis
        return

    raise IOError(('Could not correct the data read from %s. The molden or '
                   'mkl file you are trying to load contains errors. Please '
                   'report this problem to [email protected], so he '
                   'can fix it.') % filename)
Beispiel #2
0
def _read_cp2k_contracted_obasis(f):
    """Read a contracted basis set from an open CP2K ATOM output file.

    Parameters
    ----------
    f : file
        An open readable file object.

    Returns
    -------
    obasis : GOBasis
             The orbital basis read from the file.
    """
    # Load the relevant data from the file
    basis_desc = []
    for line in f:
        if line.startswith(' *******************'):
            break
        elif line[3:12] == 'Functions':
            shell_type = str_to_shell_types(line[1:2], pure=True)[0]
            a = []  # exponents (alpha)
            c = []  # contraction coefficients
            basis_desc.append((shell_type, a, c))
        else:
            values = [float(w) for w in line.split()]
            a.append(values[0])  # one exponent per line
            c.append(values[1:])  # many contraction coefficients per line

    # Convert the basis into HORTON format
    shell_map = []
    shell_types = []
    nprims = []
    alphas = []
    con_coeffs = []

    for shell_type, a, c in basis_desc:
        # get correction to contraction coefficients. CP2K uses different normalization
        # conventions.
        corrections = _get_cp2k_norm_corrections(abs(shell_type), np.array(a))
        c = np.array(c) / corrections.reshape(-1, 1)
        # fill in arrays
        for col in c.T:
            shell_map.append(0)
            shell_types.append(shell_type)
            nprims.append(len(col))
            alphas.extend(a)
            con_coeffs.extend(col)

    # Create the basis object
    coordinates = np.zeros((1, 3))
    shell_map = np.array(shell_map)
    nprims = np.array(nprims)
    shell_types = np.array(shell_types)
    alphas = np.array(alphas)
    con_coeffs = np.array(con_coeffs)
    obasis = GOBasis(coordinates, shell_map, nprims, shell_types, alphas,
                     con_coeffs)
    return obasis
Beispiel #3
0
    def apply_to(self, system):
        """Construct a GOBasis object for the system"""
        shell_map = []
        nprims = []
        shell_types = []
        alphas = []
        con_coeffs = []

        def get_basis(i, n):
            """Look up the basis for a given atom"""
            basis = self.index_map.get(i)
            if basis is not None:
                return basis
            basis = self.element_map.get(n)
            if basis is not None:
                return basis
            if self.default is None:
                raise KeyError('Could not find basis for atom %i.' % i)
            else:
                return self.default

        def translate_basis(basis_x, n):
            """Translate the first argument into a GOBasisAtom instance"""
            if isinstance(basis_x, basestring):
                basis_fam = go_basis_families.get(basis_x.lower())
                if basis_fam is None:
                    raise ValueError('Unknown basis family: %s' % basis_x)
                basis_atom = basis_fam.get(n)
                if basis_atom is None:
                    raise ValueError(
                        'The basis family %s does not contain element %i.' %
                        (basis_x, n))
                return basis_atom
            elif isinstance(basis_x, GOBasisFamily):
                basis_atom = basis_x.get(n)
                if basis_atom is None:
                    raise ValueError(
                        'The basis family %s does not contain element %i.' %
                        (basis_x.name, n))
                return basis_atom
            elif isinstance(basis_x, GOBasisAtom):
                return basis_x
            else:
                raise ValueError(
                    'Can not interpret %s as an atomic basis function.' %
                    basis_x)

        # Loop over the atoms and fill in all the lists
        for i in xrange(system.natom):
            n = system.numbers[i]
            basis_x = get_basis(i, n)
            basis_atom = translate_basis(basis_x, n)
            basis_atom.extend(i, shell_map, nprims, shell_types, alphas,
                              con_coeffs, self.pure)

        # Return the Gaussian basis object.
        return GOBasis(system.coordinates, shell_map, nprims, shell_types,
                       alphas, con_coeffs)
Beispiel #4
0
 def normalize(self):
     """Normalize the contraction."""
     if self.is_generalized():
         raise NotImplementedError("Only segmented contractions can be normalized.")
     # Warning! Ugly code ahead to avoid re-implementing the norm of contraction. The
     # code below (ab)uses the GOBasis machinery to get that result.
     # 1) Constract a GOBasis object with only this contraction.
     centers = np.array([[0.0, 0.0, 0.0]])
     shell_map = np.array([0])
     nprims = np.array([len(self.alphas)])
     shell_types = np.array([self.shell_type])
     alphas = self.alphas
     con_coeffs = self.con_coeffs
     gobasis = GOBasis(centers, shell_map, nprims, shell_types, alphas, con_coeffs)
     # 2) Get the first diagonal element of the overlap matrix
     olpdiag = gobasis.compute_overlap()[0, 0]
     # 3) Normalize the contraction
     self.con_coeffs /= np.sqrt(olpdiag)
Beispiel #5
0
 def normalize(self):
     """Normalize the contraction."""
     if self.is_generalized():
         raise NotImplementedError(
             "Only segmented contractions can be normalized.")
     # Warning! Ugly code ahead to avoid re-implementing the norm of contraction. The
     # code below (ab)uses the GOBasis machinery to get that result.
     # 1) Constract a GOBasis object with only this contraction.
     centers = np.array([[0.0, 0.0, 0.0]])
     shell_map = np.array([0])
     nprims = np.array([len(self.alphas)])
     shell_types = np.array([self.shell_type])
     alphas = self.alphas
     con_coeffs = self.con_coeffs
     gobasis = GOBasis(centers, shell_map, nprims, shell_types, alphas,
                       con_coeffs)
     # 2) Get the first diagonal element of the overlap matrix
     olpdiag = gobasis.compute_overlap()[0, 0]
     # 3) Normalize the contraction
     self.con_coeffs /= np.sqrt(olpdiag)
Beispiel #6
0
def _read_cp2k_uncontracted_obasis(f):
    """Read an uncontracted basis set from an open CP2K ATOM output file.

    Parameters
    ----------
    f : file
        An open readable file object.

    Returns
    -------
    obasis : GOBasis
             The orbital basis read from the file.
    """
    # Load the relevant data from the file
    basis_desc = []
    shell_type = None
    for line in f:
        if line.startswith(' *******************'):
            break
        elif line[3:13] == 'Exponents:':
            shell_type = str_to_shell_types(line[1:2], pure=True)[0]
        words = line.split()
        if len(words) >= 2:
            # read the exponent
            alpha = float(words[-1])
            basis_desc.append((shell_type, alpha))

    # Convert the basis into HORTON format
    shell_map = []
    shell_types = []
    nprims = []
    alphas = []
    con_coeffs = []

    # fill in arrays
    for shell_type, alpha in basis_desc:
        correction = _get_cp2k_norm_corrections(abs(shell_type), alpha)
        shell_map.append(0)
        shell_types.append(shell_type)
        nprims.append(1)
        alphas.append(alpha)
        con_coeffs.append(1.0 / correction)

    # Create the basis object
    centers = np.zeros((1, 3))
    shell_map = np.array(shell_map)
    nprims = np.array(nprims)
    shell_types = np.array(shell_types)
    alphas = np.array(alphas)
    con_coeffs = np.array(con_coeffs)
    obasis = GOBasis(centers, shell_map, nprims, shell_types, alphas,
                     con_coeffs)
    return obasis
Beispiel #7
0
    def helper_obasis(f, coordinates, pure):
        """Load the orbital basis"""
        shell_types = []
        shell_map = []
        nprims = []
        alphas = []
        con_coeffs = []

        icenter = 0
        in_atom = False
        in_shell = False
        while True:
            last_pos = f.tell()
            line = f.readline()
            if len(line) == 0:
                break
            words = line.split()
            if len(words) == 0:
                in_atom = False
                in_shell = False
            elif len(words) == 2 and not in_atom:
                icenter = int(words[0]) - 1
                in_atom = True
                in_shell = False
            elif len(words) == 3:
                in_shell = True
                shell_map.append(icenter)
                shell_label = words[0].lower()
                shell_type = str_to_shell_types(shell_label,
                                                pure.get(shell_label,
                                                         False))[0]
                shell_types.append(shell_type)
                nprims.append(int(words[1]))
            elif len(words) == 2 and in_atom:
                assert in_shell
                alpha = float(words[0].replace('D', 'E'))
                alphas.append(alpha)
                con_coeff = float(words[1].replace('D', 'E'))
                con_coeffs.append(con_coeff)
            else:
                # done, go back one line
                f.seek(last_pos)
                break

        shell_map = np.array(shell_map)
        nprims = np.array(nprims)
        shell_types = np.array(shell_types)
        alphas = np.array(alphas)
        con_coeffs = np.array(con_coeffs)
        return GOBasis(coordinates, shell_map, nprims, shell_types, alphas,
                       con_coeffs)
Beispiel #8
0
def load_fchk(filename, lf):
    '''Load from a formatted checkpoint file.

       **Arguments:**

       filename
            The filename of the Gaussian formatted checkpoint file.

       lf
            A LinalgFactory instance.

       **Returns** a dictionary with: ``title``, ``coordinates``, ``numbers``,
       ``obasis``, ``exp_alpha``, ``permutation``, ``energy``,
       ``pseudo_numbers``, ``mulliken_charges``. The dictionary may also
       contain: ``npa_charges``, ``esp_charges``, ``exp_beta``, ``dm_full_mp2``,
       ``dm_spin_mp2``, ``dm_full_mp3``, ``dm_spin_mp3``, ``dm_full_cc``,
       ``dm_spin_cc``, ``dm_full_ci``, ``dm_spin_ci``, ``dm_full_scf``,
       ``dm_spin_scf``, ``polar``, ``dipole_moment``, ``quadrupole_moment``.
    '''
    from horton.gbasis.cext import GOBasis

    fchk = FCHKFile(filename, [
        "Number of electrons",
        "Number of independant functions",
        "Number of independent functions",
        "Number of alpha electrons",
        "Number of beta electrons",
        "Atomic numbers",
        "Current cartesian coordinates",
        "Shell types",
        "Shell to atom map",
        "Shell to atom map",
        "Number of primitives per shell",
        "Primitive exponents",
        "Contraction coefficients",
        "P(S=P) Contraction coefficients",
        "Alpha Orbital Energies",
        "Alpha MO coefficients",
        "Beta Orbital Energies",
        "Beta MO coefficients",
        "Total Energy",
        "Nuclear charges",
        'Total SCF Density',
        'Spin SCF Density',
        'Total MP2 Density',
        'Spin MP2 Density',
        'Total MP3 Density',
        'Spin MP3 Density',
        'Total CC Density',
        'Spin CC Density',
        'Total CI Density',
        'Spin CI Density',
        'Mulliken Charges',
        'ESP Charges',
        'NPA Charges',
        'Polarizability',
        'Dipole Moment',
        'Quadrupole Moment',
    ])

    # A) Load the geometry
    numbers = fchk["Atomic numbers"]
    coordinates = fchk["Current cartesian coordinates"].reshape(-1, 3)
    pseudo_numbers = fchk["Nuclear charges"]
    # Mask out ghost atoms
    mask = pseudo_numbers != 0.0
    numbers = numbers[mask]
    # Do not overwrite coordinates array, because it is needed to specify basis
    system_coordinates = coordinates[mask]
    pseudo_numbers = pseudo_numbers[mask]

    # B) Load the orbital basis set
    shell_types = fchk["Shell types"]
    shell_map = fchk["Shell to atom map"] - 1
    nprims = fchk["Number of primitives per shell"]
    alphas = fchk["Primitive exponents"]
    ccoeffs_level1 = fchk["Contraction coefficients"]
    ccoeffs_level2 = fchk.get("P(S=P) Contraction coefficients")

    my_shell_types = []
    my_shell_map = []
    my_nprims = []
    my_alphas = []
    con_coeffs = []
    counter = 0
    for i, n in enumerate(nprims):
        if shell_types[i] == -1:
            # Special treatment for SP shell type
            my_shell_types.append(0)
            my_shell_types.append(1)
            my_shell_map.append(shell_map[i])
            my_shell_map.append(shell_map[i])
            my_nprims.append(nprims[i])
            my_nprims.append(nprims[i])
            my_alphas.append(alphas[counter:counter + n])
            my_alphas.append(alphas[counter:counter + n])
            con_coeffs.append(ccoeffs_level1[counter:counter + n])
            con_coeffs.append(ccoeffs_level2[counter:counter + n])
        else:
            my_shell_types.append(shell_types[i])
            my_shell_map.append(shell_map[i])
            my_nprims.append(nprims[i])
            my_alphas.append(alphas[counter:counter + n])
            con_coeffs.append(ccoeffs_level1[counter:counter + n])
        counter += n
    my_shell_types = np.array(my_shell_types)
    my_shell_map = np.array(my_shell_map)
    my_nprims = np.array(my_nprims)
    my_alphas = np.concatenate(my_alphas)
    con_coeffs = np.concatenate(con_coeffs)
    del shell_map
    del shell_types
    del nprims
    del alphas

    obasis = GOBasis(coordinates, my_shell_map, my_nprims, my_shell_types,
                     my_alphas, con_coeffs)
    if lf.default_nbasis is not None and lf.default_nbasis != obasis.nbasis:
        raise TypeError(
            'The value of lf.default_nbasis does not match nbasis reported in the fchk file.'
        )
    lf.default_nbasis = obasis.nbasis

    # permutation of the orbital basis functions
    permutation_rules = {
        -9: np.arange(19),
        -8: np.arange(17),
        -7: np.arange(15),
        -6: np.arange(13),
        -5: np.arange(11),
        -4: np.arange(9),
        -3: np.arange(7),
        -2: np.arange(5),
        0: np.array([0]),
        1: np.arange(3),
        2: np.array([0, 3, 4, 1, 5, 2]),
        3: np.array([0, 4, 5, 3, 9, 6, 1, 8, 7, 2]),
        4: np.arange(15)[::-1],
        5: np.arange(21)[::-1],
        6: np.arange(28)[::-1],
        7: np.arange(36)[::-1],
        8: np.arange(45)[::-1],
        9: np.arange(55)[::-1],
    }
    permutation = []
    for shell_type in my_shell_types:
        permutation.extend(permutation_rules[shell_type] + len(permutation))
    permutation = np.array(permutation, dtype=int)

    result = {
        'title': fchk.title,
        'coordinates': system_coordinates,
        'lf': lf,
        'numbers': numbers,
        'obasis': obasis,
        'permutation': permutation,
        'pseudo_numbers': pseudo_numbers,
    }

    # C) Load density matrices
    def load_dm(label):
        if label in fchk:
            dm = lf.create_two_index(obasis.nbasis)
            start = 0
            for i in xrange(obasis.nbasis):
                stop = start + i + 1
                dm._array[i, :i + 1] = fchk[label][start:stop]
                dm._array[:i + 1, i] = fchk[label][start:stop]
                start = stop
            return dm

    # First try to load the post-hf density matrices.
    load_orbitals = True
    for key in 'MP2', 'MP3', 'CC', 'CI', 'SCF':
        dm_full = load_dm('Total %s Density' % key)
        if dm_full is not None:
            result['dm_full_%s' % key.lower()] = dm_full
        dm_spin = load_dm('Spin %s Density' % key)
        if dm_spin is not None:
            result['dm_spin_%s' % key.lower()] = dm_spin

    # D) Load the wavefunction
    # Handle small difference in fchk files from g03 and g09
    nbasis_indep = fchk.get("Number of independant functions") or \
                   fchk.get("Number of independent functions")
    if nbasis_indep is None:
        nbasis_indep = obasis.nbasis

    # Load orbitals
    nalpha = fchk['Number of alpha electrons']
    nbeta = fchk['Number of beta electrons']
    if nalpha < 0 or nbeta < 0 or nalpha + nbeta <= 0:
        raise ValueError(
            'The file %s does not contain a positive number of electrons.' %
            filename)
    exp_alpha = lf.create_expansion(obasis.nbasis, nbasis_indep)
    exp_alpha.coeffs[:] = fchk['Alpha MO coefficients'].reshape(
        nbasis_indep, obasis.nbasis).T
    exp_alpha.energies[:] = fchk['Alpha Orbital Energies']
    exp_alpha.occupations[:nalpha] = 1.0
    result['exp_alpha'] = exp_alpha
    if 'Beta Orbital Energies' in fchk:
        # UHF case
        exp_beta = lf.create_expansion(obasis.nbasis, nbasis_indep)
        exp_beta.coeffs[:] = fchk['Beta MO coefficients'].reshape(
            nbasis_indep, obasis.nbasis).T
        exp_beta.energies[:] = fchk['Beta Orbital Energies']
        exp_beta.occupations[:nbeta] = 1.0
        result['exp_beta'] = exp_beta
    elif fchk['Number of beta electrons'] != fchk['Number of alpha electrons']:
        # ROHF case
        exp_beta = lf.create_expansion(obasis.nbasis, nbasis_indep)
        exp_beta.coeffs[:] = fchk['Alpha MO coefficients'].reshape(
            nbasis_indep, obasis.nbasis).T
        exp_beta.energies[:] = fchk['Alpha Orbital Energies']
        exp_beta.occupations[:nbeta] = 1.0
        result['exp_beta'] = exp_beta
        # Delete dm_full_scf because it is known to be buggy
        result.pop('dm_full_scf')

    # E) Load properties
    result['energy'] = fchk['Total Energy']
    if 'Polarizability' in fchk:
        result['polar'] = triangle_to_dense(fchk['Polarizability'])
    if 'Dipole Moment' in fchk:
        result['dipole_moment'] = fchk['Dipole Moment']
    if 'Quadrupole Moment' in fchk:
        # Convert to HORTON ordering: xx, xy, xz, yy, yz, zz
        result['quadrupole_moment'] = fchk['Quadrupole Moment'][[
            0, 3, 4, 1, 5, 2
        ]]

    # F) Load optional properties
    # Mask out ghost atoms from charges
    if 'Mulliken Charges' in fchk:
        result['mulliken_charges'] = fchk['Mulliken Charges'][mask]
    if 'ESP Charges' in fchk:
        result['esp_charges'] = fchk['ESP Charges'][mask]
    if 'NPA Charges' in fchk:
        result['npa_charges'] = fchk['NPA Charges'][mask]

    return result
Beispiel #9
0
def load_atom_cp2k(filename, lf):
    with open(filename) as f:
        # Find the element number
        for line in f:
            if line.startswith(' Atomic Energy Calculation'):
                number = int(line[-5:-1])
                break

        # Go to the pseudo basis set
        for line in f:
            if line.startswith(' Pseudopotential Basis'):
                break

        # TODO: add support for uncontracted and all-electron basis
        f.next()  # empty line
        line = f.next()  # Check for GTO
        assert line == ' ********************** Contracted Gaussian Type Orbitals **********************\n'

        # Load the basis used for the PP wavefn
        basis_desc = []
        for line in f:
            if line.startswith(' *******************'):
                break
            elif line[3:12] == 'Functions':
                shell_type = str_to_shell_types(line[1:2], pure=True)[0]
                a = []
                c = []
                basis_desc.append((shell_type, a, c))
            else:
                values = [float(w) for w in line.split()]
                a.append(values[0])
                c.append(values[1:])

        # Convert the basis into Horton format
        shell_map = []
        shell_types = []
        nprims = []
        alphas = []
        con_coeffs = []

        for shell_type, a, c in basis_desc:
            # get correction to contraction coefficients.
            corrections = _get_cp2k_norm_corrections(abs(shell_type), a)
            c = np.array(c) / corrections.reshape(-1, 1)
            # fill in arrays
            for col in c.T:
                shell_map.append(0)
                shell_types.append(shell_type)
                nprims.append(len(col))
                alphas.extend(a)
                con_coeffs.extend(col)

        # Create the basis object
        coordinates = np.zeros((1, 3))
        shell_map = np.array(shell_map)
        nprims = np.array(nprims)
        shell_types = np.array(shell_types)
        alphas = np.array(alphas)
        con_coeffs = np.array(con_coeffs)
        obasis = GOBasis(coordinates, shell_map, nprims, shell_types, alphas,
                         con_coeffs)

        # Search for (un)restricted
        restricted = None
        for line in f:
            if line.startswith(' METHOD    |'):
                if 'Unrestricted' in line:
                    restricted = False
                    break
                elif 'Restricted' in line:
                    restricted = True
                    break

        # Search for the core charge (pseudo number)
        for line in f:
            if line.startswith('          Core Charge'):
                pseudo_number = float(line[70:])
                assert pseudo_number == int(pseudo_number)
                pseudo_number = int(pseudo_number)
                break

        # Search for energy
        for line in f:
            if line.startswith(
                    ' Energy components [Hartree]           Total Energy ::'):
                energy = float(line[60:])
                break

        # Read orbital energies and occupations
        for line in f:
            if line.startswith(' Orbital energies'):
                break
        f.next()

        oe_alpha = []
        oe_beta = []
        empty = 0
        while empty < 2:
            line = f.next()
            words = line.split()
            if len(words) == 0:
                empty += 1
                continue
            empty = 0
            s = int(words[0])
            l = int(words[2 - restricted])
            occ = float(words[3 - restricted])
            ener = float(words[4 - restricted])
            if restricted or words[1] == 'alpha':
                oe_alpha.append((l, s, occ, ener))
            else:
                oe_beta.append((l, s, occ, ener))

        # Read orbital expansion coefficients
        line = f.next()
        assert (line == " Atomic orbital expansion coefficients [Alpha]\n") or \
               (line == " Atomic orbital expansion coefficients []\n")

        coeffs_alpha = _read_coeffs_helper(f, oe_alpha)

        if not restricted:
            line = f.next()
            assert (line == " Atomic orbital expansion coefficients [Beta]\n")

            coeffs_beta = _read_coeffs_helper(f, oe_beta)

        # Turn orbital data into a Horton wfn expansion
        if restricted:
            norb, nel = _helper_norb(oe_alpha)
            assert nel % 2 == 0
            wfn = RestrictedWFN(lf, obasis.nbasis, norb=norb)
            exp_alpha = wfn.init_exp('alpha')
            _helper_exp(exp_alpha, oe_alpha, coeffs_alpha, shell_types,
                        restricted)
        else:
            norb_alpha, nalpha = _helper_norb(oe_alpha)
            norb_beta, nbeta = _helper_norb(oe_beta)
            assert norb_alpha == norb_beta
            wfn = UnrestrictedWFN(lf, obasis.nbasis, norb=norb_alpha)
            exp_alpha = wfn.init_exp('alpha')
            exp_beta = wfn.init_exp('beta')
            _helper_exp(exp_alpha, oe_alpha, coeffs_alpha, shell_types,
                        restricted)
            _helper_exp(exp_beta, oe_beta, coeffs_beta, shell_types,
                        restricted)

    return {
        'obasis': obasis,
        'wfn': wfn,
        'coordinates': coordinates,
        'numbers': np.array([number]),
        'extra': {
            'energy': energy
        },
        'pseudo_numbers': np.array([pseudo_number]),
    }
Beispiel #10
0
    def apply_to(self, coordinates, numbers):
        """Construct a GOBasis object for the given molecular geometry

           **Arguments:**

           coordinates
                A (N, 3) float numpy array with Cartesian coordinates of the
                atoms.

           numbers
                A (N,) numpy vector with the atomic numbers.

           Note that the geometry specified by the arguments may also contain
           ghost atoms.
        """
        natom, coordinates, numbers = typecheck_geo(coordinates, numbers, need_pseudo_numbers=False)

        shell_map = []
        nprims = []
        shell_types = []
        alphas = []
        con_coeffs = []

        def get_basis(i, n):
            """Look up the basis for a given atom"""
            basis = self.index_map.get(i)
            if basis is not None:
                return basis
            basis = self.element_map.get(n)
            if basis is not None:
                return basis
            if self.default is None:
                raise KeyError('Could not find basis for atom %i.' % i)
            else:
                return self.default

        def translate_basis(basis_x, n):
            """Translate the first argument into a GOBasisAtom instance"""
            if isinstance(basis_x, basestring):
                basis_fam = go_basis_families.get(basis_x.lower())
                if basis_fam is None:
                    raise ValueError('Unknown basis family: %s' % basis_x)
                basis_atom = basis_fam.get(n)
                if basis_atom is None:
                    raise ValueError('The basis family %s does not contain element %i.' % (basis_x, n))
                return basis_atom
            elif isinstance(basis_x, GOBasisFamily):
                basis_atom = basis_x.get(n)
                if basis_atom is None:
                    raise ValueError('The basis family %s does not contain element %i.' % (basis_x.name, n))
                return basis_atom
            elif isinstance(basis_x, GOBasisAtom):
                return basis_x
            else:
                raise ValueError('Can not interpret %s as an atomic basis function.' % basis_x)

        # Loop over the atoms and fill in all the lists
        for i in xrange(natom):
            n = numbers[i]
            basis_x = get_basis(i, n)
            basis_atom = translate_basis(basis_x, n)
            basis_atom.extend(i, shell_map, nprims, shell_types, alphas, con_coeffs, self.pure)

        # Return the Gaussian basis object.
        return GOBasis(coordinates, shell_map, nprims, shell_types, alphas, con_coeffs)
Beispiel #11
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 #12
0
def load_atom_cp2k(filename, lf):
    '''Load data from a CP2K ATOM computation

       **Arguments:**

       filename
            The name of the cp2k out file

       **Returns** a dictionary with ``obasis``, ``exp_alpha``, ``coordinates``,
       ``numbers``, ``energy``, ``pseudo_numbers``. The dictionary may also
       contain: ``exp_beta``.
    '''
    with open(filename) as f:
        # Find the element number
        for line in f:
            if line.startswith(' Atomic Energy Calculation'):
                number = int(line[-5:-1])
                break

        # Go to the pseudo basis set
        for line in f:
            if line.startswith(' Pseudopotential Basis'):
                break

        f.next() # empty line
        line = f.next() # Check for GTO
        assert line == ' ********************** Contracted Gaussian Type Orbitals **********************\n'

        # Load the basis used for the PP wavefn
        basis_desc = []
        for line in f:
            if line.startswith(' *******************'):
                break
            elif line[3:12] == 'Functions':
                shell_type = str_to_shell_types(line[1:2], pure=True)[0]
                a = []
                c = []
                basis_desc.append((shell_type, a, c))
            else:
                values = [float(w) for w in line.split()]
                a.append(values[0])
                c.append(values[1:])

        # Convert the basis into HORTON format
        shell_map = []
        shell_types = []
        nprims = []
        alphas = []
        con_coeffs = []

        for shell_type, a, c in basis_desc:
            # get correction to contraction coefficients.
            corrections = _get_cp2k_norm_corrections(abs(shell_type), a)
            c = np.array(c)/corrections.reshape(-1,1)
            # fill in arrays
            for col in c.T:
                shell_map.append(0)
                shell_types.append(shell_type)
                nprims.append(len(col))
                alphas.extend(a)
                con_coeffs.extend(col)

        # Create the basis object
        coordinates = np.zeros((1, 3))
        shell_map = np.array(shell_map)
        nprims = np.array(nprims)
        shell_types = np.array(shell_types)
        alphas = np.array(alphas)
        con_coeffs = np.array(con_coeffs)
        obasis = GOBasis(coordinates, shell_map, nprims, shell_types, alphas, con_coeffs)
        if lf.default_nbasis is not None and lf.default_nbasis != obasis.nbasis:
            raise TypeError('The value of lf.default_nbasis does not match nbasis reported in the cp2k.out file.')
        lf.default_nbasis = obasis.nbasis

        # Search for (un)restricted
        restricted = None
        for line in f:
            if line.startswith(' METHOD    |'):
                if 'U' in line:
                    restricted = False
                    break
                elif 'R' in line:
                    restricted = True
                    break

        # Search for the core charge (pseudo number)
        for line in f:
            if line.startswith('          Core Charge'):
                pseudo_number = float(line[70:])
                assert pseudo_number == int(pseudo_number)
                pseudo_number = int(pseudo_number)
                break

        # Search for energy
        for line in f:
            if line.startswith(' Energy components [Hartree]           Total Energy ::'):
                energy = float(line[60:])
                break

        # Read orbital energies and occupations
        for line in f:
            if line.startswith(' Orbital energies'):
                break
        f.next()

        oe_alpha = []
        oe_beta = []
        empty = 0
        while empty < 2:
            line = f.next()
            words = line.split()
            if len(words) == 0:
                empty += 1
                continue
            empty = 0
            s = int(words[0])
            l = int(words[2-restricted])
            occ = float(words[3-restricted])
            ener = float(words[4-restricted])
            if restricted or words[1] == 'alpha':
                oe_alpha.append((l, s, occ, ener))
            else:
                oe_beta.append((l, s, occ, ener))

        # Read orbital expansion coefficients
        line = f.next()
        assert (line == " Atomic orbital expansion coefficients [Alpha]\n") or \
               (line == " Atomic orbital expansion coefficients []\n")

        coeffs_alpha = _read_coeffs_helper(f, oe_alpha)

        if not restricted:
            line = f.next()
            assert (line == " Atomic orbital expansion coefficients [Beta]\n")

            coeffs_beta = _read_coeffs_helper(f, oe_beta)


        # Turn orbital data into a HORTON orbital expansions
        if restricted:
            norb, nel = _helper_norb(oe_alpha)
            assert nel%2 == 0
            exp_alpha = lf.create_expansion(obasis.nbasis, norb)
            exp_beta = None
            _helper_exp(exp_alpha, oe_alpha, coeffs_alpha, shell_types, restricted)
        else:
            norb_alpha, nalpha = _helper_norb(oe_alpha)
            norb_beta, nbeta = _helper_norb(oe_beta)
            assert norb_alpha == norb_beta
            exp_alpha = lf.create_expansion(obasis.nbasis, norb_alpha)
            exp_beta = lf.create_expansion(obasis.nbasis, norb_beta)
            _helper_exp(exp_alpha, oe_alpha, coeffs_alpha, shell_types, restricted)
            _helper_exp(exp_beta, oe_beta, coeffs_beta, shell_types, restricted)

    result = {
        'obasis': obasis,
        'lf': lf,
        'exp_alpha': exp_alpha,
        'coordinates': coordinates,
        'numbers': np.array([number]),
        'energy': energy,
        'pseudo_numbers': np.array([pseudo_number]),
    }
    if exp_beta is not None:
        result['exp_beta'] = exp_beta
    return result
Beispiel #13
0
def _fix_molden_from_buggy_codes(result, filename):
    """Detect errors in the data loaded from a molden/mkl/... file and correct.

    Parameters
    ----------

    result: dict
        A dictionary with the data loaded in the ``load_molden`` function.

   This function can recognize erroneous files created by PSI4, ORCA and Turbomole. The
   values in `results` for the `obasis` and `signs` keys will be updated accordingly.
   """
    obasis = result['obasis']
    permutation = result.get('permutation', None)
    if _is_normalized_properly(obasis, permutation, result['orb_alpha'],
                               result.get('orb_beta')):
        # The file is good. No need to change data.
        return
    if log.do_medium:
        log('Detected incorrect normalization of orbitals loaded from a file.')

    # --- ORCA
    if log.do_medium:
        log('Trying to fix it as if it was a file generated by ORCA.')
    orca_signs = _get_orca_signs(obasis)
    orca_con_coeffs = _get_fixed_con_coeffs(obasis, 'orca')
    if orca_con_coeffs is not None:
        # Only try if some changes were made to the contraction coefficients.
        orca_obasis = GOBasis(obasis.centers, obasis.shell_map, obasis.nprims,
                              obasis.shell_types, obasis.alphas,
                              orca_con_coeffs)
        if _is_normalized_properly(orca_obasis,
                                   permutation, result['orb_alpha'],
                                   result.get('orb_beta'), orca_signs):
            if log.do_medium:
                log('Detected typical ORCA errors in file. Fixing them...')
            result['obasis'] = orca_obasis
            result['signs'] = orca_signs
            return

    # --- PSI4
    if log.do_medium:
        log('Trying to fix it as if it was a file generated by PSI4 (pre 1.0).'
            )
    psi4_con_coeffs = _get_fixed_con_coeffs(obasis, 'psi4')
    if psi4_con_coeffs is not None:
        # Only try if some changes were made to the contraction coefficients.
        psi4_obasis = GOBasis(obasis.centers, obasis.shell_map, obasis.nprims,
                              obasis.shell_types, obasis.alphas,
                              psi4_con_coeffs)
        if _is_normalized_properly(psi4_obasis,
                                   permutation, result['orb_alpha'],
                                   result.get('orb_beta')):
            if log.do_medium:
                log('Detected typical PSI4 errors in file. Fixing them...')
            result['obasis'] = psi4_obasis
            return

    # -- Turbomole
    if log.do_medium:
        log('Trying to fix it as if it was a file generated by Turbomole.')
    tb_con_coeffs = _get_fixed_con_coeffs(obasis, 'turbomole')
    if tb_con_coeffs is not None:
        # Only try if some changes were made to the contraction coefficients.
        tb_obasis = GOBasis(obasis.centers, obasis.shell_map, obasis.nprims,
                            obasis.shell_types, obasis.alphas, tb_con_coeffs)
        if _is_normalized_properly(tb_obasis, permutation, result['orb_alpha'],
                                   result.get('orb_beta')):
            if log.do_medium:
                log('Detected typical Turbomole errors in file. Fixing them...'
                    )
            result['obasis'] = tb_obasis
            return

    # --- Renormalized contractions
    if log.do_medium:
        log('Last resort: trying by renormalizing all contractions')
    normed_con_coeffs = _normalized_contractions(obasis)
    normed_obasis = GOBasis(obasis.centers, obasis.shell_map, obasis.nprims,
                            obasis.shell_types, obasis.alphas,
                            normed_con_coeffs)
    if _is_normalized_properly(normed_obasis, permutation, result['orb_alpha'],
                               result.get('orb_beta')):
        if log.do_medium:
            log('Detected unnormalized contractions in file. Fixing them...')
        result['obasis'] = normed_obasis
        return

    raise IOError(('Could not correct the data read from %s. The molden or '
                   'mkl file you are trying to load contains errors. Please '
                   'report this problem to [email protected], so he '
                   'can fix it.') % filename)
Beispiel #14
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 #15
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