Exemple #1
0
def read_ase(aseobject, check_triclinic=False, box_vectors=False):
    """
    Function to read from a ASE atoms objects

    Parameters
    ----------
    aseobject : ASE Atoms object
        name of the ASE atoms object

    triclinic : bool, optional
        True if the configuration is triclinic

    box_vectors : bool, optional
        If true, return the full box vectors along with `boxdims` which gives upper and lower bounds.
        default False.
    """
    #We have to process atoms and atomic objects from ase
    #Known issues lammps -dump modified format
    #first get box
    a = np.array(aseobject.cell[0])
    b = np.array(aseobject.cell[1])
    c = np.array(aseobject.cell[2])

    box = np.array([a, b, c])
    boxdims = np.array([[0, np.sqrt(np.sum(a**2))], [0,
                                                     np.sqrt(np.sum(b**2))],
                        [0, np.sqrt(np.sum(c**2))]])

    #box and box dims are set. Now handle atoms
    chems = np.array(aseobject.get_chemical_symbols())
    atomsymbols = np.unique(aseobject.get_chemical_symbols())
    atomtypes = np.array(range(1, len(atomsymbols) + 1))
    typedict = dict(zip(atomsymbols, atomtypes))

    #now start parsing atoms
    atoms = []
    positions = aseobject.positions
    for count, position in enumerate(positions):
        atom = pca.Atom()
        atom.pos = list(position)
        atom.id = (count + 1)
        atom.type = typedict[chems[count]]
        atom.loc = count

        customdict = {'species': chems[count]}
        atom.custom = customdict
        atoms.append(atom)

    if box_vectors:
        return atoms, boxdims, box
    else:
        return atoms, box
Exemple #2
0
def read_snap(aseobject, check_triclinic=False):
    """
    Function to read from a ASE atoms objects

    Parameters
    ----------
    aseobject : ASE Atoms object
        name of the ASE atoms object

    triclinic : bool, optional
        True if the configuration is triclinic

    """
    #We have to process atoms and atomic objects from ase
    #Known issues lammps -dump modified format
    #first get box
    a = np.array(aseobject.cell[0])
    b = np.array(aseobject.cell[1])
    c = np.array(aseobject.cell[2])

    box = np.array([a, b, c])

    #box and box dims are set. Now handle atoms
    chems = np.array(aseobject.get_chemical_symbols())
    atomsymbols = np.unique(aseobject.get_chemical_symbols())
    atomtypes = np.array(range(1, len(atomsymbols) + 1))
    typedict = dict(zip(atomsymbols, atomtypes))

    #now start parsing atoms
    atoms = []
    positions = aseobject.positions
    for count, position in enumerate(positions):
        atom = pca.Atom()
        atom.pos = list(position)
        atom.id = (count + 1)
        atom.type = typedict[chems[count]]
        atom.loc = count

        customdict = {'species': chems[count]}
        atom.custom = customdict
        atoms.append(atom)

    return atoms, box
Exemple #3
0
def read_snap(mdobject, check_triclinic=False):
    """
    Function to read from an MDTraj atoms objects

    Parameters
    ----------
    mdobject : MDTraj Atoms object
        name of the MDTraj atoms object

    triclinic : bool, optional
        True if the configuration is triclinic

    """
    #We have to process atoms and atomic objects from ase
    #Known issues lammps -dump modified format
    #first get box
    a = np.array(mdobject.unitcell_vectors[0][0])
    b = np.array(mdobject.unitcell_vectors[0][1])
    c = np.array(mdobject.unitcell_vectors[0][2])

    box = np.array([a, b, c])

    #box and box dims are set. Now handle atoms
    chems = np.array([atom.name for atom in mdobject.topology.atoms])
    atomsymbols = np.unique(chems)
    atomtypes = np.array(range(1, len(atomsymbols) + 1))
    typedict = dict(zip(atomsymbols, atomtypes))

    #now start parsing atoms
    atoms = []
    positions = mdobject.xyz[0]
    for count, position in enumerate(positions):
        atom = pca.Atom()
        atom.pos = list(position)
        atom.id = count + 1
        atom.type = typedict[chems[count]]
        atom.loc = count

        customdict = {'species': chems[count]}
        atom.custom = customdict
        atoms.append(atom)

    return atoms, box
Exemple #4
0
def unpickle_atom(atom):
    """
    Get a picklable atom and convert it to a catom
    Parameters
    ----------
    patom : picklable Atom
    Returns
    -------
    catom : A c++ Atom object
    """
    patom = pc.Atom()

    patom.pos = atom.pos
    patom.cluster = atom.cluster
    patom.neighbors = atom.neighbors
    patom.coordination = atom.coordination
    patom.neighbor_weights = atom.neighbor_weights
    patom.bonds = atom.bonds
    patom.id = atom.id
    patom.condition = atom.condition
    patom.solid = atom.solid
    patom.surface = atom.surface
    patom.largest_cluster = atom.largest_cluster
    patom.structure = atom.structure
    patom.loc = atom.loc
    patom.allq = atom.allq
    patom.allaq = atom.allaq
    patom.type = atom.type
    patom.custom = atom.custom
    patom.volume = atom.volume
    patom.avg_volume = atom.avg_volume
    patom.face_vertices = atom.face_vertices
    patom.face_perimeters = atom.face_perimeters
    patom.vertex_numbers = atom.vertex_numbers
    patom.vertex_vectors = atom.vertex_vectors
    patom.edge_lengths = atom.edge_lengths
    patom.vorovector = atom.vorovector
    patom.avg_connection = atom.avg_connection

    return patom
Exemple #5
0
def make_crystal(structure,
                 lattice_constant=1.00,
                 repetitions=None,
                 ca_ratio=1.633):
    """
    Create a basic crystal structure and return it as a list of `Atom` objects
    and box dimensions.

    Parameters
    ----------
    structure : {'bcc', 'fcc', 'hcp', 'diamond'}
        type of the crystal structure

    lattice_constant : float, optional
        lattice constant of the crystal structure, default 1

    repetitions : list of ints of len 3, optional
        of type `[nx, ny, nz]`, repetions of the unit cell in x, y and z directions.
        default `[1, 1, 1]`.

    ca_ratio : float, optional
        ratio of c/a for hcp structures, default 1.633

    Returns
    -------
    atoms : list of `Atom` objects
        list of all atoms as created by user input

    box : list of list of floats
        list of the type `[[xlow, xhigh], [ylow, yhigh], [zlow, zhigh]]` where each of them are the lower
        and upper limits of the simulation box in x, y and z directions respectively.

    Examples
    --------
    >>> atoms, box = make_crystal('bcc', lattice_constant=3.48, repetitions=[2,2,2])
    >>> sys = System()
    >>> sys.assign_atoms(atoms, box)

    """
    if repetitions == None:
        nx = 1
        ny = 1
        nz = 1
    else:
        nx = repetitions[0]
        ny = repetitions[1]
        nz = repetitions[2]

    if structure == 'bcc':

        coord_no = 2
        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcelly[1] = 0.5 * lattice_constant
        unitcellz[1] = 0.5 * lattice_constant

    elif structure == 'fcc':

        coord_no = 4
        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcellz[1] = 0.5 * lattice_constant
        unitcelly[2] = 0.5 * lattice_constant
        unitcellz[2] = 0.5 * lattice_constant
        unitcellx[3] = 0.5 * lattice_constant
        unitcelly[3] = 0.5 * lattice_constant

    elif structure == 'hcp':

        coord_no = 4
        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = np.sqrt(3)
        zfact = ca_ratio

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcelly[1] = 0.5 * lattice_constant * yfact
        unitcellx[2] = 0.5 * lattice_constant
        unitcelly[2] = lattice_constant * (1.0 / 6.0) * yfact
        unitcellz[2] = 0.5 * lattice_constant * zfact
        unitcelly[3] = 2.0 * lattice_constant * (1.0 / yfact)
        unitcellz[3] = 0.5 * lattice_constant * zfact

    elif structure == 'diamond':

        coord_no = 8
        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.25 * lattice_constant
        unitcelly[1] = 0.25 * lattice_constant
        unitcellz[1] = 0.25 * lattice_constant
        unitcellx[2] = 0.50 * lattice_constant
        unitcelly[2] = 0.50 * lattice_constant
        unitcellz[2] = 0.00 * lattice_constant
        unitcellx[3] = 0.75 * lattice_constant
        unitcelly[3] = 0.75 * lattice_constant
        unitcellz[3] = 0.25 * lattice_constant
        unitcellx[4] = 0.50 * lattice_constant
        unitcelly[4] = 0.00 * lattice_constant
        unitcellz[4] = 0.50 * lattice_constant
        unitcellx[5] = 0.00 * lattice_constant
        unitcelly[5] = 0.50 * lattice_constant
        unitcellz[5] = 0.50 * lattice_constant
        unitcellx[6] = 0.75 * lattice_constant
        unitcelly[6] = 0.25 * lattice_constant
        unitcellz[6] = 0.75 * lattice_constant
        unitcellx[7] = 0.25 * lattice_constant
        unitcelly[7] = 0.75 * lattice_constant
        unitcellz[7] = 0.75 * lattice_constant

    m = 0
    co = 1
    atoms = []
    xh = nx * lattice_constant * xfact
    yh = ny * lattice_constant * yfact
    zh = nz * lattice_constant * zfact
    boxdims = [[0, xh], [0, yh], [0, zh]]

    #create structure
    for i in range(1, nx + 1):
        for j in range(1, ny + 1):
            for k in range(1, nz + 1):
                for l in range(1, coord_no + 1):
                    m += 1
                    posx = (unitcellx[l - 1] + (lattice_constant * xfact *
                                                (float(i) - 1)))
                    posy = (unitcelly[l - 1] + (lattice_constant * yfact *
                                                (float(j) - 1)))
                    posz = (unitcellz[l - 1] + (lattice_constant * zfact *
                                                (float(k) - 1)))
                    atom = pc.Atom()
                    atom.pos = [posx, posy, posz]
                    atom.id = co
                    atom.type = 1
                    atom.loc = co - 1
                    atoms.append(atom)
                    co += 1

    return atoms, boxdims
Exemple #6
0
def make_crystal(structure,
                 lattice_constant=1.00,
                 repetitions=None,
                 ca_ratio=1.633,
                 noise=0):
    """
    Create a basic crystal structure and return it as a list of `Atom` objects
    and box dimensions.

    Parameters
    ----------
    structure : {'sc', 'bcc', 'fcc', 'hcp', 'diamond', 'a15' or 'l12'}
        type of the crystal structure

    lattice_constant : float, optional
        lattice constant of the crystal structure, default 1

    repetitions : list of ints of len 3, optional
        of type `[nx, ny, nz]`, repetions of the unit cell in x, y and z directions.
        default `[1, 1, 1]`.

    ca_ratio : float, optional
        ratio of c/a for hcp structures, default 1.633

    noise : float, optional
        If provided add normally distributed noise with standard deviation `noise` to the atomic positions.

    Returns
    -------
    atoms : list of `Atom` objects
        list of all atoms as created by user input

    box : list of list of floats
        list of the type `[[xlow, xhigh], [ylow, yhigh], [zlow, zhigh]]` where each of them are the lower
        and upper limits of the simulation box in x, y and z directions respectively.

    Examples
    --------
    >>> atoms, box = make_crystal('bcc', lattice_constant=3.48, repetitions=[2,2,2])
    >>> sys = System()
    >>> sys.assign_atoms(atoms, box)

    """
    if repetitions == None:
        nx = 1
        ny = 1
        nz = 1
    else:
        nx = repetitions[0]
        ny = repetitions[1]
        nz = repetitions[2]

    #if noise > 0.1:
    #    warnings.warn("Value of noise is rather high. Atom positions might overlap")
    if structure == 'sc':

        coord_no = 1
        atomtype = [
            1,
        ]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)

    elif structure == 'bcc':

        coord_no = 2
        atomtype = [1, 1]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcelly[1] = 0.5 * lattice_constant
        unitcellz[1] = 0.5 * lattice_constant

    elif structure == 'fcc':

        coord_no = 4
        atomtype = [1, 1, 1, 1]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcellz[1] = 0.5 * lattice_constant
        unitcelly[2] = 0.5 * lattice_constant
        unitcellz[2] = 0.5 * lattice_constant
        unitcellx[3] = 0.5 * lattice_constant
        unitcelly[3] = 0.5 * lattice_constant

    elif structure == 'hcp':

        coord_no = 4
        atomtype = [1, 1, 1, 1]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = np.sqrt(3)
        zfact = ca_ratio

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcelly[1] = 0.5 * lattice_constant * yfact
        unitcellx[2] = 0.5 * lattice_constant
        unitcelly[2] = lattice_constant * (1.0 / 6.0) * yfact
        unitcellz[2] = 0.5 * lattice_constant * zfact
        unitcelly[3] = 2.0 * lattice_constant * (1.0 / yfact)
        unitcellz[3] = 0.5 * lattice_constant * zfact

    elif structure == 'diamond':

        coord_no = 8
        atomtype = [1, 1, 1, 1, 1, 1, 1, 1]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.25 * lattice_constant
        unitcelly[1] = 0.25 * lattice_constant
        unitcellz[1] = 0.25 * lattice_constant
        unitcellx[2] = 0.50 * lattice_constant
        unitcelly[2] = 0.50 * lattice_constant
        unitcellz[2] = 0.00 * lattice_constant
        unitcellx[3] = 0.75 * lattice_constant
        unitcelly[3] = 0.75 * lattice_constant
        unitcellz[3] = 0.25 * lattice_constant
        unitcellx[4] = 0.50 * lattice_constant
        unitcelly[4] = 0.00 * lattice_constant
        unitcellz[4] = 0.50 * lattice_constant
        unitcellx[5] = 0.00 * lattice_constant
        unitcelly[5] = 0.50 * lattice_constant
        unitcellz[5] = 0.50 * lattice_constant
        unitcellx[6] = 0.75 * lattice_constant
        unitcelly[6] = 0.25 * lattice_constant
        unitcellz[6] = 0.75 * lattice_constant
        unitcellx[7] = 0.25 * lattice_constant
        unitcelly[7] = 0.75 * lattice_constant
        unitcellz[7] = 0.75 * lattice_constant

    elif structure == 'a15':

        coord_no = 8
        atomtype = [1, 1, 1, 1, 1, 1, 1, 1]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.50 * lattice_constant
        unitcelly[1] = 0.50 * lattice_constant
        unitcellz[1] = 0.50 * lattice_constant
        unitcellx[2] = 0.25 * lattice_constant
        unitcelly[2] = 0.50 * lattice_constant
        unitcellz[2] = 0.00 * lattice_constant
        unitcellx[3] = 0.75 * lattice_constant
        unitcelly[3] = 0.50 * lattice_constant
        unitcellz[3] = 0.00 * lattice_constant
        unitcellx[4] = 0.00 * lattice_constant
        unitcelly[4] = 0.25 * lattice_constant
        unitcellz[4] = 0.50 * lattice_constant
        unitcellx[5] = 0.00 * lattice_constant
        unitcelly[5] = 0.75 * lattice_constant
        unitcellz[5] = 0.50 * lattice_constant
        unitcellx[6] = 0.50 * lattice_constant
        unitcelly[6] = 0.00 * lattice_constant
        unitcellz[6] = 0.25 * lattice_constant
        unitcellx[7] = 0.50 * lattice_constant
        unitcelly[7] = 0.00 * lattice_constant
        unitcellz[7] = 0.75 * lattice_constant

    elif structure == 'l12':

        coord_no = 4
        atomtype = [1, 2, 2, 2]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcellz[1] = 0.5 * lattice_constant
        unitcelly[2] = 0.5 * lattice_constant
        unitcellz[2] = 0.5 * lattice_constant
        unitcellx[3] = 0.5 * lattice_constant
        unitcelly[3] = 0.5 * lattice_constant

    elif structure == 'b2':

        coord_no = 2
        atomtype = [1, 2]

        natoms = coord_no * nx * ny * nz

        xfact = 1.
        yfact = 1.
        zfact = 1.

        unitcellx = np.zeros(coord_no)
        unitcelly = np.zeros(coord_no)
        unitcellz = np.zeros(coord_no)
        unitcellx[1] = 0.5 * lattice_constant
        unitcelly[1] = 0.5 * lattice_constant
        unitcellz[1] = 0.5 * lattice_constant

    else:
        raise ValueError("Unknown crystal structure")

    m = 0
    co = 1
    atoms = []
    xh = nx * lattice_constant * xfact
    yh = ny * lattice_constant * yfact
    zh = nz * lattice_constant * zfact
    box = [[xh, 0, 0], [0, yh, 0], [0, 0, zh]]

    #create structure
    for i in range(1, nx + 1):
        for j in range(1, ny + 1):
            for k in range(1, nz + 1):
                for l in range(1, coord_no + 1):
                    m += 1
                    posx = (unitcellx[l - 1] + (lattice_constant * xfact *
                                                (float(i) - 1)))
                    posy = (unitcelly[l - 1] + (lattice_constant * yfact *
                                                (float(j) - 1)))
                    posz = (unitcellz[l - 1] + (lattice_constant * zfact *
                                                (float(k) - 1)))
                    if noise > 0:
                        posx = np.random.normal(loc=posx, scale=noise)
                        posy = np.random.normal(loc=posy, scale=noise)
                        posz = np.random.normal(loc=posz, scale=noise)
                    atom = pc.Atom()
                    atom.pos = [posx, posy, posz]
                    atom.id = co
                    atom.type = atomtype[l - 1]
                    atom.loc = co - 1
                    atoms.append(atom)
                    co += 1

    return atoms, box
Exemple #7
0
def read_poscar(infile, compressed=False, box_vectors=False):
    """
    Function to read a POSCAR format.

    Parameters
    ----------
    infile : string
        name of the input file

    compressed : bool, optional
        force to read a `gz` zipped file. If the filename ends with `.gz`, use of this keyword is not
        necessary, Default False

    Returns
    -------
    atoms : list of `Atom` objects
        list of all atoms as created by user input

    box : list of list of floats
        list of the type `[[xlow, xhigh], [ylow, yhigh], [zlow, zhigh]]` where each of them are the lower
        and upper limits of the simulation box in x, y and z directions respectively.

    Examples
    --------
    >>> atoms, box = read_poscar('POSCAR')
    >>> atoms, box = read_poscar('POSCAR.gz')
    >>> atoms, box = read_poscar('POSCAR.dat', compressed=True)

    """

    raw = infile.split('.')
    if raw[-1] == 'gz' or compressed:
        f = gzip.open(infile, 'rt')
    else:
        f = open(infile, 'r')

    data = []
    for line in f:
        data.append(line)

    no_atoms = data[5].split()
    nlev = 5

    try:
        no_atoms = np.array(no_atoms)
        no_atoms = no_atoms.astype(int)
    except ValueError:
        no_atoms = data[6].split()
        nlev = 6
        no_atoms = np.array(no_atoms)
        no_atoms = no_atoms.astype(int)
    except:
        raise ValueError("Unknown no of atoms")

    natoms = np.sum(no_atoms)
    atom_list = no_atoms

    scaling_factor = np.array(data[1].strip()).astype(float)
    xvector = np.array(data[2].strip().split()).astype(float)
    yvector = np.array(data[3].strip().split()).astype(float)
    zvector = np.array(data[4].strip().split()).astype(float)
    boxvecs = [xvector, yvector, zvector]

    xlow = 0
    xhigh = scaling_factor * xvector[0]
    ylow = 0
    yhigh = scaling_factor * yvector[1]
    zlow = 0
    zhigh = scaling_factor * zvector[2]
    boxdims = [[xlow, xhigh], [ylow, yhigh], [zlow, zhigh]]

    if (data[nlev + 1].strip().split()[0] == 's'
            or data[nlev + 1].strip().split()[0] == 'S'):
        selective_dynamics = True
        cord_system = data[nlev + 2].strip()
        atom_start = nlev + 3
    else:
        cord_system = data[nlev + 1].strip()
        atom_start = nlev + 2

    if cord_system in ['Cartesian', 'cartesian']:
        xhigh = 1
        yhigh = 1
        zhigh = 1

    species = 1
    count = 0

    cum_list = np.cumsum(atom_list)
    i = atom_start
    atoms = []

    while i in range(atom_start, atom_start + natoms):
        if (count < cum_list[species - 1]):
            raw = np.array(data[i].strip().split()[:3]).astype(float)
            typ = species
            x = float(raw[0]) * xhigh
            y = float(raw[1]) * yhigh
            z = float(raw[2]) * zhigh
            #if x,y,z are out of the box, they need to be put in
            if (x < xlow):
                x = x + (xhigh - xlow)
            elif (x > xhigh):
                x = x - (xhigh - xlow)
            if (y < ylow):
                y = y + (yhigh - ylow)
            elif (y > yhigh):
                y = y - (yhigh - ylow)
            if (z < zlow):
                z = z + (zhigh - zlow)
            elif (z > zhigh):
                z = z - (zhigh - zlow)

            count += 1
            idd = count
            atom = pca.Atom()
            atom.pos = [x, y, z]
            atom.id = idd
            atom.type = typ
            atom.loc = i - atom_start
            #atom = pc.Atom(pos=, id=idd, type=typ)
            atoms.append(atom)
            i += 1
        else:
            species += 1

    if box_vectors:
        return atoms, boxdims, boxvecs
    else:
        return atoms, boxdims
Exemple #8
0
def read_lammps_dump(infile,
                     compressed=False,
                     check_triclinic=False,
                     box_vectors=False,
                     customkeys=None):
    """
    Function to read a lammps dump file format - single time slice.

    Parameters
    ----------
    infile : string
        name of the input file

    compressed : bool, optional
        force to read a `gz` zipped file. If the filename ends with `.gz`, use of this keyword is not
        necessary. Default True.

    check_triclinic : bool, optional
        If true check if the sim box is triclinic. Default False.

    box_vectors : bool, optional
        If true, return the full box vectors along with `boxdims` which gives upper and lower bounds.
        default False.

    customkeys : list of strings, optional
        A list of extra keywords to read from trajectory file.

    Returns
    -------
    atoms : list of `Atom` objects
        list of all atoms as created by user input

    boxdims : list of list of floats
        The dimensions of the box. This is of the form `[[xlo, xhi],[ylo, yhi],[zlo, zhi]]` where `lo` and `hi` are
        the upper and lower bounds of the simulation box along each axes. For triclinic boxes, this is scaled to
        `[0, scalar length of the vector]`.

    box : list of list of floats
        list of the type `[[x1, x2, x3], [y1, y2, y3], [zz1, z2, z3]]` which are the box vectors. Only returned if
        `box_vectors` is set to True.

    triclinic : bool
        True if the box is triclinic. Only returned if `check_triclinic` is set to True

    .. note::

        Values are always returned in the order `atoms, boxdims, box, triclinic` if all
        return keywords are selected. For example, ff `check_triclinic` is not selected, the return
        values would still preserve the order and fall back to  `atoms, boxdims, box`.

    Notes
    -----
    Read a lammps-dump style snapshot that can have variable headers, reads in type and so on.
    Zipped files which end with a `.gz` can also be read automatically. However, if the file does not
    end with a `.gz` extension, keyword `compressed = True` can also be used.

    Examples
    --------
    >>> atoms, box = read_lammps_dump('conf.dump')
    >>> atoms, box = read_lammps_dump('conf.dump.gz')
    >>> atoms, box = read_lammps_dump('conf.d', compressed=True)

    """
    if customkeys == None:
        customkeys = []

    #first depending on if the extension is .gz - use zipped read
    raw = infile.split('.')
    if raw[-1] == 'gz' or compressed:
        f = gzip.open(infile, 'rt')
    else:
        f = open(infile, 'r')

    #now go through the file line by line
    paramsread = False
    atoms = []
    triclinic = False
    volume_fraction = 1.00

    #now if custokeys are provided - read those in too
    customread = False
    customlength = len(customkeys)
    if customlength > 0:
        customread = True

    nblock = 0
    for count, line in enumerate(f):
        #print(count, line)
        if not paramsread:
            #atom numer is at line 3
            if count == 3:
                natoms = int(line.strip())
                nblock = natoms + 9
            #box dims in lines 5,6,7
            elif count == 5:
                raw = line.strip().split()
                boxx = [float(raw[0]), float(raw[1])]
                if len(raw) == 3:
                    xy = float(raw[2])
            elif count == 6:
                raw = line.strip().split()
                boxy = [float(raw[0]), float(raw[1])]
                if len(raw) == 3:
                    xz = float(raw[2])
            elif count == 7:
                raw = line.strip().split()
                boxz = [float(raw[0]), float(raw[1])]
                if len(raw) == 3:
                    yz = float(raw[2])
                    triclinic = True
                    tilts = [xy, xz, yz]
                #boxdims = [boxx, boxy, boxz]

            #header is here
            elif count == 8:
                raw = line.strip().split()
                headerdict = {raw[x]: x - 2 for x in range(0, len(raw))}
                paramsread = True
                if customread:
                    if not np.prod([(x in headerdict) for x in customkeys]):
                        raise KeyError(
                            "some values in custokeys was not found in the file"
                        )
                #add a new keyword for scaled coordinates
                if "x" in headerdict.keys():
                    scaled = False
                elif "xs" in headerdict.keys():
                    scaled = True
                    headerdict["x"] = headerdict.pop("xs")
                    headerdict["y"] = headerdict.pop("ys")
                    headerdict["z"] = headerdict.pop("zs")
                else:
                    raise ValueError(
                        "only x/xs, y/ys andz/zs keys are allowed for traj file"
                    )

        else:
            if count == nblock:
                break
            raw = line.strip().split()
            idd = int(raw[headerdict["id"]])
            typ = int(raw[headerdict["type"]])
            x = float(raw[headerdict["x"]])
            y = float(raw[headerdict["y"]])
            z = float(raw[headerdict["z"]])

            atom = pca.Atom()
            atom.pos = [x, y, z]
            atom.id = idd
            atom.type = typ
            atom.loc = count - 8

            customdict = {}
            #if customkeys need to be read, do it
            if customread:
                for cc, kk in enumerate(customkeys):
                    customdict[kk] = raw[headerdict[kk]]

            atom.custom = customdict
            atoms.append(atom)

    #close files
    f.close()

    if triclinic:
        #process triclinic box
        amin = min([0.0, tilts[0], tilts[1], tilts[0] + tilts[1]])
        amax = max([0.0, tilts[0], tilts[1], tilts[0] + tilts[1]])
        bmin = min([0.0, tilts[2]])
        bmax = max([0.0, tilts[2]])
        xlo = boxx[0] - amin
        xhi = boxx[1] - amax
        ylo = boxy[0] - bmin
        yhi = boxy[1] - bmax
        zlo = boxz[0]
        zhi = boxz[1]

        #triclinic cell
        a = np.array([xhi - xlo, 0, 0])
        b = np.array([tilts[0], yhi - ylo, 0])
        c = np.array([tilts[1], tilts[2], zhi - zlo])

        rot = np.array([a, b, c]).T
        rotinv = np.linalg.inv(rot)
        ortho_origin = np.array([boxx[0], boxy[0], boxz[0]])

        for atom in atoms:
            #correct zero of the atomic positions (shift box to origin)
            dist = np.array(atom.pos) - ortho_origin
            atom.pos = dist

        #finally change boxdims - to triclinic box size
        box = np.array([a, b, c])
        boxdims = np.array([[0, np.sqrt(np.sum(a**2))],
                            [0, np.sqrt(np.sum(b**2))],
                            [0, np.sqrt(np.sum(c**2))]])
    else:
        box = np.array([[boxx[1] - boxx[0], 0, 0], [0, boxy[1] - boxy[0], 0],
                        [0, 0, boxz[1] - boxz[0]]])
        boxdims = np.array([[boxx[0], boxx[1]], [boxy[0], boxy[1]],
                            [boxz[0], boxz[1]]])

    #adjust for scled coordinates
    if scaled:
        for atom in atoms:
            dist = atom.pos
            ndist = dist[0] * box[0] + dist[1] * box[1] + dist[2] * box[2]
            atom.pos = ndist

    if box_vectors and check_triclinic:
        return atoms, boxdims, box, triclinic

    elif box_vectors:
        return atoms, boxdims, box

    elif check_triclinic:
        return atoms, boxdims, triclinic
    else:
        return atoms, boxdims