Ejemplo n.º 1
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
Ejemplo n.º 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
Ejemplo n.º 3
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