Exemplo n.º 1
0
    def extract(s, force_recalc, sites, custom_symbol):

        # First, we need the molecules
        if Molecules.default_name not in s.info or force_recalc:
            Molecules.get(s)
        mols = s.info[Molecules.default_name]

        elems = s.get_chemical_symbols()

        if sites is None:
            sites = range(len(s))

        labels = []

        for s_i in sites:
            # Find the molecule that it belongs to
            s_mol = [m for m in mols if s_i in m.indices][0]
            s_elems = np.array(elems, dtype='S2')
            if custom_symbol is not None:
                s_elems[s_i] = custom_symbol
            # Grab the bonds
            bonds = s_mol.get_array(Bonds.default_name)
            # This is a necessary step since the bonds are not classified
            # by original structure index yet
            bonds = {a: bonds[i] for i, a in enumerate(s_mol.indices)}
            labels.append(recursive_mol_label(s_i, s_mol.indices, 
                                              bonds, s_elems))

        return labels
Exemplo n.º 2
0
    def test_molneigh(self):

        metmol = molecule('CH4')

        cellmol = metmol.copy()
        cellmol.set_pbc(True)
        cellmol.set_cell([6, 6, 6])
        c2 = cellmol.copy()
        c2.set_positions(c2.get_positions() + 3)
        cellmol += c2

        mols = Molecules.get(cellmol)
        mol_i = [i for i, m in enumerate(mols) if 0 in m.indices][0]

        mnGen = molecularNeighbourhoodGen(cellmol, mols, max_R=5.2)
        all_neigh = [a for a in mnGen]

        self.assertEqual(len(all_neigh), 9)
        self.assertAlmostEqual(
            all_neigh[0].info['neighbourhood_info']['molecule_distance'], 0)
        self.assertAlmostEqual(
            all_neigh[1].info['neighbourhood_info']['molecule_distance'],
            3**1.5)

        mnGen = molecularNeighbourhoodGen(cellmol,
                                          mols,
                                          max_R=5,
                                          method='nearest')
        all_neigh = [a for a in mnGen]

        self.assertEqual(len(all_neigh), 9)
Exemplo n.º 3
0
    def extract(s, force_recalc, save_info):

        # First, we need the molecules
        if Molecules.default_name not in s.info or force_recalc:
            Molecules.get(s)

        # Then the hydrogen bonds
        if HydrogenBonds.default_name not in s.info or force_recalc:
            HydrogenBonds.get(s)

        # Finally the sites
        if MoleculeSites.default_name not in s.info or force_recalc:
            MoleculeSites.get(s)

        mols = s.info[Molecules.default_name]
        hbonds = s.info[HydrogenBonds.default_name]
        all_sites = s.info[MoleculeSites.default_name]

        hblabels = []
        for hbtype in hbonds:
            for hb in hbonds[hbtype]:
                A_i = hb['A'][0]
                H_i = hb['H']
                B_i = hb['B'][0]

                # Check in which molecule they are
                AH_sites = None
                B_sites = None
                for m_i, m in enumerate(mols):
                    if A_i in m:
                        AH_sites = all_sites[m_i]
                    if B_i in m:
                        B_sites = all_sites[m_i]

                if AH_sites is None or B_sites is None:
                    raise RuntimeError('Invalid hydrogen bond detected')

                # Now build the proper definition
                hblabel = ('{0}<{1},{2}>'
                           '..{3}<{4}>').format(AH_sites['name'],
                                                AH_sites['sites'][A_i],
                                                AH_sites['sites'][H_i],
                                                B_sites['name'],
                                                B_sites['sites'][B_i])
                hblabels.append(hblabel)

        return sorted(hblabels)
Exemplo n.º 4
0
    def test_linkageprops(self):

        from soprano.properties.linkage import (LinkageList, Bonds,
                                                Molecules, MoleculeNumber,
                                                MoleculeMass,
                                                MoleculeCOMLinkage,
                                                MoleculeRelativeRotation,
                                                MoleculeSpectralSort,
                                                CoordinationHistogram,
                                                HydrogenBonds,
                                                HydrogenBondsNumber)

        from soprano.properties.transform import Rotate

        a = read(os.path.join(_TESTDATA_DIR, 'mol_crystal.cif'))

        # Test bonds
        testAtoms = Atoms(['C', 'C', 'C', 'C'],
                          cell=[5, 5, 5],
                          positions=np.array([[0, 0, 0],
                                              [4, 0, 0],
                                              [3, 3, 3],
                                              [3, 3.5, 3]]),
                          pbc=True)
        testBonds = Bonds.get(testAtoms)
        self.assertTrue(testBonds[0][:2] == (0, 1))
        self.assertTrue(testBonds[1][:2] == (2, 3))
        self.assertTrue(np.all(testBonds[0][2] == (-1, 0, 0)))
        self.assertAlmostEqual(testBonds[0][3], 2*testBonds[1][3])

        # Also test coordination histogram
        coord_hist = CoordinationHistogram.get(a)
        # Testing some qualities of the Alanine crystal...
        self.assertTrue(coord_hist['H']['C'][1], 16)    # 16 H bonded to a C
        self.assertTrue(coord_hist['H']['N'][1], 12)    # 12 H bonded to a N
        self.assertTrue(coord_hist['C']['H'][3], 4)     # 4 CH3 groups
        self.assertTrue(coord_hist['C']['O'][2], 4)     # 4 COO groups

        # Test molecules
        mols = Molecules.get(a)

        self.assertTrue(MoleculeNumber.get(a) == 4)
        self.assertTrue(np.isclose(MoleculeMass.get(a), 89.09408).all())
        self.assertTrue(len(MoleculeCOMLinkage.get(a)) == 6)

        # Spectral sorting
        elems = np.array(a.get_chemical_symbols())
        mol_specsort = MoleculeSpectralSort.get(a)
        for i in range(len(mols)-1):
            for j in range(i+1,len(mols)):
                self.assertTrue((elems[mol_specsort[i].indices] ==
                                 elems[mol_specsort[j].indices]).all())

        # Now testing hydrogen bonds
        hbs = HydrogenBonds.get(a)
        hbn = HydrogenBondsNumber.get(a)

        self.assertTrue(hbn['NH..O'] == 12)
        self.assertTrue(hbn['OH..O'] == 0)
Exemplo n.º 5
0
    def extract(s, force_recalc, save_info, save_asarray):

        # First, we need the molecules
        if Molecules.default_name not in s.info or force_recalc:
            Molecules.get(s)

        elems = s.get_chemical_symbols()

        mol_sites = []

        for mol_i, mol in enumerate(s.info[Molecules.default_name]):

            # For each atom we do a depth-first traversal of the network
            sites = {}
            bonds = mol.get_array(Bonds.default_name)
            # This is a necessary step since the bonds are not classified
            # by original structure index yet
            bonds = {a: bonds[i] for i, a in enumerate(mol.indices)}
            for a in mol.indices:
                sites[a] = recursive_mol_label(a, mol.indices, bonds, elems)

            # Now grab the unique sites and pick the name of the molecule
            site_names = sorted(list(set(sites.values())))
            site_dict = {'name': site_names[0]}
            # Now rename the sites
            elem_sites = {}
            for a in sites:
                s_i = site_names.index(sites[a])
                if elems[a] not in elem_sites:
                    elem_sites[elems[a]] = [s_i]
                elif s_i not in elem_sites[elems[a]]:
                    elem_sites[elems[a]].append(s_i)
                sites[a] = '{0}_{1}'.format(elems[a],
                                            elem_sites[elems[a]].index(s_i)+1)

            site_dict['sites'] = sites
            mol_sites.append(site_dict)

            if save_asarray:
                arr = [sites[a] for a in mol.indices]
                mol.set_array(MoleculeSites.default_name, arr)

        if save_info:
            s.info[MoleculeSites.default_name] = mol_sites

        return mol_sites
Exemplo n.º 6
0
    def extract(s, force_recalc, save_info, save_asarray):

        # First, we need the molecules
        if Molecules.default_name not in s.info or force_recalc:
            Molecules.get(s)

        elems = s.get_chemical_symbols()

        def recursive_label(i, bonds, to_visit):
            # Remove from to_visit
            if i in to_visit:
                to_visit.remove(i)
            else:
                return None
            my_bonds = sorted([b for b in bonds[i] if b in to_visit])
            if len(my_bonds) > 0:
                bonded_label = sorted(
                    [recursive_label(j, bonds, to_visit) for j in my_bonds])
                bonded_label = [bl for bl in bonded_label if bl is not None]
                return '{0}[{1}]'.format(elems[i], ','.join(bonded_label))
            else:
                return '{0}'.format(elems[i])

        mol_sites = []

        for mol_i, mol in enumerate(s.info[Molecules.default_name]):

            # For each atom we do a depth-first traversal of the network
            sites = {}
            bonds = mol.get_array('bonds')
            # This is a necessary step since the bonds are not classified
            # by original structure index yet
            bonds = {a: bonds[i] for i, a in enumerate(mol.indices)}
            for a in mol.indices:
                to_visit = list(mol.indices)
                sites[a] = recursive_label(a, bonds, to_visit)

            # Now grab the unique sites and pick the name of the molecule
            site_names = sorted(list(set(sites.values())))
            site_dict = {'name': site_names[0]}
            # Now rename the sites
            elem_sites = {}
            for a in sites:
                s_i = site_names.index(sites[a])
                if elems[a] not in elem_sites:
                    elem_sites[elems[a]] = [s_i]
                elif s_i not in elem_sites[elems[a]]:
                    elem_sites[elems[a]].append(s_i)
                sites[a] = '{0}_{1}'.format(
                    elems[a], elem_sites[elems[a]].index(s_i) + 1)

            site_dict['sites'] = sites
            mol_sites.append(site_dict)

            if save_asarray:
                arr = [sites[a] for a in mol.indices]
                mol.set_array(MoleculeSites.default_name, arr)

        if save_info:
            s.info[MoleculeSites.default_name] = mol_sites

        return mol_sites
Exemplo n.º 7
0
def find_w99_atomtypes(s, force_recalc=False):
    """Calculate the W99 force field atom types for a given structure.

    | Parameters:
    |   s (ase.Atoms): the structure to calculate the atomtypes on
    |   force_recalc (bool): whether to recalculate the molecules even if
    |                        already present. Default is False.
    """

    # First, check that W99 even applies to this system
    chsyms = np.array(s.get_chemical_symbols())

    if not set(chsyms).issubset(set(['C', 'H', 'O', 'N'])):
        raise W99Error('Invalid system for use of W99 force field'
                       ' - System can only contain H, C, O and N!')

    if Molecules.default_name not in s.info or force_recalc:
        Molecules.get(s)

    mols = s.info['molecules']

    # Now the types!
    w99types = np.array(['XXX' for sym in chsyms])

    for m_i, m in enumerate(mols):

        inds = list(m.indices)
        bonds = m.get_array('bonds')
        msyms = chsyms[inds]

        for a_mi, a_i in enumerate(inds):
            # What element is it?
            el_i = msyms[a_mi]
            bnd_i = bonds[a_mi]
            if len(bnd_i) < 1:
                # Something's wrong
                raise W99Error('ERROR - W99 can not be applied to single'
                               ' atom molecular fragments')
            if el_i == 'H':
                # Hydrogen case
                if len(bnd_i) != 1:
                    raise W99Error('ERROR - Hydrogen with non-1 valence '
                                   'found')
                # What is it bonded to?
                nn_el = chsyms[bnd_i[0]]
                if nn_el == 'C':
                    w99types[a_i] = 'H_1'
                elif nn_el == 'N':
                    w99types[a_i] = 'H_4'
                elif nn_el == 'O':
                    # Alcoholic or carboxylic?
                    nn_mi = inds.index(bnd_i[0])
                    carbs = [b for b in bonds[nn_mi] if chsyms[b] == 'C']
                    if len(carbs) != 1:
                        raise W99Error('ERROR - Anomalous chemical group '
                                       'found')
                    c_mi = inds.index(carbs[0])
                    oxys = [
                        b for b in bonds[c_mi]
                        if chsyms[b] == 'O' and b != bnd_i[0]
                    ]
                    # What is it?
                    if len(oxys) == 1 and len(bonds[c_mi]) == 3:
                        # Carboxylic!
                        w99types[a_i] = 'H_3'
                    else:
                        # Alcoholic!
                        w99types[a_i] = 'H_2'
            elif el_i == 'C':
                # Carbon case
                val = len(bnd_i)
                if val > 1 and val < 5:
                    w99types[a_i] = 'C_{0}'.format(val)
                else:
                    raise W99Error('ERROR - Anomalous chemical group found')
            elif el_i == 'O':
                # Oxygen case
                val = len(bnd_i)
                if val > 0 and val < 3:
                    w99types[a_i] = 'O_{0}'.format(val)
                else:
                    raise W99Error('ERROR - Anomalous chemical group found')
            elif el_i == 'N':
                # Nitrogen case
                val = len(bnd_i)
                if val == 3:
                    w99types[a_i] = 'N_1'
                else:
                    # Count hydrogens
                    hydros = [b for b in bnd_i if chsyms[b] == 'H']
                    if len(hydros) == 0:
                        w99types[a_i] = 'N_2'
                    elif len(hydros) == 1:
                        w99types[a_i] = 'N_3'
                    else:
                        w99types[a_i] = 'N_4'

        m.set_array('w99_types', w99types[inds])

    s.set_array('w99_types', w99types)