#!/usr/bin/python # -*- coding: utf-8 -*- import sys, fileinput from math import pi, sqrt from collections import Counter from rdkit import Chem params = (('B30', 7.61, 2.91), ('Br10', 27.52, 8.44), ('C10', 14.68, 2.32), ('C20', 9.89, 4.01), ('C21', 22.77, 4.58), ('C30', -0.00, 3.15), ('C30a', -0.00, 3.48), ('C31', 13.23, 4.65), ('C31a', 13.23, 4.46), ('C32', 27.17, 5.38), ('C40', -8.40, 2.60), ('C41', 4.46, 3.48), ('C42', 16.57, 4.60), ('C43', 29.58, 5.74), ('Cl10', 24.74, 5.87), ('F10', 17.63, 1.06), ('Ge40', 9.36, 8.54), ('I10', 35.64, 13.75), ('N10', 14.09, 1.55), ('N20', 7.42, 2.60), ('N20a', 7.42, 2.44), ('N21', 18.14, 3.55), ('N30', -3.08, 2.89), ('N30a', -3.08, 2.85), ('N31', 7.74, 3.69), ('N31a', 7.74, 3.72), ('N32', 17.81, 4.60), ('N43', 5.36, 8.02), ('O10', 14.89, 1.84), ('O20', 6.25, 1.55), ('O20a', 6.25, 0.71), ('O21', 11.78, 2.51), ('P30', 10.42, 7.41), ('P40', -1.94, 4.98), ('P41', 10.06, 5.41), ('R5', 9.41, None), ('R6', 6.89, None), ('R<5', 10.89, None), ('R>6', 3.75, None), ('S10', 25.92, 10.60), ('S20', 14.90, 8.22), ('S20a', 14.90, 7.05), ('S21', 26.14, 8.71), ('S30', 5.58, 7.28), ('S40', -3.74, 5.12), ('Se20', 19.00, 11.53), ('Se20a', 19.00, 9.43), ('Si40', 9.28, 6.38), ('Si41', 23.35, 7.85), ('Sn40', 14.47, 14.90), ('Ti40', 6.09, 14.66), ('aromat', 1.82, None)) vi = dict((p[0], p[1]) for p in params) ri = dict((p[0], p[2]) for p in params) def get_atom_code(atom): """ return an atom code consistent with the keys of the 'Vinc' dictionary """ # be careful to take into account nD = number of deuterium atoms ! nD = len([x for x in atom.GetNeighbors() if x.GetMass()>2 and x.GetSymbol()=='H']) if nD > 0: print('nD %u %s' %(nD, arg)) code = atom.GetSymbol() + str(atom.GetTotalDegree()) + str(atom.GetTotalNumHs()+nD) code += 'a'*int(atom.GetIsAromatic()) return code def get_ring_descriptors(mol, maxi=6, mini=5): """ return dict of ring descriptors for molecule provided as input """ dic = Counter() ri = mol.GetRingInfo() for ring in ri.AtomRings(): size = len(ring) if size > maxi: label = 'R>'+str(maxi) elif size < mini: label = 'R<'+str(mini) else: label = 'R%u' %len(ring) dic[label] += 1 # contribute also +1 aromatic ring ? atoms = [mol.GetAtomWithIdx(i) for i in ring] if all(at.GetIsAromatic() for at in atoms): dic['aromat'] += 1 return dic if __name__ == "__main__": for smi in fileinput.input(): mol = Chem.MolFromSmiles(smi) atoms = Counter(get_atom_code(atom) for atom in mol.GetAtoms()) missing_atoms = set(atoms) - set(vi) if missing_atoms: print('Undefined atom parameters: %s' %' '.join(sorted(missing_atoms))) continue rings = get_ring_descriptors(mol) Vm = sum([atoms[k]*vi[k] for k in atoms]) # atoms contribution Vm += sum([rings[k]*vi[k] for k in rings]) # rings contribution RD = sum([atoms[k]*ri[k] for k in atoms]) # molar refraction nD = ((Vm+2*RD)/(Vm-RD))**0.5 print('%.2f,%.4f' %(Vm, nD))