Completed
Push — master ( 87dea9...e88bec )
by Rich
15:57
created

ConformerIterator   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 20
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 3
c 0
b 0
f 0
dl 0
loc 20
ccs 0
cts 0
cp 0
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 6 1
A __next__() 0 6 2
1
#! /usr/bin/env python
2
#
3
# Copyright (C) 2015-2016 Rich Lewis <[email protected]>
4
# License: 3-clause BSD
5
6 1
"""
7
## skchem.core.conformer
8
9
Defining conformers in scikit-chem.
10
"""
11
12 1
import warnings
13 1
14 1
import rdkit.Chem
0 ignored issues
show
Configuration introduced by
The import rdkit.Chem could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
15
from rdkit.Chem.rdDepictor import Compute2DCoords
0 ignored issues
show
Configuration introduced by
The import rdkit.Chem.rdDepictor could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
16
from rdkit.Chem.rdDistGeom import EmbedMolecule, EmbedMultipleConfs
0 ignored issues
show
Configuration introduced by
The import rdkit.Chem.rdDistGeom could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
Unused Code introduced by
Unused EmbedMolecule imported from rdkit.Chem.rdDistGeom
Loading history...
17 1
18
import numpy as np
0 ignored issues
show
Configuration introduced by
The import numpy could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
19
20
from .base import ChemicalObject, ChemicalObjectView
21 1
22
23
class Conformer(rdkit.Chem.rdchem.Conformer, ChemicalObject):
24
25
    """ Class representing a Conformer in scikit-chem. """
26
27
    @property
28
    def owner(self):
29 1
30
        """ skchem.Mol: the owning molecule. """
31
        from .mol import Mol
32
        return Mol.from_super(self.GetOwningMol())
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named GetOwningMol.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
33
34
    @property
35
    def positions(self):
36 1
37
        """ np.ndarray: the atom positions in the conformer.
38
39
        Note:
40
            This is a copy of the data, not the data itself.  You cannot
41
            allocate to a slice of this.
42
        """
43 1
44
        # cant slice this array sadly.
45
46
        return np.array([self.GetAtomPosition(i) for i in range(len(self))])
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named GetAtomPosition.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
47
48
    @positions.setter
49
    def positions(self, val):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
50 1
51
        assert val.shape[0] == len(self), 'Positions must be given only for ' \
52
                                          'atoms in the molecule.'
53
        assert 1 < val.shape[1] <= 3, 'Positions must be 2 or 3 dimensional.'
54
55
        if val.shape[1] == 2:
56
            val = np.hstack((val, np.zeros((len(val), 1))))
57
58
        self.Set3D(bool((val[:, 2] != 0).any()))
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named Set3D.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
59
60
        return [self.SetAtomPosition(i, v) for i, v in enumerate(val)]
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named SetAtomPosition.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
61
62
    @property
63
    def centre_of_mass(self):
64
65
        """ np.array: the centre of mass of the comformer. """
66
67
        atomic_mass = self.owner.atoms.atomic_mass
68
        return atomic_mass.dot(self.positions) / atomic_mass.sum()
69
70
    @property
71
    def geometric_centre(self):
72
73
        """ np.array: the geometric centre of the conformer. """
74
75
        return self.positions.mean(axis=0)
76
77
    def centre_representation(self, centre_of_mass=True):
78
79
        """ Centre representation to the center of mass.
80
81
        Args:
82
            centre_of_mass (bool):
83
                Whether to use the masses of atoms to calculate the centre of
84
                mass, or just use the mean position coordinate.
85
86
        Returns:
87
            Conformer
88
        """
89
90
        if centre_of_mass:
91
            self.positions -= self.centre_of_mass
92
        else:
93
            self.positions -= self.geometric_centre
94
95
    def _inertia_tensor(self):
96
97
        """ Calculate the inertia tensor. """
98
99
        mass = self.owner.atoms.atomic_mass
100
        pos = self.positions
101
102
        return np.array([[((pos[:, (i % 3) - 1] ** 2 +
103
                            pos[:, (j % 3) - 2] ** 2 if (i == j)
104
                            else - pos[:, i] * pos[:, j]) * mass).sum()
105
                          for i in range(3)] for j in range(3)])
106
107
    def align_with_principal_axes(self):
108
109
        """ Align the reference frame with the principal axes of inertia. """
110
111
        eig_val, eig_vects = np.linalg.eigh(self._inertia_tensor())
0 ignored issues
show
Unused Code introduced by
The variable eig_val seems to be unused.
Loading history...
112
        self.positions = self.positions.dot(eig_vects)
113
114
    def canonize(self):
115
116
        """ Center the reference frame at the centre of mass and """
117
118
        self.centre_representation(centre_of_mass=True)
119
        self.align_with_principal_axes()
120
121
    @property
122
    def id(self):
0 ignored issues
show
Coding Style Naming introduced by
The name id does not conform to the attribute naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
123
124
        """ The ID of the conformer. """
125
126
        return self.GetId()
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named GetId.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
127
128
    @id.setter
129
    def id(self, value):
0 ignored issues
show
Coding Style Naming introduced by
The name id does not conform to the attribute naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
130
131
        warnings.warn('Setting the conformer value directly '
132
                      'may cause issues.', UserWarning)
133
        self.SetId(int(value))
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named SetId.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
134
135
    @property
136
    def is_3d(self):
137
138
        """ bool: whether the conformer is three dimensional. """
139
140
        return self.Is3D()
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named Is3D.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
141
142
    @is_3d.setter
143
    def is_3d(self, val):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
Unused Code introduced by
The argument val seems to be unused.
Loading history...
144
145
        pos = self.positions
146
        pos[:, 2] = 0
147
        self.positions = pos
148
149
    def __len__(self):
150
151
        return self.GetNumAtoms()
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named GetNumAtoms.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
152
153
    def __repr__(self):
154
        return '<{klass} id="{id}" at {address}>'.format(
155
            klass=self.__class__.__name__,
156
            id=self.GetId(),
0 ignored issues
show
Bug introduced by
The Instance of Conformer does not seem to have a member named GetId.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
157
            address=hex(id(self)))
158
159
160
class ConformerView(ChemicalObjectView):
0 ignored issues
show
Coding Style introduced by
This class should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
161
162
    def __getitem__(self, index):
163
164
        res = super(ConformerView, self).__getitem__(index)
165
        if res is None:
166
            try:
167
                return Conformer.from_super(
168
                    self.owner.GetConformer(int(index)))
169
            except ValueError:
170
                raise IndexError(
171
                        'Conformer id {} not available (choose one '
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation.
'Conformer id {} not available (choose one '
| ^
Loading history...
172
                        'of {}).'.format(index, tuple(self.id)))
173
        else:
174
            return res
175
176
    def __setitem__(self, key, value):
177
178
        assert isinstance(value, Conformer), 'Only `Conformer`s can be added.'
179
        assert len(value) == len(self.owner.atoms), \
180
            '`Conformers` must have the same number of atoms as the `Mol`.'
181
        self.owner.RemoveConformer(int(key))
182
        with warnings.catch_warnings():
183
            warnings.simplefilter('ignore')
184
            value.id = key
185
        self.owner.AddConformer(value)
186
187
    def __delitem__(self, key):
188
189
        self.owner.RemoveConformer(key)
190
191
    def __iter__(self):
192
        return ConformerIterator(self)
193
194
    def __len__(self):
195
196
        return self.owner.GetNumConformers()
197
198
    def append(self, value):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
199
200
        assert isinstance(value, rdkit.Chem.Conformer)
201
        self[max(self.id) + 1] = value
202
203
    def append_2d(self, **kwargs):
204
205
        """ Append a 2D conformer. """
206
207
        kwargs['clearConfs'] = False
208
        Compute2DCoords(self.owner, **kwargs)
209
210
    def append_3d(self, n_conformers=1, **kwargs):
211
212
        """ Append (a) 3D conformer(s), roughly embedded but not optimized.
213
214
        Args:
215
            n_conformers (int):
216
                The number of conformers to append.
217
            Further kwargs are passed to `EmbedMultipleConfs`.
218
219
        """
220
221
        kwargs.setdefault('numConfs', n_conformers)
222
        kwargs['clearConfs'] = False
223
        EmbedMultipleConfs(self.owner, **kwargs)
224
225
    @property
226
    def positions(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
227
228
        return np.array([conformer.positions for conformer in self])
229
230
    @property
231
    def is_3d(self):
0 ignored issues
show
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
232
233
        return np.array([conformer.is_3d for conformer in self])
234
235
    @property
236
    def id(self):
0 ignored issues
show
Coding Style Naming introduced by
The name id does not conform to the attribute naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
This method should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
237
238
        return np.array([conf.GetId() for conf in self.owner.GetConformers()])
239
240
241
class ConformerIterator(object):
242
243
    """  Iterator for chemical object views.  """
244
245
    def __init__(self, view):
246
        """ Create an iterator from a chemical object view. """
247
        self.view = view
248
        self._ids = view.id
249
        self._current = 0
250
        self._high = len(view)
251
252
    def __next__(self):
253
        if self._current >= self._high:
254
            raise StopIteration
255
        else:
256
            self._current += 1
257
            return self.view[self._ids[self._current - 1]]
258
259
    # py2 compat
260
    next = __next__
261