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
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)
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)
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)
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
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
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)