Statistiques
| Branche: | Tag: | Révision :

dockonsurf / modules / isolated.py @ 082685ad

Historique | Voir | Annoter | Télécharger (7,69 ko)

1 4614bb6a Carles
"""Functions to generate the conformers to be adsorbed and the most stable one.
2 4614bb6a Carles

3 5c70d6c6 Carles
functions:
4 5c70d6c6 Carles
remove_C_linked_Hs: Removes hydrogens bonded to a carbon atom from a molecule.
5 92924d24 Carles
gen_confs: Generate a number of conformers in random orientations.
6 92924d24 Carles
get_rmsd: Gets the rmsd matrix of the conformers in a rdkit mol object.
7 92924d24 Carles
get_moments_of_inertia: Computes moments of inertia of the given conformers.
8 92924d24 Carles
mmff_opt_confs: Optimizes the geometry of the given conformers and returns the
9 92924d24 Carles
    new mol object and the energies of its conformers.
10 4614bb6a Carles
run_isolated: directs the execution of functions to achieve the goal
11 4614bb6a Carles
"""
12 4614bb6a Carles
import logging
13 4614bb6a Carles
14 92924d24 Carles
import numpy as np
15 fff3aab1 Carles
import rdkit.Chem.AllChem as Chem
16 92924d24 Carles
17 082685ad Carles Martí
from modules.calculation import check_finished_calcs
18 082685ad Carles Martí
from modules.refinement import select_confs
19 082685ad Carles Martí
from modules.formats import collect_coords
20 082685ad Carles Martí
21 4614bb6a Carles
logger = logging.getLogger('DockOnSurf')
22 4614bb6a Carles
23 4614bb6a Carles
24 92924d24 Carles
def remove_C_linked_Hs(mol: Chem.rdchem.Mol):
25 b1f6e69d Carles
    """Removes hydrogen atoms bonded to a carbon atom from a rdkit mol object.
26 5c70d6c6 Carles

27 92924d24 Carles
    @param mol: rdkit mol object of the molecule with hydrogen atoms.
28 92924d24 Carles
    @return: rdkit mol object of the molecule without hydrogen atoms linked to
29 92924d24 Carles
    a carbon atom.
30 92924d24 Carles

31 92924d24 Carles
    The functions removes the hydrogen atoms bonded to carbon atoms while
32 92924d24 Carles
    keeping the ones bonded to other atoms or non-bonded at all.
33 5c70d6c6 Carles
    """
34 5c70d6c6 Carles
35 5c70d6c6 Carles
    mol = Chem.RWMol(mol)
36 5c70d6c6 Carles
    rev_atm_idxs = [atom.GetIdx() for atom in reversed(mol.GetAtoms())]
37 5c70d6c6 Carles
38 5c70d6c6 Carles
    for atm_idx in rev_atm_idxs:
39 5c70d6c6 Carles
        atom = mol.GetAtomWithIdx(atm_idx)
40 5c70d6c6 Carles
        if atom.GetAtomicNum() != 1:
41 5c70d6c6 Carles
            continue
42 5c70d6c6 Carles
        for neigh in atom.GetNeighbors():
43 5c70d6c6 Carles
            if neigh.GetAtomicNum() == 6:
44 5c70d6c6 Carles
                mol.RemoveAtom(atom.GetIdx())
45 5c70d6c6 Carles
    return mol
46 5c70d6c6 Carles
47 5c70d6c6 Carles
48 3a46e515 Carles Marti
def gen_confs(mol: Chem.rdchem.Mol, num_confs: int):
49 92924d24 Carles
    """Generate conformers in random orientations.
50 4614bb6a Carles

51 4614bb6a Carles
    @param mol: rdkit mol object of the molecule to be adsorbed.
52 92924d24 Carles
    @param num_confs: number of conformers to randomly generate.
53 4614bb6a Carles
    @return: mol: rdkit mol object containing the different conformers.
54 bd573212 Carles
             rmsd_mtx: Matrix with the rmsd values of conformers.
55 b1f6e69d Carles

56 92924d24 Carles
    Using the rdkit library, conformers are randomly generated. If structures 
57 92924d24 Carles
    are required to be local minima, ie. setting the 'local_min' value to 
58 92924d24 Carles
    True, a geometry optimisation using UFF is performed.
59 4614bb6a Carles
    """
60 695dcff8 Carles Marti
    logger.debug('Generating Conformers.')
61 9e83b5a1 Carles
62 9324a38a Carles
    mol = Chem.AddHs(mol)
63 9062afa6 Carles Marti
    Chem.EmbedMultipleConfs(mol, numConfs=num_confs, numThreads=0,
64 9062afa6 Carles Marti
                            randomSeed=5817216)
65 5c70d6c6 Carles
    Chem.AlignMolConformers(mol)
66 695dcff8 Carles Marti
    logger.info(f'Generated {len(mol.GetConformers())} conformers.')
67 92924d24 Carles
    return mol
68 92924d24 Carles
69 62576f52 Carles
70 58ede1f9 Carles Martí
def get_moments_of_inertia(mol: Chem.rdchem.Mol):
71 92924d24 Carles
    """Computes the moments of inertia of the given conformers
72 92924d24 Carles

73 92924d24 Carles
    @param mol: rdkit mol object of the relevant molecule.
74 92924d24 Carles
    @return numpy array 2D: The inner array contains the moments of inertia for
75 92924d24 Carles
    the three principal axis of a given conformer. They are ordered by its value
76 92924d24 Carles
    in ascending order. The outer tuple loops over the conformers.
77 92924d24 Carles
    """
78 92924d24 Carles
    from rdkit.Chem.Descriptors3D import PMI1, PMI2, PMI3
79 92924d24 Carles
80 92924d24 Carles
    return np.array([[PMI(mol, confId=conf) for PMI in (PMI1, PMI2, PMI3)]
81 92924d24 Carles
                     for conf in range(mol.GetNumConformers())])
82 92924d24 Carles
83 92924d24 Carles
84 365d5b9a Carles Marti
def pre_opt_confs(mol: Chem.rdchem.Mol, force_field='mmff', max_iters=2000):
85 92924d24 Carles
    """Optimizes the geometry of the given conformers and returns the new mol
86 92924d24 Carles
    object and the energies of its conformers.
87 92924d24 Carles

88 92924d24 Carles
    @param mol: rdkit mol object of the relevant molecule.
89 ad57fd42 Carles Marti
    @param force_field: Force Field to use for the pre-optimization.
90 62576f52 Carles
    @param max_iters: Maximum number of geometry optimization iterations. With 0
91 62576f52 Carles
    a single point energy calculation is performed and only the conformer
92 62576f52 Carles
    energies are returned.
93 92924d24 Carles
    @return mol: rdkit mol object of the optimized molecule.
94 92924d24 Carles
    @return numpy.ndarray: Array with the energies of the optimized conformers.
95 92924d24 Carles

96 ad57fd42 Carles Marti
    The MMFF and UFF force fields can be used for the geometry optimization in
97 4670488d Carles Marti
    their rdkit implementation. With max_iters value set to 0, a single point
98 4670488d Carles Marti
    energy calculation is performed and only the energies are returned. For
99 4670488d Carles Marti
    values larger than 0, if the geometry does not converge for a certain
100 4670488d Carles Marti
    conformer, the latter is removed from the list of conformers and its energy
101 4670488d Carles Marti
    is not included in the returned list.
102 92924d24 Carles
    """
103 4670488d Carles Marti
    from rdkit.Chem.rdForceFieldHelpers import MMFFOptimizeMoleculeConfs, \
104 4670488d Carles Marti
        UFFOptimizeMoleculeConfs
105 92924d24 Carles
106 92924d24 Carles
    init_num_confs = mol.GetNumConformers()
107 ad57fd42 Carles Marti
    if force_field == 'mmff':
108 4670488d Carles Marti
        results = np.array(MMFFOptimizeMoleculeConfs(mol, numThreads=0,
109 4670488d Carles Marti
                                                     maxIters=max_iters,
110 4670488d Carles Marti
                                                     nonBondedThresh=10))
111 ad57fd42 Carles Marti
    elif force_field == 'uff':
112 4670488d Carles Marti
        results = np.array(UFFOptimizeMoleculeConfs(mol, numThreads=0,
113 4670488d Carles Marti
                                                    maxIters=max_iters,
114 4670488d Carles Marti
                                                    vdwThresh=10))
115 4670488d Carles Marti
    else:
116 4670488d Carles Marti
        logger.error("force_field parameter must be 'MMFF' or 'UFF'")
117 4670488d Carles Marti
        raise ValueError("force_field parameter must be 'MMFF' or 'UFF'")
118 62576f52 Carles
119 62576f52 Carles
    # Remove non-converged conformers if optimization is on, ie. maxIters > 0
120 62576f52 Carles
    # return all conformers if optimization is switched off, ie. maxIters = 0
121 62576f52 Carles
    if max_iters > 0:
122 62576f52 Carles
        for i, conv in enumerate(results[:, 0]):
123 62576f52 Carles
            if conv != 0:
124 62576f52 Carles
                mol.RemoveConformer(i)
125 62576f52 Carles
        for i, conf in enumerate(mol.GetConformers()):
126 62576f52 Carles
            conf.SetId(i)
127 62576f52 Carles
        if mol.GetNumConformers() < init_num_confs:
128 ad57fd42 Carles Marti
            logger.warning(f'Geometry optimization did not comverge for at'
129 62576f52 Carles
                           f'least one conformer. Continuing with '
130 695dcff8 Carles Marti
                           f'{mol.GetNumConformers()} converged conformers.')
131 ad57fd42 Carles Marti
        logger.info(f'Pre-optimized conformers with {force_field}.')
132 62576f52 Carles
        return mol, np.array([res[1] for res in results if res[0] == 0])
133 62576f52 Carles
    else:
134 ad57fd42 Carles Marti
        logger.info(f'Computed conformers energy with {force_field}.')
135 62576f52 Carles
        return np.array([res[1] for res in results])
136 4614bb6a Carles
137 4614bb6a Carles
138 4614bb6a Carles
def run_isolated(inp_vars):
139 4614bb6a Carles
    """Directs the execution of functions to obtain the conformers to adsorb
140 4614bb6a Carles

141 a9b058a5 Carles
    @param inp_vars: Calculation parameters from input file.
142 4614bb6a Carles
    @return:
143 4614bb6a Carles
    """
144 f3004731 Carles
    from modules.formats import adapt_format, confs_to_mol_list, \
145 f3004731 Carles
        rdkit_mol_to_ase_atoms
146 fff3aab1 Carles
    from modules.clustering import clustering, get_rmsd
147 3d6a9d3c Carles
    from modules.calculation import run_calc
148 54be2a9e Carles
149 695dcff8 Carles Marti
    logger.info('Carrying out procedures for the isolated molecule.')
150 90819cc3 Carles Marti
    rd_mol = adapt_format('rdkit', inp_vars['molec_file'],
151 90819cc3 Carles Marti
                          inp_vars['special_atoms'])
152 92924d24 Carles
    confs = gen_confs(rd_mol, inp_vars['num_conformers'])
153 4670488d Carles Marti
    if inp_vars['pre_opt']:
154 4670488d Carles Marti
        confs, confs_ener = pre_opt_confs(confs, inp_vars['pre_opt'])
155 fab7b517 Carles
    else:
156 4670488d Carles Marti
        confs_ener = pre_opt_confs(confs, max_iters=0)
157 fff3aab1 Carles
    conf_list = confs_to_mol_list(confs)
158 fff3aab1 Carles
    rmsd_mtx = get_rmsd(conf_list)
159 fab7b517 Carles
    confs_moi = get_moments_of_inertia(confs)
160 fd33bfdb Carles
    exemplars = clustering(rmsd_mtx)
161 f3004731 Carles
    mol_list = confs_to_mol_list(confs, exemplars)
162 f3004731 Carles
    ase_atms_list = [rdkit_mol_to_ase_atoms(mol) for mol in mol_list]
163 a44ad3c2 Carles Martí
    if len(ase_atms_list) == 0:
164 a44ad3c2 Carles Martí
        err_msg = "No configurations were generated: Check the parameters in" \
165 a44ad3c2 Carles Martí
                  "dockonsurf.inp"
166 a44ad3c2 Carles Martí
        logger.error(err_msg)
167 a44ad3c2 Carles Martí
        raise ValueError(err_msg)
168 f3004731 Carles
    run_calc('isolated', inp_vars, ase_atms_list)
169 082685ad Carles Martí
    finished_calcs, unfinished_calcs = check_finished_calcs('isolated',
170 082685ad Carles Martí
                                                            inp_vars['code'])
171 082685ad Carles Martí
    conf_list = collect_coords(finished_calcs, inp_vars['code'], 'isolated',
172 082685ad Carles Martí
                               inp_vars['special_atoms'])
173 082685ad Carles Martí
    most_stable_conf = select_confs(conf_list, finished_calcs, 0,
174 082685ad Carles Martí
                                    inp_vars['code'])[0]
175 082685ad Carles Martí
    logger.info('Finished the procedures for the isolated molecule section. '
176 082685ad Carles Martí
                f'Most stable conformers is {most_stable_conf}.')