Ejemplo n.º 1
0
def generate_random_perovskite(lat=None):
    '''
    This generates a random valid perovskite structure in ASE format.
    Useful for testing.
    Binary and organic perovskites are not considered.
    '''
    if not lat:
        lat = round(random.uniform(3.5, Perovskite_tilting.OCTAHEDRON_BOND_LENGTH_LIMIT*2), 3)
    A_site = random.choice(Perovskite_Structure.A)
    B_site = random.choice(Perovskite_Structure.B)
    Ci_site = random.choice(Perovskite_Structure.C)
    Cii_site = random.choice(Perovskite_Structure.C)

    while covalent_radii[chemical_symbols.index(A_site)] - \
        covalent_radii[chemical_symbols.index(B_site)] < 0.05 or \
        covalent_radii[chemical_symbols.index(A_site)] - \
        covalent_radii[chemical_symbols.index(B_site)] > 0.5:

        A_site = random.choice(Perovskite_Structure.A)
        B_site = random.choice(Perovskite_Structure.B)

    return crystal(
        [A_site, B_site, Ci_site, Cii_site],
        [(0.5, 0.25, 0.0), (0.0, 0.0, 0.0), (0.0, 0.25, 0.0), (0.25, 0.0, 0.75)],
        spacegroup=62, cellpar=[lat*math.sqrt(2), 2*lat, lat*math.sqrt(2), 90, 90, 90]
    )
Ejemplo n.º 2
0
def analyse_all_bonds(model, verbose=True, abnormal=True):
    '''
    Analyse bonds and return all abnormal bond types and list of these
    TODO: Make this more bullet proof - what happens if abnormal bonds aren't requested.
    A table of bond distance analysis for the supplied model is also possible

    Parameters:

    model: Atoms object
        Structure for which the analysis is to be conducted
    verbose: Boolean
        Determines whether the output should be printed to screen
    abnormal: Boolean
        Collect information about rogue looking bond lengths.
        (Does enabling this by default add a large time overhead?)
    '''

    # set() to ensure unique chemical symbols list
    list_of_symbols = list(set(model.get_chemical_symbols()))
    # Combination as AB = BA for bonds, avoiding redundancy
    from itertools import combinations_with_replacement
    all_bonds = combinations_with_replacement(list_of_symbols, 2)

    # Define lists to collect abnormal observations
    abnormal_bonds = []
    list_of_abnormal_bonds = []

    # Table heading
    if verbose:
        print_bond_table_header()

    from ase.data import chemical_symbols, covalent_radii
    # Iterate over all arrangements of chemical symbols
    for bonds in all_bonds:
        print_AB, AB_Bonds, AB_BondsValues = analyse_bonds(model,
                                                           bonds[0],
                                                           bonds[1],
                                                           verbose=verbose,
                                                           multirow=True)

        if abnormal and AB_BondsValues is not None:
            sum_of_covalent_radii = covalent_radii[chemical_symbols.index(
                bonds[0])] + covalent_radii[chemical_symbols.index(bonds[1])]
            abnormal_cutoff = max(0.4, sum_of_covalent_radii * 0.75)

            for values in AB_BondsValues:
                abnormal_values = [i for i in values if i < abnormal_cutoff]
                if len(abnormal_values):
                    abnormal_bonds.append(len(abnormal_values))
                    list_of_abnormal_bonds.append(print_AB)

    # This now returns empty arrays if no abnormal bond checks are done,
    # or if genuinely there are no abnormal bonds.
    return abnormal_bonds, list_of_abnormal_bonds
Ejemplo n.º 3
0
    def build_central_rdf(self, nbins=5, pcty=False):
        atoms = self.build_atoms_obj().copy()

        # center atoms at origin (COP)
        atoms.positions -= atoms.positions.mean(0)

        # calculate distances from origin
        dists = np.linalg.norm(atoms.positions, axis=1)

        # calculate distances from COP for each metal type
        dist_m1 = dists[atoms.symbols == self.metal1]
        dist_m2 = dists[atoms.symbols == self.metal2]

        fig, ax = plt.subplots()

        # get jmol color for each metal
        m1_color = jmol_colors[chemical_symbols.index(self.metal1)]
        m2_color = jmol_colors[chemical_symbols.index(self.metal2)]

        # set nbins to num shells if not given
        if not nbins:
            nbins = self.nanoparticle.num_shells

        counts_m1, bin_edges = np.histogram(dist_m1, bins=nbins)
        counts_m2, bin_edges = np.histogram(dist_m2, bins=nbins)

        # get bins for ax.hist
        bins = np.linspace(0, dists.max(), nbins + 1)

        x = (bin_edges[1:] + bin_edges[:-1]) / 2
        ax.plot(x,
                counts_m1,
                'o-',
                markeredgecolor='k',
                color=m1_color,
                markersize=8,
                label=self.metal1)
        ax.plot(x,
                counts_m2,
                'o-',
                markeredgecolor='k',
                color=m2_color,
                markersize=8,
                label=self.metal2)

        ax.set_xlabel('Distance from Core ($\\rm \\AA$)')
        ax.set_ylabel('Number of Atoms')
        ax.legend()
        fig.tight_layout()
        plt.show()
        return fig
Ejemplo n.º 4
0
    def get_checksum(self):
        '''
        Retrieve unique hash in a cross-platform manner:
        this is how calculation identity is determined
        '''
        if self._checksum:
            return self._checksum

        if not self._filename:
            raise RuntimeError('Source calc file is required in order to properly save the data!')

        calc_checksum = hashlib.sha224()
        struc_repr = ""
        for ase_obj in self.structures:
            struc_repr += "%3.6f %3.6f %3.6f %3.6f %3.6f %3.6f %3.6f %3.6f %3.6f " % tuple(map(abs, [ase_obj.cell[0][0], ase_obj.cell[0][1], ase_obj.cell[0][2], ase_obj.cell[1][0], ase_obj.cell[1][1], ase_obj.cell[1][2], ase_obj.cell[2][0], ase_obj.cell[2][1], ase_obj.cell[2][2]])) # NB beware of length & minus zeros

            for atom in ase_obj:
                struc_repr += "%s %3.6f %3.6f %3.6f " % tuple(map(abs, [chemical_symbols.index(atom.symbol), atom.x, atom.y, atom.z])) # NB beware of length & minus zeros

        if self.info["energy"] is None:
            energy = str(None)
        else:
            energy = str(round(self.info['energy'], 11 - int(math.log10(math.fabs(self.info['energy'])))))

        calc_checksum.update((
            struc_repr + "\n" +
            energy + "\n" +
            self.info['prog'] + "\n" +
            str(self.info['input']) + "\n" +
            str(sum([2**x for x in self.info['calctypes']]))
        ).encode('ascii')) # NB this is fixed and should not be changed

        result = base64.b32encode(calc_checksum.digest()).decode('ascii')
        result = result[:result.index('=')] + 'CI'
        return result
Ejemplo n.º 5
0
def write_lammps_data(filename,
                      atoms,
                      atom_types,
                      comment=None,
                      cutoff=None,
                      molecule_ids=None,
                      charges=None,
                      units='metal'):

    if isinstance(filename, str):
        fh = open(filename, 'w')
    else:
        fh = filename

    if comment is None:
        comment = 'lammpslib autogenerated data file'
    fh.write(comment.strip() + '\n\n')

    fh.write('{0} atoms\n'.format(len(atoms)))
    fh.write('{0} atom types\n'.format(len(atom_types)))

    fh.write('\n')
    cell, coord_transform = convert_cell(atoms.get_cell())
    fh.write('{0:16.8e} {1:16.8e} xlo xhi\n'.format(0.0, cell[0, 0]))
    fh.write('{0:16.8e} {1:16.8e} ylo yhi\n'.format(0.0, cell[1, 1]))
    fh.write('{0:16.8e} {1:16.8e} zlo zhi\n'.format(0.0, cell[2, 2]))
    fh.write('{0:16.8e} {1:16.8e} {2:16.8e} xy xz yz\n'
             ''.format(cell[0, 1], cell[0, 2], cell[1, 2]))

    fh.write('\nMasses\n\n')
    sym_mass = {}
    masses = atoms.get_masses()
    symbols = atoms.get_chemical_symbols()
    for sym in atom_types:
        for i in range(len(atoms)):  # TODO: Make this more efficient
            if symbols[i] == sym:
                sym_mass[sym] = convert(masses[i], "mass", "ASE", units)
                break
            else:
                sym_mass[sym] = convert(
                    ase_atomic_masses[ase_chemical_symbols.index(sym)], "mass",
                    "ASE", units)

    for (sym, typ) in sorted(atom_types.items(), key=operator.itemgetter(1)):
        fh.write('{0} {1}\n'.format(typ, sym_mass[sym]))

    fh.write('\nAtoms # full\n\n')
    if molecule_ids is None:
        molecule_ids = np.zeros(len(atoms), dtype=int)
    if charges is None:
        charges = atoms.get_initial_charges()
    for i, (sym, mol, q, pos) in enumerate(
            zip(symbols, molecule_ids, charges, atoms.get_positions())):
        typ = atom_types[sym]
        fh.write(
            '{0} {1} {2} {3:16.8e} {4:16.8e} {5:16.8e} {6:16.8e}\n'.format(
                i + 1, mol, typ, q, pos[0], pos[1], pos[2]))

    if isinstance(filename, str):
        fh.close()
Ejemplo n.º 6
0
def get_atom_kinds(atoms, props={}):
    # symbols = atoms.symbols
    # formula = atoms.symbols.formula
    # atom_kinds = formula.count()
    if hasattr(atoms, 'kinds'):
        kinds = list(set(atoms.kinds))
    else:
        atoms.kinds = atoms.get_chemical_symbols()
        kinds = list(set(atoms.kinds))
    # print(kinds)
    atom_kinds = {}
    for kind in kinds:
        atom_kinds[kind] = {}
        element = kind.split('_')[0]
        number = chemical_symbols.index(element)
        inds = [
            atom.index for atom in atoms if atoms.kinds[atom.index] == kind
        ]
        color = jmol_colors[number]
        radius = covalent_radii[number]
        atom_kinds[kind]['element'] = element
        atom_kinds[kind]['positions'] = atoms[inds].positions
        atom_kinds[kind]['number'] = number
        atom_kinds[kind]['color'] = color
        atom_kinds[kind]['transmit'] = 1.0
        atom_kinds[kind]['radius'] = radius
        atom_kinds[kind]['balltype'] = None
        if props:
            if kind in props.keys():
                for prop, value in props[kind].items():
                    atom_kinds[kind][prop] = value
    return atom_kinds
Ejemplo n.º 7
0
 def __init__(self, tilde_calc):
     self.weight = 0
     for a in tilde_calc.structures[-1]:
         if not a.symbol in chemical_symbols:
             raise ModuleError('Unexpected atom has been found!')
         try:
             self.weight += atomic_masses[chemical_symbols.index(a.symbol)]
         except IndexError:
             raise ModuleError('Application error!')
     self.weight = round(self.weight)
Ejemplo n.º 8
0
def get_APF(ase_obj):
    """
    Example crystal structure descriptor:
    https://en.wikipedia.org/wiki/Atomic_packing_factor
    """
    volume = 0.0
    for atom in ase_obj:
        volume += 4 / 3 * np.pi * covalent_radii[chemical_symbols.index(
            atom.symbol)]**3
    return volume / abs(np.linalg.det(ase_obj.cell))
Ejemplo n.º 9
0
    def __init__(self, symbols: List[str]):
        if NULL_SYMBOL in symbols:
            raise RuntimeError(
                f'Place holder symbol {NULL_SYMBOL} cannot be in list of symbols'
            )

        if len(symbols) < 1:
            raise RuntimeError('List of symbols cannot be empty')

        # Ensure that all symbols are valid
        for symbol in symbols:
            chemical_symbols.index(symbol)

        # Ensure that there are no duplicates
        if len(set(symbols)) != len(symbols):
            raise RuntimeError(
                f'List of symbols {symbols} cannot contain duplicates')

        self._symbols = [NULL_SYMBOL] + symbols
Ejemplo n.º 10
0
 def __init__(self, tilde_calc):
     self.weight = 0
     for a in tilde_calc.structures[-1]:
         if not a.symbol in chemical_symbols:
             raise ModuleError('Unexpected atom has been found!')
         try:
             self.weight += atomic_masses[chemical_symbols.index(a.symbol)]
         except IndexError:
             raise ModuleError('Application error!')
     self.weight = round(self.weight)
Ejemplo n.º 11
0
    def molecule_search(self,
                        element_pool={
                            'C': 2,
                            'H': 6
                        },
                        load_molecules=True,
                        multiple_bond_search=False):
        """Return the enumeration of molecules which can be produced from
        the specified atoms.

        Parameters:
        -----------
        element_pool: dict
            Atomic symbols keys paired with the maximum number of that atom.
        load_molecules: bool
            Load any existing molecules from the database.
        multiple_bond_search: bool
            Allow atoms to form bonds with other atoms in the molecule.
        """
        numbers = np.zeros(len(self.base_valence))
        for k, v in element_pool.items():
            numbers[chemical_symbols.index(k)] = v

        self.element_pool = numbers
        self.multiple_bond_search = multiple_bond_search

        molecules = {}
        if load_molecules:
            self.molecules = self.load_molecules(binned=True)

        search_molecules = []
        for el, cnt in enumerate(self.element_pool):

            if cnt == 0:
                continue

            molecule = Gratoms(symbols=[el])
            molecule.nodes[0]['valence'] = self.base_valence[el]

            search_molecules += [molecule]

            comp_tag, bond_tag = molecule.get_chemical_tags()
            if comp_tag not in self.molecules:
                molecules[comp_tag] = {bond_tag: [molecule]}

        for molecule in search_molecules:

            # Recusive use of molecules
            new_molecules, molecules = self._branch_molecule(
                molecule, molecules)

            search_molecules += new_molecules

        self.save_molecules(molecules)
Ejemplo n.º 12
0
def chemical_symbols_to_numbers(symbols: List[str]) -> List[int]:
    """Returns the atomic numbers equivalent to the input chemical
    symbols.

    Parameters
    ----------
    symbols
        chemical symbols
    """

    numbers = [chemical_symbols.index(symbols) for symbols in symbols]
    return numbers
Ejemplo n.º 13
0
def search_abnormal_bonds(model, verbose=True):
    '''
    Check all bond lengths in the model for abnormally
    short ones.

    Parameters:
    model: Atoms object or string. If string it will read a file
        in the same folder, e.g. "name.traj"
    '''

    # Abnormality check
    abnormal_bonds, list_of_abnormal_bonds = analyse_all_bonds(model,
                                                               verbose=verbose,
                                                               abnormal=True)

    from ase.data import chemical_symbols, covalent_radii
    import numpy as np
    if list_of_abnormal_bonds:
        sums_of_covalent_radii = []
        for i in list_of_abnormal_bonds:
            bond_chem_symbols = i.split("-")
            sums_of_covalent_radii += [
                covalent_radii[chemical_symbols.index(bond_chem_symbols[0])] +
                covalent_radii[chemical_symbols.index(bond_chem_symbols[1])]
            ]

    # Check against possible covalent radii values averaged * 0.75
    if len(abnormal_bonds) > 0:
        if verbose:
            print("-" * 40)
            print(
                "A total of", len(abnormal_bonds),
                "abnormal bond lengths observed (<" +
                str(max(0.4,
                        np.average(sums_of_covalent_radii) * 0.75)) + " A")
            print("Identities:", list_of_abnormal_bonds)
            print("-" * 40)
        return False
    else:
        return True
Ejemplo n.º 14
0
def get_polyhedra_kinds(atoms, bondlist={}, transmit=0.8, polyhedra={}):
    """
    Two modes:
    (1) Search atoms bonded to kind
    polyhedra: {'kind': ligands}
    """
    from scipy.spatial import ConvexHull
    from ase.data import covalent_radii
    from ase.neighborlist import NeighborList
    tstart = time.time()
    polyhedra_kinds = {}
    for kind, ligand in polyhedra.items():
        # print(kind, ligand)
        if kind not in polyhedra_kinds.keys():
            element = kind.split('_')[0]
            number = chemical_symbols.index(element)
            color = jmol_colors[number]
            polyhedra_kinds[kind] = {'vertices': [], 'edges': [], 'faces': []}
            polyhedra_kinds[kind]['material'] = {
                'diffuseColor': tuple(color),
                'transparency': 0.5
            }
        inds = [atom.index for atom in atoms if atom.symbol == kind]
        for ind in inds:
            vertice = []
            for bond in bondlist[ind]:
                a2, offset = bond
                if atoms[a2].symbol in ligand:
                    temp_pos = atoms[a2].position + np.dot(offset, atoms.cell)
                    vertice.append(temp_pos)
            nverts = len(vertice)
            # print(ind, nverts)
            if nverts > 3:
                # print(ind, vertice)
                # search convex polyhedra
                hull = ConvexHull(vertice)
                face = hull.simplices
                nverts = len(polyhedra_kinds[kind]['vertices'])
                face = face + nverts
                edge = []
                for f in face:
                    edge.append([f[0], f[1]])
                    edge.append([f[0], f[2]])
                    edge.append([f[1], f[2]])
                polyhedra_kinds[kind]['vertices'] = polyhedra_kinds[kind][
                    'vertices'] + list(vertice)
                polyhedra_kinds[kind][
                    'edges'] = polyhedra_kinds[kind]['edges'] + list(edge)
                polyhedra_kinds[kind][
                    'faces'] = polyhedra_kinds[kind]['faces'] + list(face)
    # print('get_polyhedra_kinds: {0:10.2f} s'.format(time.time() - tstart))
    return polyhedra_kinds
Ejemplo n.º 15
0
def classify(tilde_obj):
    if not len(tilde_obj.info['elements']) == 1 or tilde_obj.info['contents'][0] != 1: return tilde_obj

    dims = tilde_obj.info['dims'] if tilde_obj.structures[-1].periodicity == 3 else abs(det(tilde_obj.structures[-1].cell))

    if tilde_obj.structures[-1].periodicity == 0 or \
    float( dims / covalent_radii[chemical_symbols.index(tilde_obj.info['elements'][0])] ) > REL:

        # atomic radius should be REL times less than cell dimensions
        tilde_obj.info['periodicity'] = -1
        tilde_obj.structures[-1].periodicity = -1

    return tilde_obj
Ejemplo n.º 16
0
def _get_molecule_spec(atoms, nuclear_props):
    ''' Generate the molecule specification section to write
    to the Gaussian input file, from the Atoms object and dict
    of nuclear properties'''
    molecule_spec = []
    for i, atom in enumerate(atoms):
        symbol_section = atom.symbol + '('
        # Check whether any nuclear properties of the atom have been set,
        # and if so, add them to the symbol section.
        nuclear_props_set = False
        for keyword, array in nuclear_props.items():
            if array is not None and array[i] is not None:
                string = keyword + '=' + str(array[i]) + ', '
                symbol_section += string
                nuclear_props_set = True

        # Check whether the mass of the atom has been modified,
        # and if so, add it to the symbol section:
        mass_set = False
        symbol = atom.symbol
        expected_mass = atomic_masses_iupac2016[chemical_symbols.index(symbol)]
        if expected_mass != atoms[i].mass:
            mass_set = True
            string = 'iso' + '=' + str(atoms[i].mass)
            symbol_section += string

        if nuclear_props_set or mass_set:
            symbol_section = symbol_section.strip(', ')
            symbol_section += ')'
        else:
            symbol_section = symbol_section.strip('(')

        # Then attach the properties appropriately
        # this formatting was chosen for backwards compatibility reasons, but
        # it would probably be better to
        # 1) Ensure proper spacing between entries with explicit spaces
        # 2) Use fewer columns for the element
        # 3) Use 'e' (scientific notation) instead of 'f' for positions
        molecule_spec.append('{:<10s}{:20.10f}{:20.10f}{:20.10f}'.format(
            symbol_section, *atom.position))

    # unit cell vectors, in case of periodic boundary conditions
    for ipbc, tv in zip(atoms.pbc, atoms.cell):
        if ipbc:
            molecule_spec.append('TV {:20.10f}{:20.10f}{:20.10f}'.format(*tv))

    molecule_spec.append('')

    return molecule_spec
Ejemplo n.º 17
0
def classify(tilde_obj):
    if not len(tilde_obj.info['elements']
               ) == 1 or tilde_obj.info['contents'][0] != 1:
        return tilde_obj

    dims = tilde_obj.info['dims'] if tilde_obj.structures[
        -1].periodicity == 3 else abs(det(tilde_obj.structures[-1].cell))

    if tilde_obj.structures[-1].periodicity == 0 or \
    float( dims / covalent_radii[chemical_symbols.index(tilde_obj.info['elements'][0])] ) > REL:

        # atomic radius should be REL times less than cell dimensions
        tilde_obj.info['periodicity'] = -1
        tilde_obj.structures[-1].periodicity = -1

    return tilde_obj
Ejemplo n.º 18
0
def classify(tilde_obj):
    if sum(tilde_obj.structures[-1].get_pbc()
           ) == 3:  # only those initially 3-periodic
        zi, mi = tilde_obj.info['cellpar'].index(
            max(tilde_obj.info['cellpar']
                [0:3])), tilde_obj.info['cellpar'].index(
                    min(tilde_obj.info['cellpar'][0:3]))
        cmpveci = [i for i in range(3) if i not in [zi, mi]][0]

        # vacuum per one atom (av)
        atoms_volume = 0.0
        for i in tilde_obj.structures[-1]:
            atoms_volume += 4 / 3 * math.pi * (
                covalent_radii[chemical_symbols.index(i.symbol)] + r_EC)**3
        av = (abs(det(tilde_obj.structures[-1].cell)) - atoms_volume) / len(
            tilde_obj.structures[-1])
        #print "av:", av

        # too much vacuum
        if av > ADDED_VACUUM_3D_TOL:
            # 2D
            if tilde_obj.info['cellpar'][cmpveci] * L < tilde_obj.info[
                    'cellpar'][zi]:

                tilde_obj.info['techs'].append(
                    'vacuum %sA' % int(round(tilde_obj.info['cellpar'][zi])))

                tilde_obj.structures[-1].set_pbc((True, True, False))

            # TODO: 1D ?

            # 0D
            elif av > ADDED_VACUUM_3D_TOL * 4:  # TODO
                tilde_obj.structures[-1].set_pbc((False, False, False))

    # extend the last ASE object
    tilde_obj.structures[-1].periodicity = int(
        sum(tilde_obj.structures[-1].get_pbc()))
    tilde_obj.structures[-1].dims = abs(det(tilde_obj.structures[-1].cell))

    # TODO: area for surfaces

    tilde_obj.info['dims'] = tilde_obj.structures[-1].dims
    tilde_obj.info['periodicity'] = tilde_obj.structures[-1].periodicity

    return tilde_obj
Ejemplo n.º 19
0
def get_bond_kinds(atoms, atom_kinds, bondlist):
    '''
    Build faces for instancing bonds.
    The radius of bonds is determined by nbins.
    mesh.from_pydata(vertices, [], faces)
    '''
    # view(atoms)
    bond_kinds = {}
    for ind1, pairs in bondlist.items():
        kind = atoms.kinds[ind1]
        if kind not in bond_kinds.keys():
            lengths = []
            centers = []
            normals = []
            bond_kinds[kind] = {
                'lengths': lengths,
                'centers': centers,
                'normals': normals
            }
            number = chemical_symbols.index(kind)
            color = atom_kinds[kind]['color']
            radius = covalent_radii[number]
            bond_kinds[kind]['number'] = number
            bond_kinds[kind]['color'] = color
            bond_kinds[kind]['transmit'] = atom_kinds[kind]['transmit']
        for bond in pairs:
            ind2, offset = bond
            R = np.dot(offset, atoms.cell)
            # print(inds, offset)
            pos = [atoms.positions[ind1], atoms.positions[ind2] + R]
            # print(pos)
            center0 = (pos[0] + pos[1]) / 2.0
            if pos[0][2] > pos[1][2]:
                vec = pos[0] - pos[1]
            else:
                vec = pos[1] - pos[0]
            # print(vec)
            length = np.linalg.norm(vec)
            nvec = vec / length
            # kinds = [atoms[ind].symbol for ind in [a, b]]
            center = (center0 + pos[0]) / 2.0
            bond_kinds[kind]['centers'].append(center)
            bond_kinds[kind]['lengths'].append(length / 4.0)
            bond_kinds[kind]['normals'].append(nvec)
    # pprint.pprint(bond_kinds)
    return bond_kinds
Ejemplo n.º 20
0
 def plot_pdos(self,
               energies=None,
               pdos_kinds=None,
               Emin=-5,
               Emax=5,
               ax=None,
               total=False,
               select=None,
               fill=True,
               output=None,
               legend=False,
               xylabel=True,
               smearing=None):
     '''
     '''
     if energies is None: energies = self.pdos_energies
     if pdos_kinds is None: pdos_kinds = self.pdos_kinds
     xindex = (energies > Emin) & (energies < Emax)
     # print(xindex)
     if ax is None:
         fig, ax = plt.subplots(figsize=(6, 3))
     # if total:
     # self.plot_data(self.pdos_energies, self.pdos_tot, label = 'pdos', ax = ax, fill = fill)
     for kind, channels in pdos_kinds.items():
         if select and kind not in select: continue
         number = chemical_symbols.index(kind)
         color = jmol_colors[number]
         for channel, pdos in channels.items():
             if select and channel[-1] not in select[kind]: continue
             label = '{0}-{1}'.format(kind, channel)
             self.plot_data(energies,
                            pdos,
                            label=label,
                            ax=ax,
                            xindex=xindex,
                            fill=fill,
                            color=color,
                            smearing=smearing)
     if legend: ax.legend()
     if xylabel:
         ax.set_xlabel('Energy (eV)')
         ax.set_ylabel('PDOS (a.u.)')
     if output is not None:
         plt.savefig('%s' % output)
     return ax
Ejemplo n.º 21
0
    def get_checksum(self):
        ''' retrieve unique hash in a cross-platform manner:
        this is how unique identity is determined '''
        if self._checksum: return self._checksum

        if not self._filename:
            raise RuntimeError(
                'Source calc file is required in order to properly save the data!'
            )

        calc_checksum = hashlib.sha224()
        struc_repr = ""
        for ase_repr in self.structures:
            struc_repr += "%3.6f %3.6f %3.6f %3.6f %3.6f %3.6f %3.6f %3.6f %3.6f " % tuple(
                map(abs, [
                    ase_repr.cell[0][0], ase_repr.cell[0][1],
                    ase_repr.cell[0][2], ase_repr.cell[1][0],
                    ase_repr.cell[1][1], ase_repr.cell[1][2],
                    ase_repr.cell[2][0], ase_repr.cell[2][1],
                    ase_repr.cell[2][2]
                ]))  # NB beware of length & minus zeros
            for atom in ase_repr:
                struc_repr += "%s %3.6f %3.6f %3.6f " % tuple(
                    map(abs, [
                        chemical_symbols.index(atom.symbol), atom.x, atom.y,
                        atom.z
                    ]))  # NB beware of length & minus zeros

        if self.info["energy"] is None:
            energy = str(None)
        else:
            energy = str(
                round(self.info['energy'],
                      11 - int(math.log10(math.fabs(self.info['energy'])))))

        calc_checksum.update(
            (struc_repr + energy + " " + self.info['prog'] + " " +
             str(self.info['input']) + " " +
             str(sum([2**x for x in self.info['calctypes']]))).encode('ascii')
        )  # this is fixed in DB schema 5.11 and should not be changed

        result = base64.b32encode(calc_checksum.digest()).decode('ascii')
        result = result[:result.index('=')] + 'CI'
        return result
Ejemplo n.º 22
0
def get_occupied_primitive_structure(
        structure: Atoms, allowed_species: List[List[str]],
        symprec: float) -> Tuple[Atoms, List[Tuple[str, ...]]]:
    """
    Returns an occupied primitive structure.
    Will put hydrogen on sublattice 1, Helium on sublattice 2 and
    so on

    Parameters
    ----------
    structure
        input structure
    allowed_species
        chemical symbols that are allowed on each site
    symprec
        tolerance imposed when analyzing the symmetry using spglib

    Todo
    ----
    simplify the revert back to unsorted symbols
    """
    if len(structure) != len(allowed_species):
        raise ValueError(
            'structure and chemical symbols need to be the same size.')
    sorted_symbols = sorted({tuple(sorted(s)) for s in allowed_species})

    decorated_primitive = structure.copy()
    for i, sym in enumerate(allowed_species):
        sublattice = sorted_symbols.index(tuple(sorted(sym))) + 1
        decorated_primitive[i].symbol = chemical_symbols[sublattice]

    decorated_primitive = get_primitive_structure(decorated_primitive,
                                                  symprec=symprec)
    decorated_primitive.wrap()
    primitive_chemical_symbols: List[Tuple[str, ...]] = []
    for atom in decorated_primitive:
        sublattice = chemical_symbols.index(atom.symbol)
        primitive_chemical_symbols.append(sorted_symbols[sublattice - 1])

    for symbols in allowed_species:
        if tuple(sorted(symbols)) in primitive_chemical_symbols:
            index = primitive_chemical_symbols.index(tuple(sorted(symbols)))
            primitive_chemical_symbols[index] = symbols
    return decorated_primitive, primitive_chemical_symbols
Ejemplo n.º 23
0
def get_atom_kinds(atoms, scale, props={}):
    tstart = time.time()
    if atoms.info and 'kinds' in atoms.info:
        assert len(atoms.info['kinds']) == len(
            atoms), """ \n\n kinds not equal to number of atoms. 
 You increase atoms by *[x, x, x]? Please set atoms.info['kinds'] again. 
 Or remove the original one.\n"""
        kinds = list(set(atoms.info['kinds']))
    else:
        atoms.info['kinds'] = atoms.get_chemical_symbols()
        kinds = list(set(atoms.info['kinds']))
    atom_kinds = {}
    for kind in kinds:
        atom_kinds[kind] = {}
        element = kind.split('_')[0]
        number = chemical_symbols.index(element)
        inds = [
            atom.index for atom in atoms
            if atoms.info['kinds'][atom.index] == kind
        ]
        color = jmol_colors[number]
        radius = covalent_radii[number]
        atom_kinds[kind]['element'] = element
        atom_kinds[kind]['indexs'] = inds
        atom_kinds[kind]['positions'] = np.round(atoms[inds].positions,
                                                 decimals=2)
        atom_kinds[kind]['number'] = number
        atom_kinds[kind]['material'] = {
            'diffuseColor': tuple(color),
            'transparency': 0.01
        }
        atom_kinds[kind]['sphere'] = {'radius': radius * scale}
        atom_kinds[kind]['balltype'] = None
        # bond
        atom_kinds[kind]['lengths'] = []
        atom_kinds[kind]['centers'] = []
        atom_kinds[kind]['rotations'] = []
        if props:
            if kind in props.keys():
                for prop, value in props[kind].items():
                    atom_kinds[kind][prop] = value
    # print('get_atom_kinds: {0:10.2f} s'.format(time.time() - tstart))
    return atom_kinds
Ejemplo n.º 24
0
    def write_lammps_atoms(self, atoms):
        """Write atoms infor for LAMMPS"""
        
        fileobj = 'lammps_atoms'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')
        write_lammps_data(fileobj, atoms, 
                          specorder=atoms.types,
                          speclist=(atoms.get_tags() + 1),
                          )

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write('%6d %g # %s -> %s\n' % 
                          (i + 1, 
                           atomic_masses[chemical_symbols.index(cs)],
                           typ, cs))
  
        # bonds
        btypes, blist = self.get_bonds(atoms)
        fileobj.write('\n' + str(len(btypes)) + ' bond types\n')
        fileobj.write(str(len(blist)) + ' bonds\n')
        fileobj.write('\nBonds\n\n')
        
        for ib, bvals in enumerate(blist):
            fileobj.write('%8d %6d %6d %6d\n' %
                          (ib + 1, bvals[0] + 1, bvals[1] + 1, bvals[2] + 1))

        # angles
        atypes, alist = self.get_angles()
        fileobj.write('\n' + str(len(atypes)) + ' angle types\n')
        fileobj.write(str(len(alist)) + ' angles\n')
        fileobj.write('\nAngles\n\n')
        
        for ia, avals in enumerate(alist):
            fileobj.write('%8d %6d %6d %6d %6d\n' %
                          (ia + 1, avals[0] + 1, 
                           avals[1] + 1, avals[2] + 1, avals[3] + 1))

        return btypes, atypes
Ejemplo n.º 25
0
def get_atom_kinds(atoms, props={}):
    # symbols = atoms.symbols
    # formula = atoms.symbols.formula
    # atom_kinds = formula.count()
    tstart = time.time()
    if hasattr(atoms, 'kinds'):
        kinds = list(set(atoms.kinds))
    else:
        atoms.kinds = atoms.get_chemical_symbols()
        kinds = list(set(atoms.kinds))
    # print(kinds)
    atom_kinds = {}
    for kind in kinds:
        atom_kinds[kind] = {}
        element = kind.split('_')[0]
        print(kind, element)
        number = chemical_symbols.index(element)
        inds = [
            atom.index for atom in atoms if atoms.kinds[atom.index] == kind
        ]
        color = jmol_colors[number]
        radius = covalent_radii[number]
        atom_kinds[kind]['element'] = element
        atom_kinds[kind]['positions'] = atoms[inds].positions
        atom_kinds[kind]['number'] = number
        atom_kinds[kind]['color'] = color
        atom_kinds[kind]['transmit'] = 1.0
        atom_kinds[kind]['radius'] = radius
        atom_kinds[kind]['balltype'] = None
        # bond
        atom_kinds[kind]['lengths'] = []
        atom_kinds[kind]['centers'] = []
        atom_kinds[kind]['normals'] = []
        atom_kinds[kind]['verts'] = []
        atom_kinds[kind]['faces'] = []
        if props:
            if kind in props.keys():
                for prop, value in props[kind].items():
                    atom_kinds[kind][prop] = value
    print('get_atom_kinds: {0:10.2f} s'.format(time.time() - tstart))
    return atom_kinds
Ejemplo n.º 26
0
    def set_missing_parameters(self):
        """Verify that all necessary variables are set.
        """
        symbols = self.atoms.get_chemical_symbols()
        # If unspecified default to atom types in alphabetic order
        if not self.parameters.specorder:
            self.parameters.specorder = sorted(set(symbols))

        # !TODO: handle cases were setting masses actual lead to errors
        if not self.parameters.masses:
            self.parameters.masses = []
            for type_id, specie in enumerate(self.parameters.specorder):
                mass = atomic_masses[chemical_symbols.index(specie)]
                self.parameters.masses += [
                    "{0:d} {1:f}".format(type_id + 1, mass)
                ]

        # set boundary condtions
        if not self.parameters.boundary:
            b_str = " ".join(["fp"[int(x)] for x in self.atoms.get_pbc()])
            self.parameters.boundary = b_str
Ejemplo n.º 27
0
    def get_atomic_numbers(formula, return_count=False):
        ''' Return the atomic numbers associated with a chemical formula.

        Parameters
        ----------
        formula : string
            A chemical formula to parse into atomic numbers.
        return_count : bool
            Return the count of each element in the formula.

        Returns
        -------
        numbers : ndarray (n,)
            Element numbers in associated species.
        counts : ndarray (n,)
            Count of each element in a species.

        '''
        parse = re.findall('[A-Z][a-z]?|[0-9]+', formula)

        values = {}
        for i, e in enumerate(parse):
            if e.isdigit():
                values[parse[i - 1]] += int(e) - 1
            else:
                if e not in values:
                    values[e] = 1
                else:
                    values[e] += 1

        numbers = np.array([chemical_symbols.index(k) for k in values.keys()])
        srt = np.argsort(numbers)
        numbers = numbers[srt]

        if return_count:
            counts = np.array([v for v in values.values()])[srt]

            return numbers, counts

        return numbers
Ejemplo n.º 28
0
def default_atom_kind(element, positions, color = 'VESTA'):
    """
    """
    from ase.data import chemical_symbols
    from ase.data.colors import jmol_colors, cpk_colors
    from blase.default_data import vesta_color
    atom_kind = {}
    number = chemical_symbols.index(element)
    if color.upper() == 'JMOL':
        color = jmol_colors[number]
    elif color.upper() == 'CPK':
        color = jmol_colors[number]
    elif color.upper() == 'VESTA':
        color = vesta_color[element]
    radius = covalent_radii[number]
    atom_kind['element'] = element
    atom_kind['color'] = color
    atom_kind['transmit'] = 1.0
    atom_kind['radius'] = radius
    atom_kind['positions'] = positions
    atom_kind['balltype'] = None
    return atom_kind
Ejemplo n.º 29
0
def default_bond_kind(element, color = 'VESTA'):
    """
    """
    from ase.data import chemical_symbols
    from ase.data.colors import jmol_colors, cpk_colors
    from blase.default_data import vesta_color
    bond_kind = {}
    number = chemical_symbols.index(element)
    if color.upper() == 'JMOL':
        color = jmol_colors[number]
    elif color.upper() == 'CPK':
        color = jmol_colors[number]
    elif color.upper() == 'VESTA':
        color = vesta_color[element]
    bond_kind['element'] = element
    bond_kind['color'] = color
    bond_kind['transmit'] = 1.0
    bond_kind['lengths'] = []
    bond_kind['centers'] = []
    bond_kind['normals'] = []
    bond_kind['verts'] = []
    bond_kind['faces'] = []
    return bond_kind
Ejemplo n.º 30
0
def classify(tilde_obj):
    if sum(tilde_obj.structures[-1].get_pbc()) == 3: # only those initially 3-periodic
        zi, mi = tilde_obj.info['cellpar'].index(max(tilde_obj.info['cellpar'][0:3])), tilde_obj.info['cellpar'].index(min(tilde_obj.info['cellpar'][0:3]))
        cmpveci = [i for i in range(3) if i not in [zi, mi]][0]

        # vacuum per one atom (av)
        atoms_volume = 0.0
        for i in tilde_obj.structures[-1]:
            atoms_volume += 4/3 * math.pi * (covalent_radii[ chemical_symbols.index( i.symbol ) ] + r_EC) ** 3
        av = (abs(det(tilde_obj.structures[-1].cell)) - atoms_volume)/len(tilde_obj.structures[-1])
        #print "av:", av

        # too much vacuum
        if av > ADDED_VACUUM_3D_TOL:
            # 2D
            if tilde_obj.info['cellpar'][cmpveci] * L < tilde_obj.info['cellpar'][zi]:

                tilde_obj.info['techs'].append( 'vacuum %sA' % int(round(tilde_obj.info['cellpar'][zi])) )

                tilde_obj.structures[-1].set_pbc((True, True, False))

            # TODO: 1D ?

            # 0D
            elif av > ADDED_VACUUM_3D_TOL*4: # TODO
                tilde_obj.structures[-1].set_pbc((False, False, False))

    # extend the last ASE object
    tilde_obj.structures[-1].periodicity = int(sum(tilde_obj.structures[-1].get_pbc()))
    tilde_obj.structures[-1].dims = abs(det(tilde_obj.structures[-1].cell))

    # TODO: area for surfaces

    tilde_obj.info['dims'] = tilde_obj.structures[-1].dims
    tilde_obj.info['periodicity'] = tilde_obj.structures[-1].periodicity

    return tilde_obj
Ejemplo n.º 31
0
Archivo: opls.py Proyecto: grhawk/ASE
    def write_lammps_atoms(self, atoms):
        """Write atoms infor for LAMMPS"""
        
        fileobj = self.prefix + '_atoms'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')

        # header
        fileobj.write(fileobj.name + ' (by ' + str(self.__class__) + ')\n\n')
        fileobj.write(str(len(atoms)) + ' atoms\n')
        fileobj.write(str(len(atoms.types)) + ' atom types\n')
        btypes, blist = self.get_bonds(atoms)
        if len(blist):
            fileobj.write(str(len(blist)) + ' bonds\n')
            fileobj.write(str(len(btypes)) + ' bond types\n')
        atypes, alist = self.get_angles()
        if len(alist):
            fileobj.write(str(len(alist)) + ' angles\n')
            fileobj.write(str(len(atypes)) + ' angle types\n')
        dtypes, dlist = self.get_dihedrals(alist, atypes)
        if len(dlist):
            fileobj.write(str(len(dlist)) + ' dihedrals\n')
            fileobj.write(str(len(dtypes)) + ' dihedral types\n')

        # cell
        p = prism(atoms.get_cell())
        xhi, yhi, zhi, xy, xz, yz = p.get_lammps_prism_str()
        fileobj.write('\n0.0 %s  xlo xhi\n' % xhi)
        fileobj.write('0.0 %s  ylo yhi\n' % yhi)
        fileobj.write('0.0 %s  zlo zhi\n' % zhi)
        
        # atoms
        fileobj.write('\nAtoms\n\n')
        tag = atoms.get_tags()
        for i, r in enumerate(map(p.pos_to_lammps_str,
                                  atoms.get_positions())):
            q = 0  # charge will be overwritten
            fileobj.write('%6d %3d %3d %s %s %s %s' % ((i + 1, 1,
                                                        tag[i] + 1, 
                                                        q)
                                                       + tuple(r)))
            fileobj.write(' # ' + atoms.types[tag[i]] + '\n')

        # velocities
        velocities = atoms.get_velocities()
        if velocities is not None:
            fileobj.write('\nVelocities\n\n')
            for i, v in enumerate(velocities):
                fileobj.write('%6d %g %g %g\n' %
                              (i + 1, v[0], v[1], v[2]))

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write('%6d %g # %s -> %s\n' % 
                          (i + 1, 
                           atomic_masses[chemical_symbols.index(cs)],
                           typ, cs))
  
        # bonds
        if len(blist):
            fileobj.write('\nBonds\n\n')
            for ib, bvals in enumerate(blist):
                fileobj.write('%8d %6d %6d %6d ' %
                              (ib + 1, bvals[0] + 1, bvals[1] + 1, 
                               bvals[2] + 1))
                fileobj.write('# ' + btypes[bvals[0]] + '\n')

        # angles
        if len(alist):
            fileobj.write('\nAngles\n\n')
            for ia, avals in enumerate(alist):
                fileobj.write('%8d %6d %6d %6d %6d ' %
                              (ia + 1, avals[0] + 1, 
                               avals[1] + 1, avals[2] + 1, avals[3] + 1))
                fileobj.write('# ' + atypes[avals[0]] + '\n')

        # dihedrals
        if len(dlist):
            fileobj.write('\nDihedrals\n\n')
            for i, dvals in enumerate(dlist):
                fileobj.write('%8d %6d %6d %6d %6d %6d ' %
                              (i + 1, dvals[0] + 1, 
                               dvals[1] + 1, dvals[2] + 1, 
                               dvals[3] + 1, dvals[4] + 1))
                fileobj.write('# ' + dtypes[dvals[0]] + '\n')

        return btypes, atypes, dtypes
Ejemplo n.º 32
0
Archivo: opls.py Proyecto: grhawk/ASE
    def write_lammps_atoms(self, atoms):
        """Write atoms infor for LAMMPS"""

        fileobj = self.prefix + '_atoms'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')

        # header
        fileobj.write(fileobj.name + ' (by ' + str(self.__class__) + ')\n\n')
        fileobj.write(str(len(atoms)) + ' atoms\n')
        fileobj.write(str(len(atoms.types)) + ' atom types\n')
        btypes, blist = self.get_bonds(atoms)
        if len(blist):
            fileobj.write(str(len(blist)) + ' bonds\n')
            fileobj.write(str(len(btypes)) + ' bond types\n')
        atypes, alist = self.get_angles()
        if len(alist):
            fileobj.write(str(len(alist)) + ' angles\n')
            fileobj.write(str(len(atypes)) + ' angle types\n')
        dtypes, dlist = self.get_dihedrals(alist, atypes)
        if len(dlist):
            fileobj.write(str(len(dlist)) + ' dihedrals\n')
            fileobj.write(str(len(dtypes)) + ' dihedral types\n')

        # cell
        p = prism(atoms.get_cell())
        xhi, yhi, zhi, xy, xz, yz = p.get_lammps_prism_str()
        fileobj.write('\n0.0 %s  xlo xhi\n' % xhi)
        fileobj.write('0.0 %s  ylo yhi\n' % yhi)
        fileobj.write('0.0 %s  zlo zhi\n' % zhi)

        # atoms
        fileobj.write('\nAtoms\n\n')
        tag = atoms.get_tags()
        for i, r in enumerate(map(p.pos_to_lammps_str, atoms.get_positions())):
            q = 0  # charge will be overwritten
            fileobj.write('%6d %3d %3d %s %s %s %s' %
                          ((i + 1, 1, tag[i] + 1, q) + tuple(r)))
            fileobj.write(' # ' + atoms.types[tag[i]] + '\n')

        # velocities
        velocities = atoms.get_velocities()
        if velocities is not None:
            fileobj.write('\nVelocities\n\n')
            for i, v in enumerate(velocities):
                fileobj.write('%6d %g %g %g\n' % (i + 1, v[0], v[1], v[2]))

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write(
                '%6d %g # %s -> %s\n' %
                (i + 1, atomic_masses[chemical_symbols.index(cs)], typ, cs))

        # bonds
        if len(blist):
            fileobj.write('\nBonds\n\n')
            for ib, bvals in enumerate(blist):
                fileobj.write(
                    '%8d %6d %6d %6d ' %
                    (ib + 1, bvals[0] + 1, bvals[1] + 1, bvals[2] + 1))
                fileobj.write('# ' + btypes[bvals[0]] + '\n')

        # angles
        if len(alist):
            fileobj.write('\nAngles\n\n')
            for ia, avals in enumerate(alist):
                fileobj.write('%8d %6d %6d %6d %6d ' %
                              (ia + 1, avals[0] + 1, avals[1] + 1,
                               avals[2] + 1, avals[3] + 1))
                fileobj.write('# ' + atypes[avals[0]] + '\n')

        # dihedrals
        if len(dlist):
            fileobj.write('\nDihedrals\n\n')
            for i, dvals in enumerate(dlist):
                fileobj.write('%8d %6d %6d %6d %6d %6d ' %
                              (i + 1, dvals[0] + 1, dvals[1] + 1, dvals[2] + 1,
                               dvals[3] + 1, dvals[4] + 1))
                fileobj.write('# ' + dtypes[dvals[0]] + '\n')

        return btypes, atypes, dtypes
Ejemplo n.º 33
0
def write_ion(fileobj, atoms, pseudo_dir=None, scaled=True,
              add_constraints=False, copy_psp=True, comment=''):
    """
    Standard ase io file for reading the sparc-x .ion format

    inputs:
        atoms (ase atoms object):
            an ase atoms object of the system being written to a file
        pseudos (list):
            a list of the locations of the pseudopotential files to be used
    """

    directory = os.path.dirname(fileobj.name)

    elements = sorted(list(set(atoms.get_chemical_symbols())))

    fileobj.write('# Input File Generated By SPARC ASE Calculator #\n')
    fileobj.write('#CELL:')
    for comp in atoms.cell:
        fileobj.write('  {}'.format(
            format(np.linalg.norm(comp) / Bohr, ' .15f')))
    fileobj.write('\n#LATVEC\n')
    for comp in atoms.cell:
        fileobj.write('#')
        comp_n = comp / np.linalg.norm(comp)  # normalize
        for i in comp_n:
            fileobj.write(' {}'.format(format(i, ' .15f')))
        fileobj.write('\n')
    if atoms.pbc is not None:
        fileobj.write('#PBC: ')
        for condition in atoms.pbc:
            fileobj.write(str(condition) + ' ')
        fileobj.write('\n')
    fileobj.write('# ' + comment + '\n\n\n')

    # translate the constraints to usable strings
    if add_constraints == True:
        cons_indices = []
        cons_strings = []
        for constraint in atoms.constraints:
            name = type(constraint).__name__
            if name == 'FixAtoms':
                cons_indices += list(constraint.index)
                cons_strings += ['0 0 0\n'] * len(constraint.index)
            elif name == 'FixedLine' or 'FixedPlane':
                line_dir = [int(np.ceil(a)) for a in constraint.dir]
                max_dirs = 1  # for FixedLine
                # The API of FixedLine and FixedPlane is the same
                # except for the need for an inversion of indices
                if name == 'FixedPlane':
                    line_dir = [int(not a) for a in line_dir]
                    max_dirs = 2
                if line_dir.count(1) > max_dirs:
                    warnings.warn('The .ion filetype can only support'
                                  'freezing entire dimensions (x,y,z).'
                                  'The {} constraint on this atoms'
                                  ' Object is being converted to allow '
                                  'movement in any directions in which the'
                                  ' atom had some freedom to move'.format(name))
                cons_indices += constraint.get_indices()
                cons_strings.append('{} {} {}\n'.format(*line_dir))
            else:
                warnings.warn('The constraint type {} is not supported by'
                              ' the .ion format. This constraint will be'
                              ' ignored')

        # just make sure that there aren't repeats
        assert len(set(cons_indices)) == len(cons_indices)

    for i, element in enumerate(elements):
        fileobj.write('ATOM_TYPE: ')
        fileobj.write(element + '\n')

        fileobj.write('N_TYPE_ATOM: ')
        fileobj.write(str(atoms.get_chemical_symbols().count(element)) + '\n')
        if add_constraints:
            constraints_string = 'RELAX:\n'
        magmoms = [float(a) for a in atoms.get_initial_magnetic_moments()]
        if magmoms != [0.] * len(atoms):
            spin_string = 'SPIN:\n'

        # TODO: fix this psuedopotential finding code
        if pseudo_dir is not None:#there is a pseudopotential directory provided
            if not os.path.isdir(pseudo_dir):#if it is not a directory, then the SPARC_PSP_PATH is used
                pseudo_dir = os.environ['SPARC_PSP_PATH']
                warnings.warn('The path entered for `pseudo_dir` could '
                              'not be found. Using SPARC_PSP_PATH and generic pseudopotential '
                              'file names (<symbol>.pot). Psuedopotentials must be added '
                              'manually for SPARC to execute successfully.')
                fileobj.write('PSEUDO_POT: {}.pot\n'.format(element))
            else:
                pseudos_in_dir = [a for a in os.listdir(pseudo_dir)
                                  if a.endswith(element+'.pot') or a.endswith(element+'.psp8')]

                filename = [a for a in os.listdir(pseudo_dir)
                            if a.endswith(element+'.pot') or a.endswith(element+'.psp8')]

                if len(filename) == 0:
                    filename = element+'.pot'
                    warnings.warn('No pseudopotential detected for '+element+'. '
                                  'Using generic filename ('+element +
                                  '.pot). The pseudopotential '
                                  ' must be added manually for SPARC to execute successfully.')
                else:
                    if len(filename) > 1:
                        warnings.warn('Multiple psudopotentials detected for '
                                      '{} ({}).'.format(element, str(filename))+' Using '+filename[0]+'.')
                    if copy_psp:
                        filename = filename[0]
                        full_psp_path = os.path.abspath(os.path.join(pseudo_dir, filename))
                        full_dest_path = os.path.abspath(os.path.join(directory, filename))
                        if full_psp_path != full_dest_path:
                            #shutil.copyfile(os.path.join(pseudo_dir, filename),
                            #                os.path.join(directory, filename))
                            shutil.copyfile(full_psp_path, full_dest_path)
                    else:
                        filename = os.path.join(pseudo_dir, filename[0])

                #os.system('cp $SPARC_PSP_PATH/' + filename + ' .')
                fileobj.write('PSEUDO_POT: {}\n'.format(filename))

        else:
            fileobj.write('PSEUDO_POT: {}.pot\n'.format(element))

        atomic_number = chemical_symbols.index(element)
        atomic_mass = atomic_masses_iupac2016[atomic_number]
        fileobj.write('ATOMIC_MASS: {}\n'.format(atomic_mass))

        if scaled == False:
            fileobj.write('COORD:\n')
            positions = atoms.get_positions(wrap=False)
            positions /= Bohr
        else:
            fileobj.write('COORD_FRAC:\n')
            positions = atoms.get_scaled_positions(wrap=False)
        for atom, position in zip(atoms, positions):
            if atom.symbol == element:
                for component in position:
                    fileobj.write('    {}'.format(format(component, ' .15f')))
                fileobj.write('   # index {}'.format(atom.index))
                fileobj.write('\n')
                # mess with the constraints
                if add_constraints:
                    if atom.index in cons_indices:
                        constraints_indices_index = cons_indices.index(
                            atom.index)
                        constraints_string += cons_strings[constraints_indices_index]
                    else:
                        constraints_string += '1 1 1\n'
                if 'spin_string' in locals():
                    spin_string += format(atom.magmom, ' .15f') + '\n'
        # dump in the constraints
        if add_constraints:
            fileobj.write(constraints_string)
        if 'spin_string' in locals():
            fileobj.write(spin_string)
        fileobj.write('\n\n')
Ejemplo n.º 34
0
Archivo: opls.py Proyecto: wes-amat/ase
    def write_lammps_atoms(self, atoms, connectivities):
        """Write atoms input for LAMMPS"""

        fname = self.prefix + '_atoms'
        fileobj = open(fname, 'w')

        # header
        fileobj.write(fileobj.name + ' (by ' + str(self.__class__) + ')\n\n')
        fileobj.write(str(len(atoms)) + ' atoms\n')
        fileobj.write(str(len(atoms.types)) + ' atom types\n')
        blist = connectivities['bonds']
        if len(blist):
            btypes = connectivities['bond types']
            fileobj.write(str(len(blist)) + ' bonds\n')
            fileobj.write(str(len(btypes)) + ' bond types\n')
        alist = connectivities['angles']
        if len(alist):
            atypes = connectivities['angle types']
            fileobj.write(str(len(alist)) + ' angles\n')
            fileobj.write(str(len(atypes)) + ' angle types\n')
        dlist = connectivities['dihedrals']
        if len(dlist):
            dtypes = connectivities['dihedral types']
            fileobj.write(str(len(dlist)) + ' dihedrals\n')
            fileobj.write(str(len(dtypes)) + ' dihedral types\n')

        # cell
        p = Prism(atoms.get_cell())
        xhi, yhi, zhi, xy, xz, yz = p.get_lammps_prism_str()
        fileobj.write('\n0.0 %s  xlo xhi\n' % xhi)
        fileobj.write('0.0 %s  ylo yhi\n' % yhi)
        fileobj.write('0.0 %s  zlo zhi\n' % zhi)

        # atoms
        fileobj.write('\nAtoms\n\n')
        tag = atoms.get_tags()
        if atoms.has('molid'):
            molid = atoms.get_array('molid')
        else:
            molid = [1] * len(atoms)
        for i, r in enumerate(p.positions_to_lammps_strs(
                atoms.get_positions())):
            atype = atoms.types[tag[i]]
            if len(atype) < 2:
                atype = atype + ' '
            q = self.data['one'][atype][2]
            fileobj.write('%6d %3d %3d %s %s %s %s' %
                          ((i + 1, molid[i], tag[i] + 1, q) + tuple(r)))
            fileobj.write(' # ' + atoms.types[tag[i]] + '\n')

        # velocities
        velocities = atoms.get_velocities()
        if velocities is not None:
            fileobj.write('\nVelocities\n\n')
            for i, v in enumerate(velocities):
                fileobj.write('%6d %g %g %g\n' % (i + 1, v[0], v[1], v[2]))

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write(
                '%6d %g # %s -> %s\n' %
                (i + 1, atomic_masses[chemical_symbols.index(cs)], typ, cs))

        # bonds
        if len(blist):
            fileobj.write('\nBonds\n\n')
            for ib, bvals in enumerate(blist):
                fileobj.write(
                    '%8d %6d %6d %6d ' %
                    (ib + 1, bvals[0] + 1, bvals[1] + 1, bvals[2] + 1))
                try:
                    fileobj.write('# ' + btypes[bvals[0]])
                except:
                    pass
                fileobj.write('\n')

        # angles
        if len(alist):
            fileobj.write('\nAngles\n\n')
            for ia, avals in enumerate(alist):
                fileobj.write('%8d %6d %6d %6d %6d ' %
                              (ia + 1, avals[0] + 1, avals[1] + 1,
                               avals[2] + 1, avals[3] + 1))
                try:
                    fileobj.write('# ' + atypes[avals[0]])
                except:
                    pass
                fileobj.write('\n')

        # dihedrals
        if len(dlist):
            fileobj.write('\nDihedrals\n\n')
            for i, dvals in enumerate(dlist):
                fileobj.write('%8d %6d %6d %6d %6d %6d ' %
                              (i + 1, dvals[0] + 1, dvals[1] + 1, dvals[2] + 1,
                               dvals[3] + 1, dvals[4] + 1))
                try:
                    fileobj.write('# ' + dtypes[dvals[0]])
                except:
                    pass
                fileobj.write('\n')
Ejemplo n.º 35
0
        x = []
        while len(x) < n:
            a, b, c = array([numpy_random.normal(init[0], s), numpy_random.normal(init[1], s), numpy_random.normal(init[2], s)])
            if abs(a) < 1 and abs(b) < 1 and abs(c) < 1:
                x.append([a,b,c])
        X.extend(x)
    X = array(X)[:N]
    return X

if DISTRIB == 'RANDOM':
    set_x, set_y = [random.choice(chemical_symbols) for i in range(N)], [random.choice(chemical_symbols) for i in range(N)]
    set_z = [round(random.uniform(0.1, 15.0), 2) for i in range(N)]
    data, ref = [], []
    for i in range(N):
        formula = set_x[i] + set_y[i]
        set_x[i] = get_element_group(chemical_symbols.index(set_x[i]))
        set_y[i] = get_element_group(chemical_symbols.index(set_y[i]))
        data.append(Point([set_x[i], set_y[i], set_z[i]], formula))
        ref.append([set_x[i], set_y[i], set_z[i]])

else:
    nte = len(chemical_symbols)
    G = gaussian_distribution(N, k_from_n(N))

    set_x = (G[:,0] + 1)/2*nte
    set_x = map(lambda x: int(math.floor(x)), set_x.tolist())

    set_y = (G[:,1] + 1)/2*nte
    set_y = map(lambda x: int(math.floor(x)), set_y.tolist())

    set_z = (G[:,2] + 1)/2*15
Ejemplo n.º 36
0
def build_shell_dist_fig(bimet, show=False):
    """
    Creates shell distribution figure of
    BimetallicResult

    Args:

    Returns:
    (plt.Figure)
    """
    # get atoms object
    atoms = bimet.build_atoms_obj().copy()

    # build shells dictionary
    shape = bimet.shape
    num_shells = bimet.nanoparticle.num_shells
    shells_dict = build_atoms_in_shell_dict(shape, num_shells)

    # list of all shells in NP (0 is core atom)
    shell_ls = sorted(shells_dict)

    # calc total and metal counts for each shell
    tot_count = np.zeros(len(shell_ls))
    m1_count = np.zeros(len(shell_ls))
    m2_count = np.zeros(len(shell_ls))
    for i, shell in enumerate(sorted(shells_dict)):
        # indices of atoms in current shell
        indices = shells_dict[shell]

        # total atom count of current shell
        tot_count[i] = len(indices)

        # metal type counts for current shell
        m1_count[i] = (atoms[indices].symbols == bimet.metal1).sum()
        m2_count[i] = (atoms[indices].symbols == bimet.metal2).sum()

    # normalize counts to concentrations
    norm_m1 = m1_count / tot_count
    norm_m2 = m2_count / tot_count

    fig, axes = plt.subplots(2, 1, sharex=True)
    ax1, ax2 = axes

    m1_color = jmol_colors[chemical_symbols.index(bimet.metal1)]
    m2_color = jmol_colors[chemical_symbols.index(bimet.metal2)]

    ax1.plot(shell_ls, m1_count, 'o-', markeredgecolor='k',
             color=m1_color, markersize=8, label=bimet.metal1)
    ax1.plot(shell_ls, m2_count, 'o-', markeredgecolor='k',
             color=m2_color, markersize=8, label=bimet.metal2)
    ax1.legend(loc='upper left')
    ax1.set_xticks(list(range(1, bimet.nanoparticle.num_shells + 1)))

    # set ylim to maximum number of atoms on surface
    high = int(round((tot_count[-1] + 10) * 10) / 10)
    ax1.set_ylim(-2, high)
    ax1.set_ylabel('# of Atoms')

    ax2.plot(shell_ls, norm_m1, 'o-', markeredgecolor='k',
             color=m1_color, markersize=8)
    ax2.plot(shell_ls, norm_m2, 'o-', markeredgecolor='k',
             color=m2_color, markersize=8)
    ax2.set_ylabel('Concentration')
    yticks = [0, 0.25, 0.5, 0.75, 1]
    ax2.set_yticks(yticks)
    ax2.set_yticklabels(['{:,.0%}'.format(x) for x in yticks])
    ax2.set_xticks(shell_ls)

    # create xtick labels based on shell number
    xticklabels = ['Shell %i' % i for i in shell_ls]
    xticklabels[0] = 'Core'
    xticklabels[-1] = 'Surface'
    ax2.set_xticklabels(xticklabels, rotation=45)

    fig.suptitle(bimet.build_chem_formula(latex=True) + ' - %s' % shape)
    fig.tight_layout(rect=(0, 0, 1, 0.9))

    if show:
        plt.show()
    return fig
Ejemplo n.º 37
0
def classify(tilde_obj):
    if len(tilde_obj.info['elements']) == 1: return tilde_obj

    C_site = [e for e in tilde_obj.info['elements'] if e in Perovskite_Structure.C]
    if not C_site: return tilde_obj
    A_site = [e for e in tilde_obj.info['elements'] if e in Perovskite_Structure.A]
    B_site = [e for e in tilde_obj.info['elements'] if e in Perovskite_Structure.B]

    # proportional content coefficient D_prop
    AB, C = 0, 0
    for i in set(A_site + B_site):
        AB += tilde_obj.info['contents'][ tilde_obj.info['elements'].index(i) ]
    for i in C_site:
        C += tilde_obj.info['contents'][ tilde_obj.info['elements'].index(i) ]

    try: D_prop = float(C) / AB
    except ZeroDivisionError: return tilde_obj

    # 2-component pseudo-perovskites
    # TODO account other pseudo-perovskites e.g. Mn2O3 or binary-metal ones
    if tilde_obj.info['elements'][0] in ['W', 'Re'] and len(tilde_obj.info['elements']) == 2:
        if round(D_prop) == 3: tilde_obj.info['tags'].append(0x4)
        return tilde_obj

    if not A_site or not B_site: return tilde_obj

    if not 1.3 < D_prop < 2.3: return tilde_obj # D_prop grows for 2D adsorption cases (>1.9)

    n_combs, n_offs = 0, 0
    for A in A_site:
        for B in B_site:
            if B == A: continue
            for C in C_site:
                rA = covalent_radii[chemical_symbols.index(A)]
                rB = covalent_radii[chemical_symbols.index(B)]
                rC = covalent_radii[chemical_symbols.index(C)]

                # Goldschmidt tolerance factor
                # t = (rA + rC) / sqrt(2) * (rB + rC)
                # 0.71 =< t =< 1.2
                # t < 0.71 ilmenite, corundum or KNbO3 structure
                # t > 1 hexagonal perovskite polytypes
                # http://en.wikipedia.org/wiki/Goldschmidt_tolerance_factor
                factor = (rA + rC) / (math.sqrt(2) * (rB + rC))
                if not 0.71 <= factor <= 1.4: n_offs += 1
                n_combs += 1
    if n_offs == n_combs: return tilde_obj

    tilde_obj.info['tags'].append(0x4)

    if tilde_obj.structures[-1].periodicity != 3: return tilde_obj # all below is for 3d case : TODO

    contents = []
    impurities, A_hosts, B_hosts = {}, {}, {}

    # What is a defect?
    # Empirical criteria of defect for ab initio modeling: =< 25% of the content
    for n, i in enumerate(tilde_obj.info['elements']):
        contents.append( [n, i, float(tilde_obj.info['contents'][n])/sum(tilde_obj.info['contents'])] )
    contents = sorted(contents, key = lambda i: i[2])

    for num in range(len(contents)):
        try: contents[num+1]
        except IndexError: break

        # defect content differs at least 2x from the smallest content; defect partial weight <= 1/16
        if contents[num][2] <= 0.0625 and contents[num][2] / contents[num+1][2] <= 0.5:
            impurities[ contents[num][1] ] = tilde_obj.info['contents'][ contents[num][0] ] # ex: ['Fe', 2]

        elif contents[num][1] in Perovskite_Structure.A:
            A_hosts[ contents[num][1] ] = tilde_obj.info['contents'][ contents[num][0] ]

        elif contents[num][1] in Perovskite_Structure.B:
            B_hosts[ contents[num][1] ] = tilde_obj.info['contents'][ contents[num][0] ]

    #print impurities, A_hosts, B_hosts

    if len(A_hosts) > 1 or len(B_hosts) > 1: return tilde_obj # skip complex perovskites and those where an element may occupy either A or B

    # A site or B site?
    num = 0
    for impurity_element, content in six.iteritems(impurities):
        e = tilde_obj.info['elements'].index(impurity_element)
        tilde_obj.info['elements'].pop(e) # TODO
        tilde_obj.info['contents'].pop(e) # TODO
        tilde_obj.info['impurity' + str(num)] = impurity_element + str(content) if content > 1 else impurity_element
        num += 1
        if impurity_element in Perovskite_Structure.A: A_hosts[A_hosts.keys()[0]] += content
        elif impurity_element in Perovskite_Structure.B: B_hosts[B_hosts.keys()[0]] += content

    for n, i in enumerate(tilde_obj.info['elements']):
        if i in A_hosts:
            tilde_obj.info['contents'][n] = A_hosts[i] # TODO
        elif i in B_hosts:
            tilde_obj.info['contents'][n] = B_hosts[i] # TODO

    for i in C_site:
        c_content = tilde_obj.info['contents'][ tilde_obj.info['elements'].index(i) ]
        tot_content = sum(tilde_obj.info['contents'])
        D_O = float(c_content) / tot_content
        if D_O < 0.6: # C-site lack
            tilde_obj.info['lack'] = i
            break # TODO

    return tilde_obj
Ejemplo n.º 38
0
def write_lammps_data(filename, atoms, atom_types, comment=None, cutoff=None,
                      molecule_ids=None, charges=None, units='metal',
                      bond_types=None, angle_types=None, dihedral_types=None):

    if isinstance(filename, basestring):
        fh = open(filename, 'w')
    else:
        fh = filename

    if comment is None:
        comment = 'lammpslib autogenerated data file'
    fh.write(comment.strip() + '\n\n')

    fh.write('{0} atoms\n'.format(len(atoms)))
    fh.write('{0} atom types\n'.format(len(atom_types)))

    if bond_types:
        from matscipy.neighbours import neighbour_list
        i_list, j_list = neighbour_list('ij', atoms, cutoff)
        print 'Bonds:'
        bonds = []
        for bond_type, (Z1, Z2) in enumerate(bond_types):
            bond_mask = (atoms.numbers[i_list] == Z1) & (atoms.numbers[j_list] == Z2)
            print (Z1, Z2), bond_mask.sum()
            for (I, J) in zip(i_list[bond_mask], j_list[bond_mask]):
                #NB: LAMMPS uses 1-based indices for bond types and particle indices
                bond = (bond_type+1, I+1, J+1)
                bonds.append(bond)
        print
        if len(bonds) > 0:
            fh.write('{0} bonds\n'.format(len(bonds)))
            fh.write('{0} bond types\n'.format(len(bond_types)))

    if angle_types:
        print 'Angles:'
        angle_count = { angle : 0 for angle in angle_types }
        angles = []
        for I in range(len(atoms)):
            for J in j_list[i_list == I]:
                for K in j_list[i_list == J]:
                    if J < K:
                        continue
                    Zi, Zj, Zk = atoms.numbers[[I, J, K]]
                    if (Zj, Zi, Zk) in angle_types:
                        angle = (angle_types.index((Zj, Zi, Zk))+1, J+1, I+1, K+1)
                        angle_count[(Zj, Zi, Zk)] += 1
                        angles.append(angle)
        for angle in angle_types:
            print angle, angle_count[angle]
        print
        if len(angles) > 0:
            fh.write('{0} angles\n'.format(len(angles)))
            fh.write('{0} angle types\n'.format(len(angle_types)))

    if dihedral_types:
        print 'Dihedrals:'
        dihedral_count = { dihedral : 0 for dihedral in dihedral_types }
        dihedrals = []
        for I in range(len(atoms)):
            for J in j_list[i_list == I]:
                for K in j_list[i_list == J]:
                    for L in j_list[i_list == K]:
                        Zi, Zj, Zk, Zl = atoms.numbers[[I, J, K, L]]
                        if (Zi, Zj, Zk, Zl) in dihedral_types:
                            dihedral = (dihedral_types.index((Zi, Zj, Zk, Zl))+1,
                                        I+1, J+1, K+1, L+1)
                            dihedral_count[(Zi, Zj, Zk, Zl)] += 1
                            dihedrals.append(dihedral)
        for dihedral in dihedral_types:
            print dihedral, dihedral_count[dihedral]
        print
        if len(dihedrals) > 0:
            fh.write('{0} dihedrals\n'.format(len(dihedrals)))
            fh.write('{0} dihedral types\n'.format(len(dihedral_types)))

    fh.write('\n')
    cell, coord_transform = convert_cell(atoms.get_cell())
    fh.write('{0:16.8e} {1:16.8e} xlo xhi\n'.format(0.0, cell[0, 0]))
    fh.write('{0:16.8e} {1:16.8e} ylo yhi\n'.format(0.0, cell[1, 1]))
    fh.write('{0:16.8e} {1:16.8e} zlo zhi\n'.format(0.0, cell[2, 2]))
    fh.write('{0:16.8e} {1:16.8e} {2:16.8e} xy xz yz\n'.format(cell[0, 1], cell[0, 2], cell[1, 2]))

    fh.write('\nMasses\n\n')
    sym_mass = {}
    masses = atoms.get_masses()
    symbols = atoms.get_chemical_symbols()
    for sym in atom_types:
        for i in range(len(atoms)):
            if symbols[i] == sym:
                sym_mass[sym] = masses[i] / unit_convert("mass", units)
                break
            else:
                sym_mass[sym] = atomic_masses[chemical_symbols.index(sym)] / unit_convert("mass", units)

    for (sym, typ) in sorted(atom_types.items(), key=operator.itemgetter(1)):
        fh.write('{0} {1}\n'.format(typ, sym_mass[sym]))

    fh.write('\nAtoms # full\n\n')
    if molecule_ids is None:
        molecule_ids = np.zeros(len(atoms), dtype=int)
    if charges is None:
        charges = atoms.get_initial_charges()
    for i, (sym, mol, q, pos) in enumerate(zip(symbols, molecule_ids,
                                               charges, atoms.get_positions())):
        typ = atom_types[sym]
        fh.write('{0} {1} {2} {3:16.8e} {4:16.8e} {5:16.8e} {6:16.8e}\n'
                 .format(i+1, mol, typ, q, pos[0], pos[1], pos[2]))

    if bond_types and len(bonds) > 0:
        fh.write('\nBonds\n\n')
        for idx, bond in enumerate(bonds):
            fh.write('{0} {1} {2} {3}\n'
                     .format(*[idx+1] + list(bond)))

    if angle_types and len(angles) > 0:
        fh.write('\nAngles\n\n')
        for idx, angle in enumerate(angles):
            fh.write('{0} {1} {2} {3} {4}\n'
                     .format(*[idx+1] + list(angle)))

    if dihedral_types and len(dihedrals) > 0:
        fh.write('\nDihedrals\n\n')
        for idx, dihedral in enumerate(dihedrals):
            fh.write('{0} {1} {2} {3} {4} {5}\n'
                     .format(*[idx+1] + list(dihedral)))

    if isinstance(filename, basestring):
        fh.close()
Ejemplo n.º 39
0
    def write_lammps_atoms(self, atoms, connectivities):
        """Write atoms input for LAMMPS"""

        fname = self.prefix + '_atoms'
        fileobj = open(fname, 'w')

        # header
        fileobj.write(fileobj.name + ' (by ' + str(self.__class__) + ')\n\n')
        fileobj.write(str(len(atoms)) + ' atoms\n')
        fileobj.write(str(len(atoms.types)) + ' atom types\n')
        blist = connectivities['bonds']
        if len(blist):
            btypes = connectivities['bond types']
            fileobj.write(str(len(blist)) + ' bonds\n')
            fileobj.write(str(len(btypes)) + ' bond types\n')
        alist = connectivities['angles']
        if len(alist):
            atypes = connectivities['angle types']
            fileobj.write(str(len(alist)) + ' angles\n')
            fileobj.write(str(len(atypes)) + ' angle types\n')
        dlist = connectivities['dihedrals']
        if len(dlist):
            dtypes = connectivities['dihedral types']
            fileobj.write(str(len(dlist)) + ' dihedrals\n')
            fileobj.write(str(len(dtypes)) + ' dihedral types\n')

        # cell
        p = Prism(atoms.get_cell())
        xhi, yhi, zhi, xy, xz, yz = p.get_lammps_prism_str()
        fileobj.write('\n0.0 %s  xlo xhi\n' % xhi)
        fileobj.write('0.0 %s  ylo yhi\n' % yhi)
        fileobj.write('0.0 %s  zlo zhi\n' % zhi)

        # atoms
        fileobj.write('\nAtoms\n\n')
        tag = atoms.get_tags()
        if atoms.has('molid'):
            molid = atoms.get_array('molid')
        else:
            molid = [1] * len(atoms)
        for i, r in enumerate(map(p.pos_to_lammps_str,
                                  atoms.get_positions())):
            q = self.data['one'][atoms.types[tag[i]]][2]
            fileobj.write('%6d %3d %3d %s %s %s %s' % ((i + 1, molid[i],
                                                        tag[i] + 1,
                                                        q)
                                                       + tuple(r)))
            fileobj.write(' # ' + atoms.types[tag[i]] + '\n')

        # velocities
        velocities = atoms.get_velocities()
        if velocities is not None:
            fileobj.write('\nVelocities\n\n')
            for i, v in enumerate(velocities):
                fileobj.write('%6d %g %g %g\n' %
                              (i + 1, v[0], v[1], v[2]))

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write('%6d %g # %s -> %s\n' %
                          (i + 1,
                           atomic_masses[chemical_symbols.index(cs)],
                           typ, cs))

        # bonds
        if len(blist):
            fileobj.write('\nBonds\n\n')
            for ib, bvals in enumerate(blist):
                fileobj.write('%8d %6d %6d %6d ' %
                              (ib + 1, bvals[0] + 1, bvals[1] + 1,
                               bvals[2] + 1))
                try:
                    fileobj.write('# ' + btypes[bvals[0]])
                except:
                    pass
                fileobj.write('\n')

        # angles
        if len(alist):
            fileobj.write('\nAngles\n\n')
            for ia, avals in enumerate(alist):
                fileobj.write('%8d %6d %6d %6d %6d ' %
                              (ia + 1, avals[0] + 1,
                               avals[1] + 1, avals[2] + 1, avals[3] + 1))
                try:
                    fileobj.write('# ' + atypes[avals[0]])
                except:
                    pass
                fileobj.write('\n')

        # dihedrals
        if len(dlist):
            fileobj.write('\nDihedrals\n\n')
            for i, dvals in enumerate(dlist):
                fileobj.write('%8d %6d %6d %6d %6d %6d ' %
                              (i + 1, dvals[0] + 1,
                               dvals[1] + 1, dvals[2] + 1,
                               dvals[3] + 1, dvals[4] + 1))
                try:
                    fileobj.write('# ' + dtypes[dvals[0]])
                except:
                    pass
                fileobj.write('\n')
Ejemplo n.º 40
0
def write_cfg(f, a):
    """Write atomic configuration to a CFG-file (native AtomEye format).
       See: http://mt.seas.upenn.edu/Archive/Graphics/A/
    """
    if isinstance(f, basestring):
        f = paropen(f, 'w')
    if isinstance(a, list):
        if len(a) == 1:
            a = a[0]
        else:
            raise RuntimeError('Cannot write sequence to single .cfg file.')

    f.write('Number of particles = %i\n' % len(a))
    f.write('A = 1.0 Angstrom\n')
    cell = a.get_cell(complete=True)
    for i in range(3):
        for j in range(3):
            f.write('H0(%1.1i,%1.1i) = %f A\n' % (i + 1, j + 1, cell[i, j]))

    entry_count = 3
    for x in a.arrays.keys():
        if x not in cfg_default_fields:
            if len(a.get_array(x).shape) == 1:
                entry_count += 1
            else:
                entry_count += a.get_array(x).shape[1]

    vels = a.get_velocities()
    if isinstance(vels, np.ndarray):
        entry_count += 3
    else:
        f.write('.NO_VELOCITY.\n')

    f.write('entry_count = %i\n' % entry_count)

    i = 0
    for name, aux in a.arrays.items():
        if name not in cfg_default_fields:
            if len(aux.shape) == 1:
                f.write('auxiliary[%i] = %s [a.u.]\n' % (i, name))
                i += 1
            else:
                if aux.shape[1] == 3:
                    for j in range(3):
                        f.write('auxiliary[%i] = %s_%s [a.u.]\n' %
                                (i, name, chr(ord('x') + j)))
                        i += 1

                else:
                    for j in range(aux.shape[1]):
                        f.write('auxiliary[%i] = %s_%1.1i [a.u.]\n' %
                                (i, name, j))
                        i += 1

    # Distinct elements
    spos = a.get_scaled_positions()
    for i in a:
        el = i.symbol

        f.write('%f\n' % ase.data.atomic_masses[chemical_symbols.index(el)])
        f.write('%s\n' % el)

        x, y, z = spos[i.index, :]
        s = '%e %e %e ' % (x, y, z)

        if isinstance(vels, np.ndarray):
            vx, vy, vz = vels[i.index, :]
            s = s + ' %e %e %e ' % (vx, vy, vz)

        for name, aux in a.arrays.items():
            if name not in cfg_default_fields:
                if len(aux.shape) == 1:
                    s += ' %e' % aux[i.index]
                else:
                    s += (aux.shape[1] * ' %e') % tuple(aux[i.index].tolist())

        f.write('%s\n' % s)
Ejemplo n.º 41
0
def bdplotter(task, **kwargs):
    '''
    bdplotter is based on the fact that phonon DOS/bands and
    electron DOS/bands are the objects of the same kind.
    1) DOS is formatted precomputed / smeared according to a normal distribution
    2) bands are formatted precomputed / interpolated through natural cubic spline function
    '''
    if task == 'bands': # CRYSTAL, "VASP", EXCITING

        results = []

        if 'precomputed' in kwargs:
            for n in range(len(kwargs['precomputed']['ticks'])):
                if kwargs['precomputed']['ticks'][n][1] == 'GAMMA': kwargs['precomputed']['ticks'][n][1] = '&#915;'

            for stripe in kwargs['precomputed']['stripes']:
                results.append({'color':'#000000', 'data':[], 'ticks':kwargs['precomputed']['ticks']})
                for n, val in enumerate(stripe):
                    results[-1]['data'].append([ kwargs['precomputed']['abscissa'][n], val])

        else:
            if not 'order' in kwargs: order = sorted( kwargs['values'].keys() ) # TODO
            else: order = kwargs['order']

            nullstand = '0 0 0'
            if not '0 0 0' in kwargs['values']: # possible case when there is shifted Gamma point
                nullstand = order[0]

            # reduce k if too much
            if len(order)>20:
                red_order = []
                for i in range(0, len(order), int(math.floor(len(order)/10))):
                    red_order.append(order[i])
                order = red_order

            for N in range(len( kwargs['values'][nullstand] )):
                # interpolate for each curve throughout the BZ
                results.append({'color':'#000000', 'data':[], 'ticks':[]})
                d = 0.0
                x = []
                y = []
                bz_vec_ref = [0, 0, 0]

                for bz in order:
                    y.append( kwargs['values'][bz][N] )
                    bz_coords = map(frac2float, bz.split() )
                    bz_vec_cur = dot( bz_coords, linalg.inv( kwargs['xyz_matrix'] ).transpose() )
                    bz_vec_dir = map(sum, zip(bz_vec_cur, bz_vec_ref))
                    bz_vec_ref = bz_vec_cur
                    d += linalg.norm( bz_vec_dir )
                    x.append(d)
                    results[-1]['ticks'].append( [d, bz.replace(' ', '')] )

                # end in nullstand point (normally, Gamma)
                #y.append(kwargs['values'][nullstand][N])
                #if d == 0: d+=0.5
                #else: d += linalg.norm( bz_vec_ref )
                #x.append(d)
                #results[-1]['ticks'].append( [d, nullstand.replace(' ', '')] )

                divider = 10 if len(order)<10 else 1.5
                step = (max(x)-min(x)) / len(kwargs['values']) / divider

                xnew = arange(min(x), max(x)+step/2, step).tolist()
                ynew = []
                f = NaturalCubicSpline( array(x), array(y) )
                for i in xnew:
                    results[-1]['data'].append([ round(  i, 3  ), round(  f(i), 3  ) ]) # round to reduce output

        return results

    elif task == 'dos': # CRYSTAL, VASP, EXCITING

        results = []

        if 'precomputed' in kwargs:
            total_dos = [[i, kwargs['precomputed']['total'][n]] for n, i in enumerate(kwargs['precomputed']['x'])]

        else:
            tdos = TotalDos( kwargs['eigenvalues'], sigma=kwargs['sigma'] )
            tdos.set_draw_area(omega_min=kwargs['omega_min'], omega_max=kwargs['omega_max'], omega_pitch=kwargs['omega_pitch'])
            total_dos = tdos.calculate()

        results.append({'label':'total', 'color': '#000000', 'data': total_dos})

        if 'precomputed' in kwargs:
            partial_doses = []
            for k in kwargs['precomputed'].keys():
                if k in ['x', 'total']: continue
                partial_doses.append({ 'label': k, 'data': [[i, kwargs['precomputed'][k][n]] for n, i in enumerate(kwargs['precomputed']['x'])] })

        elif 'impacts' in kwargs and 'atomtypes' in kwargs:
            # get the order of atoms to evaluate their partial impact
            labels = {}
            types = []
            index, subtractor = 0, 0
            for k, atom in enumerate(kwargs['atomtypes']): # determine the order of atoms for the partial impact of every type
                if atom not in labels:
                    #if atom == 'X' and not calc.phonons: # artificial GHOST case for phonons, decrease atomic index
                    #    subtractor += 1
                    #    continue
                    labels[atom] = index
                    types.append([k+1-subtractor])
                    index += 1
                else:
                    types[ labels[atom] ].append(k+1-subtractor)

            pdos = PartialDos( kwargs['eigenvalues'], kwargs['impacts'], sigma=kwargs['sigma'] )
            pdos.set_draw_area(omega_min=kwargs['omega_min'], omega_max=kwargs['omega_max'], omega_pitch=kwargs['omega_pitch'])
            partial_doses = pdos.calculate( types, labels )

            # add colors to partials
            for i in range(len(partial_doses)):
                if partial_doses[i]['label'] == 'X': color = '#000000'
                elif partial_doses[i]['label'] == 'H': color = '#CCCCCC'
                else:
                    try: color = jmol_to_hex( jmol_colors[ chemical_symbols.index(partial_doses[i]['label']) ] )
                    except ValueError: color = '#FFCC66'
                partial_doses[i].update({'color': color})
            results.extend(partial_doses)

        return results
Ejemplo n.º 42
0
    def save(self, calc, session):
        '''
        Saves tilde_obj into the database
        NB: this is the PUBLIC method
        @returns checksum, error
        '''
        checksum = calc.get_checksum()

        try:
            existing_calc = session.query(model.Calculation).filter(model.Calculation.checksum == checksum).one()
        except NoResultFound:
            pass
        else:
            del calc
            return None, "This calculation already exists!"

        if not calc.download_size:
            for f in calc.related_files:
                calc.download_size += os.stat(f).st_size

        ormcalc = model.Calculation(checksum = checksum)

        if calc._calcset:
            ormcalc.meta_data = model.Metadata(chemical_formula = calc.info['standard'], download_size = calc.download_size)

            for child in session.query(model.Calculation).filter(model.Calculation.checksum.in_(calc._calcset)).all():
                ormcalc.children.append(child)
            ormcalc.siblings_count = len(ormcalc.children)
            ormcalc.nested_depth = calc._nested_depth

        else:
            # prepare phonon data for saving
            # this is actually a dict to list conversion TODO re-structure this
            if calc.phonons['modes']:
                phonons_json = []

                for bzpoint, frqset in calc.phonons['modes'].items():
                    # re-orientate eigenvectors
                    for i in range(0, len(calc.phonons['ph_eigvecs'][bzpoint])):
                        for j in range(0, len(calc.phonons['ph_eigvecs'][bzpoint][i])//3):
                            eigv = array([calc.phonons['ph_eigvecs'][bzpoint][i][j*3], calc.phonons['ph_eigvecs'][bzpoint][i][j*3+1], calc.phonons['ph_eigvecs'][bzpoint][i][j*3+2]])
                            R = dot( eigv, calc.structures[-1].cell ).tolist()
                            calc.phonons['ph_eigvecs'][bzpoint][i][j*3], calc.phonons['ph_eigvecs'][bzpoint][i][j*3+1], calc.phonons['ph_eigvecs'][bzpoint][i][j*3+2] = [round(x, 3) for x in R]

                    try: irreps = calc.phonons['irreps'][bzpoint]
                    except KeyError:
                        empty = []
                        for i in range(len(frqset)):
                            empty.append('')
                        irreps = empty

                    phonons_json.append({  'bzpoint':bzpoint, 'freqs':frqset, 'irreps':irreps, 'ph_eigvecs':calc.phonons['ph_eigvecs'][bzpoint]  })
                    if bzpoint == '0 0 0':
                        phonons_json[-1]['ir_active'] = calc.phonons['ir_active']
                        phonons_json[-1]['raman_active'] = calc.phonons['raman_active']
                    if calc.phonons['ph_k_degeneracy']:
                        phonons_json[-1]['ph_k_degeneracy'] = calc.phonons['ph_k_degeneracy'][bzpoint]

                ormcalc.phonons = model.Phonons()
                ormcalc.spectra.append( model.Spectra(kind = model.Spectra.PHONON, eigenvalues = json.dumps(phonons_json)) )

            # prepare electron data for saving TODO re-structure this
            for task in ['dos', 'bands']: # projected?
                if calc.electrons[task]:
                    calc.electrons[task] = calc.electrons[task].todict()

            if calc.electrons['dos'] or calc.electrons['bands']:
                ormcalc.electrons = model.Electrons(gap = calc.info['bandgap'])
                if 'bandgaptype' in calc.info:
                    ormcalc.electrons.is_direct = 1 if calc.info['bandgaptype'] == 'direct' else -1
                ormcalc.spectra.append(model.Spectra(
                    kind = model.Spectra.ELECTRON,
                    dos = json.dumps(calc.electrons['dos']),
                    bands = json.dumps(calc.electrons['bands']),
                    projected = json.dumps(calc.electrons['projected']),
                    eigenvalues = json.dumps(calc.electrons['eigvals'])
                ))

            # construct ORM for other props
            calc.related_files = list(map(virtualize_path, calc.related_files))
            ormcalc.meta_data = model.Metadata(location = calc.info['location'], finished = calc.info['finished'], raw_input = calc.info['input'], modeling_time = calc.info['duration'], chemical_formula = html_formula(calc.info['standard']), download_size = calc.download_size, filenames = json.dumps(calc.related_files))

            codefamily = model.Codefamily.as_unique(session, content = calc.info['framework'])
            codeversion = model.Codeversion.as_unique(session, content = calc.info['prog'])

            codeversion.instances.append( ormcalc.meta_data )
            codefamily.versions.append( codeversion )

            pot = model.Pottype.as_unique(session, name = calc.info['H'])
            pot.instances.append(ormcalc)
            ormcalc.recipinteg = model.Recipinteg(kgrid = calc.info['k'], kshift = calc.info['kshift'], smearing = calc.info['smear'], smeartype = calc.info['smeartype'])
            ormcalc.basis = model.Basis(kind = calc.info['ansatz'], content = json.dumps(calc.electrons['basis_set']) if calc.electrons['basis_set'] else None)
            ormcalc.energy = model.Energy(convergence = json.dumps(calc.convergence), total = calc.info['energy'])

            ormcalc.spacegroup = model.Spacegroup(n=calc.info['ng'])
            ormcalc.struct_ratios = model.Struct_ratios(chemical_formula=calc.info['standard'], formula_units=calc.info['expanded'], nelem=calc.info['nelem'], dimensions=calc.info['dims'])
            if len(calc.tresholds) > 1:
                ormcalc.struct_optimisation = model.Struct_optimisation(tresholds=json.dumps(calc.tresholds), ncycles=json.dumps(calc.ncycles))

            for n, ase_repr in enumerate(calc.structures):
                is_final = True if n == len(calc.structures)-1 else False
                struct = model.Structure(step = n, final = is_final)

                s = cell_to_cellpar(ase_repr.cell)
                struct.lattice = model.Lattice(a=s[0], b=s[1], c=s[2], alpha=s[3], beta=s[4], gamma=s[5], a11=ase_repr.cell[0][0], a12=ase_repr.cell[0][1], a13=ase_repr.cell[0][2], a21=ase_repr.cell[1][0], a22=ase_repr.cell[1][1], a23=ase_repr.cell[1][2], a31=ase_repr.cell[2][0], a32=ase_repr.cell[2][1], a33=ase_repr.cell[2][2])

                #rmts =      ase_repr.get_array('rmts') if 'rmts' in ase_repr.arrays else [None for j in range(len(ase_repr))]
                charges =   ase_repr.get_array('charges') if 'charges' in ase_repr.arrays else [None for j in range(len(ase_repr))]
                magmoms =   ase_repr.get_array('magmoms') if 'magmoms' in ase_repr.arrays else [None for j in range(len(ase_repr))]
                for n, i in enumerate(ase_repr):
                    struct.atoms.append( model.Atom( number=chemical_symbols.index(i.symbol), x=i.x, y=i.y, z=i.z, charge=charges[n], magmom=magmoms[n] ) )

                ormcalc.structures.append(struct)
            # TODO Forces

        ormcalc.uigrid = model.Grid(info=json.dumps(calc.info))

        # tags ORM
        uitopics = []
        for entity in self.hierarchy:

            if not entity['creates_topic']:
                continue

            if entity['multiple'] or calc._calcset:
                for item in calc.info.get( entity['source'], [] ):
                    uitopics.append( model.topic(cid=entity['cid'], topic=item) )
            else:
                topic = calc.info.get(entity['source'])
                if topic or not entity['optional']:
                    uitopics.append( model.topic(cid=entity['cid'], topic=topic) )

        uitopics = [model.Topic.as_unique(session, cid=x.cid, topic="%s" % x.topic) for x in uitopics]

        ormcalc.uitopics.extend(uitopics)

        if calc._calcset:
            session.add(ormcalc)
        else:
            session.add_all([codefamily, codeversion, pot, ormcalc])

        session.commit()
        del calc, ormcalc
        return checksum, None