コード例 #1
0
ファイル: ScalarCoupling.py プロジェクト: humeniuka/DFTBaby
def _overlap_AB_f90(atomlist1, atomlist2, valorbs1, valorbs2, SKT):
    """
    This function calls an external Fortran function that computes the matrix elements.
    Since hashes and tuples cannot be used easily in Fortran, the arguments are brought
    into a form that can be fed into the Fortran function.
    """
    atom_type_dic, spline_deg, tab_filled_SH0, tab_filled_D, \
        (S_knots, S_coefs, H_knots, H_coefs, D_knots, D_coefs) = \
                            combine_slako_tables_f90(SKT)

    # number of atoms
    Nat1 = len(atomlist1)
    Nat2 = len(atomlist2)
    # orbitals
    atom_indeces1, atom_types1, ls1, ms1 = atomlist2orbitals(
        atomlist1, valorbs1, atom_type_dic)
    atom_indeces2, atom_types2, ls2, ms2 = atomlist2orbitals(
        atomlist2, valorbs2, atom_type_dic)
    assert atom_indeces1 == atom_indeces2, "atomlist1 and atomlist2 should contain the same atoms in the same order!"
    # count valence orbitals
    Norb1 = len(ls1)
    Norb2 = len(ls2)
    # distances and direction
    pos1 = XYZ.atomlist2vector(atomlist1)
    pos1 = np.reshape(
        pos1, (Nat1, 3)).transpose()  # pos(:,i) is the 3d position of atom i
    pos2 = XYZ.atomlist2vector(atomlist2)
    pos2 = np.reshape(pos2, (Nat2, 3)).transpose()
    r, x, y, z = slako.slako.directional_cosines(pos1, pos2)
    # call Fortran function
    S = slako.slako.overlap12(atom_indeces1, atom_types1, ls1, ms1,
                              atom_indeces2, atom_types2, ls2, ms2, r, x, y, z,
                              spline_deg, tab_filled_SH0, S_knots, S_coefs)
    return S
コード例 #2
0
def velocities_finite_diff(atomlists, dt):
    """
    compute the velocities from finite differences between two time-steps

    Parameters:
    ===========
    atomlists: list of geometries along trajectories for each time step
    dt: nuclear time step in a.u.

    Returns:
    ========
    positions: list of vectors with positions for each time step
    velocities: list of vectors with velocities for each time step
    """
    Nt = len(atomlists)
    positions = []
    velocities = []
    pos0 = XYZ.atomlist2vector(atomlists[0])
    positions.append(pos0)
    for i in range(1, Nt):
        pos1 = XYZ.atomlist2vector(atomlists[i])
        vel = (pos1 - pos0) / dt
        positions.append(pos1)
        velocities.append(vel)
        pos0 = pos1
    velocities.append(vel)

    return positions, velocities
コード例 #3
0
    def add_polyatomic_curve(self, geometries, forces_wo_frep, forces_with_frep, \
                                 curve_name="polyatomic", weight=1.0, max_error=0.01, active_atoms=None):
        """
        compute generalized forces that act along the bond lengths and
        calculate repulsive forces for arbitrary non-linear molecule with more
        than 2 atoms.

        Parameters:
        ===========
        geometries: list of geometries (in atomlist format)
        forces_wo_frep: list of forces (in atomlist format) containing the DFTB forces only
           from the electronic hamiltonian
        forces_with_frep: list of forces (in atomlist format) containing the forces from a 
           higher level method (including nuclear repulsion)
        curve_name: some identifier for plotting
        weight: assign a weight of this data set during fitting
        max_error: for large bond lengths and repulsive potentials that cannot be represented
           as a sum of pairwise potentials, the error incurred from a pairwise decomposition
           can be large. Those geometries where the error per atom exceeds max_error 
           are not included in the fit. 
        active_atoms: list of atomic indeces. Only atoms in this list take part in the fit.
           If set to [], all atoms are included.
        """
        for atomlist, f_wo_rep, f_with_rep in zip(geometries, forces_wo_frep,
                                                  forces_with_frep):
            # repulsive potential is the difference between true forces and electronic DFTB forces
            # in cartesian coordinates
            frep = XYZ.atomlist2vector(f_with_rep) - XYZ.atomlist2vector(
                f_wo_rep)
            forcelist = XYZ.vector2atomlist(frep, atomlist)
            from numpy.linalg.linalg import LinAlgError
            if active_atoms == []:
                # by default all atoms are included into the fit
                active_atoms = [i for i in range(0, len(atomlist))]
            try:
                bond_lengths, pair_forces, error = pairwise_decomposition(
                    atomlist, forcelist)
            except LinAlgError:
                print "LINALG ERROR => do not include this geometry"
                continue
            if error > max_error:
                print "Error (%s) from pairwise decomposition too large (threshold: %s) => do not include this geometry!" % (
                    error, max_error)
                continue

            for (i, j) in bond_lengths.keys():
                if (i not in active_atoms) or (j not in active_atoms):
                    continue
                Zi = atomlist[i][0]
                Zj = atomlist[j][0]
                if (Zi == self.Z1 and Zj == self.Z2) or (Zi == self.Z2
                                                         and Zj == self.Z1):
                    self.nuclear_separation.append(bond_lengths[(i, j)])
                    self.repulsive_gradient.append(-pair_forces[(i, j)])
                    # each point is weighted by 1/sigma
                    self.weights.append(weight / max(error, 1.0e-2))
                    self.curve_ID.append(self.curve_counter)
        self.curve_names.append(curve_name)
        self.curve_counter += 1
コード例 #4
0
ファイル: FitReppots.py プロジェクト: martin-stoehr/DFTBaby
    def load_fitpaths_it(self, fit_dir):
        """
        load geometries of all fit paths from the folder `fit_dir`
        and return an iterator to the fit steps. Each fit step consists of the tuple

          (atomlist, en_rep, force_rep)

        The meaning of the elements of a fit step are as follows:

          atomlist : geometry of of fit step, list of tuples (Zi,[xi,yi,zi])
          en_rep   : energy difference (E_ref - E_elec) in Hartree
          force_rep: vector with force difference (F_ref - F_elec) in Hartree/bohr,
                     force_rep[3*i:3*(i+1)] is the force [Fx(i),Fy(i),Fz(i)] on atom i.

        """
        self.names = [
            os.path.basename(xyz)[:-4]
            for xyz in glob.glob("%s/FIT_PATHS/*.xyz" % fit_dir)
        ]

        for name in self.names:
            print("Loading fit path '%s' " % name)
            geom_xyz = os.path.join(fit_dir, "FIT_PATHS", "%s.xyz" % name)

            en_dftb_dat = os.path.join(fit_dir, "DFTB",
                                       "%s.energies.dat" % name)
            en_ref_dat = os.path.join(fit_dir, "REFERENCE",
                                      "%s.energies.dat" % name)

            forces_dftb_xyz = os.path.join(fit_dir, "DFTB",
                                           "%s.forces.xyz" % name)
            forces_ref_xyz = os.path.join(fit_dir, "REFERENCE",
                                          "%s.forces.xyz" % name)

            try:
                geometries = XYZ.read_xyz(geom_xyz)

                energies_dftb = np.loadtxt(en_dftb_dat)
                energies_ref = np.loadtxt(en_ref_dat)

                forces_dftb = XYZ.read_xyz(forces_dftb_xyz)
                forces_ref = XYZ.read_xyz(forces_ref_xyz)

                for atomlist, en_dftb, en_ref, f_dftb, f_ref in zip(
                        geometries, energies_dftb, energies_ref, forces_dftb,
                        forces_ref):
                    # compute E_rep = E_ref - E_el
                    en_rep = en_ref - en_dftb
                    # compute E_rep = F_ref - F_el
                    force_rep = XYZ.atomlist2vector(
                        f_ref) - XYZ.atomlist2vector(f_dftb)

                    yield atomlist, en_rep, force_rep

            except IOError as e:
                print("Loading of fit path '%s' failed!" % name)
コード例 #5
0
def wigner_from_G09_hessian(g09_file, Nsample=100, zero_threshold=1.0e-9):
    """
    create Wigner ensemble based on hessian matrix from Gaussian 09 calculation
    """
    suffix = g09_file.split(".")[-1]
    if suffix in ["out", "log"]:
        print("Reading Gaussian 09 log file %s" % g09_file)
        atomlist = Gaussian.read_geometry(g09_file)
        forces = Gaussian.read_forces(g09_file)
        hess = Gaussian.read_force_constants(g09_file)
    elif suffix in ["fchk"]:
        print("Reading formatted Gaussian 09 checkpoint file %s" % g09_file)
        Data = Checkpoint.parseCheckpointFile(g09_file)
        # cartesian coordinates
        pos = Data["_Current_cartesian_coordinates"]
        atnos = Data["_Atomic_numbers"]
        # forces
        frc = -Data["_Cartesian_Gradient"]
        atomlist = []
        forces = []
        for i, Zi in enumerate(atnos):
            atomlist.append((Zi, tuple(pos[3 * i:3 * (i + 1)])))
            forces.append((Zi, tuple(frc[3 * i:3 * (i + 1)])))
        # Hessian
        hess = Data["_Cartesian_Force_Constants"]

    masses = np.array(AtomicData.atomlist2masses(atomlist))

    x0 = XYZ.atomlist2vector(atomlist)
    x0 = shift_to_com(x0, masses)

    grad = -XYZ.atomlist2vector(forces)

    grad_nrm = la.norm(grad)
    print("  gradient norm = %s" % grad_nrm)
    #    assert grad_nrm < 1.0e-3, "Gradient norm too large for minimum!"
    vib_freq, vib_modes = vibrational_analysis(hess,
                                               masses,
                                               zero_threshold=zero_threshold)
    Aw, Bw = wigner_distribution(x0,
                                 hess,
                                 masses,
                                 zero_threshold=zero_threshold)
    gw = GaussianWavepacket.Gaussian(Aw, Bw)
    qs, ps = gw.sample(Nsample)
    mx = np.outer(masses, np.ones(Nsample)) * qs
    avg_com = np.mean(np.sum(mx[::3, :], axis=0)), np.mean(
        np.sum(mx[1::3, :], axis=0)), np.mean(np.sum(mx[2::3, :], axis=0))
    print(avg_com)

    geometries = [
        XYZ.vector2atomlist(qs[:, i], atomlist) for i in range(0, Nsample)
    ]

    return geometries
コード例 #6
0
def molecular_frame_transformation(atomlist):
    """
    The molecule is shifted to the center of mass and its principle axes of inertia are aligned
    with the coordinate axes. This standard orientation defines the molecular frame.
    The translation vector and Euler angles needed to transform the geometry from the
    molecular frame to the original frame are also returned.

    Returns:
    ========
    atomlist_std: molecular geometry in standard orientation
    (a,b,g): Euler angles in z-y-z convention
    cm: 3D vector with center of mass
    """
    pos = XYZ.atomlist2vector(atomlist)
    masses = AtomicData.atomlist2masses(atomlist)
    # shift center of mass to origin
    Nat = len(atomlist)
    pos_std = np.zeros(pos.shape)
    cm = center_of_mass(masses, pos)
    for i in range(0, Nat):
        pos_std[3*i:3*i+3] = pos[3*i:3*i+3] - cm
    (a,b,g) = euler_angles_inertia(masses, pos_std)
    R = EulerAngles2Rotation(a,b,g)
    for i in range(0, Nat):
        pos_std[3*i:3*i+3] = np.dot(R, pos_std[3*i:3*i+3])
    atomlist_std = XYZ.vector2atomlist(pos_std, atomlist)
    # The MolecularCoord module uses a strange convention for Euler angles.
    # Therefore we extract the Euler angles in z-y-z convention directly
    # from the rotation matrix, that rotates the molecule from the standard
    # orientation into the original orientation
    Rinv = R.transpose()
    a,b,g = rotation2EulerAngles(Rinv, convention="z-y-z")
    return atomlist_std, (a,b,g), cm
コード例 #7
0
ファイル: thomson2.py プロジェクト: martin-stoehr/DFTBaby
def remove_overlapping_atoms(atomlist, tol=1.0e-4):
    print("remove overlapping atoms")
    nat = len(atomlist)
    # The i-th atom should be removed if duplicate[i] == 1
    # Fortran
    rs = XYZ.atomlist2vector(atomlist)
    rs = np.reshape(rs, (nat, 3))
    duplicate = thomson.thomson.remove_overlapping(rs, tol)
    # python
    """
    duplicate_py = np.zeros(nat, dtype=int)
    for i in range(0, nat):
        for j in range(i+1,nat):
            posi = np.array(atomlist[i][1])
            posj = np.array(atomlist[j][1])
            Rij = la.norm(posi-posj)
            if Rij < tol:
                duplicate_py[j] = 1
    assert np.sum(abs(duplicate - duplicate_py)) < 1.0e-10
    """
    # only copy unique atoms
    atomlist_unique = []
    for i in range(0, nat):
        if duplicate[i] == 0:
            atomlist_unique.append( atomlist[i] )
    return atomlist_unique
コード例 #8
0
    def __init__(self, atomlist):
        # convert the list of atoms into a list of 3d points
        nat = len(atomlist)
        pos = XYZ.atomlist2vector(atomlist)
        points = []
        for i in range(0, nat):
            points.append(pos[3 * i:3 * (i + 1)])
        # QHull needs at least 4 point to construct the initial
        # simplex.
        if nat < 4:
            # If there are less than 4 atoms,
            # we add the center of mass as an additional point
            masses = AtomicData.atomlist2masses(atomlist)
            com = MolCo.center_of_mass(masses, pos)
            points.append(com)
        if nat < 3:
            # If there are less than 3 atoms we add
            # an arbitrary point on the x-axis
            points.append(com + np.array([0.0005, 0.0, 0.0]))
        if nat < 2:
            # If there is only one atom, we add another arbitrary
            # point on the y-axis
            points.append(com + np.array([0.0, 0.0005, 0.0]))
        # We add small random numbers to the input coordinates, so that
        # we get a 3D convex hull even if the molecule is planar
        points = np.array(points) + 0.0001 * np.random.rand(len(points), 3)
        # find the convex hull using the qhull code
        hull = ConvexHull(points, qhull_options="QbB Qt")

        # call the constructor of the parent class (MinimalEnclosingBox)
        super(MoleculeBox, self).__init__(hull)
コード例 #9
0
 def getCenterOfMass(self):
     pos = XYZ.atomlist2vector(self.atomlist)
     com = center_of_mass(self.masses, pos)
     print("Center of Mass")
     print("==============")
     print(com)
     return com
コード例 #10
0
    def _electrostatics(self):
        """
        computes the electrostatic interaction between the MM charges,
         enCoul =  - sum_i<j qi*qj/|Ri-Rj|
        and the gradient w/r/t to the positions of the individual atoms
        """
        Nat = len(self.atomlist)
        x = XYZ.atomlist2vector(self.atomlist)
        #
        enCoul = 0.0
        gradCoul = np.zeros(3 * Nat)  # gradient
        for i in range(0, Nat):
            for j in range(i + 1, Nat):
                Rij_vec = x[3 * i:3 * (i + 1)] - x[3 * j:3 * (j + 1)]
                Rij = la.norm(Rij_vec)
                # contribution to energy
                Vij = self.mm_charges[i] * self.mm_charges[j] / Rij
                enCoul += Vij
                # contribution to the gradient
                eij = Rij_vec / Rij  # unit vector
                gij = Vij / Rij * eij
                gradCoul[3 * i:3 * (i + 1)] -= gij
                gradCoul[3 * j:3 * (j + 1)] += gij

        if self.verbose > 0:
            print "MM electrostatic energy: %e" % enCoul

        return enCoul, gradCoul
コード例 #11
0
ファイル: Symmetry.py プロジェクト: martin-stoehr/DFTBaby
def write_atomlist(atomlist):
    Nat = len(atomlist)
    pos = XYZ.atomlist2vector(atomlist)
    txt  = "                in Angstrom:\n"
    txt +=     "Atom          X           Y           Z\n"
    for i in range(0, Nat):
        txt += ("  %s  " % i).rjust(3)
        txt += "%+4.7f  %+4.7f  %+4.7f\n" % tuple(pos[3*i:3*(i+1)]*AtomicData.bohr_to_angs)
    txt += "\n"
    return txt
コード例 #12
0
def grad_cartesian2internal(atomlist, gradients):
    mol = MolecularCoords(atomlist)
    jac, jac_inv = mol.getJacobian()
    for I,gradI in enumerate(gradients):
        gradIvec = XYZ.atomlist2vector(gradI)
        gradIinternal = dot(jac_inv, gradIvec)
        print("Gradient on state %s" % I)
        print("in cartesian coordinates")
        print(gradIvec)
        print("in internal coordinates")
        print(gradIinternal)
コード例 #13
0
 def f(x):
     thomson_cap = XYZ.vector2atomlist(x, thomson_cap_ref)
     #        thomson_cap = enforce_constaints(thomson_cap)
     print "thomson_cap"
     print thomson_cap
     thomson_pts = thomson_tube + thomson_cap
     XYZ.write_xyz("/tmp/thomson_minimization.xyz", [thomson_cap], mode="a")
     en = potential_energy(thomson_pts)
     # gradient of potential energy
     grad = XYZ.atomlist2vector(gradient_energy(thomson_pts))
     print "en = %s" % en
     return en  #, grad
コード例 #14
0
    def build_xyz(self, a1, a2, a3, unitcell, meso, beta):
        n, m = self.grid.shape
        center = (n / 2, m / 2)
        flake_atomlist = []
        unitcell_vec = XYZ.atomlist2vector(unitcell)
        for i in range(0, n):
            for j in range(0, m):
                if self.grid[i, j] == 1:
                    if self.orientation[i, j] != 0:
                        axis, angle = self.rotations[self.orientation[i, j]]
                        Rot = axis_angle2rotation(axis, angle)
                    else:
                        Rot = np.identity(3)
                    R = (i - n / 2) * a1 + (j - m / 2) * a2 + 0.0 * a3
                    shifted_unitcell_vec = np.zeros(unitcell_vec.shape)
                    for at in range(0, len(unitcell)):
                        # rotate and translate
                        shifted_unitcell_vec[3*at:3*(at+1)] = \
                            np.dot(Rot, unitcell_vec[3*at:3*(at+1)]) + R
                    flake_atomlist += XYZ.vector2atomlist(
                        shifted_unitcell_vec, unitcell)
                    # hydrogenize or add meso/beta substituents
                    for (lr, tb) in self.moves:
                        i_hyd = i + lr
                        j_hyd = j + tb
                        direction = lr * a1 + tb * a2
                        direction /= la.norm(direction)
                        if 0 <= i_hyd < n and 0 <= j_hyd < m:
                            if self.grid[i_hyd, j_hyd] != 1:
                                # no neighbouring porphine in that direction => add both meso and beta hydrogens
                                hydrogens = meso + beta  # hydrogens can also contain protecting groups, so it's not only H-atoms!
                            elif self.grid[i_hyd,j_hyd] == 1 \
                                    and (((self.orientation[i,j] == 0) and (self.orientation[i_hyd,j_hyd] in [5,6])) \
                                             or ((self.orientation[i_hyd,j_hyd] == 0) and (self.orientation[i,j] in [5,6]))):
                                hydrogens = beta
                            else:
                                hydrogens = []
                            # add hydrogens
                            hydadd = []
                            for at in range(0, len(hydrogens)):
                                (Zat, pos) = hydrogens[at]
                                hyddir = np.array(pos)
                                hyddir /= la.norm(hyddir)
                                angle = np.arccos(np.dot(hyddir, direction))
                                if abs(angle) < np.pi / 4.0:
                                    hydadd += [
                                        (Zat, np.dot(Rot, np.array(pos)) + R)
                                    ]
                            flake_atomlist += hydadd
                # meso-meso

        return flake_atomlist
コード例 #15
0
def _DipoleMatrix_f90(atomlist1, atomlist2, valorbs, SKT, Mproximity, S):
    """
    This function calls an external Fortran function that computes the matrix elements.
    Since hashes and tuples cannot be used easily in Fortran, the arguments are brought
    into a form that can be fed into the Fortran function.
    """
    atom_type_dic, spline_deg, tab_filled_SH0, tab_filled_D, \
        (S_knots, S_coefs, H_knots, H_coefs, D_knots, D_coefs) = \
                            combine_slako_tables_f90(SKT)

    # number of atoms
    Nat1 = len(atomlist1)
    Nat2 = len(atomlist2)
    # orbitals
    atom_indeces1,atom_types1,ls1,ms1 = atomlist2orbitals(atomlist1, valorbs, atom_type_dic)
    atom_indeces2,atom_types2,ls2,ms2 = atomlist2orbitals(atomlist2, valorbs, atom_type_dic)
    assert atom_indeces1 == atom_indeces2, "atomlist1 and atomlist2 should contain the same atoms in the same order!"
    # count valence orbitals
    Norb1 = len(ls1)
    Norb2 = len(ls2)
    # distances and direction
    pos1 = XYZ.atomlist2vector(atomlist1)
    pos1 = np.reshape(pos1,(Nat1,3)).transpose()  # pos(:,i) is the 3d position of atom i
    pos2 = XYZ.atomlist2vector(atomlist2)
    pos2 = np.reshape(pos2,(Nat2,3)).transpose()
    r,x,y,z = slako.slako.directional_cosines(pos1,pos2)

    Dipole = slako.slako.dipolematrix(atom_indeces1,atom_types1,ls1,ms1,
                              atom_indeces2,atom_types2,ls2,ms2,
                              r,x,y,z,pos1,
                              Mproximity,
                              S,
                              spline_deg, tab_filled_D,
                              D_knots, D_coefs)
    # In fortran the faster indeces come first, roll axes D(xyz,mu,nu) -> D(mu,nu,xyz)
    Dipole = np.rollaxis(Dipole,0,3)
    return Dipole
コード例 #16
0
ファイル: Puckering.py プロジェクト: humeniuka/DFTBaby
    def __init__(self, atomlist, ring_atoms=[], units="bohr"):
        """
        creates a molecule with a ring

        Parameters
        ----------
        atomlist: list of tupes (Zi,[xi,yi,zi]) with atomic positions

        Optional
        --------
        ring_atoms: indeces of atoms forming the ring
        bohr: units of coordinates [xi,yi,zi]
        """
        if units == "Angstrom":
            x = XYZ.atomlist2vector(atomlist) / AtomicData.bohr_to_angs
            self.atomlist = XYZ.vector2atomlist(x, atomlist)
        else:
            self.atomlist = atomlist
        self.ring_atoms = ring_atoms
コード例 #17
0
    def getJacobian(self):
        pos = XYZ.atomlist2vector(self.atomlist)
#        pos = self.standard_orientation()
        jac, jac_inv = jacobian_cartesian2internal(self.masses, pos, self.atomlist)
        print("Jacobian  J_ij = d( q_j )/d( x_i )")
        print("=====================================")
        print(utils.annotated_matrix(jac,["x_%s" % i for i in range(0, len(jac[:,0]))], ["q_%s" % j for j in range(0, len(jac[0,:]))]))

        print("Jacobian  J^(-1)_ij = d( x_j )/d( q_i )")
        print("=====================================")
#        jac_inv = inv(jac)
        print(utils.annotated_matrix(jac_inv,["q_%s" % i for i in range(0, len(jac_inv[:,0]))], ["x_%s" % j for j in range(0, len(jac_inv[0,:]))]))


#        print("Jacobian  J^(-1)_ij = d( x_j )/d( q_i )")
#        print("=====================================")
#        jac_inv = inv(jac)
#        print(utils.annotated_matrix(jac_inv,["q_%s" % i for i in range(0, len(pos))], ["x_%s" % j for j in range(0, len(pos))]))

        return jac, jac_inv
コード例 #18
0
    def getGeneralizedForces(self, cartesian_forces):
        """
        transform forces into internal coordinates using Jacobian

        FQ_i = dV/dq_i = sum_j dV/dx_j*dx_j/dq_i = sum_j J_ji*F_j

        F_j are cartesian forces, FQ_i are generalized forces

        Parameters:
        ===========
        cartesian_forces: list of forces on each atom
           [(Z1,[F1_x,F1_y, F1_z]), ..., (ZN,[FN_x,FN_y,FN_z)]
        """
        forces = XYZ.atomlist2vector(cartesian_forces)
        print "Cartesian forces:"
        print forces
        J = self.getJacobian()
        Q = dot(J.transpose(),forces)
        print "Generalized forces:"
        print Q
        return Q
コード例 #19
0
def nact_cartesian2internal(atomlist, nact):
    mol = MolecularCoords(atomlist)
    jac, jac_inv = mol.getJacobian()
    for (I,J),nactIJ in nact.items():
        #
        RxGrad = zeros(3)
        Grad = zeros(3)
        for i,(Zi, posi) in enumerate(atomlist):
            RxGrad += cross(array(posi), array(nactIJ[i][1]))
            Grad += array(nactIJ[i][1])
        print("Grad")
        print(Grad)
        print("RxGrad")
        print(RxGrad)
        #
        nactIJvec = XYZ.atomlist2vector(nactIJ)
        nactIJinternal = dot(jac_inv, nactIJvec)
        print("Non-adiabatic coupling vectors between state %s and %s" % (I,J))
        print("in cartesian coordinates")
        print(nactIJvec)
        print("in internal coordinates")
        print(nactIJinternal)
コード例 #20
0
ファイル: CPKS.py プロジェクト: humeniuka/DFTBaby
def dftb_numerical_charge_gradients(dftb2, atomlist, dp=0.0000001):
    """
    compute gradients of Mulliken charges numerically

    Optional:
    ---------
    dp: step size for numerical differentiation
    """
    from DFTB import XYZ

    dftb2.setGeometry(atomlist)

    dftb2.getEnergy(density_mixer=None,
                    scf_conv=1.0e-14,
                    start_from_previous=0)
    charges0 = dftb2.getPartialCharges()
    #
    atomlist0 = dftb2.getGeometry()
    vec = XYZ.atomlist2vector(atomlist0)
    Nat = len(atomlist)
    # charge gradient
    dQdp = np.zeros((3 * Nat, Nat))
    for i in range(0, 3 * Nat):
        # vec + dp
        vec_dp = np.copy(vec)
        vec_dp[i] += dp
        atomlist = XYZ.vector2atomlist(vec_dp, atomlist0)
        dftb2.setGeometry(atomlist)

        dftb2.getEnergy(density_mixer=None,
                        scf_conv=1.0e-14,
                        start_from_previous=0)

        charges1 = dftb2.getPartialCharges()

        dQdp[i, :] = (charges1 - charges0) / dp

    return dQdp
コード例 #21
0
 def plotLabels(self):
     #print "visualize labels"
     # draw atom labels
     if self.show_flags["labels"] == True:
         mlab = self.scene.mlab
         labels = []
         molecules = []
         for cube in self.cubes:
             molecules.append(cube.atomlist)
         for atomlist in self.molecules:
             molecules.append(atomlist)    
         for atomlist in molecules:
             nat = len(atomlist)
             vec = XYZ.atomlist2vector(atomlist)
             x, y, z = vec[::3], vec[1::3], vec[2::3]
             atom_names = [AtomicData.atom_names[Z-1] for (Z,pos) in atomlist]
             for i in range(0, nat):
                 name = atom_names[i].upper() + "-%d" % i
                 label = mlab.text(x[i],y[i],name, z=z[i], figure=self.scene.mayavi_scene)
                 label.actor.set(text_scale_mode='none', width=0.05, height=0.1)
                 label.property.set(justification='centered', vertical_justification='centered')
                 labels.append(label)
         self.label_objects += labels
コード例 #22
0
    def _update_visualization(self, atomlist):
        """
        only change the underlying data but do not recreate visualization.
        This is faster and avoids jerky animations.
        """
        vec = XYZ.atomlist2vector(atomlist)
        x, y, z = vec[::3], vec[1::3], vec[2::3]
        s = self.atom_radii
        if self.show_flags["atoms"] == False:
            # make atoms so small that one does not see them
            scale_factor = 0.01
            self.shown_atoms = False
        else:
            scale_factor = 0.3
            self.shown_atoms = True
        # update atom positions
        self.atoms.mlab_source.set(x=x,y=y,z=z,u=s,v=s,w=s, scalars=self.Zs, scale_factor=scale_factor)
        # atoms are coloured by their atomic number
        self.atoms.glyph.color_mode = "color_by_scalar"
        self.atoms.glyph.glyph_source.glyph_source.center = [0,0,0]
        self.atoms.module_manager.scalar_lut_manager.lut.table = self.lut
        self.atoms.module_manager.scalar_lut_manager.data_range = (0.0, 255.0)

        # update bonds
        self.bonds.mlab_source.reset(x=x,y=y,z=z, scale_factor=1.0)

        C = XYZ.connectivity_matrix(atomlist)
        Nat = len(atomlist)
        connections = []
        for i in range(0, Nat):
            Zi, posi = atomlist[i]
            for j in range(i+1,Nat):
                if C[i,j] == 1:
                    Zj, posj = atomlist[j]
                    connections.append( (i,j) )
        self.bonds.mlab_source.dataset.lines = np.array(connections)
        self.bonds.mlab_source.dataset.modified()
コード例 #23
0
ファイル: CPKS.py プロジェクト: humeniuka/DFTBaby
def dftb_numerical_mo_gradients(dftb2, atomlist, dp=0.0000001):
    """
    compute gradients of orbital energies and MO coefficients numerically by finite differences

    Optional:
    ---------
    dp: step size for numerical differentiation
    """
    from DFTB import XYZ

    dftb2.setGeometry(atomlist)

    dftb2.getEnergy()
    orbe0 = dftb2.getKSEnergies()
    orbs0 = dftb2.getKSCoefficients()
    #
    atomlist0 = dftb2.getGeometry()
    vec = XYZ.atomlist2vector(atomlist0)
    Nat = len(atomlist)
    Norb, Norb = orbs0.shape
    dorbe = np.zeros((3 * Nat, Norb))
    dorbs = np.zeros((3 * Nat, Norb, Norb))
    for i in range(0, 3 * Nat):
        vec_dp = np.copy(vec)
        vec_dp[i] += dp
        atomlist = XYZ.vector2atomlist(vec_dp, atomlist0)
        dftb2.setGeometry(atomlist)

        dftb2.getEnergy()
        orbe1 = dftb2.getKSEnergies()
        orbs1 = dftb2.getKSCoefficients()

        dorbe[i, :] = (orbe1 - orbe0) / dp
        dorbs[i, :, :] = (orbs1 - orbs0) / dp

    return dorbe, dorbs
コード例 #24
0
def check_analytic_gradients(atomlist0):
    """
    compare analytical gradients for gamma_solvent with numerical ones
    """
    from DFTB import utils
    from DFTB import XYZ

    cavity = SolventCavity(points_per_sphere=6)
    nats = len(atomlist0)
    x0 = XYZ.atomlist2vector(atomlist0)

    # ... analytical gradients
    cavity.constructSAS(atomlist0)
    cavity.constructCOSMO()
    gamma_solvent, grad_ana = cavity.constructCOSMOgradient()
    # ... numerical gradients
    grad_num = np.zeros((3 * nats, nats, nats))
    for i in range(0, nats):
        for j in range(0, nats):
            # define function for computing gamma_solvent[i,j]
            def f(x):
                atomlist = XYZ.vector2atomlist(x, atomlist0)
                cavity.constructSAS(atomlist)
                gamma_solvent = cavity.constructCOSMO()
                return gamma_solvent[i, j]

            grad_num[:, i, j] = utils.numerical_gradient(f, x0)

    print("analytical gradient")
    print(np.round(grad_ana, 6))
    print("numerical gradient")
    print(np.round(grad_num, 6))

    err = la.norm(grad_ana - grad_num)
    print("|(grad g_solvent)_num - (grad g_solvent)_ana|= %e" % err)
    assert err < 1.0e-5
コード例 #25
0
    print("Compute forces with DFTB")
    print("========================")
    print("")
    fh_en = open(energy_file, "w")
    print("# ELECTRONIC ENERGY / HARTREE", file=fh_en)

    # first geometry
    atomlist = XYZ.read_xyz(geom_file)[0]
    # read charge from title line in .xyz file
    kwds = XYZ.extract_keywords_xyz(geom_file)
    charge = kwds.get("charge", opts.charge)

    pes = PotentialEnergySurfaces(atomlist, charge=charge)
    # dftbaby needs one excited states calculation to set all variables
    x = XYZ.atomlist2vector(atomlist)
    pes.getEnergies(x)

    for i, atomlist in enumerate(XYZ.read_xyz(geom_file)):
        # compute electronic ground state forces with DFTB
        x = XYZ.atomlist2vector(atomlist)
        en = pes.getEnergy_S0(x)
        # total ground state energy including repulsive potential
        en_tot = en[0]
        print("Structure %d   enTot= %s Hartree" % (i, en_tot))
        # electronic energy without repulsive potential
        en_elec = pes.tddftb.dftb2.getEnergies()[2]
        gradVrep, gradE0, gradExc = pes.grads.gradient(I=0)
        # exclude repulsive potential from forces
        grad = gradE0 + gradExc
        forces = XYZ.vector2atomlist(-grad, atomlist)
コード例 #26
0
        default="[]")

    (opts, args) = parser.parse_args()

    if len(args) < 4:
        parser.print_help()
        exit(-1)

    xyz0 = args[0]
    xyz1 = args[1]
    N = int(args[2])
    xyz_interp = args[3]

    # read initial geometry
    atomlist0 = XYZ.read_xyz(xyz0)[0]
    x0 = XYZ.atomlist2vector(atomlist0)

    # read final geometry
    atomlist1 = XYZ.read_xyz(xyz1)[0]
    x1 = XYZ.atomlist2vector(atomlist1)

    # interpolation parameter
    rs = np.linspace(0.0, 1.0, N)

    geometries_interp = []

    if opts.coord_system == "cartesian":
        for r in rs:
            xr = x0 + r * (x1 - x0)
            geometries_interp.append(XYZ.vector2atomlist(xr, atomlist0))
    elif opts.coord_system == "internal":
コード例 #27
0
def averaged_pad_scan(xyz_file, dyson_file,
                      selected_orbitals, npts_euler, npts_theta, nskip, inter_atomic, sphere_radius):
    molecule_name = os.path.basename(xyz_file).replace(".xyz", "")
    atomlist = XYZ.read_xyz(xyz_file)[-1]
    # shift molecule to center of mass
    print "shift molecule to center of mass"
    pos = XYZ.atomlist2vector(atomlist)
    masses = AtomicData.atomlist2masses(atomlist)
    pos_com = MolCo.shift_to_com(pos, masses)
    atomlist = XYZ.vector2atomlist(pos_com, atomlist)
    # compute molecular orbitals with DFTB
    tddftb = LR_TDDFTB(atomlist)
    tddftb.setGeometry(atomlist, charge=0)
    options={"nstates": 1}
    try:
        tddftb.getEnergies(**options)
    except DFTB.Solver.ExcitedStatesNotConverged:
        pass

    valorbs, radial_val = load_pseudo_atoms(atomlist)

    if dyson_file == None:
        print "tight-binding Kohn-Sham orbitals are taken as Dyson orbitals"
        H**O, LUMO = tddftb.dftb2.getFrontierOrbitals()
        bound_orbs = tddftb.dftb2.getKSCoefficients()
        if selected_orbitals == None:
            # all orbitals
            selected_orbitals = range(0,bound_orbs.shape[1])
        else:
            selected_orbitals = eval(selected_orbitals, {}, {"H**O": H**O+1, "LUMO": LUMO+1})
            print "Indeces of selected orbitals (counting from 1): %s" % selected_orbitals
        orbital_names = ["orb_%s" % o for o in selected_orbitals]
        selected_orbitals = np.array(selected_orbitals, dtype=int)-1 # counting from 0
        dyson_orbs = bound_orbs[:,selected_orbitals]
        ionization_energies = -tddftb.dftb2.getKSEnergies()[selected_orbitals]
    else:
        print "coeffients for Dyson orbitals are read from '%s'" % dyson_file
        orbital_names, ionization_energies, dyson_orbs = load_dyson_orbitals(dyson_file)
        ionization_energies = np.array(ionization_energies) / AtomicData.hartree_to_eV

    print ""
    print "*******************************************"
    print "*  PHOTOELECTRON ANGULAR DISTRIBUTIONS    *"
    print "*******************************************"
    print ""
    
    # determine the radius of the sphere where the angular distribution is calculated. It should be
    # much larger than the extent of the molecule
    (xmin,xmax),(ymin,ymax),(zmin,zmax) = Cube.get_bbox(atomlist, dbuff=0.0)
    dx,dy,dz = xmax-xmin,ymax-ymin,zmax-zmin
    Rmax = max([dx,dy,dz]) + sphere_radius
    Npts = max(int(Rmax),1) * 50
    print "Radius of sphere around molecule, Rmax = %s bohr" % Rmax
    print "Points on radial grid, Npts = %d" % Npts
    
    nr_dyson_orbs = len(orbital_names)
    # compute PADs for all selected orbitals
    for iorb in range(0, nr_dyson_orbs):
        print "computing photoangular distribution for orbital %s" % orbital_names[iorb]
        data_file = "betas_" + molecule_name + "_" + orbital_names[iorb] + ".dat"
        pad_data = []
        print "  SCAN"
        nskip = max(1, nskip)
        # save table
        fh = open(data_file, "w")
        print "  Writing table with betas to %s" % data_file
        print>>fh, "# ionization from orbital %s   IE = %6.3f eV" % (orbital_names[iorb], ionization_energies[iorb]*AtomicData.hartree_to_eV)
        print>>fh, "# inter_atomic: %s  npts_euler: %s  npts_theta: %s  rmax: %s" % (inter_atomic, npts_euler, npts_theta, Rmax)
        print>>fh, "# PKE/eV     sigma          beta1          beta2      beta3          beta4"
        for i,E in enumerate(slako_tables_scattering.energies):
            if i % nskip != 0:
                continue
            print "    PKE = %6.6f Hartree  (%4.4f eV)" % (E, E*AtomicData.hartree_to_eV)
            k = np.sqrt(2*E)
            wavelength = 2.0 * np.pi/k
            bs_free = AtomicScatteringBasisSet(atomlist, E, rmin=0.0, rmax=Rmax+2*wavelength, Npts=Npts)
            SKT_bf, SKT_ff = load_slako_scattering(atomlist, E)
            Dipole = ScatteringDipoleMatrix(atomlist, valorbs, SKT_bf, inter_atomic=inter_atomic).real

            orientation_averaging = PAD.OrientationAveraging_small_memory(Dipole, bs_free, Rmax, E, npts_euler=npts_euler, npts_theta=npts_theta)

            pad,betasE = orientation_averaging.averaged_pad(dyson_orbs[:,iorb])
            pad_data.append( [E*AtomicData.hartree_to_eV] + list(betasE) )
            # save PAD for this energy
            print>>fh, "%10.6f   %10.6e  %+10.6e  %+10.6f  %+10.6e  %+10.6e" % tuple(pad_data[-1])
            fh.flush()
        fh.close()
コード例 #28
0
def get_2d_bbox(atomlist):
    pos = XYZ.atomlist2vector(atomlist)
    x, y, z = pos[0::3], pos[1::3], pos[2::3]
    return x.min(), y.min(), x.max(), y.max()
コード例 #29
0
    def writeTimeSeries(self, fish, time_series=[]):
        atomlist = self.pes.tddftb.dftb2.getGeometry()
        Nat = len(atomlist)  # number of QM atoms
        x = XYZ.atomlist2vector(atomlist)
        coordinates = np.reshape(x, (Nat, 3))
        symbols = [AtomicData.atom_names[Z - 1] for (Z, pos) in atomlist]
        # fish is an instance of the class fish.moleculardynamics
        if "particle-hole charges" in time_series:
            # ph charges are weighted by quantum populations |C(I)|^2
            particle_charges, hole_charges = self.getAvgParticleHoleCharges(
                fish.c)
            # append charges to file
            outfile = open("particle_hole_charges.xyz", "a")
            outfile.write("%d\n" % Nat)
            outfile.write(" time: %s fs\n" % (fish.time / fish.fs_to_au))
            tmp = fish.au_to_ang * coordinates
            for i in range(0, Nat):
                outfile.write("%s  %20.12f  %20.12f  %20.12f      %5.7f %5.7f\n" \
                              %(symbols[i],tmp[i][0],tmp[i][1],tmp[i][2],particle_charges[i], hole_charges[i]))
            outfile.close()
        if "particle-hole charges current" in time_series:
            # ph charges of the current electronic state
            if fish.state == 0:
                # ground state
                particle_charges = np.zeros(Nat)
                hole_charges = np.zeros(Nat)
            else:
                # excited state
                particle_charges, hole_charges = self.pes.tddftb.ParticleHoleCharges(
                    fish.state - 1)
            # append charges to file
            outfile = open("particle_hole_charges_current.xyz", "a")
            outfile.write("%d\n" % Nat)
            outfile.write(" time: %s fs\n" % (fish.time / fish.fs_to_au))
            tmp = fish.au_to_ang * coordinates
            for i in range(0, Nat):
                outfile.write("%s  %20.12f  %20.12f  %20.12f      %5.7f %5.7f\n" \
                              %(symbols[i],tmp[i][0],tmp[i][1],tmp[i][2],particle_charges[i], hole_charges[i]))
            outfile.close()
        if "Lambda2 current" in time_series:
            if fish.state == 0:
                # ground state, Lambda2 descriptor is only defined for excited states
                Lambda2 = -1.0
            else:
                # excited state
                Lambda2 = self.pes.tddftb.Lambda2[fish.state - 1]

            if not os.path.isfile("lambda2_current.dat"):
                outfile = open("lambda2_current.dat", "w")
                # write header
                print >> outfile, "# TIME / fs       LAMBDA2 "
                print >> outfile, "#              0  -  charge transfer state"
                print >> outfile, "#              1  -  local excitation     "
                print >> outfile, "#             -1  -  ground state (Lambda2 undefined)"
            else:
                outfile = open("lambda2_current.dat", "a")

            print >> outfile, "%14.8f    %+7.4f" % (fish.time / fish.fs_to_au,
                                                    Lambda2)
            outfile.close()
        if "Lambda2" in time_series:
            # Lambda2 descriptors for all excited states
            if not os.path.isfile("lambda2.dat"):
                outfile = open("lambda2.dat", "w")
                # write header
                print >> outfile, "# TIME / fs       LAMBDA2's OF EXCITED STATES"
                print >> outfile, "#              0  -  charge transfer state"
                print >> outfile, "#              1  -  local excitation     "
                print >> outfile, "#             -1  -  ground state (Lambda2 undefined)"
            else:
                outfile = open("lambda2.dat", "a")

            print >> outfile, "%14.8f    " % (fish.time / fish.fs_to_au),
            for I in range(1, self.nstates):
                print >> outfile, "  %+7.4f" % (self.pes.tddftb.Lambda2[I -
                                                                        1]),
            print >> outfile, ""

            outfile.close()
        if "transition charges current" in time_series:
            # transition charges for S0 -> current electronic state S_n
            if fish.state == 0:
                # ground state
                transition_charges = np.zeros(Nat)
            else:
                # excited state
                transition_charges = self.pes.tddftb.TransitionChargesState(
                    fish.state - 1)
            # append charges to file
            outfile = open("transition_charges_current.xyz", "a")
            outfile.write("%d\n" % Nat)
            outfile.write(" time: %s fs\n" % (fish.time / fish.fs_to_au))
            tmp = fish.au_to_ang * coordinates
            for i in range(0, Nat):
                outfile.write("%s  %20.12f  %20.12f  %20.12f      %5.7f\n" \
                              %(symbols[i],tmp[i][0],tmp[i][1],tmp[i][2], transition_charges[i]))
            outfile.close()
コード例 #30
0
        help=
        "Normal modes with very low frequencies (freq^2 < zero_threshold) are treated as zero modes. This allows to freeze modes that would lead to large unrealistic displacements. [default: %default]"
    )

    (opts, args) = parser.parse_args()
    if len(args) < 2:
        print usage
        exit(-1)

    xyz_file = args[0]
    hess_file = args[1]
    # should be options

    # optimized geometry
    atomlist = XYZ.read_xyz(xyz_file)[-1]
    xopt = XYZ.atomlist2vector(atomlist)
    # load hessian
    hess = np.loadtxt(hess_file)

    masses = AtomicData.atomlist2masses(atomlist)
    vib_freq, vib_modes = HarmonicApproximation.vibrational_analysis(xopt, hess, masses, \
                                 zero_threshold=opts.zero_threshold, is_molecule=True)

    # SAMPLE INITIAL CONDITIONS FROM WIGNER DISTRIBUTION
    qs, ps = HarmonicApproximation.initial_conditions_wigner(
        xopt,
        hess,
        masses,
        Nsample=opts.Nsample,
        zero_threshold=opts.zero_threshold)
    # make hydrogens slower