예제 #1
0
def read_lammps_dump(fileobj, index=-1, order=True):
    """Method which reads a LAMMPS dump file.

    order: Order the particles according to their id. Might be faster to
    switch it off.
    """
    if isinstance(fileobj, str):
        f = paropen(fileobj)
    else:
        f = fileobj

    # load everything into memory
    lines = f.readlines()

    natoms = 0
    images = []

    while len(lines) > natoms:
        line = lines.pop(0)

        if 'ITEM: TIMESTEP' in line:
            n_atoms = 0
            lo = []
            hi = []
            tilt = []
            id = []
            types = []
            positions = []
            scaled_positions = []
            velocities = []
            forces = []
            quaternions = []

        if 'ITEM: NUMBER OF ATOMS' in line:
            line = lines.pop(0)
            natoms = int(line.split()[0])

        if 'ITEM: BOX BOUNDS' in line:
            # save labels behind "ITEM: BOX BOUNDS" in
            # triclinic case (>=lammps-7Jul09)
            tilt_items = line.split()[3:]
            for i in range(3):
                line = lines.pop(0)
                fields = line.split()
                lo.append(float(fields[0]))
                hi.append(float(fields[1]))
                if (len(fields) >= 3):
                    tilt.append(float(fields[2]))

            # determine cell tilt (triclinic case!)
            if (len(tilt) >= 3):
                # for >=lammps-7Jul09 use labels behind
                # "ITEM: BOX BOUNDS" to assign tilt (vector) elements ...
                if (len(tilt_items) >= 3):
                    xy = tilt[tilt_items.index('xy')]
                    xz = tilt[tilt_items.index('xz')]
                    yz = tilt[tilt_items.index('yz')]
                # ... otherwise assume default order in 3rd column
                # (if the latter was present)
                else:
                    xy = tilt[0]
                    xz = tilt[1]
                    yz = tilt[2]
            else:
                xy = xz = yz = 0
            xhilo = (hi[0] - lo[0]) - (xy**2)**0.5 - (xz**2)**0.5
            yhilo = (hi[1] - lo[1]) - (yz**2)**0.5
            zhilo = (hi[2] - lo[2])
            if xy < 0:
                if xz < 0:
                    celldispx = lo[0] - xy - xz
                else:
                    celldispx = lo[0] - xy
            else:
                celldispx = lo[0]
            celldispy = lo[1]
            celldispz = lo[2]

            cell = [[xhilo, 0, 0], [xy, yhilo, 0], [xz, yz, zhilo]]
            celldisp = [[celldispx, celldispy, celldispz]]

        def add_quantity(fields, var, labels):
            for label in labels:
                if label not in atom_attributes:
                    return
            var.append(
                [float(fields[atom_attributes[label]]) for label in labels])

        if 'ITEM: ATOMS' in line:
            # (reliably) identify values by labels behind
            # "ITEM: ATOMS" - requires >=lammps-7Jul09
            # create corresponding index dictionary before
            # iterating over atoms to (hopefully) speed up lookups...
            atom_attributes = {}
            for (i, x) in enumerate(line.split()[2:]):
                atom_attributes[x] = i
            for n in range(natoms):
                line = lines.pop(0)
                fields = line.split()
                id.append(int(fields[atom_attributes['id']]))
                types.append(int(fields[atom_attributes['type']]))
                add_quantity(fields, positions, ['x', 'y', 'z'])
                add_quantity(fields, scaled_positions, ['xs', 'ys', 'zs'])
                add_quantity(fields, velocities, ['vx', 'vy', 'vz'])
                add_quantity(fields, forces, ['fx', 'fy', 'fz'])
                add_quantity(fields, quaternions,
                             ['c_q[1]', 'c_q[2]', 'c_q[3]', 'c_q[4]'])

            if order:

                def reorder(inlist):
                    if not len(inlist):
                        return inlist
                    outlist = [None] * len(id)
                    for i, v in zip(id, inlist):
                        outlist[i - 1] = v
                    return outlist

                types = reorder(types)
                positions = reorder(positions)
                scaled_positions = reorder(scaled_positions)
                velocities = reorder(velocities)
                forces = reorder(forces)
                quaternions = reorder(quaternions)

            if len(quaternions):
                images.append(
                    Quaternions(symbols=types,
                                positions=positions,
                                cell=cell,
                                celldisp=celldisp,
                                quaternions=quaternions))
            elif len(positions):
                images.append(
                    Atoms(symbols=types,
                          positions=positions,
                          celldisp=celldisp,
                          cell=cell))
            elif len(scaled_positions):
                images.append(
                    Atoms(symbols=types,
                          scaled_positions=scaled_positions,
                          celldisp=celldisp,
                          cell=cell))

            if len(velocities):
                images[-1].set_velocities(velocities)
            if len(forces):
                calculator = SinglePointCalculator(0.0, forces, None, None,
                                                   images[-1])
                images[-1].set_calculator(calculator)

    return images[index]
예제 #2
0
def lammps_data_to_ase_atoms(
    data,
    colnames,
    cell,
    celldisp,
    pbc=False,
    atomsobj=Atoms,
    order=True,
    specorder=None,
    prismobj=None,
    units="metal",
):
    """Extract positions and other per-atom parameters and create Atoms

    :param data: per atom data
    :param colnames: index for data
    :param cell: cell dimensions
    :param celldisp: origin shift
    :param pbc: periodic boundaries
    :param atomsobj: function to create ase-Atoms object
    :param order: sort atoms by id. Might be faster to turn off
    :param specorder: list of species to map lammps types to ase-species
    (usually .dump files to not contain type to species mapping)
    :param prismobj: Coordinate transformation between lammps and ase
    :type prismobj: Prism
    :param units: lammps units for unit transformation between lammps and ase
    :returns: Atoms object
    :rtype: Atoms

    """
    # data array of doubles
    ids = data[:, colnames.index("id")].astype(int)
    types = data[:, colnames.index("type")].astype(int)
    if order:
        sort_order = np.argsort(ids)
        ids = ids[sort_order]
        data = data[sort_order, :]
        types = types[sort_order]

    # reconstruct types from given specorder
    if specorder:
        types = [specorder[t - 1] for t in types]

    def get_quantity(labels, quantity=None):
        try:
            cols = [colnames.index(label) for label in labels]
            if quantity:
                return convert(data[:, cols], quantity, units, "ASE")

            return data[:, cols]
        except ValueError:
            return None

    # slice data block into columns
    # + perform necessary conversions to ASE units
    positions = get_quantity(["x", "y", "z"], "distance")
    scaled_positions = get_quantity(["xs", "ys", "zs"])
    velocities = get_quantity(["vx", "vy", "vz"], "velocity")
    charges = get_quantity(["q"], "charge")
    forces = get_quantity(["fx", "fy", "fz"], "force")
    # !TODO: how need quaternions be converted?
    quaternions = get_quantity(["c_q[1]", "c_q[2]", "c_q[3]", "c_q[4]"])

    # convert cell
    cell = convert(cell, "distance", units, "ASE")
    celldisp = convert(celldisp, "distance", units, "ASE")
    if prismobj:
        celldisp = prismobj.vector_to_ase(celldisp)
        cell = prismobj.update_cell(cell)

    if quaternions:
        out_atoms = Quaternions(
            symbols=types,
            positions=positions,
            cell=cell,
            celldisp=celldisp,
            pbc=pbc,
            quaternions=quaternions,
        )
    elif positions is not None:
        # reverse coordinations transform to lammps system
        # (for all vectors = pos, vel, force)
        if prismobj:
            positions = prismobj.vector_to_ase(positions, wrap=True)

        out_atoms = atomsobj(
            symbols=types,
            positions=positions,
            pbc=pbc,
            celldisp=celldisp,
            cell=cell
        )
    elif scaled_positions is not None:
        out_atoms = atomsobj(
            symbols=types,
            scaled_positions=scaled_positions,
            pbc=pbc,
            celldisp=celldisp,
            cell=cell,
        )

    if velocities is not None:
        if prismobj:
            velocities = prismobj.vector_to_ase(velocities)
        out_atoms.set_velocities(velocities)
    if charges is not None:
        out_atoms.set_initial_charges(charges)
    if forces is not None:
        if prismobj:
            forces = prismobj.vector_to_ase(forces)
        # !TODO: use another calculator if available (or move forces
        #        to atoms.property) (other problem: synchronizing
        #        parallel runs)
        calculator = SinglePointCalculator(out_atoms, energy=0.0, forces=forces)
        out_atoms.calc = calculator

    # process the extra columns of fixes, variables and computes
    #    that can be dumped, add as additional arrays to atoms object
    for colname in colnames:
        # determine if it is a compute or fix (but not the quaternian)
        if (colname.startswith('f_') or colname.startswith('v_') or
                (colname.startswith('c_') and not colname.startswith('c_q['))):
            out_atoms.new_array(colname, get_quantity([colname]), dtype='float')

    return out_atoms
예제 #3
0
    def read_a_loop(f):
        ## Time step
        line = f.readline()
        assert 'ITEM: TIMESTEP' in line
        lo = []
        hi = []
        tilt = []
        id = []
        types = []
        positions = []
        element = []  ## ssrokyz
        pe = []  ## ssrokyz
        scaled_positions = []
        velocities = []
        forces = []
        quaternions = []
        # Read out timestep
        line = f.readline()

        ## Number of atoms
        line = f.readline()
        assert 'ITEM: NUMBER OF ATOMS' in line
        line = f.readline()
        natoms = int(line.split()[0])

        ## Box bounds
        line = f.readline()
        assert 'ITEM: BOX BOUNDS' in line
        # save labels behind "ITEM: BOX BOUNDS" in
        # triclinic case (>=lammps-7Jul09)
        tilt_items = line.split()[3:]
        for i in range(3):
            line = f.readline()
            fields = line.split()
            lo.append(float(fields[0]))
            hi.append(float(fields[1]))
            if (len(fields) >= 3):
                tilt.append(float(fields[2]))

        # determine cell tilt (triclinic case!)
        if (len(tilt) >= 3):
            # for >=lammps-7Jul09 use labels behind
            # "ITEM: BOX BOUNDS" to assign tilt (vector) elements ...
            if (len(tilt_items) >= 3):
                xy = tilt[tilt_items.index('xy')]
                xz = tilt[tilt_items.index('xz')]
                yz = tilt[tilt_items.index('yz')]
            # ... otherwise assume default order in 3rd column
            # (if the latter was present)
            else:
                xy = tilt[0]
                xz = tilt[1]
                yz = tilt[2]
        else:
            xy = xz = yz = 0
        xhilo = (hi[0] - lo[0]) - (xy**2)**0.5 - (xz**2)**0.5
        yhilo = (hi[1] - lo[1]) - (yz**2)**0.5
        zhilo = (hi[2] - lo[2])
        if xy < 0:
            if xz < 0:
                celldispx = lo[0] - xy - xz
            else:
                celldispx = lo[0] - xy
        else:
            celldispx = lo[0]
        celldispy = lo[1]
        celldispz = lo[2]

        cell = [[xhilo, 0, 0], [xy, yhilo, 0], [xz, yz, zhilo]]
        celldisp = [[celldispx, celldispy, celldispz]]

        line = f.readline()
        assert 'ITEM: ATOMS' in line
        # (reliably) identify values by labels behind
        # "ITEM: ATOMS" - requires >=lammps-7Jul09
        # create corresponding index dictionary before
        # iterating over atoms to (hopefully) speed up lookups...
        atom_attributes = {}
        for (i, x) in enumerate(line.split()[2:]):
            atom_attributes[x] = i
        for n in range(natoms):
            line = f.readline()
            fields = line.split()
            id.append(int(fields[atom_attributes['id']]))
            types.append(int(fields[atom_attributes['type']]))
            element.append(str(fields[atom_attributes['element']]))  ## ssrokyz
            pe.append(float(fields[atom_attributes['c_1']]))  ## ssrokyz
            add_quantity(fields, positions, ['x', 'y', 'z'], atom_attributes)
            add_quantity(fields, scaled_positions, ['xs', 'ys', 'zs'],
                         atom_attributes)
            add_quantity(fields, velocities, ['vx', 'vy', 'vz'],
                         atom_attributes)
            add_quantity(fields, forces, ['fx', 'fy', 'fz'], atom_attributes)
            add_quantity(fields, quaternions,
                         ['c_q[1]', 'c_q[2]', 'c_q[3]', 'c_q[4]'],
                         atom_attributes)

        if order:
            types = reorder(types, id)
            element = reorder(element, id)  ## ssrokyz
            pe = reorder(pe, id)  ## ssrokyz
            positions = reorder(positions, id)
            scaled_positions = reorder(scaled_positions, id)
            velocities = reorder(
                np.array(velocities) / units.fs / 1e3, id
            )  ## ssrokyz ## lammps metal unit: Ang./picosec ## units.fs *1e3 = units.ps
            forces = reorder(forces, id)
            quaternions = reorder(quaternions, id)

        ## Make 'Atoms' object
        if len(quaternions):
            atoms = Quaternions(
                symbols=element,
                positions=positions,
                cell=cell,
                celldisp=celldisp,
                quaternions=quaternions,
            )
        elif len(positions):
            atoms = atomsobj(
                symbols=element,
                positions=positions,
                celldisp=celldisp,
                cell=cell,
            )
        elif len(scaled_positions):
            atoms = atomsobj(
                symbols=element,
                scaled_positions=scaled_positions,
                celldisp=celldisp,
                cell=cell,
            )
        if len(velocities):
            atoms.set_velocities(velocities)
        if len(forces):
            calculator = SinglePointCalculator(atoms,
                                               energy=0.0,
                                               forces=forces)
            atoms.set_calculator(calculator)
        if len(pe):
            atoms._calc.results['atomic_energies'] = pe
        return atoms
예제 #4
0
파일: lammps.py 프로젝트: lqcata/ase
def read_lammps_dump(fileobj, index=-1):
    """Method which reads a LAMMPS dump file."""
    if isinstance(fileobj, str):
        f = paropen(fileobj)
    else:
        f = fileobj

    # load everything into memory
    lines = f.readlines()

    natoms = 0
    images = []

    while len(lines) > natoms:
        line = lines.pop(0)

        if 'ITEM: TIMESTEP' in line:
            n_atoms = 0
            lo = [] ; hi = [] ; tilt = []
            id = [] ; type = []
            positions = []
            velocities = [] 
            forces = []
            quaternions = []

        if 'ITEM: NUMBER OF ATOMS' in line:
            line = lines.pop(0)
            natoms = int(line.split()[0])
            
        if 'ITEM: BOX BOUNDS' in line:
            # save labels behind "ITEM: BOX BOUNDS" in triclinic case (>=lammps-7Jul09)
            tilt_items = line.split()[3:]
            for i in range(3):
                line = lines.pop(0)
                fields = line.split()
                lo.append(float(fields[0]))
                hi.append(float(fields[1]))
                if (len(fields) >= 3):
                    tilt.append(float(fields[2]))

            # determine cell tilt (triclinic case!)
            if (len(tilt) >= 3):
                # for >=lammps-7Jul09 use labels behind "ITEM: BOX BOUNDS" to assign tilt (vector) elements ...
                if (len(tilt_items) >= 3):
                    xy = tilt[tilt_items.index('xy')]
                    xz = tilt[tilt_items.index('xz')]
                    yz = tilt[tilt_items.index('yz')]
                # ... otherwise assume default order in 3rd column (if the latter was present)
                else:
                    xy = tilt[0]
                    xz = tilt[1]
                    yz = tilt[2]
            else:
                xy = xz = yz = 0
            xhilo = (hi[0] - lo[0]) - xy - xz
            yhilo = (hi[1] - lo[1]) - yz
            zhilo = (hi[2] - lo[2])

            cell = [[xhilo,0,0],[xy,yhilo,0],[xz,yz,zhilo]]

        def add_quantity(fields, var, labels):
            for label in labels:
                if label not in atom_attributes:
                    return
            var.append([float(fields[atom_attributes[label]])
                        for label in labels])
                
        if 'ITEM: ATOMS' in line:
            # (reliably) identify values by labels behind "ITEM: ATOMS" - requires >=lammps-7Jul09
            # create corresponding index dictionary before iterating over atoms to (hopefully) speed up lookups...
            atom_attributes = {}
            for (i, x) in enumerate(line.split()[2:]):
                atom_attributes[x] = i
            for n in range(natoms):
                line = lines.pop(0)
                fields = line.split()
                id.append( int(fields[atom_attributes['id']]) )
                type.append( int(fields[atom_attributes['type']]) )
                add_quantity(fields, positions, ['x', 'y', 'z'])
                add_quantity(fields, velocities, ['vx', 'vy', 'vz'])
                add_quantity(fields, forces, ['fx', 'fy', 'fz'])
                add_quantity(fields, quaternions, ['c_q[1]', 'c_q[2]',
                                                   'c_q[3]', 'c_q[4]'])

            if len(quaternions):
                images.append(Quaternions(symbols=type,
                                          positions=positions,
                                          cell=cell,
                                          quaternions=quaternions))
            else:
                images.append(Atoms(symbols=type,
                                    positions=positions,
                                    cell=cell))

    return images[index]
예제 #5
0
def lammps_data_to_ase_atoms(
    data,
    colnames,
    cell,
    celldisp,
    pbc=False,
    atomsobj=Atoms,
    order=True,
    specorder=None,
    prismobj=None,
    units="metal",
):
    """Extract positions and other per-atom parameters and create Atoms

    :param data: per atom data
    :param colnames: index for data
    :param cell: cell dimensions
    :param celldisp: origin shift
    :param pbc: periodic boundaries
    :param atomsobj: function to create ase-Atoms object
    :param order: sort atoms by id. Might be faster to turn off.
    Disregarded in case `id` column is not given in file.
    :param specorder: list of species to map lammps types to ase-species
    (usually .dump files to not contain type to species mapping)
    :param prismobj: Coordinate transformation between lammps and ase
    :type prismobj: Prism
    :param units: lammps units for unit transformation between lammps and ase
    :returns: Atoms object
    :rtype: Atoms

    """

    # read IDs if given and order if needed
    if "id" in colnames:
        ids = data[:, colnames.index("id")].astype(int)
        if order:
            sort_order = np.argsort(ids)
            data = data[sort_order, :]

    # determine the elements
    if "element" in colnames:
        # priority to elements written in file
        elements = data[:, colnames.index("element")]
    elif "type" in colnames:
        # fall back to `types` otherwise
        elements = data[:, colnames.index("type")].astype(int)

        # reconstruct types from given specorder
        if specorder:
            elements = [specorder[t - 1] for t in elements]
    else:
        # todo: what if specorder give but no types?
        # in principle the masses could work for atoms, but that needs
        # lots of cases and new code I guess
        raise ValueError("Cannot determine atom types form LAMMPS dump file")

    def get_quantity(labels, quantity=None):
        try:
            cols = [colnames.index(label) for label in labels]
            if quantity:
                return convert(data[:, cols].astype(float), quantity, units,
                               "ASE")

            return data[:, cols].astype(float)
        except ValueError:
            return None

    # Positions
    positions = None
    scaled_positions = None
    if "x" in colnames:
        # doc: x, y, z = unscaled atom coordinates
        positions = get_quantity(["x", "y", "z"], "distance")
    elif "xs" in colnames:
        # doc: xs,ys,zs = scaled atom coordinates
        scaled_positions = get_quantity(["xs", "ys", "zs"])
    elif "xu" in colnames:
        # doc: xu,yu,zu = unwrapped atom coordinates
        positions = get_quantity(["xu", "yu", "zu"], "distance")
    elif "xsu" in colnames:
        # xsu,ysu,zsu = scaled unwrapped atom coordinates
        scaled_positions = get_quantity(["xsu", "ysu", "zsu"])
    else:
        raise ValueError("No atomic positions found in LAMMPS output")

    velocities = get_quantity(["vx", "vy", "vz"], "velocity")
    charges = get_quantity(["q"], "charge")
    forces = get_quantity(["fx", "fy", "fz"], "force")
    # !TODO: how need quaternions be converted?
    quaternions = get_quantity(["c_q[1]", "c_q[2]", "c_q[3]", "c_q[4]"])

    # convert cell
    cell = convert(cell, "distance", units, "ASE")
    celldisp = convert(celldisp, "distance", units, "ASE")
    if prismobj:
        celldisp = prismobj.vector_to_ase(celldisp)
        cell = prismobj.update_cell(cell)

    if quaternions:
        out_atoms = Quaternions(
            symbols=elements,
            positions=positions,
            cell=cell,
            celldisp=celldisp,
            pbc=pbc,
            quaternions=quaternions,
        )
    elif positions is not None:
        # reverse coordinations transform to lammps system
        # (for all vectors = pos, vel, force)
        if prismobj:
            positions = prismobj.vector_to_ase(positions, wrap=True)

        out_atoms = atomsobj(symbols=elements,
                             positions=positions,
                             pbc=pbc,
                             celldisp=celldisp,
                             cell=cell)
    elif scaled_positions is not None:
        out_atoms = atomsobj(
            symbols=elements,
            scaled_positions=scaled_positions,
            pbc=pbc,
            celldisp=celldisp,
            cell=cell,
        )

    if velocities is not None:
        if prismobj:
            velocities = prismobj.vector_to_ase(velocities)
        out_atoms.set_velocities(velocities)
    if charges is not None:
        out_atoms.set_initial_charges(charges)
    if forces is not None:
        if prismobj:
            forces = prismobj.vector_to_ase(forces)
        # !TODO: use another calculator if available (or move forces
        #        to atoms.property) (other problem: synchronizing
        #        parallel runs)
        calculator = SinglePointCalculator(out_atoms,
                                           energy=0.0,
                                           forces=forces)
        out_atoms.calc = calculator

    # process the extra columns of fixes, variables and computes
    #    that can be dumped, add as additional arrays to atoms object
    for colname in colnames:
        # determine if it is a compute or fix (but not the quaternian)
        if (colname.startswith('f_') or colname.startswith('v_') or
            (colname.startswith('c_') and not colname.startswith('c_q['))):
            out_atoms.new_array(colname,
                                get_quantity([colname]),
                                dtype='float')

    return out_atoms