diff --git a/modules/mol/alg/pymod/qsscore.py b/modules/mol/alg/pymod/qsscore.py index e7d8a0b563afc85555780924d3e728cac3c18ded..866a625704a0f1980a5e6a275114189bfbc7ecf6 100644 --- a/modules/mol/alg/pymod/qsscore.py +++ b/modules/mol/alg/pymod/qsscore.py @@ -29,6 +29,10 @@ class QSEntity: self._sequence = dict() self._pos = dict() self._pair_dist = dict() + # min and max xyz for elements in pos used for fast collision + # detection + self._min_pos = dict() + self._max_pos = dict() @property def view(self): @@ -69,11 +73,12 @@ class QSEntity: :type: :class:`list` of :class:`tuples` """ - if self._interacting_chains is None: + if self._interacting_chains is None: self._interacting_chains = list() for x in itertools.combinations(self.chain_names, 2): - if np.count_nonzero(self.PairDist(x[0], x[1]) < self.contact_d): - self._interacting_chains.append(x) + if self.PotentialInteraction(x[0], x[1]): + if np.count_nonzero(self.PairDist(x[0], x[1]) < self.contact_d): + self._interacting_chains.append(x) return self._interacting_chains def GetChain(self, chain_name): @@ -134,6 +139,52 @@ class QSEntity: 'euclidean') return self._pair_dist[key] + def GetMinPos(self, chain_name): + """ Get min x,y,z cooridnates for given chain + + Based on positions that are extracted with GetPos + + :param chain_name: Chain in :attr:`~view` + :type chain_name: :class:`str` + """ + if chain_name not in self._min_pos: + self._min_pos[chain_name] = self.GetPos(chain_name).min(0) + return self._min_pos[chain_name] + + def GetMaxPos(self, chain_name): + """ Get max x,y,z cooridnates for given chain + + Based on positions that are extracted with GetPos + + :param chain_name: Chain in :attr:`~view` + :type chain_name: :class:`str` + """ + if chain_name not in self._max_pos: + self._max_pos[chain_name] = self.GetPos(chain_name).max(0) + return self._max_pos[chain_name] + + def PotentialInteraction(self, chain_name_one, chain_name_two): + """ Returns True if chains potentially interact + + Based on crude collision detection. There is no guarantee + that they actually interact if True is returned. However, + if False is returned, they don't interact for sure. + + :param chain_name_one: Chain in :attr:`~view` + :type chain_name_one: class:`str` + :param chain_name_two: Chain in :attr:`~view` + :type chain_name_two: class:`str` + """ + min_one = self.GetMinPos(chain_name_one) + max_one = self.GetMaxPos(chain_name_one) + min_two = self.GetMinPos(chain_name_two) + max_two = self.GetMaxPos(chain_name_two) + if np.max(min_one - max_two) > self.contact_d: + return False + if np.max(min_two - max_one) > self.contact_d: + return False + return True + class QSScorerResult: """ Holds data relevant for QS-score computation. Formulas for QS scores: