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

dockonsurf / modules / screening.py @ a5cc42ff

Historique | Voir | Annoter | Télécharger (5,08 ko)

1
import logging
2
import numpy as np
3
import ase
4

    
5
logger = logging.getLogger('DockOnSurf')
6

    
7

    
8
def vect_avg(vects):
9
    """Computes the element-wise mean of a set of vectors.
10

11
    @param vects: np.ndarray with shape (num_vectors, length_vector).
12
    @return: vector average computed doing the element-wise mean.
13
    """
14
    from utilities import try_command
15
    err = "vect_avg parameter vects must be a list-like, able to be converted" \
16
          " np.array"
17
    vects = try_command(np.array, [(ValueError, err)], vects)
18
    if len(vects.shape) == 1:
19
        return vects
20
    else:
21
        num_vects = vects.shape[1]
22
        return np.array([np.average(vects[:, i]) for i in range(num_vects)])
23

    
24

    
25
def get_atom_coords(atoms: ase.Atoms, ctrs_list):
26
    """Gets the coordinates of the specified atoms from a ase.Atoms object.
27

28
    Given an ase.Atoms object and a list of atom indices specified in ctrs_list
29
    it gets the coordinates of the specified atoms. If the element in the
30
    ctrs_list is not an index but yet a list of indices, it computes the
31
    element-wise mean of the coordinates of the atoms specified in the inner
32
    list.
33
    @param atoms: ase.Atoms object for which to obtain the coordinates of.
34
    @param ctrs_list: list of (indices/list of indices) of the atoms for which
35
                      the coordinates should be extracted.
36
    @return: np.ndarray of atomic coordinates.
37
    """
38
    coords = []
39
    for i, elem in enumerate(ctrs_list):
40
        if isinstance(elem, list):
41
            coords.append(vect_avg(np.array([atoms[c].position for c in elem])))
42
        elif isinstance(elem, int):
43
            coords.append(atoms[elem].position)
44
        else:
45
            err = f"'ctrs_list must be a list of ints or lists, {type(elem)} " \
46
                  "found."
47
            logger.error(err)
48
            raise ValueError
49
    return np.array(coords)
50

    
51

    
52
def ads_euler(site, ctr, pts_angle, neigh_ctr):
53
    pass
54

    
55

    
56
def ads_chemcat(site, ctr, pts_angle):
57
    return "TO IMPLEMENT"
58

    
59

    
60
def adsorb_confs(conf_list, surf, ads_ctrs, sites, algo, num_pts, neigh_ctrs):
61
    """Generates a number of adsorbate-surface structure coordinates.
62

63
    Given a list of conformers, a surface, a list of atom indices (or list of
64
    list of indices) of both the surface and the adsorbate, it generates a
65
    number of adsorbate-surface structures for every possible combination of
66
    them at different orientations.
67
    @param conf_list: list of ase.Atoms of the different conformers
68
    @param surf: the ase.Atoms object of the surface
69
    @param ads_ctrs: the list atom indices of the adsorbate.
70
    @param sites: the list of atom indices of the surface.
71
    @param algo: the algorithm to use for the generation of adsorbates.
72
    @param num_pts: the number of points per angle orientation to sample
73
    @param neigh_ctrs: the indices of the neighboring atoms to the adsorption
74
    atoms.
75
    @return: list of ase.Atoms for the adsorbate-surface structures
76
    """
77
    surf_ads_list = []
78
    sites_coords = get_atom_coords(surf, sites)
79
    for conf in conf_list:
80
        molec_ctr_coords = get_atom_coords(conf, ads_ctrs)
81
        molec_neigh_coords = get_atom_coords(conf, neigh_ctrs)
82
        for site in sites_coords:
83
            for i, molec_ctr in enumerate(molec_ctr_coords):
84
                if algo == 'euler':
85
                    surf_ads_list.append(ads_euler(site, molec_ctr, num_pts,
86
                                                   molec_neigh_coords[i]))
87
                elif algo == 'chemcat':
88
                    surf_ads_list.append(ads_chemcat(site, molec_ctr, num_pts))
89
    return surf_ads_list
90

    
91

    
92
def run_screening(inp_vars):
93
    """Carry out the screening of adsorbate coordinates on a surface
94

95
    @param inp_vars: Calculation parameters from input file.
96
    """
97
    import os
98
    from modules.formats import read_coords, read_energies, \
99
        rdkit_mol_to_ase_atoms, adapt_format
100
    from modules.clustering import get_rmsd, clustering
101
    from modules.isolated import get_moments_of_inertia
102
    from modules.calculation import run_calc
103

    
104
    if not os.path.isdir("isolated"):
105
        err = "'isolated' directory not found. It is needed in order to carry "
106
        "out the screening of structures to be adsorbed"
107
        logger.error(err)
108
        raise ValueError(err)
109

    
110
    conf_list = read_coords(inp_vars['code'], 'isolated', 'rdkit')
111
    # TODO Implement neighbors algorithm
112
    # neigh_list = get_neighbors(conf_list[0], inp_vars['molec_ads_ctrs'])
113
    conf_enrgs = read_energies(inp_vars['code'], 'isolated')
114
    mois = np.array([get_moments_of_inertia(conf)[0] for conf in conf_list])
115
    rmsd_mtx = get_rmsd(conf_list)
116
    exemplars = clustering(rmsd_mtx)
117
    conf_list = [conf_list[idx] for idx in exemplars]
118
    conf_list = [rdkit_mol_to_ase_atoms(conf) for conf in conf_list]
119
    surf = adapt_format('ase', inp_vars['surf_file'])
120
    surf_ads_list = adsorb_confs(conf_list, surf, inp_vars['molec_ads_ctrs'],
121
                                 inp_vars['sites'], inp_vars['ads_algo'],
122
                                 inp_vars['sample_points_per_angle'],
123
                                 inp_vars['molec_neigh_ctrs'])
124
    run_calc('screening', inp_vars, surf_ads_list)