Ejemplo n.º 1
0
def example_1():
    # In this example, we will generate a smooth CNH-HCN isomerization
    # guessed pathway

    # Step 1 - Generate the bad initial guess
    print("Step 1 - Generate the bad initial guess...")
    H_coords = [(2, 0), (2, 1), (1, 1), (0, 1), (-1, 1), (-1, 0)]
    CNH_frames = [[
        structures.Atom("C", 0, 0, 0),
        structures.Atom("N", 1, 0, 0),
        structures.Atom("H", x, y, 0)
    ] for x, y in H_coords]
    # Further, randomly rotate the atoms
    CNH_frames = [
        geometry.perturbate(frame, dx=0.0, dr=360) for frame in CNH_frames
    ]
    files.write_xyz(CNH_frames, "rotated_pathway.xyz")

    # Step 2 - Use procrustes to remove rotations
    print("Step 2 - Use Procrustes to remove rotations...")
    geometry.procrustes(CNH_frames)
    files.write_xyz(CNH_frames, "procrustes_pathway.xyz")

    # Step 3 - Smooth out the band by minimizing the RMS atomic motion between
    # consecutive frames until it is below 0.1 (with a max of 50 frames).
    print("Step 3 - Smooth out the band...")
    CNH_frames = geometry.smooth_xyz(CNH_frames,
                                     R_max=0.1,
                                     F_max=50,
                                     use_procrustes=True)
    # Save smoothed band
    files.write_xyz(CNH_frames, "smoothed_pathway.xyz")
Ejemplo n.º 2
0
def _generate_ion_halide(halide, ion="Pb"):
    """
    A function to generate atomic coordinates of an ion and three halides for
    a perovskite monomer.

    **Parameters**

        halide: *list, str or str*
            The halides to use.
        ion: *str, optional*
            What ion to use.

    **Returns**

        ionX3: *Molecule*
            A molecule object holding the perovskite ion + halide atoms.

    """
    ionX3 = structures.Molecule([structures.Atom(ion, 0, 0, 0)])
    if type(halide) is str:
        halide = [halide, halide, halide]

    def vdw(y):
        return constants.PERIODIC_TABLE[units.elem_s2i(y)]['vdw_r']

    for x in halide:
        v = vdw(x)
        ionX3.atoms.append(structures.Atom(x, v, 0, 0.5 * v))
        R = geometry.rotation_matrix([0, 0, 1], 120, units="deg")
        ionX3.rotate(R)
    return ionX3
Ejemplo n.º 3
0
def isolate_atom_types(types, dump_obj, mol_len):

    count = 0
    atoms_list = []
    frames = []
    for line in dump_obj:
        words = line.split()

        if count == mol_len:
            frames.append(atoms_list)
            count = 0
            atoms_list = []

        try:
            if int(words[0]) in types:
                atom_type = types[int(words[0])]
                x = float(words[1])
                y = float(words[2])
                z = float(words[3])
                count = count + 1
                atoms_list.append(
                    structures.Atom(atom_type, x, y, z, index=count))
        except ValueError:
            pass

    return frames
Ejemplo n.º 4
0
def _test_generate_ion_halide_cation():
    obj = generate_ion_halide_cation(["Cl", "Br", "Br"],
                                     "Cs",
                                     "CsPbBrBrCl_0",
                                     WORLD_CONSTS.default_routes[0],
                                     WORLD_CONSTS.extra_section,
                                     ion="Pb",
                                     run_opt=False).atoms
    saved = [
        structures.Atom("Cs", 0.0, 0.0, 2.5299999999999998),
        structures.Atom("Pb", 0.0, 0.0, 0.0),
        structures.Atom("Cl", 2.0499999999999998, -3.3306690738754696e-15,
                        1.0249999999999999),
        structures.Atom("Br", -1.050000000000002, -1.8186533479473201, 1.05),
        structures.Atom("Br", -1.0499999999999989, 1.8186533479473219, 1.05),
    ]
    TOLERANCE = 1E-6
    return geometry.motion_per_frame([obj, saved])[1] < TOLERANCE
Ejemplo n.º 5
0
def parse_scan(input_file):
    contents = open(input_file).read()
    if 'Normal termination of Gaussian 09' not in contents:
        return None
    scan_steps = contents.split('on scan point')
    energy_list = []
    atoms_list = []

    scan_steps = [
        scan_steps[i] for i in range(1,
                                     len(scan_steps) - 1)
        if scan_steps[i][:10].split()[0] != scan_steps[i + 1][:10].split()[0]
    ]

    for scan_step in scan_steps:
        a = scan_step.rindex('SCF Done')
        energy_line = scan_step[a:scan_step.index('\n', a)]
        energy = float(
            re.search('SCF Done: +\S+ += +(\S+)', energy_line).group(1))

        last_coordinates = scan_step.rindex('Coordinates (Angstroms)')

        start = scan_step.index('---\n', last_coordinates) + 4
        end = scan_step.index('\n ---', start)
        atoms = []
        for line in scan_step[start:end].splitlines():
            columns = line.split()
            x, y, z = [float(s) for s in columns[3:6]]
            atoms.append(
                structures.Atom(element=constants.PERIODIC_TABLE[int(
                    columns[1])]['sym'],
                                x=x,
                                y=y,
                                z=z))
        energy_list.append(energy)
        atoms_list.append(atoms)
    return energy_list, atoms_list
Ejemplo n.º 6
0
def read(input_file, atom_units="Ang"):
    '''
    General read in of all possible data from a JDFTx output file.

    **Parameters**

        input_file: *str*
            JDFTx output file to be parsed.
        atom_units: *str, optional*
            What units you want coordinates to be converted to.

    **Returns**

        data: :class:`results.DFT_out`
            Generic DFT output object containing all parsed results.

    '''
    raise Exception("NEEDS TO BE DONE!")
    # Check file exists, and open
    # Allow absolute paths as filenames
    if not input_file.startswith('/') and not os.path.isfile(input_file):
        input_path = 'jdftx/%s/%s.out' % (input_file, input_file)
    else:
        input_path = input_file
    if not os.path.isfile(input_path):
        raise IOError('Expected JDFTx output file does not exist at %s'
                      % (input_path))
        sys.exit()
    data = open(input_path, 'r').read()
    data_lines = data.splitlines()

    # Get coordinates
    section, frames, gradients = data, [], []
    s = "# Ionic positions in cartesian coordinates:"
    ss = "# Forces in Cartesian coordinates:"
    while s in section:
        section = section[section.find(s) + len(s):]
        atom_block = section[:section.find('\n\n')].split('\n')[1:]
        frame, gradient = [], []
        for i, line in enumerate(atom_block):
            a = line.split()
            frame.append(structures.Atom(
                a[1],
                units.convert_dist("Bohr", atom_units, float(a[2])),
                units.convert_dist("Bohr", atom_units, float(a[3])),
                units.convert_dist("Bohr", atom_units, float(a[4])),
                index=i))
        frames.append(frame)

        # If we also have forces, read those in
        if ss in section:
            section = section[section.find(ss) + len(ss):]
            force_block = section[:section.find('\n\n')].split('\n')[1:]
            for i, line in enumerate(force_block):
                a = line.split()
                frames[-1][i].fx = units.convert(
                    "Ha/Bohr", "Ha/%s" % atom_units, float(a[2]))
                frames[-1][i].fy = units.convert(
                    "Ha/Bohr", "Ha/%s" % atom_units, float(a[3]))
                frames[-1][i].fz = units.convert(
                    "Ha/Bohr", "Ha/%s" % atom_units, float(a[4]))
                gradient.append(
                    [frames[-1][i].fx, frames[-1][i].fy, frames[-1][i].fz])
            gradients.append(gradient)

    atoms = None
    if frames:
        atoms = frames[-1]

    section, energies = data, []
    s = "IonicMinimize: Iter:"
    while s in section:
        section = section[section.find(s) + len(s):]
        energy = float(section.split("\n")[0].strip().split()[2])
        grad_k = float(section.split("\n")[0].strip().split()[4])
        energies.append(energy)
    convergence = None
    if len(energies) > 2:
        section = data[data.find("ionic-minimize"):]
        de_criteria = float(section[
            section.find("energyDiffThreshold"):].split("\n")[0].strip().split()[1])
        k_criteria = float(section[
            section.find("knormThreshold"):].split("\n")[0].strip().split()[1])
        de1 = abs(energies[-2] - energies[-3])
        de2 = abs(energies[-1] - energies[-2])
        convergence = [
            ["Change in Energy 1",
             "%.2e" % de1,
             de_criteria,
             ["NO", "YES"][de_criteria > de1]],
            ["Change in Energy 2",
             "%.2e" % de2,
             de_criteria,
             ["NO", "YES"][de_criteria > de2]],
            ["K Norm",
             "%.2e" % abs(grad_k),
             k_criteria,
             ["NO", "YES"][k_criteria > abs(grad_k)]]
        ]

    energy = None
    if energies:
        energy = energies[-1]

    converged = None
    finished = "Done!" in data
    if "IonicMinimize: Converged" in data:
        converged = True
    elif finished:
        converged = False

    time = None
    if "Duration:" in data:
        time = data[data.find("Duration:"):].split("\n")[0].split("Duration:")[-1].strip()[:-1].split(":")
        # Time should be x-x:yy:zz.zz, thus: [x-x, yy, zz.zz]
        time = float(time[2]) + 60.0 * float(time[1]) + 3600.0 * float(time[0].split("-")[-1])

    data = results.DFT_out(input_file, 'jdftx')

    # data.route = route
    # data.extra_section = extra_section
    # data.charge_and_multiplicity = charge_and_multiplicity.strip()
    data.frames = frames
    data.atoms = atoms
    data.gradients = gradients
    data.energies = energies
    data.energy = energy
    # data.charges_MULLIKEN = charges_MULLIKEN
    # data.charges_LOEWDIN = charges_LOEWDIN
    # data.charges_CHELPG = charges_CHELPG
    # data.charges = copy.deepcopy(charges_MULLIKEN)
    # data.MBO = MBO
    data.convergence = convergence
    data.converged = converged
    data.time = time
    # data.bandgaps = bandgaps
    # data.bandgap = bandgap
    # data.orbitals = orbitals
    data.finished = finished
    # data.warnings = warnings

    return data
Ejemplo n.º 7
0
from squid import orca
from squid import files
from squid import geometry
from squid.calcs import NEB
from squid import structures

if __name__ == "__main__":
    # In this example we will generate the full CNH-HCN isomerization using
    # only squid.  Then we optimize the endpoints in DFT, smooth the frames,
    # and subsequently run NEB

    # Step 1 - Generate the bad initial guess
    print("Step 1 - Generate the bad initial guess...")
    H_coords = [(2, 0), (2, 0.5), (1, 1), (0, 1), (-1, 0.5), (-1, 0)]
    CNH_frames = [[
        structures.Atom("C", 0, 0, 0),
        structures.Atom("N", 1, 0, 0),
        structures.Atom("H", x, y, 0)
    ] for x, y in H_coords]
    # Save initial frames
    files.write_xyz(CNH_frames, "bad_guess.xyz")

    # Step 2 - Optimize the endpoints
    print("Step 2 - Optimize endpoints...")
    frame_start_job = orca.job("frame_start",
                               "! HF-3c Opt",
                               atoms=CNH_frames[0],
                               queue=None)
    frame_last_job = orca.job("frame_last",
                              "! HF-3c Opt",
                              atoms=CNH_frames[-1],
Ejemplo n.º 8
0
def parse_atoms(input_file,
                get_atoms=True,
                get_energy=True,
                check_convergence=True,
                get_time=False,
                counterpoise=False,
                parse_all=False):
    # @input_file [str] : string name of log file

    # Returns: (? energy, ? atoms, ? time) | None
    # @energy [float] : If get_energy or parse_all, otherwise return omitted.
    # @atoms |[atom list] : Iff parse_all, returns atom list list.
    #       |[atom list list] : Iff not parse_all and get_atoms, atom list.
    #                           Otherwise omitted.
    # @time [float] : If get_time returns float (seconds). Otherwise, return
    #                 omitted.

    # Note that None may be returned in the event that Gaussian did not
    # terminate normally (see 7 lines down).

    if input_file[-4:] != '.log':
        input_file = input_file + '.log'
    if not os.path.exists(input_file):
        input_file = "gaussian/" + input_file
    contents = open(input_file).read()
    time = None

    if (check_convergence and get_energy and not parse_all
            and 'Normal termination of Gaussian 09' not in contents):
        return None
    if (('Normal termination of Gaussian 09' in contents)
            and (get_time | parse_all)):
        m = re.search(
            'Job cpu time: +(\S+) +days +(\S+) +hours \
+(\S+) +minutes +(\S+) +seconds', contents)
        try:
            time = float(m.group(1)) * 24 * 60 * 60 +\
                float(m.group(2)) * 60 * 60 +\
                float(m.group(3)) * 60 +\
                float(m.group(4))
        except:
            pass

    if ('Summary of Optimized Potential Surface Scan' in contents
            and not parse_all):
        index = contents.rindex('Summary of Optimized Potential Surface Scan')
        end_section = contents[index:]
        energy_lines = re.findall('Eigenvalues -- ([^\\n]+)', end_section)
        energy = [
            float(s) for line in energy_lines
            for s in re.findall('-[\d]+\.[\d]+', line)
        ]

        minima = re.split('Stationary point found', contents)
        atoms = []
        for m in minima[1:]:
            coordinates = m.index('Coordinates (Angstroms)')

            start = m.index('---\n', coordinates) + 4
            end = m.index('\n ---', start)
            atoms.append([])
            for line in m[start:end].splitlines():
                columns = line.split()
                element = columns[1]
                x, y, z = [float(s) for s in columns[3:6]]
                atoms[-1].append(
                    structures.Atom(element=constants.PERIODIC_TABLE[int(
                        columns[1])]['sym'],
                                    x=x,
                                    y=y,
                                    z=z,
                                    index=len(atoms[-1]) + 1))

        if get_energy:
            return energy, atoms

    elif get_energy and not parse_all:
        if ' MP2/' in contents:
            # MP2 files don't have just SCF energy
            energy = float(
                re.findall('EUMP2 = +(\S+)', contents)[-1].replace('D', 'e'))
        elif ' CCSD/' in contents:
            energy = float(re.findall('E\(CORR\)= +(\S+)', contents)[-1])
        else:
            if not counterpoise:
                try:
                    a = contents.rindex('SCF Done')
                    energy_line = contents[a:contents.index('\n', a)]
                except ValueError:
                    raise Exception('No SCF for ' + input_file)
                energy = float(
                    re.search('SCF Done: +\S+ += +(\S+)',
                              energy_line).group(1))
            else:
                energy = float(
                    re.findall('Counterpoise: corrected energy = +(\S+)',
                               contents)[-1])

    if parse_all:
        energies = []
        atom_frames = []
        start = 0
        orientation = 'Input orientation:'
        while True:
            try:
                # Match energy
                input_orientation = contents.find(orientation, start)
                if input_orientation == -1:
                    orientation = 'Standard orientation'
                    input_orientation = contents.find(orientation, start)
                if input_orientation >= 0:
                    start = input_orientation
                next_coordinates = contents.index('Coordinates (Angstroms)',
                                                  start)
                start = contents.index('SCF Done', start)
                energies.append(
                    float(
                        re.search('SCF Done: +\S+ += +(\S+)',
                                  contents[start:]).group(1)))
            except:
                break
            start = contents.index('---\n', next_coordinates) + 4
            end = contents.index('\n ---', start)
            lines = contents[start:end].splitlines()
            start = end

            atoms = []
            for line in lines:
                columns = line.split()
                element = columns[1]
                x, y, z = columns[3:6]
                atoms.append(
                    structures.Atom(element=element,
                                    x=float(x),
                                    y=float(y),
                                    z=float(z)))
            atom_frames.append(atoms)
        return energies, atom_frames, time

    if get_energy and not get_atoms:
        if get_time:
            return energy, time
        else:
            return energy

    try:
        # Get coordinates
        last_coordinates = contents.rindex('Input orientation:')
        last_coordinates = contents.index('Coordinates (Angstroms)',
                                          last_coordinates)
    except ValueError:
        last_coordinates = contents.rindex('Coordinates (Angstroms)')
    start = contents.index('---\n', last_coordinates) + 4
    end = contents.index('\n ---', start)
    atoms = []
    for line in contents[start:end].splitlines():
        columns = line.split()
        element = columns[1]
        x, y, z = [float(s) for s in columns[3:6]]
        atoms.append(
            structures.Atom(element=constants.PERIODIC_TABLE[int(
                columns[1])]['sym'],
                            x=x,
                            y=y,
                            z=z,
                            index=len(atoms) + 1))

    if 'Forces (Hartrees/Bohr)' in contents:
        # Get forces
        last_forces = contents.rindex('Forces (Hartrees/Bohr)')
        start = contents.index('---\n', last_forces) + 4
        end = contents.index('\n ---', start)
        for i, line in enumerate(contents[start:end].splitlines()):
            columns = line.split()
            read_force = [float(s) for s in columns[2:5]]
            atoms[i].fx, atoms[i].fy, atoms[i].fz = read_force

    # Return the appropriate values
    if get_time:
        if get_atoms:
            return energy, atoms, time
        else:
            return energy, time
    if get_energy:
        return energy, atoms
    else:
        return atoms