示例#1
0
 def process(self, line):
     """an element name in the first column indicates the start of a basis set"""
     if (line[0].isalpha()):
         self.found_basis = True
         self.ncgbf = 0
         (atom, self.basis_set) = line.strip().split(' ', 1)
         self.atno = atomic_number(atom)
         self.basis_data[self.atno] = []
     elif (line[0] == ' '):
         if (self.found_basis):
             (a, b) = line.strip().split()
             if (self.ncgbf == 0):
                 """read number of contractions and angular momentum, e.g.  5 s"""
                 self.ncgbf = int(a)
                 self.sym = b.strip().upper()
                 self.prims = []
             else:
                 """read self.ncgbf exponent and coefficient pairs"""
                 exp, coef = float(a), float(b)
                 self.prims.append((exp, coef))
                 self.ncgbf -= 1
                 if (self.ncgbf == 0):
                     """no more coefficients to read, save contraction"""
                     self.basis_data[self.atno].append(
                         (self.sym, self.prims))
                 """decrease the number of coefficients which are still to be read"""
示例#2
0
 def process(self, line):
     if "cycle" in line:
         """rest, we only want the converged gradient"""
         self.atomlist = []
         self.coordvector = []
         self.gradient = []
         return
     parts = line.strip().split()
     if len(parts) == 4:
         x, y, z = float(parts[0].replace("D", "E")), float(
             parts[1].replace("D", "E")), float(parts[2].replace("D", "E"))
         atno = atomic_number(parts[3])
         self.atomlist.append((atno, (x, y, z)))
         self.coordvector += [x, y, z]
     elif len(parts) == 3:
         gradx, grady, gradz = float(parts[0].replace("D", "E")), float(
             parts[1].replace("D", "E")), float(parts[2].replace("D", "E"))
         self.gradient += [gradx, grady, gradz]
def charge_fluctuation_functions(atom_name='h', confined=True):
    """
    create charge fluctuation functions for valence shells

    Parameters
    ----------
    atom_name     :   string with atom name

    Optional
    --------
    confined      :   controls where confined atoms (True) or free atoms (False)
                      are used

    Returns
    -------
    ls            :   list of angular momenta of the valence shells
    Fs            :   list of charge fluctuation functions for each shell
                      callable, Fs[i](x,y,z) evaluates the spherically averaged
                      charged fluctuation function for the shell with angular
                      momentum ls[i]
    """
    Zat = atomic_number(atom_name)
    atomlist = [(Zat, (0, 0, 0))]
    # load atomic valence orbitals
    basis = AtomicBasisSet(atomlist, confined=confined)
    # group basis functions by angular momentum
    ls = []
    shells = []  # contains list of basis functions for each shell
    for bf in basis.bfs:
        if len(ls) == 0 or bf.l > ls[-1]:
            # new shell begins
            ls.append(bf.l)
            # create new shell with current basis function as first element
            shells.append([bf])
        else:
            # append basis function to current shell
            shells[-1].append(bf)
    # define charge fluctuation function for each shell
    Fs = []  # list of charge fluctuation functions
    for l, shell in zip(ls, shells):
        assert len(shell) == 2 * l + 1
        Fs.append(spherically_averaged_density(shell, l))

    return ls, Fs
def plot_charge_fluctuation_functions(atom_names, confined=True):
    """
    plot numerical charge fluctuation functions computed from valence orbital density
    """
    import matplotlib.pyplot as plt
    from DFTB.Parameters import get_hubbard_parameters

    plt.title("charge fluctuation functions")
    plt.xlabel("r / bohr", fontsize=17)
    plt.ylabel("numerical F(r)")

    r = np.linspace(0.01, 4.0, 200)
    x = r
    y = 0 * r
    z = 0 * r

    for atom_name in atom_names:
        lsA, FsA_numerical = charge_fluctuation_functions(atom_name,
                                                          confined=confined)
        for la, Fa_numerical in zip(lsA, FsA_numerical):
            line, = plt.plot(r,
                             Fa_numerical(x, y, z),
                             lw=2,
                             label=r"$F_{%s,%s}(r)$ (numerical)" %
                             (atom_name.upper(), l2spec[la]))

    # compare with Gaussian fluctuation function
    for atom_name in atom_names:
        Zat = atomic_number(atom_name)
        hubbard_U = get_hubbard_parameters(None)
        # load Gaussian fluctuation functions, width is defined by the Hubbard parameter
        aux_basis = AuxiliaryBasisSet([(Zat, (0, 0, 0))], hubbard_U)
        # only the s-function is used
        Fa_gaussian = aux_basis.bfs[0]
        plt.plot(r,
                 Fa_gaussian.amp(x, y, z),
                 lw=2,
                 label=r"$F_{%s}(r)$ (Gaussian)" % atom_name.upper(),
                 ls="-.")

    plt.legend(ncol=2)
    plt.show()
示例#5
0
def onsite_integrals(atom_name='h', confined=True):
    """
    compute on-site Coulomb and exchange integrals for an atom

    Parameters
    ----------
    atom_name      :  name of atom, e.g. 'h', 'c', etc.

    Optional
    --------
    confined      :   controls where confined atoms (True) or free atoms (False)
                      are used
    """
    print(
        "computing on-site Coulomb and exchange integrals between valence orbitals of '%s'"
        % atom_name)
    Zat = atomic_number(atom_name)
    atomlist = [(Zat, (0, 0, 0))]
    basis = AtomicBasisSet(atomlist, confined=confined)
    density = AtomicDensitySuperposition(atomlist, confined=confined)
    #xc_functional = XCFunctionals.libXCFunctional("lda_x", "lda_c_pw")
    xc_functional = XCFunctionals.libXCFunctional("gga_x_pbe", "gga_c_pbe")

    for a, bfA in enumerate(basis.bfs):
        stra = "%d%s" % (bfA.n, angmom_to_xyz[(bfA.l, bfA.m)]
                         )  # name of valence orbital, e.g. 1s, 2px, etc.
        for b, bfB in enumerate(basis.bfs):
            strb = "%d%s" % (bfB.n, angmom_to_xyz[(bfB.l, bfB.m)])
            # Coulomb integral    (aa|(1/r12 + fxc[rho0])|bb)
            eri_aabb = electron_repulsion_integral(atomlist, bfA, bfA, bfB,
                                                   bfB, density, xc_functional)
            print("Coulomb  (%s,%s|{1/r12+f_xc[rho0]}|%s,%s)= %e" %
                  (stra, stra, strb, strb, eri_aabb))
            if a != b:
                # exchange integral    (ab|(1/r12 + fxc[rho0])|ab)
                eri_abab = electron_repulsion_integral(atomlist, bfA, bfB, bfA,
                                                       bfB, density,
                                                       xc_functional)
                print("exchange (%s,%s|{1/r12+f_xc[rho0]}|%s,%s)= %e" %
                      (stra, strb, stra, strb, eri_abab))
示例#6
0
def onsite_integrals_unique(atom_name='h', confined=True):
    """
    compute the 5 unique on-site electron integrals for an atom.
    Only s- and p-valence orbitals are considered. The 5 integrals
    are

      (ss|ss)
      (sp|sp)   = (s px|s px) = (s py|s py) = (s pz|s pz)
      (ss|pp)   = (s s |pxpx) = (s s |pypy) = (s s |pzpz)
      (pp|pp)   = (pxpx|pxpx) = (pypy|pypy) = (pzpz|pzpz)
      (pp'|pp') = (pxpy|pxpy) = (pxpz|pxpz) = (pypz|pypz)

    Optional
    --------
    confined      :   controls where confined atoms (True) or free atoms (False)
                      are used

    Returns
    -------
    unique_integrals  :  numpy array with unique on-site integrals
                         [(ss|ss), (sp|sp), (ss|pp), (pp|pp), (pp'|pp')]

    References
    ----------
    [1] http://openmopac.net/manual/1c2e.html
    """
    print(
        "computing unique on-site electron integrals between valence orbitals of '%s'"
        % atom_name)
    print("only s- and p-functions are considered")
    Zat = atomic_number(atom_name)
    atomlist = [(Zat, (0, 0, 0))]
    basis = AtomicBasisSet(atomlist, confined=confined)
    density = AtomicDensitySuperposition(atomlist, confined=confined)
    #xc_functional = XCFunctionals.libXCFunctional("lda_x", "lda_c_pw")
    xc_functional = XCFunctionals.libXCFunctional("gga_x_pbe", "gga_c_pbe")

    unique_integrals = np.zeros(5)
    for a, bfA in enumerate(basis.bfs):
        for b, bfB in enumerate(basis.bfs):
            # choose index into unique_integrals to which the integrals is written
            if (bfA.l == 0 and bfB.l == 0):
                # (ss|ss)
                i = 0
            elif (bfA.l == 0 and bfB.l == 1 and bfB.m == 0):
                # (sp|sp) and (ss|pp)
                i = 1
            elif (bfA.l == 1 and bfA.m == 0 and bfB.l == 1 and bfB.m == 0):
                # (pp|pp)
                i = 3
            elif (bfA.l == 1 and bfA.m == 0 and bfB.l == 1 and bfB.m == 1):
                # (pp'|pp')
                i = 4
            else:
                continue

            # compute Coulomb integral    (ab|(1/r12 + fxc[rho0])|ab)
            eri_abab = electron_repulsion_integral(atomlist, bfA, bfB, bfA,
                                                   bfB, density, xc_functional)
            unique_integrals[i] = eri_abab

            if (i == 1):
                # in addition to (sp|sp) we also need to calculated (ss|pp)
                eri_aabb = electron_repulsion_integral(atomlist, bfA, bfA, bfB,
                                                       bfB, density,
                                                       xc_functional)
                unique_integrals[2] = eri_aabb
            elif (i == 4):
                # in addition to (pp'|pp') we also compute (pp|p'p') and verify the identity
                #  (pp|p'p') = (pp|pp) - 2 (pp'|pp')
                eri_aabb = electron_repulsion_integral(atomlist, bfA, bfA, bfB,
                                                       bfB, density,
                                                       xc_functional)
                assert (
                    eri_aabb -
                    (unique_integrals[3] - 2 * unique_integrals[4])) < 1.0e-5

    print("unique 1-center integrals (in eV) for atom '%s'" % atom_name)
    print("       (ss|ss)     (sp|sp)     (ss|pp)      (pp|pp)     (pp'|pp')")
    print("    %+.7f  %+.7f  %+.7f  %+.7f  %+.7f" %
          tuple(unique_integrals * hartree_to_eV))

    return unique_integrals
示例#7
0
#!/usr/bin/env python
"""
create a sequence of structures with different bond lengths between the two dimer atoms.
"""
from DFTB import XYZ
from DFTB.AtomicData import bohr_to_angs, atomic_number
from numpy import linspace

if __name__ == "__main__":
    import sys
    if len(sys.argv) < 7:
        print("\nUsage: %s <atom 1> <atom 2> Rmin Rmax NR <dimer geometries>\n" % sys.argv[0])
        print("create dimer geometries with NR different bond lengths in the interval [Rmin,Rmax].")
        print("Rmin and Rmax are in Angstrom.")
        exit(-1)
    ZA = int(atomic_number(sys.argv[1]))
    ZB = int(atomic_number(sys.argv[2]))
    Rmin, Rmax, NR = float(sys.argv[3]), float(sys.argv[4]), int(sys.argv[5])
    dimer_file = sys.argv[6]
    def dimer(ZA, ZB, bond_length):
        atomA = (ZA, [0.0, 0.0, 0.0])
        atomB = (ZB, [0.0, 0.0, bond_length])
        return [atomA, atomB]
    bond_lengths = linspace(Rmin,Rmax,NR)
    XYZ.write_xyz(dimer_file, [dimer(ZA,ZB,bl/bohr_to_angs) for bl in bond_lengths], title="dimer trajectory")
示例#8
0
        print >> fh, "# repulsive potential in hartree/bohr"
        print >> fh, "Vrep = \\\n%s" % pp.pformat(self.Vrep)

        fh.close()


if __name__ == "__main__":
    import sys
    usage = "Usage: %s <element1> <element2>\n" % sys.argv[0]
    usage += "element1 and element2 are the elements in the atom pair for which the repulsive potential should be fitted (e.g. h and c)."
    if len(sys.argv) < 3:
        print usage
        exit(-1)
    parser = utils.OptionParserFuncWrapper(ReppotFitter.fit, usage)
    (options, args) = parser.parse_args()
    Z1, Z2 = atomic_number(args[0]), atomic_number(args[1])
    Fitter = ReppotFitter(Z1, Z2)

    print "Files with geometries and forces are read from stdin."
    print "Each line should be of the form:"
    print "<identifier>  <xyz file with geometry> <xyz file with electronic dftb forces> <xyz file with forces from different method> \\"
    print "                                    weight=<weight, positive float> max_error=<max. error per atom> \\"
    print "                                            (active_atoms=<list of atoms IDs, e.g. 0,1,2>)"
    for line in sys.stdin.readlines():
        if line.strip()[0] == "#":
            # ignore comments
            continue
        molname, geom_file, dftb_force_file, force_file, keywords_str = line.strip(
        ).split(None, 4)
        molname = molname.replace("__", " ")
        keywords = dict(
示例#9
0
 def process(self, line):
     parts = line.strip().split()
     x, y, z = float(parts[0]), float(parts[1]), float(parts[2])
     atno = atomic_number(parts[3])
     self.atomlist.append((atno, (x, y, z)))
if __name__ == "__main__":
    import sys
    import os.path

    if len(sys.argv) < 3:
        print("Usage: %s  <atom A> <atom B>" % os.path.basename(sys.argv[0]))
        print("  plot gamma-integrals for atom combination A-B.")
        print(
            "  <atom A> and <atom B> should be the names of the atoms, i.e. 'h' or 'c' etc."
        )
        exit(-1)

    atom_nameA = sys.argv[1].upper()
    atom_nameB = sys.argv[2].upper()
    Za = atomic_number(atom_nameA)
    Zb = atomic_number(atom_nameB)

    # plot gamma functions for
    # ... confined pseudo atoms
    #from DFTB.SlaterKoster.confined_pseudo_atoms import gamma_integrals
    # ... free pseudo atoms
    from DFTB.SlaterKoster.free_pseudo_atoms import gamma_integrals

    try:
        gamma_dic = gamma_integrals.gamma_integrals[(Za, Zb)]
    except KeyError as e:
        print(
            "ERROR: No numerical gamma-functions found for atom pair %s-%s." %
            (atom_nameA, atom_nameB))
        print(
def tabulate_gamma_integrals(atom_names, filename, confined=True):
    """
    Compute the gamma integrals

      gamma_{A,lA,B,lB} = (F_{A,lA}|1/r12 + f_xc[rho0A+rho0B]|F_{B,lB})

    for a range of distances for each atom combination and save them to a python file
    that can be imported

    Parameters
    ----------
    atom_names  :   list of atom names, e.g. ['h','c',...]
    filename    :   path to a python file, where the integrals will be stored in a
                    human-readable form

    Optional
    --------
    confined      :   controls where confined atoms (True) or free atoms (False)
                      are used

    Returns
    -------
    nothing, data is written to a file
    """
    import pprint
    import sys

    # interatomic distances for which gamma-function is computed numerically,
    # values in between need to be interpolated
    distances = np.linspace(0.001, 6.0, 60)

    gamma_integrals_dic = {}
    # enumerate all unique atom combinations
    n = len(atom_names)
    for a in range(0, n):
        for b in range(a, n):
            print("computing gamma integrals for atom combination %s-%s" %
                  (atom_names[a].upper(), atom_names[b].upper()))
            gamma_dic = numerical_gamma_integrals(atom_names[a],
                                                  atom_names[b],
                                                  distances,
                                                  confined=confined)

            Za = atomic_number(atom_names[a])
            Zb = atomic_number(atom_names[b])

            if Za > Zb:
                # swap atom, so that Za <= Zb
                tmp = Zb
                Zb = Za
                Za = tmp
            gamma_integrals_dic[(Za, Zb)] = gamma_dic

    fh = open(filename, "w")
    np.set_printoptions(threshold=sys.maxsize)
    pp = pprint.PrettyPrinter(depth=10)
    print("# This file has been generated automatically by %s." % sys.argv[0],
          file=fh)
    print("from numpy import array", file=fh)
    print("", file=fh)
    print("# atoms for which gamma-integrals are available", file=fh)
    print("atom_names = %s" % atom_names, file=fh)
    print("# distances in bohr for which gamma-integrals are tabulated",
          file=fh)
    print("r = %s" % pp.pformat(distances), file=fh)
    print(
        "# gamma-integrals gamma_{A,lA,B,lB} = (F_{A,lA}|1/r12 + f_xc[rho0A+rho0B]|F_{B,lB}) for each",
        file=fh)
    print(
        "# atom combination A-B. The integrals are stored in a nested dictionary, the keys",
        file=fh)
    print(
        "# on the first level are the atomic numbers (Za,Zb) with Za <= Zb, the keys on the",
        file=fh)
    print(
        "# second level are the angular momenta of the valence shell on atom A and B, i.e. (la,lb)",
        file=fh)
    print(
        "# For example the integral between the s-shell on carbon and the p-shell on nitrogen",
        file=fh)
    print("# would be stored in gamma_integrals[(6,7)][(0,1)]", file=fh)
    print("#                                      |      |   ", file=fh)
    print("#                                   (Za,Zb) (lA,lB)", file=fh)
    print("gamma_integrals = \\\n%s" % pp.pformat(gamma_integrals_dic),
          file=fh)

    print("gamma integrals for atoms %s written to '%s'" %
          (" ".join(atom_names), filename))
    fh.close()
def numerical_gamma_integrals(atom_nameA,
                              atom_nameB,
                              distances,
                              confined=True):
    """
    compute the integrals

      gamma_{A,lA,B,lB} = (F_{A,lA}|1/r12 + f_xc[rho0A+rho0B]|F_{B,lB})

    numerically on a multicenter grid

    Parameters
    ----------
    atom_nameA, atom_nameB  :  names of interacting atoms, e.g. 'h' or 'c'
    distances               :  numpy array with interatomic separations (in bohr) for which
                               the gamma integrals should be calculated

    Optional
    --------
    confined      :   controls where confined atoms (True) or free atoms (False)
                      are used

    Returns
    -------
    gamma_dic               :  dictionary with values of gamma integrals on the distance grid,
                               gamma_dic[(lA,lB)] is a numpy array holding the integrals between
                               shell lA on atom A and shell lB on atom B
    """
    # atomic numbers
    Za = atomic_number(atom_nameA)
    Zb = atomic_number(atom_nameB)
    # charge fluctuation functions for each shell
    lsA, FsA = charge_fluctuation_functions(atom_nameA, confined=confined)
    lsB, FsB = charge_fluctuation_functions(atom_nameB, confined=confined)

    xc_functional = XCFunctionals.libXCFunctional("lda_x", "lda_c_pw")

    gamma_dic = {}
    for la, Fa in zip(lsA, FsA):
        for lb, Fb in zip(lsB, FsB):
            print("  integral between %s-shell and %s-shell" %
                  (l2spec[la], l2spec[lb]))
            gamma_ab = np.zeros(len(distances))
            for i, r_ab in enumerate(distances):

                print("   %3.d of %d   interatomic distance : %4.7f bohr" %
                      (i + 1, len(distances), r_ab))
                # atoms A and B are placed symmetrically on the z-axis,
                # separated by a distance of r_ab
                atomlist = [(Za, (0, 0, -0.5 * r_ab)),
                            (Zb, (0, 0, +0.5 * r_ab))]

                # define displaced charge fluctuation functions
                def rhoAB(x, y, z):
                    return Fa(x, y, z - 0.5 * r_ab)

                def rhoCD(x, y, z):
                    return Fb(x, y, z + 0.5 * r_ab)

                #
                rho0 = AtomicDensitySuperposition(atomlist, confined=confined)

                # evaluate integral
                gamma_ab[i] = electron_repulsion_integral_rho(
                    atomlist, rhoAB, rhoCD, rho0, xc_functional)

            # save gamma integral for the interaction of a shell with angular momentum la on atom A
            # and a shell with angular momentum lb on atom B
            gamma_dic[(la, lb)] = gamma_ab

    return gamma_dic