Esempio n. 1
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
Esempio n. 2
0
def run_gaussian(atomlist, directory="."):
    """
    run Gaussian input script in `neb.gjf` and read energy and gradient
    from checkpoing file `grad.fchk`.

    Parameters
    ----------
    atomlist:  list of tuples with atomic numbers and cartesian positions (Zat,[x,y,z])
               for each atom
    directory: directory where the calculation should be performed

    Returns
    -------
    en    :  total energies of ground state (in Hartree)
    grad  :  gradient of total energy (in a.u.)
    """
    # create directory if it does not exist already
    os.system("mkdir -p %s" % directory)
    os.system("cp neb.gjf %s/neb.gjf" % directory)
    # update geometry
    XYZ.write_xyz("%s/geometry.xyz" % directory, [atomlist])
    # remove number of atoms and comment
    os.system("cd %s; tail -n +3 geometry.xyz > geom" % directory)
    # calculate electronic structure
    ret = os.system(r"cd %s; g09 < neb.gjf > neb.out" % directory)
    ret &= os.system(r"cd %s; formchk grad.chk >> neb.out" % directory)
    assert ret == 0, "Return status = %s, error in Gaussian calculation, see %s/neb.out!" % (
        ret, directory)
    # read checkpoint files
    data = Checkpoint.parseCheckpointFile("%s/grad.fchk" % directory)

    en = data["_Total_Energy"]
    grad = data["_Cartesian_Gradient"]

    return en, grad
Esempio n. 3
0
        def save_step():
            """function is called after each minimization"""
            scan_coord = self.IC.coordinate_value(xi, IJKL)

            print("current value of scan coordinate : %s" % scan_coord)

            if i == 0:
                mode = "w"
            else:
                mode = "a"
            # save relaxed geometry of step i
            XYZ.write_xyz(self.xyz_scan, [atomlist],
                          title="charge=%s energy=%s" %
                          (self.geom_kwds.get("charge", 0), self.enI),
                          mode=mode)

            # save table with energies along scan
            fh = open(self.dat_scan, mode)
            if i == 0:
                # write header
                print("# Relaxed scan along %s defined by atoms %s" %
                      (coord_type[typ], [I + 1 for I in IJKL]),
                      file=fh)
                print("# state of interest: %d" % self.state, file=fh)
                print("# ", file=fh)
                print("#  Scan coordinate     Energies ", file=fh)
                print("#    %s              Hartree " % units[typ], file=fh)

            print("  %8.5f     " % scan_coord, end=' ', file=fh)
            for en in self.energies:
                print("   %e " % en, end=' ', file=fh)
            print("", file=fh)
            fh.close()
Esempio n. 4
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
Esempio n. 5
0
def calc_gradients(xyzfile, optionfile):
    """calculates DFTB energies and gradients for a molecule in the xyz_file
    with the options given in the optionfile"""

    outputfile = open("output_dftb.txt", "a")  # redirect output to file
    sys.stdout = outputfile

    try:
        options = read_options(optionfile)  # read options
        atomlist = XYZ.read_xyz(xyzfile)[0]  # read structure

        init_options = extract_options(options, TD_INIT_OPTIONLIST)
        td_options = extract_options(options, TD_OPTIONLIST)
        grad_options = extract_options(options, GRAD_OPTIONS)
        kwds = XYZ.extract_keywords_xyz(xyzfile)

        tddftb = LR_TDDFTB(atomlist, **init_options)  # create object
        tddftb.setGeometry(atomlist, charge=kwds.get("charge", 0.0))
        tddftb.getEnergies(**td_options)  # calculate energies

        grad = Gradients(tddftb)  # calculate gradients
        grad.getGradients(**grad_options)

        energies = list(tddftb.dftb2.getEnergies())  # get partial energies

        if tddftb.dftb2.long_range_correction == 1:  # add long range correction to partial energies
            energies.append(tddftb.dftb2.E_HF_x)

        return str(energies)

    except:
        print sys.exc_info()
        return "error"
Esempio n. 6
0
    def _getPES(self):
        """calculate energies and gradients at the image positions"""
        self.V = [None for Ri in self.R]  # potential energies of each image
        self.F = [None for Ri in self.R]  # true forces acting on each image

        if self.nr_processors > 1:
            # parallelize over images
            atomlists = [XYZ.vector2atomlist(x, self.atomlist) for x in self.R]
            image_dirs = ["IMAGE_%2.2d" % i for i in range(0, len(self.R))]
            pool = Pool(self.nr_processors)
            results = pool.map(run_gaussian_map, zip(atomlists, image_dirs))
            for i, (en, grad) in enumerate(results):
                print "image %4.d   energy= %+e   |grad|= %e" % (i, en,
                                                                 la.norm(grad))
                self.V[i] = en
                self.F[i] = -grad
        else:
            # sequential implementation
            for i, Ri in enumerate(self.R):
                atomlist = XYZ.vector2atomlist(Ri, self.atomlist)
                en, grad = run_gaussian(atomlist, directory="IMAGE_%2.2d" % i)
                self.V[i] = en
                self.F[i] = -grad
                print "image %4.d   energy= %+e   |grad|= %e" % (i, en,
                                                                 la.norm(grad))
def flakes_to_xyz(grown_flakes, out_xyz, cc1=2.56, substitutions=[]):
    generations = grown_flakes.keys()
    generations.sort()

    lat, unitcell, meso, beta = zn_porphene_lattice(
        cc1=cc1, substitutions=substitutions)
    a1, a2, a3 = lat.getLatticeVectors("real")

    if out_xyz[-4:] == ".xyz":
        try:
            os.remove(opts.out_xyz)
        except OSError as e:
            print e
    for gen in generations:
        print "Generation %s (%s flakes)" % (gen, len(grown_flakes[gen]))
        print "========================="
        for fl in grown_flakes[gen]:
            print "weight = %s" % fl.weight
            print fl
            flake_atomlist = fl.build_xyz(a1, a2, a3, unitcell, meso, beta)
            # reorder atomlist so that all hydrogens are placed at the end of the file
            flake_atomlist = XYZ.hydrogens_to_end(flake_atomlist)
            XYZ.write_xyz(expandvars(expanduser(out_xyz)), [flake_atomlist],
                          title="weight=%d" % fl.weight,
                          mode="a")
Esempio n. 8
0
def get_active_space(xyzfile, optionfile):
    """calculates the active space for a given molecule and excited state
    (see http://www.dftbaby.chemie.uni-wuerzburg.de/DFTBaby/mdwiki.html#!WIKI/main_page.md, Active Space)
    
    not implemented in CAST because no use for ground state calculations
    for ground state calculations the active space can be set as small as desired"""

    outputfile = open("output_dftb.txt", "a")  # redirect output to file
    sys.stdout = outputfile

    try:
        options = read_options(optionfile)  # read options
        atomlist = XYZ.read_xyz(xyzfile)[0]  # read structure

        init_options = extract_options(options, TD_INIT_OPTIONLIST)
        td_options = extract_options(options, TD_OPTIONLIST)
        kwds = XYZ.extract_keywords_xyz(xyzfile)

        tddftb = LR_TDDFTB(atomlist, **init_options)  # create object
        tddftb.setGeometry(atomlist, charge=kwds.get("charge", 0.0))
        tddftb.getEnergies(**td_options)  # calculate energies
        occ, virt = tddftb.determineActiveSpace()
        return str((occ, virt))
    except:
        print sys.exc_info()
        return "error"
Esempio n. 9
0
def eclipsed_oligomers():
    # build eclipsed oligomers
    for n in [2, 3, 4, 5, 6, 7, 8]:
        distances = 2.5 / AtomicData.bohr_to_angs * np.ones(n)
        angles = np.zeros(n)
        Fn = build_polyfluoerene(distances, angles)
        XYZ.write_xyz("F%d_eclipsed.xyz" % n, [Fn])
Esempio n. 10
0
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
Esempio n. 11
0
def calc_energies(xyzfile, optionfile):
    """calculates DFTB energies for a molecule in the xyz_file
    with the options given in the optionfile"""

    outputfile = open("output_dftb.txt", "a")  # redirect output to file
    sys.stdout = outputfile

    try:
        options = read_options(optionfile)  # read options
        atomlist = XYZ.read_xyz(xyzfile)[0]  # read structure
        kwds = XYZ.extract_keywords_xyz(xyzfile)

        dftb2 = DFTB2(atomlist, **options)  # create dftb object
        dftb2.setGeometry(atomlist, charge=kwds.get("charge", 0.0))

        scf_options = extract_options(options,
                                      SCF_OPTIONLIST)  # calculate energy
        dftb2.getEnergy(**scf_options)
        energies = list(dftb2.getEnergies())  # get partial energies

        if dftb2.long_range_correction == 1:  # add long range correction to partial energies
            energies.append(dftb2.E_HF_x)

        return str(energies)

    except:
        print sys.exc_info()
        return "error"
Esempio n. 12
0
def capped_uff_nanotube(cnt,NcapN=0, NcapS=0, optimize_uff=1, out_xyz="/tmp/cnt.xyz"):
    """
    build capped nanotube and optimize it with UFF
    """
    nC,nT = cnt.NrCapAtoms()
    print "Expected number of Thomson points nT = %s" % nT
    print "If the caps have holes or very close atoms, you should try increasing"
    print "or reducing the number of Thomson points (by changing the options NcapN or NcapS)"
    if NcapN == 0:
        NcapN = nT
    if NcapS == 0:
        NcapS = nT

    """
    Different number of Thomson points are tested to find
    a pair (NcapN,NcapS) 
    """
    dcap = []
    dnmin=0
    dnmax=1
    ntrial=5
    for dnN in range(dnmin, dnmax):
        for dnS in range(dnmin, dnmax):
            # try for 5 times
            for n in range(0, ntrial):
                dcap.append( (dnN,dnS) )
    dcap = sorted(dcap, key=lambda (a,b): abs(a)+abs(b))

    for (dnN,dnS) in dcap:
        print "north cap: %s points, south cap: %s points" % (NcapN+dnN,NcapS+dnS)
        atomlist_carbons = capped_nanotube(cnt,NcapN+dnN,NcapS+dnS)
        if optimize_uff == 1:
            print "CNT will be optimized further with the Universal Force Field of G09"
            tmp_dir="/tmp"
            com_file = join(tmp_dir, "cnt_uff_opt.com")
            chk_file = join(tmp_dir, "cnt_uff_opt.chk")
            fchk_file = chk_file.replace(".chk", ".fchk")
            Gaussian.write_input(com_file, atomlist_carbons, \
                route="# UFF Opt", \
                title="Optimize (%s,%s)-Nanotube with UFF" % (cnt.n1,cnt.n2), chk=chk_file,mem=1000)
            try:
                Gaussian.run(com_file)
                # format checkpoint file
                Gaussian.formchk(chk_file, fchk_file)
                Data = Checkpoint.parseCheckpointFile(fchk_file)
                pos = Data["_Current_cartesian_coordinates"]
                atomlist_uff = XYZ.vector2atomlist(pos, atomlist_carbons)
                atomlist_carbons = atomlist_uff
            except Gaussian.GaussianError:
                print "UFF-optimization failed!"
                continue
        if check_connectivity(atomlist_carbons) == True:
            # no holes, correct connectivity
            break
        XYZ.write_xyz("/tmp/trials.xyz", [atomlist_carbons], mode="a")
    else:
        print ""

    XYZ.write_xyz(expandvars(expanduser(out_xyz)), [atomlist_carbons])
    print "Geometry of capped CNT written to %s" % out_xyz
Esempio n. 13
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
Esempio n. 14
0
def alternately_rotated_oligomers():
    # neighbouring fluorenes are rotated by +-10.5 degrees
    for n in [2, 3, 4, 5, 6, 7, 8]:
        distances = 2.5 / AtomicData.bohr_to_angs * np.ones(n)
        # alternate fluorenes with + or - 10.5 degrees
        angles = 21.0 / 2.0 * np.pi / 180.0 * pow(-1, np.arange(n))
        Fn = build_polyfluoerene(distances, angles)
        XYZ.write_xyz("F%d_rotated.xyz" % n, [Fn])
Esempio n. 15
0
    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)
Esempio n. 16
0
 def plot(self, images=[], energies=[], istep=0):
     geometries = [XYZ.vector2atomlist(im, self.atomlist) for im in images]
     xyz_out = "neb_%s_%d.xyz" % (self.name, istep)
     XYZ.write_xyz(xyz_out, geometries)
     print("wrote path for iteration %d to %s" % (istep, xyz_out))
     if energies != []:
         # first column: index of image
         # second column: energy of image
         data = np.vstack((np.arange(0, len(images)), energies)).transpose()
         np.savetxt("path_energies_%s_%d.dat" % (self.name, istep), data)
Esempio n. 17
0
def scan_angle_F2():
    n = 2
    distances = 2.5 / AtomicData.bohr_to_angs * np.ones(n)
    scan_geometries = []
    for a in np.linspace(0.0, np.pi, 80.0):
        print(a * 180.0 / np.pi)
        angles = [a / 2.0, -a / 2.0]
        F2 = build_polyfluoerene(distances, angles)
        scan_geometries.append(F2)
    XYZ.write_xyz("F2_angle_scan.xyz", scan_geometries)
Esempio n. 18
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
Esempio n. 19
0
 def save_xyz(x, mode="a"):
     global step
     if step % opts.save_every != 0:
         step += 1
         return
     step += 1
     atomlist_opt = XYZ.vector2atomlist(x, atomlist)
     atomlist_opt, dummy = enlarged_unitcell(atomlist_opt,
                                             lattice_vectors,
                                             nmax=opts.nr_unit_cells)
     XYZ.write_xyz(xyz_opt, [atomlist_opt], \
                   mode=mode)
Esempio n. 20
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
Esempio n. 21
0
    def addCap(self):
        #
        x_cap = initial_distribution_cap(
            self.Ncap)  # positions of Thomson points on the cap
        # for points in the cap x[i,:] = (theta_i, phi_i)
        # and for points in the tube x[i,:] = (z_i, phi_i)
        s_cap = ["C" for i in range(0, self.Ncap)]  # segment of carbo-nanotube
        # to which the Thomson point belongs, 'C' for cap and 'T' for tube
        o_cap = np.ones(self.Ncap, dtype=int)
        # o[i] == 1, position of i-th Thomson point is optimized
        # o[i] == 0, position is held constant
        #
        x_tube, o_tube, s_tube = thomson_tube(self.cnt.chiral_vector,
                                              self.cnt.tube_vector,
                                              self.cnt.a1, self.cnt.a2)

        # These unit vectors define the orientation of the
        # coordinate system
        ex = np.array([1, 0, 0])
        ey = np.array([0, 1, 0])
        ez = np.array([0, 0, 1])
        self.axes = [ex, ey, ez]
        self.Z0 = 0.0

        # combine Thomson point of cap with those of the tube
        self.x = np.vstack((x_cap, x_tube))
        self.s = np.array(s_cap + s_tube)
        self.o = np.hstack((o_cap, o_tube))

        self.N = len(self.x)

        if self.north_south == "N":
            pass
        elif self.north_south == "S":
            self.x = reflect_tube_xy(self.x, self.s, self.cnt.L)

        atomlist = self.thomson2atomlist()
        XYZ.write_xyz("/tmp/thomson_opt.xyz", [atomlist], mode="w")

        active, inactive = active_layers(self.x, self.s, self.cnt.a1,
                                         self.cnt.a2)

        def savexyz():
            atomlist = self.thomson2atomlist()
            XYZ.write_xyz("/tmp/thomson_opt.xyz", [atomlist], mode="a")

        self.x[active, :], self.s[active], self.o[
            active], self.en, self.grad = optimize_thomson(self.x[active, :],
                                                           self.s[active],
                                                           self.o[active],
                                                           R=self.cnt.R,
                                                           callback=savexyz)
        return (self.en, self.grad)
    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
Esempio n. 23
0
    def changeTrajectory(self):
        selected = self.trajSelection.selectedItems()
        trajs = map(int, [s.text() for s in selected])
        self.geometries = []
        self.nsteps = 0
        print "Selected: %s" % map(str, trajs)
        print "Plot trajectories %s" % trajs
        for ax in self.axes:
            ax.clear()
        for t in trajs:
            trajdir = self.trajdirs[t]
            print trajdir
            try:
                self.plotTrajectory(trajdir, t)
                self.geometries.append( XYZ.read_xyz(os.path.join(trajdir, "dynamics.xyz")) )
                self.nsteps = max(len(self.geometries[-1]), self.nsteps)
            except (ValueError, IOError) as e:
                print "Unable to load %s" % trajdir
                print "ERROR: %s" % e
        for canvas in self.canvases:
            canvas.draw()    

        self.animationSlider.setMinimum(0)
        self.animationSlider.setMaximum(self.nsteps)
        self.animationTime.setText("Time: %7.2f fs" % 0.0)
        self.showMolecules()
Esempio n. 24
0
 def showMolecules(self):
     tstep = self.animationSlider.value()
     self.animationTime.setText("Time: %7.2f fs" % (tstep * self.dt))
     self.mol.clear()
     for geoms in self.geometries:
         geom_time = geoms[min(tstep, len(geoms)-1)]
         # atoms
         atoms = []
         for (Z,pos) in geom_time:
             a = self.mol.addAtom()
             a.pos = np.array(pos, dtype=float)
             a.atomicNumber = Z
             atoms.append(a)
         # bond
         C = XYZ.connectivity_matrix(geom_time)
         Nat = len(geom_time)
         for i in range(0, Nat):
             for j in range(i+1,Nat):
                 if C[i,j] == 1:
                     bond = self.mol.addBond()
                     bond.setBegin(atoms[i])
                     bond.setEnd(atoms[j])
                     bond.order = 1
                     
     self.glWidget.mol = self.mol
     self.glWidget.updateGeometry()
     Avogadro.toPyQt(self.glWidget).update()
Esempio n. 25
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)
Esempio n. 26
0
def get_unique_atomtypes(fit_dir):
    """
    given a list of xyz-files, determine the atomic numbers that are present
    in any file. For each atom combination a repulsive potential is fitted.
    """

    xyz_filenames = glob.glob("%s/FIT_PATHS/*.xyz" % fit_dir)

    unique_atomtypes = []
    for f in xyz_filenames:
        for atomlist in XYZ.read_xyz_it(f):
            # atomic numbers in first frame
            for Zi, posi in atomlist:
                if not Zi in unique_atomtypes:
                    unique_atomtypes.append(Zi)

    unique_atomtypes = np.sort(unique_atomtypes)

    print("")
    print("Atom Types:")
    print("-----------")
    for Zi in unique_atomtypes:
        print("  %s" % AtomicData.atom_names[Zi - 1])
    print("")

    return unique_atomtypes
    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
Esempio n. 28
0
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
Esempio n. 29
0
def load_fragments(frag_links_file):
    """
    Load xyz-files for each fragment. To map the fragment names to the fragment
    xyz-files a file with the links has to be provided.
    Example for a fragments.lnk file:

       C60  C60.xyz
       Et   ethylene.xyz

    Parameters:
    ===========
    frag_links_file: path that links fragment names with geometry definitions
    
    Returns:
    ========
    fragments: dictionary with e.g. d["C60"] = (geometry of C60)
    """
    frag_dir = dirname(frag_links_file)
    fh = open(frag_links_file)
    fragments = {}
    for l in fh:
        frag_name, frag_xyz_path = l.split()
        if not exists(frag_xyz_path):
            # not an absolute path, try relative path toe frag_dir
            frag_xyz_path = join(frag_dir, frag_xyz_path)
        fragments[frag_name] = XYZ.read_xyz(frag_xyz_path)[0]
    fh.close()
    return fragments
Esempio n. 30
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