Esempio n. 1
0
def loadcon(filein, reset=True):
    '''
    Load a con file
        filein: may be either a filename or a file-like object
    '''
    if hasattr(filein, 'readline'):
        con = filein
    else:
        con = open(filein, 'r')
    con.readline()  # line 1: comment
    con.readline()  # line 2: comment
    # determine how many dimensions
    tmp = numpy.array(con.readline().split())  # line 3: Box lengths
    for i in range(len(tmp)):
        dim = i + 1
        try:
            float(tmp[i])
        except:
            dim = i
            break
    # handle the box
    boxlengths = numpy.zeros(dim)
    for i in range(dim):
        boxlengths[i] = float(tmp[i])
    boxangles = numpy.array([float(f) for f in con.readline().split()[0:dim]
                             ])  # line 4: Box angles
    boxtemp = numpy.zeros((dim, dim), 'd')
    boxtemp = length_angle_to_box(boxlengths, boxangles)
    con.readline()  # line 5: comment
    con.readline()  # line 6: comment
    num_types = int(con.readline().split()[0])  # line 7: number of atom types
    num_each_type = con.readline().split(
    )  # line 8: number of each type of atom
    mass_of_type = con.readline().split()  # line 9: mass of each type of atom
    num_atoms = 0
    for i in range(num_types):
        num_each_type[i] = int(num_each_type[i])
        mass_of_type[i] = float(mass_of_type[i])
        num_atoms += num_each_type[i]
    a = atoms.Atoms(num_atoms)
    a.box = boxtemp
    index = 0
    for i in range(num_types):
        name = con.readline().strip()
        if abs(1.0 - mass_of_type[i]) < 1e-6 and name != "H":
            logger.warning("WARNING: Mass of %s set to 1.0", name)

        con.readline()  # skip meaningless line
        for j in range(num_each_type[i]):
            vals = con.readline().split()
            for k in range(dim):
                a.r[index][k] = float(vals[k])
            a.mass[index] = mass_of_type[i]
            a.names[index] = name
            if not int(vals[dim]) == 0:
                a.free[index] = 0
            index += 1
    if reset:
        con.seek(0)
    return a
Esempio n. 2
0
def loadposcar(filein):
    '''
    Load the POSCAR file named filename and returns an atoms object
    '''
    if hasattr(filein, 'readline'):
        f = filein
    else:
        f = open(filein, 'r')
    # Line 1: Atom types
    AtomTypes = f.readline().split()
    # Line 2: scaling of coordinates
    scale = float(f.readline())
    # Lines 3-5: the box
    box = numpy.zeros((3, 3))
    for i in range(3):
        line = f.readline().split()
        box[i] = numpy.array([float(line[0]),
                              float(line[1]),
                              float(line[2])]) * scale
    # Line 6: number of atoms of each type.
    line = f.readline().split()
    NumAtomsPerType = []
    for l in line:
        NumAtomsPerType.append(int(l))
    # Now have enough info to make the atoms object.
    num_atoms = sum(NumAtomsPerType)
    p = atoms.Atoms(num_atoms)
    # Fill in the box.
    p.box = box
    # Line 7: selective or cartesian
    sel = f.readline()[0]
    selective_flag = (sel == 's' or sel == 'S')
    if not selective_flag:
        car = sel
    else:
        car = f.readline()[0]
    direct_flag = not (car == 'c' or car == 'C' or car == 'k' or car == 'K')
    atom_index = 0
    for i in range(len(NumAtomsPerType)):
        for j in range(NumAtomsPerType[i]):
            p.names[atom_index] = AtomTypes[i]
            line = f.readline().split()
            if (selective_flag):
                assert len(line) >= 6
            else:
                assert len(line) >= 3
            pos = line[0:3]
            if selective_flag:
                sel = line[3:7]
                if sel[0] == 'T' or sel[0] == 't':
                    p.free[atom_index] = 1
                elif sel[0] == 'F' or sel[0] == 'f':
                    p.free[atom_index] = 0
            p.r[atom_index] = numpy.array([float(q) for q in pos])
            if direct_flag:
                p.r[atom_index] = numpy.dot(p.r[atom_index], p.box)
            else:
                p.r[atom_index] *= scale
            atom_index += 1
    return p
Esempio n. 3
0
import pathfix
import io, atoms

confile = sys.argv[1]
xscale = int(sys.argv[2])
yscale = int(sys.argv[3])
zscale = int(sys.argv[4])
try:
    outcon = sys.argv[5]
except:
    outcon = "repeat-" + confile

p0 = io.loadcon(sys.argv[1])

t0 = atoms.Atoms(0)
for x in range(xscale):
    for a in range(len(p0)):
        t0.r = numpy.append(t0.r, [p0.r[a] + p0.box[0] * x], 0)
        t0.free = numpy.append(t0.free, p0.free[a])
        t0.names.append(p0.names[a])
        t0.mass = numpy.append(t0.mass, p0.mass[a])
t1 = atoms.Atoms(0)
for y in range(yscale):
    for a in range(len(t0)):
        t1.r = numpy.append(t1.r, [t0.r[a] + p0.box[1] * y], 0)
        t1.free = numpy.append(t1.free, t0.free[a])
        t1.names.append(t0.names[a])
        t1.mass = numpy.append(t1.mass, t0.mass[a])
t2 = atoms.Atoms(0)
for z in range(zscale):
Esempio n. 4
0
def read_castep_output(castep_file, cluster=None, abort=True):
    """Parse .castep file, and return Atoms object with positions,
      energy, forces, and possibly stress and atomic populations as
      well"""

    opened = False
    if type(castep_file) == type(''):
        opened = True
        castep_file = open(castep_file, 'r')

    castep_output = []

    got_header = False
    while True:
        line = castep_file.readline()
        if line == '': break
        castep_output.append(line)
        if line == ' |      CCC   AA    SSS  TTTTT  EEEEE  PPPP        |\n':
            if got_header:
                break
            else:
                got_header = True

    if opened: castep_file.close()
    # NB: CASTEP doesn't always print 'Total time'
    run_time = -1.0
    if abort:
        total_time = filter(lambda s: s.startswith('Total time'),
                            castep_output)
        if total_time == []:
            has_converged = filter(
                lambda s: s.startswith('Total energy has converged'),
                castep_output)
            if has_converged == []:
                raise ValueError("castep didn't complete")
        else:
            run_time = float(total_time[0].split()[3])

    # Now we should have contents of a valid .castep file in castep_output

    # First let's read the user parameters for this run from top of file
    param = CastepParam()
    param.read_from_castep_output(castep_output)

    # Next let's extract the lattice and atomic positions
    try:
        lattice_line = castep_output.index(
            '                                      Unit Cell\n')
    except:
        raise ValueError('No unit cell found in castep file')

    lattice_lines = castep_output[lattice_line + 3:lattice_line + 6]
    R1 = map(float, lattice_lines[0].split()[0:3])
    R2 = map(float, lattice_lines[1].split()[0:3])
    R3 = map(float, lattice_lines[2].split()[0:3])
    lattice = numpy.array([R1, R2, R3])

    try:
        cell_first_line = castep_output.index(
            '                                     Cell Contents\n')
    except ValueError:
        raise ValueError('No cell contents found in castep file')

    n_atoms = int(castep_output[cell_first_line + 2].split()[-1])

    if cluster is not None:
        # If we were passed in an Atoms object, construct mapping from
        # CASTEP (element, number) to original atom index
        cluster = cluster.copy()
        species_count = {}
        lookup = {}
        for i in range(cluster.n):
            el = cluster.species[i]
            if species_count.has_key(el):
                species_count[el] += 1
            else:
                species_count[el] = 1
            lookup[(el, species_count[el])] = i
    else:
        # Otherwise we make a new, empty Atoms object. Atoms will
        # be ordered as they are in .castep file.
        lookup = {}
        cluster = atoms.Atoms(n=n_atoms, lattice=lattice)

    cluster.params['castep_run_time'] = run_time
    cell_lines = castep_output[cell_first_line + 10:cell_first_line + 10 +
                               n_atoms]

    # Fill in species and fractional positions
    cluster.add_property('frac_pos', 0.0, ncols=3)
    for i, line in enumerate(cell_lines):
        x1, el, num, u, v, w, x2 = line.split()
        num = int(num)
        if not (el, num) in lookup:
            lookup[(el, num)] = i
        cluster.species[lookup[(el, num)]] = el
        cluster.frac_pos[lookup[(el,
                                 num)]] = numpy.array(map(float, (u, v, w)))

    # Calculate cartesian postions from fractional positions
    cluster.pos[:] = numpy.array([
        numpy.dot(cluster.frac_pos[i, :], cluster.lattice)
        for i in range(cluster.n)
    ])

    if ((param.has_key('calculate_stress')
         and param['calculate_stress'].lower() == 'true')
            or (param.has_key('finite_basis_corr')
                and param['finite_basis_corr'].lower() == 'manual')):
        energy_lines = filter(lambda s: s.startswith(' Total energy corrected for finite basis set'), \
                              castep_output)
    elif param.has_key(
            'task') and param['task'].lower() == 'geometryoptimization':
        energy_lines = filter(lambda s: s.startswith(' BFGS: Final Enthalpy'),
                              castep_output)
    else:
        energy_lines = filter(
            lambda s: s.startswith('Final energy') and not s.endswith(
                '<- EDFT\n'), castep_output)

    if (len(energy_lines) == 0):
        if abort:
            raise ValueError('No total energy found in castep file')
    else:
        # Energy is second to last field on line (last is "eV")
        # Use last matching energy line in file
        cluster.params['energy'] = float(energy_lines[-1].split()[-2])

    try:

        for fn in ('Forces', 'Symmetrised Forces'):
            force_start_lines = [
                i for i, s in enumerate(castep_output)
                if s.find('****** %s ******' % fn) != -1
            ]
            if force_start_lines != []: break

        if force_start_lines == []:
            raise ValueError

        # Use last set of forces in file
        force_start = force_start_lines[-1]

        # Extract force lines from .castep file
        force_lines = castep_output[force_start + 6:force_start + 6 +
                                    cluster.n]

        cluster.add_property('force', 0.0, ncols=3)

        # Fill in the forces
        for i, line in enumerate(force_lines):
            line = line.replace('*', '')  # Remove the *s
            el, num_str, fx, fy, fz = line.split()
            num = int(num_str)
            cluster.force[lookup[(el, num)], :] = numpy.array((fx, fy, fz))

    except ValueError, m:
        if abort:
            raise ValueError('No forces found in castep file %s: ' % m)
Esempio n. 5
0
def read_castep_md(md_file, cluster=None, abort=True, first=True):
    """Parse .md file, and return Atoms object with positions,
      energy, forces, and possibly stress and atomic populations as
      well"""

    opened = False
    if type(md_file) == type(''):
        opened = True
        md_file = open(md_file, 'r')

    E_re = re.compile(' E[ ]*$')
    R_re = re.compile(' R[ ]*$')
    V_re = re.compile(' V[ ]*$')
    F_re = re.compile(' F[ ]*$')
    h_re = re.compile(' h[ ]*$')
    in_config = False
    while True:
        line = md_file.readline()
        fields = line.split()
        if (E_re.search(line)):
            if (in_config and first):
                break
            Energy = float(fields[0])
            in_config = True
            R = []
            species = []
            at_num = []
            pos = []
            velo = []
            force = []
            cur_h_line = 0
            cur_R_line = 0
            cur_V_line = 0
            cur_F_line = 0
        if (in_config):
            if (h_re.search(line)):
                cur_h_line += 1
                R.append(map(float, fields[0:3]))
                if (cur_h_line == 3):
                    lattice = numpy.array([R[0], R[1], R[2]])
            if (R_re.search(line)):
                cur_R_line += 1
                pos.append([fields[2], fields[3], fields[3]])
                species.append(fields[0])
                at_num.append(int(fields[1]))
            if (V_re.search(line)):
                cur_V_line += 1
                velo.append([fields[2], fields[3], fields[3]])
            if (F_re.search(line)):
                cur_F_line += 1
                force.append([fields[2], fields[3], fields[3]])

    if cluster is not None:
        # If we were passed in an Atoms object, construct mapping from
        # CASTEP (element, number) to original atom index
        n_atoms = cluster.n
        cluster = cluster.copy()
        species_count = {}
        lookup = {}
        for i in range(cluster.n):
            el = cluster.species[i]
            if species_count.has_key(el):
                species_count[el] += 1
            else:
                species_count[el] = 1
            lookup[(el, species_count[el])] = i
    else:
        # Otherwise we make a new, empty Atoms object. Atoms will
        # be ordered as they are in .castep file.
        lookup = {}
        n_atoms = len(pos)
        cluster = atoms.Atoms(n=n_atoms, lattice=lattice)

    cluster.params['energy'] = Energy
    if (not first):
        cluster.add_property('new_pos', 0.0, ncols=3)
        cluster.add_property('new_velo', 0.0, ncols=3)
    cluster.add_property('force', 0.0, ncols=3)
    for i in range(n_atoms):
        el = species[i]
        num = at_num[i]
        cluster.species[lookup[(el, num)]] = el
        cluster.force[lookup[(el, num)]] = numpy.array(map(float, force[i][:]))
        if (not first):
            cluster.new_pos[lookup[(el,
                                    num)]] = numpy.array(map(float, pos[i][:]))
            cluster.new_velo[lookup[(el, num)]] = numpy.array(
                map(float, velo[i][:]))

    return cluster
Esempio n. 6
0
def read_geom():
    opened = False
    if type(geom) == type(''):
        geom = open(geom, 'r')
        opened = True

    lines = []
    line = geom.readline().strip()

    # Skip header if present
    if line.startswith('BEGIN header'):
        while not line.startswith('END header'):
            line = geom.readline().strip()
        geom.readline()  # skip blank line
    else:
        lines.append(line)

    # Read until next blank line
    while line != '':
        line = geom.readline().strip()
        if line != '': lines.append(line)

    if opened: geom.close()  # Let go of the file

    if len(lines) <= 1:  # Check for EOF
        raise IOError

    params = ParamReader()

    # First line is the time/step
    params['time'] = float(lines[0])

    # Then the energy, in Hartree
    energy_lines = filter(lambda s: s.endswith('<-- E'), lines)
    if len(energy_lines) != 1:
        raise ValueError('Number of energy lines should be exactly one.')

    params['energy'], params['hamiltonian'] = \
                           [float(x)*HARTREE_TO_EV for x in energy_lines[0].split()[0:2]]

    # Lattice is next, in units of Bohr
    lattice_lines = filter(lambda s: s.endswith('<-- h'), lines)
    lattice = numpy.array([[float(x) * BOHR_TO_ANG for x in row[0:3]]
                           for row in map(string.split, lattice_lines)])

    # Then optionally stress tensor (FIXME: units)
    stress_lines = filter(lambda s: s.endswith('<-- S'), lines)
    params['stress'] = numpy.array([[float(x) for x in row[0:3]]
                                    for row in map(string.split, stress_lines)
                                    ])

    # Find positions and forces
    poslines = filter(lambda s: s.endswith('<-- R'), lines)
    forcelines = filter(lambda s: s.endswith('<-- F'), lines)

    if len(poslines) != len(forcelines):
        raise ValueError('Number of pos lines (%d) != force lines (%d)'\
                         % (len(poslines), len(forcelines)))

    result = atoms.Atoms(n=len(poslines), lattice=lattice, params=params)

    # Now parse the positions, converting from units of Bohr
    field_list = [line.split() for line in poslines]
    result.species[:] = numpy.array(map(operator.itemgetter(0), field_list))
    result.pos[:,:] = numpy.array([ [float(x)* BOHR_TO_ANG for x in row] \
                       for row in [field[2:5] for field in field_list]])

    # And finally the forces, which are in units of hartree/bohr
    field_list = [line.split() for line in forcelines]
    force = numpy.array([ [float(x)*HARTREE_TO_EV/BOHR_TO_ANG for x in row] \
                       for row in [field[2:5] for field in field_list]])
    result.add_property('force', force)
    result.force[:] = force

    result.add_property('norm_f', norm(force))

    return result
Esempio n. 7
0
    if 'bcc' in sys.argv:
        ids = atoms.cnat(p, 3.5)
        for i in range(len(ids)):
            if ids[i] == 5:
                rejects.append(i)

    if 'a15' in sys.argv:
        ids = atoms.cnat(p, 3.5)
        for i in range(len(ids)):
            if ids[i] in [1, 2]:
                rejects.append(i)

    rejects = list(set(rejects))

    newp = atoms.Atoms(len(p) - len(rejects))
    newp.box = p.box
    index = 0
    for i in range(len(p)):
        if i not in rejects:
            newp.r[index] = p.r[i]
            newp.free[index] = p.free[i]
            newp.names[index] = p.names[i]
            newp.mass[index] = p.mass[i]
            index += 1
    filtered.append(newp)

io.savecon(sys.argv[2], filtered[0], 'w')

for p in filtered[1:]:
    io.savecon(sys.argv[2], p, 'a')